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