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