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