filter/0040775000567100000120000000000010572133402012026 5ustar jcameronwheelfilter/images/0040775000567100000120000000000010546606701013303 5ustar jcameronwheelfilter/images/up.gif0100644000567100000120000000014710545330061014403 0ustar jcameronwheelGIF89arrr!Made with GIMP! ,& |'Io|b%eRG;Ssf;filter/images/down.gif0100644000567100000120000000015410545330061014724 0ustar jcameronwheelGIF89arrr!Made with GIMP! ,+@"IUieJbA I m.dN;filter/images/gap.gif0100644000567100000120000000011110545330061014515 0ustar jcameronwheelGIF89a!Made with GIMP! ,ڋ>;filter/images/icon.gif0100664000567100000120000000276610546606701014732 0ustar jcameronwheelGIF89a00fffti_?vka0//~~~~~[<ccc:( ___ NNN333+  TRQ<]D*&&& ```tttnnn璏xww_G/"""}xsssrxqj{{{mmm\H3( m[I* E4#wnesss2(wk### tjaYOEiiiA7-/"zzz jO5FFFjZKyiZIII9+vvvmcX444[SLWQKMMMTPMUQNx XTP8,o_NDDDcZRVVV?,qqqAAA888e]T555S3'''|ws% Y2 -8   }t*.ti_*]=B/Y9dP=U5oT9C$!,00 HÇ#J0ŋ3jQ)2Ȏ Xi⁗/q 8$PA D0L*̬)&ɑ%qZ!4lʡ/"Y1F!D\ADF NHq@Ҳf/XqE .^pͼc00FK\ w#Ρ$EB MM/HAH 8@HH۵sBpjڤ,<>IH0w&, &#"կ#  ^"oǐS6 F}!TJV؇rWDłX\Ԡ0Q hj[E\@l]XxҊ+z!}a""q!F!ّc# 9@QyVjDFf8ّg!3C;Q%GkŜs8trnnGa&ṟtD*餏 Pħwhy ԇW?r Z!\B!F"(#` )L[E"$ ,AJ@%\u &ZlB '+_'`eUm(ȫ( "T) *J +",JK-`KdzBIȸ+r\./z.֬)/2' "D't20C'mP02;0,K,;filter/module.info0100664000567100000120000000023110572133423014164 0ustar jcameronwheeldesc=Filter Mail depends=mailbox procmail forward spam category=mail longdesc=Create rules to filter and forward incoming email. usermin=1 version=1.261 filter/lang/0040775000567100000120000000000010547010002012737 5ustar jcameronwheelfilter/lang/en0100664000567100000120000000461010547010002013262 0ustar jcameronwheelindex_title=Filter Mail index_condition=Filter condition index_action=Filter action index_move=Move index_none=You do not have any mail filters defined yet. All email will be delivered to your Inbox. index_none2=None of your existing Procmail rules are simple enough to display here. index_none3=You do not have any mail filters defined yet. All email will be delivered to your Inbox, after spam filtering. index_add=Add a new filter. index_cspam=Email is spam index_cheader=Header $1 matches $2 index_cre=Headers match $1 index_cre2=Body matches $1 index_calways=Always index_csize<=Smaller than $1 index_csize>=Larger than $1 index_aspam=Perform spam classification index_athrow=Throw away index_adefault=Deliver to your Inbox index_aforward=Forward to $1 index_afolder=Save in folder $1 index_afile=Write to file $1 index_areply=Send automatic reply $1 index_delete=Delete Selected Filters index_acontinue=$1, and continue index_return=filter list index_warn=Warning - The program procmail used for mail filtering is not installed on this system. Any filters defined below are unlikely to work. edit_title1=Create Filter edit_title2=Edit Filter edit_header1=Condition for filter edit_cmode0=All email edit_cmode4=Based on header edit_cheader=Header $1$2 must match $3 edit_cmode3=Email smaller than edit_cmode2=Email larger than edit_cmode5=Email classified as spam edit_cmode1=Based on regular expression edit_cbody=Apply to message body edit_other=Other.. edit_header2=Action if condition is matched edit_amode3=Deliver to Inbox edit_amode5=Perform spam classification edit_amode4=Throw away edit_amode1=Forward to addresses edit_amode0=Save to folder edit_file=Other file.. edit_continue=Continue with other filter rules, even after applying this action edit_amode6=Send automatic reply edit_amode7=Save to new folder named save_err=Failed to save filter save_econdheader=Missing or invalid email header save_esmall=Missing or invalid maximum mail size save_elarge=Missing or invalid minimum mail size save_econd=Missing regular expression save_eforward=Missing forwarding address save_efile=Missing mail file for delivery save_ereply=No autoreply text entered save_eperiod=Missing or invalid automatic reply interval save_enewfolder=Missing new folder name save_enewfolder2=Invalid new folder name save_enewfolder3=A folder with the same name already exists delete_err=Failed to delete filters delete_enone=None selected filter/down.cgi0100775000567100000120000000041310546600445013466 0ustar jcameronwheel#!/usr/local/bin/perl # Move some filter down require './filter-lib.pl'; &ReadParse(); &lock_file($procmail::procmailrc); @filters = &list_filters(); &swap_filters($filters[$in{'idx'}], $filters[$in{'idx'}+1]); &unlock_file($procmail::procmailrc); &redirect(""); filter/filter-lib.pl0100664000567100000120000001471110563175761014433 0ustar jcameronwheel# Functions for creating simple mail filtering rules # XXX use same virtualmin spam detection trick for spam module do '../web-lib.pl'; &init_config(); do '../ui-lib.pl'; # If configured, check if this user has virtualmin spam filtering enabled # before switching away from root if ($config{'virtualmin_spam'} && -x $config{'virtualmin_spam'}) { local $out = `$config{'virtualmin_spam'} $remote_user /dev/null`; if ($out =~ /\d/) { # Yes - we can show the user this $global_spamassassin = 2; } } &foreign_require("forward", "forward-lib.pl"); &switch_to_remote_user(); &create_user_config_dirs(); &foreign_require("procmail", "procmail-lib.pl"); &foreign_require("mailbox", "mailbox-lib.pl"); &foreign_require("spam", "spam-lib.pl"); $autoreply_cmd = "$forward::module_config_directory/autoreply.pl"; # list_filters() # Returns a list of filter objects, which have a 1-to-1 correlation with # procmail recipes. Any recipes too complex for parsing are not included. sub list_filters { local @rv; local @pmrc = &procmail::get_procmailrc(); foreach my $r (@pmrc) { # Check for un-supported recipes if (@{$r->{'conds'}} > 1 || $r->{'block'} || $r->{'name'}) { next; } # Check for flags local %flags = map { $_, 1 } @{$r->{'flags'}}; # Work out condition type local ($condtype, $cond); if (@{$r->{'conds'}}) { ($condtype, $cond) = @{$r->{'conds'}->[0]}; if ($condtype && $condtype ne "<" && $condtype ne ">") { # Unsupported conditon type next; } } # Work out action type local ($actionspam, $actionreply); if ($r->{'type'} eq '|' && $r->{'action'} =~ /spamassassin|spamc/) { $actionspam = 1; } elsif ($r->{'type'} eq '|' && $r->{'action'} =~ /^\Q$autoreply_cmd\E\s+(\S+)/) { $actionreply = $1; } elsif ($r->{'type'} && $r->{'type'} ne '!') { # Unsupported action type next; } # Finally create the simple object local $simple = { 'condtype' => $condtype, 'cond' => $cond, 'body' => $flags{'B'}, 'continue' => $flags{'c'}, 'actiontype' => $r->{'type'}, 'action' => $r->{'action'}, 'index' => scalar(@rv), 'recipe' => $r }; # Set spam flag if ($actionspam) { $simple->{'actionspam'} = 1; delete($simple->{'actiontype'}); delete($simple->{'action'}); } # Check for throw away if ($simple->{'actiontype'} eq '' && $simple->{'action'} eq '/dev/null') { $simple->{'actionthrow'} = 1; delete($simple->{'actiontype'}); delete($simple->{'action'}); } # Check for default delivery if ($simple->{'actiontype'} eq '' && $simple->{'action'} eq '$DEFAULT') { $simple->{'actiondefault'} = 1; delete($simple->{'actiontype'}); delete($simple->{'action'}); } # Read autoreply file if ($actionreply) { $simple->{'actionreply'} = $actionreply; $simple->{'reply'} = { }; &forward::read_autoreply($actionreply, $simple->{'reply'}); delete($simple->{'actiontype'}); delete($simple->{'action'}); } # Split condition regexp into header and value, if possible if ($simple->{'condtype'} ne '<' && $simple->{'condtype'} ne '>' && !$simple->{'body'} && $simple->{'cond'} =~ /^\^?([a-zA-Z0-9\-]+):\s*(.*)/) { if ($1 eq "X-Spam-Status" && $2 eq "Yes") { # Special case for spam detection $simple->{'condspam'} = 1; } else { # Match on some header $simple->{'condheader'} = $1; $simple->{'condvalue'} = $2; } delete($simple->{'cond'}); } push(@rv, $simple); } return @rv; } # create_filter(&filter) # Create a new filter by adding a procmail recipe sub create_filter { local ($filter) = @_; local $recipe = { }; &update_filter_recipe($filter, $recipe); &procmail::create_recipe($recipe); } # modify_filter(&filter) # Change a filter by modifying the underlying procmail recipe sub modify_filter { local ($filter) = @_; &update_filter_recipe($filter, $filter->{'recipe'}); &procmail::modify_recipe($filter->{'recipe'}); } # update_filter_recipe(&filter, &recipe) # Update a procmail recipe based on some filter sub update_filter_recipe { local ($filter, $recipe) = @_; # Set condition section local @conds; local @flags; if ($filter->{'condspam'}) { @conds = ( [ "", "X-Spam-Status: Yes" ] ); } elsif ($filter->{'condheader'}) { @conds = ( [ "", $filter->{'condheader'}.": ". $filter->{'condvalue'} ] ); } elsif ($filter->{'condtype'} eq '<' || $filter->{'condtype'} eq '>') { @conds = ( [ $filter->{'condtype'}, $filter->{'cond'} ] ); } elsif ($filter->{'cond'}) { @conds = ( [ "", $filter->{'cond'} ] ); } $recipe->{'conds'} = \@conds; # Set action section if ($filter->{'actionspam'}) { $recipe->{'type'} = '|'; $recipe->{'action'} = &spam::get_procmail_command(); push(@flags, "f", "w"); } elsif ($filter->{'actionthrow'}) { $recipe->{'type'} = ''; $recipe->{'action'} = '/dev/null'; } elsif ($filter->{'actiondefault'}) { $recipe->{'type'} = ''; $recipe->{'action'} = '$DEFAULT'; } elsif ($filter->{'actionreply'}) { $recipe->{'type'} = '|'; $recipe->{'action'} = "$autoreply_cmd $filter->{'reply'}->{'autoreply'} $remote_user"; &forward::write_autoreply($filter->{'reply'}->{'autoreply'}, $filter->{'reply'}); } else { $recipe->{'type'} = $filter->{'actiontype'}; $recipe->{'action'} = $filter->{'action'}; } # Set flags push(@flags, "B") if ($filter->{'body'}); push(@flags, "c") if ($filter->{'continue'}); $recipe->{'flags'} = [ &unique(@flags) ]; } # delete_filter(&filter) # Delete a filter by removing the underlying procmail rule sub delete_filter { local ($filter) = @_; &procmail::delete_recipe($filter->{'recipe'}); } # swap_filters(&filter1, &filter2) # Swap two filters in the config file sub swap_filters { local ($filter1, $filter2) = @_; &procmail::swap_recipes($filter1->{'recipe'}, $filter2->{'recipe'}); } # file_to_folder(file, &folders) # Given a path like mail/foo or ~/mail/foo or $HOME/mail/foo or # /home/bob/mail/foo, returns the folder object for it. sub file_to_folder { local ($file, $folders) = @_; $file =~ s/^\~/$remote_user_info[7]/; $file =~ s/^\$HOME/$remote_user_info[7]/; if ($file !~ /^\//) { $file = "$remote_user_info[7]/$file"; } local ($folder) = grep { $_->{'file'} eq $file || $_->{'file'}.'/' eq $file } @$folders; return $folder; } # get_global_spamassassin() # Returns true if spamasassin is run globally sub get_global_spamassassin { return $global_spamassassin if ($global_spamassassin); local @recipes = &procmail::parse_procmail_file( $spam::config{'global_procmailrc'}); return &spam::find_spam_recipe(\@recipes) ? 1 : 0; } sub has_spamassassin { return &foreign_installed("spam"); } 1; filter/index.cgi0100775000567100000120000001004310547007164013626 0ustar jcameronwheel#!/usr/local/bin/perl # Show a table of simple actions require './filter-lib.pl'; &ui_print_header(undef, $text{'index_title'}, "", undef, 0, 1); # Warn if procmail is not installed if ($config{'warn_procmail'} && !&has_command("procmail")) { print "$text{'index_warn'}

\n"; } @filters = &list_filters(); @links = ( &select_all_link("d"), &select_invert_link("d"), "$text{'index_add'}" ); @folders = &mailbox::list_folders(); if (@filters) { # Show table of filters print &ui_form_start("delete.cgi", "post"); @tds = ( "width=5", "width=50%", "width=50%", "width=32" ); print &ui_links_row(\@links); print &ui_columns_start([ "", $text{'index_condition'}, $text{'index_action'}, @filters > 1 ? ( $text{'index_move'} ) : ( ), ], 100, 0, \@tds); # Add a magic non-editable row for global spamassassin run if (&get_global_spamassassin()) { print &ui_columns_row( [ "", $text{'index_calways'}, $text{'index_aspam'}, @filters > 1 ? ( "" ) : ( ) ], \@tds); } # Show editable rows foreach $f (@filters) { # Work out nice condition description local $cond; $lastalways = 0; if ($f->{'condspam'}) { $cond = $text{'index_cspam'}; } elsif ($f->{'condheader'}) { $cond = &text('index_cheader', "$f->{'condheader'}", "$f->{'condvalue'}"); } elsif ($f->{'condtype'} eq '<' || $f->{'condtype'} eq '>') { $cond = &text('index_csize'.$f->{'condtype'}, &nice_size($f->{'cond'})); } elsif ($f->{'cond'}) { $cond = &text($f->{'body'} ? 'index_cre2' : 'index_cre', "$f->{'cond'}"); } else { $cond = $text{'index_calways'}; if (!$f->{'continue'} && !$f->{'actionspam'}) { $lastalways = 1; } } $cond = "$cond"; # Work out nice action description local $action; if ($f->{'actionspam'}) { $action = $text{'index_aspam'}; } elsif ($f->{'actionthrow'}) { $action = $text{'index_athrow'}; } elsif ($f->{'actiondefault'}) { $action = $text{'index_adefault'}; } elsif ($f->{'actiontype'} eq '!') { $action = &text('index_aforward', "$f->{'action'}"); } elsif ($f->{'actionreply'}) { $action = &text('index_areply', "".&html_escape(substr( $f->{'reply'}->{'autotext'}, 0, 50)).""); } else { # Work out what folder $folder = &file_to_folder($f->{'action'}, \@folders); if ($folder) { $id = &mailbox::folder_name($folder); $action = &text('index_afolder', "". "$folder->{'name'}"); } else { $action = &text('index_afile', "$f->{'action'}"); } } if ($f->{'continue'}) { $action = &text('index_acontinue', $action); } # Create mover links local $mover; if ($f eq $filters[0]) { $mover .= ""; } else { $mover .= "". ""; } if ($f eq $filters[$#filters]) { $mover .= ""; } else { $mover .= "". ""; } # Show the row print &ui_checked_columns_row( [ $cond, $action, @filters > 1 ? ( $mover ) : ( ) ], \@tds, "d", $f->{'index'} ); } # Add a magic non-editable row for default delivery if (!$lastalways) { print &ui_columns_row( [ "", $text{'index_calways'}, $text{'index_adefault'}, @filters > 1 ? ( "" ) : ( ) ], \@tds); } print &ui_columns_end(); print &ui_links_row(\@links); print &ui_form_end([ [ "delete", $text{'index_delete'} ] ]); } else { # Tell the user there are none @pmrc = &procmail::get_procmailrc(); if (@pmrc) { print "$text{'index_none2'}

\n"; } elsif (&get_global_spamassassin()) { print "$text{'index_none3'}

\n"; } else { print "$text{'index_none'}

\n"; } shift(@links); shift(@links); print &ui_links_row(\@links); } &ui_print_footer("/", $text{'index'}); filter/edit.cgi0100775000567100000120000001171510547004705013451 0ustar jcameronwheel#!/usr/local/bin/perl # Show details of one filter require './filter-lib.pl'; &ReadParse(); # Show page header and get the filter if ($in{'new'}) { &ui_print_header(undef, $text{'edit_title1'}, ""); $filter = { 'actiondefault' => 1 }; } else { &ui_print_header(undef, $text{'edit_title2'}, ""); @filters = &list_filters(); ($filter) = grep { $_->{'index'} == $in{'idx'} } @filters; } @tds = ( "nowrap width=30%", "width=70%" ); print &ui_form_start("save.cgi", "post"); print &ui_hidden("new", $in{'new'}); print &ui_hidden("idx", $in{'idx'}); # Start of condition section $cmode = $filter->{'condspam'} ? 5 : $filter->{'condheader'} ? 4 : $filter->{'condtype'} eq '<' ? 3 : $filter->{'condtype'} eq '>' ? 2 : $filter->{'cond'} ? 1 : 0; print &ui_table_start($text{'edit_header1'}, "width=100%", 2); # Always do action print &ui_table_row( &ui_oneradio("cmode", 0, $text{'edit_cmode0'}, $cmode == 0), "", undef, \@tds); # Is spam print &ui_table_row( &ui_oneradio("cmode", 5, $text{'edit_cmode5'}, $cmode == 5), "", undef, \@tds); # Check some header @headers = ( "From", "To", "Subject", "Cc" ); $common = &indexoflc($filter->{'condheader'}, @headers) >= 0; print &ui_table_row( &ui_oneradio("cmode", 4, $text{'edit_cmode4'}, $cmode == 4), &text('edit_cheader', &ui_select("condmenu", $cmode != 4 ? "From" : $common ? $filter->{'condheader'} : "", [ (map { [ $_ ] } @headers), [ "", $text{'edit_other'} ] ], 1, 0, 0, 0, "onChange='form.condheader.disabled = (form.condmenu.value!=\"\")'"), &ui_textbox("condheader", $common ? "" : $filter->{'condheader'}, 20, $cmode != 4 || $common), &ui_textbox("condvalue", $filter->{'condvalue'}, 20)), undef, \@tds); # Smaller print &ui_table_row( &ui_oneradio("cmode", 3, $text{'edit_cmode3'}, $cmode == 3), &ui_bytesbox("condsmall", $cmode == 3 ? $filter->{'cond'} : ""), undef, \@tds); # Larger print &ui_table_row( &ui_oneradio("cmode", 2, $text{'edit_cmode2'}, $cmode == 2), &ui_bytesbox("condlarge", $cmode == 2 ? $filter->{'cond'} : ""), undef, \@tds); # Matches regexp print &ui_table_row( &ui_oneradio("cmode", 1, $text{'edit_cmode1'}, $cmode == 1), &ui_textbox("cond", $cmode == 1 ? $filter->{'cond'} : "", 70)."
". &ui_checkbox("body", 1, $text{'edit_cbody'}, $filter->{'body'}), undef, \@tds); print &ui_table_end(); # Start of action section $amode = $filter->{'actionreply'} ? 6 : $filter->{'actionspam'} ? 5 : $filter->{'actionthrow'} ? 4 : $filter->{'actiondefault'} ? 3 : $filter->{'actionreply'} ? 2 : $filter->{'actiontype'} eq '!' ? 1 : 0; print &ui_table_start($text{'edit_header2'}, "width=100%", 2); # Deliver normally print &ui_table_row( &ui_oneradio("amode", 3, $text{'edit_amode3'}, $amode == 3), "", undef, \@tds); if ($amode == 5 || &has_spamassassin()) { # Run spamassassin print &ui_table_row( &ui_oneradio("amode", 5, $text{'edit_amode5'}, $amode == 5), "", undef, \@tds); } # Throw away print &ui_table_row( &ui_oneradio("amode", 4, $text{'edit_amode4'}, $amode == 4), "", undef, \@tds); # Forward to some address print &ui_table_row( &ui_oneradio("amode", 1, $text{'edit_amode1'}, $amode == 1), &ui_textbox("forward", $amode == 1 ? $filter->{'action'} : "", 70), undef, \@tds); # Save to a folder or file @folders = grep { $_->{'file'} } &mailbox::list_folders(); if ($amode == 0) { $folder = &file_to_folder($filter->{'action'}, \@folders); } else { $folder = $folders[0]; } print &ui_table_row( &ui_oneradio("amode", 0, $text{'edit_amode0'}, $amode == 0), &ui_select("folder", $folder ? &mailbox::folder_name($folder) : "", [ (map { [ &mailbox::folder_name($_), $_->{'name'} ] } @folders), [ "", $text{'edit_file'} ] ], 1, 0, 0, 0, "onChange='form.file.disabled = (form.folder.value!=\"\")'"). "\n". &ui_textbox("file", $folder ? "" : $filter->{'action'}, 50, $folder ? 1 : 0), undef, \@tds); # Save to a new folder print &ui_table_row( &ui_oneradio("amode", 7, $text{'edit_amode7'}, 0), &ui_textbox("newfolder", undef, 20), undef, \@tds); # Send autoreply if ($amode == 6) { $r = $filter->{'reply'}; $period = $r->{'replies'} && $r->{'period'} ? int($r->{'period'}/60) : $r->{'replies'} ? 60 : undef; } print &ui_table_row( &ui_oneradio("amode", 6, $text{'edit_amode6'}, $amode == 6), &ui_textarea("reply", $filter->{'reply'}->{'autotext'}, 5, 60)."
". "$forward::text{'index_period'} ". &ui_opt_textbox("period", $period, 3, $forward::text{'index_noperiod'})." ". $forward::text{'index_mins'}, undef, \@tds); # Continue checkbox print &ui_table_row( undef, &ui_checkbox("continue", 1, $text{'edit_continue'}, $filter->{'continue'}), 2); print &ui_table_end(); # End of the form, with buttons if ($in{'new'}) { print &ui_form_end([ [ "create", $text{'create'} ] ]); } else { print &ui_form_end([ [ "save", $text{'save'} ], [ "delete", $text{'delete'} ] ]); } # Show page footer &ui_print_footer("", $text{'index_return'}); filter/CHANGELOG0100664000567100000120000000015010547245426013245 0ustar jcameronwheel---- Changes since 1.240 ---- First version of this module, which allows simple Procmail configuration. filter/save.cgi0100775000567100000120000001065010571607717013470 0ustar jcameronwheel#!/usr/local/bin/perl # Create, update or delete a filter require './filter-lib.pl'; &ReadParse(); # Find existing filter object &lock_file($procmail::procmailrc); @filters = &list_filters(); if (!$in{'new'}) { ($filter) = grep { $_->{'index'} == $in{'idx'} } @filters; } else { $filter = { 'index' => scalar(@filters) }; } if ($in{'delete'}) { # Just remove &delete_filter($filter); } else { # Validate and store inputs &error_setup($text{'save_err'}); # Parse condition first delete($filter->{'condspam'}); delete($filter->{'condheader'}); delete($filter->{'condtype'}); delete($filter->{'cond'}); $filter->{'body'} = 0; if ($in{'cmode'} == 0) { # Always enabled, so nothing to set! } elsif ($in{'cmode'} == 5) { # Need to run spamassassin $filter->{'condspam'} = 1; } elsif ($in{'cmode'} == 4) { # Check some header $filter->{'condheader'} = $in{'condmenu'} || $in{'condheader'}; $filter->{'condheader'} =~ /^[a-zA-Z0-9\-]+$/ || &errror($text{'save_econdheader'}); $filter->{'condvalue'} = $in{'condvalue'}; } elsif ($in{'cmode'} == 3) { # Smaller than some size $in{'condsmall'} =~ /^\d+$/ || &errror($text{'save_esmall'}); $filter->{'cond'} = $in{'condsmall'}*$in{'condsmall_units'}; $filter->{'condtype'} = '<'; } elsif ($in{'cmode'} == 2) { # Larger than some size $in{'condlarge'} =~ /^\d+$/ || &errror($text{'save_elarge'}); $filter->{'cond'} = $in{'condlarge'}*$in{'condlarge_units'}; $filter->{'condtype'} = '>'; } elsif ($in{'cmode'} == 1) { # Matches regexp $in{'cond'} || &errror($text{'save_econd'}); $filter->{'cond'} = $in{'cond'}; $filter->{'body'} = $in{'body'}; } # Parse action section delete($filter->{'actionreply'}); delete($filter->{'actionspam'}); delete($filter->{'actionthrow'}); delete($filter->{'actiondefault'}); delete($filter->{'actionreply'}); delete($filter->{'actiontype'}); delete($filter->{'continue'}); if ($in{'amode'} == 3) { # Deliver normally $filter->{'actiondefault'} = 1; } elsif ($in{'amode'} == 5) { # Run spamassassin $filter->{'actionspam'} = 1; } elsif ($in{'amode'} == 4) { # Throw away $filter->{'actionthrow'} = 1; } elsif ($in{'amode'} == 1) { # Forward to an address $in{'forward'} =~ /^\S+$/ || &error($text{'save_eforward'}); $filter->{'action'} = $in{'forward'}; $filter->{'actiontype'} = '!'; } elsif ($in{'amode'} == 0) { # Write to a folder or file @folders = &mailbox::list_folders(); if ($in{'folder'}) { $folder = &mailbox::find_named_folder($in{'folder'}, \@folders); $file = $folder->{'file'}; } else { $in{'file'} =~ /\S/ || &error($text{'save_efile'}); $file = $in{'file'}; } $file =~ s/^\Q$remote_user_info[7]\/\E/\$HOME\//; $filter->{'action'} = $file; if ($folder->{'type'} == 1) { # Maildir has to end with / $filter->{'action'} .= '/'; } } elsif ($in{'amode'} == 6) { # Send autoreply $filter->{'actionreply'} = 1; $in{'reply'} =~ /\S/ || &error($text{'save_ereply'}); $in{'reply'} =~ s/\r//g; $filter->{'reply'}->{'autotext'} = $in{'reply'}; ($froms, $doms) = &mailbox::list_from_addresses(); $filter->{'reply'}->{'from'} = $froms->[0]; $filter->{'reply'}->{'autoreply'} ||= "$remote_user_info[7]/autoreply.$filter->{'index'}.txt"; if ($in{'period_def'}) { # No autoreply period delete($filter->{'reply'}->{'replies'}); delete($filter->{'reply'}->{'period'}); } else { # Set reply period and tracking file $in{'period'} =~ /^\d+$/ || &error($text{'save_eperiod'}); $filter->{'reply'}->{'period'} = $in{'period'}*60; $filter->{'reply'}->{'replies'} ||= "$user_module_config_directory/replies"; } } elsif ($in{'amode'} == 7) { # Create a new folder for saving (always in Maildir format) $in{'newfolder'} =~ /\S/ || &error($text{'save_enewfolder'}); $in{'newfolder'} !~ /^\// && $in{'newfolder'} !~ /\.\./ || &error($text{'save_enewfolder2'}); ($clash) = grep { $_->{'name'} eq $in{'newfolder'} } @folders; $clash && &error($text{'save_enewfolder3'}); $folder = { 'name' => $in{'newfolder'}, 'mode' => 0, 'type' => 1 }; &mailbox::save_folder($folder); $filter->{'action'} = $folder->{'file'}."/"; $filter->{'action'} =~ s/^\Q$remote_user_info[7]\/\E/\$HOME\//; } $filter->{'continue'} = $in{'continue'}; # Save or create if ($in{'new'}) { &create_filter($filter); } else { &modify_filter($filter); } } &unlock_file($procmail::procmailrc); &redirect(""); filter/delete.cgi0100775000567100000120000000066510546576755014012 0ustar jcameronwheel#!/usr/local/bin/perl # Delete several selected filters require './filter-lib.pl'; &ReadParse(); # Validate selection &error_setup($text{'delete_err'}); @d = split(/\0/, $in{'d'}); @d || &error($text{'delete_enone'}); # Do it &lock_file($procmail::procmailrc); @filters = &list_filters(); foreach $d (sort { $b <=> $a } @d) { $filter = $filters[$d]; &delete_filter($filter); } &unlock_file($procmail::procmailrc); &redirect(""); filter/up.cgi0100775000567100000120000000041110546577567013163 0ustar jcameronwheel#!/usr/local/bin/perl # Move some filter up require './filter-lib.pl'; &ReadParse(); &lock_file($procmail::procmailrc); @filters = &list_filters(); &swap_filters($filters[$in{'idx'}], $filters[$in{'idx'}-1]); &unlock_file($procmail::procmailrc); &redirect(""); filter/config.info0100664000567100000120000000022710547007130014146 0ustar jcameronwheelvirtualmin_spam=Full path to Virtualmin spam user lookup program,3,Not installed warn_procmail=Show warning if Procmail is not installed?,1,1-Yes,0-No filter/config0100664000567100000120000000011410547007137013216 0ustar jcameronwheelvirtualmin_spam=/etc/webmin/virtual-server/lookup-domain.pl warn_procmail=1