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