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