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