SF.net SVN: postfixadmin:[453] trunk/VIRTUAL_VACATION
Brought to you by:
christian_boltz,
gingerdog
From: <Gin...@us...> - 2008-08-31 20:17:18
|
Revision: 453 http://postfixadmin.svn.sourceforge.net/postfixadmin/?rev=453&view=rev Author: GingerDog Date: 2008-08-31 20:17:23 +0000 (Sun, 31 Aug 2008) Log Message: ----------- vacation.pl: plenty of refactoring; I think this addresses all hte points at https://sourceforge.net/forum/message.php?msg_id=5205584 Modified Paths: -------------- trunk/VIRTUAL_VACATION/tests/asterisk-email.txt trunk/VIRTUAL_VACATION/tests/test-email.txt trunk/VIRTUAL_VACATION/tests/test.sh trunk/VIRTUAL_VACATION/vacation.pl Modified: trunk/VIRTUAL_VACATION/tests/asterisk-email.txt =================================================================== --- trunk/VIRTUAL_VACATION/tests/asterisk-email.txt 2008-08-31 14:15:48 UTC (rev 452) +++ trunk/VIRTUAL_VACATION/tests/asterisk-email.txt 2008-08-31 20:17:23 UTC (rev 453) @@ -3,7 +3,7 @@ Delivered-To: da...@ex... Received: by mail.palepurple.co.uk (Postfix, from userid 33) id 1942F894CF9; Fri, 1 Aug 2008 11:23:45 +0100 (BST) -To: <da...@ex...> +To: "" <da...@ex...> Subject: New Phone call - annotate it! X-PHP-Script: admin.palepurple.co.uk/contacts/dispatch.php for 78.105.97.55 From: "ast...@ex..." <ast...@ex...> Modified: trunk/VIRTUAL_VACATION/tests/test-email.txt =================================================================== --- trunk/VIRTUAL_VACATION/tests/test-email.txt 2008-08-31 14:15:48 UTC (rev 452) +++ trunk/VIRTUAL_VACATION/tests/test-email.txt 2008-08-31 20:17:23 UTC (rev 453) @@ -22,7 +22,8 @@ id 8869450146; Tue, 5 Aug 2008 20:15:50 +0100 (BST) Date: Tue, 5 Aug 2008 20:15:50 +0100 From: David Goodwin <da...@ex...> -To: da...@ex... +To: "DG" <da...@ex...>, "Fred@Work" <fr...@ex...>, "Barney Rubble" + <ba...@ex...>, "Rover Dog" <ro...@ex...>, ro...@ex... Subject: test email Message-ID: <200...@co...> MIME-Version: 1.0 Modified: trunk/VIRTUAL_VACATION/tests/test.sh =================================================================== --- trunk/VIRTUAL_VACATION/tests/test.sh 2008-08-31 14:15:48 UTC (rev 452) +++ trunk/VIRTUAL_VACATION/tests/test.sh 2008-08-31 20:17:23 UTC (rev 453) @@ -18,25 +18,32 @@ # First time around, there should be no vacation record for da...@ex..., so these should all not cause mail to be sent. # some will trip up spam/mailing list protection etc though - +echo echo "NONE OF THESE SHOULD RESULT IN MAIL BEING SENT" +echo cat mailing-list.txt | perl ../vacation.pl -t yes -f fw-general-return-20540-david=exa...@li... -- da...@ex... cat test-email.txt | perl ../vacation.pl -t yes -f da...@ex... -- da...@ex... cat spam.txt | perl ../vacation.pl -t yes -f ma...@cc... -- da...@ex... cat asterisk-email.txt | perl ../vacation.pl -t yes -f www...@pa... -- da...@ex... cat facebook.txt | perl ../vacation.pl -t yes -f not...@fa... -- da...@ex... +cat mail-myself.txt | perl ../vacation.pl -t yes -f da...@ex... -- da...@ex... echo "INSERT INTO vacation (email, subject, body, created, active, domain) VALUES ('da...@ex...', 'I am on holiday', 'Yeah, that is right', NOW(), true, 'example.org')" | psql - +echo echo "VACATION TURNED ON " +echo echo "Still ignore mailing list" cat mailing-list.txt | perl ../vacation.pl -t yes -f fw-general-return-20540-david=exa...@li... -- da...@ex... -echo "* Should send vacation message for this" +echo " * Should send vacation message for this *" cat test-email.txt | perl ../vacation.pl -t yes -f da...@ex... -- da...@ex... -echo "* Spam - no vacation message for this" +echo " * Spam - no vacation message for this" cat spam.txt | perl ../vacation.pl -t yes -f ma...@xx... -- da...@ex... -echo "* OK - should send vacation message for this" +echo " * OK - should send vacation message for this" cat asterisk-email.txt | perl ../vacation.pl -t yes -f www...@pa... -- da...@ex... -echo "* Facebook - should not send vacation message for" +echo " * Facebook - should not send vacation message for" cat facebook.txt | perl ../vacation.pl -t yes -f not...@fa... -- da...@ex... +echo " * Mailing myself - should not send vacation message" +cat mail-myself.txt | perl ../vacation.pl -t yes -f da...@ex... -- da...@ex... +echo +echo Modified: trunk/VIRTUAL_VACATION/vacation.pl =================================================================== --- trunk/VIRTUAL_VACATION/vacation.pl 2008-08-31 14:15:48 UTC (rev 452) +++ trunk/VIRTUAL_VACATION/vacation.pl 2008-08-31 20:17:23 UTC (rev 453) @@ -99,8 +99,8 @@ my $db_host = ''; # connection details -my $db_username = 'your_username'; -my $db_password = 'your_password'; +my $db_username = 'dg'; +my $db_password = 'gingerdog'; my $db_name = 'postfix'; # smtp server used to send vacation e-mails @@ -139,17 +139,19 @@ use Getopt::Std; use Log::Log4perl qw(get_logger :levels); -my ($from, $to, $cc, ,$bcc , $subject, $messageid, $lastheader, $smtp_sender, $smtp_recipient, %opts, $sndrhdr, $spam, $test_mode, $logger); +my ($from, $to, $cc, $replyto , $subject, $messageid, $lastheader, $smtp_sender, $smtp_recipient, %opts, $spam, $test_mode, $logger); $subject=''; # Setup a logger... # -getopts('f:t:', \%opts) or die "Usage: $0 [-t yes] [-f sender] [-- [recipient]]\n -t for testing only\n"; +getopts('f:t:', \%opts) or die "Usage: $0 [-t yes] -f sender -- recipient\n -t for testing only\n"; $opts{f} and $smtp_sender = $opts{f}; $test_mode = 0; $opts{t} and $test_mode = 1; +$smtp_recipient = shift || $smtp_recipient || $ENV{"USER"} || ""; + my $log_layout = Log::Log4perl::Layout::PatternLayout->new("%d %p> %F:%L %M - %m%n"); if($test_mode == 1) { @@ -388,15 +390,24 @@ } } +# Remove textual stuff from a (list of) email address(es) +# e.g. convert: "aardvark" <a@b.com>, "Danger Mouse" <c@d.com>, e@f.com to +# a@b.com, c@d.com, e@f.com sub strip_address { my ($arg) = @_; if(!$arg) { return ''; } - if($arg =~ /([\w\-.%]+\@[\w.-]+)/) { - return lc($1); + my @ok; + $logger = get_logger(); + for (split(/,\s*/, lc($arg))) { + my $temp = Email::Valid->address($_); + if($temp) { + push(@ok, $temp); + } } - return ''; + my $result = join(", ", @ok); + return $result; } sub panic_prepare { @@ -412,34 +423,52 @@ $logger->error("Could not execute sql statement - '$arg' with parameters '$param'"); exit(0); } + +# Make sure the email wasn't sent by someone who could be a mailing list etc; if it was, +# then we abort after appropriate logging. +sub check_and_clean_from_address { + my ($address) = @_; + my $logger = get_logger(); + + if($address =~ /^(noreply|postmaster|mailer-daemon|listserv|majordomo|owner-|request-|bounces-)/i || + $address =~ /-(owner|request|bounces)\@/i ) { + $logger->debug("sender $address contains $1 - will not send vacation message"); + exit(0); + } + $address = strip_address($address); + if($address eq "") { + $logger->error("Address $address is not valid; exiting"); + exit(0); + } + #$logger->debug("Address cleaned up to $address"); + return $address; +} ########################### main ################################# # Take headers apart -# +$cc = ''; +$replyto = ''; + while (<STDIN>) { last if (/^$/); - if (/^\s+(.*)/ and $lastheader) { $$lastheader .= " $1"; } - elsif (/^Return-Path:\s+(.*)\n$/i) { $smtp_sender = $1; $lastheader = \$smtp_sender; } - elsif (/^Delivered-To:\s+(.*)\n$/i) { $smtp_recipient = $1; $lastheader = \$smtp_recipient; } - elsif (/^from:\s+(.*)\n$/i) { $from = $1; $lastheader = \$from; } - elsif (/^to:\s+(.*)\n$/i) { $to = $1; $lastheader = \$to; } - elsif (/^cc:\s+(.*)\n$/i) { $cc = $1; $lastheader = \$cc; } - elsif (/^bcc:\s+(.*)\n$/i) { $bcc = $1; $lastheader = \$bcc; } - elsif (/^subject:\s+(.*)\n$/i) { $subject = $1; $lastheader = \$subject; } - elsif (/^message-id:\s+(.*)\n$/i) { $messageid = $1; $lastheader = \$messageid; } + if (/^\s+(.*)/ and $lastheader) { $$lastheader .= " $1"; next; } + elsif (/^from:\s*(.*)\s*\n$/i) { $from = $1; $lastheader = \$from; } + elsif (/^to:\s*(.*)\s*\n$/i) { $to = $1; $lastheader = \$to; } + elsif (/^cc:\s*(.*)\s*\n$/i) { $cc = $1; $lastheader = \$cc; } + elsif (/^Reply-to:\s*(.*)\s*\n$/i) { $replyto = $1; $lastheader = \$replyto; } + elsif (/^subject:\s*(.*)\s*\n$/i) { $subject = $1; $lastheader = \$subject; } + elsif (/^message-id:\s*(.*)\s*\n$/i) { $messageid = $1; $lastheader = \$messageid; } elsif (/^x-spam-(flag|status):\s+yes/i) { $logger->debug("x-spam-$1: yes found; exiting"); exit (0); } elsif (/^x-facebook-notify:/i) { $logger->debug('Mail from facebook, ignoring'); exit(0); } elsif (/^precedence:\s+(bulk|list|junk)/i) { $logger->debug("precedence: $1 found; exiting"); exit (0); } elsif (/^x-loop:\s+postfix\ admin\ virtual\ vacation/i) { $logger->debug("x-loop: postfix admin virtual vacation found; exiting"); exit (0); } - elsif (/^Auto-Submitted:\s+no/i) { next; } + elsif (/^Auto-Submitted:\s*no\s*/i) { next; } elsif (/^Auto-Submitted:/i) { $logger->debug("Auto-Submitted: something found; exiting"); exit (0); } elsif (/^List-(Id|Post):/i) { $logger->debug("List-$1: found; exiting"); exit (0); } - elsif (/^Sender:\s+(.*)/i) { $sndrhdr = $1; $lastheader = \$sndrhdr; } else {$lastheader = "" ; } } -$smtp_recipient = shift || $smtp_recipient || $ENV{"USER"} || ""; # If either From: or To: are not set, exit if(!$from || !$to || !$messageid || !$smtp_sender || !$smtp_recipient) { @@ -447,15 +476,16 @@ exit(0); } -if($smtp_sender =~ /^(mailer-daemon|listserv|majordomo|owner-|request-|bounces-)/i || - $smtp_sender =~ /-(owner|request|bounces)\@/i ) { - $logger->debug("sender $smtp_sender contains $1 - will not send vacation message"); - exit(0); +$to = strip_address($to); +$from = lc ($from); +$from = check_and_clean_from_address($from); +if($replyto ne "") { + # if reply-to is invalid, or looks like a mailing list, then we probably don't want to send a reply. + $replyto = check_and_clean_from_address($replyto); } +$smtp_sender = check_and_clean_from_address($smtp_sender); +$smtp_recipient = check_and_clean_from_address($smtp_recipient); -$smtp_sender = strip_address($smtp_sender); -$smtp_recipient = strip_address($smtp_recipient); -$sndrhdr = strip_address($sndrhdr); if ($smtp_sender eq $smtp_recipient) { $logger->debug("smtp sender $smtp_sender and recipient $smtp_recipient are the same; aborting"); @@ -463,39 +493,28 @@ } my $recipfound = 0; -for (split(/,\s*/, lc($to)), split(/,\s*/, lc($cc)), split(/,\s*/, lc($bcc))) { +for (split(/,\s*/, lc($to)), split(/,\s*/, lc($cc))) { my $destinatario = strip_address($_); - if ($sndrhdr eq $destinatario) { - $logger->debug("sender header $sndrhdr contains recipient $destinatario (mailing myself?)"); + if ($smtp_sender eq $destinatario) { + $logger->debug("sender header $smtp_sender contains recipient $destinatario (mailing myself?)"); exit(0); } if ($smtp_recipient eq $destinatario) { $recipfound++; } } if (!$recipfound) { - $logger->debug("smtp envelope recipient $smtp_recipient not found in the header recipients (therefore they were bcc'ed, so won't send vacation message)"); + $logger->debug("smtp envelope recipient $smtp_recipient not found in the header recipients ($to & $cc) (therefore they were bcc'ed, so won't send vacation message)"); exit (0); } -$from = lc ($from); -if (!Email::Valid->address($from,-mxcheck => 1)) { $logger->debug("Invalid from email address: $from; exiting."); exit(0); } -if (!Email::Valid->address($smtp_sender,-mxcheck => 1)) { $logger->debug("Invalid sender email address: $smtp_sender; exiting."); exit(0); } -if ($from =~ /([\w\-.%]+\@[\w.-]+)/) { $from = $1; } -# Does the $from address look like a mailing list etc? -if ($from eq "" || - $from =~ /^(owner-|-(?:request|owner)\@|^(?:mailer-daemon|postmaster)\@)/i) { - $logger->debug("from $from contains $1"); exit (0); -} - my ($rv, $email) = find_real_address($smtp_recipient); -$logger->debug("find_email_address gave: rv:$rv, email:$email"); if ($rv == 1) { $logger->debug("Attempting to send vacation response for: $messageid to: $smtp_sender, $smtp_recipient, $email (test_mode = $test_mode)"); send_vacation_email($email, $smtp_sender, $smtp_recipient, $messageid, $test_mode); } else { - $logger->debug("SMTP recipient $smtp_recipient which resolves to $email does not have an active vacation"); + $logger->debug("SMTP recipient $smtp_recipient which resolves to $email does not have an active vacation (rv: $rv, email: $email)"); } 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |