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