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