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