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