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