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