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