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