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