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