postfix/0000755000567100000120000000000011137644405012237 5ustar jcameronwheelpostfix/config.info.uk_UA0000664000567100000120000000127211137644403015366 0ustar jcameronwheelpostfix_lookup_table_command= Postfix ('postmap'),0 postfix_config_command= Postfix,0 line1= , ,11 line2= ,11 postfix_newaliases_command= "newaliases" ( Sendmail),0 perpage=ʳ , ,0,6 max_records= ,0,6 postfix_aliases_table_command= Postfix,0 postfix_config_file= Postfix,0 postfix_control_command= Postfix,0 postfix/config.info.tr0000644000567100000120000000067211137644403015010 0ustar jcameronwheelpostfix_control_command=Postfix kontrol komutunun tam yolu,0 postfix_config_command=Postfix yaplandrma komutunun tam yolu,0 postfix_config_file=Full path to Postfix config file,0 postfix_aliases_table_command=Postfix takma isim oluturma komutunun tam yolu,0 postfix_newaliases_command="newaliases" komutunun tam yolu (Sendmail uyumluluu),0 postfix_lookup_table_command=Postfix'in komut ynetim tablosunun tam yolu (`postmap'),0 postfix/save_opts.cgi0000755000567100000120000000174711137644403014740 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save Postfix options require './postfix-lib.pl'; &ReadParse(); $access{'general'} || &error($text{'opts_ecannot'}); # &ui_print_header(undef, $text{'opts_title'}, ""); &error_setup($text{'opts_err'}); if (defined($in{"debug_peer_level_def"})) { $in{"debug_peer_level_def"} =~ /^[1-9]\d*$/ || &error($text{'opts_edebug'}); } &lock_postfix_files(); &save_options(\%in); &unlock_postfix_files(); &reload_postfix(); &webmin_log("opts"); &redirect(""); postfix/config0000644000567100000120000000127511137644403013432 0ustar jcameronwheelpostfix_control_command=/usr/sbin/postfix postfix_config_command=/usr/sbin/postconf postfix_config_file=/etc/postfix/main.cf postfix_aliases_table_command=/usr/sbin/postalias postfix_newaliases_command=/usr/bin/newaliases postfix_lookup_table_command=/usr/sbin/postmap postfix_queue_command=/usr/sbin/postqueue postfix_super_command=/usr/sbin/postsuper max_records=200 perpage=20 mailq_dir=/var/spool/postfix mailq_cmd=/usr/bin/mailq postcat_cmd=/usr/sbin/postcat sort_mode=0 fwd_mode=0 mailq_sort=0 mailq_count=0 delete_warn=1 mailq_sort=0 check_config=1 top_buttons=1 wrap_width=80 index_check=1 postfix_master=/etc/postfix/master.cf columns=2 show_cmts=0 prefix_cmts=0 ldap_doms=0 delete_confirm=1 postfix/aliases-lib.pl0000755000567100000120000001741611137644403014773 0ustar jcameronwheel# aliases-lib.pl # Alias file functions # aliases_file(&config) # Returns the alias filenames sub aliases_file { if ($config{'alias_file'}) { return [ $config{'alias_file'} ]; } else { local(@afiles, $o); foreach $o (&find_type("O", $_[0])) { if ($o->{'value'} =~ /^\s*AliasFile=(.*)$/) { push(@afiles, split(/,/, $1)); } } map { s/dbm:// } @afiles; return \@afiles; } } # list_aliases(files) # Returns an array of data structures, each containing information about # one sendmail alias sub list_aliases { local $jfiles = join(",", @{$_[0]}); local $c = $list_aliases_cache{$jfiles}; if (!defined($c)) { $c = $list_aliases_cache{$jfiles} = [ ]; local $file; local @skip = split(/\s+/, $config{'alias_skip'}); foreach $file (@{$_[0]}) { local $lalias; local $lnum = 0; local $cmt; &open_readfile(AFILE, $file); while() { s/\r|\n//g; # remove newlines if (/^\s*#+\s*(.*)/ && &is_table_comment($_, 1)) { # A comment line $cmt = &is_table_comment($_, 1); } elsif (/^(#*)\s*([^:$ \t]+)\s*:\s*(.*)$/) { local(%alias, @values, $v); $alias{'line'} = $cmt ? $lnum-1 : $lnum; $alias{'eline'} = $lnum; $alias{'file'} = $file; $alias{'files'} = $_[0]; $alias{'enabled'} = $1 ? 0 : 1; $alias{'name'} = $2; $alias{'cmt'} = $cmt; $v = $3; $alias{'value'} = $v; while($v =~ /^\s*,?\s*()"([^"]+)"(.*)$/ || $v =~ /^\s*,?\s*(\|)"([^"]+)"(.*)$/ || $v =~ /^\s*,?\s*()([^,\s]+)(.*)$/) { push(@values, $1.$2); $v = $3; } $alias{'values'} = \@values; $alias{'num'} = scalar(@$c); if (&indexof($alias{'name'}, @skip) < 0) { push(@$c, \%alias); $lalias = \%alias; } $cmt = undef; } elsif (/^(#*)\s+(\S.*)$/ && $lalias && ($1 && !$lalias->{'enabled'} || !$1 && $lalias->{'enabled'})) { # continuation of last alias $lalias->{'eline'} = $lnum; local $v = $2; $lalias->{'value'} .= $v; while($v =~ /^\s*,?\s*()"([^"]+)"(.*)$/ || $v =~ /^\s*,?\s*(\|)"([^"]+)"(.*)$/ || $v =~ /^\s*,?\s*()([^,\s]+)(.*)$/) { push(@{$lalias->{'values'}}, $1.$2); $v = $3; } $cmt = undef; } else { # Some other line $lalias = undef; $cmt = undef; } $lnum++; } close(AFILE); } } return @$c; } # alias_form([alias], [no-comment]) # Display a form for editing or creating an alias. Each alias can map to # 1 or more programs, files, lists or users sub alias_form { local ($a, $nocmt) = @_; local (@values, $v, $type, $val, @typenames); if ($a) { @values = @{$a->{'values'}}; } @typenames = map { $text{"aform_type$_"} } (0 .. 6); $typenames[0] = "<$typenames[0]>"; # Start of form and table print &ui_form_start("save_alias.cgi", "post"); if ($a) { print &ui_hidden("num", $a->{'num'}),"\n"; } else { print &ui_hidden("new", 1),"\n"; } print &ui_table_start($a ? $text{'aform_edit'} : $text{'aform_create'}, undef, 2); # Description if (!$nocmt) { print &ui_table_row(&hlink($text{'aform_cmt'},"alias_cmt"), &ui_textbox("cmt", $a ? $a->{'cmt'} : undef, 50)); } # Alias name print &ui_table_row(&hlink($text{'aform_name'},"alias_name"), &ui_textbox("name", $a ? $a->{'name'} : "", 20)); # Enabled flag print &ui_table_row(&hlink($text{'aform_enabled'}, "alias_enabled"), &ui_yesno_radio("enabled", !$a || $a->{'enabled'} ? 1 : 0)); # Destinations local @typeopts; for($j=0; $j<@typenames; $j++) { if (!$j || $access{"aedit_$j"}) { push(@typeopts, [ $j, $typenames[$j] ]); } } for($i=0; $i<=@values; $i++) { ($type, $val) = $values[$i] ? &alias_type($values[$i]) : (0, ""); local $typesel = &ui_select("type_$i", $type, \@typeopts); local $valtxt = &ui_textbox("val_$i", $val, 30); local $edlnk; if ($type == 2 && $a) { $edlnk = "". "$text{'aform_afile'}\n"; } elsif ($type == 5 && $a) { $edlnk = "". "$text{'aform_afile'}\n"; } elsif ($type == 6 && $a) { $edlnk = "". "$text{'aform_afile'}\n"; } print &ui_table_row(&hlink($text{'aform_val'},"alias_to"), $typesel."\n".$valtxt."\n".$edlnk); } # Table and form end print &ui_table_end(); if ($a) { print &ui_form_end([ [ "save", $text{'save'} ], [ "delete", $text{'delete'} ] ]); } else { print &ui_form_end([ [ "create", $text{'create'} ] ]); } } # create_alias(&details, &files, [norebuild]) # Create a new alias sub create_alias { &list_aliases($_[1]); # force cache init # Update the config file local(%aliases); local $lref = &read_file_lines($_[1]->[0]); $_[0]->{'line'} = scalar(@$lref); push(@$lref, &make_table_comment($_[0]->{'cmt'}, 1)); local $str = ($_[0]->{'enabled'} ? "" : "# ") . $_[0]->{'name'} . ": " . join(',', map { /\s/ ? "\"$_\"" : $_ } @{$_[0]->{'values'}}); push(@$lref, $str); $_[0]->{'eline'} = scalar(@$lref)-1; &flush_file_lines($_[1]->[0]); if (!$_[2]) { if (!&rebuild_map_cmd($_[1]->[0])) { &system_logged("newaliases >/dev/null 2>&1"); } } # Add to the cache local $jfiles = join(",", @{$_[1]}); local $c = $list_aliases_cache{$jfiles}; $_[0]->{'file'} = $_[1]->[0]; $_[0]->{'num'} = scalar(@$c); push(@$c, $_[0]); } # delete_alias(&details, [norebuild]) # Deletes one mail alias sub delete_alias { # Remove from the file local $lref = &read_file_lines($_[0]->{'file'}); local $len = $_[0]->{'eline'} - $_[0]->{'line'} + 1; splice(@$lref, $_[0]->{'line'}, $len); &flush_file_lines($_[0]->{'file'}); if (!$_[1]) { if (!&rebuild_map_cmd($_[0]->{'file'})) { &system_logged("newaliases >/dev/null 2>&1"); } } # Remove from the cache local $jfiles = join(",", @{$_[0]->{'files'}}); local $c = $list_aliases_cache{$jfiles}; local $idx = &indexof($_[0], @$c); splice(@$c, $idx, 1) if ($idx != -1); &renumber_list($c, $_[0], -$len); } # modify_alias(&old, &details, [norebuild]) # Update some existing alias sub modify_alias { # Add to the file local @newlines; push(@newlines, &make_table_comment($_[1]->{'cmt'}, 1)); local $str = ($_[1]->{'enabled'} ? "" : "# ") . $_[1]->{'name'} . ": " . join(',', map { /\s/ ? "\"$_\"" : $_ } @{$_[1]->{'values'}}); push(@newlines, $str); local $lref = &read_file_lines($_[0]->{'file'}); local $len = $_[0]->{'eline'} - $_[0]->{'line'} + 1; splice(@$lref, $_[0]->{'line'}, $len, @newlines); &flush_file_lines($_[0]->{'file'}); if (!$_[2]) { if (!&rebuild_map_cmd($_[0]->{'file'})) { &system_logged("newaliases >/dev/null 2>&1"); } } local $jfiles = join(",", @{$_[0]->{'files'}}); local $c = $list_aliases_cache{$jfiles}; local $idx = &indexof($_[0], @$c); $_[1]->{'file'} = $_[0]->{'file'}; $_[1]->{'line'} = $_[0]->{'line'}; $_[1]->{'eline'} = $_[1]->{'line'}+scalar(@newlines)-1; $c->[$idx] = $_[1] if ($idx != -1); &renumber_list($c, $_[0], scalar(@newlines) - $len); } # alias_type(string) # Return the type and destination of some alias string sub alias_type { local @rv; if ($_[0] =~ /^\|$module_config_directory\/autoreply.pl\s+(\S+)/) { @rv = (5, $1); } elsif ($_[0] =~ /^\|$module_config_directory\/filter.pl\s+(\S+)/) { @rv = (6, $1); } elsif ($_[0] =~ /^\|(.*)$/) { @rv = (4, $1); } elsif ($_[0] =~ /^(\/.*)$/) { @rv = (3, $1); } elsif ($_[0] =~ /^:include:(.*)$/) { @rv = (2, $1); } else { @rv = (1, $_[0]); } return wantarray ? @rv : $rv[0]; } # lock_alias_files(&files) sub lock_alias_files { foreach $f (@{$_[0]}) { &lock_file($f); } } # unlock_alias_files(&files) sub unlock_alias_files { foreach $f (@{$_[0]}) { &unlock_file($f); } } # can_edit_alias(&alias) sub can_edit_alias { local ($a) = @_; foreach my $v (@{$a->{'values'}}) { $access{"aedit_".&alias_type($v)} || return 0; } if ($access{'amode'} == 2) { $a->{'name'} =~ /$access{'aliases'}/ || return 0; } elsif ($access{'amode'} == 3) { $a->{'name'} eq $remote_user || return 0; } return 1; } 1; postfix/acl_security.pl0000755000567100000120000000151211137644403015262 0ustar jcameronwheel require 'postfix-lib.pl'; @acl_pages = ("resource", "address_rewriting", "aliases", "general", "canonical", "virtual", "transport", "relocated", "header","body", "bcc", "local_delivery", "smtpd", "sasl", "client", "smtp", "rate", "debug", "ldap", "master", "startstop", "mailq", "postfinger", "manual"); # Print the form for security options of postfix module sub acl_security_form { local $o; foreach $o (@acl_pages) { print &ui_table_row($text{'acl_'.$o}, &ui_yesno_radio($o, $_[0]->{$o} ? 1 : 0)); } print &ui_table_row($text{'acl_dir'}, &ui_textbox("dir", $_[0]->{'dir'}, 50)); } # acl_security_save(&options) # Parse the form for security options for the postfix module sub acl_security_save { local $o; foreach $o (@acl_pages) { $_[0]->{$o} = $in{$o}; } $_[0]->{'dir'} = $in{'dir'}; } postfix/save_opts_misc.cgi0000755000567100000120000000172311137644403015745 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save Postfix options ; special case in which we need to regenerate the relocated table require './postfix-lib.pl'; &ReadParse(); # &ui_print_header(undef, $text{'opts_title'}, ""); &error_setup($text{'opts_err'}); &lock_postfix_files(); &before_save(); &save_options(\%in); &ensure_map("relocated_maps"); &after_save(); &unlock_postfix_files(); ®enerate_relocated_table(); &reload_postfix(); &webmin_log("misc"); &redirect(""); postfix/edit_rfile.cgi0000775000567100000120000000607311137644403015042 0ustar jcameronwheel#!/usr/local/bin/perl # edit_rfile.cgi # Display the contents of an autoreply file require (-r 'sendmail-lib.pl' ? './sendmail-lib.pl' : -r 'qmail-lib.pl' ? './qmail-lib.pl' : './postfix-lib.pl'); &ReadParse(); if (substr($in{'file'}, 0, length($access{'apath'})) ne $access{'apath'}) { &error(&text('rfile_efile', $in{'file'})); } &ui_print_header(undef, $text{'rfile_title'}, ""); &open_readfile(FILE, $in{'file'}); while() { if (/^Reply-Tracking:\s*(.*)/) { $replies = $1; } elsif (/^Reply-Period:\s*(.*)/) { $period = $1; } elsif (/^No-Autoreply:\s*(.*)/) { $no_autoreply = $1; } elsif (/^No-Autoreply-Regexp:\s*(.*)/) { push(@no_regexp, $1); } elsif (/^From:\s*(.*)/) { $from = $1; } else { push(@lines, $_); } } close(FILE); print &text('rfile_desc', "$in{'file'}"),"

\n"; print "$text{'rfile_desc2'}

\n"; print "

\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; # Show From: address print "\n"; printf "\n", $from; print "\n"; # Show reply-tracking file print "\n"; printf "\n", $replies, &file_chooser_button("replies"); print " " x 3; # Show reply-tracking period print "\n"; printf "\n", $period, $text{'rfile_secs'}; # Show people to not autoreply to print "\n"; printf "\n", $no_autoreply; # Show regexps to not autoreply to print "\n"; print "\n"; print "
$text{'rfile_from'} %s\n", $from eq '' ? "checked" : "", $text{'rfile_auto'}; printf "\n", $from eq '' ? "" :"checked"; printf "
$text{'rfile_fromdesc'}
$text{'rfile_replies'} %s\n", $replies eq '' ? "checked" : "", $text{'rfile_none'}; printf " %s\n", $replies eq '' ? "" :"checked", $text{'rfile_file'}; printf " %s
   $text{'rfile_period'} %s\n", $period eq '' ? "checked" : "", $text{'rfile_default'}; printf "\n", $period eq '' ? "" :"checked"; printf " %s
$text{'rfile_no_autoreply'}
$text{'rfile_no_regexp'}",&ui_textarea("no_regexp", join("\n", @no_regexp), 3, 40),"
\n"; print " ", "\n"; print "
\n"; &ui_print_footer("edit_alias.cgi?name=$in{'name'}&num=$in{'num'}", $text{'aform_return'}); postfix/config-mandrake-linux0000644000567100000120000000127511137644403016347 0ustar jcameronwheelpostfix_control_command=/usr/sbin/postfix postfix_config_command=/usr/sbin/postconf postfix_config_file=/etc/postfix/main.cf postfix_aliases_table_command=/usr/sbin/postalias postfix_newaliases_command=/usr/bin/newaliases postfix_lookup_table_command=/usr/sbin/postmap postfix_queue_command=/usr/sbin/postqueue postfix_super_command=/usr/sbin/postsuper max_records=200 perpage=20 mailq_dir=/var/spool/postfix mailq_cmd=/usr/bin/mailq postcat_cmd=/usr/sbin/postcat sort_mode=0 fwd_mode=0 mailq_sort=0 mailq_count=0 delete_warn=1 mailq_sort=0 check_config=1 top_buttons=1 wrap_width=80 index_check=1 postfix_master=/etc/postfix/master.cf columns=2 show_cmts=0 prefix_cmts=0 ldap_doms=0 delete_confirm=1 postfix/log_parser.pl0000755000567100000120000000143311137644403014733 0ustar jcameronwheel# log_parser.pl # Functions for parsing this module's logs do 'postfix-lib.pl'; # parse_webmin_log(user, script, action, type, object, ¶ms) # Converts logged information from this module into human-readable form sub parse_webmin_log { local ($user, $script, $action, $type, $object, $p) = @_; if ($action eq 'delete' || $action eq 'modify' || $action eq 'create') { return &text("log_${type}_${action}", "".&html_escape($object)."") || &text("log_${action}_$type", $object); } elsif ($action eq 'manual') { return &text('log_manual', "".&html_escape($object).""); } elsif ($action eq 'delqs') { return &text('log_delqs', $object); } elsif ($action eq 'backend') { return &text('log_backend', $object); } else { return $text{'log_'.$action}; } } postfix/resource.cgi0000755000567100000120000000354311137644403014560 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # A form for controlling resource control. # # << Here are all options seen in Postfix sample-resource.cf >> require './postfix-lib.pl'; $access{'resource'} || &error($text{'resource_ecannot'}); &ui_print_header(undef, $text{'resource_title'}, ""); $default = $text{'opts_default'}; $none = $text{'opts_none'}; $no_ = $text{'opts_no'}; # Form start print &ui_form_start("save_opts.cgi"); print &ui_table_start($text{'resource_title'}, "width=100%", 4); &option_freefield("bounce_size_limit", 15); &option_freefield("command_time_limit", 15); &option_freefield("default_process_limit", 15); &option_freefield("duplicate_filter_limit", 15); &option_freefield("deliver_lock_attempts", 15); &option_freefield("deliver_lock_delay", 15); &option_freefield("fork_attempts", 15); &option_freefield("fork_delay", 15); &option_freefield("header_size_limit", 15); &option_freefield("line_length_limit", 15); &option_freefield("message_size_limit", 15); &option_freefield("qmgr_message_active_limit", 15); &option_freefield("qmgr_message_recipient_limit", 15); &option_freefield("queue_minfree", 15); &option_freefield("stale_lock_time", 15); &option_freefield("transport_retry_time", 15); &option_freefield("mailbox_size_limit", 15); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'opts_save'} ] ]); &ui_print_footer("", $text{'index_return'}); postfix/manual_update.cgi0000775000567100000120000000121611137644403015545 0ustar jcameronwheel#!/usr/local/bin/perl # Update a manually edited config file require './postfix-lib.pl'; &error_setup($text{'cmanual_err'}); $access{'manual'} || &error($text{'cmanual_ecannot'}); &ReadParseMime(); # Work out the file @files = ( $config{'postfix_config_file'}, $config{'postfix_master'} ); &indexof($in{'file'}, @files) >= 0 || &error($text{'cmanual_efile'}); $in{'data'} =~ s/\r//g; if ($in{'file'} eq $files[0]) { $in{'data'} =~ /\S/ || &error($text{'cmanual_edata'}); } # Write to it &open_lock_tempfile(DATA, ">$in{'file'}"); &print_tempfile(DATA, $in{'data'}); &close_tempfile(DATA); &webmin_log("manual", undef, $in{'file'}); &redirect(""); postfix/save_master.cgi0000775000567100000120000000360211137644403015240 0ustar jcameronwheel#!/usr/local/bin/perl # Create, update or delete a server process require './postfix-lib.pl'; $access{'master'} || &error($text{'master_ecannot'}); &ReadParse(); &error_setup($text{'master_err'}); $master = &get_master_config(); if ($in{'new'}) { $prog = { }; } else { ($prog) = grep { $_->{'name'} eq $in{'old'} } @$master; $prog || &error($text{'master_egone'}); } &lock_file($config{'postfix_master'}); if ($in{'delete'}) { # Just delete this one &delete_master($prog); } else { # Validate and store inputs $prog->{'type'} = $in{'type'}; $prog->{'enabled'} = $in{'enabled'}; $in{'name'} =~ /^\S+$/ || &error($text{'master_ename'}); if (!$in{'host_def'}) { gethostbyname($in{'host'}) || &error($text{'master_ehost'}); $in{'type'} eq 'inet' || &error($text{'master_einet'}); $prog->{'name'} = $in{'host'}.":".$in{'name'}; } else { $prog->{'name'} = $in{'name'}; } $in{'command'} =~ /^\S/ || &error($text{'master_ecommand'}); $prog->{'command'} = $in{'command'}; $prog->{'private'} = $in{'private'}; $prog->{'unpriv'} = $in{'unpriv'}; $prog->{'chroot'} = $in{'chroot'}; if ($in{'wakeup'} == 0) { $prog->{'wakeup'} = '-'; } elsif ($in{'wakeup'} == 1) { $prog->{'wakeup'} = '0'; } else { $in{'wtime'} =~ /^\d+$/ || &error($text{'master_ewakeup'}); $prog->{'wakeup'} = $in{'wtime'}.($in{'wused'} ? "?" : ""); } if ($in{'maxprocs'} == 0) { $prog->{'maxprocs'} = '-'; } elsif ($in{'maxprocs'} == 1) { $prog->{'maxprocs'} = '0'; } else { $in{'procs'} =~ /^\d+$/ || &error($text{'master_emaxprocs'}); $prog->{'maxprocs'} = $in{'procs'}; } # Save or update if ($in{'new'}) { &create_master($prog); } else { &modify_master($prog); } } &unlock_file($config{'postfix_master'}); # Apply config &reload_postfix(); &webmin_log($in{'delete'} ? "delete" : $in{'new'} ? "create" : "modify", "master", $prog->{'name'}, $prog); &redirect("master.cgi"); postfix/config-freebsd0000644000567100000120000000137311137644403015041 0ustar jcameronwheelpostfix_control_command=/usr/local/sbin/postfix postfix_config_command=/usr/local/sbin/postconf postfix_config_file=/usr/local/etc/postfix/main.cf postfix_aliases_table_command=/usr/local/sbin/postalias postfix_newaliases_command=/usr/bin/newaliases postfix_lookup_table_command=/usr/local/sbin/postmap postfix_queue_command=/usr/local/sbin/postqueue postfix_super_command=/usr/local/sbin/postsuper max_records=200 perpage=20 mailq_dir=/var/spool/postfix mailq_cmd=/usr/bin/mailq postcat_cmd=/usr/local/sbin/postcat sort_mode=0 fwd_mode=0 mailq_sort=0 mailq_count=0 delete_warn=1 mailq_sort=0 check_config=1 top_buttons=1 wrap_width=80 index_check=1 postfix_master=/usr/local/etc/postfix/master.cf columns=2 show_cmts=0 prefix_cmts=0 ldap_doms=0 delete_confirm=1 postfix/autoreply.pl0000755000567100000120000002335311137644403014627 0ustar jcameronwheel#!/usr/local/bin/perl # autoreply.pl # Simple autoreply script. Command line arguments are : # autoreply-file username alternate-file # Read sendmail module config $ENV{'PATH'} = "/bin:/usr/bin:/sbin:/usr/sbin"; $p = -l $0 ? readlink($0) : $0; $p =~ /^(.*)\/[^\/]+$/; $moddir = $1; %config = &read_config_file("$moddir/config"); # If this isn't the sendmail module, try it if (!$config{'sendmail_path'} || !-x $config{'sendmail_path'}) { $moddir =~ s/([^\/]+)$/sendmail/; %config = &read_config_file("$moddir/config"); } if (!$config{'sendmail_path'} || !-x $config{'sendmail_path'}) { # Make some guesses about sendmail if (-x "/usr/sbin/sendmail") { %config = ( 'sendmail_path' => '/usr/sbin/sendmail' ); } elsif (-x "/usr/local/sbin/sendmail") { %config = ( 'sendmail_path' => '/usr/local/sbin/sendmail' ); } elsif (-x "/opt/csw/lib/sendmail") { %config = ( 'sendmail_path' => '/opt/csw/lib/sendmail' ); } elsif (-x "/usr/lib/sendmail") { %config = ( 'sendmail_path' => '/usr/lib/sendmail' ); } else { die "Failed to find sendmail or config file"; } } # read headers and body $lnum = 0; while() { s/\r|\n//g; if (/^From\s+(\S+)/ && $lnum == 0) { # Magic From line $fromline = $1; } elsif (/^(\S+):\s+(.*)/) { $header{lc($1)} = $2; $lastheader = lc($1); } elsif (/^\s+(.*)/ && $lastheader) { $header{$lastheader} .= $_; } elsif (!$_) { last; } $lnum++; } while() { $body .= $_; } if ($header{'x-webmin-autoreply'} || $header{'auto-submitted'} && lc($header{'auto-submitted'}) ne 'no') { print STDERR "Cancelling autoreply to an autoreply\n"; exit 0; } if ($header{'x-mailing-list'} || $header{'list-id'} || $header{'precedence'} =~ /junk|bulk|list/i || $header{'to'} =~ /Multiple recipients of/i) { # Do nothing if post is from a mailing list exit 0; } if ($header{'from'} =~ /postmaster|mailer-daemon/i || $fromline =~ /postmaster|mailer-daemon|<>/ ) { # Do nothing if post is a bounce exit 0; } # work out the correct to address @to = ( &split_addresses($header{'to'}), &split_addresses($header{'cc'}), &split_addresses($header{'bcc'}) ); $to = $to[0]->[0]; foreach $t (@to) { if ($t->[0] =~ /^([^\@\s]+)/ && $1 eq $ARGV[1] || $t->[0] eq $ARGV[1]) { $to = $t->[0]; } } # build list of default reply headers $rheader{'From'} = $to; $rheader{'To'} = $header{'reply-to'} ? $header{'reply-to'} : $header{'from'}; $rheader{'Subject'} = "Autoreply to $header{'subject'}"; $rheader{'X-Webmin-Autoreply'} = 1; $rheader{'X-Originally-To'} = $header{'to'}; chop($host = `hostname`); $rheader{'Message-Id'} = "<".time().".".$$."\@".$host.">"; # read the autoreply file (or alternate) if (open(AUTO, $ARGV[0]) || $ARGV[2] && open(AUTO, $ARGV[2])) { while() { s/\$SUBJECT/$header{'subject'}/g; s/\$FROM/$header{'from'}/g; s/\$TO/$to/g; s/\$DATE/$header{'date'}/g; s/\$BODY/$body/g; if (/^(\S+):\s*(.*)/ && !$doneheaders) { if ($1 eq "No-Autoreply-Regexp") { push(@no_regexp, $2); } elsif ($1 eq "Autoreply-File") { push(@files, $2); } else { $rheader{$1} = $2; $rheaders .= $_; } } else { $rbody .= $_; $doneheaders = 1; } } close(AUTO); } else { $rbody = "Failed to open autoreply file $ARGV[0] : $!"; } # Open the replies tracking DBM, if one was set if ($rheader{'Reply-Tracking'}) { $track_replies = dbmopen(%replies, $rheader{'Reply-Tracking'}, 0700); } if ($track_replies) { # See if we have replied to this address before $period = $rheader{'Reply-Period'} || 60*60; ($from) = &split_addresses($header{'from'}); if ($from) { $lasttime = $replies{$from->[0]}; $now = time(); if ($now < $lasttime+$period) { # Autoreplied already in this period .. just halt exit(0); } $replies{$from->[0]} = $now; } } delete($rheader{'Reply-Tracking'}); delete($rheader{'Reply-Period'}); # Check if we are within the requested time range if ($rheader{'Autoreply-Start'} && time() < $rheader{'Autoreply-Start'} || $rheader{'Autoreply-End'} && time() > $rheader{'Autoreply-End'}) { # Nope .. so do nothing exit 0; } delete($rheader{'Autoreply-Start'}); delete($rheader{'Autoreply-End'}); # Check if there is a deny list, and if so don't send a reply @fromsplit = &split_addresses($header{'from'}); if (@fromsplit) { $from = $fromsplit[0]->[0]; ($fromuser, $fromdom) = split(/\@/, $from); foreach $n (split(/\s+/, $rheader{'No-Autoreply'})) { if ($n =~ /^(\S+)\@(\S+)$/ && lc($from) eq lc($n) || $n =~ /^\*\@(\S+)$/ && lc($fromdom) eq lc($1) || $n =~ /^(\S+)\@\*$/ && lc($fromuser) eq lc($1) || $n =~ /^\*\@\*(\S+)$/ && lc($fromdom) =~ /$1$/i || $n =~ /^(\S+)\@\*(\S+)$/ && lc($fromuser) eq lc($1) && lc($fromdom) =~ /$2$/i) { exit(0); } } delete($rheader{'No-Autoreply'}); } # Check if message matches one of the deny regexps foreach $re (@no_regexp) { if ($re =~ /\S/ && $rheaders =~ /$re/i) { print STDERR "Skipping due to match on $re\n"; exit(1); } } # Read attached files foreach $f (@files) { local $/ = undef; if (!open(FILE, $f)) { print STDERR "Failed to open $f : $!\n"; exit(1); } $data = ; close(FILE); $f =~ s/^.*\///; $type = &guess_mime_type($f)."; name=\"$f\""; $disp = "inline; filename=\"$f\""; push(@attach, { 'headers' => [ [ 'Content-Type', $type ], [ 'Content-Disposition', $disp ], [ 'Content-Transfer-Encoding', 'base64' ] ], 'data' => $data }); } # Work out the encoding if ($rbody =~ /[\177-\377]/) { # High-ascii $enc = "quoted-printable"; $encrbody = "ed_encode($rbody); $type = "text/plain; charset=iso-8859-1"; } else { $enc = undef; $encrbody = $rbody; $type = "text/plain"; } # run sendmail and feed it the reply ($rfrom) = &split_addresses($rheader{'From'}); if ($rfrom->[0]) { open(MAIL, "|$config{'sendmail_path'} -t -f$rfrom->[0]"); } else { open(MAIL, "|$config{'sendmail_path'} -t -f$to"); } foreach $h (keys %rheader) { print MAIL "$h: $rheader{$h}\n"; } # Create the message body if (!@attach) { # Just text, so no encoding is needed if ($enc) { print MAIL "Content-Transfer-Encoding: $enc\n"; } if (!$rheader{'Content-Type'}) { print MAIL "Content-Type: $type\n"; } print MAIL "\n"; print MAIL $encrbody; } else { # Need to send a multi-part MIME message print MAIL "MIME-Version: 1.0\n"; $bound = "bound".time(); $ctype = "multipart/mixed"; print MAIL "Content-Type: $ctype; boundary=\"$bound\"\n"; print MAIL "\n"; $bodyattach = { 'headers' => [ [ 'Content-Type', $type ], ], 'data' => $encrbody }; if ($enc) { push(@{$bodyattach->{'headers'}}, [ 'Content-Transfer-Encoding', $enc ]); } splice(@attach, 0, 0, $bodyattach); # Send attachments print MAIL "This is a multi-part message in MIME format.","\n"; $lnum++; foreach $a (@attach) { print MAIL "\n"; print MAIL "--",$bound,"\n"; local $enc; foreach $h (@{$a->{'headers'}}) { print MAIL $h->[0],": ",$h->[1],"\n"; $enc = $h->[1] if (lc($h->[0]) eq 'content-transfer-encoding'); $lnum++; } print MAIL "\n"; $lnum++; if (lc($enc) eq 'base64') { local $enc = &encode_base64($a->{'data'}); $enc =~ s/\r//g; print MAIL $enc; } else { $a->{'data'} =~ s/\r//g; $a->{'data'} =~ s/\n\.\n/\n\. \n/g; print MAIL $a->{'data'}; if ($a->{'data'} !~ /\n$/) { print MAIL "\n"; } } } print MAIL "\n"; print MAIL "--",$bound,"--","\n"; print MAIL "\n"; } close(MAIL); # split_addresses(string) # Splits a comma-separated list of addresses into [ email, real-name, original ] # triplets sub split_addresses { local (@rv, $str = $_[0]); while(1) { if ($str =~ /^[\s,]*(([^<>\(\)\s]+)\s+\(([^\(\)]+)\))(.*)$/) { # An address like foo@bar.com (Fooey Bar) push(@rv, [ $2, $3, $1 ]); $str = $4; } elsif ($str =~ /^[\s,]*("([^"]+)"\s*<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>\@]+)\s+<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>\@]+)<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>\[\]]+)\s+\[mailto:([^\s\[\]]+)\])(.*)$/|| $str =~ /^[\s,]*(()<([^<>,]+)>)(.*)/ || $str =~ /^[\s,]*(()([^\s<>,]+))(.*)/) { # Addresses like "Fooey Bar" # Fooey Bar # Fooey Bar # Fooey Bar [mailto:foo@bar.com] # # # foo@bar.com push(@rv, [ $3, $2 eq "," ? "" : $2, $1 ]); $str = $4; } else { last; } } return @rv; } # encode_base64(string) # Encodes a string into base64 format sub encode_base64 { local $res; pos($_[0]) = 0; # ensure start at the beginning while ($_[0] =~ /(.{1,57})/gs) { $res .= substr(pack('u57', $1), 1)."\n"; chop($res); } $res =~ tr|\` -_|AA-Za-z0-9+/|; local $padding = (3 - length($_[0]) % 3) % 3; $res =~ s/.{$padding}$/'=' x $padding/e if ($padding); return $res; } # guess_mime_type(filename) sub guess_mime_type { local ($file) = @_; return $file =~ /\.gif/i ? "image/gif" : $file =~ /\.(jpeg|jpg)/i ? "image/jpeg" : $file =~ /\.txt/i ? "text/plain" : $file =~ /\.(htm|html)/i ? "text/html" : $file =~ /\.doc/i ? "application/msword" : $file =~ /\.xls/i ? "application/vnd.ms-excel" : $file =~ /\.ppt/i ? "application/vnd.ms-powerpoint" : $file =~ /\.(mpg|mpeg)/i ? "video/mpeg" : $file =~ /\.avi/i ? "video/x-msvideo" : $file =~ /\.(mp2|mp3)/i ? "audio/mpeg" : $file =~ /\.wav/i ? "audio/x-wav" : "application/octet-stream"; } sub read_config_file { local %config; if (open(CONF, $_[0])) { while() { if (/^(\S+)=(.*)/) { $config{$1} = $2; } } close(CONF); } return %config; } # quoted_encode(text) # Encodes text to quoted-printable format sub quoted_encode { local $t = $_[0]; $t =~ s/([=\177-\377])/sprintf("=%2.2X",ord($1))/ge; return $t; } postfix/config.info.zh_TW.Big50000644000567100000120000000061511137644403016200 0ustar jcameronwheelpostfix_control_command= Postfix O|,0 postfix_config_command= Postfix պAO|,0 postfix_config_file= Postfix պAɪ|,0 postfix_aliases_table_command= Postfix OW͵{|,0 postfix_newaliases_command= "newaliases" (Sendmail ۮe) RO|,0 postfix_lookup_table_command= Postfix dߪ޲zO (`postmap') |,0 postfix/edit_access.cgi0000775000567100000120000000125211137644403015174 0ustar jcameronwheel#!/usr/local/bin/perl # edit_access.cgi # Display a form to edit a general access mapping table # by Roberto Tecchio, 2005 (www.tecchio.net) require './postfix-lib.pl'; $access{'smtpd'} || &error($text{'smtpd_ecannot'}); &ReadParse(); &ui_print_header(undef, $in{'title'}, ""); if (&get_current_value($in{'name'}) eq "") { print ($text{'no_map'}."

"); } else { &generate_map_edit($in{'name'}, $text{'map_click'}." ". "".&hlink("$text{'help_map_format'}", "access")."\n
\n", 1, $text{'mapping_client'}, $text{'header_value'}); } &ui_print_footer("smtpd.cgi", $text{'smtpd_title'}, "index.cgi", $text{'index_title'}); postfix/config.info.ru_RU0000664000567100000120000000124711137644403015420 0ustar jcameronwheelpostfix_lookup_table_command= Postfix (`postmap'),0 postfix_config_command= Postfix,0 line1= ,11 line2= ,11 postfix_newaliases_command= "newaliases" ( Sendmail),0 perpage= , ,0,6 max_records= ,0,6 postfix_aliases_table_command= Postfix,0 postfix_config_file= Postfix,0 postfix_control_command= Postfix,0 postfix/config.info.ja_JP.UTF-80000664000567100000120000000567611137644403016163 0ustar jcameronwheelline1=設定可能なオプション,11 perpage=1ページあたりのメールメッセージ表示数,0,6 wrap_width=メールメッセージの行送りする文字数,0 sort_mode=テーブルの並べ順,1,0-ファイル順,1-名前順 columns=エイリアスと他のテーブルの桁数,1,2-2,1-1 show_cmts=テーブルに説明を表示しますか?,1,1-はい,0-いいえ prefix_cmts=すべての説明の前に Webmin を追加しますか?,1,1-はい,0-いいえ mailq_sort=メイルキューの並び順,1,0-キューID,1-差出人アドレス,2-宛先アドレス,4-ステータス,5-サイズ mailq_count=メイルキューのサイズをメインページに表示しますか,1,0-はい,1-いいえ check_config=設定ファイル変更後にテストしますか?,1,1-はい,0-いいえ index_check=メインページでPostfixの設定をチェックしますか?,1,1-はい,0-いいえ line2=システム設定,11 postfix_control_command=Postfix制御コマンドのフルパス,0 postfix_config_command=Postfix設定コマンドのフルパス,0 postfix_config_file=Postfix設定ファイルのフルパス,0 postfix_master=Postfix master.cf ファイルのフルパス,0 postfix_aliases_table_command=Postfixエイリアス生成コマンドへのフルパス,0 postfix_newaliases_command="newaliases"(Sendmail compatibility)コマンドへのフルパス,0 postfix_lookup_table_command=Postfix ルックアップテーブルコマンド ('postmap')へのフルパス,0 postfix_queue_command=Postfix キュー管理コマンド('postqueue')へのフルパス,0 postfix_super_command=Postfix スーパバイザコマンド('postsuper')へのフルパス,0 mailq_dir=ディレクトリベースのメイルキュー,0 mailq_cmd=メイルキューの表示コマンド,0 postcat_cmd=メイルキューのデコードコマンド,0 start_cmd=Postfix 開始コマンド,3,制御コマンドを使う stop_cmd=Postfix 停止コマンド,3,制御コマンドを使う reload_cmd=Postfix 設定の適用コマンド,3,制御コマンドを使う line3=MySQL オプション,11 mysql_host=マップを編集する MySQL サーバ,3,Postfix 設定と同じ mysql_user=マップを編集する MySQL ユーザ,3,Postfix 設定と同じ mysql_pass=マップを編集する MySQL パスワード,3,Postfix 設定と同じ line4=LDAP オプション,11 ldap_host=マップを編集する LDAP サーバ,3,Postfix 設定と同じ ldap_user=マップを編集する LDAP ユーザ,3,Postfix 設定と同じ ldap_pass=マップを編集する LDAP パスワード,3,Postfix 設定と同じ ldap_class=マップのオブジェクトクラス,3,デフォルト (inetLocalMailRecipient) ldap_attrs=マップの他の LDAP 属性
(fieldname: value というフォーマット),9,40,3,\t ldap_id=マップのオブジェクトのキー属性,3,デフォルト (cn) ldap_doms=各ドメインに別々のDNを作成しますか?,1,1-はい,0-いいえ postfix/save_opts_transport.cgi0000755000567100000120000000177111137644403017051 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save Postfix options ; special because for transport tables require './postfix-lib.pl'; &ReadParse(); $access{'transport'} || &error($text{'transport_ecannot'}); # &ui_print_header(undef, $text{'opts_title'}, ""); &error_setup($text{'opts_err'}); &lock_postfix_files(); &before_save(); &save_options(\%in); &ensure_map("transport_maps"); &after_save(); &unlock_postfix_files(); ®enerate_transport_table(); &reload_postfix(); &webmin_log("transport"); &redirect(""); postfix/module.info0000644000567100000120000000135011137644405014400 0ustar jcameronwheelcategory=servers desc_ko_KR.euc=Postfix risk=low medium high desc_ru_SU= Postfix desc_tr=Postfix Yaplandrmas desc=Postfix Mail Server desc_pl=Konfiguracja Postfiksa desc_sv=Postfixinstllningar desc_de=Postfix-Konfiguration desc_es=Configuracin de Postfix desc_fr=Configuration de Postfix name=Postfix desc_ja_JP.euc=Postfix desc_zh_CN=Postfix desc_ru_RU= Postfix desc_ca=Servidor de Correu Postfix desc_zh_TW.Big5=Postfix պA longdesc=Configure the Postfix mail server. readonly=1 os_support=!windows desc_zh_TW.UTF-8=Postfix 組態 desc_zh_CN.UTF-8=Postfix 配置 desc_ja_JP.UTF-8=Postfix の設定 desc_ko_KR.UTF-8=Postfix 구성 desc_cz=Konfigurace Postfixu desc_nl=Postfix Mail Server version=1.451 postfix/bcc.cgi0000775000567100000120000000265611137644403013466 0ustar jcameronwheel#!/usr/local/bin/perl require './postfix-lib.pl'; $access{'bcc'} || &error($text{'bcc_ecannot'}); &ui_print_header(undef, $text{'bcc_title'}, "", "bcc"); &ReadParse(); # Start of BCC form print &ui_form_start("save_opts_bcc.cgi"); print &ui_table_start($text{'bcc_title'}, "width=100%", 2); &option_mapfield("sender_bcc_maps", 60); &option_mapfield("recipient_bcc_maps", 60); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'opts_save'} ] ]); # Map contents print &ui_hr(); print &ui_tabs_start([ [ "sender", $text{'bcc_sender'} ], [ "recipient", $text{'bcc_recipient'} ] ], "mode", $in{'mode'} || 'sender', 1); # Sender BCC maps print &ui_tabs_start_tab("mode", "sender"); print $text{'bcc_senderdesc'},"

\n"; if (&get_current_value("sender_bcc_maps") eq "") { print $text{'no_map'},"

\n"; } else { &generate_map_edit("sender_bcc_maps", $text{'map_click'}." ". &hlink($text{'help_map_format'}, "virtual")); } print &ui_tabs_end_tab("mode", "sender"); # Sender BCC maps print &ui_tabs_start_tab("mode", "recipient"); print $text{'bcc_recipientdesc'},"

\n"; if (&get_current_value("recipient_bcc_maps") eq "") { print $text{'no_map'},"

\n"; } else { &generate_map_edit("recipient_bcc_maps", $text{'map_click'}." ". &hlink($text{'help_map_format'}, "virtual")); } print &ui_tabs_end_tab("mode", "recipient"); print &ui_tabs_end(1); &ui_print_footer("", $text{'index_return'}); postfix/smtp.cgi0000755000567100000120000000360111137644403013707 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # A form for SMTP client parameters. # # << Here are all options seen in Postfix sample-smtp.cf >> require './postfix-lib.pl'; $access{'smtp'} || &error($text{'smtp_ecannot'}); &ui_print_header(undef, $text{'smtp_title'}, ""); $default = $text{'opts_default'}; $none = $text{'opts_none'}; $no_ = $text{'opts_no'}; # Start of form print &ui_form_start("save_opts.cgi"); print &ui_table_start($text{'smtp_title'}, "width=100%", 4); &option_radios_freefield("best_mx_transport", 25, $text{'opts_best_mx_transport_default'}); &option_radios_freefield("fallback_relay", 60, $default); &option_yesno("ignore_mx_lookup_error", 'help'); &option_yesno("smtp_skip_4xx_greeting", 'help'); &option_yesno("smtp_skip_quit_response", 'help'); &option_radios_freefield("smtp_destination_concurrency_limit", 15, $default); &option_radios_freefield("smtp_destination_recipient_limit", 15, $default); &option_freefield("smtp_connect_timeout", 15); &option_freefield("smtp_helo_timeout", 15); &option_freefield("smtp_mail_timeout", 15); &option_freefield("smtp_rcpt_timeout", 15); &option_freefield("smtp_data_init_timeout", 15); &option_freefield("smtp_data_xfer_timeout", 15); &option_freefield("smtp_data_done_timeout", 15); &option_freefield("smtp_quit_timeout", 15); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'opts_save'} ] ]); &ui_print_footer("", $text{'index_return'}); postfix/edit_canonical_mappings.cgi0000775000567100000120000000330411137644403017560 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Edit a mapping require './postfix-lib.pl'; &ReadParse(); &ui_print_header(undef, $text{'edit_mapping_title'}, ""); my $num; if (!exists($in{'num'})) { $num = &init_new_mapping(&get_current_value("sender_canonical_maps")); } else { $num = $in{'num'}; } my $mappingsaliases = &get_aliases(); my %alias; foreach $trans (@{$aliases}) { if ($trans->{'number'} == $num) { %alias = %{$trans}; } } print "

\n"; print "\n"; print "\n"; print "
$text{'edit_alias_title'}
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
$text{'aliases_name'} \n"; print ""; print "
$text{'aliases_value'} \n"; print "

\n"; print "\n"; print "

\n"; print &ui_hr(); print "
\n"; postfix/save_opts_canonical.cgi0000755000567100000120000000211011137644403016730 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save Postfix options ; special because for canonical tables require './postfix-lib.pl'; &ReadParse(); $access{'canonical'} || &error($text{'canonical_ecannot'}); # &ui_print_header(undef, $text{'opts_title'}, ""); &error_setup($text{'opts_err'}); &lock_postfix_files(); &before_save(); &save_options(\%in); &ensure_map("canonical_maps"); &ensure_map("recipient_canonical_maps"); &ensure_map("sender_canonical_maps"); &after_save(); &unlock_postfix_files(); ®enerate_canonical_table(); &reload_postfix(); &webmin_log("canonical"); &redirect(""); postfix/save_alias.cgi0000755000567100000120000000611311137644403015034 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save, modify, delete an alias for Postfix require './postfix-lib.pl'; &ReadParse(); $access{'aliases'} || &error($text{'aliases_ecannot'}); &error_setup($text{'alias_save_err'}); # Get the alias (if editing or deleting) @afiles = &get_aliases_files(&get_current_value("alias_maps")); @aliases = &list_postfix_aliases(); if (!$in{'new'}) { $a = $aliases[$in{'num'}]; } &lock_alias_files(\@afiles); if ($in{'delete'}) { # delete some alias &delete_postfix_alias($a); $loga = $a; } else { # saving or creating .. check inputs $in{'name'} =~ /^[^:@ ]+$/ || &error(&text('asave_eaddr', $in{'name'})); if ($in{'new'} || uc($a->{'name'}) ne uc($in{'name'})) { # is this name taken? for($i=0; $i<@aliases; $i++) { if (uc($in{'name'}) eq uc($aliases[$i]->{'name'})) { &error(&text('asave_ealready', $in{'name'})); } } } for($i=0; defined($t = $in{"type_$i"}); $i++) { $v = $in{"val_$i"}; $v =~ s/^\s+//; $v =~ s/\s+$//; if ($t == 1 && $v !~ /^(\S+)$/) { &error(&text('asave_etype1', $v)); } elsif ($t == 3 && $v !~ /^\/(\S+)$/) { &error(&text('asave_etype3', $v)); } elsif ($t == 4) { $v =~ /^(\S+)/ || &error($text{'asave_etype4none'}); -x $1 || &error(&text('asave_etype4', $1)); } elsif ($t == 5 && $v !~ /^\/(\S+)$/) { &error(&text('asave_etype5', $v)); } elsif ($t == 6 && $v !~ /^\/(\S+)$/) { &error(&text('asave_etype6', $v)); } if ($t == 1 || $t == 3) { push(@values, $v); } elsif ($t == 2) { push(@values, ":include:$v"); } elsif ($t == 4) { push(@values, "|$v"); } elsif ($t == 5) { # Setup autoreply script push(@values, "|$module_config_directory/autoreply.pl ". "$v $in{'name'}"); &system_logged("cp autoreply.pl $module_config_directory"); &system_logged("chmod 755 $module_config_directory/config"); } elsif ($t == 6) { # Setup filter script push(@values, "|$module_config_directory/filter.pl ". "$v $in{'name'}"); &system_logged("cp filter.pl $module_config_directory"); &system_logged("chmod 755 $module_config_directory/config"); } } $newa{'name'} = $in{'name'}; $newa{'values'} = \@values; if (defined($in{'cmt'})) { $newa{'cmt'} = $in{'cmt'}; } $newa{'enabled'} = $in{'enabled'}; if ($in{'new'}) { &create_postfix_alias(\%newa); } else { &modify_postfix_alias($a, \%newa); } $loga = \%newa; } &unlock_alias_files(\@afiles); # re-creates aliases database ®enerate_aliases(); &reload_postfix(); &webmin_log($in{'new'} ? 'create' : $in{'delete'} ? 'delete' : 'modify', 'alias', $loga->{'name'}, $loga); &redirect("aliases.cgi"); postfix/save_opts_body.cgi0000755000567100000120000000177011137644403015751 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save Postfix options ; special because for virtual tables require './postfix-lib.pl'; &ReadParse(); $access{'body'} || &error($text{'body_ecannot'}); &error_setup($text{'opts_err'}); &lock_postfix_files(); &before_save(); $in{'body_checks'} =~ /^(regexp|pcre):\/\S+$/ || &error($text{'body_eregexp'}); &save_options(\%in); &ensure_map("body_checks"); &after_save(); &unlock_postfix_files(); ®enerate_body_table(); &reload_postfix(); &webmin_log("body"); &redirect(""); postfix/save_opts_relocated.cgi0000755000567100000120000000177111137644403016757 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save Postfix options ; special because for relocated tables require './postfix-lib.pl'; &ReadParse(); $access{'relocated'} || &error($text{'relocated_ecannot'}); # &ui_print_header(undef, $text{'opts_title'}, ""); &error_setup($text{'opts_err'}); &lock_postfix_files(); &before_save(); &save_options(\%in); &ensure_map("relocated_maps"); &after_save(); &unlock_postfix_files(); ®enerate_relocated_table(); &reload_postfix(); &webmin_log("relocated"); &redirect(""); postfix/images/0000755000567100000120000000000011137644405013504 5ustar jcameronwheelpostfix/images/smtp.gif0000644000567100000120000000325511137644403015161 0ustar jcameronwheelGIF89a00:*}Е3"y`Srgx9){)X6%{'J̟ϰ v;&TTqz͡⭭H:*!L8(w- cܪїɲ]]}D6}}<-ffݶې1(Sqq͝- dՔ, `4$vG83%m6't1!u-%P@9`=5]>0ymm~u, ^, azsKDi7/X5$|[UvDM6&|9*w:){wv$M/'U3#zhe:.j9 n7+kujdW甔OHliiL?aWDB0f0'RVMz$H!,00H` $PA Ç# DĈ.>Fh`Ž(`݄ 6ܱtC3'T&!vhALU@ /Rq 8XbH yz#Lj-JD,6!aArAjĸ'8C*PJ3n]0 z^ >Ofƅ  LVGvrJtXRGܞkX&X p Dk;0`{R'Gv߁{O(ujXmgk‚EtO>؁':t҂a(b!0فb "L$a@(xDpk6Rc!яol!B(В p :BG`,CZ Ιi4 $'J@y f)F{ZM~F%pG&:)bFTigg@jfkJJkDʫ@k9 S= 0rZ+N-zmg.HnzDH ɶkIW@ژ  )79D,+`g\-(ܧ"$bE l ,B#Cܧ hQ<@l7i 8L7KiH1F4\wMXf 2ऱ^b*8 /0p5uGu 'G Ӌa? 40lrC .褏t*2Ҽ.T`y0 O8I`+l__KI@/|K_/J@;postfix/images/attach.gif0000644000567100000120000000011511137644403015432 0ustar jcameronwheelGIF89a +!, D zK4˪I1Չ '$&hg;postfix/images/master.gif0000644000567100000120000000346011137644403015467 0ustar jcameronwheelGIF89a00:*}~t@@@-'ߏ000``` kkk /"e9){ quPPP %%%UUU<4NNN]]]ppp HHHZN:*|v{B3...wwtʹjoG=$N!!!]\ӵk_[[[9*|;+~yhĨ===LLL.&Q(((fffou|||_R E|jz 444>0uHHJ}saUvvv趞K=24Bᰪ㩢KKK:::ҷwltn,-1"Icccptf`<-!(VˡBBB3%oz{WWWmp|89<6'u+++ӟTP⚛sssi[KAux###YV65?XK8(xPS^, ]ps|^`e益0ߨ7(vū!,00H*\Ȱ!A=#JHċ (A=rȒW0 ˗0c\ %Qtϟ@VJF_XӧMY(hȔJ@߰=qN ׳x {i`f>Zh۫)KM U*ػqsm Èo!hv2c&L ̟D!F ء 8Ui(@8bJ-@(HmB97(cF(0Z U(z% $@@P~c7瘖<! P!i'_>A<0 2l h(G<0@C2ZAv IxTC$`:B@sJud94q&F?(.v@ D6@Z\mĎ1@P@ y@@Dc,4 !GU - @HP5TAWh 3GHLDE,,F}!>,/Wh,B@dAלS(8 900 B<-q+X` w!lQ7@1T33M Y4qi>,C!9x| t",P&eHig@D&q9tD w% qu2C2z ?qDo|Fb1EdН& +5:aSHz @@1(dVi,$@P 5  (i>L ;postfix/images/ldap.gif0000644000567100000120000000333311137644403015113 0ustar jcameronwheelGIF89a001([2$k'UujbUfZ˼\\ʒ捄)Yނ|ke.&Tmm3%ni]þQJn警,$O|q%P/"e E88T9)zB:a;+~wr#H5&q$NL=AAa(Vrrqeyn?0ff͓!Fqk'TB3=.~6'tXJcWocUNq?7_91ZNNtKDiy1#i3+VRD◎TF!Hުc\}1(YtiDEf&J#LiiӅ{I:vk}}RR{pp+\#K-!a1$jǶYRtSSiJJnma, _nn̹І|OAODuuA?fccŒ+ ^р``(PPAwwӈF?e5-[ۜE9swl 0=*vB[tǔOE2m w@%+Z&$K}z&!L{U AYi;/v^>cT(7&SSc* dOgDO,Lm  b XG0BΜ \R " ̘C}hɆ0`W[POjXcM+` +L4@ xf<`w2]7,C%V5a/ Tn(QC Z喣.4azȁr n%;84xƨO*L@Gm 1K4/VPPw$TO23Hӏ/?88J*+kx@Ly;postfix/images/p1.gif0000644000567100000120000000006711137644403014514 0ustar jcameronwheelGIF89a !, Lf[ӵn;postfix/images/icon.gif0000644000567100000120000000346011137644403015124 0ustar jcameronwheelGIF89a00:*}~t@@@-'ߏ000``` kkk /"e9){ quPPP %%%UUU<4NNN]]]ppp HHHZN:*|v{B3...wwtʹjoG=$N!!!]\ӵk_[[[9*|;+~yhĨ===LLL.&Q(((fffou|||_R E|jz 444>0uHHJ}saUvvv趞K=24Bᰪ㩢KKK:::ҷwltn,-1"Icccptf`<-!(VˡBBB3%oz{WWWmp|89<6'u+++ӟTP⚛sssi[KAux###YV65?XK8(xPS^, ]ps|^`e益0ߨ7(vū!,00H*\Ȱ!A=#JHċ (A=rȒW0 ˗0c\ %Qtϟ@VJF_XӧMY(hȔJ@߰=qN ׳x {i`f>Zh۫)KM U*ػqsm Èo!hv2c&L ̟D!F ء 8Ui(@8bJ-@(HmB97(cF(0Z U(z% $@@P~c7瘖<! P!i'_>A<0 2l h(G<0@C2ZAv IxTC$`:B@sJud94q&F?(.v@ D6@Z\mĎ1@P@ y@@Dc,4 !GU - @HP5TAWh 3GHLDE,,F}!>,/Wh,B@dAלS(8 900 B<-q+X` w!lQ7@1T33M Y4qi>,C!9x| t",P&eHig@D&q9tD w% qu2C2z ?qDo|Fb1EdН& +5:aSHz @@1(dVi,$@P 5  (i>L ;postfix/images/bcc.gif0000755000567100000120000000527111137644403014730 0ustar jcameronwheelGIF89a00  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///111222333444555666777888999:::;;;<<<===???@@@BBBCCCDDDEEEFFFGGGHHHJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~! ,00 H*\(p1[r1cH0<]L1^`T@CYй3gPVJ53/[x\8 ;&-i֊ݲuɒ6n(ip?v`" m]m<82iIcQ^ZFΘY~#LBpN#U4nƏH{! ',X3^z2ɐ-Y$=j#eb.{ V>̑uLnj9N#1]~Y)MfiPC46v9GU'U~'4͟Wbc̜Ur(S,1cRN>PR >C-x#N>R(|2 ȱ(22 1SO7L8T0T"B`؁ 2 M6R;p'2Ģ;ti$K]\P2d$"qM4DN;׸2= 2+j=Xi*Z"0ntPydK*3N;ēO<,N9op2O} $#O=sN9r;A߄AH906O;s0pC=)62N=;Ù=4t7d 5霣O>`R0K,ʄ2 5sO>tE!X 5\8;q`J$t "l3p \KE$ˍ8 .1$/~ 3S1;lc0"*Q, A1>^r-J+ 3HbX̂ x /Ą #0V<> I #L6|J5+4 {Qτ@*_@'|$t=&%-X"t,F,J!|K t(6g+\ q1=r20.g3, <\+R^8"=ء!>P. H %`:P"p*4 \L"@=y p6 d@A1PUd!,i va Vp!p7drC^B$ /M H'rf́81(D&b R$a=$({hE/d'bc%D:!NĢ2 _ 񆎀"SE< }$Ax x \% O% G(a +C\ #$Є@ ;)h*laBh5p "ܠ ZA̱*` dT XG&@ ME$fx#@~7(a 8~;h p@/@ T;D!n8C $pXB&$P`AȀ!@., 8? `@!PKdwpCB G%@aPPD`p0PX-h NX` RpЅDatx/PSЁs@0$BFfT,dY@ O8 P JDb0z15X `C#l 6AC( 6`.WY;mU>!J'ڠ+ȁ+؃J77 !UBpL rkK .0q! 6*AT J `>C '"$PA5 ^ Đ&( C > &pH9 1@,H 4 3nh r`  0Ez`D-Nc V ׵WF p5s_uDb|0J/h6z|~}{tCfSil%oqd[3 Kg!?R&,LĂ wyɪ>ϖ$B25֥]xwf!()\n/ SHM`C>*D (&#XȊJܑR-G|$͛8s|ɳϞ ;postfix/images/general.gif0000644000567100000120000000276211137644403015615 0ustar jcameronwheelGIF89a00г{xتĻ|z޲tjܶϾϵpexo濺tkwn㖖뿻߳ۮzw쬧쏏򛒼͘øҜ⩩Ԉ~ݿщ}߰wtyRKn詢ȵ⯩zṹySKw잕nd߁wþ󥠶dW߁v뜕ፇ}rxw~{yocvlΑرų́vþ͚~{ӹ}z闗򮯬qfznzo¾Лka深½赮{yNFxۮ!,00H*\Ȱ!=#J`ċ E0A=r`Fvh˗^b͛8qB*ƁdT=!¡ѣ*U*GPJŊO`IWfK6 Z2dhX˶m[C\ ( K҅ 3sˍB#Glla.odM2BsO$hMb U\{f۸smD;Jfۖ@ +_μs4|N(Imp:|R; ӯKM p $ 6蠂x׎`SO-7w+9XAy7B P'eH"0(4xA aI/6 )DidY  . TViXfY"ލW3%$`0ڔ Ӊ:P\Rx|VfRPk"\E4裐F*U93n :̡:*uEj뭸k&$ 3k&̴ Icfvޝp") BVfwٺ;л(@, 3.P 7G\@LD3Ww oJsQ&TR'[D0,4l3%$(P@-D=41L7PG-,;postfix/images/local_delivery.gif0000644000567100000120000000447711137644403017202 0ustar jcameronwheelGIF89a00+ohfk㮭~~:*}ͽ`Uζkir|{瞙^UdXlc5$x}lh{r{{tj2!uSI}GELUSYɃytkff㖔tkC4űii^]ftr{kk]QF9̡܎zWJǍ|rˍmne_qqyoD5~cZ^Y;:>âtsj^rgxv|Ըi^UL[Qvtncuk}tZNUKrrtMAwuI;|{G9217赳簯UGpf̗[ONMP_S։/.0kljjnfxn328蘭RD8({ǭhg'%)XOj_MCxomv97;tmwwSFuszxտ!,00H*\Ȱ!A#JPċ (A=rȒ&;Lyq%K!O3H t2!.0J*G!1Ij 1gƪbAh'EGCeѐ!fUYENHȝȪ̚N LZ-.Ç!|5̸t3) ތXQ;/#"M"^Gf>h56i N ^ Ogvtc،Q$a<%ɘ4M@ )"hMDK-̨9'+Zf1D }n(qO_HGQ[%ЃC:(pA#0]PpAj r(#Cxa\x ? 8 +̅%R$S̍L!D DF‡((#..,I6`va"\#(!51p !8#.@M8\qרH&è< /QO蠈4x' 5 3pD ($J 4- ~AC bh뷐Faa %$A!ءAtsN'4z'SxI '|+ C2rAD2*IDJ hA XrHݎD?Z ..;W+WC PKA Ȕ `p(Up:P0a\x* 6 @B2 19}@G f\U۪m Î/TD 5 - a(+.'_KmRN*L:(+HXruӅ0r4Kgtt\@ PG6`#!*UK"@@!twp%@D`Ed;\n  # H*0`<t 8 A 387p&$aO΀AhE 2|Xi/P@$Cu@a2v Wp@4f6 hhNRC`m3pTG3ЌFd+8 Vq-,>ȇ- 0i L@B @ Ax mnT@*hhVCzaPd `HP.C؀N $# $S2#EkFL0  H@@"ش}DE`OFpJK@#b 6@ e X(A XB5HhA-ҚִF8 pֺV `O]K[ AjLd"( @b;postfix/images/rate.gif0000644000567100000120000000343511137644403015131 0ustar jcameronwheelGIF89a00Е9)z۫zrfrlzt^P<-;3[M?smzt:*}eY=5`i^e]VI4&q E杕2%m|YLF7D7zRF䩢aU6+h:*|㺴#J賭͡*ZE=dA27(v}rj^maYK&SZSz, ]"F¿;+~f[6*e𖏹2%fb\|D:nym㏋]Q=3huj{qKBp, `NFqRDUK}тxwlPBaVB9iQJn0#h`SPF}TF-!bMB{J;2$kvʷ6-a:,u/"eri8,l.!c?01&`ÿր{*!MUI/&Q4'k'KbXkbRF~tsi6'tti/"c؅|laOAQD$M¿0#gܡZQ{rLDo♐cVqhC4G9pd6.W~y?0{tjQCh^3(e2(aSKuohicgaLCtKAu8.fˏ!,00H*\Ȱ!RUvP㔒e4qNMCE.VP0K |Ԛ(NVIN{T LQA,FQ䡃4=h6!  /جP>RCoC%xZ J\` %w0B ALDtpN/kP}4F8%@DPB9 B‰5 D& $cӌA| 6<$$A"G$0 =dsKP@.N q`9x aV@29B*D8| Q " ҲnW}nAx4:@/' 8A2N*ǤDoHoD)Cr8HPH92S^ !Ԑ pB7 Tt}d@$s$ '!4|@)H> 3@"`l\@b(^d`̠7z@E6}(L WjF@8̡wW;postfix/images/body.gif0000664000567100000120000000337211137644403015135 0ustar jcameronwheelGIF89a0088L99N88O--D22K((<;;T::P<>ZSSuOOqEEcLLrFFkEE]33Nvvhhɣ``KKaXXk``u^^zPPrIImCCf--A**?QQsҪԟȦAA\MMeSSiWWk]]vHHgGGkHHo77M88WooҮفTTm^^qTTeIIcbbwXXn__yDDbIIp>>_EEjuuvvbbZZm^^sTTgOOaRRrPPdEE\EEi**@HHnddyyӦNNm^^tUUpHHZBBZMMgRRgMMfNNeEEgLLu77QMMviiFFaIIaRRm``sOOkEEUEEWSSl??SFFd22H@@_WWcc||BB[cczkkQQi??QGG`LLfTTrMMkHHiLLt--C77J66N88VTTjjjjEEaQQnLLhQQpUUxZZQQv00KAAd..B<>[;;[22M..G44O@@`EEh22J66P--F99W99X??`DDfCC`11I>>`CCh::X::WAAb==]IIo88RBBcIIlDDhNNtFF_88T,,@>>YCC[44G66J33G!Created with The GIMP! ,00 H*\Ȑ B<@+ 3Ə!GT_ 4pB |sf͛9R` 6pТG.m@!D Q )T`AjXfx#4jذqG;K.^||@B#H(YcȒ)[Ƭ3&N@"e *V\E˒өW~{vp 0bƐ)c 4jN8r̝CnM7ođ3N;wѳ{Aœ7^={P AR! "0? ( " 9#D"$PR%`&l‰!("&"y#"(R)*r<DJK,$R d%Zr%by-.</ 0" BpIxɧ 1@1r 2(: Z243pM4$O *** MCM5\M6`d+ڑAװ{,:i͢$I&QN0DM8i+QF!SZ[uUXcDU]y_ f~d]f%dJ2jlF=} Dw\r5\t=UT6_xw^z'7Wen[EA_x` v󏽆M;Ћ~%- $ph? c+=E$A&qo/Otf[vec?[rv#qTMsyg{@+r}1ֻo>餕s@S84#X:jjF-#5^lZÿk9XhKnfBtwzu!kG26N(9,蚎ީ@]!"+;όUۈ5 ¼(JH5M DH@;postfix/images/canonical.gif0000644000567100000120000000552411137644403016126 0ustar jcameronwheelGIF89a00ffkkᬫUUqھʛbU~}9){LLs33fͮɃddPPi!Gxuu㲬̕``|z2%khhJ?|Ϣ}}ᐐ00aQCʚ\\zCCrAAa$$Iwleez>=]9ؑԱcb**SttHHmZZjj֥=;m:2[ֹ^^5'rnnC4'S99cޓtt}CCi,,X½RR|قdd1(T//^XK|rOEypp!!AXX-!b︲ѼlcBBZeeUUbb̈zzſՌ88Zś냀uu88T\\D=czzssxx܊ZZsȨ[[7(vPPwʋSS~ŇyyppޠM?yw9+sJCigg) L~jfÕ;2`XTtqnqe]]>/77iֵIIv**DǾYSza_~ZQƚII`XX|uu|44g40Wg\\\66^Ѧ''Lϒ휜!,00H@5C7pHbA< v KXʼnN<Ȉcf#r =wulVQכ(4=yÃ)"-ăY'jjG >XdP|WS|Àdf9LA5pW [p?l&.Vjn̹n1hs p0Os @U`״@̄1B'' @6 @+1\;e8MBY4p (pF9& T"8[AIJ /09u 'SF 27e CyH~\0/S5a|0LX ~x(ghEU|@5\pq%Lln@aJ*Th*B0bdt*@U@0*d?(b@#B,F8B(Kp2?i0+/Slp9+AX& "T$[Ũt?0^ Y|,4q," $ ƘX@P$j ("V@9T a\JP&H; 6/ƈ0Ȑw@@3#Y$TB<&lbH&*1 k  %F I qH' 0HOB/A dpb=12D;0 b9O$4Xb)< !i(#"D` b `G x=(($ p(E)"q k$DYe`|>dPE iT` ),hTV 6 5tbRVdXF%d1X ЀG\,15XC,CVJM(]\q5V^!ZVr$\ \; p V\A5 p+㮉$`FA7 Pa ^6qC `Lx B`l& O4 E H!90]#ԣ !X DdX#̻A @0`vȄ|ء-p ]@\Lav}'UzY/Wa}8*>4hNl  `\@(*U%&5PZ8M÷ЁM|8L9Ƴ@iY act{V@XDWpb E/p5@7 mly.FpPN`8Ap1J$xVq1 Y r;h"na3h&46 G >أs8A altuz؆PA#<պv A@5%:5E a}TJ W}PbiXAD=h Q (1o.6ފy$WHG:Prt#8i7!@+Dw9:;postfix/images/client.gif0000755000567100000120000000446411137644403015462 0ustar jcameronwheelGIF89a00ƂƁ#,!Ћ͏*Г˜ܒ)͓5Ȗ-̓CȖ:͗&Û:  řKŝ0͝ОWܛΞ+לẸ'Ԣ9ТFأ)ΣMw)ϦCΨ:ԩ$ؤQʨmȨv*޲RׯWެbRղCҰg֬0۱PFմNͳ߷:H^ƷelͶߵx$7ؼ`Żd1޼BKKELYݿ$uUpo^YBǾkÈāƁzEɁUȾTˉpeτJmкDanӳMϝїӝ]Ҟ։ӈԪՋ_՘YؙفRuס֊}iڋU]ڪܤڦftm߈gޝvp߫xy! ,00 H*\ȰÇ#JH=yȱ#w1R.^0N1b#A0cʜDz&i˙3f̤ѣAI".;NI0ϝ;iݪE iPܜK'nдuKwY7mrWI3hО)V!klm^_oݥ ]8dАFt2d͚>]32P'Խ%߼GߺU呙gFLt؃ +W_W& 8& igmxV+ZfiX<2W;Z, =4`=4QFnic\r7ل6?4/MÏ?"?9x=-:ݢ9 *㠌O>d?*SOpC[ApQ'BR0<쓏=3;{ɣNꃏ?4*Y?AL%(`BIn՞HL(H7ܣO-F> A'PҊ0n|HI% UA &QN 2: D&8" %SPN/6@/8S 3S )TP4ң8L0@S<0J`C/T@U3M5\4$,.3H`A $[o7H:Σ p6(GM100L @ :H`\2(dp @%P \2Id.ڐ`<W<(7W|p#o6{RP*Q|8TC19A[ppͭnwV;postfix/images/smtpd.gif0000644000567100000120000000344411137644403015325 0ustar jcameronwheelGIF89a00Еff^^~ącc훠ddMMiNNm̮gg``ffeeddUUvvooWWQQ{DDciiƮhh}QQuʎgg[[hhyyeeuwvvMMru||zz]]}kxmmFFjOOvrrccюZZrs~~ffᚦƍmm\\ddllԤԶ^iMMnVVMMl{{KKqllbb采rrooˮaao{eq堠̗ZZVVrTTw~jt;;\NNn{{ho``gnppqq`kҹѠKKm^^PPq{ကۏ[[LLkPPkp}ttzzYYv[fgg\dV_ovjruεssee粲rrdd!,00H*$('J?[X`pL3j2ᄄ2FJ )l8Ja`Ȝ KA8ǕG`ɐ Fk4$0`,H 98x˅C֋#h@#C;+8 jj/)lF4JI B>,D# ;a@24>B G)B! j9l(!E6} !8q(Dn|Z;l `2LE=,nM@1)( "( t9M^7|@ $q@a" `|P:WgD#?,d83mx $ *@%;G.X 0%RO :,õB0xq-"@sSC2}4:lV0 fTE#4`ч؇- ($$?EEn))F!99^RR??dLLu::_CClZZ4TT*IIrkkBBiQQ66Y44Uxxqqbb((E''BOO{Ϗoo;;`EEl==d%%@MMxVVߘffvv((C0//NKKtLLwQQyyll77ZTT||nnYYee,,Ktt 7**G+2uu``'!!:NNy.!!9gg``ZZ^^1[[511R/,00HA pP4H  L A p` $@Abȍ(VPB.`@0Ɨ5l C)8(AK:0 |'  90:B"h`A YVHPN A X @M@ 8"+Th <82F2JU 4jPo7|:v֖8# 4h|:E>>dFQ+ 76!*P ES(aFGp '0 @)Hذ[ PpAJ(P!K\@A 8Є?R}@NE(DaQHpc#0'$ p54PE8ZqdaEZ, \pA{ T]$D TE_q`!c@elYAePi$D|W|AM̠k l!>T^|e 0~QGicylD]@A1AO(A!P1!Pt+Panцox j\F\5lDv{_"0qArsZP@E,t,QǠt!, U\4@a (C L@x4A ] r y@ %HDHqB{  +p؅[lAd@ "|`Сs}#Ae4. PXatin j8 l1C,0A MET̡@nz p`4 :Lc$!UAAVQX! x0( 8F* I=v@tK B n(A{Ca(7 ;L ua hH@< Y@;9`@4@6ЀC2p@5 v"Ơ)T Ex LPΆ04*+&Ԡf0b0+ @ .!@Jw'4a,EZ7( JxB4+nX:'8C]0 ("XG*/ P .6ΚAP&l ȍH[Bh.(aЅРB  P@s -.@Aq 4PQ5 l`)5J_ +Y ?:`0 n D$(0@4Vj'aY@Dp[0x@,|X@Ё}` % rP 1  () D"!Kh @!d#<` NEP :Іp>! z`•p#Q064[`), 5X@" j#DWLHpP A D&PC%d` '@,* 0̕@9HP-Р6Ai`6J8o=Ift+(hvs\n ~OH@#J[v@u-৴ ><%#hAd95OML0} " BAQA}﫞)(  x e԰A75!^CW>% 3P(Ԋ M JЀ%8 ox55P2l @;postfix/images/aliases.gif0000644000567100000120000000360411137644403015615 0ustar jcameronwheelGIF89a00Еw}<4x邈}uMB|bVjj"eF9\S<1jzr׹F9{$Y}XXzoaX㮲md_SRF\U|nfA5tpg򖖖A3y`Wu{߭x~wf]|ri_y}¾ѿx쀎cYưq𝠱Ͳ4)bicaW1#n1&`孰ڶԝ:.kߦᚚSHuj6'tPPxϚ񫯺\OꬦŢ²xwӕRIu, \D9q3)_䑑ddcZf][[QCJ=|}}OM~XMVVk_!,00H*\Ȱ!AuS@ŋ/9Á>ø ɓ(QjYI2Q @0E)OĜ9pA_,vhF Yr4BK4u:#tTU'WX9") zD X˞E[h۱BCMt&25;PVygO̙ ZvH!%5uk#װTt @LhvwQ%۫<4l}ūI 98 r-JZ04B9*M!k n{Ey'eS#BS Nv 1ռq"+qaOdhUBq1`E5)LTߍD XCd%9t!0 >) xAFzBN;yC6 ~I((*D6(& è@Lv5@5S qAd)h~` JHv/NuxQp*h.)@ ;!k 6PހvM K $R!0WaUh muV#} pdN r(| #0k9-0[P!`,l(Q "!0*371Ha1#q[TD[dɇQQ A hH;vAG -!g`r`^s 5CExMvP)CD  'SE|g񍍖/A L8 u@ !պBC#@&s |лF?PoA%RAx DC"AUAWϐ A!D( ÷ Y,@ Gz6']yW|W00P@B #p00b nHE3=4aB|p ! MBtia8B0$ 1 2I @2hLѨH:uFЁ IB;postfix/images/.xvpics/0000755000567100000120000000000011137644405015076 5ustar jcameronwheelpostfix/images/.xvpics/mailq.gif0000664000567100000120000000450111137644403016670 0ustar jcameronwheelP7 332 #IMGINFO:48x48 RGB (356 bytes) #END_OF_COMMENTS 48 48 255 I$II۶IH%I۶%HI%۶ڶ%HIIڶ%HII۶I$II۶I$II۶IH%I۶%HI%۶ڶ%HIIڶ%HII۶I$II۶I$II۶IH%I۶%HI%۶ڶ%HIIڶ%HII۶I$II۶I$I$II۶%H%I۶ڷ۶n]}]׺$IEHֻD)ID۶nn۶nn8]Y$I)Iֶֻ(EI)۶۷nڶ%HIIڶI$II۶۷mn~|^\kڶH%IIڷ%H%II$I۷mZ}n)Dۺ׶$II)ֶֻI$I۷ڷHI%IڷI$I۷۶%HI%۶ڶI$I۷۷۶۶۶ڷ$IH)ڶ۶۷$I)Iֶֻ$II)۶۷BD)IIֻDI)I۶۷ʩ=HE)Iڷ%HE)۶۷$۶$I%HI$I۷mے]]}E(IEۺI$I۷۶nnJnۺ+xrԎ(9nIRH(k|= 9d6Fݖ@ 9bđJ8%)4HsDՖ0龈BB:ABJ`HQ)L(#3̀rZ4a^1҅RH2>tC=E,$ DsXp aT'Ml`!k(c1?wH Ty!%dN$$0i ~4PKc!7t1$ _ܳ % j@!?7d n1/|ԥAD".,A. D@0@ PI%,A>K;%8( h@2< 89&""G6TQG'߶"."A! D A)"@.dEF6ȿD+0K4mq}"Mq=3D1 $<'fN9l:$BPL!;D-R320BW OAdmlM $Pr]wCt =}u.F$'7x/@5 `gkd褗n騧z;postfix/images/relocated.gif0000644000567100000120000000337111137644403016137 0ustar jcameronwheelGIF89a00Еffgg}񸸼kraaNNthhӑ99Uzz==Z22eey鞞TT~ֿᤤ%,ڜ nnIT\\YYqqDDf׼dd[\z^^eebbiiuJKϼllpprrhhssﵵjj}}QQyϙHHl[[ffEEh}~EE_kk򆆯{vvho@@[̃UUaauu lrѕ͂eeGG`[[uvmm֫ƪzzffjmuu}AA\PPQQhhoo``ۖx|CC``op>@߹Ȗ@@@@>G[[oll￿}ގjyd*-ccy%%!,00H*\Ȱ!Ak1ŋ3jȄ g(S\ɲ=_ 088b$@ur %AP+X̤K"t %E*Pք+1bX>={0ڶoJ]nT;/A'#Ԃ{,_L :s;q Ce$71cuOPQ8^cNVl ٸXך ޅ!-R1Y*̅M|pP]1 LGΡ/l9h:/A!BǾUG<([9+ZB$K|D X @@A7Vb B04á e4\Py,A;U؆", R4CEE@O'4Fa} ؂i@P5R<@CF<DJ T|@L^Gt@9 P?R;U*} TcPЦ $t 3zե57ch}V1F*t :۬hPD %Z)@k"ܚ+QPS*-#I o,e!´idcmP<^P/у*D @9Tk$*HJ pBk AB8p$lɴ^BI@ " b*O,0mєk}q#RS`D(Bo^}6pRW8JCO%36=+mh68DwXgڨ6XJCt@?@lz_(|32lXpBGr!t.lACãA2A)TPn )p?/T ]r)lCqP)T >&L$ /-r &2f^! L^dB`,s̠3 pa !;postfix/images/Image164.gif0000664000567100000120000001623111137644403015453 0ustar jcameronwheelGIF87a@ @ @@@@@``@``@@@@ @ @ @ @@ @ @ ` `@ ` ` @ @ @ @ @@@@@@ @ @@ @ @@@@@@@@@@`@`@@`@`@@@@@@@@@@@@@@@@@@@@``@``` ` @` ` `@`@@`@`@````@``````@````@````@````@``@ @ @@@@@``@``@@@@@ @ @@@@@``@``@@@@@ @ @@@@@``@``@@@@@ @ @@@@@``@``@@@@!,@ H*\ȰÇHHŋ3jQ# ;ns Ȓ;~˗0+vdP"UҬΐ>҈ĘHZ4Ҟ? &YWz+VY6l(Q lꑬҷ1צx]6fE SZ^w~ڏp3)3AX-ivl8k(`ˎM{m6/6|0빟BYYB'G<*qx侓IݤmدgǮ[m6@=㰷K-rnSxJ_uwr7V#%`Dfzfy UIWDeV)I'TqRJ` 瓃8樣ju^I﹗PMm iGbUM~V]j5Mޕ]IZyV}I:YxW^zG& "eBFb h5ٴp/1D ZvwN9VfIk'ȅXէn %Ev(*ƛtIv% Qti]Zv'j"ʞʦbIщX}҉"c=`Fw!fXbvWky*[ ߫z% 8`6c^'m`Ylmlj.nl,b%+V_ %S*\z)ʏ[<&ɺ,tDXv)L7t_VRXz$h?L,d?&8kL%ڔYhu-{N2M%W݀{-Mu֫aǝe^jPWޅڅmz~06bulCmׄfgYrU͙mX7yP i^fI^FyPE^|aN?ce~tA?SϷwպksͻS)̊r+ (vB'/P[\lli~ Gx{eœX?,_>0̡ lXF>l^"CR. l&..bJHEt,醧̋BcǘjtA#UH'$-)1'"׿zI೸ܑ3cTa%f#[W4%}fhtvă!"˭GI]$vT c<0A}[jDMV *A,0!hXMY%Y~hͣLǥO rBNr]ņ9uʙrӓC2ْ5H(Q̙ 1IŌDg M'CLzU= B/<DTL䓪)kCP{4bib0AȀ0IIp 0GLB#g.*ڪ8$2YO V}Zl;HZp5Q= wХjjNbUg52 kkUYK68eؘZVKEFoee.۰˼_NVcmD#n8`;GJ$d+tnyYKEҘin3Oc\̪2lx5J;gߟri+]U8GO:]R,-ʛ'po/x3GG`Jo3$4œCX&ݤ6 Ɵ)7m6yO6xnׄ^{nM,O܄7ee,{<ʼE=2R$(\Ev;V)̕+iI8Zx1" _G0:!/MN_:u໤dzֳZhyaI5#u^<yΨ/-+YI;3V٪>숔vlTK}EIl3iQ}@TGdacoFίc+Fu۔YH[5 ǎl$G 7FC3LpFշE3خK\rmĕ/ u5S")?>d'Ô0Ԩ97ӅqFAj9c},Rm51Oh&b)BlʚH(++&!A}ݕ-0slg!3XO &Gb^h 8 ͗+U|jyj78'Pޭ׮ɖ9)3wIk_xmcYcuHM FW|hWXAOaO3M}Q`|sscAUAY>Lv95+fWO%rTAŒXs 2:߃Hr9+dT_ǥq{ɃSvHLVd]"d6i9^gS:V8m_rfe9=9_?VXA!zTCs3,Ǟ9d8i2N*@B3d)lW(ʓ#_MbFgI2&!lGuGm;qW)>1A?nʆg~tN$J/^i?%7y3g6+hmClAxS<9d@WfFIZ|V{6i!"͇~aohfC?ԫiꪕ6f6jGqWcκڨcAC|q\+RyEՠk+ĤҚv*?(D@fGF_#9Z& 1*mdwJ=XyDקƁlQGW"Bߤv栓zldʨeB~{Ft&y$iԠq* J܆9dYj&&2met͗Gpjײ-Y=HTpAV8 TIJ,SGɵ~ 6^y[-Vq>Fwf+QjU 띄㖦c 87A{+n闛Xk^V)zW1ipOfYf=ar 8%R"+JsQUMi|55U8cc=9[!vT7~e@7`D 8ć8N H6wd{hyoBW[3fy5,+ȧ$eyCdUUv-rWK O k@at[8.X k|gzսB%>~a Y/*ѤRGxbC>@(|2s-*X3*)ҒCDuR{YPc%].Qw,8|-Ua@jl#: 3xˮ59{s<՗8X/{vh˳O_ :NUS9e:⸂7Bc;LpHG)"E 8L,J܂ Ʒ5!*OJ9c8^'7RyY{}x +v A]\ʺщ׌Su }Wm1UP,8vnZܶߵO)a}- Y>vn YKBa-Z(#5 y}uj hS^gs&.0ɪ.m}tf/wrqlXuhX<.#ۓcWF(~ВʔeUba^~I#V\)Qn`ۍ18M}[қ޿{HFqq=Is7iHPsގ {Kѳ)1ѳES朅:6$ HNK0\ib 36wějV.?1hH]fOD:,.C0-2@rI8\.ʜ6 4ltÍZ5u\  k:z;1ya5_bx *=|}V3 ujf=u7wK6?[?bC\q̩Rՠ,\YHT?Kg) CAlQ^Sh8ݓl<\=eO1O`!K@ Q#G>!$+^|@F$IR̘RcJ\| @B2ns%L=})!PCRliӊ6*teի~YRl+3,͉iݾ迏nMɔiS q յ(-|]$VMEiW\0%RYsϖjQC8eNx9ohY fZiM!S,`KcZ[xڙX{ջ8'tj(c]զ >\mjEj5#-7)//M$nR.40BO>j= CP(ZP["L%k2TLX:D#㲰 oT˦#j1?k 6&3 @363Hҳ-ʠl,@2)Ǭ@c3@l;FlQ8TSLמt̃ʥ3H5#8@2S)& *5bȸ5I_JbR$L C~dWRMǚnɈ Ve/F0eT]oQmk-ZR}"E.J%wҮ44,miOv=K®B\t+0}wŕƞ ˤ7~ŕO`D5X5]=Ԩ<(R j@cX=qZC> 4T,̙!Hq9#jtgZF /·ZiIiƊ.\i?L5C,ހWɵ0'-taE^*"WmJoǖ3M#UG;SyؽЭ/gF-wđ^lb'y+ϱ\K=[G=c\?/rsY-j|'3n97}o$ןhy7֘42_>=} ?QЃ׽T`@ V9NmSZfs!IxBO,,'VN1a +uP4 b ѓp/$b ЊWPE.vыɻ 9`xj11T:\#;postfix/images/transport.gif0000644000567100000120000000241311137644403016225 0ustar jcameronwheelGIF89a00P!m#?7_$M`쪤z{ǀvaܵv꫌Rznrl[N<7h<5`۱^?7a>,_˘8ҫaҌSF̷3%n?8_Њ1)TK4iΦƀ(Oճs>ϣN,%XۻWL ,!w$m"ʌbŁ[tС:*|֚]񜗭}O8pC9e"Ű˪p,Orܐ (Wʉƾ/o!FI?pRGaɋZIې4A2ՒWPsW-a%N{٢J=l!ɒ)=6_~=!,00H*\Ȱ!W#JpDċ  0A=rȒ&;Lyq%K._:)!͚7xcJIJIfO)HHJU&#K%bՆ ŠvÈ`BΑ(H(1m5$c'@ԉQ#T0 (50̹ T)! )qB?(Nm-!pS,-(W ;H8ȵ O,ν"hyq("̢FȜ7߇I$ߏߖR8F ("CMvB"]ZDQK 4 \!I0r4h8` 8KGDiF!<@." TVi}Ж#veB`(i#yҙhGYDx|'l\\dR&袌6($GVj饘f;postfix/images/p2.gif0000664000567100000120000000006711137644403014517 0ustar jcameronwheelGIF89a !, Lf[ӵn;postfix/images/manual.gif0000644000567100000120000000073611137644403015454 0ustar jcameronwheelGIF89a00ff̙ff̙̙33̙33f̙bbb!Made with GIMP!,00 dihjh.αj ~>RXÙ&he[XiFjWc{;9)nkQFlM#qWF5R/"+ld9CMxSQ }TZor jNdom mhuV1k Uvݪ,e{PL} ћ9$t㚻; "މ`9sň U@ ""J+Bqu| 1SNB7g(Ev:rn$CQʡXjʵׯ`ÊKٳ]C;postfix/images/debug.gif0000644000567100000120000000412711137644403015263 0ustar jcameronwheelGIF89a00Еړ@0>.]PþRD_RL>~VH@1_RI9B3XJzoE60vơ6&{洮Ka8D Y@*"bcK HCMҪMɜkQkX% E€߿hF`!<\"K\eΠZXigkb[hI"$r릔&@[ZrY GF |J%J8;F/ڊN5eZ h<#}G06 "a@ ! Gy! t!F`St',K!"A8b8q@A+‘Hp){ˆ#x1O̠LP`~YƠbbSƢÛo2 ty(}BWhN8FQ$0%egq-UtiE@]~Ā-h$ 4ì⠌U@R:%@HRoZӔ-@ T%FXK0HT BNF@`A֛$" +ːw 1]Ԡ…P pFF  ),r @[M)ŵ$lցG"Tܲb;<DK`H@FG DmG*a1E\w͵ dMFe}Mxc@U`tH&q@ሻD?2?ה'o/'g%M"-X̔ qrxlck'@ # ~;sTj!{1K1`A4< (a @^ $, f "2,A@%\RBtpJ.D!8$T` gH BA*p(@B5T"l 3%,| $2>8aC'PNh7 nAGʰtc&$ vo#~F^qCCX;`;#"*`;`I#߀E:0 H "8 1 YhA C-L!c p5<3p6 VGՄ l 8RXU HH& clTB9.Є)&0l`P8ɏ| H!\a53C%HIO!d!14~* @ЂP>x^G>ЀZXC>z;postfix/images/address_rewriting.gif0000644000567100000120000000455011137644403017714 0ustar jcameronwheelGIF89a00Е-t(WFNkC7z."dۃSEcjxr}QZ|5$z1#k񛔾γ͢=:hB3€>6^T]#K}\c|[e:*|yfqHPnlxma}sYc E{RYuICvLUu8(z~qvưܼ-!_iu6(u4&pL>u⍃=-jm½׽ࣝi]/(TₐĈbmy֭ؒ8(|ui1 wu{CCfw+(Po{訠XK:*~z1"x^PzaThsH9ms^iȖۊȇsvsqe6&vU\w>/KTsMTp{fYOXx4#yymdo畚䮷PXs{V`!G0,XJBl}PImzyJSqq{vr{9*}^UksY[TVt?3r;+~?CeX_z*"N]hӳܴwPA`g7'{˦ǀٚ!,00w`*\0 \JH0|ȑ:Lwp8fX!rR:ґ BCTW]">2AB\17#&B҆&, (R Pb(JH"扖qtgJn A9JUZ?Da*AʐQdV#倳 WPP(@Q'4A*L"sDFpqE$QA0#fQȃ)PG q1B nP]0mAF!Z+2OH#DDbx‡ A@(ZI׸@iB9[ApB,$E%sP.tC/q̰;eQ ݣB % !D1@ @rP`|*kPpR'Ђ)`=PTM.qA&M,PBXBPBi|C^ 1,A p,4.p|T|I)|F[pXH:,x}pLb|PCAt ] BY /d8;)p/I|Dܲ+T  @1g6p(DpR8 I,sb >! :% Y+ 7 ֵ@q "PXbp V'eo-E> " .h#g@@) 8 aMdxCrf5p0(b,$p 7", )8ъc~)) ( Ăa8'@*AD(NA4$X!c̱Ԫ(A< P+J '7,`-H#{!\ ], 3C0Z"|& ŅPN| ؂) i-2(ڀ4x:5P'6q EQP$Thp!qsf=\.7DlZL\k :P:'RW! E\ X@)WԃpS-@>hXG֚2! Gxт]E ALB+&@h@8l^ L )tΘV Ad-Ђ4B7":N(lg YE,"07^¬w?@DMI?J;|||-'⏓cUlll쮯hhhdddyiXXXPPP LLL57<\ODDD:::888444 -!b(((:*| 2+ RF[N, HA3*T(eÁ--\ŋ] Q!G C%$B6gF\rT `TP0 Jd [lY̎H9!J~Xj)$MEBq4%Cy= pZ`F'8) P+by+v Dmi! $ A0!Z4):@"iUS%ʑ@ *d$t)'` 5Y"C ~J[SYp0H.ka eR%p4kWP$AJ kA ACfJyD !bP$!NH cDZ 4٤(;postfix/images/resource.gif0000644000567100000120000000274311137644403016026 0ustar jcameronwheelGIF89a00EEEnnn@@@ꞞFFFUUUḸzzzz===檪:'qqq–]]]---~~~XaRRR9)&HHH{>1ꭡOOO666JJJGGGýK1111ʾєդ֐~uuucccꆆ 999iffŕӜDDD񑎍ҖڃpsM3GOlR[{q7*|9)worf57>eeeͽcn{ ²ͻLLL̕M>G7wg뮷ۧךL1?Fa_kVD@5;P~NQ_xMD3#͵otXXXegp***```elrsv06InG?U8חj`ꗅ"$*:@YtǽKMSH0R6``cxϿӌ(*0GGH뮠uZ%%%z5#h(Z#ԳYWV`FS#49OĿÛD,&˳2 89  :p(Q:g'%JBH ,T!D44Xƻ@} ,.pYB$C¡ "&Q ycM zQ3W.lPUhׂ 4B͜$yb@{$icFet\B~9QXTgC`qRo * c@T 0pmZ6Kg>*A)P]rVܚ)H{E#CHU A"p"vd1tû< @;x [/\SL<@8PQ?0AFpPNTqM˔KqJYD$l(22 4l8|?nHD@-Dml;postfix/aliases.cgi0000775000567100000120000000660011137644403014351 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Manages aliases for Postfix # # << Here are all options seen in Postfix sample-aliases.cf >> require './postfix-lib.pl'; $access{'aliases'} || &error($text{'aliases_ecannot'}); &ui_print_header(undef, $text{'aliases_title'}, "", "aliases"); # alias general options print "$text{'aliases_warning'}

\n"; print &ui_form_start("save_opts_aliases.cgi"); print &ui_table_start($text{'aliasopts_title'}, "width=100%", 2); # Aliases file &option_mapfield("alias_maps", 60); # Aliases DB? &option_mapfield("alias_database", 60); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'opts_save'} ] ]); print &ui_hr(); # double-table displaying all aliases my @aliases = &list_postfix_aliases(); if ($config{'sort_mode'} == 1) { @aliases = sort { lc($a->{'name'}) cmp lc($b->{'name'}) } @aliases; } # find a good place to split $lines = 0; for($i=0; $i<@aliases; $i++) { $aline[$i] = $lines; $al = scalar(@{$aliases[$i]->{'values'}}); $lines += ($al ? $al : 1); } $midline = int(($lines+1) / 2); for($mid=0; $mid<@aliases && $aline[$mid] < $midline; $mid++) { } # render tables print &ui_form_start("delete_aliases.cgi", "post"); @links = ( &select_all_link("d", 1), &select_invert_link("d", 1), "$text{'new_alias'}", ); print &ui_links_row(\@links); if ($config{'columns'} == 2) { @grid = ( ); push(@grid, &aliases_table(@aliases[0..$mid-1])); if ($mid < @aliases) { push(@grid, &aliases_table(@aliases[$mid..$#aliases])); } print &ui_grid_table(\@grid, 2, 100, [ "width=50%", "width=50%" ]); } else { print &aliases_table(@aliases); } print &ui_links_row(\@links); print &ui_form_end([ [ "delete", $text{'aliases_delete'} ] ]); # manual edit button if ($access{'manual'} && &can_map_manual($_[0])) { print &ui_hr(); print &ui_buttons_start(); print &ui_buttons_row("edit_manual.cgi", $text{'new_manual'}, $text{'new_manualmsg'}, &ui_hidden("map_name", "alias_maps")); print &ui_buttons_end(); } &ui_print_footer("", $text{'index_return'}); # aliases_table(&alias, ...) # Returns a table of aliases sub aliases_table { my @table; foreach my $a (@_) { my @cols; push(@cols, { 'type' => 'checkbox', 'name' => 'd', 'value' => $a->{'name'} }); push(@cols, "{'num'}\">". ($a->{'enabled'} ? "" : "").&html_escape($a->{'name'}). ($a->{'enabled'} ? "" : "").""); local $vstr; foreach $v (@{$a->{'values'}}) { ($anum, $astr) = &alias_type($v); $vstr .= &text("aliases_type$anum", "".&html_escape($astr)."")."
\n"; } $vstr ||= "$text{'aliases_none'}\n"; push(@cols, $vstr); push(@cols, &html_escape($a->{'cmt'})) if ($config{'show_cmts'}); push(@table, \@cols); } return &ui_columns_table( [ '', $text{'aliases_addr'}, $text{'aliases_to'}, $config{'show_cmts'} ? ( $text{'mapping_cmt'} ) : ( ) ], 100, \@table); } postfix/flushq.cgi0000775000567100000120000000100711137644403014226 0ustar jcameronwheel#!/usr/local/bin/perl # flushq.cgi # Run postqueue -f and display the output require './postfix-lib.pl'; &ui_print_unbuffered_header(undef, $text{'flushq_title'}, ""); $cmd = "$config{'postfix_queue_command'} -c $config_dir -f"; print &text('flushq_desc', "$cmd"),"
\n"; print "

";
&foreign_require("proc", "proc-lib.pl");
&foreign_call("proc", "safe_process_exec_logged", $cmd, 0, 0, STDOUT, undef, 1);
print "
\n"; &webmin_log("flushq"); &ui_print_footer("mailq.cgi", $text{'mailq_return'}); postfix/boxes-lib.pl0000775000567100000120000020206511137644403014470 0ustar jcameronwheel# boxes-lib.pl # Functions to parsing user mail files use POSIX; if ($userconfig{'date_tz'} || $config{'date_tz'}) { # Set the timezone for all date calculations, and force a conversion # now as in some cases the first one fails! $ENV{'TZ'} = $userconfig{'date_tz'} || $config{'date_tz'}; strftime('%H:%M', localtime(time())); } use Time::Local; $dbm_index_min = 1000000; $dbm_index_version = 3; # list_mails(user|file, [start], [end]) # Returns a subset of mail from a mbox format file sub list_mails { local (@rv, $h, $done); my %index; &build_dbm_index($_[0], \%index); local ($start, $end); local $isize = $index{'mailcount'}; if (@_ == 1 || !defined($_[1]) && !defined($_[2])) { $start = 0; $end = $isize-1; } elsif ($_[2] < 0) { $start = $isize+$_[2]-1; $end = $isize+$_[1]-1; $start = $start<0 ? 0 : $start; } else { $start = $_[1]; $end = $_[2]; $end = $isize-1 if ($end >= $isize); } $rv[$isize-1] = undef if ($isize); # force array to right size local $dash = &dash_mode($_[0]); open(MAIL, &user_mail_file($_[0])); $start = 0 if ($start < 0); for($i=$start; $i<=$end; $i++) { # Seek to mail position local @idx = split(/\0/, $index{$i}); local $pos = $idx[0]; local $startline = $idx[1]; seek(MAIL, $pos, 0); # Read the mail local $mail = &read_mail_fh(MAIL, $dash ? 2 : 1, 0); $mail->{'line'} = $startline; $mail->{'eline'} = $startline + $mail->{'lines'} - 1; $mail->{'idx'} = $i; # ID is position in file and message ID $mail->{'id'} = $pos." ".$i." ".$startline." ". substr($mail->{'header'}->{'message-id'}, 0, 255); $rv[$i] = $mail; } return @rv; } # select_mails(user|file, &ids, headersonly) # Returns a list of messages from an mbox with the given IDs. The ID contains # the file offset, message number, line and message ID, and the former is used # if valid. sub select_mails { local ($file, $ids, $headersonly) = @_; local @rv; local (@rv); my %index; local $gotindex; local $umf = &user_mail_file($file); local $dash = &dash_mode($umf); open(MAIL, $umf); foreach my $i (@$ids) { local ($pos, $idx, $startline, $wantmid) = split(/ /, $i); # Go to where the mail is supposed to be, and check if any starts there seek(MAIL, $pos, 0); local $ll = ; local $fromok = $ll !~ /^From\s+(\S+).*\d+\r?\n/ || ($1 eq '-' && !$dash) ? 0 : 1; print DEBUG "seeking to $pos in $umf, got $ll"; if (!$fromok) { # Oh noes! Need to find it if (!$gotindex++) { &build_dbm_index($file, \%index); } $pos = undef; while(my ($k, $v) = each %index) { if (int($k) eq $k) { my ($p, $line, $subject, $from, $mid)= split(/\0/, $v); if ($mid eq $wantmid) { # Found it! $pos = $p; $idx = $k; $startline = $line; last; } } } } if (defined($pos)) { # Now we can read seek(MAIL, $pos, 0); local $mail = &read_mail_fh(MAIL, $dash ? 2 : 1, $headersonly); $mail->{'line'} = $startline; $mail->{'eline'} = $startline + $mail->{'lines'} - 1; $mail->{'idx'} = $idx; $mail->{'id'} = "$pos $idx $startline $wantmid"; push(@rv, $mail); } else { push(@rv, undef); # Mail is gone? } } close(MAIL); return @rv; } # idlist_mails(user|file) # Returns a list of IDs in some mbox sub idlist_mails { my %index; local $idlist = &build_dbm_index($_[0], \%index); return @$idlist; } # search_mail(user, field, match) # Returns an array of messages matching some search sub search_mail { return &advanced_search_mail($_[0], [ [ $_[1], $_[2] ] ], 1); } # advanced_search_mail(user|file, &fields, andmode, [&limits], [headersonly]) # Returns an array of messages matching some search sub advanced_search_mail { local (%index, @rv, $i); local $dash = &dash_mode($_[0]); local @possible; # index positions of possible mails local $possible_certain = 0; # is possible list authoratative? local ($min, $max); # We have a DBM index .. if the search includes the from and subject # fields, scan it first to cut down on the total time &build_dbm_index($_[0], \%index); # Check which fields are used in search local @dbmfields = grep { $_->[0] eq 'from' || $_->[0] eq 'subject' } @{$_[1]}; local $alldbm = (scalar(@dbmfields) == scalar(@{$_[1]})); $min = 0; $max = $index{'mailcount'}-1; if ($_[3] && $_[3]->{'latest'}) { $min = $max - $_[3]->{'latest'}; } # Only check DBM if it contains some fields, and if it contains all # fields when in 'or' mode. if (@dbmfields && ($alldbm || $_[2])) { # Scan the DBM to build up a list of 'possibles' for($i=$min; $i<=$max; $i++) { local @idx = split(/\0/, $index{$i}); local $fake = { 'header' => { 'from', $idx[2], 'subject', $idx[3] } }; local $m = &mail_matches(\@dbmfields, $_[2], $fake); push(@possible, $i) if ($m); } $possible_certain = $alldbm; } else { # None of the DBM fields are in the search .. have to scan all @possible = ($min .. $max); } # Need to scan through possible messages to find those that match open(MAIL, &user_mail_file($_[0])); local $headersonly = !&matches_needs_body($_[1]); foreach $i (@possible) { # Seek to mail position local @idx = split(/\0/, $index{$i}); local $pos = $idx[0]; local $startline = $idx[1]; seek(MAIL, $pos, 0); # Read the mail local $mail = &read_mail_fh(MAIL, $dash ? 2 : 1, $headersonly); $mail->{'line'} = $startline; $mail->{'eline'} = $startline + $mail->{'lines'} - 1; $mail->{'idx'} = $i; $mail->{'id'} = $pos." ".$i." ".$startline." ". substr($mail->{'header'}->{'message-id'}, 0, 255); push(@rv, $mail) if ($possible_certain || &mail_matches($_[1], $_[2], $mail)); } return @rv; } # build_dbm_index(user|file, &index) # Updates a reference to a DBM hash that indexes the given mail file. # Hash contains keys 0, 1, 2 .. each of which has a value containing the # position of the mail in the file, line number, subject, sender and message ID. # Special key lastchange = time index was last updated # mailcount = number of messages in index # version = index format version # Returns a list of all IDs sub build_dbm_index { local $ifile = &user_index_file($_[0]); local $umf = &user_mail_file($_[0]); local @st = stat($umf); local $index = $_[1]; dbmopen(%$index, $ifile, 0600); # Read file of IDs local $idsfile = $ifile.".ids"; local @ids; local $idschanged; if (open(IDSFILE, $idsfile)) { @ids = ; chop(@ids); close(IDSFILE); } if (scalar(@ids) != $index->{'mailcount'}) { # Build for first time print DEBUG "need meta-index rebuild for $_[0] ",scalar(@ids)," != ",$index->{'mailcount'},"\n"; @ids = ( ); while(my ($k, $v) = each %$index) { if ($k eq int($k) && $k < $index->{'mailcount'}) { local ($pos, $line, $subject, $sender, $mid) = split(/\0/, $v); $ids[$k] = $pos." ".$k." ".$line." ".$mid; } elsif ($k >= $index->{'mailcount'}) { # Old crap that is off the end delete($index->{$k}); } } $index->{'mailcount'} = scalar(@ids); # Now known for sure $idschanged = 1; } if (!@st || $index->{'lastchange'} < $st[9] || $index->{'lastsize'} != $st[7] || $st[7] < $dbm_index_min || $index->{'version'} != $dbm_index_version) { # The mail file is newer than the index, or we are always re-indexing local $fromok = 1; local ($ll, @idx); local $dash = &dash_mode($umf); if ($st[7] < $dbm_index_min || $index->{'version'} != $dbm_index_version) { $fromok = 0; # Always re-index open(MAIL, $umf); } else { if (open(MAIL, $umf)) { # Check the last 100 messages (at most), to see if # the mail file has been truncated, had mails deleted, # or re-written. local $il = $index->{'mailcount'}-1; local $i; for($i=($il>100 ? 100 : $il); $i>=0; $i--) { @idx = split(/\0/, $index->{$il-$i}); seek(MAIL, $idx[0], 0); $ll = ; $fromok = 0 if ($ll !~ /^From\s+(\S+).*\d+\r?\n/ || ($1 eq '-' && !$dash)); } } else { $fromok = 0; # No mail file yet } } local ($pos, $lnum, $istart); if ($index->{'mailcount'} && $fromok && $st[7] > $idx[0]) { # Mail file seems to have gotten bigger, most likely # because new mail has arrived ... only reindex the new mails print DEBUG "re-indexing from $idx[0]\n"; $pos = $idx[0] + length($ll); $lnum = $idx[1] + 1; $istart = $index->{'mailcount'}; } else { # Mail file has changed in some other way ... do a rebuild # of the whole index print DEBUG "totally re-indexing\n"; $istart = 0; $pos = 0; $lnum = 0; seek(MAIL, 0, 0); @ids = ( ); $idschanged = 1; %$index = ( ); } local ($doingheaders, @nidx); while() { if (/^From\s+(\S+).*\d+\r?\n/ && ($1 ne '-' || $dash)) { @nidx = ( $pos, $lnum ); $idschanged = 1; push(@ids, $pos." ".$istart." ".$lnum); $index->{$istart++} = join("\0", @nidx); $doingheaders = 1; } elsif ($_ eq "\n" || $_ eq "\r\n") { $doingheaders = 0; } elsif ($doingheaders && /^From:\s*(.{0,255})/i) { $nidx[2] = $1; $index->{$istart-1} = join("\0", @nidx); } elsif ($doingheaders && /^Subject:\s*(.{0,255})/i) { $nidx[3] = $1; $index->{$istart-1} = join("\0", @nidx); } elsif ($doingheaders && /^Message-ID:\s*(.{0,255})/i) { $nidx[4] = $1; $index->{$istart-1} = join("\0", @nidx); $ids[$#ids] .= " ".$1; } $pos += length($_); $lnum++; } close(MAIL); $index->{'lastchange'} = time(); $index->{'lastsize'} = $st[7]; $index->{'mailcount'} = $istart; $index->{'version'} = $dbm_index_version; } # Write out IDs file, if needed if ($idschanged) { open(IDSFILE, ">$idsfile"); foreach my $id (@ids) { print IDSFILE $id,"\n"; } close(IDSFILE); } return \@ids; } # has_dbm_index(user|file) # Returns 1 if a DBM index exists for some user or file sub has_dbm_index { local $ifile = &user_index_file($_[0]); foreach my $ext (".dir", ".pag", ".db") { return 1 if (-r $ifile.$ext); } return 0; } # empty_mail(user|file) # Truncate a mail file to nothing sub empty_mail { local $umf = &user_mail_file($_[0]); local $ifile = &user_index_file($_[0]); open(TRUNC, ">$umf"); close(TRUNC); # Set index size to 0 local %index; dbmopen(%index, $ifile, 0600); $index{'mailcount'} = 0; $index{'lastchange'} = time(); dbmclose(%index); } # count_mail(user|file) # Returns the number of messages in some mail file sub count_mail { my %index; &build_dbm_index($_[0], \%index); return $index{'mailcount'}; } # parse_mail(&mail, [&parent], [savebody], [keep-cr]) # Extracts the attachments from the mail body sub parse_mail { return if ($_[0]->{'parsed'}++); local $ct = $_[0]->{'header'}->{'content-type'}; local (@attach, $h, $a); if ($ct =~ /multipart\/(\S+)/i && ($ct =~ /boundary="([^"]+)"/i || $ct =~ /boundary=([^;\s]+)/i)) { # Multipart MIME message local $bound = "--".$1; local @lines = $_[3] ? split(/\n/, $_[0]->{'body'}) : split(/\r?\n/, $_[0]->{'body'}); local $l; local $max = @lines; while($l < $max && $lines[$l++] ne $bound) { # skip to first boundary } while(1) { # read attachment headers local (@headers, $attach); while($lines[$l]) { $attach->{'raw'} .= $lines[$l]."\n"; $attach->{'rawheaders'} .= $lines[$l]."\n"; if ($lines[$l] =~ /^(\S+):\s*(.*)/) { push(@headers, [ $1, $2 ]); } elsif ($lines[$l] =~ /^\s+(.*)/) { $headers[$#headers]->[1] .= $1 unless($#headers < 0); } $l++; } $attach->{'raw'} .= $lines[$l]."\n"; $l++; $attach->{'headers'} = \@headers; foreach $h (@headers) { $attach->{'header'}->{lc($h->[0])} = $h->[1]; } if ($attach->{'header'}->{'content-type'} =~ /^([^;]+)/) { $attach->{'type'} = lc($1); } else { $attach->{'type'} = 'text/plain'; } if ($attach->{'header'}->{'content-disposition'} =~ /filename\s*=\s*"([^"]+)"/i) { $attach->{'filename'} = $1; } elsif ($attach->{'header'}->{'content-disposition'} =~ /filename\s*=\s*([^;\s]+)/i) { $attach->{'filename'} = $1; } elsif ($attach->{'header'}->{'content-type'} =~ /name\s*=\s*"([^"]+)"/i) { $attach->{'filename'} = $1; } # read the attachment body while($l < $max && $lines[$l] ne $bound && $lines[$l] ne "$bound--") { $attach->{'data'} .= $lines[$l]."\n"; $attach->{'raw'} .= $lines[$l]."\n"; $l++; } $attach->{'data'} =~ s/\n\n$/\n/; # Lose trailing blank line $attach->{'raw'} =~ s/\n\n$/\n/; # decode if necessary if (lc($attach->{'header'}->{'content-transfer-encoding'}) eq 'base64') { # Standard base64 encoded attachment $attach->{'data'} = &b64decode($attach->{'data'}); } elsif (lc($attach->{'header'}->{'content-transfer-encoding'}) eq 'x-uue') { # UUencoded attachment $attach->{'data'} = &uudecode($attach->{'data'}); } elsif (lc($attach->{'header'}->{'content-transfer-encoding'}) eq 'quoted-printable') { # Quoted-printable text attachment $attach->{'data'} = "ed_decode($attach->{'data'}); } elsif (lc($attach->{'type'}) eq 'application/mac-binhex40' && &has_command("hexbin")) { # Macintosh binhex encoded attachment local $temp = &transname(); mkdir($temp, 0700); open(HEXBIN, "| (cd $temp ; hexbin -n attach -d 2>/dev/null)"); print HEXBIN $attach->{'data'}; close(HEXBIN); if (!$?) { open(HEXBIN, "$temp/attach.data"); local $/ = undef; $attach->{'data'} = ; close(HEXBIN); local $ct = &guess_mime_type($attach->{'filename'}); $attach->{'type'} = $ct; $attach->{'header'} = { 'content-type' => $ct }; $attach->{'headers'} = [ [ 'Content-Type', $ct ] ]; } unlink("$temp/attach.data"); rmdir($temp); } $attach->{'idx'} = scalar(@attach); $attach->{'parent'} = $_[1] ? $_[1] : $_[0]; push(@attach, $attach) if (@headers || $attach->{'data'}); if ($attach->{'type'} =~ /multipart\/(\S+)/i) { # This attachment contains more attachments .. # expand them. local $amail = { 'header' => $attach->{'header'}, 'body' => $attach->{'data'} }; &parse_mail($amail, $attach, 0, $_[3]); $attach->{'attach'} = [ @{$amail->{'attach'}} ]; map { $_->{'idx'} += scalar(@attach) } @{$amail->{'attach'}}; push(@attach, @{$amail->{'attach'}}); } elsif (lc($attach->{'type'}) eq 'application/ms-tnef') { # This attachment is a winmail.dat file, which may # contain multiple other attachments! local ($opentnef, $tnef); if (!($opentnef = &has_command("opentnef")) && !($tnef = &has_command("tnef"))) { $attach->{'error'} = "tnef command not installed"; } else { # Can actually decode local $tempfile = &transname(); open(TEMPFILE, ">$tempfile"); print TEMPFILE $attach->{'data'}; close(TEMPFILE); local $tempdir = &transname(); mkdir($tempdir, 0700); if ($opentnef) { system("$opentnef -d $tempdir -i $tempfile >/dev/null 2>&1"); } else { system("$tnef -C $tempdir -f $tempfile >/dev/null 2>&1"); } pop(@attach); # lose winmail.dat opendir(DIR, $tempdir); while($f = readdir(DIR)) { next if ($f eq '.' || $f eq '..'); local $data; open(FILE, "$tempdir/$f"); while() { $data .= $_; } close(FILE); local $ct = &guess_mime_type($f); push(@attach, { 'type' => $ct, 'idx' => scalar(@attach), 'header' => { 'content-type' => $ct }, 'headers' => [ [ 'Content-Type', $ct ] ], 'filename' => $f, 'data' => $data }); } closedir(DIR); unlink(glob("$tempdir/*"), $tempfile); rmdir($tempdir); } } last if ($l >= $max || $lines[$l] eq "$bound--"); $l++; } $_[0]->{'attach'} = \@attach; } elsif ($_[0]->{'body'} =~ /begin\s+([0-7]+)\s+(.*)/i) { # Message contains uuencoded file(s) local @lines = split(/\n/, $_[0]->{'body'}); local ($attach, $rest); foreach $l (@lines) { if ($l =~ /^begin\s+([0-7]+)\s+(.*)/i) { $attach = { 'type' => &guess_mime_type($2), 'idx' => scalar(@{$_[0]->{'attach'}}), 'parent' => $_[1], 'filename' => $2 }; push(@{$_[0]->{'attach'}}, $attach); } elsif ($l =~ /^end/ && $attach) { $attach = undef; } elsif ($attach) { $attach->{'data'} .= unpack("u", $l); } else { $rest .= $l."\n"; } } if ($rest =~ /\S/) { # Some leftover text push(@{$_[0]->{'attach'}}, { 'type' => "text/plain", 'idx' => scalar(@{$_[0]->{'attach'}}), 'parent' => $_[1], 'data' => $rest }); } } elsif (lc($_[0]->{'header'}->{'content-transfer-encoding'}) eq 'base64') { # Signed body section $ct =~ s/;.*$//; $_[0]->{'attach'} = [ { 'type' => lc($ct), 'idx' => 0, 'parent' => $_[1], 'data' => &b64decode($_[0]->{'body'}) } ]; } elsif (lc($_[0]->{'header'}->{'content-type'}) eq 'x-sun-attachment') { # Sun attachment format, which can contain several sections local $sun; foreach $sun (split(/----------/, $_[0]->{'body'})) { local ($headers, $rest) = split(/\r?\n\r?\n/, $sun, 2); local $attach = { 'idx' => scalar(@{$_[0]->{'attach'}}), 'parent' => $_[1], 'data' => $rest }; if ($headers =~ /X-Sun-Data-Name:\s*(\S+)/) { $attach->{'filename'} = $1; } if ($headers =~ /X-Sun-Data-Type:\s*(\S+)/) { local $st = $1; $attach->{'type'} = $st eq "text" ? "text/plain" : $st eq "html" ? "text/html" : $st =~ /\// ? $st : "application/octet-stream"; } elsif ($attach->{'filename'}) { $attach->{'type'} = &guess_mime_type($attach->{'filename'}); } else { $attach->{'type'} = "text/plain"; # fallback } push(@{$_[0]->{'attach'}}, $attach); } } else { # One big attachment (probably text) local ($type, $body); ($type = $ct) =~ s/;.*$//; $type = 'text/plain' if (!$type); if (lc($_[0]->{'header'}->{'content-transfer-encoding'}) eq 'base64') { $body = &b64decode($_[0]->{'body'}); } elsif (lc($_[0]->{'header'}->{'content-transfer-encoding'}) eq 'quoted-printable') { $body = "ed_decode($_[0]->{'body'}); } else { $body = $_[0]->{'body'}; } $_[0]->{'attach'} = [ { 'type' => lc($type), 'idx' => 0, 'parent' => $_[1], 'data' => $body } ]; } delete($_[0]->{'body'}) if (!$_[2]); } # delete_mail(user|file, &mail, ...) # Delete mail messages from a user by copying the file and rebuilding the index sub delete_mail { # Validate messages local @m = sort { $a->{'line'} <=> $b->{'line'} } @_[1..@_-1]; foreach my $m (@m) { defined($m->{'line'}) && defined($m->{'eline'}) && $m->{'eline'} > $m->{'line'} || &error("Message to delete is invalid, perhaps to due to ". "out-of-date index"); } local $i = 0; local $f = &user_mail_file($_[0]); local $ifile = &user_index_file($_[0]); local $lnum = 0; local (%dline, @fline); local ($dpos = 0, $dlnum = 0); local (@index, %index); &build_dbm_index($_[0], \%index); local $tmpf = $< == 0 ? "$f.del" : $_[0] =~ /^\/.*\/([^\/]+)$/ ? "$user_module_config_directory/$1.del" : "$user_module_config_directory/$_[0].del"; open(SOURCE, $f) || &error("Read failed : $!"); open(DEST, ">$tmpf") || &error("Open of $tmpf failed : $!"); while() { if ($i >= @m || $lnum < $m[$i]->{'line'}) { # Within a range that we want to preserve $dpos += length($_); $dlnum++; local $w = (print DEST $_); if (!$w) { local $e = "$!"; close(DEST); close(SOURCE); unlink($tmpf); &error("Write to $tmpf failed : $e"); } } elsif (!$fline[$i]) { # Start line of a message to delete if (!/^From\s/) { # Not actually a message! Fail now close(DEST); close(SOURCE); unlink($tmpf); &error("Index on $f is corrupt - did not find expected mesage start at line $lnum"); } $fline[$i] = 1; } elsif ($lnum == $m[$i]->{'eline'}) { # End line of the current message to delete $dline{$m[$i]->{'line'}}++; $i++; } $lnum++; } close(SOURCE); close(DEST) || &error("Write to $tmpf failed : $?"); local @st = stat($f); unlink($f) if ($< == 0); # Force a total index re-build (XXX lazy!) $index{'mailcount'} = $in{'lastchange'} = 0; dbmclose(%index); if ($< == 0) { rename($tmpf, $f); } else { system("cat ".quotemeta($tmpf)." > ".quotemeta($f). " && rm -f ".quotemeta($tmpf)); } chown($st[4], $st[5], $f); chmod($st[2], $f); } # modify_mail(user|file, old, new, textonly) # Modify one email message in a mailbox by copying the file and rebuilding # the index. sub modify_mail { local $f = &user_mail_file($_[0]); local $ifile = &user_index_file($_[0]); local $lnum = 0; local ($sizediff, $linesdiff); local %index; &build_dbm_index($_[0], \%index); # Replace the email that gets modified local $tmpf = $< == 0 ? "$f.del" : $_[0] =~ /^\/.*\/([^\/]+)$/ ? "$user_module_config_directory/$1.del" : "$user_module_config_directory/$_[0].del"; open(SOURCE, $f); open(DEST, ">$tmpf"); while() { if ($lnum < $_[1]->{'line'} || $lnum > $_[1]->{'eline'}) { # before or after the message to change local $w = (print DEST $_); if (!$w) { local $e = "$?"; close(DEST); close(SOURCE); unlink($tmpf); &error("Write to $tmpf failed : $e"); } } elsif ($lnum == $_[1]->{'line'}) { # found start of message to change .. put in the new one close(DEST); local @ost = stat($tmpf); local $nlines = &send_mail($_[2], $tmpf, $_[3], 1); local @nst = stat($tmpf); local $newsize = $nst[7] - $ost[7]; $sizediff = $newsize - $_[1]->{'size'}; $linesdiff = $nlines - ($_[1]->{'eline'} - $_[1]->{'line'} + 1); open(DEST, ">>$tmpf"); } $lnum++; } close(SOURCE); close(DEST) || &error("Write failed : $!"); # Now update the index and delete the temp file for($i=0; $i<$index{'mailcount'}; $i++) { local @idx = split(/\0/, $index{$i}); if ($idx[1] > $_[1]->{'line'}) { $idx[0] += $sizediff; $idx[1] += $linesdiff; $index{$i} = join("\0", @idx); } } $index{'lastchange'} = time(); local @st = stat($f); unlink($f); if ($< == 0) { rename($tmpf, $f); } else { system("cat $tmpf >$f && rm -f $tmpf"); } chown($st[4], $st[5], $f); chmod($st[2], $f); } # send_mail(&mail, [file], [textonly], [nocr], [smtp-server], # [smtp-user], [smtp-pass], [smtp-auth-mode], # [¬ify-flags], [port]) # Send out some email message or append it to a file. # Returns the number of lines written. sub send_mail { return 0 if (&is_readonly_mode()); local (%header, $h); local $lnum = 0; local $sm = $_[4] || $config{'send_mode'}; local $eol = $_[3] || !$sm ? "\n" : "\r\n"; local $port = $_[9] || $config{'smtp_port'} || 25; foreach $h (@{$_[0]->{'headers'}}) { $header{lc($h->[0])} = $h->[1]; } # Add the date header, always in english &clear_time_locale(); local @tm = localtime(time()); push(@{$_[0]->{'headers'}}, [ 'Date', strftime("%a, %d %b %Y %H:%M:%S %z (%Z)", @tm) ]) if (!$header{'date'}); &reset_time_locale(); local @from = &address_parts($header{'from'}); local $fromaddr; if (@from && $from[0] =~ /\S/) { $fromaddr = $from[0]; } else { local @uinfo = getpwuid($<); $fromaddr = $uinfo[0] || "nobody"; $fromaddr .= '@'.&get_system_hostname(); } local $esmtp = $_[8] ? 1 : 0; if ($_[1]) { # Just append the email to a file using mbox format open(MAIL, ">>$_[1]") || &error("Write failed : $!"); $lnum++; print MAIL $_[0]->{'fromline'} ? $_[0]->{'fromline'}.$eol : &make_from_line($fromaddr).$eol; } elsif ($sm) { # Connect to SMTP server &open_socket($sm, $port, MAIL); &smtp_command(MAIL); if ($esmtp) { &smtp_command(MAIL, "ehlo ".&get_system_hostname()."\r\n"); } else { &smtp_command(MAIL, "helo ".&get_system_hostname()."\r\n"); } # Get username and password from parameters, or from module config local $user = $_[5] || $userconfig{'smtp_user'} || $config{'smtp_user'}; local $pass = $_[6] || $userconfig{'smtp_pass'} || $config{'smtp_pass'}; local $auth = $_[7] || $userconfig{'smtp_auth'} || $config{'smtp_auth'} || "Cram-MD5"; if ($user) { # Send authentication commands eval "use Authen::SASL"; if ($@) { &error("Perl module Authen::SASL is needed for SMTP authentication"); } my $sasl = Authen::SASL->new('mechanism' => uc($auth), 'callback' => { 'auth' => $user, 'user' => $user, 'pass' => $pass } ); &error("Failed to create Authen::SASL object") if (!$sasl); local $conn = $sasl->client_new("smtp", &get_system_hostname()); local $arv = &smtp_command(MAIL, "auth $auth\r\n", 1); if ($arv =~ /^(334)\s+(.*)/) { # Server says to go ahead $extra = $2; local $initial = $conn->client_start(); local $auth_ok; if ($initial) { local $enc = &encode_base64($initial); $enc =~ s/\r|\n//g; $arv = &smtp_command(MAIL, "$enc\r\n", 1); if ($arv =~ /^(\d+)\s+(.*)/) { if ($1 == 235) { $auth_ok = 1; } else { &error("Unknown SMTP authentication response : $arv"); } } $extra = $2; } while(!$auth_ok) { local $message = &decode_base64($extra); local $return = $conn->client_step($message); local $enc = &encode_base64($return); $enc =~ s/\r|\n//g; $arv = &smtp_command(MAIL, "$enc\r\n", 1); if ($arv =~ /^(\d+)\s+(.*)/) { if ($1 == 235) { $auth_ok = 1; } elsif ($1 == 535) { &error("SMTP authentication failed : $arv"); } $extra = $2; } else { &error("Unknown SMTP authentication response : $arv"); } } } } &smtp_command(MAIL, "mail from: <$fromaddr>\r\n"); local $notify = $_[8] ? " NOTIFY=".join(",", @{$_[8]}) : ""; local $u; foreach $u (&address_parts($header{'to'}.",".$header{'cc'}. ",".$header{'bcc'})) { &smtp_command(MAIL, "rcpt to: <$u>$notify\r\n"); } &smtp_command(MAIL, "data\r\n"); } elsif (defined(&send_mail_program)) { # Use specified mail injector local $cmd = &send_mail_program($fromaddr); $cmd || &error("No mail program was found on your system!"); open(MAIL, "| $cmd >/dev/null 2>&1"); } elsif ($config{'qmail_dir'}) { # Start qmail-inject open(MAIL, "| $config{'qmail_dir'}/bin/qmail-inject"); } elsif ($config{'postfix_control_command'}) { # Start postfix's sendmail wrapper local $cmd = -x "/usr/lib/sendmail" ? "/usr/lib/sendmail" : &has_command("sendmail"); $cmd || &error($text{'send_ewrapper'}); open(MAIL, "| $cmd -t -f$fromaddr >/dev/null 2>&1"); } else { # Start sendmail &has_command($config{'sendmail_path'}) || &error(&text('send_epath', "$config{'sendmail_path'}")); open(MAIL, "| $config{'sendmail_path'} -t -f$fromaddr >/dev/null 2>&1"); } local $ctype = "multipart/mixed"; local $msg_id; foreach $h (@{$_[0]->{'headers'}}) { if (defined($_[0]->{'body'}) || $_[2]) { print MAIL $h->[0],": ",$h->[1],$eol; $lnum++; } else { if ($h->[0] !~ /^(MIME-Version|Content-Type)$/i) { print MAIL $h->[0],": ",$h->[1],$eol; $lnum++; } elsif (lc($h->[0]) eq 'content-type') { $ctype = $h->[1]; } } if (lc($h->[0]) eq 'message-id') { $msg_id++; } } if (!$msg_id) { # Add a message-id header if missing $main::mailboxes_message_id_count++; print MAIL "Message-Id: <",time().".".$$.".". $main::mailboxes_message_id_count."\@". &get_system_hostname(),">",$eol; } # Work out first attachment content type local ($ftype, $fenc); if (@{$_[0]->{'attach'}} >= 1) { local $first = $_[0]->{'attach'}->[0]; $ftype = "text/plain"; foreach my $h (@{$first->{'headers'}}) { if (lc($h->[0]) eq "content-type") { $ftype = $h->[1]; } if (lc($h->[0]) eq "content-transfer-encoding") { $fenc = $h->[1]; } } } if (defined($_[0]->{'body'})) { # Use original mail body print MAIL $eol; $lnum++; $_[0]->{'body'} =~ s/\r//g; $_[0]->{'body'} =~ s/\n\.\n/\n\. \n/g; $_[0]->{'body'} =~ s/\n/$eol/g; $_[0]->{'body'} .= $eol if ($_[0]->{'body'} !~ /\n$/); (print MAIL $_[0]->{'body'}) || &error("Write failed : $!"); $lnum += ($_[0]->{'body'} =~ tr/\n/\n/); } elsif (!$_[2] || $ftype !~ /text\/plain/i || $fenc =~ /quoted-printable|base64/) { # Sending MIME-encoded email if ($ctype !~ /multipart\/report/i) { $ctype =~ s/;.*$//; } print MAIL "MIME-Version: 1.0",$eol; local $bound = "bound".time(); print MAIL "Content-Type: $ctype; boundary=\"$bound\"",$eol; print MAIL $eol; $lnum += 3; # Send attachments print MAIL "This is a multi-part message in MIME format.",$eol; $lnum++; foreach $a (@{$_[0]->{'attach'}}) { print MAIL $eol; print MAIL "--",$bound,$eol; $lnum += 2; local $enc; foreach $h (@{$a->{'headers'}}) { print MAIL $h->[0],": ",$h->[1],$eol; $enc = $h->[1] if (lc($h->[0]) eq 'content-transfer-encoding'); $lnum++; } print MAIL $eol; $lnum++; if (lc($enc) eq 'base64') { local $enc = &encode_base64($a->{'data'}); $enc =~ s/\r//g; $enc =~ s/\n/$eol/g; print MAIL $enc; $lnum += ($enc =~ tr/\n/\n/); } else { $a->{'data'} =~ s/\r//g; $a->{'data'} =~ s/\n\.\n/\n\. \n/g; $a->{'data'} =~ s/\n/$eol/g; print MAIL $a->{'data'}; $lnum += ($a->{'data'} =~ tr/\n/\n/); if ($a->{'data'} !~ /\n$/) { print MAIL $eol; $lnum++; } } } print MAIL $eol; (print MAIL "--",$bound,"--",$eol) || &error("Write failed : $!"); print MAIL $eol; $lnum += 3; } else { # Sending text-only mail from first attachment local $a = $_[0]->{'attach'}->[0]; print MAIL $eol; $lnum++; $a->{'data'} =~ s/\r//g; $a->{'data'} =~ s/\n/$eol/g; (print MAIL $a->{'data'}) || &error("Write failed : $!"); $lnum += ($a->{'data'} =~ tr/\n/\n/); if ($a->{'data'} !~ /\n$/) { print MAIL $eol; $lnum++; } } if ($sm && !$_[1]) { &smtp_command(MAIL, ".$eol"); &smtp_command(MAIL, "quit$eol"); } if (!close(MAIL)) { # Only bother to report an error on close if writing to a file if ($_[1]) { &error("Write failed : $!"); } } return $lnum; } # mail_size(&mail, [textonly]) # Returns the size of an email message in bytes sub mail_size { local ($mail, $textonly) = @_; local $temp = &transname(); &send_mail($mail, $temp, $textonly); local @st = stat($temp); unlink($temp); return $st[7]; } # b64decode(string) # Converts a string from base64 format to normal sub b64decode { local($str) = $_[0]; local($res); $str =~ tr|A-Za-z0-9+=/||cd; $str =~ s/=+$//; $str =~ tr|A-Za-z0-9+/| -_|; while ($str =~ /(.{1,60})/gs) { my $len = chr(32 + length($1)*3/4); $res .= unpack("u", $len . $1 ); } return $res; } # can_read_mail(user) sub can_read_mail { return 1 if ($_[0] && $access{'sent'} eq $_[0]); local @u = getpwnam($_[0]); return 0 if (!@u); return 0 if ($_[0] =~ /\.\./); return 0 if ($access{'mmode'} == 0); return 1 if ($access{'mmode'} == 1); local $u; if ($access{'mmode'} == 2) { foreach $u (split(/\s+/, $access{'musers'})) { return 1 if ($u eq $_[0]); } return 0; } elsif ($access{'mmode'} == 4) { return 1 if ($_[0] eq $remote_user); } elsif ($access{'mmode'} == 5) { return $u[3] eq $access{'musers'}; } elsif ($access{'mmode'} == 3) { foreach $u (split(/\s+/, $access{'musers'})) { return 0 if ($u eq $_[0]); } return 1; } elsif ($access{'mmode'} == 6) { return ($_[0] =~ /^$access{'musers'}$/); } elsif ($access{'mmode'} == 7) { return (!$access{'musers'} || $u[2] >= $access{'musers'}) && (!$access{'musers2'} || $u[2] <= $access{'musers2'}); } return 0; # can't happen! } # from_hostname() sub from_hostname { local ($d, $masq); local $conf = &get_sendmailcf(); foreach $d (&find_type("D", $conf)) { if ($d->{'value'} =~ /^M\s*(\S*)/) { $masq = $1; } } return $masq ? $masq : &get_system_hostname(); } # mail_from_queue(qfile, [dfile|"auto"]) # Reads a message from the Sendmail mail queue sub mail_from_queue { local $mail = { 'file' => $_[0] }; $mail->{'quar'} = $_[0] =~ /\/hf/; $mail->{'lost'} = $_[0] =~ /\/Qf/; if ($_[1] eq "auto") { $mail->{'dfile'} = $_[0]; $mail->{'dfile'} =~ s/\/(qf|hf|Qf)/\/df/; } elsif ($_[1]) { $mail->{'dfile'} = $_[1]; } $mail->{'lfile'} = $_[0]; $mail->{'lfile'} =~ s/\/(qf|hf|Qf)/\/xf/; local $_; local @headers; open(QF, $_[0]) || return undef; while() { s/\r|\n//g; if (/^M(.*)/) { $mail->{'status'} = $1; } elsif (/^H\?[^\?]*\?(\S+):\s+(.*)/ || /^H(\S+):\s+(.*)/) { push(@headers, [ $1, $2 ]); $mail->{'rawheaders'} .= "$1: $2\n"; } elsif (/^\s+(.*)/) { $headers[$#headers]->[1] .= $1 unless($#headers < 0); $mail->{'rawheaders'} .= $_."\n"; } } close(QF); $mail->{'headers'} = \@headers; foreach $h (@headers) { $mail->{'header'}->{lc($h->[0])} = $h->[1]; } if ($mail->{'dfile'}) { # Read the mail body open(DF, $mail->{'dfile'}); while() { $mail->{'body'} .= $_; } close(DF); } local $datafile = $mail->{'dfile'}; if (!$datafile) { ($datafile = $mail->{'file'}) =~ s/\/(qf|hf|Qf)/\/df/; } local @st0 = stat($mail->{'file'}); local @st1 = stat($datafile); $mail->{'size'} = $st0[7] + $st1[7]; return $mail; } # wrap_lines(text, width) # Given a multi-line string, return an array of lines wrapped to # the given width sub wrap_lines { local @rv; local $w = $_[1]; foreach $rest (split(/\n/, $_[0])) { if ($rest =~ /\S/) { while($rest =~ /^(.{1,$w}\S*)\s*([\0-\377]*)$/) { push(@rv, $1); $rest = $2; } } else { # Empty line .. keep as it is push(@rv, $rest); } } return @rv; } # smtp_command(handle, command, no-error) sub smtp_command { local ($m, $c) = @_; print $m $c; local $r = <$m>; if ($r !~ /^[23]\d+/ && !$_[2]) { &error(&text('send_esmtp', "".&html_escape($c)."", "".&html_escape($r)."")); } $r =~ s/\r|\n//g; if ($r =~ /^(\d+)\-/) { # multi-line ESMTP response! while(1) { local $nr = <$m>; $nr =~ s/\r|\n//g; if ($nr =~ /^(\d+)\-(.*)/) { $r .= "\n".$2; } elsif ($nr =~ /^(\d+)\s+(.*)/) { $r .= "\n".$2; last; } } } return $r; } # address_parts(string) # Returns the email addresses in a string sub address_parts { local @rv; local $rest = $_[0]; while($rest =~ /([^<>\s,'"\@]+\@[A-z0-9\-\.\!]+)(.*)/) { push(@rv, $1); $rest = $2; } return wantarray ? @rv : $rv[0]; } # link_urls(text, separate) sub link_urls { local $r = $_[0]; local $tar = $_[1] ? "target=link".int(rand()*100000) : ""; $r =~ s/((http|ftp|https|mailto):[^><"'\s]+[^><"'\s\.\)])/$1<\/a>/g; return $r; } # link_urls_and_escape(text, separate) # HTML escapes some text, as well as properly linking URLs in it sub link_urls_and_escape { local $l = $_[0]; local $rv; local $tar = $_[1] ? " target=link".int(rand()*100000) : ""; while($l =~ /^(.*?)((http|ftp|https|mailto):[^><"'\s]+[^><"'\s\.\)])(.*)/) { local ($before, $url, $after) = ($1, $2, $4); $rv .= &eucconv_and_escape($before)."". &html_escape($url).""; $l = $after; } $rv .= &eucconv_and_escape($l); return $rv; } # uudecode(text) sub uudecode { local @lines = split(/\n/, $_[0]); local ($l, $data); for($l=0; $lines[$l] !~ /begin\s+([0-7]+)\s/i; $l++) { } while($lines[++$l]) { $data .= unpack("u", $lines[$l]); } return $data; } # simplify_date(datestring) # Given a date from an email header, convert to the user's preferred format sub simplify_date { local $u = &parse_mail_date($_[0]); if ($u) { local $fmt = $userconfig{'date_fmt'} || $config{'date_fmt'} || "dmy"; local $strf = $fmt eq "dmy" ? "%d/%m/%Y" : $fmt eq "mdy" ? "%m/%d/%Y" : "%Y/%m/%d"; return strftime("$strf %H:%M", localtime($u)); } elsif ($_[0] =~ /^(\S+),\s+0*(\d+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+)/) { return "$2/$3/$4 $5:$6"; } elsif ($_[0] =~ /^0*(\d+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+)/) { return "$1/$2/$3 $4:$5"; } return $_[0]; } # simplify_from(from) # Simplifies a From: address for display in the mail list. Only the first # address is returned. sub simplify_from { local $rv = &eucconv(&decode_mimewords($_[0])); local @sp = &split_addresses($rv); if (!@sp) { return $text{'mail_nonefrom'}; } else { local $first = &html_escape($sp[0]->[1] ? $sp[0]->[1] : $sp[0]->[2]); if (length($first) > 80) { return substr($first, 0, 80)." .."; } else { return $first.(@sp > 1 ? " , ..." : ""); } } } # simplify_subject(subject) # Simplifies and truncates a subject for display in the mail list sub simplify_subject { local $rv = &eucconv(&decode_mimewords($_[0])); $rv = substr($rv, 0, 80)." .." if (length($rv) > 80); return &html_escape($rv); } # quoted_decode(text) # Converts quoted-printable format to the original sub quoted_decode { local $t = $_[0]; $t =~ s/[ \t]+?(\r?\n)/$1/g; $t =~ s/=\r?\n//g; $t =~ s/(^|[^\r])\n\Z/$1\r\n/; $t =~ s/=([a-fA-F0-9]{2})/pack("c",hex($1))/ge; return $t; } # quoted_encode(text) # Encodes text to quoted-printable format sub quoted_encode { local $t = $_[0]; $t =~ s/([=\177-\377])/sprintf("=%2.2X",ord($1))/ge; return $t; } # decode_mimewords(string) # Converts a string in MIME words format like # =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= to actual 8-bit characters sub decode_mimewords { my $encstr = shift; my %params = @_; my @tokens; $@ = ''; ### error-return ### Collapse boundaries between adjacent encoded words: $encstr =~ s{(\?\=)\r?\n[ \t](\=\?)}{$1$2}gs; pos($encstr) = 0; ### print STDOUT "ENC = [", $encstr, "]\n"; ### Decode: my ($charset, $encoding, $enc, $dec); while (1) { last if (pos($encstr) >= length($encstr)); my $pos = pos($encstr); ### save it ### Case 1: are we looking at "=?..?..?="? if ($encstr =~ m{\G # from where we left off.. =\?([^?]*) # "=?" + charset + \?([bq]) # "?" + encoding + \?([^?]+) # "?" + data maybe with spcs + \?= # "?=" }xgi) { ($charset, $encoding, $enc) = ($1, lc($2), $3); $dec = (($encoding eq 'q') ? _decode_Q($enc) : _decode_B($enc)); push @tokens, [$dec, $charset]; next; } ### Case 2: are we looking at a bad "=?..." prefix? ### We need this to detect problems for case 3, which stops at "=?": pos($encstr) = $pos; # reset the pointer. if ($encstr =~ m{\G=\?}xg) { $@ .= qq|unterminated "=?..?..?=" in "$encstr" (pos $pos)\n|; push @tokens, ['=?']; next; } ### Case 3: are we looking at ordinary text? pos($encstr) = $pos; # reset the pointer. if ($encstr =~ m{\G # from where we left off... ([\x00-\xFF]*? # shortest possible string, \n*) # followed by 0 or more NLs, (?=(\Z|=\?)) # terminated by "=?" or EOS }xg) { length($1) or die "MIME::Words: internal logic err: empty token\n"; push @tokens, [$1]; next; } ### Case 4: bug! die "MIME::Words: unexpected case:\n($encstr) pos $pos\n\t". "Please alert developer.\n"; } return join('',map {$_->[0]} @tokens); } # _decode_Q STRING # Private: used by _decode_header() to decode "Q" encoding, which is # almost, but not exactly, quoted-printable. :-P sub _decode_Q { my $str = shift; $str =~ s/_/\x20/g; # RFC-1522, Q rule 2 $str =~ s/=([\da-fA-F]{2})/pack("C", hex($1))/ge; # RFC-1522, Q rule 1 $str; } # _decode_B STRING # Private: used by _decode_header() to decode "B" encoding. sub _decode_B { my $str = shift; &decode_base64($str); } # encode_mimewords(string, %params) # Converts a word with 8-bit characters to MIME words format sub encode_mimewords { my ($rawstr, %params) = @_; my $charset = $params{Charset} || 'ISO-8859-1'; my $encoding = lc($params{Encoding} || 'q'); my $NONPRINT = "\\x00-\\x1F\\x7F-\\xFF"; if ($rawstr =~ /^[\x20-\x7E]*$/) { # No encoding needed return $rawstr; } ### Encode any "words" with unsafe characters. ### We limit such words to 18 characters, to guarantee that the ### worst-case encoding give us no more than 54 + ~10 < 75 characters my $word; $rawstr =~ s{([ a-zA-Z0-9\x7F-\xFF]{1,18})}{ ### get next "word" $word = $1; (($word !~ /(?:[$NONPRINT])|(?:^\s+$)/o) ? $word ### no unsafe chars : encode_mimeword($word, $encoding, $charset)); ### has unsafe chars }xeg; $rawstr =~ s/\?==\?/?= =?/g; return $rawstr; } # encode_mimeword(string, [encoding], [charset]) # Converts a word with 8-bit characters to MIME words format sub encode_mimeword { my $word = shift; my $encoding = uc(shift || 'Q'); my $charset = uc(shift || 'ISO-8859-1'); my $encfunc = (($encoding eq 'Q') ? \&_encode_Q : \&_encode_B); return "=?$charset?$encoding?" . &$encfunc($word) . "?="; } # _encode_Q STRING # Private: used by _encode_header() to decode "Q" encoding, which is # almost, but not exactly, quoted-printable. :-P sub _encode_Q { my $str = shift; my $NONPRINT = "\\x00-\\x1F\\x7F-\\xFF"; $str =~ s{([ _\?\=$NONPRINT])}{sprintf("=%02X", ord($1))}eog; return $str; } # _encode_B STRING # Private: used by _decode_header() to decode "B" encoding. sub _encode_B { my $str = shift; my $enc = &encode_base64($str); $enc =~ s/\n//; return $enc; } # user_mail_file(user|file, [other details]) sub user_mail_file { if ($_[0] =~ /^\//) { return $_[0]; } elsif ($config{'mail_dir'}) { return &mail_file_style($_[0], $config{'mail_dir'}, $config{'mail_style'}); } elsif (@_ > 1) { return "$_[7]/$config{'mail_file'}"; } else { local @u = getpwnam($_[0]); return "$u[7]/$config{'mail_file'}"; } } # mail_file_style(user, basedir, style) sub mail_file_style { if ($_[2] == 0) { return "$_[1]/$_[0]"; } elsif ($_[2] == 1) { return $_[1]."/".substr($_[0], 0, 1)."/".$_[0]; } elsif ($_[2] == 2) { return $_[1]."/".substr($_[0], 0, 1)."/". substr($_[0], 0, 2)."/".$_[0]; } else { return $_[1]."/".substr($_[0], 0, 1)."/". substr($_[0], 1, 1)."/".$_[0]; } } # user_index_file(user|file) sub user_index_file { local $us = $_[0]; $us =~ s/\//_/g; local $f; local $hn = &get_system_hostname(); if ($_[0] =~ /^\/.*\/([^\/]+)$/) { # A file .. the index file is in ~/.usermin/mailbox or # /etc/webmin/mailboxes if ($user_module_config_directory && $config{'shortindex'}) { # Use short name for index file $f = "$user_module_config_directory/$1.findex"; } else { $f = $user_module_config_directory ? "$user_module_config_directory/$us.findex" : "$module_config_directory/$us.findex"; } } else { # A username .. the index file is in /etc/webmin/mailboxes $f = $user_module_config_directory ? "$user_module_config_directory/$_[0].index" : "$module_config_directory/$_[0].index"; } return -r $f && !-r "$f.$hn" ? $f : "$f.$hn"; } # extract_mail(data) # Converts the text of a message into mail object. sub extract_mail { local $text = $_[0]; $text =~ s/^\s+//; local ($amail, @aheaders, $i); local @alines = split(/\n/, $text); while($i < @alines && $alines[$i]) { if ($alines[$i] =~ /^(\S+):\s*(.*)/) { push(@aheaders, [ $1, $2 ]); $amail->{'rawheaders'} .= $alines[$i]."\n"; } elsif ($alines[$i] =~ /^\s+(.*)/) { $aheaders[$#aheaders]->[1] .= $1 unless($#aheaders < 0); $amail->{'rawheaders'} .= $alines[$i]."\n"; } $i++; } $amail->{'headers'} = \@aheaders; foreach $h (@aheaders) { $amail->{'header'}->{lc($h->[0])} = $h->[1]; } splice(@alines, 0, $i); $amail->{'body'} = join("\n", @alines)."\n"; return $amail; } # split_addresses(string) # Splits a comma-separated list of addresses into [ email, real-name, original ] # triplets sub split_addresses { local (@rv, $str = $_[0]); while(1) { if ($str =~ /^[\s,]*(([^<>\(\)\s]+)\s+\(([^\(\)]+)\))(.*)$/) { # An address like foo@bar.com (Fooey Bar) push(@rv, [ $2, $3, $1 ]); $str = $4; } elsif ($str =~ /^[\s,]*("([^"]+)"\s*<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>\@]+)\s+<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>\@]+)<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>\[\]]+)\s+\[mailto:([^\s\[\]]+)\])(.*)$/|| $str =~ /^[\s,]*(()<([^<>,]+)>)(.*)/ || $str =~ /^[\s,]*(()([^\s<>,]+))(.*)/) { # Addresses like "Fooey Bar" # Fooey Bar # Fooey Bar # Fooey Bar [mailto:foo@bar.com] # # # foo@bar.com push(@rv, [ $3, $2 eq "," ? "" : $2, $1 ]); $str = $4; } else { last; } } return @rv; } $match_ascii = '\x1b\([BHJ]([\t\x20-\x7e]*)'; $match_jis = '\x1b\$[@B](([\x21-\x7e]{2})*)'; sub eucconv { local($_) = @_; if ($current_lang eq 'ja_JP.euc') { s/$match_jis/&j2e($1)/geo; s/$match_ascii/$1/go; } $_; } sub j2e { local($_) = @_; tr/\x21-\x7e/\xa1-\xfe/; $_; } # eucconv_and_escape(string) sub eucconv_and_escape { return &html_escape(&eucconv($_[0])); } # list_maildir(file, [start], [end], [headersonly]) # Returns a subset of mail from a maildir format directory sub list_maildir { local (@rv, $i, $f); &mark_read_maildir($_[0]); local @files = &get_maildir_files($_[0]); local ($start, $end); if (!defined($_[1])) { $start = 0; $end = @files - 1; } elsif ($_[2] < 0) { $start = @files + $_[2] - 1; $end = @files + $_[1] - 1; $start = 0 if ($start < 0); } else { $start = $_[1]; $end = $_[2]; $end = @files-1 if ($end >= @files); } foreach $f (@files) { if ($i < $start || $i > $end) { # Skip files outside requested index range push(@rv, undef); $i++; next; } local $mail = &read_mail_file($f, $_[3]); $mail->{'idx'} = $i++; $mail->{'id'} = $f; # ID is relative path, like cur/4535534 $mail->{'id'} = substr($mail->{'id'}, length($_[0])+1); push(@rv, $mail); } return @rv; } # idlist_maildir(file) # Returns a list of files in a maildir, which form the IDs sub idlist_maildir { local ($file) = @_; &mark_read_maildir($file); return map { substr($_, length($file)+1) } &get_maildir_files($file); } # select_maildir(file, &ids, headersonly) # Returns a list of messages with the given IDs, from a maildir directory sub select_maildir { local ($file, $ids, $headersonly) = @_; &mark_read_maildir($file); local @files = &get_maildir_files($file); local @rv; foreach my $i (@$ids) { local $path = "$file/$i"; local $mail = &read_mail_file($path, $headersonly); if (!$mail && $path =~ /^(.*)\/(cur|tmp|new)\/([^:]*)(:2,([A-Za-z]*))?$/) { # Flag may have changed - update path local $suffix = "$2/$3"; local ($newfile) = grep { substr($_, length($file)+1, length($suffix)) eq $suffix } @files; if ($newfile) { $path = $newfile; $mail = &read_mail_file($path, $headersonly); } } if (!$mail && $path =~ /\/cur\//) { # May have moved - update path $path =~ s/\/cur\//\/new\//g; $mail = &read_mail_file($path, $headersonly); } if ($mail) { # Set ID from corrected path $mail->{'id'} = $path; $mail->{'id'} = substr($mail->{'id'}, length($file)+1); # Get index in directory $mail->{'idx'} = &indexof($path, @files); } push(@rv, $mail); } return @rv; } # Get ordered list of message files (with in-memory and on-disk caching, as # this can be slow) # get_maildir_files(directory) sub get_maildir_files { # Work out last modified time local $newest; foreach my $d ("$_[0]/cur", "$_[0]/new") { local @dst = stat($d); $newest = $dst[9] if ($dst[9] > $newest); } local $skipt = $config{'maildir_deleted'} || $userconfig{'maildir_deleted'}; local @files; if (defined($main::list_maildir_cache{$_[0]}) && $main::list_maildir_cache_time{$_[0]} == $newest) { # Use the in-memory cache cache @files = @{$main::list_maildir_cache{$_[0]}}; } else { # Check the on-disk cache file local $cachefile = &get_maildir_cachefile($_[0]); local @cst = $cachefile ? stat($cachefile) : ( ); if ($cst[9] >= $newest) { # Can read the cache open(CACHE, $cachefile); while() { chop; push(@files, $_[0]."/".$_); } close(CACHE); $main::list_maildir_cache_time{$_[0]} = $cst[9]; } else { # Really read local @shorts; foreach my $d ("cur", "new") { opendir(DIR, "$_[0]/$d"); while(my $f = readdir(DIR)) { next if ($f eq "." || $f eq ".."); if ($skipt && $f =~ /:2,([A-Za-z]*T[A-Za-z]*)$/) { # Flagged as deleted by IMAP .. skip next; } push(@shorts, "$d/$f") } closedir(DIR); } @shorts = sort { substr($a, 4) cmp substr($b, 4) } @shorts; @files = map { "$_[0]/$_" } @shorts; # Write out the on-disk cache if ($cachefile) { &open_tempfile(CACHE, ">$cachefile", 1); my $err; foreach my $f (@shorts) { my $ok = (print CACHE $f,"\n"); $err++ if (!$ok); } &close_tempfile(CACHE) if (!$err); local @st = stat($_[0]); if ($< == 0) { # Cache should have some ownership as directory &set_ownership_permissions($st[4], $st[5], undef, $cachefile); } } $main::list_maildir_cache_time{$_[0]} = $st[9]; } $main::list_maildir_cache{$_[0]} = \@files; } return @files; } # search_maildir(file, field, what) # Search for messages in a maildir directory, and return the results sub search_maildir { return &advanced_search_maildir($_[0], [ [ $_[1], $_[2] ] ], 1); } # advanced_search_maildir(user|file, &fields, andmode, [&limit], [headersonly]) # Search for messages in a maildir directory, and return the results sub advanced_search_maildir { &mark_read_maildir($_[0]); local @rv; local ($min, $max); if ($_[3] && $_[3]->{'latest'}) { $min = -1; $max = -$_[3]->{'latest'}; } local $headersonly = $_[4] && !&matches_needs_body($_[1]); foreach $mail (&list_maildir($_[0], $min, $max, $headersonly)) { push(@rv, $mail) if ($mail && &mail_matches($_[1], $_[2], $mail)); } return @rv; } # mark_read_maildir(dir) # Move any messages in the 'new' directory of this maildir to 'cur' sub mark_read_maildir { local ($dir) = @_; local @files = &get_maildir_files($dir); local $i = 0; foreach my $nf (@files) { if (substr($nf, length($dir)+1, 3) eq "new") { local $cf = $nf; $cf =~ s/\/new\//\/cur\//g; if (rename($nf, $cf)) { $files[$i] = $cf; $changed = 1; } } $i++; } if ($changed) { # Update the cache $main::list_maildir_cache{$dir} = \@files; local $cachefile = &get_maildir_cachefile($dir); if ($cachefile) { &open_tempfile(CACHE, ">$cachefile", 1); foreach my $f (@files) { local $short = substr($f, length($dir)+1); &print_tempfile(CACHE, $short,"\n"); } &close_tempfile(CACHE); local @st = stat($_[0]); if ($< == 0) { &set_ownership_permissions($st[4], $st[5], undef, $cachefile); } } } } # delete_maildir(&mail, ...) # Delete messages from a maildir directory sub delete_maildir { local $m; # Find all maildirs being deleted from local %dirs; foreach $m (@_) { if ($m->{'file'} =~ /^(.*)\/(cur|new)\/([^\/]+)$/) { $dirs{$1}->{"$2/$3"} = 1; } } # Delete from caches foreach my $dir (keys %dirs) { local $cachefile = &get_maildir_cachefile($dir); next if (!$cachefile); local @cst = stat($cachefile); next if (!@cst); # Work out last modified time, and don't update cache if too new local $newest; foreach my $d ("$dir/cur", "$dir/new") { local @dst = stat($d); $newest = $dst[9] if ($dst[9] > $newest); } next if ($newest > $cst[9]); local $lref = &read_file_lines($cachefile); for(my $i=0; $i<@$lref; $i++) { if ($dirs{$dir}->{$lref->[$i]}) { # Found an entry to remove splice(@$lref, $i--, 1); } } &flush_file_lines($cachefile); } # Actually delete the files foreach $m (@_) { unlink($m->{'file'}); } } # modify_maildir(&oldmail, &newmail, textonly) # Replaces a message in a maildir directory sub modify_maildir { unlink($_[0]->{'file'}); &send_mail($_[1], $_[0]->{'file'}, $_[2], 1); } # write_maildir(&mail, directory, textonly) # Adds some message in maildir format to a directory sub write_maildir { # Work out last modified time, and don't update cache if too new local $cachefile = &get_maildir_cachefile($_[1]); local $up2date = 0; if ($cachefile) { local @cst = stat($cachefile); if (@cst) { local $newest; foreach my $d ("$dir/cur", "$dir/new") { local @dst = stat($d); $newest = $dst[9] if ($dst[9] > $newest); } $up2date = 1 if ($newest <= $cst[9]); } } # Select a unique filename and write to it local $now = time(); $_[0]->{'id'} = &unique_maildir_filename($_[1]); $mf = "$_[1]/$_[0]->{'id'}"; &send_mail($_[0], $mf, $_[2], 1); $_[0]->{'file'} = $mf; # Set ownership of the new message file to match the directory local @st = stat($_[1]); if ($< == 0) { &set_ownership_permissions($st[4], $st[5], undef, $mf); } # Create tmp and new sub-dirs, if missing foreach my $sd ("tmp", "new") { local $sdpath = "$_[1]/$sd"; if (!-d $sdpath) { mkdir($sdpath, 0755); if ($< == 0) { &set_ownership_permissions($st[4], $st[5], undef, $sdpath); } } } if ($up2date && $cachefile) { # Bring cache up to date $now--; local $lref = &read_file_lines($cachefile); push(@$lref, $_[0]->{'id'}); &flush_file_lines($cachefile); } } # unique_maildir_filename(dir) # Returns a filename for a new message in a maildir, relative to the directory sub unique_maildir_filename { local ($dir) = @_; mkdir("$dir/cur", 0755); local $now = time(); local $hn = &get_system_hostname(); ++$main::write_maildir_count; local $rv; do { $rv = "cur/$now.$$.$main::write_maildir_count.$hn"; $now++; } while(-r "$dir/$rv"); return $rv; } # empty_maildir(file) # Delete all messages in an maildir directory sub empty_maildir { local $d; foreach $d ("$_[0]/cur", "$_[0]/new") { local $f; opendir(DIR, $d); while($f = readdir(DIR)) { unlink("$d/$f") if ($f ne '.' && $f ne '..'); } closedir(DIR); } &flush_maildir_cachefile($_[0]); } # get_maildir_cachefile(dir) # Returns the cache file for a maildir directory sub get_maildir_cachefile { local ($dir) = @_; local $cd = $user_module_config_directory || $module_config_directory; local $sd = "$cd/maildircache"; if (!-d $sd) { &make_dir($sd, 0755) || return undef; } $dir =~ s/\//_/g; return "$sd/$dir"; } # flush_maildir_cachefile(dir) # Clear the on-disk and in-memory maildir caches sub flush_maildir_cachefile { local ($dir) = @_; local $cachefile = &get_maildir_cachefile($dir); unlink($cachefile) if ($cachefile); delete($main::list_maildir_cache{$dir}); delete($main::list_maildir_cache_time{$dir}); } # count_maildir(dir) # Returns the number of messages in a maildir directory sub count_maildir { local @files = &get_maildir_files($_[0]); return scalar(@files); } # list_mhdir(file, [start], [end], [headersonly]) # Returns a subset of mail from an MH format directory sub list_mhdir { local ($start, $end, $f, $i, @rv); opendir(DIR, $_[0]); local @files = map { "$_[0]/$_" } sort { $a <=> $b } grep { /^\d+$/ } readdir(DIR); closedir(DIR); if (!defined($_[1])) { $start = 0; $end = @files - 1; } elsif ($_[2] < 0) { $start = @files + $_[2] - 1; $end = @files + $_[1] - 1; $start = 0 if ($start < 0); } else { $start = $_[1]; $end = $_[2]; $end = @files-1 if ($end >= @files); } foreach $f (@files) { if ($i < $start || $i > $end) { # Skip files outside requested index range push(@rv, undef); $i++; next; } local $mail = &read_mail_file($f, $_[3]); $mail->{'idx'} = $i++; $mail->{'id'} = $f; # ID is message number $mail->{'id'} = substr($mail->{'id'}, length($_[0])+1); push(@rv, $mail); } return @rv; } # idlist_mhdir(file) # Returns a list of files in an MH directory, which are the IDs sub idlist_mhdir { opendir(DIR, $file); local @files = grep { /^\d+$/ } readdir(DIR); closedir(DIR); return @files; } # select_mhdir(file, &ids, headersonly) # Returns a list of messages with the given indexes, from an mhdir directory sub select_mhdir { local ($file, $ids, $headersonly) = @_; local @rv; opendir(DIR, $file); local @files = map { "$file/$_" } sort { $a <=> $b } grep { /^\d+$/ } readdir(DIR); closedir(DIR); foreach my $i (@$ids) { local $mail = &read_mail_file("$file/$i", $headersonly); if ($mail) { $mail->{'idx'} = &indexof("$file/$i", @files); $mail->{'id'} = $i; } push(@rv, $mail); } return @rv; } # search_mhdir(file|user, field, what) # Search for messages in an MH directory, and return the results sub search_mhdir { return &advanced_search_mhdir($_[0], [ [ $_[1], $_[2] ] ], 1); } # advanced_search_mhdir(file|user, &fields, andmode, &limit, [headersonly]) # Search for messages in an MH directory, and return the results sub advanced_search_mhdir { local @rv; local ($min, $max); if ($_[3] && $_[3]->{'latest'}) { $min = -1; $max = -$_[3]->{'latest'}; } local $headersonly = $_[4] && !&matches_needs_body($_[1]); foreach $mail (&list_mhdir($_[0], $min, $max, $headersonly)) { push(@rv, $mail) if ($mail && &mail_matches($_[1], $_[2], $mail)); } return @rv; } # delete_mhdir(&mail, ...) # Delete messages from an MH directory sub delete_mhdir { local $m; foreach $m (@_) { unlink($m->{'file'}); } } # modify_mhdir(&oldmail, &newmail, textonly) # Replaces a message in a maildir directory sub modify_mhdir { unlink($_[0]->{'file'}); &send_mail($_[1], $_[0]->{'file'}, $_[2], 1); } # max_mhdir(dir) # Returns the maximum message ID in the directory sub max_mhdir { local $max = 1; opendir(DIR, $_[0]); foreach $f (readdir(DIR)) { $max = $f if ($f =~ /^\d+$/ && $f > $max); } closedir(DIR); return $max; } # empty_mhdir(file) # Delete all messages in an MH format directory sub empty_mhdir { local $f; opendir(DIR, $_[0]); foreach $f (readdir(DIR)) { unlink("$_[0]/$f") if ($f =~ /^\d+$/); } closedir(DIR); } # count_mhdir(file) # Returns the number of messages in an MH directory sub count_mhdir { opendir(DIR, $_[0]); local @files = grep { /^\d+$/ } readdir(DIR); closedir(DIR); return scalar(@files); } # read_mail_file(file, [headersonly]) # Read a single message from a file sub read_mail_file { local (@headers, $mail); # Open and read the mail file open(MAIL, $_[0]) || return undef; $mail = &read_mail_fh(MAIL, 0, $_[1]); $mail->{'file'} = $_[0]; close(MAIL); local @st = stat($_[0]); $mail->{'size'} = $st[7]; $mail->{'time'} = $st[9]; # Set read flags based on the name if ($_[0] =~ /:2,([A-Za-z]*)$/) { local @flags = split(//, $1); $mail->{'read'} = &indexoflc("S", @flags) >= 0 ? 1 : 0; $mail->{'special'} = &indexoflc("F", @flags) >= 0 ? 1 : 0; $mail->{'replied'} = &indexoflc("R", @flags) >= 0 ? 1 : 0; $mail->{'flags'} = 1; } return $mail; } # read_mail_fh(handle, [end-mode], [headersonly]) # Reads an email message from the given file handle, either up to end of # the file, or a From line. End mode 0 = EOF, 1 = From without -, # 2 = From possibly with - sub read_mail_fh { local ($fh, $endmode, $headeronly) = @_; local (@headers, $mail); # Read the headers local $lnum = 0; while(1) { $lnum++; local $line = <$fh>; $mail->{'size'} += length($line); $line =~ s/\r|\n//g; last if ($line eq ''); if ($line =~ /^(\S+):\s*(.*)/) { push(@headers, [ $1, $2 ]); $mail->{'rawheaders'} .= $line."\n"; } elsif ($line =~ /^\s+(.*)/) { $headers[$#headers]->[1] .= $1 unless($#headers < 0); $mail->{'rawheaders'} .= $line."\n"; } elsif ($line =~ /^From\s+(\S+).*\d+/ && ($1 ne '-' || $endmode == 2)) { $mail->{'fromline'} = $line; } } $mail->{'headers'} = \@headers; foreach $h (@headers) { $mail->{'header'}->{lc($h->[0])} = $h->[1]; } if (!$headersonly) { # Read the mail body if ($endmode == 0) { # Till EOF while(read($fh, $buf, 1024) > 0) { $mail->{'size'} += length($buf); $mail->{'body'} .= $buf; $lc = ($buf =~ tr/\n/\n/); $lnum += $lc; } close(MAIL); } else { # Tell next From line while(1) { $line = <$fh>; last if (!$line || $line =~ /^From\s+(\S+).*\d+\r?\n/ && ($1 ne '-' || $endmode == 2)); $lnum++; $mail->{'size'} += length($line); $mail->{'body'} .= $line; } } $mail->{'lines'} = $lnum; } elsif ($endmode) { # Not reading the body, but we still need to search till the next # From: line in order to get the size while(1) { $line = <$fh>; last if (!$line || $line =~ /^From\s+(\S+).*\d+\r?\n/ && ($1 ne '-' || $endmode == 2)); $lnum++; $mail->{'size'} += length($line); } $mail->{'lines'} = $lnum; } return $mail; } # dash_mode(user|file) # Returns 1 if the messages in this folder are separated by lines like # From - instead of the usual From foo@bar.com sub dash_mode { open(DASH, &user_mail_file($_[0])) || return 0; # assume no local $line = ; close(DASH); return $line =~ /^From\s+(\S+).*\d/ && $1 eq '-'; } # mail_matches(&fields, andmode, &mail) # Returns 1 if some message matches a search sub mail_matches { local $count = 0; local $f; foreach $f (@{$_[0]}) { local $field = $f->[0]; local $what = $f->[1]; local $neg = ($field =~ s/^\!//); if ($field eq 'body') { $count++ if (!$neg && $_[2]->{'body'} =~ /\Q$what\E/i || $neg && $_[2]->{'body'} !~ /\Q$what\E/i); } elsif ($field eq 'size') { $count++ if (!$neg && $_[2]->{'size'} > $what || $neg && $_[2]->{'size'} < $what); } elsif ($field eq 'headers') { local $headers = $_[2]->{'rawheaders'} || join("", map { $_->[0].": ".$_->[1]."\n" } @{$_[2]->{'headers'}}); $count++ if (!$neg && $headers =~ /\Q$what\E/i || $neg && $headers !~ /\Q$what\E/i); } elsif ($field eq 'all') { local $headers = $_[2]->{'rawheaders'} || join("", map { $_->[0].": ".$_->[1]."\n" } @{$_[2]->{'headers'}}); $count++ if (!$neg && ($_[2]->{'body'} =~ /\Q$what\E/i || $headers =~ /\Q$what\E/i) || $neg && ($_[2]->{'body'} !~ /\Q$what\E/i && $headers !~ /\Q$what\E/i)); } elsif ($field eq 'status') { $count++ if (!$neg && $_[2]->{$field} =~ /\Q$what\E/i|| $neg && $_[2]->{$field} !~ /\Q$what\E/i); } else { $count++ if (!$neg && $_[2]->{'header'}->{$field} =~ /\Q$what\E/i|| $neg && $_[2]->{'header'}->{$field} !~ /\Q$what\E/i); } return 1 if ($count && !$_[1]); } return $count == scalar(@{$_[0]}); } # search_fields(&fields) # Returns an array of headers/fields from a search sub search_fields { local @rv; foreach my $f (@{$_[0]}) { $f->[0] =~ /^\!?(.*)$/; push(@rv, $1); } return &unique(@rv); } # matches_needs_body(&fields) # Returns 1 if a search needs to check the mail body sub matches_needs_body { foreach my $f (@{$_[0]}) { return 1 if ($f->[0] eq 'body' || $f->[0] eq 'all'); } return 0; } # parse_delivery_status(text) # Returns the fields from a message/delivery-status attachment sub parse_delivery_status { local @lines = split(/[\r\n]+/, $_[0]); local (%rv, $l); foreach $l (@lines) { if ($l =~ /^(\S+):\s*(.*)/) { $rv{lc($1)} = $2; } } return \%rv; } # parse_mail_date(string) # Converts a mail Date: header into a unix time sub parse_mail_date { local ($str) = @_; $str =~ s/^[, \t]+//; open(OLDSTDERR, ">&STDERR"); # suppress STDERR from Time::Local close(STDERR); my $rv = eval { if ($str =~ /^(\S+),\s+(\d+)\s+(\S+)\s+(\d+)\s+(\d+):\s?(\d+):\s?(\d+)\s+(\S+)/) { # Format like Mon, 13 Dec 2004 14:40:41 +0100 # or Mon, 13 Dec 2004 14:18:16 GMT # or Tue, 14 Sep 04 02:45:09 GMT local $tm = timegm($7, $6, $5, $2, &month_to_number($3), $4 < 50 ? $4+100 : $4 < 1000 ? $4 : $4-1900); local $tz = $8; if ($tz =~ /^(\-|\+)?\d+$/) { local $tz = int($tz); $tz = $tz/100 if ($tz >= 50 || $tz <= -50); $tm -= $tz*60*60; } return $tm; } elsif ($str =~ /^(\S+),\s+(\d+),?\s+(\S+)\s+(\d+)\s+(\d+):\s?(\d+):\s?(\d+)/) { # Format like Mon, 13 Dec 2004 14:40:41 or # Mon, 13, Dec 2004 14:40:41 # No timezone, so assume local local $tm = timelocal($7, $6, $5, $2, &month_to_number($3), $4 < 50 ? $4+100 : $4 < 1000 ? $4 : $4-1900); return $tm; } elsif ($str =~ /^(\S+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/) { # Format like Tue Dec 7 12:58:52 2004 local $tm = timelocal($6, $5, $4, $3, &month_to_number($2), $7 < 50 ? $7+100 : $7 < 1000 ? $7 : $7-1900); return $tm; } elsif ($str =~ /^(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)\s+(\S+)/) { # Format like Dec 7 12:58:52 2004 GMT local $tm = timelocal($5, $4, $3, $2, &month_to_number($1), $6 < 50 ? $6+100 : $6 < 1000 ? $6 : $6-1900); local $tz = $7; if ($tz =~ /^(\-|\+)?\d+$/) { $tz = int($tz); $tz = $tz/100 if ($tz >= 50 || $tz <= -50); $tm -= $tz*60*60; } return $tm; } elsif ($str =~ /^(\d{4})\-(\d+)\-(\d+)\s+(\d+):(\d+)/) { # Format like 2004-12-07 12:53 local $tm = timelocal(0, $4, $4, $3, $2-1, $1 < 50 ? $1+100 : $1 < 1000 ? $1 : $1-1900); } elsif ($str =~ /^(\d+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\S+)/) { # Format like 30 Jun 2005 21:01:01 -0000 local $tm = timegm($6, $5, $4, $1, &month_to_number($2), $3 < 50 ? $3+100 : $3 < 1000 ? $3 : $3-1900); local $tz = $7; if ($tz =~ /^(\-|\+)?\d+$/) { $tz = int($tz); $tz = $tz/100 if ($tz >= 50 || $tz <= -50); $tm -= $tz*60*60; } return $tm; } elsif ($str =~ /^(\d+)\/(\S+)\/(\d+)\s+(\d+):(\d+)/) { # Format like 21/Feb/2008 24:13 local $tm = timelocal(0, $5, $4, $1, &month_to_number($2), $3-1900); return $tm; } else { return undef; } }; open(STDERR, ">&OLDSTDERR"); close(OLDSTDERR); if ($@) { return undef; } return $rv; } # send_text_mail(from, to, cc, subject, body, [smtp-server]) # A convenience function for sending a email with just a text body sub send_text_mail { local ($from, $to, $cc, $subject, $body, $smtp) = @_; local $cs = &get_charset(); local $attach = $body =~ /[\177-\377]/ ? { 'headers' => [ [ 'Content-Type', 'text/plain; charset='.$cs ], [ 'Content-Transfer-Encoding', 'quoted-printable' ] ], 'data' => "ed_encode($body) } : { 'headers' => [ [ 'Content-type', 'text/plain' ] ], 'data' => &entities_to_ascii($body) }; local $mail = { 'headers' => [ [ 'From', $from ], [ 'To', $to ], [ 'Cc', $cc ], [ 'Subject', $subject ] ], 'attach' => [ $attach ] }; return &send_mail($mail, undef, 1, 0, $smtp); } # clear_time_locale() # Temporarily force the locale to C, until reset_time_locale is called sub clear_time_locale { if ($main::clear_time_locale_count == 0) { eval { $main::clear_time_locale_old = POSIX::setlocale(POSIX::LC_TIME); POSIX::setlocale(POSIX::LC_TIME, "C"); }; } $main::clear_time_locale_count++; } # reset_time_locale() # Revert the locale to whatever it was before clear_time_locale was called sub reset_time_locale { if ($main::clear_time_locale_count == 1) { eval { POSIX::setlocale(POSIX::LC_TIME, $main::clear_time_locale_old); $main::clear_time_locale_old = undef; }; } $main::clear_time_locale_count--; } # make_from_line(address, [time]) # Returns a From line for mbox emails, based on the current time sub make_from_line { local ($addr, $t) = @_; $t ||= time(); &clear_time_locale(); local $rv = "From $addr ".strftime("%a %b %e %H:%M:%S %Y", localtime($t)); &reset_time_locale(); return $rv; } sub notes_decode { # Deprecated - does nothing } 1; postfix/save_ffile.cgi0000775000567100000120000000154211137644403015033 0ustar jcameronwheel#!/usr/local/bin/perl # save_ffile.cgi # Save a filter file require (-r 'sendmail-lib.pl' ? './sendmail-lib.pl' : -r 'qmail-lib.pl' ? './qmail-lib.pl' : './postfix-lib.pl'); &ReadParseMime(); &error_setup($text{'ffile_err'}); if (substr($in{'file'}, 0, length($access{'apath'})) ne $access{'apath'}) { &error(&text('ffile_efile', $in{'file'})); } for($i=0; defined($in{"field_$i"}); $i++) { next if (!$in{"field_$i"}); $in{"match_$i"} || &error($text{'ffile_ematch'}); $in{"action_$i"} || &error($text{'ffile_eaction'}); push(@filter, $in{"what_$i"}." ".$in{"action_$i"}." ". $in{"field_$i"}." ".$in{"match_$i"}."\n"); } push(@filter, "2 ".$in{'other'}."\n") if ($in{'other'}); &open_lock_tempfile(FILE, ">$in{'file'}"); &print_tempfile(FILE, @filter); &close_tempfile(FILE); &redirect("edit_alias.cgi?num=$in{'num'}&name=$in{'name'}"); postfix/save_client.cgi0000755000567100000120000000322411137644403015221 0ustar jcameronwheel#!/usr/local/bin/perl # Save SMTP authentication options require './postfix-lib.pl'; &ReadParse(); $access{'client'} || &error($text{'opts_ecannot'}); &error_setup($text{'client_err'}); &lock_postfix_files(); if ($in{'client_def'}) { # Reset to default &set_current_value("smtpd_client_restrictions", "__DEFAULT_VALUE_IE_NOT_IN_CONFIG_FILE__"); } else { # Save client options @opts = split(/[\s,]+/,&get_current_value("smtpd_client_restrictions")); %oldopts = map { $_, 1 } @opts; %newopts = map { $_, 1 } split(/\0/, $in{'client'}); # Save boolean options foreach $o (&list_client_restrictions()) { if ($newopts{$o} && !$oldopts{$o}) { push(@opts, $o); } elsif (!$newopts{$o} && $oldopts{$o}) { @opts = grep { $_ ne $o } @opts; } } # Save options with values foreach $o (&list_multi_client_restrictions()) { # Find all current positions local @pos; for(my $i=0; $i<@opts; $i++) { push(@pos, $i) if ($opts[$i] eq $o); } # Make sure something was entered if ($newopts{$o}) { $in{"value_$o"} =~ /\S/ || &error(&text('client_evalue', $text{'sasl_'.$o})); } # Sync with values entered @v = split(/\s+/, $in{"value_$o"}); for(my $i=0; $i<@pos || $i<@v; $i++) { if ($i<@pos && $i<@v) { # Updating a value $opts[$pos[$i]+1] = $v[$i]; } elsif ($i<@pos && $i>=@v) { # Removing a value splice(@opts, $pos[$i], 2); } elsif ($i>=@pos && $i<@v) { # Adding a value, at the end push(@opts, $o, $v[$i]); } } } &set_current_value("smtpd_client_restrictions", join(" ", @opts)); } &unlock_postfix_files(); &reload_postfix(); &webmin_log("client"); &redirect(""); postfix/edit_master.cgi0000775000567100000120000000575511137644403015242 0ustar jcameronwheel#!/usr/local/bin/perl # Edit or create a server process require './postfix-lib.pl'; $access{'master'} || &error($text{'master_ecannot'}); &ReadParse(); $master = &get_master_config(); if ($in{'new'}) { &ui_print_header(undef, $text{'master_create'}, ""); $prog = { 'enabled' => 1, 'type' => 'inet', 'private' => '-', 'unpriv' => '-', 'chroot' => '-', 'wakeup' => '-', 'maxprocs' => '-', }; } else { ($prog) = grep { $_->{'name'} eq $in{'name'} } @$master; $prog || &error($text{'master_egone'}); &ui_print_header(undef, $text{'master_edit'}, ""); } print &ui_form_start("save_master.cgi", "post"); print &ui_hidden("new", $in{'new'}),"\n"; print &ui_hidden("old", $in{'name'}),"\n"; print &ui_table_start($text{'master_header'}, "width=100%", 4); print &ui_table_row($text{'master_type'}, &ui_select("type", $prog->{'type'}, [ [ "inet", $text{'master_inet'} ], [ "unix", $text{'master_unix'} ], [ "fifo", $text{'master_fifo'} ] ])); print &ui_table_row($text{'master_enabled'}, &ui_yesno_radio("enabled", int($prog->{'enabled'}))); if ($prog->{'name'} =~ s/^(\S+)://) { $host = $1; } print &ui_table_row($text{'master_name2'}, &ui_textbox("name", $prog->{'name'}, 20)); print &ui_table_row($text{'master_host'}, &ui_opt_textbox("host", $host, 15, $text{'master_any'})); print &ui_table_row($text{'master_command'}, &ui_textbox("command", $prog->{'command'}, 80), 3); print &ui_table_hr(); print &ui_table_row($text{'master_private2'}, &ui_radio("private", $prog->{'private'}, [ [ "y", $text{'yes'} ], [ "n", $text{'no'} ], [ "-", $text{'master_defyes'} ] ])); print &ui_table_row($text{'master_unpriv2'}, &ui_radio("unpriv", $prog->{'unpriv'}, [ [ "y", $text{'yes'} ], [ "n", $text{'no'} ], [ "-", $text{'master_defyes'} ] ])); print &ui_table_row($text{'master_chroot2'}, &ui_radio("chroot", $prog->{'chroot'}, [ [ "y", $text{'yes'} ], [ "n", $text{'no'} ], [ "-", $text{'master_defyes'} ] ])); $wmode = $prog->{'wakeup'} eq '-' ? 0 : $prog->{'wakeup'} eq '0' ? 1 : 2; $wused = $prog->{'wakeup'} =~ s/\?$//; print &ui_table_row($text{'master_wakeup'}, &ui_radio("wakeup", $wmode, [ [ 0, $text{'default'} ], [ 1, $text{'master_unlimit'} ], [ 2, &text('master_wtime', &ui_textbox("wtime", $wmode == 2 ? $prog->{'wakeup'} : "", 6)) ] ]). " (".&ui_checkbox("wused", 1, $text{'master_wused'}, $wused).")", 3); $pmode = $prog->{'maxprocs'} eq '-' ? 0 : $prog->{'maxprocs'} eq '0' ? 1 : 2; print &ui_table_row($text{'master_max2'}, &ui_radio("maxprocs", $pmode, [ [ 0, $text{'default'} ], [ 1, $text{'master_unlimit'} ], [ 2, &text('master_procs', &ui_textbox("procs", $pmode == 2 ? $prog->{'maxprocs'} : "", 6)) ] ]), 3); print &ui_table_end(); print &ui_form_end([ $in{'new'} ? ( [ "create", $text{'create'} ] ) : ( [ "save", $text{'save'} ], [ "delete", $text{'delete'} ] ) ] ); &ui_print_footer("master.cgi", $text{'master_return'}, "", $text{'index_return'}); postfix/config.info0000644000567100000120000000464311137644403014366 0ustar jcameronwheelline1=Configurable options,11 perpage=Mail messages to display per page,0,6 wrap_width=Width to wrap mail messages at,0 sort_mode=Sort tables by,1,0-Order in file,1-Name columns=Columns for aliases and other tables,1,2-2,1-1 show_cmts=Show descriptions in tables?,1,1-Yes,0-No prefix_cmts=Prefix all description comments with Webmin?,1,1-Yes,0-No mailq_sort=Sort mail queue by,1,0-Queue ID,1-From address,2-To address,4-Status,5-Size mailq_count=Show size of mail queue on main page?,1,0-Yes,1-No check_config=Test config file after change?,1,1-Yes,0-No index_check=Check Postfix configuration on main page?,1,1-Yes,0-No delete_confirm=Prompt for confirmation before deleting?,1,1-Yes,0-No line2=System configuration,11 postfix_control_command=Full path to Postfix control command,0 postfix_config_command=Full path to Postfix config command,0 postfix_config_file=Full path to Postfix config file,0 postfix_master=Full path to Postfix master.cf file,0 postfix_aliases_table_command=Full path to Postfix aliases generation command,0 postfix_newaliases_command=Full path to "newaliases" (Sendmail compatibility) command,0 postfix_lookup_table_command=Full path to Postfix lookup table command management (`postmap'),0 postfix_queue_command=Full path to Postfix queue management command (`postqueue'),0 postfix_super_command=Full path to Postfix supervisor command,0 mailq_dir=Mail queue base directory,0 mailq_cmd=Mail queue display command,0 postcat_cmd=Mail queue decoding command,0 start_cmd=Command to start Postfix,3,Use control command stop_cmd=Command to stop Postfix,3,Use control command reload_cmd=Command to apply Postfix configuration,3,Use control command line3=MySQL options,11 mysql_host=MySQL server for editing maps,3,Same as Postfix configuration mysql_user=MySQL login for editing maps,3,Same as Postfix configuration mysql_pass=MySQL password for editing maps,3,Same as Postfix configuration line4=LDAP options,11 ldap_host=LDAP server for editing maps,3,Same as Postfix configuration ldap_user=LDAP login for editing maps,3,Same as Postfix configuration ldap_pass=LDAP password for editing maps,3,Same as Postfix configuration ldap_class=Object classes for maps,3,Default (inetLocalMailRecipient) ldap_attrs=Other LDAP attributes for maps
(In fieldname: value format),9,40,3,\t ldap_id=Key attribute for map objects,3,Default (cn) ldap_doms=Create separate DN for each domain?,1,1-Yes,0-No postfix/body.cgi0000775000567100000120000000250411137644403013664 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Manages virtuals for Postfix # # << Here are all options seen in Postfix sample-virtual.cf >> require './postfix-lib.pl'; $access{'body'} || &error($text{'body_ecannot'}); &ui_print_header(undef, $text{'body_title'}, "", "body"); # Start of body form print &ui_form_start("save_opts_body.cgi"); print &ui_table_start($text{'body_title'}, "width=100%", 2); &option_mapfield("body_checks", 60); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'opts_save'} ] ]); # Map contents print &ui_hr(); if (&get_current_value("body_checks") eq "") { print $text{'no_map'},"

\n"; } else { &generate_map_edit("body_checks", $text{'map_click'}." ". &hlink($text{'help_map_format'}, "body"), 1, $text{'header_name'}, $text{'header_value'}); } &ui_print_footer("", $text{'index_return'}); postfix/config.info.nl0000644000567100000120000000000011137644403014755 0ustar jcameronwheelpostfix/sasl.cgi0000755000567100000120000000312311137644403013665 0ustar jcameronwheel#!/usr/local/bin/perl # Show SMTP authentication related paramters require './postfix-lib.pl'; $access{'sasl'} || &error($text{'sasl_ecannot'}); &ui_print_header(undef, $text{'sasl_title'}, ""); $default = $text{'opts_default'}; $none = $text{'opts_none'}; $no_ = $text{'opts_no'}; # Form start print &ui_form_start("save_sasl.cgi"); print &ui_table_start($text{'sasl_title'}, "width=100%", 4); # Enabled, accept broken clients &option_yesno("smtpd_sasl_auth_enable"); &option_yesno("broken_sasl_auth_clients"); # Anonymous and plain-text options %opts = map { $_, 1 } split(/[\s,]+/, &get_current_value("smtpd_sasl_security_options")); @cbs = ( ); foreach $o ("noanonymous", "noplaintext") { push(@cbs, &ui_checkbox("sasl_opts", $o, $text{'sasl_'.$o}, $opts{$o})); } print &ui_table_row($text{'sasl_opts'}, join("
\n", @cbs), 3); # SASL-related relay restrictions %recip = map { $_, 1 } split(/[\s,]+/, &get_current_value("smtpd_recipient_restrictions")); @cbs = ( ); foreach $o (&list_smtpd_restrictions()) { push(@cbs, &ui_checkbox("sasl_recip", $o, $text{'sasl_'.$o}, $recip{$o})); } print &ui_table_row($text{'sasl_recip'}, join("
\n", @cbs), 3); # Delay bad logins &option_yesno("smtpd_delay_reject"); print &ui_table_hr(); # SMTP TLS options &option_yesno("smtpd_use_tls"); &option_radios_freefield("smtpd_tls_cert_file", 60, $none); &option_radios_freefield("smtpd_tls_key_file", 60, $none); &option_radios_freefield("smtpd_tls_CAfile", 60, $none); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'opts_save'} ] ]); &ui_print_footer("", $text{'index_return'}); postfix/map_chooser_save.cgi0000775000567100000120000001501711137644403016247 0ustar jcameronwheel#!/usr/local/bin/perl # Show a form for selecting the source for a map require './postfix-lib.pl'; &ReadParse(); &error_setup($text{'chooser_err'}); @oldmaps = &get_maps_types_files($in{'map'}); # Build a list of maps from inputs for($i=0; defined($t = $in{"type_".$i}); $i++) { next if (!$t); if ($t eq "hash") { # Simple file $in{"hash_$i"} =~ /^[\/\.]\S+$/ || &error(&text('chooser_ehash', $i+1)); push(@maps, "hash:".$in{"hash_$i"}); } elsif ($t eq "regexp") { # Regular expressions file $in{"regexp_$i"} =~ /^[\/\.]\S+$/ || &error(&text('chooser_eregexp', $i+1)); push(@maps, "regexp:".$in{"regexp_$i"}); } elsif ($t eq "pcre") { # Perl-style regular expressions file $in{"pcre_$i"} =~ /^[\/\.]\S+$/ || &error(&text('chooser_epcre', $i+1)); push(@maps, "pcre:".$in{"pcre_$i"}); } elsif ($t eq "mysqlsrc") { # Common MySQL source push(@maps, "mysql:".$in{"mysqlsrc_$i"}); } elsif ($t eq "mysql") { # MySQL database if ($oldmaps[$i]->[0] eq "mysql" && $oldmaps[$i]->[1] =~ /^[\/\.]/) { # Same file as before $file = $oldmaps[$i]->[1]; } else { # Pick a filename based on the field $file = &guess_config_dir()."/".$in{'mapname'}. ($i ? ".$i" : "").".mysql.conf"; } # Validate and save MySQL settings, starting with host if ($in{"mhosts_${i}_def"}) { &save_backend_config($file, "hosts", undef); } else { $in{"mhosts_$i"} =~ /\S/ || &error(&text('chooser_emhosts', $i+1)); &save_backend_config($file, "hosts", $in{"mhosts_$i"}); } # Username $in{"muser_$i"} =~ /^\S+$/ || &error(&text('chooser_emuser', $i+1)); &save_backend_config($file, "user", $in{"muser_$i"}); # Password $in{"mpassword_$i"} =~ /^\S+$/ || &error(&text('chooser_empassword', $i+1)); &save_backend_config($file, "password", $in{"mpassword_$i"}); # Custom query if ($postfix_version >= 2.2) { if ($in{"mquery_${i}_def"}) { &save_backend_config($file, "query", undef); } else { $in{"mdbname_$i"} =~ /\S/ || &error(&text('chooser_emquery', $i+1)); &save_backend_config($file, "query", $in{"mquery_$i"}); } } # Database name $in{"mdbname_$i"} =~ /^\S+$/ || &error(&text('chooser_emdbname', $i+1)); &save_backend_config($file, "dbname", $in{"mdbname_$i"}); # Table name $in{"mtable_$i"} =~ /^\S+$/ || &error(&text('chooser_emtable', $i+1)); &save_backend_config($file, "table", $in{"mtable_$i"}); # Value field $in{"mselect_field_$i"} =~ /^[a-z0-9\_]+$/i || &error(&text('chooser_emselect_field', $i+1)); &save_backend_config($file, "select_field", $in{"mselect_field_$i"}); # Key field $in{"mwhere_field_$i"} =~ /^[a-z0-9\_]+$/i || &error(&text('chooser_emwhere_field', $i+1)); &save_backend_config($file, "where_field", $in{"mwhere_field_$i"}); # Additional select conditions if ($in{"madditional_conditions_${i}_def"}) { &save_backend_config($file, "additional_conditions"); } else { $in{"madditional_conditions_$i"} =~ /\S/ || &error(&text('chooser_emadditional', $i+1)); &save_backend_config($file, "additional_conditions", $in{"madditional_conditions_$i"}); } push(@maps, "mysql:$file"); push(@files, $file); } elsif ($t eq "ldap") { # LDAP database if ($oldmaps[$i]->[0] eq "ldap" && $oldmaps[$i]->[1] =~ /^[\/\.]/) { # Same file as before $file = $oldmaps[$i]->[1]; } else { # Pick a filename based on the field $file = &guess_config_dir()."/".$in{'mapname'}. ($i ? ".$i" : "").".ldap.conf"; } # Save LDAP server hostname if ($in{"lserver_host_${i}_def"}) { &save_backend_config($file, "server_host", undef); } else { $in{"lserver_host_$i"} =~ /\S/ || &error(&text('chooser_elserver_host', $i+1)); &save_backend_config($file, "server_host", $in{"lserver_host_$i"}); } # LDAP port number if ($in{"lserver_port_${i}_def"}) { &save_backend_config($file, "server_port", undef); } else { $in{"lserver_port_$i"} =~ /^\d+$/ || &error(&text('chooser_elserver_port', $i+1)); &save_backend_config($file, "server_port", $in{"lserver_port_$i"}); } # Start TLS? &save_backend_config($file, "start_tls", $in{"lstart_tls_$i"}); # Search base $in{"lsearch_base_$i"} =~ /\S/ || &error(&text('chooser_elsearch_base', $i+1)); &save_backend_config($file, "search_base", $in{"lsearch_base_$i"}); # Query filter if ($in{"lquery_filter_${i}_def"}) { &save_backend_config($file, "query_filter", undef); } else { $in{"lquery_filter_$i"} =~ /^\S+$/ || &error(&text('chooser_elquery_filter', $i+1)); &save_backend_config($file, "query_filter", $in{"lquery_filter_$i"}); } # Resulting attribute if ($in{"lresult_attribute_${i}_def"}) { &save_backend_config($file, "result_attribute", undef); } else { $in{"lresult_attribute_$i"} =~ /^\S+$/ || &error(&text('chooser_elresult_attribute', $i+1)); &save_backend_config($file, "result_attribute", $in{"lresult_attribute_$i"}); } # Search scope &save_backend_config($file, "scope", $in{"lscope_$i"} || undef); # Login to server? &save_backend_config($file, "bind", $in{"lbind_$i"}); # Username if ($in{"lbind_dn_${i}_def"}) { &save_backend_config($file, "bind_dn", undef); } else { $in{"lbind_dn_$i"} =~ /\S/ || &error(&text('chooser_elbind_dn', $i+1)); &save_backend_config($file, "bind_dn", $in{"lbind_dn_$i"}); } # Password if ($in{"lbind_pw_${i}_def"}) { &save_backend_config($file, "bind_pw", undef); } else { $in{"lbind_pw_$i"} =~ /\S/ || &error(&text('chooser_elbind_pw', $i+1)); &save_backend_config($file, "bind_pw", $in{"lbind_pw_$i"}); } push(@maps, "ldap:$file"); push(@files, $file); } elsif ($t eq "other") { # Some other map $in{"other_$i"} =~ /^[a-z0-9]+:[^, ]+$/i || &error(&text('chooser_eother', $i+1)); push(@maps, $in{"other_$i"}); } else { &error("Unknown type $t"); } } @maps || &error($text{'chooser_enone'}); # Write out mysql and LDAP files @files = &unique(@files); @newfiles = map { !-r $_ } @files; foreach $f (@files) { &lock_file($f); } &flush_file_lines(@files); foreach $f (@newfiles) { &set_ownership_permissions(undef, undef, 0700, $f); } foreach $f (@files) { &unlock_file($f); } # Create final string for map $str = join(",", @maps); &popup_header($text{'chooser_title'}); print < top.opener.ifield.value = "$str"; window.close(); EOF if (@files) { &webmin_log("backend", undef, $in{'map_name'}); } &popup_footer(); postfix/view_mailq.cgi0000755000567100000120000000743211137644403015067 0ustar jcameronwheel#!/usr/local/bin/perl # view_mailq.cgi # Display some message from the mail queue require './postfix-lib.pl'; require './boxes-lib.pl'; &ReadParse(); $access{'mailq'} || &error($text{'mailq_ecannot'}); $mail = &parse_queue_file($in{'id'}); $mail || &error($text{'mailq_egone'}); &parse_mail($mail); @sub = split(/\0/, $in{'sub'}); $subs = join("", map { "&sub=$_" } @sub); foreach $s (@sub) { # We are looking at a mail within a mail .. local $amail = &extract_mail($mail->{'attach'}->[$s]->{'data'}); &parse_mail($amail); $mail = $amail; } if (!@sub) { $desc = &text('view_qdesc',"$in{'id'}"); } else { $desc = $text{'view_sub'}; } &ui_print_header($desc, $text{'view_title'}, ""); print "

\n"; print "\n"; print "\n"; print "\n"; print "
", "\n"; if ($in{'headers'}) { print "\n"; } else { print "\n"; } print "
$text{'view_headers'}$text{'view_noheaders'}$text{'view_allheaders'}
\n"; if ($in{'headers'}) { # Show all the headers if ($mail->{'fromline'}) { print "", "\n"; } foreach $h (@{$mail->{'headers'}}) { print " ", "\n"; } } else { # Just show the most useful headers print " ", "\n"; print " ", "\n"; print " ", "\n" if ($mail->{'header'}->{'cc'}); print " ", "\n"; print " ", "\n"; } print "
$text{'mail_rfc'}",&html_escape($mail->{'fromline'}),"
$h->[0]:",&html_escape(&decode_mimewords($h->[1])), "
$text{'mail_from'}",&html_escape($mail->{'header'}->{'from'}),"
$text{'mail_to'}",&html_escape($mail->{'header'}->{'to'}),"
$text{'mail_cc'}",&html_escape($mail->{'header'}->{'cc'}),"
$text{'mail_date'}",&html_escape($mail->{'header'}->{'date'}),"
$text{'mail_subject'}",&html_escape( $mail->{'header'}->{'subject'}),"

\n"; # Find body attachment @attach = @{$mail->{'attach'}}; foreach $a (@attach) { if ($a->{'type'} eq 'text/plain') { $body = $a; last; } } if ($body) { print "
\n";
	foreach $l (&wrap_lines($body->{'data'}, $config{'wrap_width'})) {
		print &link_urls_and_escape($l),"\n";
		}
	print "

\n"; } # Display other attachments @attach = grep { $_ ne $body } @attach; @attach = grep { !$_->{'attach'} } @attach; if (@attach) { print "\n"; print "\n"; print "
$text{'view_attach'}
\n"; foreach $a (@attach) { if ($a->{'type'} eq 'message/rfc822') { push(@titles, $text{'view_sub'}); push(@links, "view_mailq.cgi?id=$in{'id'}$subs&sub=$a->{'idx'}"); } else { push(@titles, $a->{'filename'} ? &decode_mimewords($a->{'filename'}) : $a->{'type'}); push(@links, "detach_queue.cgi?id=$in{'id'}&attach=$a->{'idx'}$subs"); } push(@icons, "images/boxes.gif"); } &icons_table(\@links, \@titles, \@icons, 8); print "

\n"; } # Display buttons if (!@sub) { print "\n"; print "

\n"; } print "

\n"; &ui_print_footer(!@sub ? ( ) : ( "view_mailq.cgi?id=$in{'id'}", $text{'view_return'} ), "mailq.cgi", $text{'mailq_return'}, "", $text{'index_return'}); postfix/address_rewriting.cgi0000755000567100000120000000274611137644403016454 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # A form for editing address rewriting for Postfix # # << Here are all options seen in Postfix sample-rewrite.cf >> require './postfix-lib.pl'; $access{'address_rewriting'} || &error($text{'address_rewriting_ecannot'}); &ui_print_header(undef, $text{'address_rewriting_title'}, ""); $default = $text{'opts_default'}; $none = $text{'opts_none'}; $no_ = $text{'opts_no'}; print &ui_form_start("save_opts.cgi"); print &ui_table_start($text{'address_rewriting_title'}, "width=100%", 4); &option_yesno("allow_percent_hack"); &option_yesno("append_at_myorigin"); &option_yesno("append_dot_mydomain"); &option_yesno("swap_bangpath", 'help'); &option_radios_freefield("empty_address_recipient", 35, $text{'opt_empty_recip_default'}); &option_radios_freefield("masquerade_domains", 35, $none); &option_radios_freefield("masquerade_exceptions", 35, $none); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'opts_save'} ] ]); &ui_print_footer("", $text{'index_return'}); postfix/config.info.ru_SU0000644000567100000120000000124711137644403015417 0ustar jcameronwheelline1= ,11 max_records= ,0,6 perpage= , ,0,6 line2= ,11 postfix_control_command= Postfix,0 postfix_config_command= Postfix,0 postfix_config_file= Postfix,0 postfix_aliases_table_command= Postfix,0 postfix_newaliases_command= "newaliases" ( Sendmail),0 postfix_lookup_table_command= Postfix (`postmap'),0 postfix/save_opts_header.cgi0000755000567100000120000000200611137644403016235 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save Postfix options ; special because for virtual tables require './postfix-lib.pl'; &ReadParse(); $access{'header'} || &error($text{'header_ecannot'}); &error_setup($text{'opts_err'}); &lock_postfix_files(); &before_save(); $in{'header_checks'} =~ /^(regexp|pcre):\/\S+$/ || &error($text{'header_eregexp'}); &save_options(\%in); &ensure_map("header_checks"); &after_save(); &unlock_postfix_files(); ®enerate_header_table(); &reload_postfix(); &webmin_log("header"); &redirect(""); postfix/config.info.es0000644000567100000120000000070611137644403014770 0ustar jcameronwheelpostfix_control_command=Full path to Postfix control command,0 postfix_config_command=Full path to Postfix config command,0 postfix_config_file=Full path to Postfix config file,0 postfix_aliases_table_command=Full path to Postfix aliases generation commande,0 postfix_newaliases_command=Full path to "newaliases" (Sendmail compatibility) command,0 postfix_lookup_table_command=Full path to Postfix lookup table command management (`postmap'),0 postfix/edit_manual.cgi0000775000567100000120000000211211137644403015204 0ustar jcameronwheel#!/usr/local/bin/perl # Show a form for editing a mapping file require './postfix-lib.pl'; &ReadParse(); $access{'manual'} || &error($text{'manual_ecannot'}); &ui_print_header(undef, $text{'manual_title'}, ""); # Find the maps files @files = &get_maps_files(&get_real_value($in{'map_name'})); $file = $in{'file'} || $files[0]; if (@files > 1) { # Show form to select print &ui_form_start("edit_manual.cgi"); print &ui_hidden("map_name", $in{'map_name'}); print $text{'manual_file'},"\n"; print &ui_select("file", $file, [ map { [ $_ ] } @files ]),"\n"; print &ui_submit($text{'manual_change'}); print &ui_form_end(); } # Show the file contents $data = &read_file_contents($file); print &ui_form_start("save_manual.cgi", "form-data"); print &ui_hidden("map_name", $in{'map_name'}); print &ui_hidden("file", $file); print &text('manual_editing', "$file"),"
\n"; print &ui_table_start(); print &ui_table_row(undef, &ui_textarea("data", $data, 20, 80), 2); print &ui_table_end(); print &ui_form_end([ [ "save", $text{'save'} ] ] ); &ui_print_footer("", $text{'index_return'}); postfix/edit_afile.cgi0000775000567100000120000000212311137644403015011 0ustar jcameronwheel#!/usr/local/bin/perl # edit_afile.cgi # Display the contents of an address file require (-r 'sendmail-lib.pl' ? './sendmail-lib.pl' : -r 'qmail-lib.pl' ? './qmail-lib.pl' : './postfix-lib.pl'); &ReadParse(); if (substr($in{'file'}, 0, length($access{'apath'})) ne $access{'apath'}) { &error(&text('afile_efile', $in{'file'})); } &ui_print_header(undef, $text{'afile_title'}, ""); &open_readfile(FILE, $in{'file'}); @lines = ; close(FILE); print "",&text('afile_desc', "$in{'file'}"),"

\n"; print "

\n"; print "\n"; print "\n"; print "\n"; print "

\n"; print " ", "\n"; print "

\n"; &ui_print_footer("edit_alias.cgi?name=$in{'name'}&num=$in{'num'}",$text{'aform_return'}); postfix/save_opts_aliases.cgi0000755000567100000120000000170211137644403016430 0ustar jcameronwheel#!/usr/local/bin/perl # # postfix-module by Guillaume Cottenceau , # for webmin by Jamie Cameron # # Copyright (c) 2000 by Mandrakesoft # # Permission to use, copy, modify, and distribute this software and its # documentation under the terms of the GNU General Public License is hereby # granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # # Save Postfix options ; special because for aliases require './postfix-lib.pl'; &ReadParse(); # &ui_print_header(undef, $text{'opts_title'}, ""); &error_setup($text{'opts_err'}); &lock_postfix_files(); &before_save(); &save_options(\%in); &ensure_map("alias_maps"); &ensure_map("alias_database"); &after_save(); &unlock_postfix_files(); ®enerate_aliases(); &reload_postfix(); &webmin_log("aliases"); &redirect(""); postfix/install_check.pl0000775000567100000120000000060011137644403015376 0ustar jcameronwheel# install_check.pl do 'postfix-lib.pl'; # is_installed(mode) # For mode 1, returns 2 if the server is installed and configured for use by # Webmin, 1 if installed but not configured, or 0 otherwise. # For mode 0, returns 1 if installed, 0 if not sub is_installed { return 0 if (!-x $config{'postfix_control_command'}); if ($_[0]) { return 2 if (!&check_postfix()); } return 1; } postfix/config-netbsd0000644000567100000120000000127511137644403014707 0ustar jcameronwheelpostfix_control_command=/usr/sbin/postfix postfix_config_command=/usr/sbin/postconf postfix_config_file=/etc/postfix/main.cf postfix_aliases_table_command=/usr/sbin/postalias postfix_newaliases_command=/usr/bin/newaliases postfix_lookup_table_command=/usr/sbin/postmap postfix_queue_command=/usr/sbin/postqueue postfix_super_command=/usr/sbin/postsuper max_records=200 perpage=20 mailq_dir=/var/spool/postfix mailq_cmd=/usr/bin/mailq postcat_cmd=/usr/sbin/postcat sort_mode=0 fwd_mode=0 mailq_sort=0 mailq_count=0 delete_warn=1 mailq_sort=0 check_config=1 top_buttons=1 wrap_width=80 index_check=1 postfix_master=/etc/postfix/master.cf columns=2 show_cmts=0 prefix_cmts=0 ldap_doms=0 delete_confirm=1 postfix/config.info.de0000664000567100000120000000362611137644403014757 0ustar jcameronwheelline1=Konfigurierbare Optionen,11 perpage=Mailnachrichten für die Anzeige pro Seite,0,6 wrap_width=Breite für Zeilenumbruch der Nachrichten,0 sort_mode=Sotiere Tabellen nach,1,0-Reihenfolge in Datei,1-Name columns=Spalten für Aliase und andere Tabellen,1,2-2,1-1 show_cmts=Zeige Beschreibungen in Tabellen?,1,1-Ja,0-Nein prefix_cmts=Beginne alle beschreibenden Kommentare mit Webmin?,1,1-Ja,0-Nein mailq_sort=Sortiere Mailqueue nach,1,0-Queue ID,1-Absenderadresse,2-Empfängeradresse,4-Status,5-Größe mailq_count=Zeige Größe der Mailqueue auf der Hauptseite?,1,0-Ja,1-Nein check_config=Konfigurationsdatei nach Änderungen prüfen?,1,1-Ja,0-Nein index_check=Postfix Konfiguration auf Hauptseite prüfen?,1,1-Ja,0-Nein line2=Systemkonfiguration,11 postfix_control_command=Vollständiger Pfad zum Postfix Kontrollprogramm,0 postfix_config_command=Vollständiger Pfad zum Postfix Konfigurationsprogramm,0 postfix_config_file=Vollständiger Pfad zur Postfix Konfigurationsdatei,0 postfix_master=Vollständiger Pfad zur master.cf Datei,0 postfix_aliases_table_command=Vollständiger Pfad zum Befehl zum Erstellen von Postfix-Aliasen,0 postfix_newaliases_command=Vollständiger Pfad zum "newaliases" (Sendmail Kompatibilität) Befehl,0 postfix_lookup_table_command=Vollständiger Pfad zum Lookup-Tabellen Management-Befehl (`postmap'),0 postfix_queue_command=Vollständiger Pfad zum Postfix Queueverwaltungskommando (`postqueue'),0 postfix_super_command=Vollständiger Pfad zum Postfix supervisor Kommando,0 mailq_dir=Basisverzeichnis der Mailqueue,0 mailq_cmd=Mailqueue Anzeigekommando,0 postcat_cmd=Mailqueue Dekodierkommando,0 start_cmd=Startbefehl für Postfix,3,Benutze Kontrollbefehl stop_cmd=Stopbefehle für Postfix,3,Benutze Kontrollbefehl reload_cmd=Kommando um Postfix Konfiguration anzuwenden,3,Benutze Kontrollbefehl postfix/help/0000755000567100000120000000000011137644405013167 5ustar jcameronwheelpostfix/help/opt_prepend_delivered_header.pl.html0000664000567100000120000000072411137644403022344 0ustar jcameronwheel
Docza Delivered-To: gdy...
prepend_delivered_header

Ten parametr okrela, kiedy Postfix powinien doczc do wiadomoci nagwek Delivered-To:.

Domylnie, Postfix docza nagwek Delivered-To:, podczas przekazywania poczty oraz podczas dorczania do pliku (skrzynki pocztowej) i do programu. Wyczenie nagwka Delivered-To: przy przekazywaniu poczty nie jest zalecane.


postfix/help/opt_best_mx_transport.pl.html0000664000567100000120000000101411137644403021122 0ustar jcameronwheel
Akcja, gdy host jest MX-em o najwyszym priorytecie
best_mx_transport

Ten parametr okrela co si dzieje, gdy the lokalny system jest wymieniony jako MX o najwyszym priorytecie. Domylnie, Postfix sygnalizuje bd "mail loops back to myself" i odrzuca wiadomo.

Podaj local, aby przekaza poczte lokalnemu programowi dorczajcemu. Moesz poda dowoln metod ekspedycji zdefiniowan w pliku Postfiksa master.cf.


postfix/help/intro.ca.html0000644000567100000120000000105711137644403015573 0ustar jcameronwheel
Postfix
Postfix l'intent de Wietse Venema de donar una alternativa al programa Sendmail, mpliament usat. Sendmail s el responsable de la majoria de correu enviat a travs d'Internet. Amb un nombre estimat d'usuaris de 100 milions, aix s alguns bilions de missatges diaris. Un nmero per quedar esmaperdut.

Postfix intenta ser rpid, senzill d'administrar i segur, al mateix temps que s prou compatible amb sendmail com per no fastiguejar els usuaris existents.


postfix/help/opt_myorigin.pl.html0000664000567100000120000000073511137644403017213 0ustar jcameronwheel
Wasna domena w poczcie wychodzcej
myorigin

Naley poda tu domen, ktra ma si pojawia w poczcie wysyanej z tej maszyny. Domylne w konfiguracji Postfiksa jest uywanie lokalnej nazwy maszyny, hostname.

Jeli ten host nie jest serwerem dla naprawd maej lokalizacji, prawdopodobnie chcesz zmieni to na domainname, dla ktrej domylna jest domena nadrzdna nazwy maszyny.


postfix/help/opt_delay_warning_time.sv.html0000644000567100000120000000046511137644403021232 0ustar jcameronwheel
Tid (timmar) innan varningsmeddelande om utebliven sndning skickas
delay_warning_time

Denna parameter anger efter hur mnga timmar en varning ska skickas om att e-postmeddelandet nnu inte har snts. Standardinstllningen r att ingen varning skickas.
postfix/help/opt_myhostname.es.html0000644000567100000120000000065211137644403017532 0ustar jcameronwheel
Nombre de mquina en Internet de este sistema de correo
myhostname

Este parmetro especifica el nombre de mquina en Internet de este sistema de correo. La opcin por defecto es usar el nombre de dominio plenamente cualificado obtenido mediante gethostname().

$myhostname se usa como valor por defecto en otras muchas opciones de configuracin.


postfix/help/alias_enabled.ru_RU.html0000664000567100000120000000024011137644403017647 0ustar jcameronwheel
. .
postfix/help/opt_default_database_type.pl.html0000664000567100000120000000062611137644404021667 0ustar jcameronwheel
Domylny rodzaj bazy danych
default_database_type

Ten parametr okrela domylny rodzaj bazy danych uywanej przez polecenia postalias(1)postmap(1). W wielu systemach uniksowych domylnym rodzajem jest albo `dbm' albo `hash'. Warto domylna tego parametru jest ustalona podczas kompilacji Postfiksa.
postfix/help/opt_relay_domains.ca.html0000644000567100000120000000200111137644404020137 0ustar jcameronwheel
Restringeix la retransmissi de correu
relay_domains

Aquest parmetre restringeix des de quins dominis de noms de host clients (i subdominis dels mateixos) acceptar retransmissions aquest sistema de correu, i restringeix sobre quins dominis de noms de host clients (i subdominis dels mateixos) far retransmissions.

Especifiqueu una llista de hosts o dominis, patrons /fitxer/nom o taules taules de consulta tipus:nom, separats per comes i/o espais en blanc. Un nom de fitxer es reemplaa pel seu contingut; una taula tipus:nom es fa coincidir quan un domini (pare) apareix com a clau de consulta.

NOTA: Postfix no reenviar automticament el correu per als dominis que tenen llistat aquest sistema com el seu host primari o MX de recanvi. Vegeu la restricci permit_mx_backup a la descripci del parmetre smtpd_recipient_restrictions


postfix/help/opt_virtual_maps.sv.html0000644000567100000120000000105411137644404020073 0ustar jcameronwheel
Domnuppslagningstabeller
virtual_maps

Denna parameter anger uppslagningstabeller som anvnds till att leda om vissa adresser eller hela domner till ngon annan adress. Detta anvnds vanligen fr att implementera std fr virtuella domner.

Standard r att ingen adressomledning grs.

Exempel:

  • dbm:/etc/postfix/virtual
  • hash:/etc/postfix/virtual
  • hash:/etc/postfix/virtual, nis:virtual
  • hash:/etc/postfix/virtual, netinfo:/virtual

postfix/help/master.html0000664000567100000120000000056611137644404015360 0ustar jcameronwheel
Server Processes
This page can be used to manage the various server processes used by Postfix for receiving and processing email. Unless you are an expert in Postfix configuration they should not generally be edited, however you want want to enable or disable certain server processes to turn on and off Postfix features like SMTP over SSL.