rfc 3685 (Spamtest and VirusTest Extensions)

Andrew B. Panphiloff andrew at panfilov.org.ru
Wed Mar 30 17:30:25 EST 2005


Yesterday, I have ported sieve-spamasssassin patch from contrib 
directory to cyrus-imapd-2.2.12 (see attachment).
Can anybody help me to do this patch rfc-compatible ?

Ken Murchison wrote:

> Andrew B. Panphiloff wrote:
>
>> Does cyrus-imapd support thees extensions ?
>
>
> Not currently.
>
>
>

-------------- next part --------------
diff -Nru cyrus-imapd-2.2.12/imap/lmtp_sieve.c cyrus-imapd-2.2.12.sa/imap/lmtp_sieve.c
--- cyrus-imapd-2.2.12/imap/lmtp_sieve.c	2004-06-01 17:47:16.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/imap/lmtp_sieve.c	2005-03-30 11:12:10.063744024 +0400
@@ -672,6 +672,163 @@
 static char *markflags[] = { "\\flagged" };
 static sieve_imapflags_t mark = { markflags, 1 };
 
+
+/* spam support */
+
+static int
+getline (int s, char *buf, int len)
+{
+    char *bp = buf;
+    int ret = 1;
+    char ch;
+
+    while ((ret = read (s, &ch, 1)) == 1 && ch != '\n') {
+	if (len > 0) {
+	    *bp++ = ch;
+	    len--;
+	}
+    }
+    if (len > 0)
+	*bp = '\0';
+    return (buf != bp);
+}
+
+
+static int
+full_write (int s, char *buf, int len)
+{
+    int total;
+    int ret;
+
+    for (total = 0; total < len; total += ret) {
+	ret = write (s, buf + total, len - total);
+	if (ret < 0)
+	    return 0;
+    }
+    return total == len;
+}
+
+
+static int
+read_response (int s, int *result)
+{
+    char is_spam[6];
+    char buf[1024];
+    int major;
+    int minor;
+    int response;
+    int score;
+    int threshold;
+
+    if (! getline (s, buf, sizeof (buf))) {
+	syslog (LOG_ERR, "read_response: response getline failed");
+	return SIEVE_FAIL;
+    }
+    if (sscanf (buf, "SPAMD/%d.%d %d %*s", &major, &minor, &response) != 3) {
+	syslog (LOG_ERR, "read_response: response sscanf failed, buf: %s",
+		buf);
+	return SIEVE_FAIL;
+    }
+    if (major < 1 || (major == 1 && minor < 1)) {
+	syslog (LOG_ERR, "read_response: bad spamd version: %d.%d",
+		major, minor);
+	return SIEVE_FAIL;
+    }
+    if (! getline (s, buf, sizeof (buf))) {
+	syslog (LOG_ERR, "read_response: header getline failed");
+	return SIEVE_FAIL;
+    }
+    if (sscanf (buf, "Spam: %s ; %f / %f", is_spam, &score, &threshold) != 3) {
+	syslog (LOG_ERR, "read_response: header sscanf failed, buf: %s",
+		buf);
+	return SIEVE_FAIL;
+    }
+
+    *result = ! strcmp(is_spam, "True");
+    return SIEVE_OK;
+}
+
+static int spam (void *mc, int *is_spam)
+{
+    sieve_msgdata_t *mydata = (sieve_msgdata_t *) mc;
+    message_data_t *md = mydata->m;
+    int s;
+    struct sockaddr_in addr;
+    struct hostent *host;
+    char header[128];
+    int max_size = config_getint(IMAPOPT_SPAM_MAX_SIZE);
+    const char *hostname = config_getstring (IMAPOPT_SPAMD_HOST);
+    int port = config_getint (IMAPOPT_SPAMD_PORT);
+    char *msg_buf;
+    int ret;
+      
+    if (md->size > max_size) {
+	syslog (LOG_INFO, "spam: skipping message bigger than %d", max_size);
+	return SIEVE_FAIL;
+    }
+
+    memset (&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+
+    if ((host = gethostbyname (hostname)) == NULL) {
+	syslog (LOG_ERR, "spam: gethostbyname failed");
+	return SIEVE_FAIL;
+    }
+    memcpy (&addr.sin_addr, host->h_addr, sizeof (addr.sin_addr));
+
+    if((s = socket (PF_INET, SOCK_STREAM, 0)) < 0) {
+	syslog (LOG_ERR, "spam: socket failed");
+	return SIEVE_FAIL;
+    }
+
+    if (connect (s, (const struct sockaddr *) &addr, sizeof (addr)) < 0) {
+	syslog (LOG_ERR, "spam: connect failed");
+	close (s);
+	return SIEVE_FAIL;
+    }
+
+    if ((msg_buf = malloc (md->size)) == NULL) {
+	syslog (LOG_ERR, "spam: malloc(%d) failed", md->size);
+	close (s);
+	return SIEVE_FAIL;
+    }
+    rewind (md->f);
+    if (fread (msg_buf, 1, md->size, md->f) != md->size || ferror (md->f)) {
+	syslog (LOG_ERR, "spam: read message failed");
+	free (msg_buf);
+	close (s);
+	return SIEVE_FAIL;
+    }
+
+    else {
+	snprintf (header, sizeof (header),
+		  "CHECK SPAMC/1.2\r\nContent-length: %d\r\n\r\n", md->size);
+    }
+    if (! full_write (s, header, strlen (header))) {
+	syslog (LOG_ERR, "spam: write header failed");
+	free (msg_buf);
+	close (s);
+	return SIEVE_FAIL;
+    }
+    if (! full_write (s, msg_buf, md->size)) {
+	syslog (LOG_ERR, "spam: write message failed");
+	free (msg_buf);
+	close (s);
+	return SIEVE_FAIL;
+    }
+
+    shutdown (s, SHUT_WR);
+    ret = read_response (s, is_spam);
+    shutdown (s, SHUT_RD);
+
+    free (msg_buf);
+    close (s);
+
+    syslog(LOG_DEBUG, "spam result: %d\n", is_spam);
+    return ret;
+}
+
 static int sieve_parse_error_handler(int lineno, const char *msg, 
 				     void *ic __attribute__((unused)),
 				     void *sc)
@@ -785,6 +942,11 @@
 	syslog(LOG_ERR, "sieve_register_execute_error() returns %d\n", res);
 	fatal("sieve_register_execute_error()", EC_SOFTWARE);
     }
+    res = sieve_register_spam(interp, &spam);
+    if (res != SIEVE_OK) {
+	syslog(LOG_ERR, "sieve_register_spam() returns %d\n", res);
+	fatal("sieve_register_spam()", EC_SOFTWARE);
+    }
 
     return interp;
 }
diff -Nru cyrus-imapd-2.2.12/lib/imapoptions cyrus-imapd-2.2.12.sa/lib/imapoptions
--- cyrus-imapd-2.2.12/lib/imapoptions	2004-07-21 23:07:45.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/lib/imapoptions	2005-03-30 11:12:04.758550536 +0400
@@ -152,6 +152,12 @@
    creating the mailbox INBOX.  The user's quota is set to the value
    if it is positive, otherwise the user has unlimited quota. */
 
+{ "spam_max_size", 0, INT }
+
+{ "spamd_port", 783 , INT }
+
+{ "spamd_host", "127.0.0.1", STRING }
+
 { "berkeley_cachesize", 512, INT }
 /* Size (in kilobytes) of the shared memory buffer pool (cache) used
    by the berkeley environment.  The minimum allowed value is 20.  The
diff -Nru cyrus-imapd-2.2.12/sieve/bc_dump.c cyrus-imapd-2.2.12.sa/sieve/bc_dump.c
--- cyrus-imapd-2.2.12/sieve/bc_dump.c	2003-10-22 22:03:23.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/bc_dump.c	2005-03-30 11:12:04.759550384 +0400
@@ -97,6 +97,10 @@
 	printf("%d: FALSE\n",ip);
 	break;
 
+    case SPAM:
+	printf("%d: SPAM\n",ip);
+	break;
+	
     case BC_NOT:
 	printf("%d: NOT TEST(\n",ip++);
 	/*   printf("  (until %d)\n", d->data[ip++].jump);*/
diff -Nru cyrus-imapd-2.2.12/sieve/bc_emit.c cyrus-imapd-2.2.12.sa/sieve/bc_emit.c
--- cyrus-imapd-2.2.12/sieve/bc_emit.c	2003-10-22 22:03:24.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/bc_emit.c	2005-03-30 11:12:04.759550384 +0400
@@ -190,6 +190,7 @@
     switch(bc->data[(*codep)++].op) {
     case BC_TRUE:
     case BC_FALSE:
+    case BC_SPAM:
 	/* No parameter opcodes */
 	break;
 	
diff -Nru cyrus-imapd-2.2.12/sieve/bc_eval.c cyrus-imapd-2.2.12.sa/sieve/bc_eval.c
--- cyrus-imapd-2.2.12/sieve/bc_eval.c	2004-07-29 19:42:31.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/bc_eval.c	2005-03-30 11:12:10.064743872 +0400
@@ -315,7 +315,6 @@
     comparator_t * comp=NULL;
     void * comprock=NULL;
     int op= ntohl(bc[i].op);
-    
     switch(op)
     {
     case BC_FALSE:
@@ -356,6 +355,14 @@
 	i=list_end; /* adjust for short-circuit */
 	break;
     }
+    case BC_SPAM:
+    {
+ 	int is_spam;
+ 	if (interp->spam == NULL || interp->spam (m, &is_spam) != SIEVE_OK)
+		break;
+ 	res = is_spam;
+	break;
+    }
     case BC_SIZE:/*4*/
     {
 	int s;
diff -Nru cyrus-imapd-2.2.12/sieve/bc_generate.c cyrus-imapd-2.2.12.sa/sieve/bc_generate.c
--- cyrus-imapd-2.2.12/sieve/bc_generate.c	2004-08-11 22:43:15.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/bc_generate.c	2005-03-30 11:12:04.761550080 +0400
@@ -267,6 +267,10 @@
 				       ? B_OVER : B_UNDER);
 	retval->data[codep++].value = t->u.sz.n;
 	break;
+    case SPAM:
+	if(!atleast(retval,codep+1)) return -1;
+	retval->data[codep++].op = BC_SPAM;
+	break;
     case EXISTS:/* BC_EXISTS { headers : string list } */
 	if(!atleast(retval,codep+1)) return -1;
 	retval->data[codep++].op = BC_EXISTS;
diff -Nru cyrus-imapd-2.2.12/sieve/bytecode.h cyrus-imapd-2.2.12.sa/sieve/bytecode.h
--- cyrus-imapd-2.2.12/sieve/bytecode.h	2004-06-22 20:54:54.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/bytecode.h	2005-03-30 11:12:04.761550080 +0400
@@ -111,6 +111,7 @@
     BC_TRUE,
     BC_NOT,
     BC_EXISTS,
+    BC_SPAM,
     BC_SIZE,
     BC_ANYOF,
     BC_ALLOF,
diff -Nru cyrus-imapd-2.2.12/sieve/interp.c cyrus-imapd-2.2.12.sa/sieve/interp.c
--- cyrus-imapd-2.2.12/sieve/interp.c	2004-11-07 17:53:19.000000000 +0300
+++ cyrus-imapd-2.2.12.sa/sieve/interp.c	2005-03-30 11:12:04.762549928 +0400
@@ -144,6 +144,12 @@
     return SIEVE_OK;
 }
 
+int sieve_register_spam(sieve_interp_t *interp, sieve_spam *f)
+{
+    interp->spam = f;
+    return SIEVE_OK;
+}
+
 /* add the callbacks for messages. again, undefined if used after
    sieve_script_parse */
 int sieve_register_size(sieve_interp_t *interp, sieve_get_size *f)
diff -Nru cyrus-imapd-2.2.12/sieve/interp.h cyrus-imapd-2.2.12.sa/sieve/interp.h
--- cyrus-imapd-2.2.12/sieve/interp.h	2002-03-10 05:58:09.000000000 +0300
+++ cyrus-imapd-2.2.12.sa/sieve/interp.h	2005-03-30 11:12:04.762549928 +0400
@@ -35,6 +35,7 @@
     sieve_callback *redirect, *discard, *reject, *fileinto, *keep;
     sieve_callback *notify;
     sieve_vacation_t *vacation;
+    sieve_spam *spam;
 
     sieve_get_size *getsize;
     sieve_get_header *getheader;
diff -Nru cyrus-imapd-2.2.12/sieve/script.c cyrus-imapd-2.2.12.sa/sieve/script.c
--- cyrus-imapd-2.2.12/sieve/script.c	2004-07-15 19:02:51.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/script.c	2005-03-30 11:12:04.763549776 +0400
@@ -114,6 +114,13 @@
     } else if (!strcmp("comparator-i;ascii-numeric", req)) {
 	s->support.i_ascii_numeric = 1;
 	return 1;
+    } else if (!strcmp("spam",req)) {
+	if (s->interp.spam) {
+	    s->support.spam = 1;
+	    return 1;
+	} else {
+	    return 0;
+	}
     }
     return 0;
 }
diff -Nru cyrus-imapd-2.2.12/sieve/script.h cyrus-imapd-2.2.12.sa/sieve/script.h
--- cyrus-imapd-2.2.12/sieve/script.h	2003-10-22 22:50:30.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/script.h	2005-03-30 11:12:04.763549776 +0400
@@ -47,6 +47,7 @@
 	int notify         : 1;
 	int regex          : 1;
 	int subaddress     : 1;
+	int spam      : 1;
 	int relational     : 1;
 	int i_ascii_numeric: 1;
     } support;
diff -Nru cyrus-imapd-2.2.12/sieve/sieve_interface.h cyrus-imapd-2.2.12.sa/sieve/sieve_interface.h
--- cyrus-imapd-2.2.12/sieve/sieve_interface.h	2003-10-22 22:50:30.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/sieve_interface.h	2005-03-30 11:12:04.765549472 +0400
@@ -52,6 +52,8 @@
 typedef int sieve_get_envelope(void *message_context, 
 			       const char *field,
 			       const char ***contents);
+typedef int sieve_spam(void *message_context, int *is_spam);
+
 
 typedef struct sieve_vacation {
     int min_response;		/* 0 -> defaults to 3 */
@@ -123,6 +125,7 @@
 int sieve_register_vacation(sieve_interp_t *interp, sieve_vacation_t *v);
 int sieve_register_imapflags(sieve_interp_t *interp, sieve_imapflags_t *mark);
 int sieve_register_notify(sieve_interp_t *interp, sieve_callback *f);
+int sieve_register_spam(sieve_interp_t *interp, sieve_spam *f);
 
 /* add the callbacks for messages. again, undefined if used after
    sieve_script_parse */
diff -Nru cyrus-imapd-2.2.12/sieve/sieve-lex.l cyrus-imapd-2.2.12.sa/sieve/sieve-lex.l
--- cyrus-imapd-2.2.12/sieve/sieve-lex.l	2002-06-08 00:04:49.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/sieve-lex.l	2005-03-30 11:12:04.763549776 +0400
@@ -91,6 +91,7 @@
 <INITIAL>header		return HEADER;
 <INITIAL>not		return NOT;
 <INITIAL>size		return SIZE;
+<INITIAL>spam		return SPAM;
 <INITIAL>reject		return REJCT;
 <INITIAL>fileinto	return FILEINTO;
 <INITIAL>redirect	return REDIRECT;
diff -Nru cyrus-imapd-2.2.12/sieve/sieve.y cyrus-imapd-2.2.12.sa/sieve/sieve.y
--- cyrus-imapd-2.2.12/sieve/sieve.y	2004-06-30 00:29:26.000000000 +0400
+++ cyrus-imapd-2.2.12.sa/sieve/sieve.y	2005-03-30 11:12:04.764549624 +0400
@@ -150,6 +150,7 @@
 %token SETFLAG ADDFLAG REMOVEFLAG MARK UNMARK
 %token NOTIFY DENOTIFY
 %token ANYOF ALLOF EXISTS SFALSE STRUE HEADER NOT SIZE ADDRESS ENVELOPE
+%token SPAM
 %token COMPARATOR IS CONTAINS MATCHES REGEX COUNT VALUE OVER UNDER
 %token GT GE LT LE EQ NE
 %token ALL LOCALPART DOMAIN USER DETAIL
@@ -432,6 +433,11 @@
 	| NOT test		 { $$ = new_test(NOT); $$->u.t = $2; }
 	| SIZE sizetag NUMBER    { $$ = new_test(SIZE); $$->u.sz.t = $2;
 		                   $$->u.sz.n = $3; }
+	| SPAM			 { if (!parse_script->support.spam) {
+				     yyerror("spam not required");
+				     YYERROR;
+				   }
+				   $$ = new_test(SPAM); }
 	| error			 { $$ = NULL; }
 	;
 
diff -Nru cyrus-imapd-2.2.12/timsieved/scripttest.c cyrus-imapd-2.2.12.sa/timsieved/scripttest.c
--- cyrus-imapd-2.2.12/timsieved/scripttest.c	2004-03-11 18:23:21.000000000 +0300
+++ cyrus-imapd-2.2.12.sa/timsieved/scripttest.c	2005-03-30 11:12:04.765549472 +0400
@@ -171,6 +171,12 @@
 	return TIMSIEVE_FAIL;
     }
 
+    res = sieve_register_spam(i, (sieve_spam *) &foo);
+    if (res != SIEVE_OK) {
+	syslog (LOG_ERR, "sieve_register_spam() returns %d\n", res);
+	return TIMSIEVE_FAIL;
+    }
+ 
     res = sieve_register_parse_error(i, &mysieve_error);
     if (res != SIEVE_OK) {
 	syslog(LOG_ERR, "sieve_register_parse_error() returns %d\n", res);


More information about the Info-cyrus mailing list