Only in spamass-milter-0.2.0-orig/contrib: spamass-milter.spec
diff -ur spamass-milter-0.2.0-orig/spamass-milter.cpp spamass-milter-0.2.0/spamass-milter.cpp
--- spamass-milter-0.2.0-orig/spamass-milter.cpp	2003-06-26 11:10:44.000000000 -0400
+++ spamass-milter-0.2.0/spamass-milter.cpp	2004-09-20 10:42:24.000000000 -0400
@@ -150,13 +150,15 @@
   };
 
 const char *const debugstrings[] = {
-	"ALL", "FUNC", "POLL", "UORI", "STR", "MISC", "NET", "SPAMC",
+	"ALL", "FUNC", "POLL", "UORI", "STR", "MISC", "NET", "SPAMC", "RCPT",
 	NULL
 };
 
 int flag_debug = (1<<D_ALWAYS);
 bool flag_reject = false;
 int reject_score = -1;
+bool flag_rcpt_filter = false;
+char *rcpt_filter = NULL;
 bool dontmodify = false;
 bool flag_sniffuser = false;
 char *defaultuser;
@@ -174,7 +176,7 @@
 main(int argc, char* argv[])
 {
    int c, err = 0;
-   const char *args = "p:fd:mr:u:D:i:b:B:";
+   const char *args = "p:fd:mr:R:u:D:i:b:B:";
    char *sock = NULL;
    bool dofork = false;
 
@@ -207,6 +209,10 @@
 				flag_reject = true;
 				reject_score = atoi(optarg);
 				break;
+			case 'R':
+				flag_rcpt_filter = true;
+				rcpt_filter = optarg;
+				break;
 			case 'u':
 				flag_sniffuser = true;
 				defaultuser = strdup(optarg);
@@ -259,6 +265,7 @@
       cout << "   -m: don't modify body, Content-type: or Subject:" << endl;
       cout << "   -r nn: reject messages with a score >= nn with an SMTP error.\n"
               "          use -1 to reject any messages tagged by SA." << endl;
+      cout << "   -R cmd: filter out recipients with zero exit status."<< endl;
       cout << "   -u defaultuser: pass the recipient's username to spamc.\n"
               "          Uses 'defaultuser' if there are multiple recipients." << endl;
       cout << "   -- spamc args: pass the remaining flags to spamc." << endl;
@@ -576,6 +583,7 @@
 	}
 	sctx->assassin = NULL;
 	sctx->helo = NULL;
+	sctx->rcpts = 0;
 	
 	/* store a pointer to it with setpriv */
 	smfi_setpriv(ctx, sctx);
@@ -718,6 +726,54 @@
 	{
 		assassin->recipients.push_back( *rcpt ); // XXX verify that this worked
 	}
+
+	sctx->rcpts++;
+	if(flag_rcpt_filter && rcpt_filter)
+	{
+		int rcpt_filter_result = 0;
+		int size = 0;
+		char *cmd_buffer = NULL;
+		char *tmp_rcpt = NULL;
+		char * queue_id = smfi_getsymval(ctx,"i");
+		
+		debug(D_RCPT,"%s: rcpt_filter",queue_id);
+
+		
+		if((tmp_rcpt = strdup(envrcpt[0])) != NULL)
+		{
+			tmp_rcpt[strlen(tmp_rcpt)-1] = '\0';
+			size = strlen(rcpt_filter);
+			tmp_rcpt++;
+			size += strlen(tmp_rcpt);
+			cmd_buffer = (char *) malloc(size+10);
+		}
+		if(cmd_buffer) 
+		{
+			debug(D_RCPT,"%s: rcpt_filter, malloc succeeded", queue_id);
+			sprintf(cmd_buffer,"%s %s",rcpt_filter, tmp_rcpt );
+			cmd_buffer[size+2] = '\0';
+			debug(D_RCPT, "%s: rcpt_filter, filter string <%s>", queue_id, cmd_buffer);
+			
+			rcpt_filter_result = system(cmd_buffer);
+			if(!rcpt_filter_result)
+			{
+				debug(D_RCPT,"%s: rcpt_filter, removing rcpt", queue_id);
+				sctx->rcpts--;
+			} else
+				debug(D_RCPT,"%s: rcpt_filter, leaving rcpt", queue_id);
+
+		} else
+			debug(D_RCPT,"%s: rcp_filter, malloc failed", queue_id);
+
+		if(cmd_buffer)
+			free(cmd_buffer);
+		if(tmp_rcpt)
+		{
+			tmp_rcpt--;
+			free(tmp_rcpt);
+		}
+	
+	}
 	return SMFIS_CONTINUE;
 }
 
@@ -740,6 +796,21 @@
   SpamAssassin* assassin = ((struct context *)smfi_getpriv(ctx))->assassin;
   debug(D_FUNC, "mlfi_header: enter");
 
+  {
+	struct context * sctx = (struct context *) smfi_getpriv(ctx);
+	char * queue_id = smfi_getsymval(ctx,"i");
+	if(flag_rcpt_filter && !sctx->rcpts) 
+	{
+		debug(D_RCPT,"%s: rcpt_filter, accepting message without processing");
+		mlfi_abort(ctx); // For lack of specific cleanup 
+		debug(D_FUNC, "%s: mlfi_header: rcpt_filter leave", queue_id);
+		return SMFIS_ACCEPT;
+	} else
+		debug(D_RCPT, "%s: rcpt_filter, processing message", queue_id);
+	
+	debug(D_FUNC, "%s: mlfi_header: rcpt_filter leave", queue_id);
+  }
+
   // Check if the SPAMC program has already been run, if not we run it.
   if ( !(assassin->connected) )
      {
diff -ur spamass-milter-0.2.0-orig/spamass-milter.h spamass-milter-0.2.0/spamass-milter.h
--- spamass-milter-0.2.0-orig/spamass-milter.h	2003-06-14 15:17:41.000000000 -0400
+++ spamass-milter-0.2.0/spamass-milter.h	2004-09-20 10:42:33.000000000 -0400
@@ -63,7 +63,7 @@
 // Debug tokens.
 enum debuglevel 
 {
-	D_ALWAYS, D_FUNC, D_POLL, D_UORI, D_STR, D_MISC, D_NET, D_SPAMC,
+	D_ALWAYS, D_FUNC, D_POLL, D_UORI, D_STR, D_MISC, D_NET, D_SPAMC, D_RCPT,
 	D_MAX // must be last
 };
 
@@ -153,6 +153,7 @@
 	struct in_addr connect_ip;	// remote IP address
 	char *helo;
 	SpamAssassin *assassin; // pointer to the SA object if we're processing a message
+	int rcpts; // must be positive if we are to do ANY spamassassin processing
 };
 
 /* This hack is the only way to call pointers to member functions! */
