Tidying: coverity issues
[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 = {NULL, 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 add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage)
1050 {
1051 address_item *new_addr;
1052
1053 for (new_addr=*generated; new_addr; new_addr=new_addr->next)
1054   {
1055   if (Ustrcmp(new_addr->address,addr)==0 && (file ? testflag(new_addr, af_pfr|af_file) : 1))
1056     {
1057     if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
1058       {
1059       debug_printf("Repeated %s `%s' ignored.\n",file ? "fileinto" : "redirect", addr);
1060       }
1061     return;
1062     }
1063   }
1064
1065 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
1066   {
1067   debug_printf("%s `%s'\n",file ? "fileinto" : "redirect", addr);
1068   }
1069 new_addr=deliver_make_addr(addr,TRUE);
1070 if (file)
1071   {
1072   setflag(new_addr, af_pfr|af_file);
1073   new_addr->mode = 0;
1074   }
1075 new_addr->prop.errors_address = NULL;
1076 new_addr->next = *generated;
1077 *generated = new_addr;
1078 }
1079
1080
1081 /*************************************************
1082 *         Return decoded header field            *
1083 *************************************************/
1084
1085 /*
1086 Unfold the header field as described in RFC 2822 and remove all
1087 leading and trailing white space, then perform MIME decoding and
1088 translate the header field to UTF-8.
1089
1090 Arguments:
1091   value       returned value of the field
1092   header      name of the header field
1093
1094 Returns:      nothing          The expanded string is empty
1095                                in case there is no such header
1096 */
1097
1098 static void expand_header(struct String *value, const struct String *header)
1099 {
1100 uschar *s,*r,*t;
1101 uschar *errmsg;
1102
1103 value->length=0;
1104 value->character=(uschar*)0;
1105
1106 t=r=s=expand_string(string_sprintf("$rheader_%s",quote(header)));
1107 while (*r==' ' || *r=='\t') ++r;
1108 while (*r)
1109   {
1110   if (*r=='\n')
1111     ++r;
1112   else
1113     *t++=*r++;
1114   }
1115 while (t>s && (*(t-1)==' ' || *(t-1)=='\t')) --t;
1116 *t='\0';
1117 value->character=rfc2047_decode(s,check_rfc2047_length,US"utf-8",'\0',&value->length,&errmsg);
1118 }
1119
1120
1121 /*************************************************
1122 *        Parse remaining hash comment            *
1123 *************************************************/
1124
1125 /*
1126 Token definition:
1127   Comment up to terminating CRLF
1128
1129 Arguments:
1130   filter      points to the Sieve filter including its state
1131
1132 Returns:      1                success
1133               -1               syntax error
1134 */
1135
1136 static int parse_hashcomment(struct Sieve *filter)
1137 {
1138 ++filter->pc;
1139 while (*filter->pc)
1140   {
1141 #ifdef RFC_EOL
1142   if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1143 #else
1144   if (*filter->pc=='\n')
1145 #endif
1146     {
1147 #ifdef RFC_EOL
1148     filter->pc+=2;
1149 #else
1150     ++filter->pc;
1151 #endif
1152     ++filter->line;
1153     return 1;
1154     }
1155   else ++filter->pc;
1156   }
1157 filter->errmsg=CUS "missing end of comment";
1158 return -1;
1159 }
1160
1161
1162 /*************************************************
1163 *       Parse remaining C-style comment          *
1164 *************************************************/
1165
1166 /*
1167 Token definition:
1168   Everything up to star slash
1169
1170 Arguments:
1171   filter      points to the Sieve filter including its state
1172
1173 Returns:      1                success
1174               -1               syntax error
1175 */
1176
1177 static int parse_comment(struct Sieve *filter)
1178 {
1179   filter->pc+=2;
1180   while (*filter->pc)
1181   {
1182     if (*filter->pc=='*' && *(filter->pc+1)=='/')
1183     {
1184       filter->pc+=2;
1185       return 1;
1186     }
1187     else ++filter->pc;
1188   }
1189   filter->errmsg=CUS "missing end of comment";
1190   return -1;
1191 }
1192
1193
1194 /*************************************************
1195 *         Parse optional white space             *
1196 *************************************************/
1197
1198 /*
1199 Token definition:
1200   Spaces, tabs, CRLFs, hash comments or C-style comments
1201
1202 Arguments:
1203   filter      points to the Sieve filter including its state
1204
1205 Returns:      1                success
1206               -1               syntax error
1207 */
1208
1209 static int parse_white(struct Sieve *filter)
1210 {
1211 while (*filter->pc)
1212   {
1213   if (*filter->pc==' ' || *filter->pc=='\t') ++filter->pc;
1214 #ifdef RFC_EOL
1215   else if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1216 #else
1217   else if (*filter->pc=='\n')
1218 #endif
1219     {
1220 #ifdef RFC_EOL
1221     filter->pc+=2;
1222 #else
1223     ++filter->pc;
1224 #endif
1225     ++filter->line;
1226     }
1227   else if (*filter->pc=='#')
1228     {
1229     if (parse_hashcomment(filter)==-1) return -1;
1230     }
1231   else if (*filter->pc=='/' && *(filter->pc+1)=='*')
1232     {
1233     if (parse_comment(filter)==-1) return -1;
1234     }
1235   else break;
1236   }
1237 return 1;
1238 }
1239
1240
1241 #ifdef ENCODED_CHARACTER
1242 /*************************************************
1243 *      Decode hex-encoded-character string       *
1244 *************************************************/
1245
1246 /*
1247 Encoding definition:
1248    blank                = SP / TAB / CRLF
1249    hex-pair-seq         = *blank hex-pair *(1*blank hex-pair) *blank
1250    hex-pair             = 1*2HEXDIG
1251
1252 Arguments:
1253   src         points to a hex-pair-seq
1254   end         points to its end
1255   dst         points to the destination of the decoded octets,
1256               optionally to (uschar*)0 for checking only
1257
1258 Returns:      >=0              number of decoded octets
1259               -1               syntax error
1260 */
1261
1262 static int hex_decode(uschar *src, uschar *end, uschar *dst)
1263 {
1264 int decoded=0;
1265
1266 while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1267 do
1268   {
1269   int x,d,n;
1270
1271   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);
1272   if (d==0) return -1;
1273   if (dst) *dst++=x;
1274   ++decoded;
1275   if (src==end) return decoded;
1276   if (*src==' ' || *src=='\t' || *src=='\n')
1277     while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1278   else
1279     return -1;
1280   }
1281 while (src<end);
1282 return decoded;
1283 }
1284
1285
1286 /*************************************************
1287 *    Decode unicode-encoded-character string     *
1288 *************************************************/
1289
1290 /*
1291 Encoding definition:
1292    blank                = SP / TAB / CRLF
1293    unicode-hex-seq      = *blank unicode-hex *(blank unicode-hex) *blank
1294    unicode-hex          = 1*HEXDIG
1295
1296    It is an error for a script to use a hexadecimal value that isn't in
1297    either the range 0 to D7FF or the range E000 to 10FFFF.
1298
1299    At this time, strings are already scanned, thus the CRLF is converted
1300    to the internally used \n (should RFC_EOL have been used).
1301
1302 Arguments:
1303   src         points to a unicode-hex-seq
1304   end         points to its end
1305   dst         points to the destination of the decoded octets,
1306               optionally to (uschar*)0 for checking only
1307
1308 Returns:      >=0              number of decoded octets
1309               -1               syntax error
1310               -2               semantic error (character range violation)
1311 */
1312
1313 static int unicode_decode(uschar *src, uschar *end, uschar *dst)
1314 {
1315 int decoded=0;
1316
1317 while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1318 do
1319   {
1320   uschar *hex_seq;
1321   int c,d,n;
1322
1323   unicode_hex:
1324   for (hex_seq=src; src<end && *src=='0'; ++src);
1325   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);
1326   if (src==hex_seq) return -1;
1327   if (d==7 || (!((c>=0 && c<=0xd7ff) || (c>=0xe000 && c<=0x10ffff)))) return -2;
1328   if (c<128)
1329     {
1330     if (dst) *dst++=c;
1331     ++decoded;
1332     }
1333   else if (c>=0x80 && c<=0x7ff)
1334     {
1335       if (dst)
1336         {
1337         *dst++=192+(c>>6);
1338         *dst++=128+(c&0x3f);
1339         }
1340       decoded+=2;
1341     }
1342   else if (c>=0x800 && c<=0xffff)
1343     {
1344       if (dst)
1345         {
1346         *dst++=224+(c>>12);
1347         *dst++=128+((c>>6)&0x3f);
1348         *dst++=128+(c&0x3f);
1349         }
1350       decoded+=3;
1351     }
1352   else if (c>=0x10000 && c<=0x1fffff)
1353     {
1354       if (dst)
1355         {
1356         *dst++=240+(c>>18);
1357         *dst++=128+((c>>10)&0x3f);
1358         *dst++=128+((c>>6)&0x3f);
1359         *dst++=128+(c&0x3f);
1360         }
1361       decoded+=4;
1362     }
1363   if (*src==' ' || *src=='\t' || *src=='\n')
1364     {
1365     while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1366     if (src==end) return decoded;
1367     goto unicode_hex;
1368     }
1369   }
1370 while (src<end);
1371 return decoded;
1372 }
1373
1374
1375 /*************************************************
1376 *       Decode encoded-character string          *
1377 *************************************************/
1378
1379 /*
1380 Encoding definition:
1381    encoded-arb-octets   = "${hex:" hex-pair-seq "}"
1382    encoded-unicode-char = "${unicode:" unicode-hex-seq "}"
1383
1384 Arguments:
1385   encoded     points to an encoded string, returns decoded string
1386   filter      points to the Sieve filter including its state
1387
1388 Returns:      1                success
1389               -1               syntax error
1390 */
1391
1392 static int string_decode(struct Sieve *filter, struct String *data)
1393 {
1394 uschar *src,*dst,*end;
1395
1396 src=data->character;
1397 dst=src;
1398 end=data->character+data->length;
1399 while (src<end)
1400   {
1401   uschar *brace;
1402
1403   if (
1404       strncmpic(src,US "${hex:",6)==0
1405       && (brace=Ustrchr(src+6,'}'))!=(uschar*)0
1406       && (hex_decode(src+6,brace,(uschar*)0))>=0
1407      )
1408     {
1409     dst+=hex_decode(src+6,brace,dst);
1410     src=brace+1;
1411     }
1412   else if (
1413            strncmpic(src,US "${unicode:",10)==0
1414            && (brace=Ustrchr(src+10,'}'))!=(uschar*)0
1415           )
1416     {
1417     switch (unicode_decode(src+10,brace,(uschar*)0))
1418       {
1419       case -2:
1420         {
1421         filter->errmsg=CUS "unicode character out of range";
1422         return -1;
1423         }
1424       case -1:
1425         {
1426         *dst++=*src++;
1427         break;
1428         }
1429       default:
1430         {
1431         dst+=unicode_decode(src+10,brace,dst);
1432         src=brace+1;
1433         }
1434       }
1435     }
1436   else *dst++=*src++;
1437   }
1438   data->length=dst-data->character;
1439   *dst='\0';
1440 return 1;
1441 }
1442 #endif
1443
1444
1445 /*************************************************
1446 *          Parse an optional string              *
1447 *************************************************/
1448
1449 /*
1450 Token definition:
1451    quoted-string = DQUOTE *CHAR DQUOTE
1452            ;; in general, \ CHAR inside a string maps to CHAR
1453            ;; so \" maps to " and \\ maps to \
1454            ;; note that newlines and other characters are all allowed
1455            ;; in strings
1456
1457    multi-line          = "text:" *(SP / HTAB) (hash-comment / CRLF)
1458                          *(multi-line-literal / multi-line-dotstuff)
1459                          "." CRLF
1460    multi-line-literal  = [CHAR-NOT-DOT *CHAR-NOT-CRLF] CRLF
1461    multi-line-dotstuff = "." 1*CHAR-NOT-CRLF CRLF
1462            ;; A line containing only "." ends the multi-line.
1463            ;; Remove a leading '.' if followed by another '.'.
1464   string           = quoted-string / multi-line
1465
1466 Arguments:
1467   filter      points to the Sieve filter including its state
1468   id          specifies identifier to match
1469
1470 Returns:      1                success
1471               -1               syntax error
1472               0                identifier not matched
1473 */
1474
1475 static int parse_string(struct Sieve *filter, struct String *data)
1476 {
1477 int dataCapacity=0;
1478
1479 data->length=0;
1480 data->character=(uschar*)0;
1481 if (*filter->pc=='"') /* quoted string */
1482   {
1483   ++filter->pc;
1484   while (*filter->pc)
1485     {
1486     if (*filter->pc=='"') /* end of string */
1487       {
1488       int foo=data->length;
1489
1490       ++filter->pc;
1491       /* that way, there will be at least one character allocated */
1492       data->character=string_catn(data->character,&dataCapacity,&foo,CUS "",1);
1493 #ifdef ENCODED_CHARACTER
1494       if (filter->require_encoded_character
1495           && string_decode(filter,data)==-1)
1496         return -1;
1497 #endif
1498       return 1;
1499       }
1500     else if (*filter->pc=='\\' && *(filter->pc+1)) /* quoted character */
1501       {
1502       data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc+1,1);
1503       filter->pc+=2;
1504       }
1505     else /* regular character */
1506       {
1507 #ifdef RFC_EOL
1508       if (*filter->pc=='\r' && *(filter->pc+1)=='\n') ++filter->line;
1509 #else
1510       if (*filter->pc=='\n')
1511         {
1512         data->character=string_catn(data->character,&dataCapacity,&data->length,US"\r",1);
1513         ++filter->line;
1514         }
1515 #endif
1516       data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc,1);
1517       filter->pc++;
1518       }
1519     }
1520   filter->errmsg=CUS "missing end of string";
1521   return -1;
1522   }
1523 else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */
1524   {
1525   filter->pc+=5;
1526   /* skip optional white space followed by hashed comment or CRLF */
1527   while (*filter->pc==' ' || *filter->pc=='\t') ++filter->pc;
1528   if (*filter->pc=='#')
1529     {
1530     if (parse_hashcomment(filter)==-1) return -1;
1531     }
1532 #ifdef RFC_EOL
1533   else if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1534 #else
1535   else if (*filter->pc=='\n')
1536 #endif
1537     {
1538 #ifdef RFC_EOL
1539     filter->pc+=2;
1540 #else
1541     ++filter->pc;
1542 #endif
1543     ++filter->line;
1544     }
1545   else
1546     {
1547     filter->errmsg=CUS "syntax error";
1548     return -1;
1549     }
1550   while (*filter->pc)
1551     {
1552 #ifdef RFC_EOL
1553     if (*filter->pc=='\r' && *(filter->pc+1)=='\n') /* end of line */
1554 #else
1555     if (*filter->pc=='\n') /* end of line */
1556 #endif
1557       {
1558       data->character=string_catn(data->character,&dataCapacity,&data->length,CUS "\r\n",2);
1559 #ifdef RFC_EOL
1560       filter->pc+=2;
1561 #else
1562       ++filter->pc;
1563 #endif
1564       ++filter->line;
1565 #ifdef RFC_EOL
1566       if (*filter->pc=='.' && *(filter->pc+1)=='\r' && *(filter->pc+2)=='\n') /* end of string */
1567 #else
1568       if (*filter->pc=='.' && *(filter->pc+1)=='\n') /* end of string */
1569 #endif
1570         {
1571         int foo=data->length;
1572
1573         /* that way, there will be at least one character allocated */
1574         data->character=string_catn(data->character,&dataCapacity,&foo,CUS "",1);
1575 #ifdef RFC_EOL
1576         filter->pc+=3;
1577 #else
1578         filter->pc+=2;
1579 #endif
1580         ++filter->line;
1581 #ifdef ENCODED_CHARACTER
1582         if (filter->require_encoded_character
1583             && string_decode(filter,data)==-1)
1584           return -1;
1585 #endif
1586         return 1;
1587         }
1588       else if (*filter->pc=='.' && *(filter->pc+1)=='.') /* remove dot stuffing */
1589         {
1590         data->character=string_catn(data->character,&dataCapacity,&data->length,CUS ".",1);
1591         filter->pc+=2;
1592         }
1593       }
1594     else /* regular character */
1595       {
1596       data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc,1);
1597       filter->pc++;
1598       }
1599     }
1600   filter->errmsg=CUS "missing end of multi line string";
1601   return -1;
1602   }
1603 else return 0;
1604 }
1605
1606
1607 /*************************************************
1608 *          Parse a specific identifier           *
1609 *************************************************/
1610
1611 /*
1612 Token definition:
1613   identifier       = (ALPHA / "_") *(ALPHA DIGIT "_")
1614
1615 Arguments:
1616   filter      points to the Sieve filter including its state
1617   id          specifies identifier to match
1618
1619 Returns:      1                success
1620               0                identifier not matched
1621 */
1622
1623 static int parse_identifier(struct Sieve *filter, const uschar *id)
1624 {
1625   size_t idlen=Ustrlen(id);
1626
1627   if (strncmpic(US filter->pc,US id,idlen)==0)
1628   {
1629     uschar next=filter->pc[idlen];
1630
1631     if ((next>='A' && next<='Z') || (next>='a' && next<='z') || next=='_' || (next>='0' && next<='9')) return 0;
1632     filter->pc+=idlen;
1633     return 1;
1634   }
1635   else return 0;
1636 }
1637
1638
1639 /*************************************************
1640 *                 Parse a number                 *
1641 *************************************************/
1642
1643 /*
1644 Token definition:
1645   number           = 1*DIGIT [QUANTIFIER]
1646   QUANTIFIER       = "K" / "M" / "G"
1647
1648 Arguments:
1649   filter      points to the Sieve filter including its state
1650   data        returns value
1651
1652 Returns:      1                success
1653               -1               no string list found
1654 */
1655
1656 static int parse_number(struct Sieve *filter, unsigned long *data)
1657 {
1658 unsigned long d,u;
1659
1660 if (*filter->pc>='0' && *filter->pc<='9')
1661   {
1662   uschar *e;
1663
1664   errno=0;
1665   d=Ustrtoul(filter->pc,&e,10);
1666   if (errno==ERANGE)
1667     {
1668     filter->errmsg=CUstrerror(ERANGE);
1669     return -1;
1670     }
1671   filter->pc=e;
1672   u=1;
1673   if (*filter->pc=='K') { u=1024; ++filter->pc; }
1674   else if (*filter->pc=='M') { u=1024*1024; ++filter->pc; }
1675   else if (*filter->pc=='G') { u=1024*1024*1024; ++filter->pc; }
1676   if (d>(ULONG_MAX/u))
1677     {
1678     filter->errmsg=CUstrerror(ERANGE);
1679     return -1;
1680     }
1681   d*=u;
1682   *data=d;
1683   return 1;
1684   }
1685 else
1686   {
1687   filter->errmsg=CUS "missing number";
1688   return -1;
1689   }
1690 }
1691
1692
1693 /*************************************************
1694 *              Parse a string list               *
1695 *************************************************/
1696
1697 /*
1698 Grammar:
1699   string-list      = "[" string *("," string) "]" / string
1700
1701 Arguments:
1702   filter      points to the Sieve filter including its state
1703   data        returns string list
1704
1705 Returns:      1                success
1706               -1               no string list found
1707 */
1708
1709 static int
1710 parse_stringlist(struct Sieve *filter, struct String **data)
1711 {
1712 const uschar *orig=filter->pc;
1713 int dataCapacity = 0;
1714 int dataLength = 0;
1715 struct String *d = NULL;
1716 int m;
1717
1718 if (*filter->pc=='[') /* string list */
1719   {
1720   ++filter->pc;
1721   for (;;)
1722     {
1723     if (parse_white(filter)==-1) goto error;
1724     if (dataLength+1 >= dataCapacity) /* increase buffer */
1725       {
1726       struct String *new;
1727       int newCapacity;          /* Don't amalgamate with next line; some compilers grumble */
1728
1729       dataCapacity = dataCapacity ? dataCapacity * 2 : 4;
1730       new = store_get(sizeof(struct String) * dataCapacity);
1731
1732       if (d) memcpy(new,d,sizeof(struct String)*dataLength);
1733       d = new;
1734       }
1735
1736     m=parse_string(filter,&d[dataLength]);
1737     if (m==0)
1738       {
1739       if (dataLength==0) break;
1740       else
1741         {
1742         filter->errmsg=CUS "missing string";
1743         goto error;
1744         }
1745       }
1746     else if (m==-1) goto error;
1747     else ++dataLength;
1748     if (parse_white(filter)==-1) goto error;
1749     if (*filter->pc==',') ++filter->pc;
1750     else break;
1751     }
1752   if (*filter->pc==']')
1753     {
1754     d[dataLength].character=(uschar*)0;
1755     d[dataLength].length=-1;
1756     ++filter->pc;
1757     *data=d;
1758     return 1;
1759     }
1760   else
1761     {
1762     filter->errmsg=CUS "missing closing bracket";
1763     goto error;
1764     }
1765   }
1766 else /* single string */
1767   {
1768   if ((d=store_get(sizeof(struct String)*2))==(struct String*)0)
1769     {
1770     return -1;
1771     }
1772   m=parse_string(filter,&d[0]);
1773   if (m==-1)
1774     {
1775     return -1;
1776     }
1777   else if (m==0)
1778     {
1779     filter->pc=orig;
1780     return 0;
1781     }
1782   else
1783     {
1784     d[1].character=(uschar*)0;
1785     d[1].length=-1;
1786     *data=d;
1787     return 1;
1788     }
1789   }
1790 error:
1791 filter->errmsg=CUS "missing string list";
1792 return -1;
1793 }
1794
1795
1796 /*************************************************
1797 *    Parse an optional address part specifier    *
1798 *************************************************/
1799
1800 /*
1801 Grammar:
1802   address-part     =  ":localpart" / ":domain" / ":all"
1803   address-part     =/ ":user" / ":detail"
1804
1805 Arguments:
1806   filter      points to the Sieve filter including its state
1807   a           returns address part specified
1808
1809 Returns:      1                success
1810               0                no comparator found
1811               -1               syntax error
1812 */
1813
1814 static int parse_addresspart(struct Sieve *filter, enum AddressPart *a)
1815 {
1816 #ifdef SUBADDRESS
1817 if (parse_identifier(filter,CUS ":user")==1)
1818   {
1819   if (!filter->require_subaddress)
1820     {
1821     filter->errmsg=CUS "missing previous require \"subaddress\";";
1822     return -1;
1823     }
1824   *a=ADDRPART_USER;
1825   return 1;
1826   }
1827 else if (parse_identifier(filter,CUS ":detail")==1)
1828   {
1829   if (!filter->require_subaddress)
1830     {
1831     filter->errmsg=CUS "missing previous require \"subaddress\";";
1832     return -1;
1833     }
1834   *a=ADDRPART_DETAIL;
1835   return 1;
1836   }
1837 else
1838 #endif
1839 if (parse_identifier(filter,CUS ":localpart")==1)
1840   {
1841   *a=ADDRPART_LOCALPART;
1842   return 1;
1843   }
1844 else if (parse_identifier(filter,CUS ":domain")==1)
1845   {
1846   *a=ADDRPART_DOMAIN;
1847   return 1;
1848   }
1849 else if (parse_identifier(filter,CUS ":all")==1)
1850   {
1851   *a=ADDRPART_ALL;
1852   return 1;
1853   }
1854 else return 0;
1855 }
1856
1857
1858 /*************************************************
1859 *         Parse an optional comparator           *
1860 *************************************************/
1861
1862 /*
1863 Grammar:
1864   comparator = ":comparator" <comparator-name: string>
1865
1866 Arguments:
1867   filter      points to the Sieve filter including its state
1868   c           returns comparator
1869
1870 Returns:      1                success
1871               0                no comparator found
1872               -1               incomplete comparator found
1873 */
1874
1875 static int parse_comparator(struct Sieve *filter, enum Comparator *c)
1876 {
1877 struct String comparator_name;
1878
1879 if (parse_identifier(filter,CUS ":comparator")==0) return 0;
1880 if (parse_white(filter)==-1) return -1;
1881 switch (parse_string(filter,&comparator_name))
1882   {
1883   case -1: return -1;
1884   case 0:
1885     {
1886     filter->errmsg=CUS "missing comparator";
1887     return -1;
1888     }
1889   default:
1890     {
1891     int match;
1892
1893     if (eq_asciicase(&comparator_name,&str_ioctet,0))
1894       {
1895       *c=COMP_OCTET;
1896       match=1;
1897       }
1898     else if (eq_asciicase(&comparator_name,&str_iascii_casemap,0))
1899       {
1900       *c=COMP_EN_ASCII_CASEMAP;
1901       match=1;
1902       }
1903     else if (eq_asciicase(&comparator_name,&str_enascii_casemap,0))
1904       {
1905       *c=COMP_EN_ASCII_CASEMAP;
1906       match=1;
1907       }
1908     else if (eq_asciicase(&comparator_name,&str_iascii_numeric,0))
1909       {
1910       *c=COMP_ASCII_NUMERIC;
1911       match=1;
1912       }
1913     else
1914       {
1915       filter->errmsg=CUS "invalid comparator";
1916       match=-1;
1917       }
1918     return match;
1919     }
1920   }
1921 }
1922
1923
1924 /*************************************************
1925 *          Parse an optional match type          *
1926 *************************************************/
1927
1928 /*
1929 Grammar:
1930   match-type = ":is" / ":contains" / ":matches"
1931
1932 Arguments:
1933   filter      points to the Sieve filter including its state
1934   m           returns match type
1935
1936 Returns:      1                success
1937               0                no match type found
1938 */
1939
1940 static int parse_matchtype(struct Sieve *filter, enum MatchType *m)
1941 {
1942   if (parse_identifier(filter,CUS ":is")==1)
1943   {
1944     *m=MATCH_IS;
1945     return 1;
1946   }
1947   else if (parse_identifier(filter,CUS ":contains")==1)
1948   {
1949     *m=MATCH_CONTAINS;
1950     return 1;
1951   }
1952   else if (parse_identifier(filter,CUS ":matches")==1)
1953   {
1954     *m=MATCH_MATCHES;
1955     return 1;
1956   }
1957   else return 0;
1958 }
1959
1960
1961 /*************************************************
1962 *   Parse and interpret an optional test list    *
1963 *************************************************/
1964
1965 /*
1966 Grammar:
1967   test-list = "(" test *("," test) ")"
1968
1969 Arguments:
1970   filter      points to the Sieve filter including its state
1971   n           total number of tests
1972   num_true    number of passed tests
1973   exec        Execute parsed statements
1974
1975 Returns:      1                success
1976               0                no test list found
1977               -1               syntax or execution error
1978 */
1979
1980 static int parse_testlist(struct Sieve *filter, int *n, int *num_true, int exec)
1981 {
1982 if (parse_white(filter)==-1) return -1;
1983 if (*filter->pc=='(')
1984   {
1985   ++filter->pc;
1986   *n=0;
1987    *num_true=0;
1988   for (;;)
1989     {
1990     int cond;
1991
1992     switch (parse_test(filter,&cond,exec))
1993       {
1994       case -1: return -1;
1995       case 0: filter->errmsg=CUS "missing test"; return -1;
1996       default: ++*n; if (cond) ++*num_true; break;
1997       }
1998     if (parse_white(filter)==-1) return -1;
1999     if (*filter->pc==',') ++filter->pc;
2000     else break;
2001     }
2002   if (*filter->pc==')')
2003     {
2004     ++filter->pc;
2005     return 1;
2006     }
2007   else
2008     {
2009     filter->errmsg=CUS "missing closing paren";
2010     return -1;
2011     }
2012   }
2013 else return 0;
2014 }
2015
2016
2017 /*************************************************
2018 *     Parse and interpret an optional test       *
2019 *************************************************/
2020
2021 /*
2022 Arguments:
2023   filter      points to the Sieve filter including its state
2024   cond        returned condition status
2025   exec        Execute parsed statements
2026
2027 Returns:      1                success
2028               0                no test found
2029               -1               syntax or execution error
2030 */
2031
2032 static int parse_test(struct Sieve *filter, int *cond, int exec)
2033 {
2034 if (parse_white(filter)==-1) return -1;
2035 if (parse_identifier(filter,CUS "address"))
2036   {
2037   /*
2038   address-test = "address" { [address-part] [comparator] [match-type] }
2039                  <header-list: string-list> <key-list: string-list>
2040
2041   header-list From, To, Cc, Bcc, Sender, Resent-From, Resent-To
2042   */
2043
2044   enum AddressPart addressPart=ADDRPART_ALL;
2045   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2046   enum MatchType matchType=MATCH_IS;
2047   struct String *hdr,*h,*key,*k;
2048   int m;
2049   int ap=0,co=0,mt=0;
2050
2051   for (;;)
2052     {
2053     if (parse_white(filter)==-1) return -1;
2054     if ((m=parse_addresspart(filter,&addressPart))!=0)
2055       {
2056       if (m==-1) return -1;
2057       if (ap)
2058         {
2059         filter->errmsg=CUS "address part already specified";
2060         return -1;
2061         }
2062       else ap=1;
2063       }
2064     else if ((m=parse_comparator(filter,&comparator))!=0)
2065       {
2066       if (m==-1) return -1;
2067       if (co)
2068         {
2069         filter->errmsg=CUS "comparator already specified";
2070         return -1;
2071         }
2072       else co=1;
2073       }
2074     else if ((m=parse_matchtype(filter,&matchType))!=0)
2075       {
2076       if (m==-1) return -1;
2077       if (mt)
2078         {
2079         filter->errmsg=CUS "match type already specified";
2080         return -1;
2081         }
2082       else mt=1;
2083       }
2084     else break;
2085     }
2086   if (parse_white(filter)==-1) return -1;
2087   if ((m=parse_stringlist(filter,&hdr))!=1)
2088     {
2089     if (m==0) filter->errmsg=CUS "header string list expected";
2090     return -1;
2091     }
2092   if (parse_white(filter)==-1) return -1;
2093   if ((m=parse_stringlist(filter,&key))!=1)
2094     {
2095     if (m==0) filter->errmsg=CUS "key string list expected";
2096     return -1;
2097     }
2098   *cond=0;
2099   for (h=hdr; h->length!=-1 && !*cond; ++h)
2100     {
2101     uschar *header_value=(uschar*)0,*extracted_addr,*end_addr;
2102
2103     if
2104       (
2105       !eq_asciicase(h,&str_from,0)
2106       && !eq_asciicase(h,&str_to,0)
2107       && !eq_asciicase(h,&str_cc,0)
2108       && !eq_asciicase(h,&str_bcc,0)
2109       && !eq_asciicase(h,&str_sender,0)
2110       && !eq_asciicase(h,&str_resent_from,0)
2111       && !eq_asciicase(h,&str_resent_to,0)
2112       )
2113       {
2114       filter->errmsg=CUS "invalid header field";
2115       return -1;
2116       }
2117     if (exec)
2118       {
2119       /* We are only interested in addresses below, so no MIME decoding */
2120       header_value=expand_string(string_sprintf("$rheader_%s",quote(h)));
2121       if (header_value == NULL)
2122         {
2123         filter->errmsg=CUS "header string expansion failed";
2124         return -1;
2125         }
2126       parse_allow_group = TRUE;
2127       while (*header_value && !*cond)
2128         {
2129         uschar *error;
2130         int start, end, domain;
2131         int saveend;
2132         uschar *part=NULL;
2133
2134         end_addr = parse_find_address_end(header_value, FALSE);
2135         saveend = *end_addr;
2136         *end_addr = 0;
2137         extracted_addr = parse_extract_address(header_value, &error, &start, &end, &domain, FALSE);
2138
2139         if (extracted_addr) switch (addressPart)
2140           {
2141           case ADDRPART_ALL: part=extracted_addr; break;
2142 #ifdef SUBADDRESS
2143           case ADDRPART_USER:
2144 #endif
2145           case ADDRPART_LOCALPART: part=extracted_addr; part[domain-1]='\0'; break;
2146           case ADDRPART_DOMAIN: part=extracted_addr+domain; break;
2147 #ifdef SUBADDRESS
2148           case ADDRPART_DETAIL: part=NULL; break;
2149 #endif
2150           }
2151
2152         *end_addr = saveend;
2153         if (part)
2154           {
2155           for (k=key; k->length!=-1; ++k)
2156             {
2157             struct String partStr;
2158
2159             partStr.character=part;
2160             partStr.length=Ustrlen(part);
2161             if (extracted_addr)
2162               {
2163               *cond=compare(filter,k,&partStr,comparator,matchType);
2164               if (*cond==-1) return -1;
2165               if (*cond) break;
2166               }
2167             }
2168           }
2169         if (saveend == 0) break;
2170         header_value = end_addr + 1;
2171         }
2172       parse_allow_group = FALSE;
2173       parse_found_group = FALSE;
2174       }
2175     }
2176   return 1;
2177   }
2178 else if (parse_identifier(filter,CUS "allof"))
2179   {
2180   /*
2181   allof-test   = "allof" <tests: test-list>
2182   */
2183
2184   int n,num_true;
2185
2186   switch (parse_testlist(filter,&n,&num_true,exec))
2187     {
2188     case -1: return -1;
2189     case 0: filter->errmsg=CUS "missing test list"; return -1;
2190     default: *cond=(n==num_true); return 1;
2191     }
2192   }
2193 else if (parse_identifier(filter,CUS "anyof"))
2194   {
2195   /*
2196   anyof-test   = "anyof" <tests: test-list>
2197   */
2198
2199   int n,num_true;
2200
2201   switch (parse_testlist(filter,&n,&num_true,exec))
2202     {
2203     case -1: return -1;
2204     case 0: filter->errmsg=CUS "missing test list"; return -1;
2205     default: *cond=(num_true>0); return 1;
2206     }
2207   }
2208 else if (parse_identifier(filter,CUS "exists"))
2209   {
2210   /*
2211   exists-test = "exists" <header-names: string-list>
2212   */
2213
2214   struct String *hdr,*h;
2215   int m;
2216
2217   if (parse_white(filter)==-1) return -1;
2218   if ((m=parse_stringlist(filter,&hdr))!=1)
2219     {
2220     if (m==0) filter->errmsg=CUS "header string list expected";
2221     return -1;
2222     }
2223   if (exec)
2224     {
2225     *cond=1;
2226     for (h=hdr; h->length!=-1 && *cond; ++h)
2227       {
2228       uschar *header_def;
2229
2230       header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
2231       if (header_def == NULL)
2232         {
2233         filter->errmsg=CUS "header string expansion failed";
2234         return -1;
2235         }
2236       if (Ustrcmp(header_def,"false")==0) *cond=0;
2237       }
2238     }
2239   return 1;
2240   }
2241 else if (parse_identifier(filter,CUS "false"))
2242   {
2243   /*
2244   false-test = "false"
2245   */
2246
2247   *cond=0;
2248   return 1;
2249   }
2250 else if (parse_identifier(filter,CUS "header"))
2251   {
2252   /*
2253   header-test = "header" { [comparator] [match-type] }
2254                 <header-names: string-list> <key-list: string-list>
2255   */
2256
2257   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2258   enum MatchType matchType=MATCH_IS;
2259   struct String *hdr,*h,*key,*k;
2260   int m;
2261   int co=0,mt=0;
2262
2263   for (;;)
2264     {
2265     if (parse_white(filter)==-1) return -1;
2266     if ((m=parse_comparator(filter,&comparator))!=0)
2267       {
2268       if (m==-1) return -1;
2269       if (co)
2270         {
2271         filter->errmsg=CUS "comparator already specified";
2272         return -1;
2273         }
2274       else co=1;
2275       }
2276     else if ((m=parse_matchtype(filter,&matchType))!=0)
2277       {
2278       if (m==-1) return -1;
2279       if (mt)
2280         {
2281         filter->errmsg=CUS "match type already specified";
2282         return -1;
2283         }
2284       else mt=1;
2285       }
2286     else break;
2287     }
2288   if (parse_white(filter)==-1) return -1;
2289   if ((m=parse_stringlist(filter,&hdr))!=1)
2290     {
2291     if (m==0) filter->errmsg=CUS "header string list expected";
2292     return -1;
2293     }
2294   if (parse_white(filter)==-1) return -1;
2295   if ((m=parse_stringlist(filter,&key))!=1)
2296     {
2297     if (m==0) filter->errmsg=CUS "key string list expected";
2298     return -1;
2299     }
2300   *cond=0;
2301   for (h=hdr; h->length!=-1 && !*cond; ++h)
2302     {
2303     if (!is_header(h))
2304       {
2305       filter->errmsg=CUS "invalid header field";
2306       return -1;
2307       }
2308     if (exec)
2309       {
2310       struct String header_value;
2311       uschar *header_def;
2312
2313       expand_header(&header_value,h);
2314       header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
2315       if (header_value.character == NULL || header_def == NULL)
2316         {
2317         filter->errmsg=CUS "header string expansion failed";
2318         return -1;
2319         }
2320       for (k=key; k->length!=-1; ++k)
2321         {
2322         if (Ustrcmp(header_def,"true")==0)
2323           {
2324           *cond=compare(filter,k,&header_value,comparator,matchType);
2325           if (*cond==-1) return -1;
2326           if (*cond) break;
2327           }
2328         }
2329       }
2330     }
2331   return 1;
2332   }
2333 else if (parse_identifier(filter,CUS "not"))
2334   {
2335   if (parse_white(filter)==-1) return -1;
2336   switch (parse_test(filter,cond,exec))
2337     {
2338     case -1: return -1;
2339     case 0: filter->errmsg=CUS "missing test"; return -1;
2340     default: *cond=!*cond; return 1;
2341     }
2342   }
2343 else if (parse_identifier(filter,CUS "size"))
2344   {
2345   /*
2346   relop = ":over" / ":under"
2347   size-test = "size" relop <limit: number>
2348   */
2349
2350   unsigned long limit;
2351   int overNotUnder;
2352
2353   if (parse_white(filter)==-1) return -1;
2354   if (parse_identifier(filter,CUS ":over")) overNotUnder=1;
2355   else if (parse_identifier(filter,CUS ":under")) overNotUnder=0;
2356   else
2357     {
2358     filter->errmsg=CUS "missing :over or :under";
2359     return -1;
2360     }
2361   if (parse_white(filter)==-1) return -1;
2362   if (parse_number(filter,&limit)==-1) return -1;
2363   *cond=(overNotUnder ? (message_size>limit) : (message_size<limit));
2364   return 1;
2365   }
2366 else if (parse_identifier(filter,CUS "true"))
2367   {
2368   *cond=1;
2369   return 1;
2370   }
2371 else if (parse_identifier(filter,CUS "envelope"))
2372   {
2373   /*
2374   envelope-test = "envelope" { [comparator] [address-part] [match-type] }
2375                   <envelope-part: string-list> <key-list: string-list>
2376
2377   envelope-part is case insensitive "from" or "to"
2378 #ifdef ENVELOPE_AUTH
2379   envelope-part =/ "auth"
2380 #endif
2381   */
2382
2383   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2384   enum AddressPart addressPart=ADDRPART_ALL;
2385   enum MatchType matchType=MATCH_IS;
2386   struct String *env,*e,*key,*k;
2387   int m;
2388   int co=0,ap=0,mt=0;
2389
2390   if (!filter->require_envelope)
2391     {
2392     filter->errmsg=CUS "missing previous require \"envelope\";";
2393     return -1;
2394     }
2395   for (;;)
2396     {
2397     if (parse_white(filter)==-1) return -1;
2398     if ((m=parse_comparator(filter,&comparator))!=0)
2399       {
2400       if (m==-1) return -1;
2401       if (co)
2402         {
2403         filter->errmsg=CUS "comparator already specified";
2404         return -1;
2405         }
2406       else co=1;
2407       }
2408     else if ((m=parse_addresspart(filter,&addressPart))!=0)
2409       {
2410       if (m==-1) return -1;
2411       if (ap)
2412         {
2413         filter->errmsg=CUS "address part already specified";
2414         return -1;
2415         }
2416       else ap=1;
2417       }
2418     else if ((m=parse_matchtype(filter,&matchType))!=0)
2419       {
2420       if (m==-1) return -1;
2421       if (mt)
2422         {
2423         filter->errmsg=CUS "match type already specified";
2424         return -1;
2425         }
2426       else mt=1;
2427       }
2428     else break;
2429     }
2430   if (parse_white(filter)==-1) return -1;
2431   if ((m=parse_stringlist(filter,&env))!=1)
2432     {
2433     if (m==0) filter->errmsg=CUS "envelope string list expected";
2434     return -1;
2435     }
2436   if (parse_white(filter)==-1) return -1;
2437   if ((m=parse_stringlist(filter,&key))!=1)
2438     {
2439     if (m==0) filter->errmsg=CUS "key string list expected";
2440     return -1;
2441     }
2442   *cond=0;
2443   for (e=env; e->length!=-1 && !*cond; ++e)
2444     {
2445     const uschar *envelopeExpr=CUS 0;
2446     uschar *envelope=US 0;
2447
2448     if (eq_asciicase(e,&str_from,0))
2449       {
2450       switch (addressPart)
2451         {
2452         case ADDRPART_ALL: envelopeExpr=CUS "$sender_address"; break;
2453 #ifdef SUBADDRESS
2454         case ADDRPART_USER:
2455 #endif
2456         case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$sender_address}"; break;
2457         case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$sender_address}"; break;
2458 #ifdef SUBADDRESS
2459         case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2460 #endif
2461         }
2462       }
2463     else if (eq_asciicase(e,&str_to,0))
2464       {
2465       switch (addressPart)
2466         {
2467         case ADDRPART_ALL: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix@$domain"; break;
2468 #ifdef SUBADDRESS
2469         case ADDRPART_USER: envelopeExpr=filter->useraddress; break;
2470         case ADDRPART_DETAIL: envelopeExpr=filter->subaddress; break;
2471 #endif
2472         case ADDRPART_LOCALPART: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix"; break;
2473         case ADDRPART_DOMAIN: envelopeExpr=CUS "$domain"; break;
2474         }
2475       }
2476 #ifdef ENVELOPE_AUTH
2477     else if (eq_asciicase(e,&str_auth,0))
2478       {
2479       switch (addressPart)
2480         {
2481         case ADDRPART_ALL: envelopeExpr=CUS "$authenticated_sender"; break;
2482 #ifdef SUBADDRESS
2483         case ADDRPART_USER:
2484 #endif
2485         case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$authenticated_sender}"; break;
2486         case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$authenticated_sender}"; break;
2487 #ifdef SUBADDRESS
2488         case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2489 #endif
2490         }
2491       }
2492 #endif
2493     else
2494       {
2495       filter->errmsg=CUS "invalid envelope string";
2496       return -1;
2497       }
2498     if (exec && envelopeExpr)
2499       {
2500       if ((envelope=expand_string(US envelopeExpr)) == NULL)
2501         {
2502         filter->errmsg=CUS "header string expansion failed";
2503         return -1;
2504         }
2505       for (k=key; k->length!=-1; ++k)
2506         {
2507         struct String envelopeStr;
2508
2509         envelopeStr.character=envelope;
2510         envelopeStr.length=Ustrlen(envelope);
2511         *cond=compare(filter,k,&envelopeStr,comparator,matchType);
2512         if (*cond==-1) return -1;
2513         if (*cond) break;
2514         }
2515       }
2516     }
2517   return 1;
2518   }
2519 #ifdef ENOTIFY
2520 else if (parse_identifier(filter,CUS "valid_notify_method"))
2521   {
2522   /*
2523   valid_notify_method = "valid_notify_method"
2524                         <notification-uris: string-list>
2525   */
2526
2527   struct String *uris,*u;
2528   int m;
2529
2530   if (!filter->require_enotify)
2531     {
2532     filter->errmsg=CUS "missing previous require \"enotify\";";
2533     return -1;
2534     }
2535   if (parse_white(filter)==-1) return -1;
2536   if ((m=parse_stringlist(filter,&uris))!=1)
2537     {
2538     if (m==0) filter->errmsg=CUS "URI string list expected";
2539     return -1;
2540     }
2541   if (exec)
2542     {
2543     *cond=1;
2544     for (u=uris; u->length!=-1 && *cond; ++u)
2545       {
2546         string_item *recipient;
2547         struct String header,subject,body;
2548
2549         recipient=NULL;
2550         header.length=-1;
2551         header.character=(uschar*)0;
2552         subject.length=-1;
2553         subject.character=(uschar*)0;
2554         body.length=-1;
2555         body.character=(uschar*)0;
2556         if (parse_mailto_uri(filter,u->character,&recipient,&header,&subject,&body)!=1)
2557           *cond=0;
2558       }
2559     }
2560   return 1;
2561   }
2562 else if (parse_identifier(filter,CUS "notify_method_capability"))
2563   {
2564   /*
2565   notify_method_capability = "notify_method_capability" [COMPARATOR] [MATCH-TYPE]
2566                              <notification-uri: string>
2567                              <notification-capability: string>
2568                              <key-list: string-list>
2569   */
2570
2571   int m;
2572   int co=0,mt=0;
2573
2574   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2575   enum MatchType matchType=MATCH_IS;
2576   struct String uri,capa,*keys,*k;
2577
2578   if (!filter->require_enotify)
2579     {
2580     filter->errmsg=CUS "missing previous require \"enotify\";";
2581     return -1;
2582     }
2583   for (;;)
2584     {
2585     if (parse_white(filter)==-1) return -1;
2586     if ((m=parse_comparator(filter,&comparator))!=0)
2587       {
2588       if (m==-1) return -1;
2589       if (co)
2590         {
2591         filter->errmsg=CUS "comparator already specified";
2592         return -1;
2593         }
2594       else co=1;
2595       }
2596     else if ((m=parse_matchtype(filter,&matchType))!=0)
2597       {
2598       if (m==-1) return -1;
2599       if (mt)
2600         {
2601         filter->errmsg=CUS "match type already specified";
2602         return -1;
2603         }
2604       else mt=1;
2605       }
2606     else break;
2607     }
2608     if ((m=parse_string(filter,&uri))!=1)
2609       {
2610       if (m==0) filter->errmsg=CUS "missing notification URI string";
2611       return -1;
2612       }
2613     if (parse_white(filter)==-1) return -1;
2614     if ((m=parse_string(filter,&capa))!=1)
2615       {
2616       if (m==0) filter->errmsg=CUS "missing notification capability string";
2617       return -1;
2618       }
2619     if (parse_white(filter)==-1) return -1;
2620     if ((m=parse_stringlist(filter,&keys))!=1)
2621       {
2622       if (m==0) filter->errmsg=CUS "missing key string list";
2623       return -1;
2624       }
2625     if (exec)
2626       {
2627       string_item *recipient;
2628       struct String header,subject,body;
2629
2630       *cond=0;
2631       recipient=NULL;
2632       header.length=-1;
2633       header.character=(uschar*)0;
2634       subject.length=-1;
2635       subject.character=(uschar*)0;
2636       body.length=-1;
2637       body.character=(uschar*)0;
2638       if (parse_mailto_uri(filter,uri.character,&recipient,&header,&subject,&body)==1)
2639         {
2640         if (eq_asciicase(&capa,&str_online,0)==1)
2641           for (k=keys; k->length!=-1; ++k)
2642             {
2643             *cond=compare(filter,k,&str_maybe,comparator,matchType);
2644             if (*cond==-1) return -1;
2645             if (*cond) break;
2646             }
2647         }
2648       }
2649     return 1;
2650   }
2651 #endif
2652 else return 0;
2653 }
2654
2655
2656 /*************************************************
2657 *     Parse and interpret an optional block      *
2658 *************************************************/
2659
2660 /*
2661 Arguments:
2662   filter      points to the Sieve filter including its state
2663   exec        Execute parsed statements
2664   generated   where to hang newly-generated addresses
2665
2666 Returns:      2                success by stop
2667               1                other success
2668               0                no block command found
2669               -1               syntax or execution error
2670 */
2671
2672 static int parse_block(struct Sieve *filter, int exec,
2673   address_item **generated)
2674 {
2675 int r;
2676
2677 if (parse_white(filter)==-1) return -1;
2678 if (*filter->pc=='{')
2679   {
2680   ++filter->pc;
2681   if ((r=parse_commands(filter,exec,generated))==-1 || r==2) return r;
2682   if (*filter->pc=='}')
2683     {
2684     ++filter->pc;
2685     return 1;
2686     }
2687   else
2688     {
2689     filter->errmsg=CUS "expecting command or closing brace";
2690     return -1;
2691     }
2692   }
2693 else return 0;
2694 }
2695
2696
2697 /*************************************************
2698 *           Match a semicolon                    *
2699 *************************************************/
2700
2701 /*
2702 Arguments:
2703   filter      points to the Sieve filter including its state
2704
2705 Returns:      1                success
2706               -1               syntax error
2707 */
2708
2709 static int parse_semicolon(struct Sieve *filter)
2710 {
2711   if (parse_white(filter)==-1) return -1;
2712   if (*filter->pc==';')
2713   {
2714     ++filter->pc;
2715     return 1;
2716   }
2717   else
2718   {
2719     filter->errmsg=CUS "missing semicolon";
2720     return -1;
2721   }
2722 }
2723
2724
2725 /*************************************************
2726 *     Parse and interpret a Sieve command        *
2727 *************************************************/
2728
2729 /*
2730 Arguments:
2731   filter      points to the Sieve filter including its state
2732   exec        Execute parsed statements
2733   generated   where to hang newly-generated addresses
2734
2735 Returns:      2                success by stop
2736               1                other success
2737               -1               syntax or execution error
2738 */
2739 static int
2740 parse_commands(struct Sieve *filter, int exec, address_item **generated)
2741 {
2742 while (*filter->pc)
2743   {
2744   if (parse_white(filter)==-1) return -1;
2745   if (parse_identifier(filter,CUS "if"))
2746     {
2747     /*
2748     if-command = "if" test block *( "elsif" test block ) [ else block ]
2749     */
2750
2751     int cond,m,unsuccessful;
2752
2753     /* test block */
2754     if (parse_white(filter)==-1) return -1;
2755     if ((m=parse_test(filter,&cond,exec))==-1) return -1;
2756     if (m==0)
2757       {
2758       filter->errmsg=CUS "missing test";
2759       return -1;
2760       }
2761     if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2762         (debug_selector & D_filter) != 0)
2763       {
2764       if (exec) debug_printf("if %s\n",cond?"true":"false");
2765       }
2766     m=parse_block(filter,exec ? cond : 0, generated);
2767     if (m==-1 || m==2) return m;
2768     if (m==0)
2769       {
2770       filter->errmsg=CUS "missing block";
2771       return -1;
2772       }
2773     unsuccessful = !cond;
2774     for (;;) /* elsif test block */
2775       {
2776       if (parse_white(filter)==-1) return -1;
2777       if (parse_identifier(filter,CUS "elsif"))
2778         {
2779         if (parse_white(filter)==-1) return -1;
2780         m=parse_test(filter,&cond,exec && unsuccessful);
2781         if (m==-1 || m==2) return m;
2782         if (m==0)
2783           {
2784           filter->errmsg=CUS "missing test";
2785           return -1;
2786           }
2787         if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2788             (debug_selector & D_filter) != 0)
2789           {
2790           if (exec) debug_printf("elsif %s\n",cond?"true":"false");
2791           }
2792         m=parse_block(filter,exec && unsuccessful ? cond : 0, generated);
2793         if (m==-1 || m==2) return m;
2794         if (m==0)
2795           {
2796           filter->errmsg=CUS "missing block";
2797           return -1;
2798           }
2799         if (exec && unsuccessful && cond) unsuccessful = 0;
2800         }
2801       else break;
2802       }
2803     /* else block */
2804     if (parse_white(filter)==-1) return -1;
2805     if (parse_identifier(filter,CUS "else"))
2806       {
2807       m=parse_block(filter,exec && unsuccessful, generated);
2808       if (m==-1 || m==2) return m;
2809       if (m==0)
2810         {
2811         filter->errmsg=CUS "missing block";
2812         return -1;
2813         }
2814       }
2815     }
2816   else if (parse_identifier(filter,CUS "stop"))
2817     {
2818     /*
2819     stop-command     =  "stop" { stop-options } ";"
2820     stop-options     =
2821     */
2822
2823     if (parse_semicolon(filter)==-1) return -1;
2824     if (exec)
2825       {
2826       filter->pc+=Ustrlen(filter->pc);
2827       return 2;
2828       }
2829     }
2830   else if (parse_identifier(filter,CUS "keep"))
2831     {
2832     /*
2833     keep-command     =  "keep" { keep-options } ";"
2834     keep-options     =
2835     */
2836
2837     if (parse_semicolon(filter)==-1) return -1;
2838     if (exec)
2839       {
2840       add_addr(generated,US"inbox",1,0,0,0);
2841       filter->keep = 0;
2842       }
2843     }
2844   else if (parse_identifier(filter,CUS "discard"))
2845     {
2846     /*
2847     discard-command  =  "discard" { discard-options } ";"
2848     discard-options  =
2849     */
2850
2851     if (parse_semicolon(filter)==-1) return -1;
2852     if (exec) filter->keep=0;
2853     }
2854   else if (parse_identifier(filter,CUS "redirect"))
2855     {
2856     /*
2857     redirect-command =  "redirect" redirect-options "string" ";"
2858     redirect-options =
2859     redirect-options =) ":copy"
2860     */
2861
2862     struct String recipient;
2863     int m;
2864     int copy=0;
2865
2866     for (;;)
2867       {
2868       if (parse_white(filter)==-1) return -1;
2869       if (parse_identifier(filter,CUS ":copy")==1)
2870         {
2871         if (!filter->require_copy)
2872           {
2873           filter->errmsg=CUS "missing previous require \"copy\";";
2874           return -1;
2875           }
2876           copy=1;
2877         }
2878       else break;
2879       }
2880     if (parse_white(filter)==-1) return -1;
2881     if ((m=parse_string(filter,&recipient))!=1)
2882       {
2883       if (m==0) filter->errmsg=CUS "missing redirect recipient string";
2884       return -1;
2885       }
2886     if (strchr(CCS recipient.character,'@')==(char*)0)
2887       {
2888       filter->errmsg=CUS "unqualified recipient address";
2889       return -1;
2890       }
2891     if (exec)
2892       {
2893       add_addr(generated,recipient.character,0,0,0,0);
2894       if (!copy) filter->keep = 0;
2895       }
2896     if (parse_semicolon(filter)==-1) return -1;
2897     }
2898   else if (parse_identifier(filter,CUS "fileinto"))
2899     {
2900     /*
2901     fileinto-command =  "fileinto" { fileinto-options } string ";"
2902     fileinto-options =
2903     fileinto-options =) [ ":copy" ]
2904     */
2905
2906     struct String folder;
2907     uschar *s;
2908     int m;
2909     unsigned long maxage, maxmessages, maxstorage;
2910     int copy=0;
2911
2912     maxage = maxmessages = maxstorage = 0;
2913     if (!filter->require_fileinto)
2914       {
2915       filter->errmsg=CUS "missing previous require \"fileinto\";";
2916       return -1;
2917       }
2918     for (;;)
2919       {
2920       if (parse_white(filter)==-1) return -1;
2921       if (parse_identifier(filter,CUS ":copy")==1)
2922         {
2923         if (!filter->require_copy)
2924           {
2925           filter->errmsg=CUS "missing previous require \"copy\";";
2926           return -1;
2927           }
2928           copy=1;
2929         }
2930       else break;
2931       }
2932     if (parse_white(filter)==-1) return -1;
2933     if ((m=parse_string(filter,&folder))!=1)
2934       {
2935       if (m==0) filter->errmsg=CUS "missing fileinto folder string";
2936       return -1;
2937       }
2938     m=0; s=folder.character;
2939     if (folder.length==0) m=1;
2940     if (Ustrcmp(s,"..")==0 || Ustrncmp(s,"../",3)==0) m=1;
2941     else while (*s)
2942       {
2943       if (Ustrcmp(s,"/..")==0 || Ustrncmp(s,"/../",4)==0) { m=1; break; }
2944       ++s;
2945       }
2946     if (m)
2947       {
2948       filter->errmsg=CUS "invalid folder";
2949       return -1;
2950       }
2951     if (exec)
2952       {
2953       add_addr(generated, folder.character, 1, maxage, maxmessages, maxstorage);
2954       if (!copy) filter->keep = 0;
2955       }
2956     if (parse_semicolon(filter)==-1) return -1;
2957     }
2958 #ifdef ENOTIFY
2959   else if (parse_identifier(filter,CUS "notify"))
2960     {
2961     /*
2962     notify-command =  "notify" { notify-options } <method: string> ";"
2963     notify-options =  [":from" string]
2964                       [":importance" <"1" / "2" / "3">]
2965                       [":options" 1*(string-list / number)]
2966                       [":message" string]
2967     */
2968
2969     int m;
2970     struct String from;
2971     struct String importance;
2972     struct String message;
2973     struct String method;
2974     struct Notification *already;
2975     string_item *recipient;
2976     struct String header;
2977     struct String subject;
2978     struct String body;
2979     uschar *envelope_from;
2980     struct String auto_submitted_value;
2981     uschar *auto_submitted_def;
2982
2983     if (!filter->require_enotify)
2984       {
2985       filter->errmsg=CUS "missing previous require \"enotify\";";
2986       return -1;
2987       }
2988     from.character=(uschar*)0;
2989     from.length=-1;
2990     importance.character=(uschar*)0;
2991     importance.length=-1;
2992     message.character=(uschar*)0;
2993     message.length=-1;
2994     recipient=NULL;
2995     header.length=-1;
2996     header.character=(uschar*)0;
2997     subject.length=-1;
2998     subject.character=(uschar*)0;
2999     body.length=-1;
3000     body.character=(uschar*)0;
3001     envelope_from=(sender_address && sender_address[0]) ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : US "";
3002     for (;;)
3003       {
3004       if (parse_white(filter)==-1) return -1;
3005       if (parse_identifier(filter,CUS ":from")==1)
3006         {
3007         if (parse_white(filter)==-1) return -1;
3008         if ((m=parse_string(filter,&from))!=1)
3009           {
3010           if (m==0) filter->errmsg=CUS "from string expected";
3011           return -1;
3012           }
3013         }
3014       else if (parse_identifier(filter,CUS ":importance")==1)
3015         {
3016         if (parse_white(filter)==-1) return -1;
3017         if ((m=parse_string(filter,&importance))!=1)
3018           {
3019           if (m==0) filter->errmsg=CUS "importance string expected";
3020           return -1;
3021           }
3022         if (importance.length!=1 || importance.character[0]<'1' || importance.character[0]>'3')
3023           {
3024           filter->errmsg=CUS "invalid importance";
3025           return -1;
3026           }
3027         }
3028       else if (parse_identifier(filter,CUS ":options")==1)
3029         {
3030         if (parse_white(filter)==-1) return -1;
3031         }
3032       else if (parse_identifier(filter,CUS ":message")==1)
3033         {
3034         if (parse_white(filter)==-1) return -1;
3035         if ((m=parse_string(filter,&message))!=1)
3036           {
3037           if (m==0) filter->errmsg=CUS "message string expected";
3038           return -1;
3039           }
3040         }
3041       else break;
3042       }
3043     if (parse_white(filter)==-1) return -1;
3044     if ((m=parse_string(filter,&method))!=1)
3045       {
3046       if (m==0) filter->errmsg=CUS "missing method string";
3047       return -1;
3048       }
3049     if (parse_semicolon(filter)==-1) return -1;
3050     if (parse_mailto_uri(filter,method.character,&recipient,&header,&subject,&body)!=1)
3051       return -1;
3052     if (exec)
3053       {
3054       if (message.length==-1) message=subject;
3055       if (message.length==-1) expand_header(&message,&str_subject);
3056       expand_header(&auto_submitted_value,&str_auto_submitted);
3057       auto_submitted_def=expand_string(string_sprintf("${if def:header_auto-submitted {true}{false}}"));
3058       if (auto_submitted_value.character == NULL || auto_submitted_def == NULL)
3059         {
3060         filter->errmsg=CUS "header string expansion failed";
3061         return -1;
3062         }
3063         if (Ustrcmp(auto_submitted_def,"true")!=0 || Ustrcmp(auto_submitted_value.character,"no")==0)
3064         {
3065         for (already=filter->notified; already; already=already->next)
3066           {
3067           if (already->method.length==method.length
3068               && (method.length==-1 || Ustrcmp(already->method.character,method.character)==0)
3069               && already->importance.length==importance.length
3070               && (importance.length==-1 || Ustrcmp(already->importance.character,importance.character)==0)
3071               && already->message.length==message.length
3072               && (message.length==-1 || Ustrcmp(already->message.character,message.character)==0))
3073             break;
3074           }
3075         if (already==(struct Notification*)0)
3076           /* New notification, process it */
3077           {
3078           struct Notification *sent;
3079           sent=store_get(sizeof(struct Notification));
3080           sent->method=method;
3081           sent->importance=importance;
3082           sent->message=message;
3083           sent->next=filter->notified;
3084           filter->notified=sent;
3085   #ifndef COMPILE_SYNTAX_CHECKER
3086           if (filter_test == FTEST_NONE)
3087             {
3088             string_item *p;
3089             int pid,fd;
3090
3091             if ((pid = child_open_exim2(&fd,envelope_from,envelope_from))>=1)
3092               {
3093               FILE *f;
3094               uschar *buffer;
3095               int buffer_capacity;
3096
3097               f = fdopen(fd, "wb");
3098               fprintf(f,"From: %s\n",from.length==-1 ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : from.character);
3099               for (p=recipient; p; p=p->next) fprintf(f,"To: %s\n",p->text);
3100               fprintf(f,"Auto-Submitted: auto-notified; %s\n",filter->enotify_mailto_owner);
3101               if (header.length>0) fprintf(f,"%s",header.character);
3102               if (message.length==-1)
3103                 {
3104                 message.character=US"Notification";
3105                 message.length=Ustrlen(message.character);
3106                 }
3107               /* Allocation is larger than neccessary, but enough even for split MIME words */
3108               buffer_capacity=32+4*message.length;
3109               buffer=store_get(buffer_capacity);
3110               if (message.length!=-1) fprintf(f,"Subject: %s\n",parse_quote_2047(message.character, message.length, US"utf-8", buffer, buffer_capacity, TRUE));
3111               fprintf(f,"\n");
3112               if (body.length>0) fprintf(f,"%s\n",body.character);
3113               fflush(f);
3114               (void)fclose(f);
3115               (void)child_close(pid, 0);
3116               }
3117             }
3118           if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3119             {
3120             debug_printf("Notification to `%s': '%s'.\n",method.character,message.length!=-1 ? message.character : CUS "");
3121             }
3122 #endif
3123           }
3124         else
3125           {
3126           if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3127             {
3128             debug_printf("Repeated notification to `%s' ignored.\n",method.character);
3129             }
3130           }
3131         }
3132       else
3133         {
3134         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3135           {
3136           debug_printf("Ignoring notification, triggering message contains Auto-submitted: field.\n");
3137           }
3138         }
3139       }
3140     }
3141 #endif
3142 #ifdef VACATION
3143   else if (parse_identifier(filter,CUS "vacation"))
3144     {
3145     /*
3146     vacation-command =  "vacation" { vacation-options } <reason: string> ";"
3147     vacation-options =  [":days" number]
3148                         [":subject" string]
3149                         [":from" string]
3150                         [":addresses" string-list]
3151                         [":mime"]
3152                         [":handle" string]
3153     */
3154
3155     int m;
3156     unsigned long days;
3157     struct String subject;
3158     struct String from;
3159     struct String *addresses;
3160     int reason_is_mime;
3161     string_item *aliases;
3162     struct String handle;
3163     struct String reason;
3164
3165     if (!filter->require_vacation)
3166       {
3167       filter->errmsg=CUS "missing previous require \"vacation\";";
3168       return -1;
3169       }
3170     if (exec)
3171       {
3172       if (filter->vacation_ran)
3173         {
3174         filter->errmsg=CUS "trying to execute vacation more than once";
3175         return -1;
3176         }
3177       filter->vacation_ran=1;
3178       }
3179     days=VACATION_MIN_DAYS>7 ? VACATION_MIN_DAYS : 7;
3180     subject.character=(uschar*)0;
3181     subject.length=-1;
3182     from.character=(uschar*)0;
3183     from.length=-1;
3184     addresses=(struct String*)0;
3185     aliases=NULL;
3186     reason_is_mime=0;
3187     handle.character=(uschar*)0;
3188     handle.length=-1;
3189     for (;;)
3190       {
3191       if (parse_white(filter)==-1) return -1;
3192       if (parse_identifier(filter,CUS ":days")==1)
3193         {
3194         if (parse_white(filter)==-1) return -1;
3195         if (parse_number(filter,&days)==-1) return -1;
3196         if (days<VACATION_MIN_DAYS) days=VACATION_MIN_DAYS;
3197         else if (days>VACATION_MAX_DAYS) days=VACATION_MAX_DAYS;
3198         }
3199       else if (parse_identifier(filter,CUS ":subject")==1)
3200         {
3201         if (parse_white(filter)==-1) return -1;
3202         if ((m=parse_string(filter,&subject))!=1)
3203           {
3204           if (m==0) filter->errmsg=CUS "subject string expected";
3205           return -1;
3206           }
3207         }
3208       else if (parse_identifier(filter,CUS ":from")==1)
3209         {
3210         if (parse_white(filter)==-1) return -1;
3211         if ((m=parse_string(filter,&from))!=1)
3212           {
3213           if (m==0) filter->errmsg=CUS "from string expected";
3214           return -1;
3215           }
3216         if (check_mail_address(filter,&from)!=1)
3217           return -1;
3218         }
3219       else if (parse_identifier(filter,CUS ":addresses")==1)
3220         {
3221         struct String *a;
3222
3223         if (parse_white(filter)==-1) return -1;
3224         if ((m=parse_stringlist(filter,&addresses))!=1)
3225           {
3226           if (m==0) filter->errmsg=CUS "addresses string list expected";
3227           return -1;
3228           }
3229         for (a=addresses; a->length!=-1; ++a)
3230           {
3231           string_item *new;
3232
3233           new=store_get(sizeof(string_item));
3234           new->text=store_get(a->length+1);
3235           if (a->length) memcpy(new->text,a->character,a->length);
3236           new->text[a->length]='\0';
3237           new->next=aliases;
3238           aliases=new;
3239           }
3240         }
3241       else if (parse_identifier(filter,CUS ":mime")==1)
3242         reason_is_mime=1;
3243       else if (parse_identifier(filter,CUS ":handle")==1)
3244         {
3245         if (parse_white(filter)==-1) return -1;
3246         if ((m=parse_string(filter,&from))!=1)
3247           {
3248           if (m==0) filter->errmsg=CUS "handle string expected";
3249           return -1;
3250           }
3251         }
3252       else break;
3253       }
3254     if (parse_white(filter)==-1) return -1;
3255     if ((m=parse_string(filter,&reason))!=1)
3256       {
3257       if (m==0) filter->errmsg=CUS "missing reason string";
3258       return -1;
3259       }
3260     if (reason_is_mime)
3261       {
3262       uschar *s,*end;
3263
3264       for (s=reason.character,end=reason.character+reason.length; s<end && (*s&0x80)==0; ++s);
3265       if (s<end)
3266         {
3267         filter->errmsg=CUS "MIME reason string contains 8bit text";
3268         return -1;
3269         }
3270       }
3271     if (parse_semicolon(filter)==-1) return -1;
3272
3273     if (exec)
3274       {
3275       address_item *addr;
3276       int capacity,start;
3277       uschar *buffer;
3278       int buffer_capacity;
3279       struct String key;
3280       md5 base;
3281       uschar digest[16];
3282       uschar hexdigest[33];
3283       int i;
3284       uschar *once;
3285
3286       if (filter_personal(aliases,TRUE))
3287         {
3288         if (filter_test == FTEST_NONE)
3289           {
3290           /* ensure oncelog directory exists; failure will be detected later */
3291
3292           (void)directory_make(NULL, filter->vacation_directory, 0700, FALSE);
3293           }
3294         /* build oncelog filename */
3295
3296         key.character=(uschar*)0;
3297         key.length=0;
3298         capacity=0;
3299         if (handle.length==-1)
3300           {
3301           if (subject.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,subject.character,subject.length);
3302           if (from.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,from.character,from.length);
3303           key.character=string_catn(key.character,&capacity,&key.length,reason_is_mime?US"1":US"0",1);
3304           key.character=string_catn(key.character,&capacity,&key.length,reason.character,reason.length);
3305           }
3306         else
3307           key=handle;
3308         md5_start(&base);
3309         md5_end(&base, key.character, key.length, digest);
3310         for (i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]);
3311         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3312           {
3313           debug_printf("Sieve: mail was personal, vacation file basename: %s\n", hexdigest);
3314           }
3315         if (filter_test == FTEST_NONE)
3316           {
3317           capacity=Ustrlen(filter->vacation_directory);
3318           start=capacity;
3319           once=string_catn(filter->vacation_directory,&capacity,&start,US"/",1);
3320           once=string_catn(once,&capacity,&start,hexdigest,33);
3321           once[start] = '\0';
3322
3323           /* process subject */
3324
3325           if (subject.length==-1)
3326             {
3327             uschar *subject_def;
3328
3329             subject_def=expand_string(US"${if def:header_subject {true}{false}}");
3330             if (Ustrcmp(subject_def,"true")==0)
3331               {
3332               expand_header(&subject,&str_subject);
3333               capacity=6;
3334               start=6;
3335               subject.character=string_catn(US"Auto: ",&capacity,&start,subject.character,subject.length);
3336               subject.length=start;
3337               }
3338             else
3339               {
3340               subject.character=US"Automated reply";
3341               subject.length=Ustrlen(subject.character);
3342               }
3343             }
3344
3345           /* add address to list of generated addresses */
3346
3347           addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
3348           setflag(addr, af_pfr);
3349           setflag(addr, af_ignore_error);
3350           addr->next = *generated;
3351           *generated = addr;
3352           addr->reply = store_get(sizeof(reply_item));
3353           memset(addr->reply,0,sizeof(reply_item)); /* XXX */
3354           addr->reply->to = string_copy(sender_address);
3355           if (from.length==-1)
3356             addr->reply->from = expand_string(US"$local_part@$domain");
3357           else
3358             addr->reply->from = from.character;
3359           /* Allocation is larger than neccessary, but enough even for split MIME words */
3360           buffer_capacity=32+4*subject.length;
3361           buffer=store_get(buffer_capacity);
3362           /* deconst cast safe as we pass in a non-const item */
3363           addr->reply->subject = US parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE);
3364           addr->reply->oncelog=once;
3365           addr->reply->once_repeat=days*86400;
3366
3367           /* build body and MIME headers */
3368
3369           if (reason_is_mime)
3370             {
3371             uschar *mime_body,*reason_end;
3372             static const uschar nlnl[]="\r\n\r\n";
3373
3374             for
3375               (
3376               mime_body=reason.character,reason_end=reason.character+reason.length;
3377               mime_body<(reason_end-(sizeof(nlnl)-1)) && memcmp(mime_body,nlnl,(sizeof(nlnl)-1));
3378               ++mime_body
3379               );
3380             capacity = 0;
3381             start = 0;
3382             addr->reply->headers = string_catn(NULL,&capacity,&start,reason.character,mime_body-reason.character);
3383             addr->reply->headers[start] = '\0';
3384             capacity = 0;
3385             start = 0;
3386             if (mime_body+(sizeof(nlnl)-1)<reason_end) mime_body+=(sizeof(nlnl)-1);
3387             else mime_body=reason_end-1;
3388             addr->reply->text = string_catn(NULL,&capacity,&start,mime_body,reason_end-mime_body);
3389             addr->reply->text[start] = '\0';
3390             }
3391           else
3392             {
3393             struct String qp = { NULL, 0 };  /* Keep compiler happy (PH) */
3394
3395             capacity = 0;
3396             start = reason.length;
3397             addr->reply->headers = US"MIME-Version: 1.0\n"
3398                                    "Content-Type: text/plain;\n"
3399                                    "\tcharset=\"utf-8\"\n"
3400                                    "Content-Transfer-Encoding: quoted-printable";
3401             addr->reply->text = quoted_printable_encode(&reason,&qp)->character;
3402             }
3403           }
3404         }
3405         else if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3406           {
3407           debug_printf("Sieve: mail was not personal, vacation would ignore it\n");
3408           }
3409       }
3410     }
3411     else break;
3412 #endif
3413   }
3414 return 1;
3415 }
3416
3417
3418 /*************************************************
3419 *       Parse and interpret a sieve filter       *
3420 *************************************************/
3421
3422 /*
3423 Arguments:
3424   filter      points to the Sieve filter including its state
3425   exec        Execute parsed statements
3426   generated   where to hang newly-generated addresses
3427
3428 Returns:      1                success
3429               -1               syntax or execution error
3430 */
3431
3432 static int
3433 parse_start(struct Sieve *filter, int exec, address_item **generated)
3434 {
3435 filter->pc=filter->filter;
3436 filter->line=1;
3437 filter->keep=1;
3438 filter->require_envelope=0;
3439 filter->require_fileinto=0;
3440 #ifdef ENCODED_CHARACTER
3441 filter->require_encoded_character=0;
3442 #endif
3443 #ifdef ENVELOPE_AUTH
3444 filter->require_envelope_auth=0;
3445 #endif
3446 #ifdef ENOTIFY
3447 filter->require_enotify=0;
3448 filter->notified=(struct Notification*)0;
3449 #endif
3450 #ifdef SUBADDRESS
3451 filter->require_subaddress=0;
3452 #endif
3453 #ifdef VACATION
3454 filter->require_vacation=0;
3455 filter->vacation_ran=0;
3456 #endif
3457 filter->require_copy=0;
3458 filter->require_iascii_numeric=0;
3459
3460 if (parse_white(filter)==-1) return -1;
3461
3462 if (exec && filter->vacation_directory != NULL && filter_test == FTEST_NONE)
3463   {
3464   DIR *oncelogdir;
3465   struct dirent *oncelog;
3466   struct stat properties;
3467   time_t now;
3468
3469   /* clean up old vacation log databases */
3470
3471   oncelogdir=opendir(CS filter->vacation_directory);
3472
3473   if (oncelogdir ==(DIR*)0 && errno != ENOENT)
3474     {
3475     filter->errmsg=CUS "unable to open vacation directory";
3476     return -1;
3477     }
3478
3479   if (oncelogdir != NULL)
3480     {
3481     time(&now);
3482
3483     while ((oncelog=readdir(oncelogdir))!=(struct dirent*)0)
3484       {
3485       if (strlen(oncelog->d_name)==32)
3486         {
3487         uschar *s=string_sprintf("%s/%s",filter->vacation_directory,oncelog->d_name);
3488         if (Ustat(s,&properties)==0 && (properties.st_mtime+VACATION_MAX_DAYS*86400)<now)
3489           Uunlink(s);
3490         }
3491       }
3492     closedir(oncelogdir);
3493     }
3494   }
3495
3496 while (parse_identifier(filter,CUS "require"))
3497   {
3498   /*
3499   require-command = "require" <capabilities: string-list>
3500   */
3501
3502   struct String *cap,*check;
3503   int m;
3504
3505   if (parse_white(filter)==-1) return -1;
3506   if ((m=parse_stringlist(filter,&cap))!=1)
3507     {
3508     if (m==0) filter->errmsg=CUS "capability string list expected";
3509     return -1;
3510     }
3511   for (check=cap; check->character; ++check)
3512     {
3513     if (eq_octet(check,&str_envelope,0)) filter->require_envelope=1;
3514     else if (eq_octet(check,&str_fileinto,0)) filter->require_fileinto=1;
3515 #ifdef ENCODED_CHARACTER
3516     else if (eq_octet(check,&str_encoded_character,0)) filter->require_encoded_character=1;
3517 #endif
3518 #ifdef ENVELOPE_AUTH
3519     else if (eq_octet(check,&str_envelope_auth,0)) filter->require_envelope_auth=1;
3520 #endif
3521 #ifdef ENOTIFY
3522     else if (eq_octet(check,&str_enotify,0))
3523       {
3524       if (filter->enotify_mailto_owner == NULL)
3525         {
3526         filter->errmsg=CUS "enotify disabled";
3527         return -1;
3528         }
3529         filter->require_enotify=1;
3530       }
3531 #endif
3532 #ifdef SUBADDRESS
3533     else if (eq_octet(check,&str_subaddress,0)) filter->require_subaddress=1;
3534 #endif
3535 #ifdef VACATION
3536     else if (eq_octet(check,&str_vacation,0))
3537       {
3538       if (filter_test == FTEST_NONE && filter->vacation_directory == NULL)
3539         {
3540         filter->errmsg=CUS "vacation disabled";
3541         return -1;
3542         }
3543       filter->require_vacation=1;
3544       }
3545 #endif
3546     else if (eq_octet(check,&str_copy,0)) filter->require_copy=1;
3547     else if (eq_octet(check,&str_comparator_ioctet,0)) ;
3548     else if (eq_octet(check,&str_comparator_iascii_casemap,0)) ;
3549     else if (eq_octet(check,&str_comparator_enascii_casemap,0)) ;
3550     else if (eq_octet(check,&str_comparator_iascii_numeric,0)) filter->require_iascii_numeric=1;
3551     else
3552       {
3553       filter->errmsg=CUS "unknown capability";
3554       return -1;
3555       }
3556     }
3557     if (parse_semicolon(filter)==-1) return -1;
3558   }
3559   if (parse_commands(filter,exec,generated)==-1) return -1;
3560   if (*filter->pc)
3561     {
3562     filter->errmsg=CUS "syntax error";
3563     return -1;
3564     }
3565   return 1;
3566 }
3567
3568
3569 /*************************************************
3570 *            Interpret a sieve filter file       *
3571 *************************************************/
3572
3573 /*
3574 Arguments:
3575   filter      points to the entire file, read into store as a single string
3576   options     controls whether various special things are allowed, and requests
3577               special actions (not currently used)
3578   vacation_directory    where to store vacation "once" files
3579   enotify_mailto_owner  owner of mailto notifications
3580   useraddress string expression for :user part of address
3581   subaddress  string expression for :subaddress part of address
3582   generated   where to hang newly-generated addresses
3583   error       where to pass back an error text
3584
3585 Returns:      FF_DELIVERED     success, a significant action was taken
3586               FF_NOTDELIVERED  success, no significant action
3587               FF_DEFER         defer requested
3588               FF_FAIL          fail requested
3589               FF_FREEZE        freeze requested
3590               FF_ERROR         there was a problem
3591 */
3592
3593 int
3594 sieve_interpret(uschar *filter, int options, uschar *vacation_directory,
3595   uschar *enotify_mailto_owner, uschar *useraddress, uschar *subaddress,
3596   address_item **generated, uschar **error)
3597 {
3598 struct Sieve sieve;
3599 int r;
3600 uschar *msg;
3601
3602 options = options; /* Keep picky compilers happy */
3603 error = error;
3604
3605 DEBUG(D_route) debug_printf("Sieve: start of processing\n");
3606 sieve.filter=filter;
3607
3608 if (vacation_directory == NULL)
3609   sieve.vacation_directory = NULL;
3610 else
3611   {
3612   sieve.vacation_directory=expand_string(vacation_directory);
3613   if (sieve.vacation_directory == NULL)
3614     {
3615     *error = string_sprintf("failed to expand \"%s\" "
3616       "(sieve_vacation_directory): %s", vacation_directory,
3617       expand_string_message);
3618     return FF_ERROR;
3619     }
3620   }
3621
3622 if (enotify_mailto_owner == NULL)
3623   sieve.enotify_mailto_owner = NULL;
3624 else
3625   {
3626   sieve.enotify_mailto_owner=expand_string(enotify_mailto_owner);
3627   if (sieve.enotify_mailto_owner == NULL)
3628     {
3629     *error = string_sprintf("failed to expand \"%s\" "
3630       "(sieve_enotify_mailto_owner): %s", enotify_mailto_owner,
3631       expand_string_message);
3632     return FF_ERROR;
3633     }
3634   }
3635
3636 sieve.useraddress = useraddress == NULL ? CUS "$local_part_prefix$local_part$local_part_suffix" : useraddress;
3637 sieve.subaddress = subaddress;
3638
3639 #ifdef COMPILE_SYNTAX_CHECKER
3640 if (parse_start(&sieve,0,generated)==1)
3641 #else
3642 if (parse_start(&sieve,1,generated)==1)
3643 #endif
3644   {
3645   if (sieve.keep)
3646     {
3647     add_addr(generated,US"inbox",1,0,0,0);
3648     msg = string_sprintf("Implicit keep");
3649     r = FF_DELIVERED;
3650     }
3651   else
3652     {
3653     msg = string_sprintf("No implicit keep");
3654     r = FF_DELIVERED;
3655     }
3656   }
3657 else
3658   {
3659   msg = string_sprintf("Sieve error: %s in line %d",sieve.errmsg,sieve.line);
3660 #ifdef COMPILE_SYNTAX_CHECKER
3661   r = FF_ERROR;
3662   *error = msg;
3663 #else
3664   add_addr(generated,US"inbox",1,0,0,0);
3665   r = FF_DELIVERED;
3666 #endif
3667   }
3668
3669 #ifndef COMPILE_SYNTAX_CHECKER
3670 if (filter_test != FTEST_NONE) printf("%s\n", (const char*) msg);
3671   else debug_printf("%s\n", msg);
3672 #endif
3673
3674 DEBUG(D_route) debug_printf("Sieve: end of processing\n");
3675 return r;
3676 }