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