From: Philip Hazel Date: Fri, 17 Jun 2005 10:47:05 +0000 (+0000) Subject: Michael Haardt's patch to update Sieve to RFC3028bis. X-Git-Tag: exim-4_52~42 X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=commitdiff_plain;h=5ea815927da4109ae019a30dac22151c5b988094;hp=90e9ce597d563d233e6623a8cb59b67d55a91d03 Michael Haardt's patch to update Sieve to RFC3028bis. --- diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index e1992752f..d5a78abcb 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -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 ----------------- diff --git a/doc/doc-txt/README.SIEVE b/doc/doc-txt/README.SIEVE index 04383f6e5..d63bed7c9 100644 --- a/doc/doc-txt/README.SIEVE +++ b/doc/doc-txt/README.SIEVE @@ -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. diff --git a/src/src/sieve.c b/src/src/sieve.c index 2a680e175..296a23c2d 100644 --- a/src/src/sieve.c +++ b/src/src/sieve.c @@ -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")) */ - 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; serrmsg=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";