SPDX: license tags (mostly by guesswork)
[exim.git] / src / src / sieve.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /*
6  * Copyright (c) The Exim Maintainers 2016 - 2022
7  * Copyright (c) Michael Haardt 2003 - 2015
8  * See the file NOTICE for conditions of use and distribution.
9  * SPDX-License-Identifier: GPL-2.0-only
10  */
11
12 /* This code was contributed by Michael Haardt. */
13
14
15 /* Sieve mail filter. */
16
17 #include <ctype.h>
18 #include <errno.h>
19 #include <limits.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "exim.h"
24
25 #if HAVE_ICONV
26 # include <iconv.h>
27 #endif
28
29 /* Define this for RFC compliant \r\n end-of-line terminators.      */
30 /* Undefine it for UNIX-style \n end-of-line terminators (default). */
31 #undef RFC_EOL
32
33 /* Define this for development of the Sieve extension "encoded-character". */
34 #define ENCODED_CHARACTER
35
36 /* Define this for development of the Sieve extension "envelope-auth". */
37 #undef ENVELOPE_AUTH
38
39 /* Define this for development of the Sieve extension "enotify".    */
40 #define ENOTIFY
41
42 /* Define this for the Sieve extension "subaddress".                */
43 #define SUBADDRESS
44
45 /* Define this for the Sieve extension "vacation".                  */
46 #define VACATION
47
48 /* Must be >= 1                                                     */
49 #define VACATION_MIN_DAYS 1
50 /* Must be >= VACATION_MIN_DAYS, must be > 7, should be > 30        */
51 #define VACATION_MAX_DAYS 31
52
53 /* Keep this at 75 to accept only RFC compliant MIME words.         */
54 /* Increase it if you want to match headers from buggy MUAs.        */
55 #define MIMEWORD_LENGTH 75
56
57 struct Sieve
58   {
59   const uschar *filter;
60   const uschar *pc;
61   int line;
62   const uschar *errmsg;
63   int keep;
64   int require_envelope;
65   int require_fileinto;
66 #ifdef ENCODED_CHARACTER
67   int require_encoded_character;
68 #endif
69 #ifdef ENVELOPE_AUTH
70   int require_envelope_auth;
71 #endif
72 #ifdef ENOTIFY
73   int require_enotify;
74   struct Notification *notified;
75 #endif
76   const uschar *enotify_mailto_owner;
77 #ifdef SUBADDRESS
78   int require_subaddress;
79 #endif
80 #ifdef VACATION
81   int require_vacation;
82   int vacation_ran;
83 #endif
84   const uschar *vacation_directory;
85   const uschar *subaddress;
86   const uschar *useraddress;
87   int require_copy;
88   int require_iascii_numeric;
89   };
90
91 enum Comparator { COMP_OCTET, COMP_EN_ASCII_CASEMAP, COMP_ASCII_NUMERIC };
92 enum MatchType { MATCH_IS, MATCH_CONTAINS, MATCH_MATCHES };
93 #ifdef SUBADDRESS
94 enum AddressPart { ADDRPART_USER, ADDRPART_DETAIL, ADDRPART_LOCALPART, ADDRPART_DOMAIN, ADDRPART_ALL };
95 #else
96 enum AddressPart { ADDRPART_LOCALPART, ADDRPART_DOMAIN, ADDRPART_ALL };
97 #endif
98 enum RelOp { LT, LE, EQ, GE, GT, NE };
99
100 struct String
101   {
102   uschar *character;
103   int length;
104   };
105
106 struct Notification
107   {
108   struct String method;
109   struct String importance;
110   struct String message;
111   struct Notification *next;
112   };
113
114 /* This should be a complete list of supported extensions, so that an external
115 ManageSieve (RFC 5804) program can interrogate the current Exim binary for the
116 list of extensions and provide correct information to a client.
117
118 We'll emit the list in the order given here; keep it alphabetically sorted, so
119 that callers don't get surprised.
120
121 List *MUST* end with a NULL.  Which at least makes ifdef-vs-comma easier. */
122
123 const uschar *exim_sieve_extension_list[] = {
124   CUS"comparator-i;ascii-numeric",
125   CUS"copy",
126 #ifdef ENCODED_CHARACTER
127   CUS"encoded-character",
128 #endif
129 #ifdef ENOTIFY
130   CUS"enotify",
131 #endif
132   CUS"envelope",
133 #ifdef ENVELOPE_AUTH
134   CUS"envelope-auth",
135 #endif
136   CUS"fileinto",
137 #ifdef SUBADDRESS
138   CUS"subaddress",
139 #endif
140 #ifdef VACATION
141   CUS"vacation",
142 #endif
143   NULL
144 };
145
146 static int eq_asciicase(const struct String *needle, const struct String *haystack, int match_prefix);
147 static int parse_test(struct Sieve *filter, int *cond, int exec);
148 static int parse_commands(struct Sieve *filter, int exec, address_item **generated);
149
150 static uschar str_from_c[]="From";
151 static const struct String str_from={ str_from_c, 4 };
152 static uschar str_to_c[]="To";
153 static const struct String str_to={ str_to_c, 2 };
154 static uschar str_cc_c[]="Cc";
155 static const struct String str_cc={ str_cc_c, 2 };
156 static uschar str_bcc_c[]="Bcc";
157 static const struct String str_bcc={ str_bcc_c, 3 };
158 #ifdef ENVELOPE_AUTH
159 static uschar str_auth_c[]="auth";
160 static const struct String str_auth={ str_auth_c, 4 };
161 #endif
162 static uschar str_sender_c[]="Sender";
163 static const struct String str_sender={ str_sender_c, 6 };
164 static uschar str_resent_from_c[]="Resent-From";
165 static const struct String str_resent_from={ str_resent_from_c, 11 };
166 static uschar str_resent_to_c[]="Resent-To";
167 static const struct String str_resent_to={ str_resent_to_c, 9 };
168 static uschar str_fileinto_c[]="fileinto";
169 static const struct String str_fileinto={ str_fileinto_c, 8 };
170 static uschar str_envelope_c[]="envelope";
171 static const struct String str_envelope={ str_envelope_c, 8 };
172 #ifdef ENCODED_CHARACTER
173 static uschar str_encoded_character_c[]="encoded-character";
174 static const struct String str_encoded_character={ str_encoded_character_c, 17 };
175 #endif
176 #ifdef ENVELOPE_AUTH
177 static uschar str_envelope_auth_c[]="envelope-auth";
178 static const struct String str_envelope_auth={ str_envelope_auth_c, 13 };
179 #endif
180 #ifdef ENOTIFY
181 static uschar str_enotify_c[]="enotify";
182 static const struct String str_enotify={ str_enotify_c, 7 };
183 static uschar str_online_c[]="online";
184 static const struct String str_online={ str_online_c, 6 };
185 static uschar str_maybe_c[]="maybe";
186 static const struct String str_maybe={ str_maybe_c, 5 };
187 static uschar str_auto_submitted_c[]="Auto-Submitted";
188 static const struct String str_auto_submitted={ str_auto_submitted_c, 14 };
189 #endif
190 #ifdef SUBADDRESS
191 static uschar str_subaddress_c[]="subaddress";
192 static const struct String str_subaddress={ str_subaddress_c, 10 };
193 #endif
194 #ifdef VACATION
195 static uschar str_vacation_c[]="vacation";
196 static const struct String str_vacation={ str_vacation_c, 8 };
197 static uschar str_subject_c[]="Subject";
198 static const struct String str_subject={ str_subject_c, 7 };
199 #endif
200 static uschar str_copy_c[]="copy";
201 static const struct String str_copy={ str_copy_c, 4 };
202 static uschar str_iascii_casemap_c[]="i;ascii-casemap";
203 static const struct String str_iascii_casemap={ str_iascii_casemap_c, 15 };
204 static uschar str_enascii_casemap_c[]="en;ascii-casemap";
205 static const struct String str_enascii_casemap={ str_enascii_casemap_c, 16 };
206 static uschar str_ioctet_c[]="i;octet";
207 static const struct String str_ioctet={ str_ioctet_c, 7 };
208 static uschar str_iascii_numeric_c[]="i;ascii-numeric";
209 static const struct String str_iascii_numeric={ str_iascii_numeric_c, 15 };
210 static uschar str_comparator_iascii_casemap_c[]="comparator-i;ascii-casemap";
211 static const struct String str_comparator_iascii_casemap={ str_comparator_iascii_casemap_c, 26 };
212 static uschar str_comparator_enascii_casemap_c[]="comparator-en;ascii-casemap";
213 static const struct String str_comparator_enascii_casemap={ str_comparator_enascii_casemap_c, 27 };
214 static uschar str_comparator_ioctet_c[]="comparator-i;octet";
215 static const struct String str_comparator_ioctet={ str_comparator_ioctet_c, 18 };
216 static uschar str_comparator_iascii_numeric_c[]="comparator-i;ascii-numeric";
217 static const struct String str_comparator_iascii_numeric={ str_comparator_iascii_numeric_c, 26 };
218
219
220 /*************************************************
221 *          Encode to quoted-printable            *
222 *************************************************/
223
224 /*
225 Arguments:
226   src               UTF-8 string
227   dst               US-ASCII string
228
229 Returns
230   dst
231 */
232
233 static struct String *
234 quoted_printable_encode(const struct String *src, struct String *dst)
235 {
236 uschar *new = NULL;
237 uschar ch;
238 size_t line;
239
240 /* Two passes: one to count output allocation size, second
241 to do the encoding */
242
243 for (int pass = 0; pass <= 1; pass++)
244   {
245   line=0;
246   if (pass==0)
247     dst->length=0;
248   else
249     {
250     dst->character = store_get(dst->length+1, src->character); /* plus one for \0 */
251     new=dst->character;
252     }
253   for (const uschar * start = src->character, * end = start + src->length;
254        start < end; ++start)
255     {
256     ch=*start;
257     if (line>=73)       /* line length limit */
258       {
259       if (pass==0)
260         dst->length+=2;
261       else
262         {
263         *new++='=';     /* line split */
264         *new++='\n';
265         }
266       line=0;
267       }
268     if (  (ch>='!' && ch<='<')
269        || (ch>='>' && ch<='~')
270        || (  (ch=='\t' || ch==' ')
271           && start+2<end
272           && (*(start+1)!='\r' || *(start+2)!='\n')     /* CRLF */
273           )
274        )
275       {
276       if (pass==0)
277         ++dst->length;
278       else
279         *new++=*start;  /* copy char */
280       ++line;
281       }
282     else if (ch=='\r' && start+1<end && *(start+1)=='\n') /* CRLF */
283       {
284       if (pass==0)
285         ++dst->length;
286       else
287         *new++='\n';                                    /* NL */
288       line=0;
289       ++start;  /* consume extra input char */
290       }
291     else
292       {
293       if (pass==0)
294         dst->length+=3;
295       else
296         {               /* encoded char */
297         new += sprintf(CS new,"=%02X",ch);
298         }
299       line+=3;
300       }
301     }
302   }
303   *new='\0'; /* not included in length, but nice */
304   return dst;
305 }
306
307
308 /*************************************************
309 *     Check mail address for correct syntax      *
310 *************************************************/
311
312 /*
313 Check mail address for being syntactically correct.
314
315 Arguments:
316   filter      points to the Sieve filter including its state
317   address     String containing one address
318
319 Returns
320   1           Mail address is syntactically OK
321  -1           syntax error
322 */
323
324 int check_mail_address(struct Sieve *filter, const struct String *address)
325 {
326 int start, end, domain;
327 uschar *error,*ss;
328
329 if (address->length>0)
330   {
331   ss = parse_extract_address(address->character, &error, &start, &end, &domain,
332     FALSE);
333   if (!ss)
334     {
335     filter->errmsg=string_sprintf("malformed address \"%s\" (%s)",
336       address->character, error);
337     return -1;
338     }
339   else
340     return 1;
341   }
342 else
343   {
344   filter->errmsg=CUS "empty address";
345   return -1;
346   }
347 }
348
349
350 /*************************************************
351 *          Decode URI encoded string             *
352 *************************************************/
353
354 /*
355 Arguments:
356   str               URI encoded string
357
358 Returns
359   0                 Decoding successful
360  -1                 Encoding error
361 */
362
363 #ifdef ENOTIFY
364 static int
365 uri_decode(struct String *str)
366 {
367 uschar *s,*t,*e;
368
369 if (str->length==0) return 0;
370 for (s=str->character,t=s,e=s+str->length; s<e; )
371   if (*s=='%')
372     {
373     if (s+2<e && isxdigit(*(s+1)) && isxdigit(*(s+2)))
374       {
375       *t++=((isdigit(*(s+1)) ? *(s+1)-'0' : tolower(*(s+1))-'a'+10)<<4)
376            | (isdigit(*(s+2)) ? *(s+2)-'0' : tolower(*(s+2))-'a'+10);
377       s+=3;
378       }
379     else return -1;
380     }
381   else
382     *t++=*s++;
383
384 *t='\0';
385 str->length=t-str->character;
386 return 0;
387 }
388
389
390 /*************************************************
391 *               Parse mailto URI                 *
392 *************************************************/
393
394 /*
395 Parse mailto-URI.
396
397        mailtoURI   = "mailto:" [ to ] [ headers ]
398        to          = [ addr-spec *("%2C" addr-spec ) ]
399        headers     = "?" header *( "&" header )
400        header      = hname "=" hvalue
401        hname       = *urlc
402        hvalue      = *urlc
403
404 Arguments:
405   filter      points to the Sieve filter including its state
406   uri         URI, excluding scheme
407   recipient
408   body
409
410 Returns
411   1           URI is syntactically OK
412   0           Unknown URI scheme
413  -1           syntax error
414 */
415
416 static int
417 parse_mailto_uri(struct Sieve *filter, const uschar *uri,
418   string_item **recipient, struct String *header, struct String *subject,
419   struct String *body)
420 {
421 const uschar *start;
422 struct String to, hname;
423 struct String hvalue = {.character = NULL, .length = 0};
424 string_item *new;
425
426 if (Ustrncmp(uri,"mailto:",7))
427   {
428   filter->errmsg=US "Unknown URI scheme";
429   return 0;
430   }
431
432 uri+=7;
433 if (*uri && *uri!='?')
434   for (;;)
435     {
436     /* match to */
437     for (start=uri; *uri && *uri!='?' && (*uri!='%' || *(uri+1)!='2' || tolower(*(uri+2))!='c'); ++uri);
438     if (uri>start)
439       {
440       gstring * g = string_catn(NULL, start, uri-start);
441
442       to.character = string_from_gstring(g);
443       to.length = g->ptr;
444       if (uri_decode(&to)==-1)
445         {
446         filter->errmsg=US"Invalid URI encoding";
447         return -1;
448         }
449       new = store_get(sizeof(string_item), GET_UNTAINTED);
450       new->text = store_get(to.length+1, to.character);
451       if (to.length) memcpy(new->text, to.character, to.length);
452       new->text[to.length] = '\0';
453       new->next = *recipient;
454       *recipient = new;
455       }
456     else
457       {
458       filter->errmsg = US"Missing addr-spec in URI";
459       return -1;
460       }
461     if (*uri=='%') uri+=3;
462     else break;
463     }
464 if (*uri=='?')
465   {
466   ++uri;
467   for (;;)
468     {
469     /* match hname */
470     for (start=uri; *uri && (isalnum(*uri) || strchr("$-_.+!*'(),%",*uri)); ++uri);
471     if (uri>start)
472       {
473       gstring * g = string_catn(NULL, start, uri-start);
474
475       hname.character = string_from_gstring(g);
476       hname.length = g->ptr;
477       if (uri_decode(&hname)==-1)
478         {
479         filter->errmsg=US"Invalid URI encoding";
480         return -1;
481         }
482       }
483     /* match = */
484     if (*uri=='=')
485       ++uri;
486     else
487       {
488       filter->errmsg=US"Missing equal after hname";
489       return -1;
490       }
491     /* match hvalue */
492     for (start=uri; *uri && (isalnum(*uri) || strchr("$-_.+!*'(),%",*uri)); ++uri);
493     if (uri>start)
494       {
495       gstring * g = string_catn(NULL, start, uri-start);
496
497       hname.character = string_from_gstring(g);
498       hname.length = g->ptr;
499       if (uri_decode(&hvalue)==-1)
500         {
501         filter->errmsg=US"Invalid URI encoding";
502         return -1;
503         }
504       }
505     if (hname.length==2 && strcmpic(hname.character, US"to")==0)
506       {
507       new=store_get(sizeof(string_item), GET_UNTAINTED);
508       new->text = store_get(hvalue.length+1, hvalue.character);
509       if (hvalue.length) memcpy(new->text, hvalue.character, hvalue.length);
510       new->text[hvalue.length]='\0';
511       new->next=*recipient;
512       *recipient=new;
513       }
514     else if (hname.length==4 && strcmpic(hname.character, US"body")==0)
515       *body=hvalue;
516     else if (hname.length==7 && strcmpic(hname.character, US"subject")==0)
517       *subject=hvalue;
518     else
519       {
520       static struct String ignore[]=
521         {
522         {US"date",4},
523         {US"from",4},
524         {US"message-id",10},
525         {US"received",8},
526         {US"auto-submitted",14}
527         };
528       static struct String *end=ignore+sizeof(ignore)/sizeof(ignore[0]);
529       struct String *i;
530
531       for (i=ignore; i<end && !eq_asciicase(&hname,i,0); ++i);
532       if (i==end)
533         {
534         gstring * g;
535
536         if (header->length==-1) header->length = 0;
537
538         g = string_catn(NULL, header->character, header->length);
539         g = string_catn(g, hname.character, hname.length);
540         g = string_catn(g, CUS ": ", 2);
541         g = string_catn(g, hvalue.character, hvalue.length);
542         g = string_catn(g, CUS "\n", 1);
543
544         header->character = string_from_gstring(g);
545         header->length = g->ptr;
546         }
547       }
548     if (*uri=='&') ++uri;
549     else break;
550     }
551   }
552 if (*uri)
553   {
554   filter->errmsg=US"Syntactically invalid URI";
555   return -1;
556   }
557 return 1;
558 }
559 #endif
560
561
562 /*************************************************
563 *          Octet-wise string comparison          *
564 *************************************************/
565
566 /*
567 Arguments:
568   needle            UTF-8 string to search ...
569   haystack          ... inside the haystack
570   match_prefix      1 to compare if needle is a prefix of haystack
571
572 Returns:      0               needle not found in haystack
573               1               needle found
574 */
575
576 static int eq_octet(const struct String *needle,
577   const struct String *haystack, int match_prefix)
578 {
579 size_t nl,hl;
580 const uschar *n,*h;
581
582 nl=needle->length;
583 n=needle->character;
584 hl=haystack->length;
585 h=haystack->character;
586 while (nl>0 && hl>0)
587   {
588 #if !HAVE_ICONV
589   if (*n&0x80) return 0;
590   if (*h&0x80) return 0;
591 #endif
592   if (*n!=*h) return 0;
593   ++n;
594   ++h;
595   --nl;
596   --hl;
597   }
598 return (match_prefix ? nl==0 : nl==0 && hl==0);
599 }
600
601
602 /*************************************************
603 *    ASCII case-insensitive string comparison    *
604 *************************************************/
605
606 /*
607 Arguments:
608   needle            UTF-8 string to search ...
609   haystack          ... inside the haystack
610   match_prefix      1 to compare if needle is a prefix of haystack
611
612 Returns:      0               needle not found in haystack
613               1               needle found
614 */
615
616 static int eq_asciicase(const struct String *needle,
617   const struct String *haystack, int match_prefix)
618 {
619 size_t nl,hl;
620 const uschar *n,*h;
621 uschar nc,hc;
622
623 nl=needle->length;
624 n=needle->character;
625 hl=haystack->length;
626 h=haystack->character;
627 while (nl>0 && hl>0)
628   {
629   nc=*n;
630   hc=*h;
631 #if !HAVE_ICONV
632   if (nc&0x80) return 0;
633   if (hc&0x80) return 0;
634 #endif
635   /* tolower depends on the locale and only ASCII case must be insensitive */
636   if ((nc>='A' && nc<='Z' ? nc|0x20 : nc) != (hc>='A' && hc<='Z' ? hc|0x20 : hc)) return 0;
637   ++n;
638   ++h;
639   --nl;
640   --hl;
641   }
642 return (match_prefix ? nl==0 : nl==0 && hl==0);
643 }
644
645
646 /*************************************************
647 *              Glob pattern search               *
648 *************************************************/
649
650 /*
651 Arguments:
652   needle          pattern to search ...
653   haystack        ... inside the haystack
654   ascii_caseless  ignore ASCII case
655   match_octet     match octets, not UTF-8 multi-octet characters
656
657 Returns:      0               needle not found in haystack
658               1               needle found
659               -1              pattern error
660 */
661
662 static int eq_glob(const struct String *needle,
663   const struct String *haystack, int ascii_caseless, int match_octet)
664 {
665 const uschar *n,*h,*nend,*hend;
666 int may_advance=0;
667
668 n=needle->character;
669 h=haystack->character;
670 nend=n+needle->length;
671 hend=h+haystack->length;
672 while (n<nend)
673   {
674   if (*n=='*')
675     {
676     ++n;
677     may_advance=1;
678     }
679   else
680     {
681     const uschar *npart,*hpart;
682
683     /* Try to match a non-star part of the needle at the current */
684     /* position in the haystack.                                 */
685     match_part:
686     npart=n;
687     hpart=h;
688     while (npart<nend && *npart!='*') switch (*npart)
689       {
690       case '?':
691         {
692         if (hpart==hend) return 0;
693         if (match_octet)
694           ++hpart;
695         else
696           {
697           /* Match one UTF8 encoded character */
698           if ((*hpart&0xc0)==0xc0)
699             {
700             ++hpart;
701             while (hpart<hend && ((*hpart&0xc0)==0x80)) ++hpart;
702             }
703           else
704             ++hpart;
705           }
706         ++npart;
707         break;
708         }
709       case '\\':
710         {
711         ++npart;
712         if (npart==nend) return -1;
713         /* FALLTHROUGH */
714         }
715       default:
716         {
717         if (hpart==hend) return 0;
718         /* tolower depends on the locale, but we need ASCII */
719         if
720           (
721 #if !HAVE_ICONV
722           (*hpart&0x80) || (*npart&0x80) ||
723 #endif
724           ascii_caseless
725           ? ((*npart>='A' && *npart<='Z' ? *npart|0x20 : *npart) != (*hpart>='A' && *hpart<='Z' ? *hpart|0x20 : *hpart))
726           : *hpart!=*npart
727           )
728           {
729           if (may_advance)
730             /* string match after a star failed, advance and try again */
731             {
732             ++h;
733             goto match_part;
734             }
735           else return 0;
736           }
737         else
738           {
739           ++npart;
740           ++hpart;
741           };
742         }
743       }
744     /* at this point, a part was matched successfully */
745     if (may_advance && npart==nend && hpart<hend)
746       /* needle ends, but haystack does not: if there was a star before, advance and try again */
747       {
748       ++h;
749       goto match_part;
750       }
751     h=hpart;
752     n=npart;
753     may_advance=0;
754     }
755   }
756 return (h==hend ? 1 : may_advance);
757 }
758
759
760 /*************************************************
761 *    ASCII numeric comparison                    *
762 *************************************************/
763
764 /*
765 Arguments:
766   a                 first numeric string
767   b                 second numeric string
768   relop             relational operator
769
770 Returns:      0               not (a relop b)
771               1               a relop b
772 */
773
774 static int eq_asciinumeric(const struct String *a,
775   const struct String *b, enum RelOp relop)
776 {
777 size_t al,bl;
778 const uschar *as,*aend,*bs,*bend;
779 int cmp;
780
781 as=a->character;
782 aend=a->character+a->length;
783 bs=b->character;
784 bend=b->character+b->length;
785
786 while (*as>='0' && *as<='9' && as<aend) ++as;
787 al=as-a->character;
788 while (*bs>='0' && *bs<='9' && bs<bend) ++bs;
789 bl=bs-b->character;
790
791 if (al && bl==0) cmp=-1;
792 else if (al==0 && bl==0) cmp=0;
793 else if (al==0 && bl) cmp=1;
794 else
795   {
796   cmp=al-bl;
797   if (cmp==0) cmp=memcmp(a->character,b->character,al);
798   }
799 switch (relop)
800   {
801   case LT: return cmp<0;
802   case LE: return cmp<=0;
803   case EQ: return cmp==0;
804   case GE: return cmp>=0;
805   case GT: return cmp>0;
806   case NE: return cmp!=0;
807   }
808   /*NOTREACHED*/
809   return -1;
810 }
811
812
813 /*************************************************
814 *             Compare strings                    *
815 *************************************************/
816
817 /*
818 Arguments:
819   filter      points to the Sieve filter including its state
820   needle      UTF-8 pattern or string to search ...
821   haystack    ... inside the haystack
822   co          comparator to use
823   mt          match type to use
824
825 Returns:      0               needle not found in haystack
826               1               needle found
827               -1              comparator does not offer matchtype
828 */
829
830 static int compare(struct Sieve *filter, const struct String *needle, const struct String *haystack,
831   enum Comparator co, enum MatchType mt)
832 {
833 int r=0;
834
835 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
836   (debug_selector & D_filter) != 0)
837   {
838   debug_printf("String comparison (match ");
839   switch (mt)
840     {
841     case MATCH_IS: debug_printf(":is"); break;
842     case MATCH_CONTAINS: debug_printf(":contains"); break;
843     case MATCH_MATCHES: debug_printf(":matches"); break;
844     }
845   debug_printf(", comparison \"");
846   switch (co)
847     {
848     case COMP_OCTET: debug_printf("i;octet"); break;
849     case COMP_EN_ASCII_CASEMAP: debug_printf("en;ascii-casemap"); break;
850     case COMP_ASCII_NUMERIC: debug_printf("i;ascii-numeric"); break;
851     }
852   debug_printf("\"):\n");
853   debug_printf("  Search = %s (%d chars)\n", needle->character,needle->length);
854   debug_printf("  Inside = %s (%d chars)\n", haystack->character,haystack->length);
855   }
856 switch (mt)
857   {
858   case MATCH_IS:
859     switch (co)
860       {
861       case COMP_OCTET:
862         if (eq_octet(needle,haystack,0)) r=1;
863         break;
864       case COMP_EN_ASCII_CASEMAP:
865         if (eq_asciicase(needle,haystack,0)) r=1;
866         break;
867       case COMP_ASCII_NUMERIC:
868         if (!filter->require_iascii_numeric)
869           {
870           filter->errmsg=CUS "missing previous require \"comparator-i;ascii-numeric\";";
871           return -1;
872           }
873         if (eq_asciinumeric(needle,haystack,EQ)) r=1;
874         break;
875       }
876     break;
877
878   case MATCH_CONTAINS:
879     {
880     struct String h;
881
882     switch (co)
883       {
884       case COMP_OCTET:
885         for (h = *haystack; h.length; ++h.character,--h.length)
886          if (eq_octet(needle,&h,1)) { r=1; break; }
887         break;
888       case COMP_EN_ASCII_CASEMAP:
889         for (h = *haystack; h.length; ++h.character, --h.length)
890           if (eq_asciicase(needle,&h,1)) { r=1; break; }
891         break;
892       default:
893         filter->errmsg=CUS "comparator does not offer specified matchtype";
894         return -1;
895       }
896     break;
897     }
898
899   case MATCH_MATCHES:
900     switch (co)
901       {
902       case COMP_OCTET:
903         if ((r=eq_glob(needle,haystack,0,1))==-1)
904           {
905           filter->errmsg=CUS "syntactically invalid pattern";
906           return -1;
907           }
908         break;
909       case COMP_EN_ASCII_CASEMAP:
910         if ((r=eq_glob(needle,haystack,1,1))==-1)
911           {
912           filter->errmsg=CUS "syntactically invalid pattern";
913           return -1;
914           }
915         break;
916       default:
917         filter->errmsg=CUS "comparator does not offer specified matchtype";
918         return -1;
919       }
920     break;
921   }
922 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
923   (debug_selector & D_filter) != 0)
924   debug_printf("  Result %s\n",r?"true":"false");
925 return r;
926 }
927
928
929 /*************************************************
930 *         Check header field syntax              *
931 *************************************************/
932
933 /*
934 RFC 2822, section 3.6.8 says:
935
936   field-name      =       1*ftext
937
938   ftext           =       %d33-57 /               ; Any character except
939                           %d59-126                ;  controls, SP, and
940                                                   ;  ":".
941
942 That forbids 8-bit header fields.  This implementation accepts them, since
943 all of Exim is 8-bit clean, so it adds %d128-%d255.
944
945 Arguments:
946   header      header field to quote for suitable use in Exim expansions
947
948 Returns:      0               string is not a valid header field
949               1               string is a value header field
950 */
951
952 static int is_header(const struct String *header)
953 {
954 size_t l;
955 const uschar *h;
956
957 l=header->length;
958 h=header->character;
959 if (l==0) return 0;
960 while (l)
961   {
962   if (((unsigned char)*h)<33 || ((unsigned char)*h)==':' || ((unsigned char)*h)==127) return 0;
963   else
964     {
965     ++h;
966     --l;
967     }
968   }
969 return 1;
970 }
971
972
973 /*************************************************
974 *       Quote special characters string          *
975 *************************************************/
976
977 /*
978 Arguments:
979   header      header field to quote for suitable use in Exim expansions
980               or as debug output
981
982 Returns:      quoted string
983 */
984
985 static const uschar *
986 quote(const struct String *header)
987 {
988 gstring * quoted = NULL;
989 size_t l;
990 const uschar *h;
991
992 l=header->length;
993 h=header->character;
994 while (l)
995   {
996   switch (*h)
997     {
998     case '\0':
999       quoted = string_catn(quoted, CUS "\\0", 2);
1000       break;
1001     case '$':
1002     case '{':
1003     case '}':
1004       quoted = string_catn(quoted, CUS "\\", 1);
1005     default:
1006       quoted = string_catn(quoted, h, 1);
1007     }
1008   ++h;
1009   --l;
1010   }
1011 quoted = string_catn(quoted, CUS "", 1);
1012 return string_from_gstring(quoted);
1013 }
1014
1015
1016 /*************************************************
1017 *   Add address to list of generated addresses   *
1018 *************************************************/
1019
1020 /*
1021 According to RFC 5228, duplicate delivery to the same address must
1022 not happen, so the list is first searched for the address.
1023
1024 Arguments:
1025   generated   list of generated addresses
1026   addr        new address to add
1027   file        address denotes a file
1028
1029 Returns:      nothing
1030 */
1031
1032 static void
1033 add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage)
1034 {
1035 address_item *new_addr;
1036
1037 for (new_addr = *generated; new_addr; new_addr = new_addr->next)
1038   if (  Ustrcmp(new_addr->address,addr) == 0
1039      && (  !file
1040         || testflag(new_addr, af_pfr)
1041         || testflag(new_addr, af_file)
1042         )
1043      )
1044     {
1045     if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
1046       debug_printf("Repeated %s `%s' ignored.\n",file ? "fileinto" : "redirect", addr);
1047
1048     return;
1049     }
1050
1051 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
1052   debug_printf("%s `%s'\n",file ? "fileinto" : "redirect", addr);
1053
1054 new_addr = deliver_make_addr(addr,TRUE);
1055 if (file)
1056   {
1057   setflag(new_addr, af_pfr);
1058   setflag(new_addr, af_file);
1059   new_addr->mode = 0;
1060   }
1061 new_addr->prop.errors_address = NULL;
1062 new_addr->next = *generated;
1063 *generated = new_addr;
1064 }
1065
1066
1067 /*************************************************
1068 *         Return decoded header field            *
1069 *************************************************/
1070
1071 /*
1072 Unfold the header field as described in RFC 2822 and remove all
1073 leading and trailing white space, then perform MIME decoding and
1074 translate the header field to UTF-8.
1075
1076 Arguments:
1077   value       returned value of the field
1078   header      name of the header field
1079
1080 Returns:      nothing          The expanded string is empty
1081                                in case there is no such header
1082 */
1083
1084 static void expand_header(struct String *value, const struct String *header)
1085 {
1086 uschar *s,*r,*t;
1087 uschar *errmsg;
1088
1089 value->length=0;
1090 value->character=(uschar*)0;
1091
1092 t = r = s = expand_string(string_sprintf("$rheader_%s",quote(header)));
1093 if (!t) return;
1094 while (*r==' ' || *r=='\t') ++r;
1095 while (*r)
1096   {
1097   if (*r=='\n')
1098     ++r;
1099   else
1100     *t++=*r++;
1101   }
1102 while (t>s && (*(t-1)==' ' || *(t-1)=='\t')) --t;
1103 *t='\0';
1104 value->character=rfc2047_decode(s,check_rfc2047_length,US"utf-8",'\0',&value->length,&errmsg);
1105 }
1106
1107
1108 /*************************************************
1109 *        Parse remaining hash comment            *
1110 *************************************************/
1111
1112 /*
1113 Token definition:
1114   Comment up to terminating CRLF
1115
1116 Arguments:
1117   filter      points to the Sieve filter including its state
1118
1119 Returns:      1                success
1120               -1               syntax error
1121 */
1122
1123 static int parse_hashcomment(struct Sieve *filter)
1124 {
1125 ++filter->pc;
1126 while (*filter->pc)
1127   {
1128 #ifdef RFC_EOL
1129   if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1130 #else
1131   if (*filter->pc=='\n')
1132 #endif
1133     {
1134 #ifdef RFC_EOL
1135     filter->pc+=2;
1136 #else
1137     ++filter->pc;
1138 #endif
1139     ++filter->line;
1140     return 1;
1141     }
1142   else ++filter->pc;
1143   }
1144 filter->errmsg=CUS "missing end of comment";
1145 return -1;
1146 }
1147
1148
1149 /*************************************************
1150 *       Parse remaining C-style comment          *
1151 *************************************************/
1152
1153 /*
1154 Token definition:
1155   Everything up to star slash
1156
1157 Arguments:
1158   filter      points to the Sieve filter including its state
1159
1160 Returns:      1                success
1161               -1               syntax error
1162 */
1163
1164 static int parse_comment(struct Sieve *filter)
1165 {
1166   filter->pc+=2;
1167   while (*filter->pc)
1168   {
1169     if (*filter->pc=='*' && *(filter->pc+1)=='/')
1170     {
1171       filter->pc+=2;
1172       return 1;
1173     }
1174     else ++filter->pc;
1175   }
1176   filter->errmsg=CUS "missing end of comment";
1177   return -1;
1178 }
1179
1180
1181 /*************************************************
1182 *         Parse optional white space             *
1183 *************************************************/
1184
1185 /*
1186 Token definition:
1187   Spaces, tabs, CRLFs, hash comments or C-style comments
1188
1189 Arguments:
1190   filter      points to the Sieve filter including its state
1191
1192 Returns:      1                success
1193               -1               syntax error
1194 */
1195
1196 static int parse_white(struct Sieve *filter)
1197 {
1198 while (*filter->pc)
1199   {
1200   if (*filter->pc==' ' || *filter->pc=='\t') ++filter->pc;
1201 #ifdef RFC_EOL
1202   else if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1203 #else
1204   else if (*filter->pc=='\n')
1205 #endif
1206     {
1207 #ifdef RFC_EOL
1208     filter->pc+=2;
1209 #else
1210     ++filter->pc;
1211 #endif
1212     ++filter->line;
1213     }
1214   else if (*filter->pc=='#')
1215     {
1216     if (parse_hashcomment(filter)==-1) return -1;
1217     }
1218   else if (*filter->pc=='/' && *(filter->pc+1)=='*')
1219     {
1220     if (parse_comment(filter)==-1) return -1;
1221     }
1222   else break;
1223   }
1224 return 1;
1225 }
1226
1227
1228 #ifdef ENCODED_CHARACTER
1229 /*************************************************
1230 *      Decode hex-encoded-character string       *
1231 *************************************************/
1232
1233 /*
1234 Encoding definition:
1235    blank                = SP / TAB / CRLF
1236    hex-pair-seq         = *blank hex-pair *(1*blank hex-pair) *blank
1237    hex-pair             = 1*2HEXDIG
1238
1239 Arguments:
1240   src         points to a hex-pair-seq
1241   end         points to its end
1242   dst         points to the destination of the decoded octets,
1243               optionally to (uschar*)0 for checking only
1244
1245 Returns:      >=0              number of decoded octets
1246               -1               syntax error
1247 */
1248
1249 static int hex_decode(uschar *src, uschar *end, uschar *dst)
1250 {
1251 int decoded=0;
1252
1253 while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1254 do
1255   {
1256   int x,d,n;
1257
1258   for (x = 0, d = 0;
1259       d<2 && src<end && isxdigit(n=tolower(*src));
1260       x=(x<<4)|(n>='0' && n<='9' ? n-'0' : 10+(n-'a')) ,++d, ++src) ;
1261   if (d==0) return -1;
1262   if (dst) *dst++=x;
1263   ++decoded;
1264   if (src==end) return decoded;
1265   if (*src==' ' || *src=='\t' || *src=='\n')
1266     while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1267   else
1268     return -1;
1269   }
1270 while (src<end);
1271 return decoded;
1272 }
1273
1274
1275 /*************************************************
1276 *    Decode unicode-encoded-character string     *
1277 *************************************************/
1278
1279 /*
1280 Encoding definition:
1281    blank                = SP / TAB / CRLF
1282    unicode-hex-seq      = *blank unicode-hex *(blank unicode-hex) *blank
1283    unicode-hex          = 1*HEXDIG
1284
1285    It is an error for a script to use a hexadecimal value that isn't in
1286    either the range 0 to D7FF or the range E000 to 10FFFF.
1287
1288    At this time, strings are already scanned, thus the CRLF is converted
1289    to the internally used \n (should RFC_EOL have been used).
1290
1291 Arguments:
1292   src         points to a unicode-hex-seq
1293   end         points to its end
1294   dst         points to the destination of the decoded octets,
1295               optionally to (uschar*)0 for checking only
1296
1297 Returns:      >=0              number of decoded octets
1298               -1               syntax error
1299               -2               semantic error (character range violation)
1300 */
1301
1302 static int
1303 unicode_decode(uschar *src, uschar *end, uschar *dst)
1304 {
1305 int decoded=0;
1306
1307 while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1308 do
1309   {
1310   uschar *hex_seq;
1311   int c,d,n;
1312
1313   unicode_hex:
1314   for (hex_seq = src; src < end && *src=='0'; ) src++;
1315   for (c = 0, d = 0;
1316        d < 7 && src < end && isxdigit(n=tolower(*src));
1317        c=(c<<4)|(n>='0' && n<='9' ? n-'0' : 10+(n-'a')), ++d, ++src) ;
1318   if (src == hex_seq) return -1;
1319   if (d==7 || (!((c>=0 && c<=0xd7ff) || (c>=0xe000 && c<=0x10ffff)))) return -2;
1320   if (c<128)
1321     {
1322     if (dst) *dst++=c;
1323     ++decoded;
1324     }
1325   else if (c>=0x80 && c<=0x7ff)
1326     {
1327       if (dst)
1328         {
1329         *dst++=192+(c>>6);
1330         *dst++=128+(c&0x3f);
1331         }
1332       decoded+=2;
1333     }
1334   else if (c>=0x800 && c<=0xffff)
1335     {
1336       if (dst)
1337         {
1338         *dst++=224+(c>>12);
1339         *dst++=128+((c>>6)&0x3f);
1340         *dst++=128+(c&0x3f);
1341         }
1342       decoded+=3;
1343     }
1344   else if (c>=0x10000 && c<=0x1fffff)
1345     {
1346       if (dst)
1347         {
1348         *dst++=240+(c>>18);
1349         *dst++=128+((c>>10)&0x3f);
1350         *dst++=128+((c>>6)&0x3f);
1351         *dst++=128+(c&0x3f);
1352         }
1353       decoded+=4;
1354     }
1355   if (*src==' ' || *src=='\t' || *src=='\n')
1356     {
1357     while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1358     if (src==end) return decoded;
1359     goto unicode_hex;
1360     }
1361   }
1362 while (src<end);
1363 return decoded;
1364 }
1365
1366
1367 /*************************************************
1368 *       Decode encoded-character string          *
1369 *************************************************/
1370
1371 /*
1372 Encoding definition:
1373    encoded-arb-octets   = "${hex:" hex-pair-seq "}"
1374    encoded-unicode-char = "${unicode:" unicode-hex-seq "}"
1375
1376 Arguments:
1377   encoded     points to an encoded string, returns decoded string
1378   filter      points to the Sieve filter including its state
1379
1380 Returns:      1                success
1381               -1               syntax error
1382 */
1383
1384 static int string_decode(struct Sieve *filter, struct String *data)
1385 {
1386 uschar *src,*dst,*end;
1387
1388 src=data->character;
1389 dst=src;
1390 end=data->character+data->length;
1391 while (src<end)
1392   {
1393   uschar *brace;
1394
1395   if (
1396       strncmpic(src,US "${hex:",6)==0
1397       && (brace=Ustrchr(src+6,'}'))!=(uschar*)0
1398       && (hex_decode(src+6,brace,(uschar*)0))>=0
1399      )
1400     {
1401     dst+=hex_decode(src+6,brace,dst);
1402     src=brace+1;
1403     }
1404   else if (
1405            strncmpic(src,US "${unicode:",10)==0
1406            && (brace=Ustrchr(src+10,'}'))!=(uschar*)0
1407           )
1408     {
1409     switch (unicode_decode(src+10,brace,(uschar*)0))
1410       {
1411       case -2:
1412         {
1413         filter->errmsg=CUS "unicode character out of range";
1414         return -1;
1415         }
1416       case -1:
1417         {
1418         *dst++=*src++;
1419         break;
1420         }
1421       default:
1422         {
1423         dst+=unicode_decode(src+10,brace,dst);
1424         src=brace+1;
1425         }
1426       }
1427     }
1428   else *dst++=*src++;
1429   }
1430   data->length=dst-data->character;
1431   *dst='\0';
1432 return 1;
1433 }
1434 #endif
1435
1436
1437 /*************************************************
1438 *          Parse an optional string              *
1439 *************************************************/
1440
1441 /*
1442 Token definition:
1443    quoted-string = DQUOTE *CHAR DQUOTE
1444            ;; in general, \ CHAR inside a string maps to CHAR
1445            ;; so \" maps to " and \\ maps to \
1446            ;; note that newlines and other characters are all allowed
1447            ;; in strings
1448
1449    multi-line          = "text:" *(SP / HTAB) (hash-comment / CRLF)
1450                          *(multi-line-literal / multi-line-dotstuff)
1451                          "." CRLF
1452    multi-line-literal  = [CHAR-NOT-DOT *CHAR-NOT-CRLF] CRLF
1453    multi-line-dotstuff = "." 1*CHAR-NOT-CRLF CRLF
1454            ;; A line containing only "." ends the multi-line.
1455            ;; Remove a leading '.' if followed by another '.'.
1456   string           = quoted-string / multi-line
1457
1458 Arguments:
1459   filter      points to the Sieve filter including its state
1460   id          specifies identifier to match
1461
1462 Returns:      1                success
1463               -1               syntax error
1464               0                identifier not matched
1465 */
1466
1467 static int
1468 parse_string(struct Sieve *filter, struct String *data)
1469 {
1470 gstring * g = NULL;
1471
1472 data->length = 0;
1473 data->character = NULL;
1474
1475 if (*filter->pc=='"') /* quoted string */
1476   {
1477   ++filter->pc;
1478   while (*filter->pc)
1479     {
1480     if (*filter->pc=='"') /* end of string */
1481       {
1482       ++filter->pc;
1483
1484       if (g)
1485         {
1486         data->character = string_from_gstring(g);
1487         data->length = g->ptr;
1488         }
1489       else
1490         data->character = US"\0";
1491       /* that way, there will be at least one character allocated */
1492
1493 #ifdef ENCODED_CHARACTER
1494       if (filter->require_encoded_character
1495           && string_decode(filter,data)==-1)
1496         return -1;
1497 #endif
1498       return 1;
1499       }
1500     else if (*filter->pc=='\\' && *(filter->pc+1)) /* quoted character */
1501       {
1502       g = string_catn(g, filter->pc+1, 1);
1503       filter->pc+=2;
1504       }
1505     else /* regular character */
1506       {
1507 #ifdef RFC_EOL
1508       if (*filter->pc=='\r' && *(filter->pc+1)=='\n') ++filter->line;
1509 #else
1510       if (*filter->pc=='\n')
1511         {
1512         g = string_catn(g, US"\r", 1);
1513         ++filter->line;
1514         }
1515 #endif
1516       g = string_catn(g, filter->pc, 1);
1517       filter->pc++;
1518       }
1519     }
1520   filter->errmsg=CUS "missing end of string";
1521   return -1;
1522   }
1523 else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */
1524   {
1525   filter->pc+=5;
1526   /* skip optional white space followed by hashed comment or CRLF */
1527   while (*filter->pc==' ' || *filter->pc=='\t') ++filter->pc;
1528   if (*filter->pc=='#')
1529     {
1530     if (parse_hashcomment(filter)==-1) return -1;
1531     }
1532 #ifdef RFC_EOL
1533   else if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1534 #else
1535   else if (*filter->pc=='\n')
1536 #endif
1537     {
1538 #ifdef RFC_EOL
1539     filter->pc+=2;
1540 #else
1541     ++filter->pc;
1542 #endif
1543     ++filter->line;
1544     }
1545   else
1546     {
1547     filter->errmsg=CUS "syntax error";
1548     return -1;
1549     }
1550   while (*filter->pc)
1551     {
1552 #ifdef RFC_EOL
1553     if (*filter->pc=='\r' && *(filter->pc+1)=='\n') /* end of line */
1554 #else
1555     if (*filter->pc=='\n') /* end of line */
1556 #endif
1557       {
1558       g = string_catn(g, CUS "\r\n", 2);
1559 #ifdef RFC_EOL
1560       filter->pc+=2;
1561 #else
1562       ++filter->pc;
1563 #endif
1564       ++filter->line;
1565 #ifdef RFC_EOL
1566       if (*filter->pc=='.' && *(filter->pc+1)=='\r' && *(filter->pc+2)=='\n') /* end of string */
1567 #else
1568       if (*filter->pc=='.' && *(filter->pc+1)=='\n') /* end of string */
1569 #endif
1570         {
1571         if (g)
1572           {
1573           data->character = string_from_gstring(g);
1574           data->length = g->ptr;
1575           }
1576         else
1577           data->character = US"\0";
1578         /* that way, there will be at least one character allocated */
1579
1580 #ifdef RFC_EOL
1581         filter->pc+=3;
1582 #else
1583         filter->pc+=2;
1584 #endif
1585         ++filter->line;
1586 #ifdef ENCODED_CHARACTER
1587         if (filter->require_encoded_character
1588             && string_decode(filter,data)==-1)
1589           return -1;
1590 #endif
1591         return 1;
1592         }
1593       else if (*filter->pc=='.' && *(filter->pc+1)=='.') /* remove dot stuffing */
1594         {
1595         g = string_catn(g, CUS ".", 1);
1596         filter->pc+=2;
1597         }
1598       }
1599     else /* regular character */
1600       {
1601       g = string_catn(g, filter->pc, 1);
1602       filter->pc++;
1603       }
1604     }
1605   filter->errmsg=CUS "missing end of multi line string";
1606   return -1;
1607   }
1608 else return 0;
1609 }
1610
1611
1612 /*************************************************
1613 *          Parse a specific identifier           *
1614 *************************************************/
1615
1616 /*
1617 Token definition:
1618   identifier       = (ALPHA / "_") *(ALPHA DIGIT "_")
1619
1620 Arguments:
1621   filter      points to the Sieve filter including its state
1622   id          specifies identifier to match
1623
1624 Returns:      1                success
1625               0                identifier not matched
1626 */
1627
1628 static int parse_identifier(struct Sieve *filter, const uschar *id)
1629 {
1630   size_t idlen=Ustrlen(id);
1631
1632   if (strncmpic(US filter->pc,US id,idlen)==0)
1633   {
1634     uschar next=filter->pc[idlen];
1635
1636     if ((next>='A' && next<='Z') || (next>='a' && next<='z') || next=='_' || (next>='0' && next<='9')) return 0;
1637     filter->pc+=idlen;
1638     return 1;
1639   }
1640   else return 0;
1641 }
1642
1643
1644 /*************************************************
1645 *                 Parse a number                 *
1646 *************************************************/
1647
1648 /*
1649 Token definition:
1650   number           = 1*DIGIT [QUANTIFIER]
1651   QUANTIFIER       = "K" / "M" / "G"
1652
1653 Arguments:
1654   filter      points to the Sieve filter including its state
1655   data        returns value
1656
1657 Returns:      1                success
1658               -1               no string list found
1659 */
1660
1661 static int parse_number(struct Sieve *filter, unsigned long *data)
1662 {
1663 unsigned long d,u;
1664
1665 if (*filter->pc>='0' && *filter->pc<='9')
1666   {
1667   uschar *e;
1668
1669   errno=0;
1670   d=Ustrtoul(filter->pc,&e,10);
1671   if (errno==ERANGE)
1672     {
1673     filter->errmsg=CUstrerror(ERANGE);
1674     return -1;
1675     }
1676   filter->pc=e;
1677   u=1;
1678   if (*filter->pc=='K') { u=1024; ++filter->pc; }
1679   else if (*filter->pc=='M') { u=1024*1024; ++filter->pc; }
1680   else if (*filter->pc=='G') { u=1024*1024*1024; ++filter->pc; }
1681   if (d>(ULONG_MAX/u))
1682     {
1683     filter->errmsg=CUstrerror(ERANGE);
1684     return -1;
1685     }
1686   d*=u;
1687   *data=d;
1688   return 1;
1689   }
1690 else
1691   {
1692   filter->errmsg=CUS "missing number";
1693   return -1;
1694   }
1695 }
1696
1697
1698 /*************************************************
1699 *              Parse a string list               *
1700 *************************************************/
1701
1702 /*
1703 Grammar:
1704   string-list      = "[" string *("," string) "]" / string
1705
1706 Arguments:
1707   filter      points to the Sieve filter including its state
1708   data        returns string list
1709
1710 Returns:      1                success
1711               -1               no string list found
1712 */
1713
1714 static int
1715 parse_stringlist(struct Sieve *filter, struct String **data)
1716 {
1717 const uschar *orig=filter->pc;
1718 int dataCapacity = 0;
1719 int dataLength = 0;
1720 struct String *d = NULL;
1721 int m;
1722
1723 if (*filter->pc=='[') /* string list */
1724   {
1725   ++filter->pc;
1726   for (;;)
1727     {
1728     if (parse_white(filter)==-1) goto error;
1729     if (dataLength+1 >= dataCapacity) /* increase buffer */
1730       {
1731       struct String *new;
1732
1733       dataCapacity = dataCapacity ? dataCapacity * 2 : 4;
1734       new = store_get(sizeof(struct String) * dataCapacity, GET_UNTAINTED);
1735
1736       if (d) memcpy(new,d,sizeof(struct String)*dataLength);
1737       d = new;
1738       }
1739
1740     m=parse_string(filter,&d[dataLength]);
1741     if (m==0)
1742       {
1743       if (dataLength==0) break;
1744       else
1745         {
1746         filter->errmsg=CUS "missing string";
1747         goto error;
1748         }
1749       }
1750     else if (m==-1) goto error;
1751     else ++dataLength;
1752     if (parse_white(filter)==-1) goto error;
1753     if (*filter->pc==',') ++filter->pc;
1754     else break;
1755     }
1756   if (*filter->pc==']')
1757     {
1758     d[dataLength].character=(uschar*)0;
1759     d[dataLength].length=-1;
1760     ++filter->pc;
1761     *data=d;
1762     return 1;
1763     }
1764   else
1765     {
1766     filter->errmsg=CUS "missing closing bracket";
1767     goto error;
1768     }
1769   }
1770 else /* single string */
1771   {
1772   if (!(d=store_get(sizeof(struct String)*2, GET_UNTAINTED)))
1773     return -1;
1774
1775   m=parse_string(filter,&d[0]);
1776   if (m==-1)
1777     return -1;
1778
1779   else if (m==0)
1780     {
1781     filter->pc=orig;
1782     return 0;
1783     }
1784   else
1785     {
1786     d[1].character=(uschar*)0;
1787     d[1].length=-1;
1788     *data=d;
1789     return 1;
1790     }
1791   }
1792 error:
1793 filter->errmsg=CUS "missing string list";
1794 return -1;
1795 }
1796
1797
1798 /*************************************************
1799 *    Parse an optional address part specifier    *
1800 *************************************************/
1801
1802 /*
1803 Grammar:
1804   address-part     =  ":localpart" / ":domain" / ":all"
1805   address-part     =/ ":user" / ":detail"
1806
1807 Arguments:
1808   filter      points to the Sieve filter including its state
1809   a           returns address part specified
1810
1811 Returns:      1                success
1812               0                no comparator found
1813               -1               syntax error
1814 */
1815
1816 static int parse_addresspart(struct Sieve *filter, enum AddressPart *a)
1817 {
1818 #ifdef SUBADDRESS
1819 if (parse_identifier(filter,CUS ":user")==1)
1820   {
1821   if (!filter->require_subaddress)
1822     {
1823     filter->errmsg=CUS "missing previous require \"subaddress\";";
1824     return -1;
1825     }
1826   *a=ADDRPART_USER;
1827   return 1;
1828   }
1829 else if (parse_identifier(filter,CUS ":detail")==1)
1830   {
1831   if (!filter->require_subaddress)
1832     {
1833     filter->errmsg=CUS "missing previous require \"subaddress\";";
1834     return -1;
1835     }
1836   *a=ADDRPART_DETAIL;
1837   return 1;
1838   }
1839 else
1840 #endif
1841 if (parse_identifier(filter,CUS ":localpart")==1)
1842   {
1843   *a=ADDRPART_LOCALPART;
1844   return 1;
1845   }
1846 else if (parse_identifier(filter,CUS ":domain")==1)
1847   {
1848   *a=ADDRPART_DOMAIN;
1849   return 1;
1850   }
1851 else if (parse_identifier(filter,CUS ":all")==1)
1852   {
1853   *a=ADDRPART_ALL;
1854   return 1;
1855   }
1856 else return 0;
1857 }
1858
1859
1860 /*************************************************
1861 *         Parse an optional comparator           *
1862 *************************************************/
1863
1864 /*
1865 Grammar:
1866   comparator = ":comparator" <comparator-name: string>
1867
1868 Arguments:
1869   filter      points to the Sieve filter including its state
1870   c           returns comparator
1871
1872 Returns:      1                success
1873               0                no comparator found
1874               -1               incomplete comparator found
1875 */
1876
1877 static int parse_comparator(struct Sieve *filter, enum Comparator *c)
1878 {
1879 struct String comparator_name;
1880
1881 if (parse_identifier(filter,CUS ":comparator")==0) return 0;
1882 if (parse_white(filter)==-1) return -1;
1883 switch (parse_string(filter,&comparator_name))
1884   {
1885   case -1: return -1;
1886   case 0:
1887     {
1888     filter->errmsg=CUS "missing comparator";
1889     return -1;
1890     }
1891   default:
1892     {
1893     int match;
1894
1895     if (eq_asciicase(&comparator_name,&str_ioctet,0))
1896       {
1897       *c=COMP_OCTET;
1898       match=1;
1899       }
1900     else if (eq_asciicase(&comparator_name,&str_iascii_casemap,0))
1901       {
1902       *c=COMP_EN_ASCII_CASEMAP;
1903       match=1;
1904       }
1905     else if (eq_asciicase(&comparator_name,&str_enascii_casemap,0))
1906       {
1907       *c=COMP_EN_ASCII_CASEMAP;
1908       match=1;
1909       }
1910     else if (eq_asciicase(&comparator_name,&str_iascii_numeric,0))
1911       {
1912       *c=COMP_ASCII_NUMERIC;
1913       match=1;
1914       }
1915     else
1916       {
1917       filter->errmsg=CUS "invalid comparator";
1918       match=-1;
1919       }
1920     return match;
1921     }
1922   }
1923 }
1924
1925
1926 /*************************************************
1927 *          Parse an optional match type          *
1928 *************************************************/
1929
1930 /*
1931 Grammar:
1932   match-type = ":is" / ":contains" / ":matches"
1933
1934 Arguments:
1935   filter      points to the Sieve filter including its state
1936   m           returns match type
1937
1938 Returns:      1                success
1939               0                no match type found
1940 */
1941
1942 static int parse_matchtype(struct Sieve *filter, enum MatchType *m)
1943 {
1944   if (parse_identifier(filter,CUS ":is")==1)
1945   {
1946     *m=MATCH_IS;
1947     return 1;
1948   }
1949   else if (parse_identifier(filter,CUS ":contains")==1)
1950   {
1951     *m=MATCH_CONTAINS;
1952     return 1;
1953   }
1954   else if (parse_identifier(filter,CUS ":matches")==1)
1955   {
1956     *m=MATCH_MATCHES;
1957     return 1;
1958   }
1959   else return 0;
1960 }
1961
1962
1963 /*************************************************
1964 *   Parse and interpret an optional test list    *
1965 *************************************************/
1966
1967 /*
1968 Grammar:
1969   test-list = "(" test *("," test) ")"
1970
1971 Arguments:
1972   filter      points to the Sieve filter including its state
1973   n           total number of tests
1974   num_true    number of passed tests
1975   exec        Execute parsed statements
1976
1977 Returns:      1                success
1978               0                no test list found
1979               -1               syntax or execution error
1980 */
1981
1982 static int parse_testlist(struct Sieve *filter, int *n, int *num_true, int exec)
1983 {
1984 if (parse_white(filter)==-1) return -1;
1985 if (*filter->pc=='(')
1986   {
1987   ++filter->pc;
1988   *n=0;
1989    *num_true=0;
1990   for (;;)
1991     {
1992     int cond;
1993
1994     switch (parse_test(filter,&cond,exec))
1995       {
1996       case -1: return -1;
1997       case 0: filter->errmsg=CUS "missing test"; return -1;
1998       default: ++*n; if (cond) ++*num_true; break;
1999       }
2000     if (parse_white(filter)==-1) return -1;
2001     if (*filter->pc==',') ++filter->pc;
2002     else break;
2003     }
2004   if (*filter->pc==')')
2005     {
2006     ++filter->pc;
2007     return 1;
2008     }
2009   else
2010     {
2011     filter->errmsg=CUS "missing closing paren";
2012     return -1;
2013     }
2014   }
2015 else return 0;
2016 }
2017
2018
2019 /*************************************************
2020 *     Parse and interpret an optional test       *
2021 *************************************************/
2022
2023 /*
2024 Arguments:
2025   filter      points to the Sieve filter including its state
2026   cond        returned condition status
2027   exec        Execute parsed statements
2028
2029 Returns:      1                success
2030               0                no test found
2031               -1               syntax or execution error
2032 */
2033
2034 static int
2035 parse_test(struct Sieve *filter, int *cond, int exec)
2036 {
2037 if (parse_white(filter)==-1) return -1;
2038 if (parse_identifier(filter,CUS "address"))
2039   {
2040   /*
2041   address-test = "address" { [address-part] [comparator] [match-type] }
2042                  <header-list: string-list> <key-list: string-list>
2043
2044   header-list From, To, Cc, Bcc, Sender, Resent-From, Resent-To
2045   */
2046
2047   enum AddressPart addressPart=ADDRPART_ALL;
2048   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2049   enum MatchType matchType=MATCH_IS;
2050   struct String *hdr,*key;
2051   int m;
2052   int ap=0,co=0,mt=0;
2053
2054   for (;;)
2055     {
2056     if (parse_white(filter)==-1) return -1;
2057     if ((m=parse_addresspart(filter,&addressPart))!=0)
2058       {
2059       if (m==-1) return -1;
2060       if (ap)
2061         {
2062         filter->errmsg=CUS "address part already specified";
2063         return -1;
2064         }
2065       else ap=1;
2066       }
2067     else if ((m=parse_comparator(filter,&comparator))!=0)
2068       {
2069       if (m==-1) return -1;
2070       if (co)
2071         {
2072         filter->errmsg=CUS "comparator already specified";
2073         return -1;
2074         }
2075       else co=1;
2076       }
2077     else if ((m=parse_matchtype(filter,&matchType))!=0)
2078       {
2079       if (m==-1) return -1;
2080       if (mt)
2081         {
2082         filter->errmsg=CUS "match type already specified";
2083         return -1;
2084         }
2085       else mt=1;
2086       }
2087     else break;
2088     }
2089   if (parse_white(filter)==-1) return -1;
2090   if ((m=parse_stringlist(filter,&hdr))!=1)
2091     {
2092     if (m==0) filter->errmsg=CUS "header string list expected";
2093     return -1;
2094     }
2095   if (parse_white(filter)==-1) return -1;
2096   if ((m=parse_stringlist(filter,&key))!=1)
2097     {
2098     if (m==0) filter->errmsg=CUS "key string list expected";
2099     return -1;
2100     }
2101   *cond=0;
2102   for (struct String * h = hdr; h->length!=-1 && !*cond; ++h)
2103     {
2104     uschar *header_value=(uschar*)0,*extracted_addr,*end_addr;
2105
2106     if
2107       (
2108       !eq_asciicase(h,&str_from,0)
2109       && !eq_asciicase(h,&str_to,0)
2110       && !eq_asciicase(h,&str_cc,0)
2111       && !eq_asciicase(h,&str_bcc,0)
2112       && !eq_asciicase(h,&str_sender,0)
2113       && !eq_asciicase(h,&str_resent_from,0)
2114       && !eq_asciicase(h,&str_resent_to,0)
2115       )
2116       {
2117       filter->errmsg=CUS "invalid header field";
2118       return -1;
2119       }
2120     if (exec)
2121       {
2122       /* We are only interested in addresses below, so no MIME decoding */
2123       if (!(header_value = expand_string(string_sprintf("$rheader_%s",quote(h)))))
2124         {
2125         filter->errmsg=CUS "header string expansion failed";
2126         return -1;
2127         }
2128       f.parse_allow_group = TRUE;
2129       while (*header_value && !*cond)
2130         {
2131         uschar *error;
2132         int start, end, domain;
2133         int saveend;
2134         uschar *part=NULL;
2135
2136         end_addr = parse_find_address_end(header_value, FALSE);
2137         saveend = *end_addr;
2138         *end_addr = 0;
2139         extracted_addr = parse_extract_address(header_value, &error, &start, &end, &domain, FALSE);
2140
2141         if (extracted_addr) switch (addressPart)
2142           {
2143           case ADDRPART_ALL: part=extracted_addr; break;
2144 #ifdef SUBADDRESS
2145           case ADDRPART_USER:
2146 #endif
2147           case ADDRPART_LOCALPART: part=extracted_addr; part[domain-1]='\0'; break;
2148           case ADDRPART_DOMAIN: part=extracted_addr+domain; break;
2149 #ifdef SUBADDRESS
2150           case ADDRPART_DETAIL: part=NULL; break;
2151 #endif
2152           }
2153
2154         *end_addr = saveend;
2155         if (part)
2156           {
2157           for (struct String * k = key; k->length !=- 1; ++k)
2158             {
2159             struct String partStr = {.character = part, .length = Ustrlen(part)};
2160
2161             if (extracted_addr)
2162               {
2163               *cond=compare(filter,k,&partStr,comparator,matchType);
2164               if (*cond==-1) return -1;
2165               if (*cond) break;
2166               }
2167             }
2168           }
2169         if (saveend == 0) break;
2170         header_value = end_addr + 1;
2171         }
2172       f.parse_allow_group = FALSE;
2173       f.parse_found_group = FALSE;
2174       }
2175     }
2176   return 1;
2177   }
2178 else if (parse_identifier(filter,CUS "allof"))
2179   {
2180   /*
2181   allof-test   = "allof" <tests: test-list>
2182   */
2183
2184   int n,num_true;
2185
2186   switch (parse_testlist(filter,&n,&num_true,exec))
2187     {
2188     case -1: return -1;
2189     case 0: filter->errmsg=CUS "missing test list"; return -1;
2190     default: *cond=(n==num_true); return 1;
2191     }
2192   }
2193 else if (parse_identifier(filter,CUS "anyof"))
2194   {
2195   /*
2196   anyof-test   = "anyof" <tests: test-list>
2197   */
2198
2199   int n,num_true;
2200
2201   switch (parse_testlist(filter,&n,&num_true,exec))
2202     {
2203     case -1: return -1;
2204     case 0: filter->errmsg=CUS "missing test list"; return -1;
2205     default: *cond=(num_true>0); return 1;
2206     }
2207   }
2208 else if (parse_identifier(filter,CUS "exists"))
2209   {
2210   /*
2211   exists-test = "exists" <header-names: string-list>
2212   */
2213
2214   struct String *hdr;
2215   int m;
2216
2217   if (parse_white(filter)==-1) return -1;
2218   if ((m=parse_stringlist(filter,&hdr))!=1)
2219     {
2220     if (m==0) filter->errmsg=CUS "header string list expected";
2221     return -1;
2222     }
2223   if (exec)
2224     {
2225     *cond=1;
2226     for (struct String * h = hdr; h->length != -1 && *cond; ++h)
2227       {
2228       uschar *header_def;
2229
2230       header_def = expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
2231       if (!header_def)
2232         {
2233         filter->errmsg=CUS "header string expansion failed";
2234         return -1;
2235         }
2236       if (Ustrcmp(header_def,"false")==0) *cond=0;
2237       }
2238     }
2239   return 1;
2240   }
2241 else if (parse_identifier(filter,CUS "false"))
2242   {
2243   /*
2244   false-test = "false"
2245   */
2246
2247   *cond=0;
2248   return 1;
2249   }
2250 else if (parse_identifier(filter,CUS "header"))
2251   {
2252   /*
2253   header-test = "header" { [comparator] [match-type] }
2254                 <header-names: string-list> <key-list: string-list>
2255   */
2256
2257   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2258   enum MatchType matchType=MATCH_IS;
2259   struct String *hdr,*key;
2260   int m;
2261   int co=0,mt=0;
2262
2263   for (;;)
2264     {
2265     if (parse_white(filter)==-1) return -1;
2266     if ((m=parse_comparator(filter,&comparator))!=0)
2267       {
2268       if (m==-1) return -1;
2269       if (co)
2270         {
2271         filter->errmsg=CUS "comparator already specified";
2272         return -1;
2273         }
2274       else co=1;
2275       }
2276     else if ((m=parse_matchtype(filter,&matchType))!=0)
2277       {
2278       if (m==-1) return -1;
2279       if (mt)
2280         {
2281         filter->errmsg=CUS "match type already specified";
2282         return -1;
2283         }
2284       else mt=1;
2285       }
2286     else break;
2287     }
2288   if (parse_white(filter)==-1) return -1;
2289   if ((m=parse_stringlist(filter,&hdr))!=1)
2290     {
2291     if (m==0) filter->errmsg=CUS "header string list expected";
2292     return -1;
2293     }
2294   if (parse_white(filter)==-1) return -1;
2295   if ((m=parse_stringlist(filter,&key))!=1)
2296     {
2297     if (m==0) filter->errmsg=CUS "key string list expected";
2298     return -1;
2299     }
2300   *cond=0;
2301   for (struct String * h = hdr; h->length != -1 && !*cond; ++h)
2302     {
2303     if (!is_header(h))
2304       {
2305       filter->errmsg=CUS "invalid header field";
2306       return -1;
2307       }
2308     if (exec)
2309       {
2310       struct String header_value;
2311       uschar *header_def;
2312
2313       expand_header(&header_value,h);
2314       header_def = expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
2315       if (!header_value.character || !header_def)
2316         {
2317         filter->errmsg=CUS "header string expansion failed";
2318         return -1;
2319         }
2320       for (struct String * k = key; k->length != -1; ++k)
2321         if (Ustrcmp(header_def,"true")==0)
2322           {
2323           *cond=compare(filter,k,&header_value,comparator,matchType);
2324           if (*cond==-1) return -1;
2325           if (*cond) break;
2326           }
2327       }
2328     }
2329   return 1;
2330   }
2331 else if (parse_identifier(filter,CUS "not"))
2332   {
2333   if (parse_white(filter)==-1) return -1;
2334   switch (parse_test(filter,cond,exec))
2335     {
2336     case -1: return -1;
2337     case 0: filter->errmsg=CUS "missing test"; return -1;
2338     default: *cond=!*cond; return 1;
2339     }
2340   }
2341 else if (parse_identifier(filter,CUS "size"))
2342   {
2343   /*
2344   relop = ":over" / ":under"
2345   size-test = "size" relop <limit: number>
2346   */
2347
2348   unsigned long limit;
2349   int overNotUnder;
2350
2351   if (parse_white(filter)==-1) return -1;
2352   if (parse_identifier(filter,CUS ":over")) overNotUnder=1;
2353   else if (parse_identifier(filter,CUS ":under")) overNotUnder=0;
2354   else
2355     {
2356     filter->errmsg=CUS "missing :over or :under";
2357     return -1;
2358     }
2359   if (parse_white(filter)==-1) return -1;
2360   if (parse_number(filter,&limit)==-1) return -1;
2361   *cond=(overNotUnder ? (message_size>limit) : (message_size<limit));
2362   return 1;
2363   }
2364 else if (parse_identifier(filter,CUS "true"))
2365   {
2366   *cond=1;
2367   return 1;
2368   }
2369 else if (parse_identifier(filter,CUS "envelope"))
2370   {
2371   /*
2372   envelope-test = "envelope" { [comparator] [address-part] [match-type] }
2373                   <envelope-part: string-list> <key-list: string-list>
2374
2375   envelope-part is case insensitive "from" or "to"
2376 #ifdef ENVELOPE_AUTH
2377   envelope-part =/ "auth"
2378 #endif
2379   */
2380
2381   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2382   enum AddressPart addressPart=ADDRPART_ALL;
2383   enum MatchType matchType=MATCH_IS;
2384   struct String *env,*key;
2385   int m;
2386   int co=0,ap=0,mt=0;
2387
2388   if (!filter->require_envelope)
2389     {
2390     filter->errmsg=CUS "missing previous require \"envelope\";";
2391     return -1;
2392     }
2393   for (;;)
2394     {
2395     if (parse_white(filter)==-1) return -1;
2396     if ((m=parse_comparator(filter,&comparator))!=0)
2397       {
2398       if (m==-1) return -1;
2399       if (co)
2400         {
2401         filter->errmsg=CUS "comparator already specified";
2402         return -1;
2403         }
2404       else co=1;
2405       }
2406     else if ((m=parse_addresspart(filter,&addressPart))!=0)
2407       {
2408       if (m==-1) return -1;
2409       if (ap)
2410         {
2411         filter->errmsg=CUS "address part already specified";
2412         return -1;
2413         }
2414       else ap=1;
2415       }
2416     else if ((m=parse_matchtype(filter,&matchType))!=0)
2417       {
2418       if (m==-1) return -1;
2419       if (mt)
2420         {
2421         filter->errmsg=CUS "match type already specified";
2422         return -1;
2423         }
2424       else mt=1;
2425       }
2426     else break;
2427     }
2428   if (parse_white(filter)==-1) return -1;
2429   if ((m=parse_stringlist(filter,&env))!=1)
2430     {
2431     if (m==0) filter->errmsg=CUS "envelope string list expected";
2432     return -1;
2433     }
2434   if (parse_white(filter)==-1) return -1;
2435   if ((m=parse_stringlist(filter,&key))!=1)
2436     {
2437     if (m==0) filter->errmsg=CUS "key string list expected";
2438     return -1;
2439     }
2440   *cond=0;
2441   for (struct String * e = env; e->length != -1 && !*cond; ++e)
2442     {
2443     const uschar *envelopeExpr=CUS 0;
2444     uschar *envelope=US 0;
2445
2446     if (eq_asciicase(e,&str_from,0))
2447       {
2448       switch (addressPart)
2449         {
2450         case ADDRPART_ALL: envelopeExpr=CUS "$sender_address"; break;
2451 #ifdef SUBADDRESS
2452         case ADDRPART_USER:
2453 #endif
2454         case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$sender_address}"; break;
2455         case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$sender_address}"; break;
2456 #ifdef SUBADDRESS
2457         case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2458 #endif
2459         }
2460       }
2461     else if (eq_asciicase(e,&str_to,0))
2462       {
2463       switch (addressPart)
2464         {
2465         case ADDRPART_ALL: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix@$domain"; break;
2466 #ifdef SUBADDRESS
2467         case ADDRPART_USER: envelopeExpr=filter->useraddress; break;
2468         case ADDRPART_DETAIL: envelopeExpr=filter->subaddress; break;
2469 #endif
2470         case ADDRPART_LOCALPART: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix"; break;
2471         case ADDRPART_DOMAIN: envelopeExpr=CUS "$domain"; break;
2472         }
2473       }
2474 #ifdef ENVELOPE_AUTH
2475     else if (eq_asciicase(e,&str_auth,0))
2476       {
2477       switch (addressPart)
2478         {
2479         case ADDRPART_ALL: envelopeExpr=CUS "$authenticated_sender"; break;
2480 #ifdef SUBADDRESS
2481         case ADDRPART_USER:
2482 #endif
2483         case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$authenticated_sender}"; break;
2484         case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$authenticated_sender}"; break;
2485 #ifdef SUBADDRESS
2486         case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2487 #endif
2488         }
2489       }
2490 #endif
2491     else
2492       {
2493       filter->errmsg=CUS "invalid envelope string";
2494       return -1;
2495       }
2496     if (exec && envelopeExpr)
2497       {
2498       if (!(envelope=expand_string(US envelopeExpr)))
2499         {
2500         filter->errmsg=CUS "header string expansion failed";
2501         return -1;
2502         }
2503       for (struct String * k = key; k->length != -1; ++k)
2504         {
2505         struct String envelopeStr = {.character = envelope, .length = Ustrlen(envelope)};
2506
2507         *cond=compare(filter,k,&envelopeStr,comparator,matchType);
2508         if (*cond==-1) return -1;
2509         if (*cond) break;
2510         }
2511       }
2512     }
2513   return 1;
2514   }
2515 #ifdef ENOTIFY
2516 else if (parse_identifier(filter,CUS "valid_notify_method"))
2517   {
2518   /*
2519   valid_notify_method = "valid_notify_method"
2520                         <notification-uris: string-list>
2521   */
2522
2523   struct String *uris;
2524   int m;
2525
2526   if (!filter->require_enotify)
2527     {
2528     filter->errmsg=CUS "missing previous require \"enotify\";";
2529     return -1;
2530     }
2531   if (parse_white(filter)==-1) return -1;
2532   if ((m=parse_stringlist(filter,&uris))!=1)
2533     {
2534     if (m==0) filter->errmsg=CUS "URI string list expected";
2535     return -1;
2536     }
2537   if (exec)
2538     {
2539     *cond=1;
2540     for (struct String * u = uris; u->length != -1 && *cond; ++u)
2541       {
2542         string_item *recipient;
2543         struct String header,subject,body;
2544
2545         recipient=NULL;
2546         header.length=-1;
2547         header.character=(uschar*)0;
2548         subject.length=-1;
2549         subject.character=(uschar*)0;
2550         body.length=-1;
2551         body.character=(uschar*)0;
2552         if (parse_mailto_uri(filter,u->character,&recipient,&header,&subject,&body)!=1)
2553           *cond=0;
2554       }
2555     }
2556   return 1;
2557   }
2558 else if (parse_identifier(filter,CUS "notify_method_capability"))
2559   {
2560   /*
2561   notify_method_capability = "notify_method_capability" [COMPARATOR] [MATCH-TYPE]
2562                              <notification-uri: string>
2563                              <notification-capability: string>
2564                              <key-list: string-list>
2565   */
2566
2567   int m;
2568   int co=0,mt=0;
2569
2570   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2571   enum MatchType matchType=MATCH_IS;
2572   struct String uri,capa,*keys;
2573
2574   if (!filter->require_enotify)
2575     {
2576     filter->errmsg=CUS "missing previous require \"enotify\";";
2577     return -1;
2578     }
2579   for (;;)
2580     {
2581     if (parse_white(filter)==-1) return -1;
2582     if ((m=parse_comparator(filter,&comparator))!=0)
2583       {
2584       if (m==-1) return -1;
2585       if (co)
2586         {
2587         filter->errmsg=CUS "comparator already specified";
2588         return -1;
2589         }
2590       else co=1;
2591       }
2592     else if ((m=parse_matchtype(filter,&matchType))!=0)
2593       {
2594       if (m==-1) return -1;
2595       if (mt)
2596         {
2597         filter->errmsg=CUS "match type already specified";
2598         return -1;
2599         }
2600       else mt=1;
2601       }
2602     else break;
2603     }
2604     if ((m=parse_string(filter,&uri))!=1)
2605       {
2606       if (m==0) filter->errmsg=CUS "missing notification URI string";
2607       return -1;
2608       }
2609     if (parse_white(filter)==-1) return -1;
2610     if ((m=parse_string(filter,&capa))!=1)
2611       {
2612       if (m==0) filter->errmsg=CUS "missing notification capability string";
2613       return -1;
2614       }
2615     if (parse_white(filter)==-1) return -1;
2616     if ((m=parse_stringlist(filter,&keys))!=1)
2617       {
2618       if (m==0) filter->errmsg=CUS "missing key string list";
2619       return -1;
2620       }
2621     if (exec)
2622       {
2623       string_item *recipient;
2624       struct String header,subject,body;
2625
2626       *cond=0;
2627       recipient=NULL;
2628       header.length=-1;
2629       header.character=(uschar*)0;
2630       subject.length=-1;
2631       subject.character=(uschar*)0;
2632       body.length=-1;
2633       body.character=(uschar*)0;
2634       if (parse_mailto_uri(filter,uri.character,&recipient,&header,&subject,&body)==1)
2635         if (eq_asciicase(&capa,&str_online,0)==1)
2636           for (struct String * k = keys; k->length != -1; ++k)
2637             {
2638             *cond=compare(filter,k,&str_maybe,comparator,matchType);
2639             if (*cond==-1) return -1;
2640             if (*cond) break;
2641             }
2642       }
2643     return 1;
2644   }
2645 #endif
2646 else return 0;
2647 }
2648
2649
2650 /*************************************************
2651 *     Parse and interpret an optional block      *
2652 *************************************************/
2653
2654 /*
2655 Arguments:
2656   filter      points to the Sieve filter including its state
2657   exec        Execute parsed statements
2658   generated   where to hang newly-generated addresses
2659
2660 Returns:      2                success by stop
2661               1                other success
2662               0                no block command found
2663               -1               syntax or execution error
2664 */
2665
2666 static int parse_block(struct Sieve *filter, int exec,
2667   address_item **generated)
2668 {
2669 int r;
2670
2671 if (parse_white(filter)==-1) return -1;
2672 if (*filter->pc=='{')
2673   {
2674   ++filter->pc;
2675   if ((r=parse_commands(filter,exec,generated))==-1 || r==2) return r;
2676   if (*filter->pc=='}')
2677     {
2678     ++filter->pc;
2679     return 1;
2680     }
2681   else
2682     {
2683     filter->errmsg=CUS "expecting command or closing brace";
2684     return -1;
2685     }
2686   }
2687 else return 0;
2688 }
2689
2690
2691 /*************************************************
2692 *           Match a semicolon                    *
2693 *************************************************/
2694
2695 /*
2696 Arguments:
2697   filter      points to the Sieve filter including its state
2698
2699 Returns:      1                success
2700               -1               syntax error
2701 */
2702
2703 static int parse_semicolon(struct Sieve *filter)
2704 {
2705   if (parse_white(filter)==-1) return -1;
2706   if (*filter->pc==';')
2707   {
2708     ++filter->pc;
2709     return 1;
2710   }
2711   else
2712   {
2713     filter->errmsg=CUS "missing semicolon";
2714     return -1;
2715   }
2716 }
2717
2718
2719 /*************************************************
2720 *     Parse and interpret a Sieve command        *
2721 *************************************************/
2722
2723 /*
2724 Arguments:
2725   filter      points to the Sieve filter including its state
2726   exec        Execute parsed statements
2727   generated   where to hang newly-generated addresses
2728
2729 Returns:      2                success by stop
2730               1                other success
2731               -1               syntax or execution error
2732 */
2733 static int
2734 parse_commands(struct Sieve *filter, int exec, address_item **generated)
2735 {
2736 while (*filter->pc)
2737   {
2738   if (parse_white(filter)==-1) return -1;
2739   if (parse_identifier(filter,CUS "if"))
2740     {
2741     /*
2742     if-command = "if" test block *( "elsif" test block ) [ else block ]
2743     */
2744
2745     int cond,m,unsuccessful;
2746
2747     /* test block */
2748     if (parse_white(filter)==-1) return -1;
2749     if ((m=parse_test(filter,&cond,exec))==-1) return -1;
2750     if (m==0)
2751       {
2752       filter->errmsg=CUS "missing test";
2753       return -1;
2754       }
2755     if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2756         (debug_selector & D_filter) != 0)
2757       {
2758       if (exec) debug_printf("if %s\n",cond?"true":"false");
2759       }
2760     m=parse_block(filter,exec ? cond : 0, generated);
2761     if (m==-1 || m==2) return m;
2762     if (m==0)
2763       {
2764       filter->errmsg=CUS "missing block";
2765       return -1;
2766       }
2767     unsuccessful = !cond;
2768     for (;;) /* elsif test block */
2769       {
2770       if (parse_white(filter)==-1) return -1;
2771       if (parse_identifier(filter,CUS "elsif"))
2772         {
2773         if (parse_white(filter)==-1) return -1;
2774         m=parse_test(filter,&cond,exec && unsuccessful);
2775         if (m==-1 || m==2) return m;
2776         if (m==0)
2777           {
2778           filter->errmsg=CUS "missing test";
2779           return -1;
2780           }
2781         if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2782             (debug_selector & D_filter) != 0)
2783           {
2784           if (exec) debug_printf("elsif %s\n",cond?"true":"false");
2785           }
2786         m=parse_block(filter,exec && unsuccessful ? cond : 0, generated);
2787         if (m==-1 || m==2) return m;
2788         if (m==0)
2789           {
2790           filter->errmsg=CUS "missing block";
2791           return -1;
2792           }
2793         if (exec && unsuccessful && cond) unsuccessful = 0;
2794         }
2795       else break;
2796       }
2797     /* else block */
2798     if (parse_white(filter)==-1) return -1;
2799     if (parse_identifier(filter,CUS "else"))
2800       {
2801       m=parse_block(filter,exec && unsuccessful, generated);
2802       if (m==-1 || m==2) return m;
2803       if (m==0)
2804         {
2805         filter->errmsg=CUS "missing block";
2806         return -1;
2807         }
2808       }
2809     }
2810   else if (parse_identifier(filter,CUS "stop"))
2811     {
2812     /*
2813     stop-command     =  "stop" { stop-options } ";"
2814     stop-options     =
2815     */
2816
2817     if (parse_semicolon(filter)==-1) return -1;
2818     if (exec)
2819       {
2820       filter->pc+=Ustrlen(filter->pc);
2821       return 2;
2822       }
2823     }
2824   else if (parse_identifier(filter,CUS "keep"))
2825     {
2826     /*
2827     keep-command     =  "keep" { keep-options } ";"
2828     keep-options     =
2829     */
2830
2831     if (parse_semicolon(filter)==-1) return -1;
2832     if (exec)
2833       {
2834       add_addr(generated,US"inbox",1,0,0,0);
2835       filter->keep = 0;
2836       }
2837     }
2838   else if (parse_identifier(filter,CUS "discard"))
2839     {
2840     /*
2841     discard-command  =  "discard" { discard-options } ";"
2842     discard-options  =
2843     */
2844
2845     if (parse_semicolon(filter)==-1) return -1;
2846     if (exec) filter->keep=0;
2847     }
2848   else if (parse_identifier(filter,CUS "redirect"))
2849     {
2850     /*
2851     redirect-command =  "redirect" redirect-options "string" ";"
2852     redirect-options =
2853     redirect-options =) ":copy"
2854     */
2855
2856     struct String recipient;
2857     int m;
2858     int copy=0;
2859
2860     for (;;)
2861       {
2862       if (parse_white(filter)==-1) return -1;
2863       if (parse_identifier(filter,CUS ":copy")==1)
2864         {
2865         if (!filter->require_copy)
2866           {
2867           filter->errmsg=CUS "missing previous require \"copy\";";
2868           return -1;
2869           }
2870           copy=1;
2871         }
2872       else break;
2873       }
2874     if (parse_white(filter)==-1) return -1;
2875     if ((m=parse_string(filter,&recipient))!=1)
2876       {
2877       if (m==0) filter->errmsg=CUS "missing redirect recipient string";
2878       return -1;
2879       }
2880     if (strchr(CCS recipient.character,'@')==(char*)0)
2881       {
2882       filter->errmsg=CUS "unqualified recipient address";
2883       return -1;
2884       }
2885     if (exec)
2886       {
2887       add_addr(generated,recipient.character,0,0,0,0);
2888       if (!copy) filter->keep = 0;
2889       }
2890     if (parse_semicolon(filter)==-1) return -1;
2891     }
2892   else if (parse_identifier(filter,CUS "fileinto"))
2893     {
2894     /*
2895     fileinto-command =  "fileinto" { fileinto-options } string ";"
2896     fileinto-options =
2897     fileinto-options =) [ ":copy" ]
2898     */
2899
2900     struct String folder;
2901     uschar *s;
2902     int m;
2903     unsigned long maxage, maxmessages, maxstorage;
2904     int copy=0;
2905
2906     maxage = maxmessages = maxstorage = 0;
2907     if (!filter->require_fileinto)
2908       {
2909       filter->errmsg=CUS "missing previous require \"fileinto\";";
2910       return -1;
2911       }
2912     for (;;)
2913       {
2914       if (parse_white(filter)==-1) return -1;
2915       if (parse_identifier(filter,CUS ":copy")==1)
2916         {
2917         if (!filter->require_copy)
2918           {
2919           filter->errmsg=CUS "missing previous require \"copy\";";
2920           return -1;
2921           }
2922           copy=1;
2923         }
2924       else break;
2925       }
2926     if (parse_white(filter)==-1) return -1;
2927     if ((m=parse_string(filter,&folder))!=1)
2928       {
2929       if (m==0) filter->errmsg=CUS "missing fileinto folder string";
2930       return -1;
2931       }
2932     m=0; s=folder.character;
2933     if (folder.length==0) m=1;
2934     if (Ustrcmp(s,"..")==0 || Ustrncmp(s,"../",3)==0) m=1;
2935     else while (*s)
2936       {
2937       if (Ustrcmp(s,"/..")==0 || Ustrncmp(s,"/../",4)==0) { m=1; break; }
2938       ++s;
2939       }
2940     if (m)
2941       {
2942       filter->errmsg=CUS "invalid folder";
2943       return -1;
2944       }
2945     if (exec)
2946       {
2947       add_addr(generated, folder.character, 1, maxage, maxmessages, maxstorage);
2948       if (!copy) filter->keep = 0;
2949       }
2950     if (parse_semicolon(filter)==-1) return -1;
2951     }
2952 #ifdef ENOTIFY
2953   else if (parse_identifier(filter,CUS "notify"))
2954     {
2955     /*
2956     notify-command =  "notify" { notify-options } <method: string> ";"
2957     notify-options =  [":from" string]
2958                       [":importance" <"1" / "2" / "3">]
2959                       [":options" 1*(string-list / number)]
2960                       [":message" string]
2961     */
2962
2963     int m;
2964     struct String from;
2965     struct String importance;
2966     struct String message;
2967     struct String method;
2968     struct Notification *already;
2969     string_item *recipient;
2970     struct String header;
2971     struct String subject;
2972     struct String body;
2973     uschar *envelope_from;
2974     struct String auto_submitted_value;
2975     uschar *auto_submitted_def;
2976
2977     if (!filter->require_enotify)
2978       {
2979       filter->errmsg=CUS "missing previous require \"enotify\";";
2980       return -1;
2981       }
2982     from.character=(uschar*)0;
2983     from.length=-1;
2984     importance.character=(uschar*)0;
2985     importance.length=-1;
2986     message.character=(uschar*)0;
2987     message.length=-1;
2988     recipient=NULL;
2989     header.length=-1;
2990     header.character=(uschar*)0;
2991     subject.length=-1;
2992     subject.character=(uschar*)0;
2993     body.length=-1;
2994     body.character=(uschar*)0;
2995     envelope_from = sender_address && sender_address[0]
2996      ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : US "";
2997     if (!envelope_from)
2998       {
2999       filter->errmsg=CUS "expansion failure for envelope from";
3000       return -1;
3001       }
3002     for (;;)
3003       {
3004       if (parse_white(filter)==-1) return -1;
3005       if (parse_identifier(filter,CUS ":from")==1)
3006         {
3007         if (parse_white(filter)==-1) return -1;
3008         if ((m=parse_string(filter,&from))!=1)
3009           {
3010           if (m==0) filter->errmsg=CUS "from string expected";
3011           return -1;
3012           }
3013         }
3014       else if (parse_identifier(filter,CUS ":importance")==1)
3015         {
3016         if (parse_white(filter)==-1) return -1;
3017         if ((m=parse_string(filter,&importance))!=1)
3018           {
3019           if (m==0) filter->errmsg=CUS "importance string expected";
3020           return -1;
3021           }
3022         if (importance.length!=1 || importance.character[0]<'1' || importance.character[0]>'3')
3023           {
3024           filter->errmsg=CUS "invalid importance";
3025           return -1;
3026           }
3027         }
3028       else if (parse_identifier(filter,CUS ":options")==1)
3029         {
3030         if (parse_white(filter)==-1) return -1;
3031         }
3032       else if (parse_identifier(filter,CUS ":message")==1)
3033         {
3034         if (parse_white(filter)==-1) return -1;
3035         if ((m=parse_string(filter,&message))!=1)
3036           {
3037           if (m==0) filter->errmsg=CUS "message string expected";
3038           return -1;
3039           }
3040         }
3041       else break;
3042       }
3043     if (parse_white(filter)==-1) return -1;
3044     if ((m=parse_string(filter,&method))!=1)
3045       {
3046       if (m==0) filter->errmsg=CUS "missing method string";
3047       return -1;
3048       }
3049     if (parse_semicolon(filter)==-1) return -1;
3050     if (parse_mailto_uri(filter,method.character,&recipient,&header,&subject,&body)!=1)
3051       return -1;
3052     if (exec)
3053       {
3054       if (message.length==-1) message=subject;
3055       if (message.length==-1) expand_header(&message,&str_subject);
3056       expand_header(&auto_submitted_value,&str_auto_submitted);
3057       auto_submitted_def=expand_string(US"${if def:header_auto-submitted {true}{false}}");
3058       if (!auto_submitted_value.character || !auto_submitted_def)
3059         {
3060         filter->errmsg=CUS "header string expansion failed";
3061         return -1;
3062         }
3063         if (Ustrcmp(auto_submitted_def,"true")!=0 || Ustrcmp(auto_submitted_value.character,"no")==0)
3064         {
3065         for (already=filter->notified; already; already=already->next)
3066           {
3067           if (already->method.length==method.length
3068               && (method.length==-1 || Ustrcmp(already->method.character,method.character)==0)
3069               && already->importance.length==importance.length
3070               && (importance.length==-1 || Ustrcmp(already->importance.character,importance.character)==0)
3071               && already->message.length==message.length
3072               && (message.length==-1 || Ustrcmp(already->message.character,message.character)==0))
3073             break;
3074           }
3075         if (!already)
3076           /* New notification, process it */
3077           {
3078           struct Notification * sent = store_get(sizeof(struct Notification), GET_UNTAINTED);
3079           sent->method=method;
3080           sent->importance=importance;
3081           sent->message=message;
3082           sent->next=filter->notified;
3083           filter->notified=sent;
3084   #ifndef COMPILE_SYNTAX_CHECKER
3085           if (filter_test == FTEST_NONE)
3086             {
3087             int pid, fd;
3088
3089             if ((pid = child_open_exim2(&fd, envelope_from, envelope_from,
3090                         US"sieve-notify")) >= 1)
3091               {
3092               FILE * f = fdopen(fd, "wb");
3093
3094               fprintf(f,"From: %s\n", from.length == -1
3095                 ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain")
3096                 : from.character);
3097               for (string_item * p = recipient; p; p=p->next)
3098                 fprintf(f, "To: %s\n",p->text);
3099               fprintf(f, "Auto-Submitted: auto-notified; %s\n", filter->enotify_mailto_owner);
3100               if (header.length > 0) fprintf(f, "%s", header.character);
3101               if (message.length==-1)
3102                 {
3103                 message.character=US"Notification";
3104                 message.length=Ustrlen(message.character);
3105                 }
3106               if (message.length != -1)
3107                 fprintf(f, "Subject: %s\n", parse_quote_2047(message.character,
3108                   message.length, US"utf-8", TRUE));
3109               fprintf(f,"\n");
3110               if (body.length > 0) fprintf(f, "%s\n", body.character);
3111               fflush(f);
3112               (void)fclose(f);
3113               (void)child_close(pid, 0);
3114               }
3115             }
3116           if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
3117             debug_printf("Notification to `%s': '%s'.\n",method.character,message.length!=-1 ? message.character : CUS "");
3118 #endif
3119           }
3120         else
3121           if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
3122             debug_printf("Repeated notification to `%s' ignored.\n",method.character);
3123         }
3124       else
3125         if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
3126           debug_printf("Ignoring notification, triggering message contains Auto-submitted: field.\n");
3127       }
3128     }
3129 #endif
3130 #ifdef VACATION
3131   else if (parse_identifier(filter,CUS "vacation"))
3132     {
3133     /*
3134     vacation-command =  "vacation" { vacation-options } <reason: string> ";"
3135     vacation-options =  [":days" number]
3136                         [":subject" string]
3137                         [":from" string]
3138                         [":addresses" string-list]
3139                         [":mime"]
3140                         [":handle" string]
3141     */
3142
3143     int m;
3144     unsigned long days;
3145     struct String subject;
3146     struct String from;
3147     struct String *addresses;
3148     int reason_is_mime;
3149     string_item *aliases;
3150     struct String handle;
3151     struct String reason;
3152
3153     if (!filter->require_vacation)
3154       {
3155       filter->errmsg=CUS "missing previous require \"vacation\";";
3156       return -1;
3157       }
3158     if (exec)
3159       {
3160       if (filter->vacation_ran)
3161         {
3162         filter->errmsg=CUS "trying to execute vacation more than once";
3163         return -1;
3164         }
3165       filter->vacation_ran=1;
3166       }
3167     days=VACATION_MIN_DAYS>7 ? VACATION_MIN_DAYS : 7;
3168     subject.character=(uschar*)0;
3169     subject.length=-1;
3170     from.character=(uschar*)0;
3171     from.length=-1;
3172     addresses=(struct String*)0;
3173     aliases=NULL;
3174     reason_is_mime=0;
3175     handle.character=(uschar*)0;
3176     handle.length=-1;
3177     for (;;)
3178       {
3179       if (parse_white(filter)==-1) return -1;
3180       if (parse_identifier(filter,CUS ":days")==1)
3181         {
3182         if (parse_white(filter)==-1) return -1;
3183         if (parse_number(filter,&days)==-1) return -1;
3184         if (days<VACATION_MIN_DAYS) days=VACATION_MIN_DAYS;
3185         else if (days>VACATION_MAX_DAYS) days=VACATION_MAX_DAYS;
3186         }
3187       else if (parse_identifier(filter,CUS ":subject")==1)
3188         {
3189         if (parse_white(filter)==-1) return -1;
3190         if ((m=parse_string(filter,&subject))!=1)
3191           {
3192           if (m==0) filter->errmsg=CUS "subject string expected";
3193           return -1;
3194           }
3195         }
3196       else if (parse_identifier(filter,CUS ":from")==1)
3197         {
3198         if (parse_white(filter)==-1) return -1;
3199         if ((m=parse_string(filter,&from))!=1)
3200           {
3201           if (m==0) filter->errmsg=CUS "from string expected";
3202           return -1;
3203           }
3204         if (check_mail_address(filter,&from)!=1)
3205           return -1;
3206         }
3207       else if (parse_identifier(filter,CUS ":addresses")==1)
3208         {
3209         if (parse_white(filter)==-1) return -1;
3210         if ((m=parse_stringlist(filter,&addresses))!=1)
3211           {
3212           if (m==0) filter->errmsg=CUS "addresses string list expected";
3213           return -1;
3214           }
3215         for (struct String * a = addresses; a->length != -1; ++a)
3216           {
3217           string_item * new = store_get(sizeof(string_item), GET_UNTAINTED);
3218
3219           new->text = store_get(a->length+1, a->character);
3220           if (a->length) memcpy(new->text,a->character,a->length);
3221           new->text[a->length]='\0';
3222           new->next=aliases;
3223           aliases=new;
3224           }
3225         }
3226       else if (parse_identifier(filter,CUS ":mime")==1)
3227         reason_is_mime=1;
3228       else if (parse_identifier(filter,CUS ":handle")==1)
3229         {
3230         if (parse_white(filter)==-1) return -1;
3231         if ((m=parse_string(filter,&from))!=1)
3232           {
3233           if (m==0) filter->errmsg=CUS "handle string expected";
3234           return -1;
3235           }
3236         }
3237       else break;
3238       }
3239     if (parse_white(filter)==-1) return -1;
3240     if ((m=parse_string(filter,&reason))!=1)
3241       {
3242       if (m==0) filter->errmsg=CUS "missing reason string";
3243       return -1;
3244       }
3245     if (reason_is_mime)
3246       {
3247       uschar *s,*end;
3248
3249       for (s = reason.character, end = reason.character + reason.length;
3250           s<end && (*s&0x80)==0; ) s++;
3251       if (s<end)
3252         {
3253         filter->errmsg=CUS "MIME reason string contains 8bit text";
3254         return -1;
3255         }
3256       }
3257     if (parse_semicolon(filter)==-1) return -1;
3258
3259     if (exec)
3260       {
3261       address_item *addr;
3262       md5 base;
3263       uschar digest[16];
3264       uschar hexdigest[33];
3265       gstring * once;
3266
3267       if (filter_personal(aliases,TRUE))
3268         {
3269         if (filter_test == FTEST_NONE)
3270           {
3271           /* ensure oncelog directory exists; failure will be detected later */
3272
3273           (void)directory_make(NULL, filter->vacation_directory, 0700, FALSE);
3274           }
3275         /* build oncelog filename */
3276
3277         md5_start(&base);
3278
3279         if (handle.length==-1)
3280           {
3281           gstring * key = NULL;
3282           if (subject.length!=-1) key =string_catn(key, subject.character, subject.length);
3283           if (from.length!=-1) key = string_catn(key, from.character, from.length);
3284           key = string_catn(key, reason_is_mime?US"1":US"0", 1);
3285           key = string_catn(key, reason.character, reason.length);
3286           md5_end(&base, key->s, key->ptr, digest);
3287           }
3288         else
3289           md5_end(&base, handle.character, handle.length, digest);
3290
3291         for (int i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]);
3292
3293         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3294           debug_printf("Sieve: mail was personal, vacation file basename: %s\n", hexdigest);
3295
3296         if (filter_test == FTEST_NONE)
3297           {
3298           once = string_cat (NULL, filter->vacation_directory);
3299           once = string_catn(once, US"/", 1);
3300           once = string_catn(once, hexdigest, 33);
3301
3302           /* process subject */
3303
3304           if (subject.length==-1)
3305             {
3306             uschar *subject_def;
3307
3308             subject_def = expand_string(US"${if def:header_subject {true}{false}}");
3309             if (subject_def && Ustrcmp(subject_def,"true")==0)
3310               {
3311               gstring * g = string_catn(NULL, US"Auto: ", 6);
3312
3313               expand_header(&subject,&str_subject);
3314               g = string_catn(g, subject.character, subject.length);
3315               subject.character = string_from_gstring(g);
3316               subject.length = g->ptr;
3317               }
3318             else
3319               {
3320               subject.character=US"Automated reply";
3321               subject.length=Ustrlen(subject.character);
3322               }
3323             }
3324
3325           /* add address to list of generated addresses */
3326
3327           addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
3328           setflag(addr, af_pfr);
3329           addr->prop.ignore_error = TRUE;
3330           addr->next = *generated;
3331           *generated = addr;
3332           addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
3333           memset(addr->reply,0,sizeof(reply_item)); /* XXX */
3334           addr->reply->to = string_copy(sender_address);
3335           if (from.length==-1)
3336             addr->reply->from = expand_string(US"$local_part@$domain");
3337           else
3338             addr->reply->from = from.character;
3339           /* deconst cast safe as we pass in a non-const item */
3340           addr->reply->subject = US parse_quote_2047(subject.character, subject.length, US"utf-8", TRUE);
3341           addr->reply->oncelog = string_from_gstring(once);
3342           addr->reply->once_repeat=days*86400;
3343
3344           /* build body and MIME headers */
3345
3346           if (reason_is_mime)
3347             {
3348             uschar *mime_body,*reason_end;
3349             static const uschar nlnl[]="\r\n\r\n";
3350
3351             for
3352               (
3353               mime_body = reason.character, reason_end = reason.character + reason.length;
3354               mime_body < (reason_end-(sizeof(nlnl)-1)) && memcmp(mime_body, nlnl, (sizeof(nlnl)-1));
3355               ) mime_body++;
3356
3357             addr->reply->headers = string_copyn(reason.character, mime_body-reason.character);
3358
3359             if (mime_body+(sizeof(nlnl)-1)<reason_end) mime_body+=(sizeof(nlnl)-1);
3360             else mime_body=reason_end-1;
3361             addr->reply->text = string_copyn(mime_body, reason_end-mime_body);
3362             }
3363           else
3364             {
3365             struct String qp = { .character = NULL, .length = 0 };  /* Keep compiler happy (PH) */
3366
3367             addr->reply->headers = US"MIME-Version: 1.0\n"
3368                                    "Content-Type: text/plain;\n"
3369                                    "\tcharset=\"utf-8\"\n"
3370                                    "Content-Transfer-Encoding: quoted-printable";
3371             addr->reply->text = quoted_printable_encode(&reason,&qp)->character;
3372             }
3373           }
3374         }
3375         else if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3376           debug_printf("Sieve: mail was not personal, vacation would ignore it\n");
3377       }
3378     }
3379     else break;
3380 #endif
3381   }
3382 return 1;
3383 }
3384
3385
3386 /*************************************************
3387 *       Parse and interpret a sieve filter       *
3388 *************************************************/
3389
3390 /*
3391 Arguments:
3392   filter      points to the Sieve filter including its state
3393   exec        Execute parsed statements
3394   generated   where to hang newly-generated addresses
3395
3396 Returns:      1                success
3397               -1               syntax or execution error
3398 */
3399
3400 static int
3401 parse_start(struct Sieve *filter, int exec, address_item **generated)
3402 {
3403 filter->pc=filter->filter;
3404 filter->line=1;
3405 filter->keep=1;
3406 filter->require_envelope=0;
3407 filter->require_fileinto=0;
3408 #ifdef ENCODED_CHARACTER
3409 filter->require_encoded_character=0;
3410 #endif
3411 #ifdef ENVELOPE_AUTH
3412 filter->require_envelope_auth=0;
3413 #endif
3414 #ifdef ENOTIFY
3415 filter->require_enotify=0;
3416 filter->notified=(struct Notification*)0;
3417 #endif
3418 #ifdef SUBADDRESS
3419 filter->require_subaddress=0;
3420 #endif
3421 #ifdef VACATION
3422 filter->require_vacation=0;
3423 filter->vacation_ran=0;
3424 #endif
3425 filter->require_copy=0;
3426 filter->require_iascii_numeric=0;
3427
3428 if (parse_white(filter)==-1) return -1;
3429
3430 if (exec && filter->vacation_directory && filter_test == FTEST_NONE)
3431   {
3432   DIR *oncelogdir;
3433   struct dirent *oncelog;
3434   struct stat properties;
3435   time_t now;
3436
3437   /* clean up old vacation log databases */
3438
3439   if (  !(oncelogdir = exim_opendir(filter->vacation_directory))
3440      && errno != ENOENT)
3441     {
3442     filter->errmsg = CUS "unable to open vacation directory";
3443     return -1;
3444     }
3445
3446   if (oncelogdir)
3447     {
3448     time(&now);
3449
3450     while ((oncelog = readdir(oncelogdir)))
3451       if (strlen(oncelog->d_name)==32)
3452         {
3453         uschar *s = string_sprintf("%s/%s", filter->vacation_directory, oncelog->d_name);
3454         if (Ustat(s,&properties) == 0 && properties.st_mtime+VACATION_MAX_DAYS*86400 < now)
3455           Uunlink(s);
3456         }
3457     closedir(oncelogdir);
3458     }
3459   }
3460
3461 while (parse_identifier(filter,CUS "require"))
3462   {
3463   /*
3464   require-command = "require" <capabilities: string-list>
3465   */
3466
3467   struct String *cap;
3468   int m;
3469
3470   if (parse_white(filter)==-1) return -1;
3471   if ((m=parse_stringlist(filter,&cap))!=1)
3472     {
3473     if (m==0) filter->errmsg=CUS "capability string list expected";
3474     return -1;
3475     }
3476   for (struct String * check = cap; check->character; ++check)
3477     {
3478     if (eq_octet(check,&str_envelope,0)) filter->require_envelope=1;
3479     else if (eq_octet(check,&str_fileinto,0)) filter->require_fileinto=1;
3480 #ifdef ENCODED_CHARACTER
3481     else if (eq_octet(check,&str_encoded_character,0)) filter->require_encoded_character=1;
3482 #endif
3483 #ifdef ENVELOPE_AUTH
3484     else if (eq_octet(check,&str_envelope_auth,0)) filter->require_envelope_auth=1;
3485 #endif
3486 #ifdef ENOTIFY
3487     else if (eq_octet(check,&str_enotify,0))
3488       {
3489       if (!filter->enotify_mailto_owner)
3490         {
3491         filter->errmsg=CUS "enotify disabled";
3492         return -1;
3493         }
3494         filter->require_enotify=1;
3495       }
3496 #endif
3497 #ifdef SUBADDRESS
3498     else if (eq_octet(check,&str_subaddress,0)) filter->require_subaddress=1;
3499 #endif
3500 #ifdef VACATION
3501     else if (eq_octet(check,&str_vacation,0))
3502       {
3503       if (filter_test == FTEST_NONE && !filter->vacation_directory)
3504         {
3505         filter->errmsg=CUS "vacation disabled";
3506         return -1;
3507         }
3508       filter->require_vacation=1;
3509       }
3510 #endif
3511     else if (eq_octet(check,&str_copy,0)) filter->require_copy=1;
3512     else if (eq_octet(check,&str_comparator_ioctet,0)) ;
3513     else if (eq_octet(check,&str_comparator_iascii_casemap,0)) ;
3514     else if (eq_octet(check,&str_comparator_enascii_casemap,0)) ;
3515     else if (eq_octet(check,&str_comparator_iascii_numeric,0)) filter->require_iascii_numeric=1;
3516     else
3517       {
3518       filter->errmsg=CUS "unknown capability";
3519       return -1;
3520       }
3521     }
3522     if (parse_semicolon(filter)==-1) return -1;
3523   }
3524   if (parse_commands(filter,exec,generated)==-1) return -1;
3525   if (*filter->pc)
3526     {
3527     filter->errmsg=CUS "syntax error";
3528     return -1;
3529     }
3530   return 1;
3531 }
3532
3533
3534 /*************************************************
3535 *            Interpret a sieve filter file       *
3536 *************************************************/
3537
3538 /*
3539 Arguments:
3540   filter      points to the entire file, read into store as a single string
3541   options     controls whether various special things are allowed, and requests
3542               special actions (not currently used)
3543   vacation_directory    where to store vacation "once" files
3544   enotify_mailto_owner  owner of mailto notifications
3545   useraddress string expression for :user part of address
3546   subaddress  string expression for :subaddress part of address
3547   generated   where to hang newly-generated addresses
3548   error       where to pass back an error text
3549
3550 Returns:      FF_DELIVERED     success, a significant action was taken
3551               FF_NOTDELIVERED  success, no significant action
3552               FF_DEFER         defer requested
3553               FF_FAIL          fail requested
3554               FF_FREEZE        freeze requested
3555               FF_ERROR         there was a problem
3556 */
3557
3558 int
3559 sieve_interpret(const uschar * filter, int options,
3560   const uschar * vacation_directory, const uschar * enotify_mailto_owner,
3561   const uschar * useraddress, const uschar * subaddress,
3562   address_item ** generated, uschar ** error)
3563 {
3564 struct Sieve sieve;
3565 int r;
3566 uschar * msg;
3567
3568 DEBUG(D_route) debug_printf("Sieve: start of processing\n");
3569 sieve.filter = filter;
3570
3571 if (!vacation_directory)
3572   sieve.vacation_directory = NULL;
3573 else if (!(sieve.vacation_directory = expand_cstring(vacation_directory)))
3574   {
3575   *error = string_sprintf("failed to expand \"%s\" "
3576     "(sieve_vacation_directory): %s", vacation_directory,
3577     expand_string_message);
3578   return FF_ERROR;
3579   }
3580
3581 if (!enotify_mailto_owner)
3582   sieve.enotify_mailto_owner = NULL;
3583 else if (!(sieve.enotify_mailto_owner = expand_cstring(enotify_mailto_owner)))
3584   {
3585   *error = string_sprintf("failed to expand \"%s\" "
3586     "(sieve_enotify_mailto_owner): %s", enotify_mailto_owner,
3587     expand_string_message);
3588   return FF_ERROR;
3589   }
3590
3591 sieve.useraddress = useraddress
3592   ? useraddress : CUS "$local_part_prefix$local_part$local_part_suffix";
3593 sieve.subaddress = subaddress;
3594
3595 #ifdef COMPILE_SYNTAX_CHECKER
3596 if (parse_start(&sieve, 0, generated) == 1)
3597 #else
3598 if (parse_start(&sieve, 1, generated) == 1)
3599 #endif
3600   if (sieve.keep)
3601     {
3602     add_addr(generated, US"inbox", 1, 0, 0, 0);
3603     msg = US"Implicit keep";
3604     r = FF_DELIVERED;
3605     }
3606   else
3607     {
3608     msg = US"No implicit keep";
3609     r = FF_DELIVERED;
3610     }
3611 else
3612   {
3613   msg = string_sprintf("Sieve error: %s in line %d",sieve.errmsg,sieve.line);
3614 #ifdef COMPILE_SYNTAX_CHECKER
3615   r = FF_ERROR;
3616   *error = msg;
3617 #else
3618   add_addr(generated,US"inbox",1,0,0,0);
3619   r = FF_DELIVERED;
3620 #endif
3621   }
3622
3623 #ifndef COMPILE_SYNTAX_CHECKER
3624 if (filter_test != FTEST_NONE) printf("%s\n", (const char*) msg);
3625   else debug_printf("%s\n", msg);
3626 #endif
3627
3628 DEBUG(D_route) debug_printf("Sieve: end of processing\n");
3629 return r;
3630 }