You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by fe...@apache.org on 2004/11/13 03:01:37 UTC

svn commit: rev 57552 - in spamassassin/trunk: . lib/Mail/SpamAssassin lib/Mail/SpamAssassin/Plugin

Author: felicity
Date: Fri Nov 12 18:01:35 2004
New Revision: 57552

Modified:
   spamassassin/trunk/lib/Mail/SpamAssassin/Plugin.pm
   spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm
   spamassassin/trunk/lib/Mail/SpamAssassin/Reporter.pm
   spamassassin/trunk/spamassassin.raw
Log:
bug 3778: plugins will be called during report and revoke operations.  bug 3643: finish converting Razor2 to a plugin.  also added in plugin call to cache/log/etc the razor result, moving towards _RBL_ esque implementation via extra plugin.  changed report and revoke to return 1 for success and 0 for failure -- like every other function.  fixed spamcop-report debug output.

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin.pm	(original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin.pm	Fri Nov 12 18:01:35 2004
@@ -468,6 +468,46 @@
 
 =back
 
+=item $plugin->plugin_report ( { options ... } )
+
+Called if the message is to be reported as spam.
+
+=over 4
+
+=item report
+
+Reference to the Reporter object
+
+=item text
+
+Reference to a markup removed copy of the message in scalar format
+
+=item msg
+
+Reference to the original message object
+
+=back
+
+=item $plugin->plugin_revoke ( { options ... } )
+
+Called if the message is to be reported as ham (revokes a spam report).
+
+=over 4
+
+=item revoke
+
+Reference to the Reporter object
+
+=item text
+
+Reference to a markup removed copy of the message in scalar format
+
+=item msg
+
+Reference to the original message object
+
+=back
+
 =item $plugin->finish ()
 
 Called when the C<Mail::SpamAssassin> object is destroyed.

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm	(original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm	Fri Nov 12 18:01:35 2004
@@ -51,8 +51,8 @@
   }
   else {
     if (eval { require Razor2::Client::Agent; }) {
-      dbg("razor2: razor2 is available");
       $self->{razor2_available} = 1;
+      dbg("razor2: razor2 is available, version " . $Razor2::Client::Version::VERSION . "\n");
     }
     else {
       dbg("razor2: razor2 is not available");
@@ -112,25 +112,28 @@
   $conf->{parser}->register_commands(\@cmds);
 }
 
-sub razor2_lookup {
-  my ($self, $permsgstatus, $fulltext) = @_;
-  my $timeout=$self->{main}->{conf}->{razor_timeout};
+# This is to reset the alarm before die() - spamd can die of a stray alarm!
+sub adie {
+  my $msg = shift;
+  alarm 0;
+  die $msg;
+}
 
-  # Set the score for the ranged checks
-  $self->{razor2_cf_score} = 0;
-  return $self->{razor2_result} if ( defined $self->{razor2_result} );
-  $self->{razor2_result} = 0;
+sub razor2_access {
+  my ($self, $fulltext, $type) = @_;
+  my $timeout=$self->{main}->{conf}->{razor_timeout};
+  my $return = 0;
+  my @results = ();
 
-  return unless $self->{main}->{conf}->{use_razor2};
-  return unless $self->{razor2_available};
-  
   # razor also debugs to stdout. argh. fix it to stderr...
   if ($Mail::SpamAssassin::DEBUG) {
     open (OLDOUT, ">&STDOUT");
     open (STDOUT, ">&STDERR");
   }
 
-  $permsgstatus->enter_helper_run_mode();
+  my $debug = $type eq 'check' ? 'razor2' : 'reporter';
+
+  Mail::SpamAssassin::PerMsgStatus::enter_helper_run_mode($self);
 
     eval {
       local ($^W) = 0;    # argh, warnings in Razor
@@ -139,24 +142,29 @@
       alarm $timeout;
 
       # everything's in the module!
-      my $rc = Razor2::Client::Agent->new('razor-check');
+      my $rc = Razor2::Client::Agent->new("razor-$type");
 
       if ($rc) {
-        my %opt = (
+        $rc->{opt} = {
 		   debug      => ($Mail::SpamAssassin::DEBUG &&
-				  $Mail::SpamAssassin::facilities{razor2}), 
+				  ($Mail::SpamAssassin::facilities{all} ||
+				   $Mail::SpamAssassin::facilities{razor2})),
 		   foreground => 1,
 		   config     => $self->{main}->{conf}->{razor_config}
-        );
-        $rc->{opt} = \%opt;
-        $rc->do_conf() or die "razor2: " . $rc->errstr;
+        };
+        $rc->do_conf() or adie "$debug: " . $rc->errstr;
 
-	my $tmptext = $$fulltext;
-	my @msg = (\$tmptext);
+        # Razor2 requires authentication for reporting
+        my $ident;
+	if ($type ne 'check') {
+	  $ident = $rc->get_ident
+            or adie("reporter: razor2: $type requires authentication");
+        }
 
+        my @msg = ($fulltext);
         my $objects = $rc->prepare_objects( \@msg )
-          or die "razor2: error in prepare_objects";
-        $rc->get_server_info() or die $rc->errprefix("razor2: spamassassin");
+          or adie "$debug: error in prepare_objects";
+        $rc->get_server_info() or adie $rc->errprefix("$debug: spamassassin");
 
 	# let's reset the alarm since get_server_info() calls
 	# nextserver() which calls discover() which very likely will
@@ -164,23 +172,34 @@
 	alarm $timeout;
 
         my $sigs = $rc->compute_sigs($objects)
-          or die "razor2: error in compute_sigs";
+          or adie "$debug: error in compute_sigs";
 
         # 
         # if mail isn't whitelisted, check it out
+	# see 'man razor-whitelist'
         #   
-        if ( ! $rc->local_check( $objects->[0] ) ) {
-          if (!$rc->connect()) {
-            # provide a better error message when servers are unavailable,
-            # than "Bad file descriptor Died".
-            die "razor2: could not connect to any servers\n";
+        if ( $type ne 'check' || ! $rc->local_check($objects->[0]) ) {
+          # provide a better error message when servers are unavailable,
+          # than "Bad file descriptor Died".
+          $rc->connect() or adie "$debug: could not connect to any servers\n";
+
+	  # Talk to the Razor server and do work
+          if ($type eq 'check') {
+            $rc->check($objects) or adie $rc->errprefix("$debug: spamassassin");
+	  }
+	  else {
+            $rc->authenticate($ident) or adie($rc->errprefix("$debug: spamassassin"));
+            $rc->report($objects) or adie($rc->errprefix("$debug: spamassassin"));
           }
-          $rc->check($objects) or die $rc->errprefix("razor2: spamassassin");
-          $rc->disconnect() or die $rc->errprefix("razor2: spamassassin");
+
+          $rc->disconnect() or adie $rc->errprefix("$debug: spamassassin");
 
 	  # if we got here, we're done doing remote stuff, abort the alert
 	  alarm 0;
 
+          # Razor 2.14 says that if we get here, we did ok.
+          $return = 1;
+
           # figure out if we have a log file we need to close...
           if (ref($rc->{logref}) && exists $rc->{logref}->{fd}) {
             # the fd can be stdout or stderr, so we need to find out if it is
@@ -197,55 +216,53 @@
             close $rc->{logref}->{fd} if ($untie);
           }
 
-	  dbg("razor2: using results from Razor version " .
-	      $Razor2::Client::Version::VERSION . "\n");
-
-	  # so $objects->[0] is the first (only) message, and ->{spam} is a general yes/no
-          $self->{razor2_result} = $objects->[0]->{spam} || 0;
-
-	  # great for debugging, but leave this off!
-	  #use Data::Dumper;
-	  #print Dumper($objects),"\n";
-
-	  # ->{p} is for each part of the message
-	  # so go through each part, taking the highest cf we find
-	  # of any part that isn't contested (ct).  This helps avoid false
-	  # positives.  equals logic_method 4.
-	  #
-	  # razor-agents < 2.14 have a different object format, so we now support both.
-	  # $objects->[0]->{resp} vs $objects->[0]->{p}->[part #]->{resp}
-	  my $part = 0;
-	  my $arrayref = $objects->[0]->{p} || $objects;
-	  if ( defined $arrayref ) {
-	    foreach my $cf ( @{$arrayref} ) {
-	      if ( exists $cf->{resp} ) {
-	        for (my $response=0;$response<@{$cf->{resp}};$response++) {
-	          my $tmp = $cf->{resp}->[$response];
-	      	  my $tmpcf = $tmp->{cf} || 0; # Part confidence
-	      	  my $tmpct = $tmp->{ct} || 0; # Part contested?
-		  my $engine = $cf->{sent}->[$response]->{e};
-	          dbg("razor2: found razor2 part: part=$part engine=$engine ct=$tmpct cf=$tmpcf");
-	          $self->{razor2_cf_score} = $tmpcf if ( !$tmpct && $tmpcf > $self->{razor2_cf_score} );
+          if ($type eq 'check') {
+	    # so $objects->[0] is the first (only) message, and ->{spam} is a general yes/no
+	    push(@results, { result => $objects->[0]->{spam} });
+
+	    # great for debugging, but leave this off!
+	    #use Data::Dumper;
+	    #print Dumper($objects),"\n";
+
+	    # ->{p} is for each part of the message
+	    # so go through each part, taking the highest cf we find
+	    # of any part that isn't contested (ct).  This helps avoid false
+	    # positives.  equals logic_method 4.
+	    #
+	    # razor-agents < 2.14 have a different object format, so we now support both.
+	    # $objects->[0]->{resp} vs $objects->[0]->{p}->[part #]->{resp}
+	    my $part = 0;
+	    my $arrayref = $objects->[0]->{p} || $objects;
+	    if ( defined $arrayref ) {
+	      foreach my $cf ( @{$arrayref} ) {
+	        if ( exists $cf->{resp} ) {
+	          for (my $response=0;$response<@{$cf->{resp}};$response++) {
+	            my $tmp = $cf->{resp}->[$response];
+	      	    my $tmpcf = $tmp->{cf} || 0; # Part confidence
+	      	    my $tmpct = $tmp->{ct} || 0; # Part contested?
+		    my $engine = $cf->{sent}->[$response]->{e};
+
+		    push(@results,
+		      { part => $part, engine => $engine, contested => $tmpct, confidence => $tmpcf });
+	          }
 	        }
+	        else {
+		  push(@results, { part => $part, noreponse => 1 });
+	        }
+	        $part++;
 	      }
-	      else {
-		my $text = "part=$part noresponse";
-		$text .= " skipme=1" if ( $cf->{skipme} );
-	        dbg("razor2: found razor2 part: $text");
-	      }
-	      $part++;
 	    }
-	  }
-	  else {
-	    # If we have some new $objects format that isn't close to
-	    # the current razor-agents 2.x version, we won't FP but we
-	    # should alert in debug.
-	    dbg("razor2: it looks like the internal Razor object has changed format!");
-	  }
-        }
+	    else {
+	      # If we have some new $objects format that isn't close to
+	      # the current razor-agents 2.x version, we won't FP but we
+	      # should alert in debug.
+	      dbg("$debug: it looks like the internal Razor object has changed format!");
+	    }
+          }
+	}
       }
       else {
-        warn "razor2: undefined Razor2::Client::Agent\n";
+        warn "$debug: undefined Razor2::Client::Agent\n";
       }
   
       alarm 0;
@@ -255,21 +272,23 @@
   
     if ($@) {
       if ( $@ =~ /alarm/ ) {
-          dbg("razor2: check timed out after $timeout seconds");
-        } elsif ($@ =~ /(?:could not connect|network is unreachable)/) {
-          # make this a dbg(); SpamAssassin will still continue,
-          # but without Razor checking.  otherwise there may be
-          # DSNs and errors in syslog etc., yuck
-          dbg("razor2: check could not connect to any servers");
-        } else {
-          warn("razor2: check skipped: $! $@");
-        }
+          dbg("$debug: razor2 $type timed out after $timeout seconds");
+      } elsif ($@ =~ /(?:could not connect|network is unreachable)/) {
+        # make this a dbg(); SpamAssassin will still continue,
+        # but without Razor checking.  otherwise there may be
+        # DSNs and errors in syslog etc., yuck
+        dbg("$debug: razor2 $type could not connect to any servers");
+      } elsif ($@ =~ /timeout/i) {
+        dbg("$debug: razor2 $type timed out connecting to razor servers");
+      } else {
+        warn("$debug: razor2 $type failed: $! $@");
       }
+    }
 
   # work around serious brain damage in Razor2 (constant seed)
   srand;
 
-  $permsgstatus->leave_helper_run_mode();
+  Mail::SpamAssassin::PerMsgStatus::leave_helper_run_mode($self);
 
   # razor also debugs to stdout. argh. fix it to stderr...
   if ($Mail::SpamAssassin::DEBUG) {
@@ -277,24 +296,89 @@
     close OLDOUT;
   }
 
-  dbg("razor2: results: spam? " . $self->{razor2_result} .
-      "  highest cf score: " . $self->{razor2_cf_score} . "\n");
+  return wantarray ? ($return, @results) : $return;
+}
+
+sub plugin_report {
+  my($self, $options) = @_;
 
-  if ($self->{razor2_result} > 0) {
-      return 1;
+  return unless $self->{razor2_available};
+  return if $self->{main}->{local_tests_only};
+  return unless $self->{main}->{conf}->{use_razor2};
+  return if $options->{report}->{options}->{dont_report_to_razor};
+
+  if ($self->razor2_access($options->{text}, 'report')) {
+    $options->{report}->{report_available} = 1;
+    dbg ('reporter: spam reported to Razor.');
+    $options->{report}->{report_return} = 1;
+  }
+  else {
+    dbg ('reporter: could not report spam to Razor.');
   }
-  return 0;
 }
 
-sub check_razor2 {
-  my ($self, $permsgstatus) = @_;
+sub plugin_revoke {
+  my($self, $options) = @_;
 
+  return unless $self->{razor2_available};
+  return if $self->{main}->{local_tests_only};
   return unless $self->{main}->{conf}->{use_razor2};
+  return if $options->{revoke}->{options}->{dont_report_to_razor};
+
+  if ($self->razor2_access($options->{text}, 'revoke')) {
+    $options->{revoke}->{revoke_available} = 1;
+    dbg('reporter: spam revoked from Razor');
+    $options->{revoke}->{revoke_return} = 1;
+  }
+  else {
+    dbg('reporter: could not revoke spam from Razor');
+  }
+}
+
+sub check_razor2 {
+  my ($self, $permsgstatus, $full) = @_;
+
+  return $permsgstatus->{razor2_result} if (defined $permsgstatus->{razor2_result});
+  $permsgstatus->{razor2_result} = 0;
+  $permsgstatus->{razor2_cf_score} = 0;
+
   return unless $self->{razor2_available};
-  return $self->{razor2_result} if (defined $self->{razor2_result});
+  return unless $self->{main}->{conf}->{use_razor2};
+
+  my $return;
+  my @results = ();
 
-  my $full = $permsgstatus->{msg}->get_pristine();
-  return $self->razor2_lookup ($permsgstatus, \$full);
+  # TODO: check for cache header, set results appropriately
+
+  # do it this way to make it easier to get out the results later from the
+  # netcache plugin
+  ($return, @results) = $self->razor2_access($full, 'check');
+  $self->{main}->call_plugins ('process_razor_result', @results);
+
+  foreach my $result (@results) {
+    if (exists $result->{result}) {
+      $permsgstatus->{razor2_result} = $result->{result} if $result->{result};
+    }
+    elsif ($result->{noresponse}) {
+      dbg('razor2: part=' . $result->{part} . ' noresponse');
+    }
+    else {
+      dbg('razor2: part=' . $result->{part} .
+        ' engine=' .  $result->{engine} .
+	' contested=' . $result->{contested} .
+	' confidence=' . $result->{confidence});
+
+      next if $result->{contested};
+      if ($result->{confidence} > $permsgstatus->{razor2_cf_score}) {
+        $permsgstatus->{razor2_cf_score} = $result->{confidence};
+      }
+    }
+  }
+
+  dbg("razor2: results: spam? " . $permsgstatus->{razor2_result} .
+    "  highest cf score: " . $permsgstatus->{razor2_cf_score} . "\n");
+
+  return $permsgstatus->{razor2_result};
 }
 
 # Check the cf value of a given message and return if it's within the
@@ -304,20 +388,21 @@
 
   # If Razor2 isn't available, or the general test is disabled, don't
   # continue.
-  return 0 unless $self->{main}->{conf}->{use_razor2};
   return unless $self->{razor2_available};
-  return 0 unless $self->{main}->{conf}->{scores}->{'RAZOR2_CHECK'};
+  return unless $self->{main}->{conf}->{use_razor2};
+  return unless $self->{main}->{conf}->{scores}->{'RAZOR2_CHECK'};
 
   # If Razor2 hasn't been checked yet, go ahead and run it.
-  if (!defined $self->{razor2_result}) {
-    $self->check_razor2($permsgstatus);
+  unless (defined $permsgstatus->{razor2_result}) {
+    $self->check_razor2($permsgstatus, $body);
   }
 
-  if ($self->{razor2_cf_score} >= $min && $self->{razor2_cf_score} <= $max) {
-    $permsgstatus->test_log(sprintf ("cf: %3d", $self->{razor2_cf_score}));
+  if ($permsgstatus->{razor2_cf_score} >= $min && $permsgstatus->{razor2_cf_score} <= $max) {
+    $permsgstatus->test_log(sprintf ("cf: %3d", $permsgstatus->{razor2_cf_score}));
     return 1;
   }
-  return 0;
+
+  return;
 }
 
 sub dbg { Mail::SpamAssassin::dbg(@_); }

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Reporter.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Reporter.pm	(original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Reporter.pm	Fri Nov 12 18:01:35 2004
@@ -44,10 +44,9 @@
     'main'		=> $main,
     'msg'		=> $msg,
     'options'		=> $options,
+    'conf'		=> $main->{conf},
   };
 
-  $self->{conf} = $self->{main}->{conf};
-
   bless ($self, $class);
   $self;
 }
@@ -56,16 +55,16 @@
 
 sub report {
   my ($self) = @_;
-  my $return = 1;
-  my $available = 0;
+  $self->{report_return} = 1;
+  $self->{report_available} = 0;
 
   my $text = $self->{main}->remove_spamassassin_markup ($self->{msg});
 
   if (!$self->{options}->{dont_report_to_dcc} && $self->is_dcc_available()) {
     if ($self->dcc_report($text)) {
-      $available = 1;
+      $self->{report_available} = 1;
       dbg("reporter: spam reported to DCC");
-      $return = 0;
+      $self->{report_return} = 0;
     }
     else {
       dbg("reporter: could not report spam to DCC");
@@ -73,82 +72,53 @@
   }
   if (!$self->{options}->{dont_report_to_pyzor} && $self->is_pyzor_available()) {
     if ($self->pyzor_report($text)) {
-      $available = 1;
+      $self->{report_available} = 1;
       dbg("reporter: spam reported to Pyzor");
-      $return = 0;
+      $self->{report_return} = 0;
     }
     else {
       dbg("reporter: could not report spam to Pyzor");
     }
   }
-  if (!$self->{options}->{dont_report_to_razor} && $self->is_razor_available()) {
-    if ($self->razor_report($text)) {
-      $available = 1;
-      dbg("reporter: spam reported to Razor");
-      $return = 0;
-    }
-    else {
-      dbg("reporter: could not report spam to Razor");
-    }
-  }
   if (!$self->{options}->{dont_report_to_spamcop} && $self->is_spamcop_available()) {
     if ($self->spamcop_report($text)) {
-      $available = 1;
+      $self->{report_available} = 1;
       dbg("reporter: spam reported to SpamCop");
-      $return = 0;
+      $self->{report_return} = 0;
     }
     else {
-      dbg("reporter: could not report spam to reporter.");
+      dbg("reporter: could not report spam to SpamCop.");
     }
   }
 
+  $self->{main}->call_plugins ("plugin_report", { report => $self, text => \$text, msg => $self->{msg} });
+
   $self->delete_fulltext_tmpfile();
 
-  if ($available == 0) {
+  if ($self->{report_available} == 0) {
     warn "reporter: no network reporting methods available, so couldn't report\n";
   }
 
-  return $return;
+  return $self->{report_return};
 }
 
 ###########################################################################
 
 sub revoke {
   my ($self) = @_;
-  my $return = 1;
+  $self->{revoke_return} = 0;
+  $self->{revoke_available} = 0;
 
   my $text = $self->{main}->remove_spamassassin_markup($self->{msg});
 
-  if (!$self->{main}->{local_tests_only}
-      && !$self->{options}->{dont_report_to_razor}
-      && $self->is_razor_available()) # we only work with Razor2
-  {
-    if ($self->razor_revoke($text)) {
-      dbg("reporter: spam revoked from Razor");
-      $return = 0;
-    }
-    else {
-      dbg("reporter: could not revoke spam from Razor");
-    }
-  }
-
-  # This is where you would revoke from DCC and Pyzor but I was unable
-  # to find where they supported revoke
+  $self->{main}->call_plugins ("plugin_revoke", { revoke => $self, text => \$text, msg => $self->{msg} });
 
-  return $return;
+  return $self->{revoke_return};
 }
 
 ###########################################################################
 # non-public methods.
 
-# This is to reset the alarm before die() - spamd can die of a stray alarm!
-
-sub adie {
-  my $msg = shift;
-  alarm 0;
-  die $msg;
-}
-
 # Close an fh piped to a process, possibly exiting if the process returned nonzero.
 # thanks to nix /at/ esperi.demon.co.uk for this.
 sub close_pipe_fh {
@@ -168,113 +138,6 @@
   }
 }
 
-sub razor_report {
-  my ($self, $fulltext, $revoke) = @_;
-  my $timeout=$self->{conf}->{razor_timeout} || 10;
-  my $response;
-
-  # If we passed in a true value for $revoke then we must be revoking
-  my $type = (defined($revoke) && $revoke) ? 'revoke' : 'report';
-
-  # razor also debugs to stdout. argh. fix it to stderr...
-  if ($Mail::SpamAssassin::DEBUG) {
-    open (OLDOUT, ">&STDOUT");
-    open (STDOUT, ">&STDERR");
-  }
-
-  $self->enter_helper_run_mode();
-
-  # Use Razor2 if it's available
-  eval { require Razor2::Client::Agent; };
-  if ( !$@ ) {
-    eval {
-      local ($^W) = 0;    # argh, warnings in Razor
-
-      local $SIG{ALRM} = sub { die "alarm\n" };
-      alarm $timeout;
-
-      # everything's in the module!
-      my $rc = Razor2::Client::Agent->new("razor-$type");
-
-      if ($rc) {
-        my %opt = (
-          debug      => $Mail::SpamAssassin::DEBUG,
-          foreground => 1,
-          config     => $self->{conf}->{razor_config}
-        );
-        $rc->{opt} = \%opt;
-        $rc->do_conf() or adie("reporter: razor2: " . $rc->errstr);
-
-        # Razor2 requires authentication for reporting
-        my $ident = $rc->get_ident
-          or adie("reporter: razor2: $type requires authentication");
-
-	my @msg = (\$fulltext);
-        my $objects = $rc->prepare_objects( \@msg )
-          or adie("reporter: razor2: error in prepare_objects");
-        $rc->get_server_info() or adie $rc->errprefix("reporter: razor2");
-
-	# let's reset the alarm since get_server_info() calls
-	# nextserver() which calls discover() which very likely will
-	# reset the alarm for us ... how polite.  :(  
-	alarm $timeout;
-
-        my $sigs = $rc->compute_sigs($objects)
-          or adie("reporter: razor2: error in compute_sigs");
-
-        $rc->connect() or adie($rc->errprefix("reporter: razor2"));
-        $rc->authenticate($ident) or adie($rc->errprefix("reporter: razor2"));
-        $rc->report($objects) or adie($rc->errprefix("reporter: razor2"));
-        $rc->disconnect() or adie($rc->errprefix("reporter: razor2"));
-        $response = 1; # Razor 2.14 says that if we get here, we did ok.
-      }
-      else {
-        warn "reporter: undefined Razor2::Client::Agent\n";
-      }
-
-      alarm 0;
-      dbg("reporter: razor2 spam $type, response is \"$response\".");
-    };
-
-    alarm 0;
-
-    if ($@) {
-      if ( $@ =~ /alarm/ ) {
-        dbg("reporter: razor2 $type timed out after $timeout secs.");
-      } elsif ($@ =~ /could not connect/) {
-        dbg("reporter: razor2 $type could not connect to any servers");
-      } elsif ($@ =~ /timeout/i) {
-        dbg("reporter: razor2 $type timed out connecting to razor servers");
-      } else {
-        warn "reporter: razor2 $type failed: $! $@";
-      }
-      undef $response;
-    }
-  }
-
-  # work around serious brain damage in Razor2 (constant seed)
-  srand;
-
-  $self->leave_helper_run_mode();
-
-  if ($Mail::SpamAssassin::DEBUG) {
-    open (STDOUT, ">&OLDOUT");
-    close OLDOUT;
-  }
-
-  if (defined($response) && $response+0) {
-    return 1;
-  } else {
-    return 0;
-  }
-}
-
-sub razor_revoke {
-  my ($self, $fulltext) = @_;
-
-  return $self->razor_report($fulltext, 1);
-}
-
 sub dcc_report {
   my ($self, $fulltext) = @_;
   my $timeout=$self->{conf}->{dcc_timeout};
@@ -504,9 +367,6 @@
 }
 sub is_pyzor_available {
   Mail::SpamAssassin::PerMsgStatus::is_pyzor_available(@_);
-}
-sub is_razor_available {
-  Mail::SpamAssassin::PerMsgStatus::is_razor2_available(@_);
 }
 sub is_spamcop_available {
   my ($self) = @_;

Modified: spamassassin/trunk/spamassassin.raw
==============================================================================
--- spamassassin/trunk/spamassassin.raw	(original)
+++ spamassassin/trunk/spamassassin.raw	Fri Nov 12 18:01:35 2004
@@ -405,11 +405,11 @@
     $mail->finish();
 
     my $failed;
-    if ( $opt{'report'} && $spamtest->report_as_spam($new_mail) ) {
+    if ( $opt{'report'} && !$spamtest->report_as_spam($new_mail) ) {
       $failed = 'report';
     }
 
-    if ( $opt{'revoke'} && $spamtest->revoke_as_spam($new_mail) ) {
+    if ( $opt{'revoke'} && !$spamtest->revoke_as_spam($new_mail) ) {
       $failed = 'revoke';
     }