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