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.




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

Reply via email to