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