Michael Haardt's patch to update Sieve to RFC3028bis.
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Fri, 17 Jun 2005 10:47:05 +0000 (10:47 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Fri, 17 Jun 2005 10:47:05 +0000 (10:47 +0000)
doc/doc-txt/ChangeLog
doc/doc-txt/README.SIEVE
src/src/sieve.c

index e1992752fd17b143ce2303b592d3f42f5e239c84..d5a78abcb5a441a15fca247d789404d7a3497125 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.161 2005/06/17 10:20:30 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.162 2005/06/17 10:47:05 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -148,6 +148,13 @@ PH/18 If the "use_postmaster" option was set for a recipient callout together
       FROM address for the random test, but not for the subsequent recipient
       test. It is now used for both.
 
+PH/19 Applied Michael Haardt's patch to update Sieve to RFC3028bis. "The
+      patch removes a few documentation additions to RFC 3028, because the
+      latest draft now contains them. It adds the new en;ascii-case comparator
+      and a new error check for 8bit text in MIME parts. Comparator and
+      require names are now matched exactly. I enabled the subaddress
+      extension, but it is not well tested yet (read: it works for me)."
+
 
 Exim version 4.51
 -----------------
index 04383f6e596e739d4373ddaee7b578e727d582e6..d63bed7c908c848be152787b64a41bf72cdfc443 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/README.SIEVE,v 1.4 2005/05/03 10:02:27 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/README.SIEVE,v 1.5 2005/06/17 10:47:05 ph10 Exp $
 
               Notes on the Sieve implementation for Exim
 
@@ -20,9 +20,9 @@ then there is no way around it.
 
 Exim Implementation
 
-The Exim Sieve implementation offers the core as defined by RFC 3028, the
-"envelope" (RFC 3028), the "fileinto" (RFC 3028), the "copy" (RFC 3894)
-and the "vacation" (draft-ietf-sieve-vacation-01.txt) extension,
+The Exim Sieve implementation offers the core as defined by RFC 3028bis,
+the "envelope" (RFC 3028), the "fileinto" (RFC 3028), the "copy" (RFC
+3894) and the "vacation" (draft-ietf-sieve-vacation-02.txt) extension,
 the "i;ascii-numeric" comparator, but not the "reject" extension.
 Exim does not support MDMs, so adding it just to the sieve filter makes
 little sense.
@@ -141,17 +141,6 @@ This implementation treats them literally, as it does if the word is
 correct, but its character set can not be converted to UTF-8.
 
 
-Address Test For Multiple Addresses Per Header
-
-A header may contain multiple addresses.  RFC 3028 does not explicitly
-specify how to deal with them, but since the "address" test checks if
-anything matches anything else, matching one address suffices to
-satify the condition.  That makes it impossible to test if a header
-contains a certain set of addresses and no more, but it is more logical
-than letting the test fail if the header contains an additional address
-besides the one the test checks for.
-
-
 Semantics Of Keep
 
 The keep command is equivalent to fileinto "inbox": It saves the
@@ -180,19 +169,11 @@ virtual mail domains it is probably not what the user expects it to be.
 String Arguments
 
 There has been confusion if the string arguments to "require" are to be
-matched case-sensitive or not.  This implementation matches them with
-the match type ":is" (default, see section 2.7.1) and the comparator
-"i;ascii-casemap" (default, see section 2.7.3).  The RFC defines the
-command defaults clearly, so any different implementations violate RFC
-3028.  The same is valid for comparator names, also specified as strings.
-
-
-Number Units
-
-There is a mistake in RFC 3028: The suffix G denotes gibi-, not tebibyte.
-The mistake os obvious, because RFC 3028 specifies G to denote 2^30
-(which is gibi, not tebi), and that's what this implementation uses as
-scaling factor for the suffix G.
+matched case-sensitive or not.  The comparator default is case-insensitive
+comparison, but "require" does not allow to specify a comparator, so
+this default does not apply.  Lacking a clear specification, matching
+the strings exactly makes most sense.  The same is valid for comparator
+names, also specified as strings.
 
 
 Sieve Syntax and Semantics
@@ -367,19 +348,13 @@ the UTF-8 reason is processed to compose the resulting message.
 
 Default Subject
 
-The draft specifies that the default message subject is "Re: "
-plus the old subject, stripped by any leading "Re: " strings.
-This string is to be taken literally, unlike some software which
-matches a regular expression like "[rR][eE]: *".  Using this
-subject is dangerous, because many mailing lists verify addresses
-by sending a secret key in the subject of a message, asking to
-reply to the message for confirmation.  Using the default vacation
-subject confirms any subscription request of this kind, allowing
-to subscribe a third party to any mailing list, either to annoy
-the user or to declare spam as legitimate mail by proving to
-use opt-in.  The draft specifies to use "Re: " in front of the
-subject, but this implementation uses "Auto: ", as suggested in
-RFC 3834, section 3.1.5.
+The draft specifies that the default message subject is "Auto: " plus
+the old subject.  Using this subject is dangerous, because many mailing
+lists verify addresses by sending a secret key in the subject of a
+message, asking to reply to the message for confirmation.  Using the
+default vacation subject confirms any subscription request of this kind,
+allowing to subscribe a third party to any mailing list, either to annoy
+the user or to declare spam as legitimate mail by proving to use opt-in.
 
 
 Rate Limiting Responses
@@ -404,11 +379,3 @@ Global Reply Address Blacklist
 The draft requires that each implementation offers a global black list
 of addresses that will never be replied to.  Exim offers this as option
 "never_mail" in the autoreply transport.
-
-
-Interaction With Other Sieve Elements
-
-The draft describes the interaction with vacation, discard, keep,
-fileinto and redirect.  It MUST describe compatibility with other
-actions, but doesn't.  In this implementation, vacation is compatible
-with any other action.
index 2a680e17525293d42fe0dda25f39248f5923a485..296a23c2d92d10c41c41873429d413e0272c5c2b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/sieve.c,v 1.11 2005/05/03 10:02:27 ph10 Exp $ */
+/* $Cambridge: exim/src/src/sieve.c,v 1.12 2005/06/17 10:47:05 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -29,8 +29,7 @@
 #undef RFC_EOL
 
 /* Define this for development of the subaddress Sieve extension.   */
-/* The code is currently broken.                                    */
-#undef SUBADDRESS
+#define SUBADDRESS
 
 /* Define this for the vacation Sieve extension.                    */
 #define VACATION
@@ -67,7 +66,7 @@ struct Sieve
   int require_iascii_numeric;
   };
 
-enum Comparator { COMP_OCTET, COMP_ASCII_CASEMAP, COMP_ASCII_NUMERIC };
+enum Comparator { COMP_OCTET, COMP_EN_ASCII_CASEMAP, COMP_ASCII_NUMERIC };
 enum MatchType { MATCH_IS, MATCH_CONTAINS, MATCH_MATCHES };
 #ifdef SUBADDRESS
 enum AddressPart { ADDRPART_USER, ADDRPART_DETAIL, ADDRPART_LOCALPART, ADDRPART_DOMAIN, ADDRPART_ALL };
@@ -117,12 +116,16 @@ static uschar str_copy_c[]="copy";
 static const struct String str_copy={ str_copy_c, 4 };
 static uschar str_iascii_casemap_c[]="i;ascii-casemap";
 static const struct String str_iascii_casemap={ str_iascii_casemap_c, 15 };
+static uschar str_enascii_casemap_c[]="en;ascii-casemap";
+static const struct String str_enascii_casemap={ str_enascii_casemap_c, 16 };
 static uschar str_ioctet_c[]="i;octet";
 static const struct String str_ioctet={ str_ioctet_c, 7 };
 static uschar str_iascii_numeric_c[]="i;ascii-numeric";
 static const struct String str_iascii_numeric={ str_iascii_numeric_c, 15 };
 static uschar str_comparator_iascii_casemap_c[]="comparator-i;ascii-casemap";
 static const struct String str_comparator_iascii_casemap={ str_comparator_iascii_casemap_c, 26 };
+static uschar str_comparator_enascii_casemap_c[]="comparator-en;ascii-casemap";
+static const struct String str_comparator_enascii_casemap={ str_comparator_enascii_casemap_c, 27 };
 static uschar str_comparator_ioctet_c[]="comparator-i;octet";
 static const struct String str_comparator_ioctet={ str_comparator_ioctet_c, 18 };
 static uschar str_comparator_iascii_numeric_c[]="comparator-i;ascii-numeric";
@@ -646,7 +649,7 @@ if ((filter_test != FTEST_NONE && debug_selector != 0) ||
   switch (co)
     {
     case COMP_OCTET: debug_printf("i;octet"); break;
-    case COMP_ASCII_CASEMAP: debug_printf("i;ascii-casemap"); break;
+    case COMP_EN_ASCII_CASEMAP: debug_printf("en;ascii-casemap"); break;
     case COMP_ASCII_NUMERIC: debug_printf("i;ascii-numeric"); break;
     }
   debug_printf("\"):\n");
@@ -664,7 +667,7 @@ switch (mt)
         if (eq_octet(needle,haystack,0)) r=1;
         break;
         }
-      case COMP_ASCII_CASEMAP:
+      case COMP_EN_ASCII_CASEMAP:
         {
         if (eq_asciicase(needle,haystack,0)) r=1;
         break;
@@ -693,7 +696,7 @@ switch (mt)
         for (h=*haystack; h.length; ++h.character,--h.length) if (eq_octet(needle,&h,1)) { r=1; break; }
         break;
         }
-      case COMP_ASCII_CASEMAP:
+      case COMP_EN_ASCII_CASEMAP:
         {
         for (h=*haystack; h.length; ++h.character,--h.length) if (eq_asciicase(needle,&h,1)) { r=1; break; }
         break;
@@ -715,7 +718,7 @@ switch (mt)
         if (eq_octetglob(needle,haystack)) r=1;
         break;
         }
-      case COMP_ASCII_CASEMAP:
+      case COMP_EN_ASCII_CASEMAP:
         {
         if (eq_asciicaseglob(needle,haystack)) r=1;
         break;
@@ -1470,7 +1473,12 @@ switch (parse_string(filter,&comparator_name))
       }
     else if (eq_asciicase(&comparator_name,&str_iascii_casemap,0))
       {
-      *c=COMP_ASCII_CASEMAP;
+      *c=COMP_EN_ASCII_CASEMAP;
+      match=1;
+      }
+    else if (eq_asciicase(&comparator_name,&str_enascii_casemap,0))
+      {
+      *c=COMP_EN_ASCII_CASEMAP;
       match=1;
       }
     else if (eq_asciicase(&comparator_name,&str_iascii_numeric,0))
@@ -1610,7 +1618,7 @@ if (parse_identifier(filter,CUS "address"))
   */
 
   enum AddressPart addressPart=ADDRPART_ALL;
-  enum Comparator comparator=COMP_ASCII_CASEMAP;
+  enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
   enum MatchType matchType=MATCH_IS;
   struct String *hdr,*h,*key,*k;
   int m;
@@ -1820,7 +1828,7 @@ else if (parse_identifier(filter,CUS "header"))
                 <header-names: string-list> <key-list: string-list>
   */
 
-  enum Comparator comparator=COMP_ASCII_CASEMAP;
+  enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
   enum MatchType matchType=MATCH_IS;
   struct String *hdr,*h,*key,*k;
   int m;
@@ -1943,7 +1951,7 @@ else if (parse_identifier(filter,CUS "envelope"))
   envelope-part is case insensitive "from" or "to"
   */
 
-  enum Comparator comparator=COMP_ASCII_CASEMAP;
+  enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
   enum AddressPart addressPart=ADDRPART_ALL;
   enum MatchType matchType=MATCH_IS;
   struct String *env,*e,*key,*k;
@@ -2304,7 +2312,7 @@ while (*filter->pc)
     fileinto-command =  "fileinto" { fileinto-options } string ";"
     fileinto-options =
     fileinto-options =) [ ":copy" ]
-    */
+   */
 
     struct String folder;
     uschar *s;
@@ -2493,6 +2501,17 @@ while (*filter->pc)
       if (m==0) filter->errmsg=CUS "missing reason string";
       return -1;
       }
+    if (reason_is_mime)
+      {
+      uschar *s,*end;
+
+      for (s=reason.character,end=reason.character+reason.length; s<end && (*s&0x80)==0; ++s);
+      if (s<end)
+        {
+        filter->errmsg=CUS "MIME reason string contains 8bit text";
+        return -1;
+        }
+      }
     if (parse_semicolon(filter)==-1) return -1;
 
     if (exec)
@@ -2550,11 +2569,6 @@ while (*filter->pc)
           if (subject.length==-1)
             {
             expand_header(&subject,&str_subject);
-            while (subject.length>=4 && Ustrncmp(subject.character,"Re: ",4)==0)
-            {
-              subject.character+=4;
-              subject.length-=4;
-            }
             capacity=6;
             start=6;
             subject.character=string_cat(US"Auto: ",&capacity,&start,subject.character,subject.length);
@@ -2722,13 +2736,13 @@ while (parse_identifier(filter,CUS "require"))
     }
   for (check=cap; check->character; ++check)
     {
-    if (eq_asciicase(check,&str_envelope,0)) filter->require_envelope=1;
-    else if (eq_asciicase(check,&str_fileinto,0)) filter->require_fileinto=1;
+    if (eq_octet(check,&str_envelope,0)) filter->require_envelope=1;
+    else if (eq_octet(check,&str_fileinto,0)) filter->require_fileinto=1;
 #ifdef SUBADDRESS
-    else if (eq_asciicase(check,&str_subaddress,0)) filter->require_subaddress=1;
+    else if (eq_octet(check,&str_subaddress,0)) filter->require_subaddress=1;
 #endif
 #ifdef VACATION
-    else if (eq_asciicase(check,&str_vacation,0))
+    else if (eq_octet(check,&str_vacation,0))
       {
       if (filter_test == FTEST_NONE && filter->vacation_directory == NULL)
         {
@@ -2738,10 +2752,11 @@ while (parse_identifier(filter,CUS "require"))
       filter->require_vacation=1;
       }
 #endif
-    else if (eq_asciicase(check,&str_copy,0)) filter->require_copy=1;
-    else if (eq_asciicase(check,&str_comparator_ioctet,0)) ;
-    else if (eq_asciicase(check,&str_comparator_iascii_casemap,0)) ;
-    else if (eq_asciicase(check,&str_comparator_iascii_numeric,0)) filter->require_iascii_numeric=1;
+    else if (eq_octet(check,&str_copy,0)) filter->require_copy=1;
+    else if (eq_octet(check,&str_comparator_ioctet,0)) ;
+    else if (eq_octet(check,&str_comparator_iascii_casemap,0)) ;
+    else if (eq_octet(check,&str_comparator_enascii_casemap,0)) ;
+    else if (eq_octet(check,&str_comparator_iascii_numeric,0)) filter->require_iascii_numeric=1;
     else
       {
       filter->errmsg=CUS "unknown capability";