--- original/amavisd	2006-05-09 23:34:43.000000000 +0200
+++ modified/amavisd	2006-05-09 23:35:17.000000000 +0200
@@ -106,6 +106,7 @@
 #  Amavis::Out::SQL::Quarantine
 #  Amavis::AV
 #  Amavis::SpamControl
+#  Amavis::SpamControl::DSPAM
 #  Amavis::SpamControl::SpamAssassin
 #  Amavis::Unpackers
 #------------------------------------------------------------------------------
@@ -232,7 +233,7 @@
       %hdrfrom_notify_sender_by_ccat
       %admin_maps_by_ccat %dsn_bcc_by_ccat
       %warnrecip_maps_by_ccat %addr_extension_maps_by_ccat
-      @load_spamscanners
+      @load_spamscanners $spamscanner_tables
     )],
     'confvars' => [qw(
       $myproduct_name $myversion_id $myversion_id_numeric $myversion_date
@@ -6353,8 +6354,8 @@
   $extra_code_in_amcl $extra_code_in_smtp $extra_code_in_courier
   $extra_code_out_smtp $extra_code_out_pipe
   $extra_code_out_bsmtp $extra_code_out_local $extra_code_p0f
-  $extra_code_antivirus $extra_code_antispam $extra_code_antispam_sa
-  $extra_code_unpackers);
+  $extra_code_antivirus $extra_code_antispam $extra_code_antispam_dspam
+  $extra_code_antispam_sa $extra_code_unpackers);
 
 use vars qw(%modules_basic);
 use vars qw($user_id_sql $wb_listed_sql $implicit_maps_inserted);
@@ -6758,6 +6759,7 @@
   do_log(0,"OS_Fingerprint code %s loaded", $extra_code_p0f        ?'':" NOT");
   do_log(0,"ANTI-VIRUS code     %s loaded", $extra_code_antivirus  ?'':" NOT");
   do_log(0,"ANTI-SPAM code      %s loaded", $extra_code_antispam   ?'':" NOT");
+  do_log(0,"ANTI-SPAM-DSPAM code%s loaded", $extra_code_antispam_dspam ?'':" NOT");
   do_log(0,"ANTI-SPAM-SA code   %s loaded", $extra_code_antispam_sa?'':" NOT");
   do_log(0,"Unpackers code      %s loaded", $extra_code_unpackers  ?'':" NOT");
 
@@ -9052,8 +9054,8 @@
     $extra_code_out_smtp, $extra_code_out_pipe,
     $extra_code_out_bsmtp, $extra_code_out_local, $extra_code_p0f,
     $extra_code_sql_base, $extra_code_sql_log, $extra_code_sql_quar,
-    $extra_code_antivirus, $extra_code_antispam, $extra_code_antispam_sa,
-    $extra_code_unpackers,
+    $extra_code_antivirus, $extra_code_antispam, $extra_code_antispam_dspam,
+    $extra_code_antispam_sa, $extra_code_unpackers,
     $Amavis::Conf::log_templ, $Amavis::Conf::log_recip_templ);
   if ($unicode_aware) {
 #   binmode(\*Amavis::DATA, ":encoding(utf8)")    #  :encoding(iso-8859-1)
@@ -9301,12 +9303,13 @@
 if (@$bpscm && !ref($bpscm->[0]) && $bpscm->[0]) {
   # do a simple-minded test to make it easy to turn off spam checks
   $extra_code_antispam = undef;
+  $extra_code_antispam_dspam = undef;
   $extra_code_antispam_sa = undef;
 } else {
   eval $extra_code_antispam or die "Problem in the antispam code: $@";
   freeMemory(\$extra_code_antispam);
 
-  my(@scanners) = (["SpamAssassin", \$extra_code_antispam_sa]);
+  my(@scanners) = (["SpamAssassin", \$extra_code_antispam_sa], ["DSPAM", \$extra_code_antispam_dspam]);
   foreach my $ref (@scanners) {
     my($scannername) = ${$ref}[0];
     my($coderef) = ${$ref}[1];
@@ -14502,14 +14505,45 @@
   }
 }
 
+# returns the second parameter if the first is undefined. 
+# Logs an error if the first parameter is defined and not equal to the second.
+# private method: do not use outside of Amavis::SpamControl
+sub setScannerIfNotSet($$) {
+  my($name, $spamscanner) = @_;
+  if (not defined $spamscanner) {
+    return $name;
+  } elsif ($name ne $spamscanner) {
+    do_log(0, "ERROR in SpamControl: More than one spam scanner should be used for a mail!");
+  }
+  return $spamscanner;
+}
+
+# returns the name of the spam scanner to use for this message
+# private method: do not use outside of Amavis::SpamControl
+sub get_spamscanner_name($) {
+  my(@recipients) = @{shift()};
+  my($spamscanner) = undef;
+  foreach my $address (@recipients) {
+    my($name) = lookup(0, $address, cr('spamscanner_tables'));
+    next if not defined $name;
+    $spamscanner = setScannerIfNotSet($name, $spamscanner);
+  }
+  if (not defined $spamscanner) {  # fall back to default scanner!
+    $spamscanner = "SpamAssassin"; # TODO: make default scanner configurable
+  }
+  return $spamscanner;
+}
+ 
+
 # returns an array of values: ($spam_level)
 # throws exception (die) in case of errors,
 # or just returns undef if it did not complete its jobs
 sub spam_scan($$) {
   my($conn,$msginfo) = @_;
-  my $name = "SpamAssassin";
-  if (! defined $spamscanners{$name}) {
-    do_log(5, "SpamControl: spam scanner '$name' not available");
+  my($name) = get_spamscanner_name(\@{$msginfo->recips()});
+  if (not defined $spamscanners{$name}) {
+    do_log(0, "ERROR SpamControl: spam scanner '$name' not available. Skipping spam scanning.");
+    return undef;
   } else {
     do_log(5, "SpamControl: calling spam scanner $name");
     my($scanner_obj) = $spamscanners{$name};
@@ -14677,6 +14711,79 @@
 
 __DATA__
 #
+package Amavis::SpamControl::DSPAM;
+use strict;
+use re 'taint';
+no warnings 'uninitialized';
+
+BEGIN {
+  use Exporter ();
+  use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
+  $VERSION = '1.000';
+  @ISA = qw(Exporter);
+}
+
+use subs @EXPORT_OK;
+use English qw(-no_match_vars);
+
+BEGIN {
+  import Amavis::Conf qw(:platform c cr ca);
+  import Amavis::Lookup qw(lookup);
+  import Amavis::Out::EditHeader;
+  import Amavis::Util qw(do_log run_command);
+  use File::Temp();
+}
+
+sub checkConfiguration() {
+  my($dspam) = $Amavis::Conf::dspam;
+  if (not defined $dspam) {
+    die "path to DSPAM not configured";
+  }
+  elsif (not -f $dspam) { 
+    die "No such file '".$dspam."'";
+  }
+  elsif (not -r $dspam or not -x $dspam) {
+    die "'".$dspam."' not readable/executable.";
+  }
+  do_log(5, "DSPAM: using '".$dspam."'");
+}
+
+sub new() {
+  my($class) = shift; 
+  my($self) = bless({}, $class);
+  $self->checkConfiguration();
+  $self->{'dspam'} = $Amavis::Conf::dspam;
+  $self->{'initialized_stage'} = 1;
+  $self;
+}
+
+sub init_pre_chroot {
+  my($self) = shift;
+  $self->{'initialized_stage'} == 1
+    or die "Wrong initialization sequence: " . $self->{'initialized_stage'};
+  $self->{'initialized_stage'} = 2;
+}
+
+sub init_pre_fork {
+  my($self) = shift;
+  do_log(5, "DSPAM init_pre_fork called!");
+  $self->{'initialized_stage'} == 2
+    or die "Wrong initialization sequence: " . $self->{'initialized_stage'};
+  $self->{'initialized_stage'} = 3;
+}
+
+sub check {
+  my($self,$msginfo) = @_;
+  do_log(5, "DSPAM check called!");
+  $msginfo->spam_level(0);
+  $msginfo->spam_status("DSPAM");
+  return 0;
+}
+
+1;
+
+__DATA__
+#
 package Amavis::SpamControl::SpamAssassin;
 use strict;
 use re 'taint';
