I'd like to put forward the following patch for dovecot-sieve.

Essentially this just merges in some changes made in CMU sieve 2.3.8 and
as such brings the behaviour more in line with RFC 3834 "Recommendations
for Automatic Responses to Electronic Mail":

 - fixes erroneous sender "-request" substring match

 - checks for existence of a selection of list-* headers

 - expands "named-as-recipient" header checks to "Resent-To", "Resent-CC"
   and "Resent-BCC" fields.  Note that the appended patch also includes a
   fix for some missing parentheses in the "resent-to" test which resulted
   in some extra work being done but was otherwise harmless.  The fix has
   been sent to <[EMAIL PROTECTED]>

 - prefixes subject in response with "Auto: " rather than (non-expanding)
   "Re: "

I also, mostly for kicks, attach two sieve-like scripts that attempt to
encapsulate the when-not-to-respond logic as implemented (if the patch
were to be applied) and as advised by RFC 3834 respectively.  I wrote
these as an exercise to help me gain a better understanding of sieve and
the CMU implementation.  I'm not sure they are otherwise useful.
#
# An attempt to render, as SIEVE, the actions of shouldRespond() from CMU
# sieve/bc_eval.c as distributed with cyrus-imapd 2.3.8
#
# This is not valid SIEVE; The following expansions must first be
# performed:
#
#  - %myaddrs%  list of valid recipient addresses
#  - %envrcpt%  the actual envelope recipient
#
# Example:
#
#  sed -e 's/%myaddrs%/["[EMAIL PROTECTED]", "[EMAIL PROTECTED]"]/' \
#      -e 's/%envrcpt%/"[EMAIL PROTECTED]"/' < vacation.sieve.in
#
require ["envelope"];

if anyof ( exists "list-id",
           exists "list-help",
           exists "list-subscribe",
           exists "list-unsubscribe",
           exists "list-post",
           exists "list-owner",
           exists "list-archive",

           # XXX bc_eval.c also skips leading whitespace
           not header :is "auto-submitted" "no",

           # XXX bc_eval.c also skips leading whitespace
           header :is "precedence" ["junk", "bulk", "list"],

           # XXX does this really catch null sender?
           envelope :all :is "from" "",

           # envelope sender equals envelope recipient; redundant if we assume
           # %envrcpt% is an element in %myaddrs%
           envelope :all :is "from" %envrcpt%,
           envelope :all :is "from" %myaddrs%,

           envelope :localpart :is "from" ["mailer-daemon",
                                           "listserv",
                                           "majordomo"],
           envelope :comparator "i;octet"
                    :localpart :matches "from" ["*-request",
                                                "owner-*"],
           not address :all :is ["to",
                                 "cc",
                                 "bcc",
                                 "resent-to",
                                 "resent-cc",
                                 "resent-bcc"] %myaddrs%
) {
  discard;
}
#
# An attempt to render, as SIEVE, the advice from RFC 3834 section 2 "When
# (not) to send automatic responses".  Assumes we are a "Personal
# Responder".
#
# This is not valid SIEVE; The following expansions must first be
# performed:
#
#  - %myaddrs%    list of valid recipient addresses
#  - %untrusted%  list of untrusted envelope senders
#
# Example:
#
#  sed -e 's/%myaddrs%/["[EMAIL PROTECTED]", "[EMAIL PROTECTED]"]/' \
#      -e 's/%untrusted%/["[EMAIL PROTECTED]"]/' < rfc3834.sieve.in
#
require ["envelope"];

if anyof ( # Fails to account for syntax defined in section 5.1
           # SHOULD NOT
           not header :is "auto-submitted" "no", 
           
           # SHOULD NOT
           not address :all :is ["to",
                                 "cc",
                                 "bcc",
                                 "resent-to",
                                 "resent-cc",
                                 "resent-bcc"] %myaddrs%,

           # MAY
           envelope :all :is "from" %untrusted%,

           # XXX Not clear if this correctly expresses a null sender
           # MUST NOT
           envelope :all :is "from" "",

           # Strictly speaking localparts are case-sensitive hence the
           # use of :comparator.  In reality the default "i;ascii-casemap"
           # comparator almost certainly make more sense.
           # MAY
           envelope :comparator "i;octet"
                    :localpart :is "from" ["MAILER-DAEMON"],
           envelope :comparator "i;octet"
                    :localpart :matches "from" ["*-request",
                                                "owner-*"],

           # XXX no such recommendation is actually made
           # MAY
           header :is "precedence" "list",

           # Mentions List-* and references RFC2369.  Not possible to
           # express "list-*" as a header match in sieve.  Instead just
           # enumerate the RFC2369 and RFC2919 (List-ID) defined headers.
           # MAY
           exists "list-help",
           exists "list-unsubscribe",
           exists "list-subscribe",
           exists "list-post",
           exists "list-owner",
           exists "list-archive",
           exists "list-id"
) {
  discard;
}
# HG changeset patch
# User <[EMAIL PROTECTED]>
# Date 1186514697 -3600
# Node ID 5132f4b25eb08437f22ce2458bfa6b1e4d27ae9c
# Parent  9137442dd18a511023a29fc50062cdb0091e3b1b
Merge in changes from CMU sieve 2.3.8

diff -r 9137442dd18a -r 5132f4b25eb0 src/libsieve/bc_eval.c
--- a/src/libsieve/bc_eval.c    Wed Aug 01 15:02:51 2007 +0300
+++ b/src/libsieve/bc_eval.c    Tue Aug 07 20:24:57 2007 +0100
@@ -124,7 +124,7 @@ static int sysaddr(const char *addr)
     if (!strncasecmp(addr, "majordomo", 9))
        return 1;
 
-    if (strstr(addr, "-request"))
+    if (strstr(addr, "-request@"))
        return 1;
 
     if (!strncmp(addr, "owner-", 6))
@@ -186,6 +186,17 @@ static char* look_for_me(char *myaddr, i
 
     return found;
 }
+
+static char *list_fields[] = {
+    "list-id",
+    "list-help",
+    "list-subscribe",
+    "list-unsubscribe",
+    "list-post",
+    "list-owner",
+    "list-archive",
+    NULL
+};
  
 /* Determine if we should respond to a vacation message */
 static int shouldRespond(void * m, sieve_interp_t *interp,
@@ -195,14 +206,28 @@ static int shouldRespond(void * m, sieve
     const char **body;
     char buf[128];
     char *myaddr = NULL;
-    int l = SIEVE_OK;
+    int l = SIEVE_OK, j;
     void *data = NULL, *marker = NULL;
     char *tmp;
     int curra, x;
     char *found=NULL;
     char *reply_to=NULL;
   
-    /* is there an Auto-Submitted keyword other than "no"? */
+    /* Implementations SHOULD NOT respond to any message that contains a
+       "List-Id" [RFC2919], "List-Help", "List-Subscribe", "List-
+       Unsubscribe", "List-Post", "List-Owner" or "List-Archive" [RFC2369]
+       header field. */
+    for (j = 0; list_fields[j]; j++) {
+       strcpy(buf, list_fields[j]);
+       if (interp->getheader(m, buf, &body) == SIEVE_OK) {
+           l = SIEVE_DONE;
+           break;
+       }
+    }
+
+    /* Implementations SHOULD NOT respond to any message that has an
+       "Auto-submitted" header field with a value other than "no".
+       This header field is described in [RFC3834]. */
     strcpy(buf, "auto-submitted");
     if (interp->getheader(m, buf, &body) == SIEVE_OK) {
        /* we don't deal with comments, etc. here */
@@ -212,6 +237,7 @@ static int shouldRespond(void * m, sieve
     }
 
     /* is there a Precedence keyword of "junk | bulk | list"? */
+    /* XXX  non-standard header, but worth checking */
     strcpy(buf, "precedence");
     if (interp->getheader(m, buf, &body) == SIEVE_OK) {
        /* we don't deal with comments, etc. here */
@@ -282,7 +308,7 @@ static int shouldRespond(void * m, sieve
     if (l == SIEVE_OK) {
        /* ok, we're willing to respond to the sender.
           but is this message to me?  that is, is my address
-          in the TO, CC or BCC fields? */
+          in the [Resent]-To, [Resent]-Cc or [Resent]-Bcc fields? */
        if (strcpy(buf, "to"), 
            interp->getheader(m, buf, &body) == SIEVE_OK)
            found = look_for_me(myaddr, numaddresses ,bc, i, body);
@@ -290,6 +316,15 @@ static int shouldRespond(void * m, sieve
                       (interp->getheader(m, buf, &body) == SIEVE_OK)))
            found = look_for_me(myaddr, numaddresses, bc, i, body);
        if (!found && (strcpy(buf, "bcc"),
+                      (interp->getheader(m, buf, &body) == SIEVE_OK)))
+           found = look_for_me(myaddr, numaddresses, bc, i, body);
+       if (!found && (strcpy(buf, "resent-to"), 
+                      (interp->getheader(m, buf, &body) == SIEVE_OK)))
+           found = look_for_me(myaddr, numaddresses ,bc, i, body);
+       if (!found && (strcpy(buf, "resent-cc"),
+                      (interp->getheader(m, buf, &body) == SIEVE_OK)))
+           found = look_for_me(myaddr, numaddresses, bc, i, body);
+       if (!found && (strcpy(buf, "resent-bcc"),
                       (interp->getheader(m, buf, &body) == SIEVE_OK)))
            found = look_for_me(myaddr, numaddresses, bc, i, body);
        if (!found)
@@ -1093,10 +1128,7 @@ int sieve_eval_bc(sieve_interp_t *i, con
                        /* s[0] contains the original subject */
                        const char *origsubj = s[0];
 
-                       while (!strncasecmp(origsubj, "Re: ", 4)) 
-                           origsubj += 4;
-
-                       snprintf(subject, sizeof(subject), "Re: %s", origsubj);
+                       snprintf(subject, sizeof(subject), "Auto: %s", 
origsubj);
                    }
                } else {
                    /* user specified subject */

Reply via email to