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