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