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