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