tidying
[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
1708 parse_stringlist(struct Sieve *filter, struct String **data)
1709 {
1710 const uschar *orig=filter->pc;
1711 int dataCapacity = 0;
1712 int dataLength = 0;
1713 struct String *d = NULL;
1714 int m;
1715
1716 if (*filter->pc=='[') /* string list */
1717   {
1718   ++filter->pc;
1719   for (;;)
1720     {
1721     if (parse_white(filter)==-1) goto error;
1722     if (dataLength+1 >= dataCapacity) /* increase buffer */
1723       {
1724       struct String *new;
1725       int newCapacity;          /* Don't amalgamate with next line; some compilers grumble */
1726
1727       dataCapacity = dataCapacity ? dataCapacity * 2 : 4;
1728       new = store_get(sizeof(struct String) * dataCapacity);
1729
1730       if (d) memcpy(new,d,sizeof(struct String)*dataLength);
1731       d = new;
1732       }
1733
1734     m=parse_string(filter,&d[dataLength]);
1735     if (m==0)
1736       {
1737       if (dataLength==0) break;
1738       else
1739         {
1740         filter->errmsg=CUS "missing string";
1741         goto error;
1742         }
1743       }
1744     else if (m==-1) goto error;
1745     else ++dataLength;
1746     if (parse_white(filter)==-1) goto error;
1747     if (*filter->pc==',') ++filter->pc;
1748     else break;
1749     }
1750   if (*filter->pc==']')
1751     {
1752     d[dataLength].character=(uschar*)0;
1753     d[dataLength].length=-1;
1754     ++filter->pc;
1755     *data=d;
1756     return 1;
1757     }
1758   else
1759     {
1760     filter->errmsg=CUS "missing closing bracket";
1761     goto error;
1762     }
1763   }
1764 else /* single string */
1765   {
1766   if ((d=store_get(sizeof(struct String)*2))==(struct String*)0)
1767     {
1768     return -1;
1769     }
1770   m=parse_string(filter,&d[0]);
1771   if (m==-1)
1772     {
1773     return -1;
1774     }
1775   else if (m==0)
1776     {
1777     filter->pc=orig;
1778     return 0;
1779     }
1780   else
1781     {
1782     d[1].character=(uschar*)0;
1783     d[1].length=-1;
1784     *data=d;
1785     return 1;
1786     }
1787   }
1788 error:
1789 filter->errmsg=CUS "missing string list";
1790 return -1;
1791 }
1792
1793
1794 /*************************************************
1795 *    Parse an optional address part specifier    *
1796 *************************************************/
1797
1798 /*
1799 Grammar:
1800   address-part     =  ":localpart" / ":domain" / ":all"
1801   address-part     =/ ":user" / ":detail"
1802
1803 Arguments:
1804   filter      points to the Sieve filter including its state
1805   a           returns address part specified
1806
1807 Returns:      1                success
1808               0                no comparator found
1809               -1               syntax error
1810 */
1811
1812 static int parse_addresspart(struct Sieve *filter, enum AddressPart *a)
1813 {
1814 #ifdef SUBADDRESS
1815 if (parse_identifier(filter,CUS ":user")==1)
1816   {
1817   if (!filter->require_subaddress)
1818     {
1819     filter->errmsg=CUS "missing previous require \"subaddress\";";
1820     return -1;
1821     }
1822   *a=ADDRPART_USER;
1823   return 1;
1824   }
1825 else if (parse_identifier(filter,CUS ":detail")==1)
1826   {
1827   if (!filter->require_subaddress)
1828     {
1829     filter->errmsg=CUS "missing previous require \"subaddress\";";
1830     return -1;
1831     }
1832   *a=ADDRPART_DETAIL;
1833   return 1;
1834   }
1835 else
1836 #endif
1837 if (parse_identifier(filter,CUS ":localpart")==1)
1838   {
1839   *a=ADDRPART_LOCALPART;
1840   return 1;
1841   }
1842 else if (parse_identifier(filter,CUS ":domain")==1)
1843   {
1844   *a=ADDRPART_DOMAIN;
1845   return 1;
1846   }
1847 else if (parse_identifier(filter,CUS ":all")==1)
1848   {
1849   *a=ADDRPART_ALL;
1850   return 1;
1851   }
1852 else return 0;
1853 }
1854
1855
1856 /*************************************************
1857 *         Parse an optional comparator           *
1858 *************************************************/
1859
1860 /*
1861 Grammar:
1862   comparator = ":comparator" <comparator-name: string>
1863
1864 Arguments:
1865   filter      points to the Sieve filter including its state
1866   c           returns comparator
1867
1868 Returns:      1                success
1869               0                no comparator found
1870               -1               incomplete comparator found
1871 */
1872
1873 static int parse_comparator(struct Sieve *filter, enum Comparator *c)
1874 {
1875 struct String comparator_name;
1876
1877 if (parse_identifier(filter,CUS ":comparator")==0) return 0;
1878 if (parse_white(filter)==-1) return -1;
1879 switch (parse_string(filter,&comparator_name))
1880   {
1881   case -1: return -1;
1882   case 0:
1883     {
1884     filter->errmsg=CUS "missing comparator";
1885     return -1;
1886     }
1887   default:
1888     {
1889     int match;
1890
1891     if (eq_asciicase(&comparator_name,&str_ioctet,0))
1892       {
1893       *c=COMP_OCTET;
1894       match=1;
1895       }
1896     else if (eq_asciicase(&comparator_name,&str_iascii_casemap,0))
1897       {
1898       *c=COMP_EN_ASCII_CASEMAP;
1899       match=1;
1900       }
1901     else if (eq_asciicase(&comparator_name,&str_enascii_casemap,0))
1902       {
1903       *c=COMP_EN_ASCII_CASEMAP;
1904       match=1;
1905       }
1906     else if (eq_asciicase(&comparator_name,&str_iascii_numeric,0))
1907       {
1908       *c=COMP_ASCII_NUMERIC;
1909       match=1;
1910       }
1911     else
1912       {
1913       filter->errmsg=CUS "invalid comparator";
1914       match=-1;
1915       }
1916     return match;
1917     }
1918   }
1919 }
1920
1921
1922 /*************************************************
1923 *          Parse an optional match type          *
1924 *************************************************/
1925
1926 /*
1927 Grammar:
1928   match-type = ":is" / ":contains" / ":matches"
1929
1930 Arguments:
1931   filter      points to the Sieve filter including its state
1932   m           returns match type
1933
1934 Returns:      1                success
1935               0                no match type found
1936 */
1937
1938 static int parse_matchtype(struct Sieve *filter, enum MatchType *m)
1939 {
1940   if (parse_identifier(filter,CUS ":is")==1)
1941   {
1942     *m=MATCH_IS;
1943     return 1;
1944   }
1945   else if (parse_identifier(filter,CUS ":contains")==1)
1946   {
1947     *m=MATCH_CONTAINS;
1948     return 1;
1949   }
1950   else if (parse_identifier(filter,CUS ":matches")==1)
1951   {
1952     *m=MATCH_MATCHES;
1953     return 1;
1954   }
1955   else return 0;
1956 }
1957
1958
1959 /*************************************************
1960 *   Parse and interpret an optional test list    *
1961 *************************************************/
1962
1963 /*
1964 Grammar:
1965   test-list = "(" test *("," test) ")"
1966
1967 Arguments:
1968   filter      points to the Sieve filter including its state
1969   n           total number of tests
1970   num_true    number of passed tests
1971   exec        Execute parsed statements
1972
1973 Returns:      1                success
1974               0                no test list found
1975               -1               syntax or execution error
1976 */
1977
1978 static int parse_testlist(struct Sieve *filter, int *n, int *num_true, int exec)
1979 {
1980 if (parse_white(filter)==-1) return -1;
1981 if (*filter->pc=='(')
1982   {
1983   ++filter->pc;
1984   *n=0;
1985    *num_true=0;
1986   for (;;)
1987     {
1988     int cond;
1989
1990     switch (parse_test(filter,&cond,exec))
1991       {
1992       case -1: return -1;
1993       case 0: filter->errmsg=CUS "missing test"; return -1;
1994       default: ++*n; if (cond) ++*num_true; break;
1995       }
1996     if (parse_white(filter)==-1) return -1;
1997     if (*filter->pc==',') ++filter->pc;
1998     else break;
1999     }
2000   if (*filter->pc==')')
2001     {
2002     ++filter->pc;
2003     return 1;
2004     }
2005   else
2006     {
2007     filter->errmsg=CUS "missing closing paren";
2008     return -1;
2009     }
2010   }
2011 else return 0;
2012 }
2013
2014
2015 /*************************************************
2016 *     Parse and interpret an optional test       *
2017 *************************************************/
2018
2019 /*
2020 Arguments:
2021   filter      points to the Sieve filter including its state
2022   cond        returned condition status
2023   exec        Execute parsed statements
2024
2025 Returns:      1                success
2026               0                no test found
2027               -1               syntax or execution error
2028 */
2029
2030 static int parse_test(struct Sieve *filter, int *cond, int exec)
2031 {
2032 if (parse_white(filter)==-1) return -1;
2033 if (parse_identifier(filter,CUS "address"))
2034   {
2035   /*
2036   address-test = "address" { [address-part] [comparator] [match-type] }
2037                  <header-list: string-list> <key-list: string-list>
2038
2039   header-list From, To, Cc, Bcc, Sender, Resent-From, Resent-To
2040   */
2041
2042   enum AddressPart addressPart=ADDRPART_ALL;
2043   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2044   enum MatchType matchType=MATCH_IS;
2045   struct String *hdr,*h,*key,*k;
2046   int m;
2047   int ap=0,co=0,mt=0;
2048
2049   for (;;)
2050     {
2051     if (parse_white(filter)==-1) return -1;
2052     if ((m=parse_addresspart(filter,&addressPart))!=0)
2053       {
2054       if (m==-1) return -1;
2055       if (ap)
2056         {
2057         filter->errmsg=CUS "address part already specified";
2058         return -1;
2059         }
2060       else ap=1;
2061       }
2062     else if ((m=parse_comparator(filter,&comparator))!=0)
2063       {
2064       if (m==-1) return -1;
2065       if (co)
2066         {
2067         filter->errmsg=CUS "comparator already specified";
2068         return -1;
2069         }
2070       else co=1;
2071       }
2072     else if ((m=parse_matchtype(filter,&matchType))!=0)
2073       {
2074       if (m==-1) return -1;
2075       if (mt)
2076         {
2077         filter->errmsg=CUS "match type already specified";
2078         return -1;
2079         }
2080       else mt=1;
2081       }
2082     else break;
2083     }
2084   if (parse_white(filter)==-1) return -1;
2085   if ((m=parse_stringlist(filter,&hdr))!=1)
2086     {
2087     if (m==0) filter->errmsg=CUS "header string list expected";
2088     return -1;
2089     }
2090   if (parse_white(filter)==-1) return -1;
2091   if ((m=parse_stringlist(filter,&key))!=1)
2092     {
2093     if (m==0) filter->errmsg=CUS "key string list expected";
2094     return -1;
2095     }
2096   *cond=0;
2097   for (h=hdr; h->length!=-1 && !*cond; ++h)
2098     {
2099     uschar *header_value=(uschar*)0,*extracted_addr,*end_addr;
2100
2101     if
2102       (
2103       !eq_asciicase(h,&str_from,0)
2104       && !eq_asciicase(h,&str_to,0)
2105       && !eq_asciicase(h,&str_cc,0)
2106       && !eq_asciicase(h,&str_bcc,0)
2107       && !eq_asciicase(h,&str_sender,0)
2108       && !eq_asciicase(h,&str_resent_from,0)
2109       && !eq_asciicase(h,&str_resent_to,0)
2110       )
2111       {
2112       filter->errmsg=CUS "invalid header field";
2113       return -1;
2114       }
2115     if (exec)
2116       {
2117       /* We are only interested in addresses below, so no MIME decoding */
2118       header_value=expand_string(string_sprintf("$rheader_%s",quote(h)));
2119       if (header_value == NULL)
2120         {
2121         filter->errmsg=CUS "header string expansion failed";
2122         return -1;
2123         }
2124       parse_allow_group = TRUE;
2125       while (*header_value && !*cond)
2126         {
2127         uschar *error;
2128         int start, end, domain;
2129         int saveend;
2130         uschar *part=NULL;
2131
2132         end_addr = parse_find_address_end(header_value, FALSE);
2133         saveend = *end_addr;
2134         *end_addr = 0;
2135         extracted_addr = parse_extract_address(header_value, &error, &start, &end, &domain, FALSE);
2136
2137         if (extracted_addr) switch (addressPart)
2138           {
2139           case ADDRPART_ALL: part=extracted_addr; break;
2140 #ifdef SUBADDRESS
2141           case ADDRPART_USER:
2142 #endif
2143           case ADDRPART_LOCALPART: part=extracted_addr; part[domain-1]='\0'; break;
2144           case ADDRPART_DOMAIN: part=extracted_addr+domain; break;
2145 #ifdef SUBADDRESS
2146           case ADDRPART_DETAIL: part=NULL; break;
2147 #endif
2148           }
2149
2150         *end_addr = saveend;
2151         if (part)
2152           {
2153           for (k=key; k->length!=-1; ++k)
2154             {
2155             struct String partStr;
2156
2157             partStr.character=part;
2158             partStr.length=Ustrlen(part);
2159             if (extracted_addr)
2160               {
2161               *cond=compare(filter,k,&partStr,comparator,matchType);
2162               if (*cond==-1) return -1;
2163               if (*cond) break;
2164               }
2165             }
2166           }
2167         if (saveend == 0) break;
2168         header_value = end_addr + 1;
2169         }
2170       parse_allow_group = FALSE;
2171       parse_found_group = FALSE;
2172       }
2173     }
2174   return 1;
2175   }
2176 else if (parse_identifier(filter,CUS "allof"))
2177   {
2178   /*
2179   allof-test   = "allof" <tests: test-list>
2180   */
2181
2182   int n,num_true;
2183
2184   switch (parse_testlist(filter,&n,&num_true,exec))
2185     {
2186     case -1: return -1;
2187     case 0: filter->errmsg=CUS "missing test list"; return -1;
2188     default: *cond=(n==num_true); return 1;
2189     }
2190   }
2191 else if (parse_identifier(filter,CUS "anyof"))
2192   {
2193   /*
2194   anyof-test   = "anyof" <tests: test-list>
2195   */
2196
2197   int n,num_true;
2198
2199   switch (parse_testlist(filter,&n,&num_true,exec))
2200     {
2201     case -1: return -1;
2202     case 0: filter->errmsg=CUS "missing test list"; return -1;
2203     default: *cond=(num_true>0); return 1;
2204     }
2205   }
2206 else if (parse_identifier(filter,CUS "exists"))
2207   {
2208   /*
2209   exists-test = "exists" <header-names: string-list>
2210   */
2211
2212   struct String *hdr,*h;
2213   int m;
2214
2215   if (parse_white(filter)==-1) return -1;
2216   if ((m=parse_stringlist(filter,&hdr))!=1)
2217     {
2218     if (m==0) filter->errmsg=CUS "header string list expected";
2219     return -1;
2220     }
2221   if (exec)
2222     {
2223     *cond=1;
2224     for (h=hdr; h->length!=-1 && *cond; ++h)
2225       {
2226       uschar *header_def;
2227
2228       header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
2229       if (header_def == NULL)
2230         {
2231         filter->errmsg=CUS "header string expansion failed";
2232         return -1;
2233         }
2234       if (Ustrcmp(header_def,"false")==0) *cond=0;
2235       }
2236     }
2237   return 1;
2238   }
2239 else if (parse_identifier(filter,CUS "false"))
2240   {
2241   /*
2242   false-test = "false"
2243   */
2244
2245   *cond=0;
2246   return 1;
2247   }
2248 else if (parse_identifier(filter,CUS "header"))
2249   {
2250   /*
2251   header-test = "header" { [comparator] [match-type] }
2252                 <header-names: string-list> <key-list: string-list>
2253   */
2254
2255   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2256   enum MatchType matchType=MATCH_IS;
2257   struct String *hdr,*h,*key,*k;
2258   int m;
2259   int co=0,mt=0;
2260
2261   for (;;)
2262     {
2263     if (parse_white(filter)==-1) return -1;
2264     if ((m=parse_comparator(filter,&comparator))!=0)
2265       {
2266       if (m==-1) return -1;
2267       if (co)
2268         {
2269         filter->errmsg=CUS "comparator already specified";
2270         return -1;
2271         }
2272       else co=1;
2273       }
2274     else if ((m=parse_matchtype(filter,&matchType))!=0)
2275       {
2276       if (m==-1) return -1;
2277       if (mt)
2278         {
2279         filter->errmsg=CUS "match type already specified";
2280         return -1;
2281         }
2282       else mt=1;
2283       }
2284     else break;
2285     }
2286   if (parse_white(filter)==-1) return -1;
2287   if ((m=parse_stringlist(filter,&hdr))!=1)
2288     {
2289     if (m==0) filter->errmsg=CUS "header string list expected";
2290     return -1;
2291     }
2292   if (parse_white(filter)==-1) return -1;
2293   if ((m=parse_stringlist(filter,&key))!=1)
2294     {
2295     if (m==0) filter->errmsg=CUS "key string list expected";
2296     return -1;
2297     }
2298   *cond=0;
2299   for (h=hdr; h->length!=-1 && !*cond; ++h)
2300     {
2301     if (!is_header(h))
2302       {
2303       filter->errmsg=CUS "invalid header field";
2304       return -1;
2305       }
2306     if (exec)
2307       {
2308       struct String header_value;
2309       uschar *header_def;
2310
2311       expand_header(&header_value,h);
2312       header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
2313       if (header_value.character == NULL || header_def == NULL)
2314         {
2315         filter->errmsg=CUS "header string expansion failed";
2316         return -1;
2317         }
2318       for (k=key; k->length!=-1; ++k)
2319         {
2320         if (Ustrcmp(header_def,"true")==0)
2321           {
2322           *cond=compare(filter,k,&header_value,comparator,matchType);
2323           if (*cond==-1) return -1;
2324           if (*cond) break;
2325           }
2326         }
2327       }
2328     }
2329   return 1;
2330   }
2331 else if (parse_identifier(filter,CUS "not"))
2332   {
2333   if (parse_white(filter)==-1) return -1;
2334   switch (parse_test(filter,cond,exec))
2335     {
2336     case -1: return -1;
2337     case 0: filter->errmsg=CUS "missing test"; return -1;
2338     default: *cond=!*cond; return 1;
2339     }
2340   }
2341 else if (parse_identifier(filter,CUS "size"))
2342   {
2343   /*
2344   relop = ":over" / ":under"
2345   size-test = "size" relop <limit: number>
2346   */
2347
2348   unsigned long limit;
2349   int overNotUnder;
2350
2351   if (parse_white(filter)==-1) return -1;
2352   if (parse_identifier(filter,CUS ":over")) overNotUnder=1;
2353   else if (parse_identifier(filter,CUS ":under")) overNotUnder=0;
2354   else
2355     {
2356     filter->errmsg=CUS "missing :over or :under";
2357     return -1;
2358     }
2359   if (parse_white(filter)==-1) return -1;
2360   if (parse_number(filter,&limit)==-1) return -1;
2361   *cond=(overNotUnder ? (message_size>limit) : (message_size<limit));
2362   return 1;
2363   }
2364 else if (parse_identifier(filter,CUS "true"))
2365   {
2366   *cond=1;
2367   return 1;
2368   }
2369 else if (parse_identifier(filter,CUS "envelope"))
2370   {
2371   /*
2372   envelope-test = "envelope" { [comparator] [address-part] [match-type] }
2373                   <envelope-part: string-list> <key-list: string-list>
2374
2375   envelope-part is case insensitive "from" or "to"
2376 #ifdef ENVELOPE_AUTH
2377   envelope-part =/ "auth"
2378 #endif
2379   */
2380
2381   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2382   enum AddressPart addressPart=ADDRPART_ALL;
2383   enum MatchType matchType=MATCH_IS;
2384   struct String *env,*e,*key,*k;
2385   int m;
2386   int co=0,ap=0,mt=0;
2387
2388   if (!filter->require_envelope)
2389     {
2390     filter->errmsg=CUS "missing previous require \"envelope\";";
2391     return -1;
2392     }
2393   for (;;)
2394     {
2395     if (parse_white(filter)==-1) return -1;
2396     if ((m=parse_comparator(filter,&comparator))!=0)
2397       {
2398       if (m==-1) return -1;
2399       if (co)
2400         {
2401         filter->errmsg=CUS "comparator already specified";
2402         return -1;
2403         }
2404       else co=1;
2405       }
2406     else if ((m=parse_addresspart(filter,&addressPart))!=0)
2407       {
2408       if (m==-1) return -1;
2409       if (ap)
2410         {
2411         filter->errmsg=CUS "address part already specified";
2412         return -1;
2413         }
2414       else ap=1;
2415       }
2416     else if ((m=parse_matchtype(filter,&matchType))!=0)
2417       {
2418       if (m==-1) return -1;
2419       if (mt)
2420         {
2421         filter->errmsg=CUS "match type already specified";
2422         return -1;
2423         }
2424       else mt=1;
2425       }
2426     else break;
2427     }
2428   if (parse_white(filter)==-1) return -1;
2429   if ((m=parse_stringlist(filter,&env))!=1)
2430     {
2431     if (m==0) filter->errmsg=CUS "envelope string list expected";
2432     return -1;
2433     }
2434   if (parse_white(filter)==-1) return -1;
2435   if ((m=parse_stringlist(filter,&key))!=1)
2436     {
2437     if (m==0) filter->errmsg=CUS "key string list expected";
2438     return -1;
2439     }
2440   *cond=0;
2441   for (e=env; e->length!=-1 && !*cond; ++e)
2442     {
2443     const uschar *envelopeExpr=CUS 0;
2444     uschar *envelope=US 0;
2445
2446     if (eq_asciicase(e,&str_from,0))
2447       {
2448       switch (addressPart)
2449         {
2450         case ADDRPART_ALL: envelopeExpr=CUS "$sender_address"; break;
2451 #ifdef SUBADDRESS
2452         case ADDRPART_USER:
2453 #endif
2454         case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$sender_address}"; break;
2455         case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$sender_address}"; break;
2456 #ifdef SUBADDRESS
2457         case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2458 #endif
2459         }
2460       }
2461     else if (eq_asciicase(e,&str_to,0))
2462       {
2463       switch (addressPart)
2464         {
2465         case ADDRPART_ALL: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix@$domain"; break;
2466 #ifdef SUBADDRESS
2467         case ADDRPART_USER: envelopeExpr=filter->useraddress; break;
2468         case ADDRPART_DETAIL: envelopeExpr=filter->subaddress; break;
2469 #endif
2470         case ADDRPART_LOCALPART: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix"; break;
2471         case ADDRPART_DOMAIN: envelopeExpr=CUS "$domain"; break;
2472         }
2473       }
2474 #ifdef ENVELOPE_AUTH
2475     else if (eq_asciicase(e,&str_auth,0))
2476       {
2477       switch (addressPart)
2478         {
2479         case ADDRPART_ALL: envelopeExpr=CUS "$authenticated_sender"; break;
2480 #ifdef SUBADDRESS
2481         case ADDRPART_USER:
2482 #endif
2483         case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$authenticated_sender}"; break;
2484         case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$authenticated_sender}"; break;
2485 #ifdef SUBADDRESS
2486         case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2487 #endif
2488         }
2489       }
2490 #endif
2491     else
2492       {
2493       filter->errmsg=CUS "invalid envelope string";
2494       return -1;
2495       }
2496     if (exec && envelopeExpr)
2497       {
2498       if ((envelope=expand_string(US envelopeExpr)) == NULL)
2499         {
2500         filter->errmsg=CUS "header string expansion failed";
2501         return -1;
2502         }
2503       for (k=key; k->length!=-1; ++k)
2504         {
2505         struct String envelopeStr;
2506
2507         envelopeStr.character=envelope;
2508         envelopeStr.length=Ustrlen(envelope);
2509         *cond=compare(filter,k,&envelopeStr,comparator,matchType);
2510         if (*cond==-1) return -1;
2511         if (*cond) break;
2512         }
2513       }
2514     }
2515   return 1;
2516   }
2517 #ifdef ENOTIFY
2518 else if (parse_identifier(filter,CUS "valid_notify_method"))
2519   {
2520   /*
2521   valid_notify_method = "valid_notify_method"
2522                         <notification-uris: string-list>
2523   */
2524
2525   struct String *uris,*u;
2526   int m;
2527
2528   if (!filter->require_enotify)
2529     {
2530     filter->errmsg=CUS "missing previous require \"enotify\";";
2531     return -1;
2532     }
2533   if (parse_white(filter)==-1) return -1;
2534   if ((m=parse_stringlist(filter,&uris))!=1)
2535     {
2536     if (m==0) filter->errmsg=CUS "URI string list expected";
2537     return -1;
2538     }
2539   if (exec)
2540     {
2541     *cond=1;
2542     for (u=uris; u->length!=-1 && *cond; ++u)
2543       {
2544         string_item *recipient;
2545         struct String header,subject,body;
2546
2547         recipient=NULL;
2548         header.length=-1;
2549         header.character=(uschar*)0;
2550         subject.length=-1;
2551         subject.character=(uschar*)0;
2552         body.length=-1;
2553         body.character=(uschar*)0;
2554         if (parse_mailto_uri(filter,u->character,&recipient,&header,&subject,&body)!=1)
2555           *cond=0;
2556       }
2557     }
2558   return 1;
2559   }
2560 else if (parse_identifier(filter,CUS "notify_method_capability"))
2561   {
2562   /*
2563   notify_method_capability = "notify_method_capability" [COMPARATOR] [MATCH-TYPE]
2564                              <notification-uri: string>
2565                              <notification-capability: string>
2566                              <key-list: string-list>
2567   */
2568
2569   int m;
2570   int co=0,mt=0;
2571
2572   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2573   enum MatchType matchType=MATCH_IS;
2574   struct String uri,capa,*keys,*k;
2575
2576   if (!filter->require_enotify)
2577     {
2578     filter->errmsg=CUS "missing previous require \"enotify\";";
2579     return -1;
2580     }
2581   for (;;)
2582     {
2583     if (parse_white(filter)==-1) return -1;
2584     if ((m=parse_comparator(filter,&comparator))!=0)
2585       {
2586       if (m==-1) return -1;
2587       if (co)
2588         {
2589         filter->errmsg=CUS "comparator already specified";
2590         return -1;
2591         }
2592       else co=1;
2593       }
2594     else if ((m=parse_matchtype(filter,&matchType))!=0)
2595       {
2596       if (m==-1) return -1;
2597       if (mt)
2598         {
2599         filter->errmsg=CUS "match type already specified";
2600         return -1;
2601         }
2602       else mt=1;
2603       }
2604     else break;
2605     }
2606     if ((m=parse_string(filter,&uri))!=1)
2607       {
2608       if (m==0) filter->errmsg=CUS "missing notification URI string";
2609       return -1;
2610       }
2611     if (parse_white(filter)==-1) return -1;
2612     if ((m=parse_string(filter,&capa))!=1)
2613       {
2614       if (m==0) filter->errmsg=CUS "missing notification capability string";
2615       return -1;
2616       }
2617     if (parse_white(filter)==-1) return -1;
2618     if ((m=parse_stringlist(filter,&keys))!=1)
2619       {
2620       if (m==0) filter->errmsg=CUS "missing key string list";
2621       return -1;
2622       }
2623     if (exec)
2624       {
2625       string_item *recipient;
2626       struct String header,subject,body;
2627
2628       *cond=0;
2629       recipient=NULL;
2630       header.length=-1;
2631       header.character=(uschar*)0;
2632       subject.length=-1;
2633       subject.character=(uschar*)0;
2634       body.length=-1;
2635       body.character=(uschar*)0;
2636       if (parse_mailto_uri(filter,uri.character,&recipient,&header,&subject,&body)==1)
2637         {
2638         if (eq_asciicase(&capa,&str_online,0)==1)
2639           for (k=keys; k->length!=-1; ++k)
2640             {
2641             *cond=compare(filter,k,&str_maybe,comparator,matchType);
2642             if (*cond==-1) return -1;
2643             if (*cond) break;
2644             }
2645         }
2646       }
2647     return 1;
2648   }
2649 #endif
2650 else return 0;
2651 }
2652
2653
2654 /*************************************************
2655 *     Parse and interpret an optional block      *
2656 *************************************************/
2657
2658 /*
2659 Arguments:
2660   filter      points to the Sieve filter including its state
2661   exec        Execute parsed statements
2662   generated   where to hang newly-generated addresses
2663
2664 Returns:      2                success by stop
2665               1                other success
2666               0                no block command found
2667               -1               syntax or execution error
2668 */
2669
2670 static int parse_block(struct Sieve *filter, int exec,
2671   address_item **generated)
2672 {
2673 int r;
2674
2675 if (parse_white(filter)==-1) return -1;
2676 if (*filter->pc=='{')
2677   {
2678   ++filter->pc;
2679   if ((r=parse_commands(filter,exec,generated))==-1 || r==2) return r;
2680   if (*filter->pc=='}')
2681     {
2682     ++filter->pc;
2683     return 1;
2684     }
2685   else
2686     {
2687     filter->errmsg=CUS "expecting command or closing brace";
2688     return -1;
2689     }
2690   }
2691 else return 0;
2692 }
2693
2694
2695 /*************************************************
2696 *           Match a semicolon                    *
2697 *************************************************/
2698
2699 /*
2700 Arguments:
2701   filter      points to the Sieve filter including its state
2702
2703 Returns:      1                success
2704               -1               syntax error
2705 */
2706
2707 static int parse_semicolon(struct Sieve *filter)
2708 {
2709   if (parse_white(filter)==-1) return -1;
2710   if (*filter->pc==';')
2711   {
2712     ++filter->pc;
2713     return 1;
2714   }
2715   else
2716   {
2717     filter->errmsg=CUS "missing semicolon";
2718     return -1;
2719   }
2720 }
2721
2722
2723 /*************************************************
2724 *     Parse and interpret a Sieve command        *
2725 *************************************************/
2726
2727 /*
2728 Arguments:
2729   filter      points to the Sieve filter including its state
2730   exec        Execute parsed statements
2731   generated   where to hang newly-generated addresses
2732
2733 Returns:      2                success by stop
2734               1                other success
2735               -1               syntax or execution error
2736 */
2737 static int
2738 parse_commands(struct Sieve *filter, int exec, address_item **generated)
2739 {
2740 while (*filter->pc)
2741   {
2742   if (parse_white(filter)==-1) return -1;
2743   if (parse_identifier(filter,CUS "if"))
2744     {
2745     /*
2746     if-command = "if" test block *( "elsif" test block ) [ else block ]
2747     */
2748
2749     int cond,m,unsuccessful;
2750
2751     /* test block */
2752     if (parse_white(filter)==-1) return -1;
2753     if ((m=parse_test(filter,&cond,exec))==-1) return -1;
2754     if (m==0)
2755       {
2756       filter->errmsg=CUS "missing test";
2757       return -1;
2758       }
2759     if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2760         (debug_selector & D_filter) != 0)
2761       {
2762       if (exec) debug_printf("if %s\n",cond?"true":"false");
2763       }
2764     m=parse_block(filter,exec ? cond : 0, generated);
2765     if (m==-1 || m==2) return m;
2766     if (m==0)
2767       {
2768       filter->errmsg=CUS "missing block";
2769       return -1;
2770       }
2771     unsuccessful = !cond;
2772     for (;;) /* elsif test block */
2773       {
2774       if (parse_white(filter)==-1) return -1;
2775       if (parse_identifier(filter,CUS "elsif"))
2776         {
2777         if (parse_white(filter)==-1) return -1;
2778         m=parse_test(filter,&cond,exec && unsuccessful);
2779         if (m==-1 || m==2) return m;
2780         if (m==0)
2781           {
2782           filter->errmsg=CUS "missing test";
2783           return -1;
2784           }
2785         if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2786             (debug_selector & D_filter) != 0)
2787           {
2788           if (exec) debug_printf("elsif %s\n",cond?"true":"false");
2789           }
2790         m=parse_block(filter,exec && unsuccessful ? cond : 0, generated);
2791         if (m==-1 || m==2) return m;
2792         if (m==0)
2793           {
2794           filter->errmsg=CUS "missing block";
2795           return -1;
2796           }
2797         if (exec && unsuccessful && cond) unsuccessful = 0;
2798         }
2799       else break;
2800       }
2801     /* else block */
2802     if (parse_white(filter)==-1) return -1;
2803     if (parse_identifier(filter,CUS "else"))
2804       {
2805       m=parse_block(filter,exec && unsuccessful, generated);
2806       if (m==-1 || m==2) return m;
2807       if (m==0)
2808         {
2809         filter->errmsg=CUS "missing block";
2810         return -1;
2811         }
2812       }
2813     }
2814   else if (parse_identifier(filter,CUS "stop"))
2815     {
2816     /*
2817     stop-command     =  "stop" { stop-options } ";"
2818     stop-options     =
2819     */
2820
2821     if (parse_semicolon(filter)==-1) return -1;
2822     if (exec)
2823       {
2824       filter->pc+=Ustrlen(filter->pc);
2825       return 2;
2826       }
2827     }
2828   else if (parse_identifier(filter,CUS "keep"))
2829     {
2830     /*
2831     keep-command     =  "keep" { keep-options } ";"
2832     keep-options     =
2833     */
2834
2835     if (parse_semicolon(filter)==-1) return -1;
2836     if (exec)
2837       {
2838       add_addr(generated,US"inbox",1,0,0,0);
2839       filter->keep = 0;
2840       }
2841     }
2842   else if (parse_identifier(filter,CUS "discard"))
2843     {
2844     /*
2845     discard-command  =  "discard" { discard-options } ";"
2846     discard-options  =
2847     */
2848
2849     if (parse_semicolon(filter)==-1) return -1;
2850     if (exec) filter->keep=0;
2851     }
2852   else if (parse_identifier(filter,CUS "redirect"))
2853     {
2854     /*
2855     redirect-command =  "redirect" redirect-options "string" ";"
2856     redirect-options =
2857     redirect-options =) ":copy"
2858     */
2859
2860     struct String recipient;
2861     int m;
2862     int copy=0;
2863
2864     for (;;)
2865       {
2866       if (parse_white(filter)==-1) return -1;
2867       if (parse_identifier(filter,CUS ":copy")==1)
2868         {
2869         if (!filter->require_copy)
2870           {
2871           filter->errmsg=CUS "missing previous require \"copy\";";
2872           return -1;
2873           }
2874           copy=1;
2875         }
2876       else break;
2877       }
2878     if (parse_white(filter)==-1) return -1;
2879     if ((m=parse_string(filter,&recipient))!=1)
2880       {
2881       if (m==0) filter->errmsg=CUS "missing redirect recipient string";
2882       return -1;
2883       }
2884     if (strchr(CCS recipient.character,'@')==(char*)0)
2885       {
2886       filter->errmsg=CUS "unqualified recipient address";
2887       return -1;
2888       }
2889     if (exec)
2890       {
2891       add_addr(generated,recipient.character,0,0,0,0);
2892       if (!copy) filter->keep = 0;
2893       }
2894     if (parse_semicolon(filter)==-1) return -1;
2895     }
2896   else if (parse_identifier(filter,CUS "fileinto"))
2897     {
2898     /*
2899     fileinto-command =  "fileinto" { fileinto-options } string ";"
2900     fileinto-options =
2901     fileinto-options =) [ ":copy" ]
2902     */
2903
2904     struct String folder;
2905     uschar *s;
2906     int m;
2907     unsigned long maxage, maxmessages, maxstorage;
2908     int copy=0;
2909
2910     maxage = maxmessages = maxstorage = 0;
2911     if (!filter->require_fileinto)
2912       {
2913       filter->errmsg=CUS "missing previous require \"fileinto\";";
2914       return -1;
2915       }
2916     for (;;)
2917       {
2918       if (parse_white(filter)==-1) return -1;
2919       if (parse_identifier(filter,CUS ":copy")==1)
2920         {
2921         if (!filter->require_copy)
2922           {
2923           filter->errmsg=CUS "missing previous require \"copy\";";
2924           return -1;
2925           }
2926           copy=1;
2927         }
2928       else break;
2929       }
2930     if (parse_white(filter)==-1) return -1;
2931     if ((m=parse_string(filter,&folder))!=1)
2932       {
2933       if (m==0) filter->errmsg=CUS "missing fileinto folder string";
2934       return -1;
2935       }
2936     m=0; s=folder.character;
2937     if (folder.length==0) m=1;
2938     if (Ustrcmp(s,"..")==0 || Ustrncmp(s,"../",3)==0) m=1;
2939     else while (*s)
2940       {
2941       if (Ustrcmp(s,"/..")==0 || Ustrncmp(s,"/../",4)==0) { m=1; break; }
2942       ++s;
2943       }
2944     if (m)
2945       {
2946       filter->errmsg=CUS "invalid folder";
2947       return -1;
2948       }
2949     if (exec)
2950       {
2951       add_addr(generated, folder.character, 1, maxage, maxmessages, maxstorage);
2952       if (!copy) filter->keep = 0;
2953       }
2954     if (parse_semicolon(filter)==-1) return -1;
2955     }
2956 #ifdef ENOTIFY
2957   else if (parse_identifier(filter,CUS "notify"))
2958     {
2959     /*
2960     notify-command =  "notify" { notify-options } <method: string> ";"
2961     notify-options =  [":from" string]
2962                       [":importance" <"1" / "2" / "3">]
2963                       [":options" 1*(string-list / number)]
2964                       [":message" string]
2965     */
2966
2967     int m;
2968     struct String from;
2969     struct String importance;
2970     struct String message;
2971     struct String method;
2972     struct Notification *already;
2973     string_item *recipient;
2974     struct String header;
2975     struct String subject;
2976     struct String body;
2977     uschar *envelope_from;
2978     struct String auto_submitted_value;
2979     uschar *auto_submitted_def;
2980
2981     if (!filter->require_enotify)
2982       {
2983       filter->errmsg=CUS "missing previous require \"enotify\";";
2984       return -1;
2985       }
2986     from.character=(uschar*)0;
2987     from.length=-1;
2988     importance.character=(uschar*)0;
2989     importance.length=-1;
2990     message.character=(uschar*)0;
2991     message.length=-1;
2992     recipient=NULL;
2993     header.length=-1;
2994     header.character=(uschar*)0;
2995     subject.length=-1;
2996     subject.character=(uschar*)0;
2997     body.length=-1;
2998     body.character=(uschar*)0;
2999     envelope_from=(sender_address && sender_address[0]) ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : US "";
3000     for (;;)
3001       {
3002       if (parse_white(filter)==-1) return -1;
3003       if (parse_identifier(filter,CUS ":from")==1)
3004         {
3005         if (parse_white(filter)==-1) return -1;
3006         if ((m=parse_string(filter,&from))!=1)
3007           {
3008           if (m==0) filter->errmsg=CUS "from string expected";
3009           return -1;
3010           }
3011         }
3012       else if (parse_identifier(filter,CUS ":importance")==1)
3013         {
3014         if (parse_white(filter)==-1) return -1;
3015         if ((m=parse_string(filter,&importance))!=1)
3016           {
3017           if (m==0) filter->errmsg=CUS "importance string expected";
3018           return -1;
3019           }
3020         if (importance.length!=1 || importance.character[0]<'1' || importance.character[0]>'3')
3021           {
3022           filter->errmsg=CUS "invalid importance";
3023           return -1;
3024           }
3025         }
3026       else if (parse_identifier(filter,CUS ":options")==1)
3027         {
3028         if (parse_white(filter)==-1) return -1;
3029         }
3030       else if (parse_identifier(filter,CUS ":message")==1)
3031         {
3032         if (parse_white(filter)==-1) return -1;
3033         if ((m=parse_string(filter,&message))!=1)
3034           {
3035           if (m==0) filter->errmsg=CUS "message string expected";
3036           return -1;
3037           }
3038         }
3039       else break;
3040       }
3041     if (parse_white(filter)==-1) return -1;
3042     if ((m=parse_string(filter,&method))!=1)
3043       {
3044       if (m==0) filter->errmsg=CUS "missing method string";
3045       return -1;
3046       }
3047     if (parse_semicolon(filter)==-1) return -1;
3048     if (parse_mailto_uri(filter,method.character,&recipient,&header,&subject,&body)!=1)
3049       return -1;
3050     if (exec)
3051       {
3052       if (message.length==-1) message=subject;
3053       if (message.length==-1) expand_header(&message,&str_subject);
3054       expand_header(&auto_submitted_value,&str_auto_submitted);
3055       auto_submitted_def=expand_string(string_sprintf("${if def:header_auto-submitted {true}{false}}"));
3056       if (auto_submitted_value.character == NULL || auto_submitted_def == NULL)
3057         {
3058         filter->errmsg=CUS "header string expansion failed";
3059         return -1;
3060         }
3061         if (Ustrcmp(auto_submitted_def,"true")!=0 || Ustrcmp(auto_submitted_value.character,"no")==0)
3062         {
3063         for (already=filter->notified; already; already=already->next)
3064           {
3065           if (already->method.length==method.length
3066               && (method.length==-1 || Ustrcmp(already->method.character,method.character)==0)
3067               && already->importance.length==importance.length
3068               && (importance.length==-1 || Ustrcmp(already->importance.character,importance.character)==0)
3069               && already->message.length==message.length
3070               && (message.length==-1 || Ustrcmp(already->message.character,message.character)==0))
3071             break;
3072           }
3073         if (already==(struct Notification*)0)
3074           /* New notification, process it */
3075           {
3076           struct Notification *sent;
3077           sent=store_get(sizeof(struct Notification));
3078           sent->method=method;
3079           sent->importance=importance;
3080           sent->message=message;
3081           sent->next=filter->notified;
3082           filter->notified=sent;
3083   #ifndef COMPILE_SYNTAX_CHECKER
3084           if (filter_test == FTEST_NONE)
3085             {
3086             string_item *p;
3087             int pid,fd;
3088
3089             if ((pid = child_open_exim2(&fd,envelope_from,envelope_from))>=1)
3090               {
3091               FILE *f;
3092               uschar *buffer;
3093               int buffer_capacity;
3094
3095               f = fdopen(fd, "wb");
3096               fprintf(f,"From: %s\n",from.length==-1 ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : from.character);
3097               for (p=recipient; p; p=p->next) fprintf(f,"To: %s\n",p->text);
3098               fprintf(f,"Auto-Submitted: auto-notified; %s\n",filter->enotify_mailto_owner);
3099               if (header.length>0) fprintf(f,"%s",header.character);
3100               if (message.length==-1)
3101                 {
3102                 message.character=US"Notification";
3103                 message.length=Ustrlen(message.character);
3104                 }
3105               /* Allocation is larger than neccessary, but enough even for split MIME words */
3106               buffer_capacity=32+4*message.length;
3107               buffer=store_get(buffer_capacity);
3108               if (message.length!=-1) fprintf(f,"Subject: %s\n",parse_quote_2047(message.character, message.length, US"utf-8", buffer, buffer_capacity, TRUE));
3109               fprintf(f,"\n");
3110               if (body.length>0) fprintf(f,"%s\n",body.character);
3111               fflush(f);
3112               (void)fclose(f);
3113               (void)child_close(pid, 0);
3114               }
3115             }
3116           if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3117             {
3118             debug_printf("Notification to `%s': '%s'.\n",method.character,message.length!=-1 ? message.character : CUS "");
3119             }
3120 #endif
3121           }
3122         else
3123           {
3124           if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3125             {
3126             debug_printf("Repeated notification to `%s' ignored.\n",method.character);
3127             }
3128           }
3129         }
3130       else
3131         {
3132         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3133           {
3134           debug_printf("Ignoring notification, triggering message contains Auto-submitted: field.\n");
3135           }
3136         }
3137       }
3138     }
3139 #endif
3140 #ifdef VACATION
3141   else if (parse_identifier(filter,CUS "vacation"))
3142     {
3143     /*
3144     vacation-command =  "vacation" { vacation-options } <reason: string> ";"
3145     vacation-options =  [":days" number]
3146                         [":subject" string]
3147                         [":from" string]
3148                         [":addresses" string-list]
3149                         [":mime"]
3150                         [":handle" string]
3151     */
3152
3153     int m;
3154     unsigned long days;
3155     struct String subject;
3156     struct String from;
3157     struct String *addresses;
3158     int reason_is_mime;
3159     string_item *aliases;
3160     struct String handle;
3161     struct String reason;
3162
3163     if (!filter->require_vacation)
3164       {
3165       filter->errmsg=CUS "missing previous require \"vacation\";";
3166       return -1;
3167       }
3168     if (exec)
3169       {
3170       if (filter->vacation_ran)
3171         {
3172         filter->errmsg=CUS "trying to execute vacation more than once";
3173         return -1;
3174         }
3175       filter->vacation_ran=1;
3176       }
3177     days=VACATION_MIN_DAYS>7 ? VACATION_MIN_DAYS : 7;
3178     subject.character=(uschar*)0;
3179     subject.length=-1;
3180     from.character=(uschar*)0;
3181     from.length=-1;
3182     addresses=(struct String*)0;
3183     aliases=NULL;
3184     reason_is_mime=0;
3185     handle.character=(uschar*)0;
3186     handle.length=-1;
3187     for (;;)
3188       {
3189       if (parse_white(filter)==-1) return -1;
3190       if (parse_identifier(filter,CUS ":days")==1)
3191         {
3192         if (parse_white(filter)==-1) return -1;
3193         if (parse_number(filter,&days)==-1) return -1;
3194         if (days<VACATION_MIN_DAYS) days=VACATION_MIN_DAYS;
3195         else if (days>VACATION_MAX_DAYS) days=VACATION_MAX_DAYS;
3196         }
3197       else if (parse_identifier(filter,CUS ":subject")==1)
3198         {
3199         if (parse_white(filter)==-1) return -1;
3200         if ((m=parse_string(filter,&subject))!=1)
3201           {
3202           if (m==0) filter->errmsg=CUS "subject string expected";
3203           return -1;
3204           }
3205         }
3206       else if (parse_identifier(filter,CUS ":from")==1)
3207         {
3208         if (parse_white(filter)==-1) return -1;
3209         if ((m=parse_string(filter,&from))!=1)
3210           {
3211           if (m==0) filter->errmsg=CUS "from string expected";
3212           return -1;
3213           }
3214         if (check_mail_address(filter,&from)!=1)
3215           return -1;
3216         }
3217       else if (parse_identifier(filter,CUS ":addresses")==1)
3218         {
3219         struct String *a;
3220
3221         if (parse_white(filter)==-1) return -1;
3222         if ((m=parse_stringlist(filter,&addresses))!=1)
3223           {
3224           if (m==0) filter->errmsg=CUS "addresses string list expected";
3225           return -1;
3226           }
3227         for (a=addresses; a->length!=-1; ++a)
3228           {
3229           string_item *new;
3230
3231           new=store_get(sizeof(string_item));
3232           new->text=store_get(a->length+1);
3233           if (a->length) memcpy(new->text,a->character,a->length);
3234           new->text[a->length]='\0';
3235           new->next=aliases;
3236           aliases=new;
3237           }
3238         }
3239       else if (parse_identifier(filter,CUS ":mime")==1)
3240         reason_is_mime=1;
3241       else if (parse_identifier(filter,CUS ":handle")==1)
3242         {
3243         if (parse_white(filter)==-1) return -1;
3244         if ((m=parse_string(filter,&from))!=1)
3245           {
3246           if (m==0) filter->errmsg=CUS "handle string expected";
3247           return -1;
3248           }
3249         }
3250       else break;
3251       }
3252     if (parse_white(filter)==-1) return -1;
3253     if ((m=parse_string(filter,&reason))!=1)
3254       {
3255       if (m==0) filter->errmsg=CUS "missing reason string";
3256       return -1;
3257       }
3258     if (reason_is_mime)
3259       {
3260       uschar *s,*end;
3261
3262       for (s=reason.character,end=reason.character+reason.length; s<end && (*s&0x80)==0; ++s);
3263       if (s<end)
3264         {
3265         filter->errmsg=CUS "MIME reason string contains 8bit text";
3266         return -1;
3267         }
3268       }
3269     if (parse_semicolon(filter)==-1) return -1;
3270
3271     if (exec)
3272       {
3273       address_item *addr;
3274       int capacity,start;
3275       uschar *buffer;
3276       int buffer_capacity;
3277       struct String key;
3278       md5 base;
3279       uschar digest[16];
3280       uschar hexdigest[33];
3281       int i;
3282       uschar *once;
3283
3284       if (filter_personal(aliases,TRUE))
3285         {
3286         if (filter_test == FTEST_NONE)
3287           {
3288           /* ensure oncelog directory exists; failure will be detected later */
3289
3290           (void)directory_make(NULL, filter->vacation_directory, 0700, FALSE);
3291           }
3292         /* build oncelog filename */
3293
3294         key.character=(uschar*)0;
3295         key.length=0;
3296         capacity=0;
3297         if (handle.length==-1)
3298           {
3299           if (subject.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,subject.character,subject.length);
3300           if (from.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,from.character,from.length);
3301           key.character=string_catn(key.character,&capacity,&key.length,reason_is_mime?US"1":US"0",1);
3302           key.character=string_catn(key.character,&capacity,&key.length,reason.character,reason.length);
3303           }
3304         else
3305           key=handle;
3306         md5_start(&base);
3307         md5_end(&base, key.character, key.length, digest);
3308         for (i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]);
3309         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3310           {
3311           debug_printf("Sieve: mail was personal, vacation file basename: %s\n", hexdigest);
3312           }
3313         if (filter_test == FTEST_NONE)
3314           {
3315           capacity=Ustrlen(filter->vacation_directory);
3316           start=capacity;
3317           once=string_catn(filter->vacation_directory,&capacity,&start,US"/",1);
3318           once=string_catn(once,&capacity,&start,hexdigest,33);
3319           once[start] = '\0';
3320
3321           /* process subject */
3322
3323           if (subject.length==-1)
3324             {
3325             uschar *subject_def;
3326
3327             subject_def=expand_string(US"${if def:header_subject {true}{false}}");
3328             if (Ustrcmp(subject_def,"true")==0)
3329               {
3330               expand_header(&subject,&str_subject);
3331               capacity=6;
3332               start=6;
3333               subject.character=string_catn(US"Auto: ",&capacity,&start,subject.character,subject.length);
3334               subject.length=start;
3335               }
3336             else
3337               {
3338               subject.character=US"Automated reply";
3339               subject.length=Ustrlen(subject.character);
3340               }
3341             }
3342
3343           /* add address to list of generated addresses */
3344
3345           addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
3346           setflag(addr, af_pfr);
3347           setflag(addr, af_ignore_error);
3348           addr->next = *generated;
3349           *generated = addr;
3350           addr->reply = store_get(sizeof(reply_item));
3351           memset(addr->reply,0,sizeof(reply_item)); /* XXX */
3352           addr->reply->to = string_copy(sender_address);
3353           if (from.length==-1)
3354             addr->reply->from = expand_string(US"$local_part@$domain");
3355           else
3356             addr->reply->from = from.character;
3357           /* Allocation is larger than neccessary, but enough even for split MIME words */
3358           buffer_capacity=32+4*subject.length;
3359           buffer=store_get(buffer_capacity);
3360           /* deconst cast safe as we pass in a non-const item */
3361           addr->reply->subject = US parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE);
3362           addr->reply->oncelog=once;
3363           addr->reply->once_repeat=days*86400;
3364
3365           /* build body and MIME headers */
3366
3367           if (reason_is_mime)
3368             {
3369             uschar *mime_body,*reason_end;
3370             static const uschar nlnl[]="\r\n\r\n";
3371
3372             for
3373               (
3374               mime_body=reason.character,reason_end=reason.character+reason.length;
3375               mime_body<(reason_end-(sizeof(nlnl)-1)) && memcmp(mime_body,nlnl,(sizeof(nlnl)-1));
3376               ++mime_body
3377               );
3378             capacity = 0;
3379             start = 0;
3380             addr->reply->headers = string_catn(NULL,&capacity,&start,reason.character,mime_body-reason.character);
3381             addr->reply->headers[start] = '\0';
3382             capacity = 0;
3383             start = 0;
3384             if (mime_body+(sizeof(nlnl)-1)<reason_end) mime_body+=(sizeof(nlnl)-1);
3385             else mime_body=reason_end-1;
3386             addr->reply->text = string_catn(NULL,&capacity,&start,mime_body,reason_end-mime_body);
3387             addr->reply->text[start] = '\0';
3388             }
3389           else
3390             {
3391             struct String qp = { NULL, 0 };  /* Keep compiler happy (PH) */
3392
3393             capacity = 0;
3394             start = reason.length;
3395             addr->reply->headers = US"MIME-Version: 1.0\n"
3396                                    "Content-Type: text/plain;\n"
3397                                    "\tcharset=\"utf-8\"\n"
3398                                    "Content-Transfer-Encoding: quoted-printable";
3399             addr->reply->text = quoted_printable_encode(&reason,&qp)->character;
3400             }
3401           }
3402         }
3403         else if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3404           {
3405           debug_printf("Sieve: mail was not personal, vacation would ignore it\n");
3406           }
3407       }
3408     }
3409     else break;
3410 #endif
3411   }
3412 return 1;
3413 }
3414
3415
3416 /*************************************************
3417 *       Parse and interpret a sieve filter       *
3418 *************************************************/
3419
3420 /*
3421 Arguments:
3422   filter      points to the Sieve filter including its state
3423   exec        Execute parsed statements
3424   generated   where to hang newly-generated addresses
3425
3426 Returns:      1                success
3427               -1               syntax or execution error
3428 */
3429
3430 static int
3431 parse_start(struct Sieve *filter, int exec, address_item **generated)
3432 {
3433 filter->pc=filter->filter;
3434 filter->line=1;
3435 filter->keep=1;
3436 filter->require_envelope=0;
3437 filter->require_fileinto=0;
3438 #ifdef ENCODED_CHARACTER
3439 filter->require_encoded_character=0;
3440 #endif
3441 #ifdef ENVELOPE_AUTH
3442 filter->require_envelope_auth=0;
3443 #endif
3444 #ifdef ENOTIFY
3445 filter->require_enotify=0;
3446 filter->notified=(struct Notification*)0;
3447 #endif
3448 #ifdef SUBADDRESS
3449 filter->require_subaddress=0;
3450 #endif
3451 #ifdef VACATION
3452 filter->require_vacation=0;
3453 filter->vacation_ran=0;
3454 #endif
3455 filter->require_copy=0;
3456 filter->require_iascii_numeric=0;
3457
3458 if (parse_white(filter)==-1) return -1;
3459
3460 if (exec && filter->vacation_directory != NULL && filter_test == FTEST_NONE)
3461   {
3462   DIR *oncelogdir;
3463   struct dirent *oncelog;
3464   struct stat properties;
3465   time_t now;
3466
3467   /* clean up old vacation log databases */
3468
3469   oncelogdir=opendir(CS filter->vacation_directory);
3470
3471   if (oncelogdir ==(DIR*)0 && errno != ENOENT)
3472     {
3473     filter->errmsg=CUS "unable to open vacation directory";
3474     return -1;
3475     }
3476
3477   if (oncelogdir != NULL)
3478     {
3479     time(&now);
3480
3481     while ((oncelog=readdir(oncelogdir))!=(struct dirent*)0)
3482       {
3483       if (strlen(oncelog->d_name)==32)
3484         {
3485         uschar *s=string_sprintf("%s/%s",filter->vacation_directory,oncelog->d_name);
3486         if (Ustat(s,&properties)==0 && (properties.st_mtime+VACATION_MAX_DAYS*86400)<now)
3487           Uunlink(s);
3488         }
3489       }
3490     closedir(oncelogdir);
3491     }
3492   }
3493
3494 while (parse_identifier(filter,CUS "require"))
3495   {
3496   /*
3497   require-command = "require" <capabilities: string-list>
3498   */
3499
3500   struct String *cap,*check;
3501   int m;
3502
3503   if (parse_white(filter)==-1) return -1;
3504   if ((m=parse_stringlist(filter,&cap))!=1)
3505     {
3506     if (m==0) filter->errmsg=CUS "capability string list expected";
3507     return -1;
3508     }
3509   for (check=cap; check->character; ++check)
3510     {
3511     if (eq_octet(check,&str_envelope,0)) filter->require_envelope=1;
3512     else if (eq_octet(check,&str_fileinto,0)) filter->require_fileinto=1;
3513 #ifdef ENCODED_CHARACTER
3514     else if (eq_octet(check,&str_encoded_character,0)) filter->require_encoded_character=1;
3515 #endif
3516 #ifdef ENVELOPE_AUTH
3517     else if (eq_octet(check,&str_envelope_auth,0)) filter->require_envelope_auth=1;
3518 #endif
3519 #ifdef ENOTIFY
3520     else if (eq_octet(check,&str_enotify,0))
3521       {
3522       if (filter->enotify_mailto_owner == NULL)
3523         {
3524         filter->errmsg=CUS "enotify disabled";
3525         return -1;
3526         }
3527         filter->require_enotify=1;
3528       }
3529 #endif
3530 #ifdef SUBADDRESS
3531     else if (eq_octet(check,&str_subaddress,0)) filter->require_subaddress=1;
3532 #endif
3533 #ifdef VACATION
3534     else if (eq_octet(check,&str_vacation,0))
3535       {
3536       if (filter_test == FTEST_NONE && filter->vacation_directory == NULL)
3537         {
3538         filter->errmsg=CUS "vacation disabled";
3539         return -1;
3540         }
3541       filter->require_vacation=1;
3542       }
3543 #endif
3544     else if (eq_octet(check,&str_copy,0)) filter->require_copy=1;
3545     else if (eq_octet(check,&str_comparator_ioctet,0)) ;
3546     else if (eq_octet(check,&str_comparator_iascii_casemap,0)) ;
3547     else if (eq_octet(check,&str_comparator_enascii_casemap,0)) ;
3548     else if (eq_octet(check,&str_comparator_iascii_numeric,0)) filter->require_iascii_numeric=1;
3549     else
3550       {
3551       filter->errmsg=CUS "unknown capability";
3552       return -1;
3553       }
3554     }
3555     if (parse_semicolon(filter)==-1) return -1;
3556   }
3557   if (parse_commands(filter,exec,generated)==-1) return -1;
3558   if (*filter->pc)
3559     {
3560     filter->errmsg=CUS "syntax error";
3561     return -1;
3562     }
3563   return 1;
3564 }
3565
3566
3567 /*************************************************
3568 *            Interpret a sieve filter file       *
3569 *************************************************/
3570
3571 /*
3572 Arguments:
3573   filter      points to the entire file, read into store as a single string
3574   options     controls whether various special things are allowed, and requests
3575               special actions (not currently used)
3576   vacation_directory    where to store vacation "once" files
3577   enotify_mailto_owner  owner of mailto notifications
3578   useraddress string expression for :user part of address
3579   subaddress  string expression for :subaddress part of address
3580   generated   where to hang newly-generated addresses
3581   error       where to pass back an error text
3582
3583 Returns:      FF_DELIVERED     success, a significant action was taken
3584               FF_NOTDELIVERED  success, no significant action
3585               FF_DEFER         defer requested
3586               FF_FAIL          fail requested
3587               FF_FREEZE        freeze requested
3588               FF_ERROR         there was a problem
3589 */
3590
3591 int
3592 sieve_interpret(uschar *filter, int options, uschar *vacation_directory,
3593   uschar *enotify_mailto_owner, uschar *useraddress, uschar *subaddress,
3594   address_item **generated, uschar **error)
3595 {
3596 struct Sieve sieve;
3597 int r;
3598 uschar *msg;
3599
3600 options = options; /* Keep picky compilers happy */
3601 error = error;
3602
3603 DEBUG(D_route) debug_printf("Sieve: start of processing\n");
3604 sieve.filter=filter;
3605
3606 if (vacation_directory == NULL)
3607   sieve.vacation_directory = NULL;
3608 else
3609   {
3610   sieve.vacation_directory=expand_string(vacation_directory);
3611   if (sieve.vacation_directory == NULL)
3612     {
3613     *error = string_sprintf("failed to expand \"%s\" "
3614       "(sieve_vacation_directory): %s", vacation_directory,
3615       expand_string_message);
3616     return FF_ERROR;
3617     }
3618   }
3619
3620 if (enotify_mailto_owner == NULL)
3621   sieve.enotify_mailto_owner = NULL;
3622 else
3623   {
3624   sieve.enotify_mailto_owner=expand_string(enotify_mailto_owner);
3625   if (sieve.enotify_mailto_owner == NULL)
3626     {
3627     *error = string_sprintf("failed to expand \"%s\" "
3628       "(sieve_enotify_mailto_owner): %s", enotify_mailto_owner,
3629       expand_string_message);
3630     return FF_ERROR;
3631     }
3632   }
3633
3634 sieve.useraddress = useraddress == NULL ? CUS "$local_part_prefix$local_part$local_part_suffix" : useraddress;
3635 sieve.subaddress = subaddress;
3636
3637 #ifdef COMPILE_SYNTAX_CHECKER
3638 if (parse_start(&sieve,0,generated)==1)
3639 #else
3640 if (parse_start(&sieve,1,generated)==1)
3641 #endif
3642   {
3643   if (sieve.keep)
3644     {
3645     add_addr(generated,US"inbox",1,0,0,0);
3646     msg = string_sprintf("Implicit keep");
3647     r = FF_DELIVERED;
3648     }
3649   else
3650     {
3651     msg = string_sprintf("No implicit keep");
3652     r = FF_DELIVERED;
3653     }
3654   }
3655 else
3656   {
3657   msg = string_sprintf("Sieve error: %s in line %d",sieve.errmsg,sieve.line);
3658 #ifdef COMPILE_SYNTAX_CHECKER
3659   r = FF_ERROR;
3660   *error = msg;
3661 #else
3662   add_addr(generated,US"inbox",1,0,0,0);
3663   r = FF_DELIVERED;
3664 #endif
3665   }
3666
3667 #ifndef COMPILE_SYNTAX_CHECKER
3668 if (filter_test != FTEST_NONE) printf("%s\n", (const char*) msg);
3669   else debug_printf("%s\n", msg);
3670 #endif
3671
3672 DEBUG(D_route) debug_printf("Sieve: end of processing\n");
3673 return r;
3674 }