[PATCH] Allow the admin to define a global sieve script that is execute before user-defined scripts

Florian G. Pflug fgp at phlo.org
Thu Dec 14 13:08:47 EST 2006


Hi

I've developed a patch that extends the "/vendor/cmu/cyrus-imapd/sieve"
mailbox annotation to be meaningful for a user's inbox
in addition to shared mailboxes.
For a user's inbox, the sieve-annotation specifies the name of a global
sieve script that is executed when new mail is delivery to that user
_before_ his private sieve-default-script is executed.

I need this to easily file Junk-mails into a users junk folder without
messing with his private sieve script.

My patch changes the "sieve_execute_t *exe" parameter of sieve_execute_bytecode
to "sieve_execute_t **exes" (exes has to be a null-terminated array of
pointers to a sieve_execute_t structure). sieve_execute_bytecode calls
sieve_eval_bc for each entry of that array, passing 1 for is_incl for all
but the last entry. This makes a script defined via the
"/vendor/cmu/cyrus-imapd/sieve" annotation on a users's inbox behave like
it was included at the top of the user's own sieve script.

Patch is attached. I'd like to see this included in cyrus 2.3, and am ready
to improve that patch if it's not acceptable for inclusion in it's present form.

I'm not subscribed to this list, so please reply to me personally.

greetings, Florian Pflug

-------------- next part --------------
diff -Naur orig/cyrus-imapd-2.3.7/imap/lmtp_sieve.c cyrus-imapd-2.3.7/imap/lmtp_sieve.c
--- orig/cyrus-imapd-2.3.7/imap/lmtp_sieve.c	2006-05-23 15:09:35.000000000 +0200
+++ cyrus-imapd-2.3.7/imap/lmtp_sieve.c	2006-12-14 18:28:23.000000000 +0100
@@ -859,33 +859,67 @@
 {
     char namebuf[MAX_MAILBOX_NAME+1] = "";
     struct annotation_data attrib;
-    const char *script = NULL;
+    const char *script_main = NULL;
+    const char *script_prepend = NULL;
     char fname[MAX_MAILBOX_PATH+1];
-    sieve_execute_t *bc = NULL;
+    sieve_execute_t *bc_prepend = NULL;
+    sieve_execute_t *bc_main = NULL;
+    sieve_execute_t *bcs_empty[3] = {NULL, NULL, NULL} ;
+    sieve_execute_t **bcs = bcs_empty ;
     script_data_t sdata;
     char userbuf[MAX_MAILBOX_NAME+1] = "";
     char authuserbuf[MAX_MAILBOX_NAME+1];
     int r = 0;
 
+    if (domain) snprintf(namebuf, sizeof(namebuf), "%s!", domain);
+    else namebuf[0] = '\0';
+
     if (!user) {
 	/* shared mailbox, check for annotation */
-	if (domain) snprintf(namebuf, sizeof(namebuf), "%s!", domain);
 	strlcat(namebuf, mailbox, sizeof(namebuf));
 
-	if (annotatemore_lookup(namebuf,
+	if (!annotatemore_lookup(namebuf,
 				"/vendor/cmu/cyrus-imapd/sieve", "",
 				&attrib) != 0 || !attrib.value) {
-	    /* no sieve script annotation */
-	    return 1; /* do normal delivery actions */
+            script_main = attrib.value ;
+	}
+    }
+    else {
+        /* User. check for prepend annotation */
+        strlcat(namebuf, "user.", sizeof(namebuf));
+        strlcat(namebuf, user, sizeof(namebuf));
+      
+	if (!annotatemore_lookup(namebuf,
+				"/vendor/cmu/cyrus-imapd/sieve", "",
+				&attrib) != 0 || !attrib.value) {
+            script_prepend = attrib.value;
 	}
-
-	script = attrib.value;
     }
 
-    if (sieve_find_script(user, domain, script, fname, sizeof(fname)) != 0 ||
-	sieve_script_load(fname, &bc) != SIEVE_OK) {
-	/* no sieve script */
-	return 1; /* do normal delivery actions */
+    /* Note that sieve_find_script returns a user's default script
+       if script_main is null, and searches for global scripts if
+       user is null */
+    if (sieve_find_script(user, domain, script_main, fname, sizeof(fname)) != 0 ||
+	sieve_script_load(fname, &bc_main) != SIEVE_OK) {
+        bc_main = NULL ;
+    }
+    /* prepend-script are always global scripts. The user could just use
+       include otherwise */
+    if (script_prepend == NULL ||
+        sieve_find_script(NULL, domain, script_prepend, fname, sizeof(fname)) != 0 ||
+	sieve_script_load(fname, &bc_prepend) != SIEVE_OK) {
+        bc_prepend = NULL ;
+    }
+    
+    if (bc_prepend == NULL) {
+        if (bc_main == NULL)
+            return 1; /*No sieve scripts, do normal actions */
+        else
+            bcs[0] = bc_main ;
+    }
+    else {
+        bcs[0] = bc_prepend ;
+        bcs[1] = bc_main ;
     }
 
     if (user) strlcpy(userbuf, user, sizeof(userbuf));
@@ -908,7 +942,7 @@
 	sdata.authstate = msgdata->authstate;
     }	
 
-    r = sieve_execute_bytecode(bc, interp,
+    r = sieve_execute_bytecode(bcs, interp,
 			       (void *) &sdata, (void *) msgdata);
 
     if ((r == SIEVE_OK) && (msgdata->m->id)) {
@@ -928,7 +962,8 @@
 		
     /* free everything */
     if (user && sdata.authstate) auth_freestate(sdata.authstate);
-    sieve_script_unload(&bc);
+    while (*bcs != NULL)
+        sieve_script_unload(bcs++) ;
 		
     /* if there was an error, r is non-zero and 
        we'll do normal delivery */
diff -Naur orig/cyrus-imapd-2.3.7/sieve/script.c cyrus-imapd-2.3.7/sieve/script.c
--- orig/cyrus-imapd-2.3.7/sieve/script.c	2005-10-05 17:56:23.000000000 +0200
+++ cyrus-imapd-2.3.7/sieve/script.c	2006-12-14 18:28:47.000000000 +0100
@@ -873,9 +873,10 @@
 		  sieve_imapflags_t * imapflags, action_list_t *actions,
 		  notify_list_t *notify_list, const char **errmsg);
 
-int sieve_execute_bytecode(sieve_execute_t *exe, sieve_interp_t *interp,
+int sieve_execute_bytecode(sieve_execute_t **exes, sieve_interp_t *interp,
 			   void *script_context, void *message_context) 
 {
+    sieve_execute_t **exe = exes ;
     action_list_t *actions = NULL;
     notify_list_t *notify_list = NULL;
     /*   notify_action_t *notify_action;*/
@@ -912,9 +913,15 @@
 			     actions_string, errmsg);
     }
     else {
-	ret = sieve_eval_bc(exe, 0, interp, &body_cache,
-			    script_context, message_context,
-			    &imapflags, actions, notify_list, &errmsg);
+        /* Loop over executables until an error or a stop occurs */
+        ret = 0 ;
+        while ((*exe != NULL) && (ret == 0)) {
+          /* Pretend that all but the last exe is an include. */
+          ret = sieve_eval_bc(*exe, (exe[1] == NULL) ? 0 : 1, interp,
+                              &body_cache, script_context, message_context,
+			      &imapflags, actions, notify_list, &errmsg);
+          exe++ ;
+        }
 
 	if (ret < 0) {
 	    ret = do_sieve_error(SIEVE_RUN_ERROR, interp, &body_cache,
diff -Naur orig/cyrus-imapd-2.3.7/sieve/test.c cyrus-imapd-2.3.7/sieve/test.c
--- orig/cyrus-imapd-2.3.7/sieve/test.c	2005-10-05 17:56:25.000000000 +0200
+++ cyrus-imapd-2.3.7/sieve/test.c	2006-12-12 15:59:31.000000000 +0100
@@ -730,6 +730,7 @@
 {
     sieve_interp_t *i;
     sieve_execute_t *exe = NULL;
+    sieve_execute_t **exes = {exe, NULL} ;
     message_data_t *m;
     char *script = NULL, *message = NULL;
     int c, force_fail = 0, usage_error = 0;
@@ -884,7 +885,7 @@
 	    exit(1);
 	}
 
-	res = sieve_execute_bytecode(exe, i, NULL, m);
+	res = sieve_execute_bytecode(exes, i, NULL, m);
 	if (res != SIEVE_OK) {
 	    printf("sieve_execute_bytecode() returns %d\n", res);
 	    exit(1);


More information about the Cyrus-devel mailing list