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