Roger Walker wrote:
        The plugin in the current distribution has a note not to use 2.50,
but 2.40 or newer. The current version is 2.61. Does this work properly
with the supplied plugin?


There are (at least) three ways to run SpamAssassin from within qpsmtpd:


1) Call Mail::SpamAssassin directly; this is slow and eats RAM like mad, so it is not really recommended for production servers.

2) Call spamc which talks to spamd (a resident Mail::SpamAssassin process); this is much faster than #1 (since you don't need to spawn a large Perl process for each e-mail).

3) Talk to spamd directly from qpsmtpd. This has the disadvantage that if the internal spamd API changes, the plugin needs to change too. It has the advantage that it does not require spawning any other process (even one as small as spamc), so it should be faster than #2. It will certainly require the least amount of RAM of any solution.

Both #'s 2 and 3 can also take advantage of the Mail::SpamAssassin 2.60+ feature of using Unix Domain Sockets to communicate with spamd, which should also be a distinct performance gain (as well as being much better security-wise). spamd can also be potentially run using PPerl (Persistent Perl) which makes everything even faster.

Personally, I am using method #3 with a patched version of the base spamassassin plugin which enables the Domain Sockets support. I am working on a shim module, currently called Mail::SpamAssassin::SpamC, which will encapsulate the spamd API, so that future changes will not be required to the qpsmtpd plugin.

I've attached my current patch, which is based on earlier patches by Keith Ivey and Peter J Holzer. I am currently using M::SA 2.60 on my machines, but I don't know of any reason why 2.61 wouldn't work just as well.

HTH

John
# cvs diff -u plugins/spamassassin
Index: plugins/spamassassin
===================================================================
RCS  /cvs/public/qpsmtpd/plugins/spamassassin,v
retrieving revision 1.5
diff -u -r1.5 spamassassin
--- plugins/spamassassin        18 Mar 2003 09:53:37 -0000      1.5
+++ plugins/spamassassin        3 Jan 2004 16:20:08 -0000
@@ -49,6 +49,12 @@

 The default is to never munge the subject based on the SpamAssassin score.

+=item spamd_socket [/path/to/socket]
+
+Beginning with Mail::SpamAssassin 2.60, it is possible to use Unix
+domain sockets for spamd.  This is faster and more secure than using
+a TCP connection.
+
 =back

 With both options the configuration line will look like the following
@@ -92,8 +98,17 @@
   my $paddr   = sockaddr_in($port, $iaddr);

   my $proto   = getprotobyname('tcp');
+  if ( $self->{_args}->{spamd_socket} =~ /^([\w\/.]+)$/ ) { # connect to Unix Domain 
Socket
+    my $spamd_socket = $1;
+
+    socket(SPAMD, PF_UNIX, SOCK_STREAM, 0)
+      or $self->log(1, "Could not open socket: $!") and return (DECLINED);
+
+    $paddr = sockaddr_un($spamd_socket);
+  } else {
   socket(SPAMD, PF_INET, SOCK_STREAM, $proto)
     or $self->log(1, "Could not open socket: $!") and return (DECLINED);
+  }

   connect(SPAMD, $paddr)
     or $self->log(1, "Could not connect to spamassassin daemon: $!") and return 
DECLINED;
@@ -102,9 +117,11 @@

   $transaction->body_resetpos;

-  print SPAMD "REPORT_IFSPAM SPAMC/1.0" . CRLF;
+  print SPAMD "SYMBOLS SPAMC/1.0" . CRLF;
   # or CHECK or REPORT or SYMBOLS

+  print SPAMD "X-Envelope-From: ", $transaction->sender->format, CRLF;
+
   print SPAMD join CRLF, split /\n/, $transaction->header->as_string
     or warn "Could not print to spamd: $!";

@@ -124,16 +141,24 @@
     $transaction->header->add("X-Spam-Check-By", $self->qp->config('me'));
   }

+  my ($flag, $hits, $required);
   while (<SPAMD>) {
     #warn "GOT FROM SPAMD1: $_";
-    next unless m/\S/;
-    s/\r?\n$/\n/;
-    my @h = split /: /, $_, 2;
+    last unless m/\S/;
+    if (m{Spam: (\w+) ; (-?\d+\.\d) / (-?\d+\.\d)}) {
+      ($flag, $hits, $required) = ($1, $2, $3);
+    }
+  }

-    $transaction->header->add(@h);
-    last if $h[0] eq "Spam" and $h[1] =~ m/^False/;
+  my $tests = <SPAMD> || '';
+  $tests =~ s/\s+$//;
+  $self->log(5, "$flag, hits=$hits, required=$required, tests=$tests") if $tests;
+  $tests =~ s/(.{1,60}(?:,|$))/$1\n\t/g; # wrap
+  $tests =~ s/\s+$//;

-  }
+
+  $transaction->header->add('X-Spam-Status', "$flag, hits=$hits required=$required" .
+    ( $tests ? "\n\ttests=$tests" : '' ) );

   return (DECLINED);
 }
@@ -157,7 +182,9 @@
   return DECLINED unless $score >= $self->{_args}->{munge_subject_threshold};

   my $subject = $transaction->header->get('Subject') || '';
-  $transaction->header->replace('Subject', "***SPAM*** $subject");
+  $subject = sprintf('@SPAM(%05.2f) %s', $score, $subject);
+  $self->log(5, qq(munging subject to "$subject"));
+  $transaction->header->replace('Subject', $subject);

   return DECLINED;
 }

Reply via email to