Hi, I'm working on using SpamAssassin within a perl mail processing script. In order to reduce overheads, I'm not loading the mail being processed into a variable and load new instances of Mail::SpamAssassin every time, but instead am running spamd and getting the script to check the mails against it.
But I ran into a problem. I'd rather not rely on spamc and IPC::Open2 to talk to it from within the script, instead I'd like to write spamc in Perl. How can I do this? I can't see a way to close the client sending side, to get spamd to process the mail, while still keeping the client open to receive the response. If anyone's got a solution to that I'd be interested to hear it, but in the mean time I solved the problem by changing spamd to allow the message to be terminated with a '.', like SMTP and other protocols -- is there any reason spamd doesn't do this already? Instead of = (<STDIN>) and the foreach loop, I wrote: my @msglines; my $actual_length; while (<STDIN>) { last if /^\.[\r\n]*$/; $actual_length += length; push (@msglines, $_); } Could this be implemeted in the main source? It works with both the old style and ending with a '.'. Also, why are the hit values int'd? I'd much prefer them as decimals. And also, I'd like to be able to get the list of symbols back as well, along with the score, with a command like SYMBOLS SPAMC/1.x . Could either of those be implemted too? I've attached a patch to do all of this, but with the decimals only for < SPAMC/1.3. - Alan -- Alan Ford * [EMAIL PROTECTED]
--- spamd.raw Fri Mar 29 14:39:55 2002 +++ spamd Fri Mar 29 14:44:44 2002 @@ -226,9 +226,10 @@ # It might be a CHECK message, meaning that we should just check # if it's spam or not, then return the appropriate response. - elsif (/CHECK SPAMC\/(.*)/) + elsif (/(CHECK) SPAMC\/(.*)/ || /(SYMBOLS) SPAMC\/(.*)/) { - my $version = $1; + my $method = $1; + my $version = $2; my $expected_length; # Protocol version 1.0 and greater may have "User:" and @@ -291,10 +292,12 @@ my $resp = "EX_OK"; # Now read in message - my @msglines = (<STDIN>); + my @msglines; my $actual_length; - for (@msglines) { + while (<STDIN>) { + last if /^\.[\r\n]*$/; $actual_length += length; + push (@msglines, $_); } my $mail = Mail::SpamAssassin::NoMailAudit->new ( data => \@msglines, @@ -309,19 +312,25 @@ # Now use copy-on-writed (hopefully) SA object my $status = $spamtest->check($mail); - my $msg_score = int($status->get_hits); - my $msg_threshold = int($status->get_required_hits); + my $msg_score = $status->get_hits; + my $msg_threshold = $status->get_required_hits; my $was_it_spam; + if ($version < 1.3) { + $msg_score = int $msg_score; + $msg_threshold = int $msg_threshold; + } if ($status->is_spam) { - print "SPAMD/1.1 $resphash{$resp} $resp\r\nSpam: True ; $msg_score / $msg_threshold\r\n\r\n"; + print "SPAMD/1.1 $resphash{$resp} $resp\r\nSpam: True ; $msg_score / +$msg_threshold\r\n"; $was_it_spam = 'identified spam'; } else { - print "SPAMD/1.1 $resphash{$resp} $resp\r\nSpam: False ; $msg_score / $msg_threshold\r\n\r\n"; + print "SPAMD/1.1 $resphash{$resp} $resp\r\nSpam: False ; $msg_score / +$msg_threshold\r\n"; $was_it_spam = 'clean message'; } + print $status->get_names_of_tests_hit, "\r\n" if ($method eq "SYMBOLS"); + print "\r\n"; $current_user ||= '(unknown)'; logmsg "$was_it_spam ($msg_score/$msg_threshold) for $current_user:$> in ". sprintf("%3d", time - $start) ." seconds.\n"; @@ -398,10 +407,12 @@ my $resp = "EX_OK"; # Now read in message - my @msglines = (<STDIN>); + my @msglines; my $actual_length; - for (@msglines) { + while (<STDIN>) { + last if /^\.[\r\n]*$/; $actual_length += length; + push (@msglines, $_); } my $mail = Mail::SpamAssassin::NoMailAudit->new ( data => \@msglines, @@ -434,8 +445,12 @@ } my $was_it_spam; if($status->is_spam) { $was_it_spam = 'identified spam'; } else { $was_it_spam = 'clean message'; } - my $msg_score = int($status->get_hits); - my $msg_threshold = int($status->get_required_hits); + my $msg_score = $status->get_hits; + my $msg_threshold = $status->get_required_hits; + if ($version < 1.3) { + $msg_score = int $msg_score; + $msg_threshold = int $msg_threshold; + } $current_user ||= '(unknown)'; logmsg "$was_it_spam ($msg_score/$msg_threshold) for $current_user:$> in ". sprintf("%3d", time - $start) ." seconds.\n";