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