diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/src/sieve.c | 291 |
1 files changed, 83 insertions, 208 deletions
diff --git a/src/src/sieve.c b/src/src/sieve.c index 296a23c2d..32170a337 100644 --- a/src/src/sieve.c +++ b/src/src/sieve.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/sieve.c,v 1.12 2005/06/17 10:47:05 ph10 Exp $ */ +/* $Cambridge: exim/src/src/sieve.c,v 1.13 2005/08/30 10:55:52 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -311,8 +311,7 @@ while (nl>0 && hl>0) if (hc&0x80) return 0; #endif /* tolower depends on the locale and only ASCII case must be insensitive */ - if ((nc&0x80) || (hc&0x80)) { if (nc!=hc) return 0; } - else if ((nc>='A' && nc<='Z' ? nc|0x20 : nc) != (hc>='A' && hc<='Z' ? hc|0x20 : hc)) return 0; + if ((nc>='A' && nc<='Z' ? nc|0x20 : nc) != (hc>='A' && hc<='Z' ? hc|0x20 : hc)) return 0; ++n; ++h; --nl; @@ -323,7 +322,7 @@ return (match_prefix ? nl==0 : nl==0 && hl==0); /************************************************* -* Octet-wise glob pattern search * +* Glob pattern search * *************************************************/ /* @@ -333,231 +332,99 @@ Arguments: Returns: 0 needle not found in haystack 1 needle found + -1 pattern error */ -static int eq_octetglob(const struct String *needle, - const struct String *haystack) +static int eq_glob(const struct String *needle, + const struct String *haystack, int ascii_caseless) { -struct String n,h; +const uschar *n,*h,*nend,*hend; +int may_advance=0; -n=*needle; -h=*haystack; -while (n.length) +n=needle->character; +h=haystack->character; +nend=n+needle->length; +hend=h+haystack->length; +while (n<nend) { - switch (n.character[0]) - { - case '*': - { - int currentLength; - - ++n.character; - --n.length; - /* The greedy match is not yet well tested. Some day we may */ - /* need to refer to the matched parts, so the code is already */ - /* prepared for that. */ -#if 1 - /* greedy match */ - currentLength=h.length; - h.character+=h.length; - h.length=0; - while (h.length<=currentLength) - { - if (eq_octetglob(&n,&h)) return 1; - else /* go back one octet */ - { - --h.character; - ++h.length; - } - } - return 0; -#else - /* minimal match */ - while (h.length) - { - if (eq_octetglob(&n,&h)) return 1; - else /* advance one octet */ - { - ++h.character; - --h.length; - } - } - break; -#endif - } - case '?': - { - if (h.length) - { - ++h.character; - --h.length; - ++n.character; - --n.length; - } - else return 0; - break; - } - case '\\': - { - ++n.character; - --n.length; - /* FALLTHROUGH */ - } - default: - { - if - ( - h.length==0 || -#if !HAVE_ICONV - (h.character[0]&0x80) || (n.character[0]&0x80) || -#endif - h.character[0]!=n.character[0] - ) return 0; - else - { - ++h.character; - --h.length; - ++n.character; - --n.length; - }; - } + if (*n=='*') + { + ++n; + may_advance=1; } - } -return (h.length==0); -} - - -/************************************************* -* ASCII case-insensitive glob pattern search * -*************************************************/ - -/* -Arguments: - needle UTF-8 pattern to search ... - haystack ... inside the haystack - -Returns: 0 needle not found in haystack - 1 needle found -*/ - -static int eq_asciicaseglob(const struct String *needle, - const struct String *haystack) -{ -struct String n,h; + else + { + const uschar *npart,*hpart; -n=*needle; -h=*haystack; -while (n.length) - { - switch (n.character[0]) - { - case '*': - { - int currentLength; - - ++n.character; - --n.length; - /* The greedy match is not yet well tested. Some day we may */ - /* need to refer to the matched parts, so the code is already */ - /* prepared for that. */ -#if 1 - /* greedy match */ - currentLength=h.length; - h.character+=h.length; - h.length=0; - while (h.length<=currentLength) + /* Try to match a non-star part of the needle at the current */ + /* position in the haystack. */ + match_part: + npart=n; + hpart=h; + while (npart<nend && *npart!='*') switch (*npart) + { + case '?': { - if (eq_asciicaseglob(&n,&h)) return 1; - else /* go back one UTF-8 character */ + if (hpart==hend) return 0; + /* watch out: Do not match one character, but one UTF8 encoded character */ + if ((*hpart&0xc0)==0xc0) { - if (h.length==currentLength) return 0; - --h.character; - ++h.length; - if (h.character[0]&0x80) - { - while (h.length<currentLength && (*(h.character-1)&0x80)) - { - --h.character; - ++h.length; - } - } + ++hpart; + while (hpart<hend && ((*hpart&0xc0)==0x80)) ++hpart; } + else + ++hpart; + ++npart; + break; } - /* NOTREACHED */ -#else - while (h.length) + case '\\': { - if (eq_asciicaseglob(&n,&h)) return 1; - else /* advance one UTF-8 character */ - { - if (h.character[0]&0x80) - { - while (h.length && (h.character[0]&0x80)) - { - ++h.character; - --h.length; - } - } - else - { - ++h.character; - --h.length; - } - } + ++npart; + if (npart==nend) return -1; + /* FALLTHROUGH */ } - break; -#endif - } - case '?': - { - if (h.length) + default: { - ++n.character; - --n.length; - /* advance one UTF-8 character */ - if (h.character[0]&0x80) + if (hpart==hend) return 0; + /* tolower depends on the locale, but we need ASCII */ + if + ( +#if !HAVE_ICONV + (*hpart&0x80) || (*npart&0x80) || +#endif + ascii_caseless + ? ((*npart>='A' && *npart<='Z' ? *npart|0x20 : *npart) != (*hpart>='A' && *hpart<='Z' ? *hpart|0x20 : *hpart)) + : *hpart!=*npart + ) { - while (h.length && (h.character[0]&0x80)) + if (may_advance) + /* string match after a star failed, advance and try again */ { - ++h.character; - --h.length; + ++h; + goto match_part; } + else return 0; } else { - ++h.character; - --h.length; - } + ++npart; + ++hpart; + }; } - else return 0; - break; } - case '\\': - { - ++n.character; - --n.length; - /* FALLTHROUGH */ - } - default: + /* at this point, a part was matched successfully */ + if (may_advance && npart==nend && hpart<hend) + /* needle ends, but haystack does not: if there was a star before, advance and try again */ { - char nc,hc; - - if (h.length==0) return 0; - nc=n.character[0]; - hc=h.character[0]; -#if !HAVE_ICONV - if ((hc&0x80) || (nc&0x80)) return 0; -#endif - /* tolower depends on the locale and only ASCII case must be insensitive */ - if ((nc&0x80) || (hc&0x80)) { if (nc!=hc) return 0; } - else if ((nc>='A' && nc<='Z' ? nc|0x20 : nc) != (hc>='A' && hc<='Z' ? hc|0x20 : hc)) return 0; - ++h.character; - --h.length; - ++n.character; - --n.length; + ++h; + goto match_part; } + h=hpart; + n=npart; + may_advance=0; } } -return (h.length==0); +return (h==hend ? 1 : may_advance); } @@ -715,12 +582,20 @@ switch (mt) { case COMP_OCTET: { - if (eq_octetglob(needle,haystack)) r=1; + if ((r=eq_glob(needle,haystack,0))==-1) + { + filter->errmsg=CUS "syntactically invalid pattern"; + return -1; + } break; } case COMP_EN_ASCII_CASEMAP: { - if (eq_asciicaseglob(needle,haystack)) r=1; + if ((r=eq_glob(needle,haystack,1))==-1) + { + filter->errmsg=CUS "syntactically invalid pattern"; + return -1; + } break; } default: @@ -2838,12 +2713,12 @@ if (parse_start(&sieve,1,generated)==1) if (sieve.keep) { add_addr(generated,US"inbox",1,0,0,0); - msg = string_sprintf("Keep"); + msg = string_sprintf("Implicit keep"); r = FF_DELIVERED; } - else + else { - msg = string_sprintf("No keep"); + msg = string_sprintf("No implicit keep"); r = FF_DELIVERED; } } |