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.
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);