# procmail-lib.pl # Functions for parsing the .procmailrc file BEGIN { push(@INC, ".."); }; use WebminCore; &init_config(); %minfo = &get_module_info($module_name); if ($minfo{'usermin'}) { &switch_to_remote_user(); &create_user_config_dirs(); $procmailrc = "$remote_user_info[7]/.procmailrc"; $includes = $userconfig{'includes'}; } else { $procmailrc = $config{'procmailrc'}; $includes = $config{'includes'}; } # get_procmailrc() # Parses the .procmailrc file into recipes sub get_procmailrc { return &parse_procmail_file($procmailrc); } # parse_procmail_file(file) sub parse_procmail_file { local (@rv, $rec, $_); local $lnum = 0; local $fh = $_[0]; open($fh, "<".$_[0]); while(<$fh>) { local $slnum = $lnum; s/\s+$//; while(s/\\$//) { local $cont = <$fh>; last if (!$cont); $cont =~ s/\s+$//; $cont =~ s/^\s+//; $_ .= $cont; $lnum++; } while(/^\s*([^\s=]+)\s*=([^"]*)"([^"]*)$/) { # Quote in environment variable that is not ended! local $cont = <$fh>; last if (!$cont); $cont =~ s/\r|\n//g; $_ .= "\n".$cont; $lnum++; } if (!/^\*/) { s/#.*$//; s/\s+$//; } if (/^\s*([^\s=]+)\s*=\s*"((.|\n)*)"$/ || /^\s*([^\s=]+)\s*=\s*'((.|\n)*)'$/ || /^\s*([^\s=]+)\s*=\s*((.|\n)*)$/) { if ($1 eq "INCLUDERC") { local $ifile = $2; if ($includes && $ifile !~ /\$/) { # Including another file local @inc = &parse_procmail_file( &make_absolute($ifile, $procmailrc)); map { $_->{'index'} += scalar(@rv) } @inc; push(@rv, @inc); } else { # Just indicate the include local $inc = { 'index' => scalar(@rv), 'file' => $_[0], 'line' => $slnum, 'eline' => $lnum, 'include' => $ifile }; push(@rv, $inc); } } elsif ($1 eq "SWITCHRC") { # Change to another file local @inc = &parse_procmail_file( &make_absolute("$2", $procmailrc)); map { $_->{'index'} += scalar(@rv) } @inc; push(@rv, @inc); last; } elsif ($rec) { # Environment variable as action for recipe $rec->{'type'} = "="; $rec->{'action'} = "$1=$2"; $rec->{'eline'} = $lnum; $rec = undef; } else { # Environment variable assignment local $env = { 'index' => scalar(@rv), 'file' => $_[0], 'line' => $slnum, 'eline' => $lnum, 'name' => $1, 'value' => $2 }; push(@rv, $env); } } elsif (/^\s*:0\s*(\S*)\s*:\s*(.*)$/ || /^:0\s*(\S*)/) { # Start of a new recipe $rec = { 'index' => scalar(@rv), 'file' => $_[0], 'line' => $slnum, 'eline' => $lnum, 'lockfile' => $2, 'flags' => [ split(//, $1) ] }; push(@rv, $rec); } elsif (/^\s*\*\s*(\!|\$|\?|<|>|)(.*)$/) { # A condition for a recipe push(@{$rec->{'conds'}}, [ $1, $2 ]); $rec->{'eline'} = $lnum; } elsif (/^\s*\{\s*$/) { # A conditional action .. read till the end local $nest = 1; $rec->{'block'} = ""; while(<$fh>) { $lnum++; if (/^\{\s*$/) { $nest++; } elsif (/^\}\s*$/) { last if (!--$nest); } $rec->{'block'} .= $_; } $rec->{'eline'} = $lnum; $rec = undef; } elsif (/^\s*\{(.*)\}\s*$/) { # A single-line conditional action .. $rec->{'block'} = $1; $rec->{'eline'} = $lnum; $rec = undef; } elsif (/^\s*(\!|\|)\s*(.*)$/) { # The action for a recipe $rec->{'type'} = $1; $rec->{'action'} = $2; $rec->{'eline'} = $lnum; $rec = undef; } elsif (/\S/) { if ($rec->{'action'}) { # Unknown line &error(&text('config_eline', $slnum+1, $_[0], "<tt>$_</tt>")); } else { # File delivery action $rec->{'type'} = undef; $rec->{'action'} = $_; $rec->{'eline'} = $lnum; if ($rec->{'action'} =~ /^\"(.*)\"$/) { # Quoted path .. un-quote $rec->{'action'} = $1; } $rec = undef; } } $lnum++; } close($fh); return @rv; } # create_recipe(&recipe, [file]) sub create_recipe { local $lref = &read_file_lines($_[1] || $procmailrc); push(@$lref, &recipe_lines($_[0])); &flush_file_lines(); } # create_recipe_before(&recipe, &before, [file]) sub create_recipe_before { local $lref = &read_file_lines($_[2] || $procmailrc); local @lines = &recipe_lines($_[0]); splice(@$lref, $_[1]->{'line'}, 0, @lines); $_[1]->{'line'} += @lines; $_[1]->{'eline'} += @lines; &flush_file_lines(); } # delete_recipe(&recipe) sub delete_recipe { local $lref = &read_file_lines($_[0]->{'file'}); splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1); &flush_file_lines(); } # modify_recipe(&recipe) sub modify_recipe { local $lref = &read_file_lines($_[0]->{'file'}); splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1, &recipe_lines($_[0])); &flush_file_lines(); } # swap_recipes(&recipe1, &recipe2) sub swap_recipes { local $lref0 = &read_file_lines($_[0]->{'file'}); local $lref1 = &read_file_lines($_[1]->{'file'}); local @lines0 = @$lref0[$_[0]->{'line'} .. $_[0]->{'eline'}]; local @lines1 = @$lref1[$_[1]->{'line'} .. $_[1]->{'eline'}]; if ($_[0]->{'line'} < $_[1]->{'line'}) { splice(@$lref1, $_[1]->{'line'}, $_[1]->{'eline'} - $_[1]->{'line'} + 1, @lines0); splice(@$lref0, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1, @lines1); } else { splice(@$lref0, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1, @lines1); splice(@$lref1, $_[1]->{'line'}, $_[1]->{'eline'} - $_[1]->{'line'} + 1, @lines0); } &flush_file_lines(); } sub recipe_lines { if ($_[0]->{'name'}) { # Environment variable local $v = $_[0]->{'value'} =~ /\n/ ? $_[0]->{'value'} : $_[0]->{'value'} =~ /^\`/ ? $_[0]->{'value'} : $_[0]->{'value'} =~ /^\S+$/ ? $_[0]->{'value'} : $_[0]->{'value'} =~ /"/ ? "'$_[0]->{'value'}'" : "\"$_[0]->{'value'}\""; return ( $_[0]->{'name'}."=".$v ); } elsif ($_[0]->{'include'}) { # Included file local $v = $_[0]->{'include'} =~ /^\`/ ? $_[0]->{'include'} : $_[0]->{'include'} =~ /^\S+$/ ? $_[0]->{'include'} : $_[0]->{'include'} =~ /"/ ? "'$_[0]->{'include'}'" : "\"$_[0]->{'include'}\""; return ( "INCLUDERC=".$v ); } else { # Recipe with conditions and action local (@rv, $c); push(@rv, ":0".join("", @{$_[0]->{'flags'}})); if (defined($_[0]->{'lockfile'})) { $rv[0] .= ":".$_[0]->{'lockfile'}; } foreach $c (@{$_[0]->{'conds'}}) { push(@rv, "* ".$c->[0].$c->[1]); } if (defined($_[0]->{'block'})) { push(@rv, "{", split(/\n/, $_[0]->{'block'}), "}"); } elsif ($_[0]->{'type'} && $_[0]->{'type'} ne '=') { push(@rv, $_[0]->{'type'}." ".$_[0]->{'action'}); } elsif ($_[0]->{'action'} =~ /^(\S+)=/) { # Variable assignment .. don't quote push(@rv, $_[0]->{'action'}); } elsif ($_[0]->{'action'} !~ /^\S+$/) { # File with a space .. need to quote push(@rv, "\"$_[0]->{'action'}\""); } else { # File delivery push(@rv, $_[0]->{'action'}); } return @rv; } } # parse_action(&recipe) sub parse_action { if ($_[0]->{'type'} eq '|') { return (4, $_[0]->{'action'}); } elsif ($_[0]->{'type'} eq '!') { return (3, $_[0]->{'action'}); } elsif ($_[0]->{'type'} eq '=') { local ($n, $v) = split(/=/, $_[0]->{'action'}, 2); return (6, $n); } elsif (defined($_[0]->{'block'})) { return (5); } elsif ($_[0]->{'action'} =~ /^(.*)\/$/) { return (2, $1); } elsif ($_[0]->{'action'} =~ /^(.*)\/\.$/) { return (1, $1); } else { return (0, $_[0]->{'action'}); } } # make_absolute(file, basefile) sub make_absolute { return $_[0] if ($_[0] =~ /^\//); $_[1] =~ /^(.*)\/[^\/]+$/; return "$1/$_[0]"; } # check_mailserver_config() # Works out which mail server appears to be installed, and returns the # module name and possibly an error message if Procmail is not setup sub check_mailserver_config { # Find a running mail server local $ms = &foreign_installed("qmailadmin") && &qmailadmin::is_qmail_running() ? "qmailadmin" : &foreign_installed("postfix") && &postfix::is_postfix_running() ? "postfix" : &foreign_installed("sendmail") && &sendmail::is_sendmail_running() ? "sendmail" : undef; # Fall back to installed mail server local $ms = &foreign_installed("qmailadmin") ? "qmailadmin" : &foreign_installed("postfix") ? "postfix" : &foreign_installed("sendmail") ? "sendmail" : undef; return () if (!$ms); local $err; local $procmail_cmd = &has_command($config{'procmail'}); if ($ms eq "qmailadmin") { # Don't know how to check for this $err = undef; } elsif ($ms eq "postfix") { # Check mailbox_command &foreign_require("postfix", "postfix-lib.pl"); local $cmd = &postfix::get_real_value("mailbox_command"); if ($cmd !~ /procmail/) { $err = &text('check_epostfix', "mailbox_command", $postfix::config{'postfix_config_file'}, $procmail_cmd); } } elsif ($ms eq "sendmail") { # Check for local or procmail mailer &foreign_require("sendmail", "sendmail-lib.pl"); local $conf = &sendmail::get_sendmailcf(); local $found; foreach my $c (@$conf) { if ($c->{'type'} eq 'M' && $c->{'value'} =~ /procmail/) { $found++; last; } } if (!$found) { $err = &text('check_esendmail','../sendmail/list_features.cgi'); } } return ($ms, $err); } # check_virtualmin_config(&config) # Returns 1 if Virtualmin created this procmail config sub check_virtualmin_config { my ($conf) = @_; return 0 if (!&foreign_check("virtual-server")); &foreign_require("virtual-server"); my $gotvirt = 0; foreach my $r (@$conf) { if ($r->{'type'} eq '=' && $r->{'action'} =~ /^VIRTUALMIN=/) { $gotvirt++; } } return $gotvirt; } @known_flags = ('H', 'B', 'D', 'h', 'b', 'c', 'w', 'W', 'i', 'r', 'f'); 1;
Name | Type | Size | Permission | Actions |
---|---|---|---|---|
images | Folder | 0755 |
|
|
lang | Folder | 0755 |
|
|
CHANGELOG | File | 289 B | 0644 |
|
backup_config.pl | File | 649 B | 0755 |
|
cgi_args.pl | File | 488 B | 0755 |
|
config | File | 56 B | 0644 |
|
config-freebsd | File | 66 B | 0644 |
|
config.info | File | 237 B | 0644 |
|
config.info.ca | File | 281 B | 0644 |
|
config.info.cs | File | 212 B | 0644 |
|
config.info.de | File | 265 B | 0644 |
|
config.info.es | File | 57 B | 0644 |
|
config.info.fr | File | 265 B | 0644 |
|
config.info.hu | File | 0 B | 0644 |
|
config.info.ko | File | 272 B | 0644 |
|
config.info.nl | File | 262 B | 0644 |
|
config.info.no | File | 244 B | 0644 |
|
config.info.pl | File | 0 B | 0644 |
|
config.info.ru | File | 278 B | 0644 |
|
config.info.uk | File | 296 B | 0644 |
|
delete_recipes.cgi | File | 418 B | 0755 |
|
down.cgi | File | 277 B | 0755 |
|
edit_env.cgi | File | 1022 B | 0755 |
|
edit_inc.cgi | File | 864 B | 0755 |
|
edit_recipe.cgi | File | 2.75 KB | 0755 |
|
index.cgi | File | 4.79 KB | 0755 |
|
install_check.pl | File | 483 B | 0755 |
|
log_parser.pl | File | 764 B | 0755 |
|
manual_form.cgi | File | 533 B | 0755 |
|
manual_save.cgi | File | 331 B | 0755 |
|
module.info | File | 198 B | 0644 |
|
module.info.af | File | 0 B | 0644 |
|
module.info.af.auto | File | 161 B | 0644 |
|
module.info.ar | File | 0 B | 0644 |
|
module.info.ar.auto | File | 222 B | 0644 |
|
module.info.be | File | 0 B | 0644 |
|
module.info.be.auto | File | 265 B | 0644 |
|
module.info.bg | File | 0 B | 0644 |
|
module.info.bg.auto | File | 225 B | 0644 |
|
module.info.ca | File | 142 B | 0644 |
|
module.info.ca.auto | File | 17 B | 0644 |
|
module.info.cs | File | 35 B | 0644 |
|
module.info.cs.auto | File | 137 B | 0644 |
|
module.info.da | File | 0 B | 0644 |
|
module.info.da.auto | File | 154 B | 0644 |
|
module.info.de | File | 149 B | 0644 |
|
module.info.de.auto | File | 17 B | 0644 |
|
module.info.el | File | 0 B | 0644 |
|
module.info.el.auto | File | 335 B | 0644 |
|
module.info.es | File | 34 B | 0644 |
|
module.info.es.auto | File | 150 B | 0644 |
|
module.info.eu | File | 0 B | 0644 |
|
module.info.eu.auto | File | 175 B | 0644 |
|
module.info.fa | File | 0 B | 0644 |
|
module.info.fa.auto | File | 243 B | 0644 |
|
module.info.fi | File | 0 B | 0644 |
|
module.info.fi.auto | File | 179 B | 0644 |
|
module.info.fr | File | 36 B | 0644 |
|
module.info.fr.auto | File | 139 B | 0644 |
|
module.info.he | File | 0 B | 0644 |
|
module.info.he.auto | File | 183 B | 0644 |
|
module.info.hr | File | 0 B | 0644 |
|
module.info.hr.auto | File | 158 B | 0644 |
|
module.info.hu | File | 37 B | 0644 |
|
module.info.hu.auto | File | 135 B | 0644 |
|
module.info.it | File | 37 B | 0644 |
|
module.info.it.auto | File | 129 B | 0644 |
|
module.info.ja | File | 0 B | 0644 |
|
module.info.ja.auto | File | 216 B | 0644 |
|
module.info.ko | File | 31 B | 0644 |
|
module.info.ko.auto | File | 152 B | 0644 |
|
module.info.lt | File | 0 B | 0644 |
|
module.info.lt.auto | File | 170 B | 0644 |
|
module.info.lv | File | 0 B | 0644 |
|
module.info.lv.auto | File | 177 B | 0644 |
|
module.info.ms | File | 132 B | 0644 |
|
module.info.ms.auto | File | 17 B | 0644 |
|
module.info.mt | File | 0 B | 0644 |
|
module.info.mt.auto | File | 159 B | 0644 |
|
module.info.nl | File | 31 B | 0644 |
|
module.info.nl.auto | File | 136 B | 0644 |
|
module.info.no | File | 31 B | 0644 |
|
module.info.no.auto | File | 123 B | 0644 |
|
module.info.pl | File | 33 B | 0644 |
|
module.info.pl.auto | File | 138 B | 0644 |
|
module.info.pt | File | 0 B | 0644 |
|
module.info.pt.auto | File | 156 B | 0644 |
|
module.info.pt_BR | File | 0 B | 0644 |
|
module.info.pt_BR.auto | File | 165 B | 0644 |
|
module.info.ro | File | 0 B | 0644 |
|
module.info.ro.auto | File | 160 B | 0644 |
|
module.info.ru | File | 47 B | 0644 |
|
module.info.ru.auto | File | 219 B | 0644 |
|
module.info.sk | File | 0 B | 0644 |
|
module.info.sk.auto | File | 171 B | 0644 |
|
module.info.sl | File | 0 B | 0644 |
|
module.info.sl.auto | File | 139 B | 0644 |
|
module.info.sv | File | 0 B | 0644 |
|
module.info.sv.auto | File | 157 B | 0644 |
|
module.info.th | File | 0 B | 0644 |
|
module.info.th.auto | File | 248 B | 0644 |
|
module.info.tr | File | 0 B | 0644 |
|
module.info.tr.auto | File | 165 B | 0644 |
|
module.info.uk | File | 0 B | 0644 |
|
module.info.uk.auto | File | 250 B | 0644 |
|
module.info.ur | File | 0 B | 0644 |
|
module.info.ur.auto | File | 229 B | 0644 |
|
module.info.vi | File | 0 B | 0644 |
|
module.info.vi.auto | File | 185 B | 0644 |
|
module.info.zh | File | 0 B | 0644 |
|
module.info.zh.auto | File | 154 B | 0644 |
|
module.info.zh_TW | File | 0 B | 0644 |
|
module.info.zh_TW.auto | File | 163 B | 0644 |
|
prefs.info | File | 16 B | 0644 |
|
procmail-lib.pl | File | 9.39 KB | 0755 |
|
save_env.cgi | File | 753 B | 0755 |
|
save_inc.cgi | File | 680 B | 0755 |
|
save_recipe.cgi | File | 2.58 KB | 0755 |
|
up.cgi | File | 271 B | 0755 |
|