Sort out group syntax problems, particularly with verify=header_sender.
[exim.git] / src / src / sieve.c
1 /* $Cambridge: exim/src/src/sieve.c,v 1.23 2006/10/10 15:36:50 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       parse_allow_group = FALSE;
1830       parse_found_group = FALSE;
1831       }
1832     }
1833   return 1;
1834   }
1835 else if (parse_identifier(filter,CUS "allof"))
1836   {
1837   /*
1838   allof-test   = "allof" <tests: test-list>
1839   */
1840
1841   int n,true;
1842
1843   switch (parse_testlist(filter,&n,&true,exec))
1844     {
1845     case -1: return -1;
1846     case 0: filter->errmsg=CUS "missing test list"; return -1;
1847     default: *cond=(n==true); return 1;
1848     }
1849   }
1850 else if (parse_identifier(filter,CUS "anyof"))
1851   {
1852   /*
1853   anyof-test   = "anyof" <tests: test-list>
1854   */
1855
1856   int n,true;
1857
1858   switch (parse_testlist(filter,&n,&true,exec))
1859     {
1860     case -1: return -1;
1861     case 0: filter->errmsg=CUS "missing test list"; return -1;
1862     default: *cond=(true>0); return 1;
1863     }
1864   }
1865 else if (parse_identifier(filter,CUS "exists"))
1866   {
1867   /*
1868   exists-test = "exists" <header-names: string-list>
1869   */
1870
1871   struct String *hdr,*h;
1872   int m;
1873
1874   if (parse_white(filter)==-1) return -1;
1875   if ((m=parse_stringlist(filter,&hdr))!=1)
1876     {
1877     if (m==0) filter->errmsg=CUS "header string list expected";
1878     return -1;
1879     }
1880   if (exec)
1881     {
1882     *cond=1;
1883     for (h=hdr; h->length!=-1 && *cond; ++h)
1884       {
1885       uschar *header_def;
1886
1887       header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
1888       if (header_def == NULL)
1889         {
1890         filter->errmsg=CUS "header string expansion failed";
1891         return -1;
1892         }
1893       if (Ustrcmp(header_def,"false")==0) *cond=0;
1894       }
1895     }
1896   return 1;
1897   }
1898 else if (parse_identifier(filter,CUS "false"))
1899   {
1900   /*
1901   false-test = "false"
1902   */
1903
1904   *cond=0;
1905   return 1;
1906   }
1907 else if (parse_identifier(filter,CUS "header"))
1908   {
1909   /*
1910   header-test = "header" { [comparator] [match-type] }
1911                 <header-names: string-list> <key-list: string-list>
1912   */
1913
1914   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
1915   enum MatchType matchType=MATCH_IS;
1916   struct String *hdr,*h,*key,*k;
1917   int m;
1918   int co=0,mt=0;
1919
1920   for (;;)
1921     {
1922     if (parse_white(filter)==-1) return -1;
1923     if ((m=parse_comparator(filter,&comparator))!=0)
1924       {
1925       if (m==-1) return -1;
1926       if (co)
1927         {
1928         filter->errmsg=CUS "comparator already specified";
1929         return -1;
1930         }
1931       else co=1;
1932       }
1933     else if ((m=parse_matchtype(filter,&matchType))!=0)
1934       {
1935       if (m==-1) return -1;
1936       if (mt)
1937         {
1938         filter->errmsg=CUS "match type already specified";
1939         return -1;
1940         }
1941       else mt=1;
1942       }
1943     else break;
1944     }
1945   if (parse_white(filter)==-1) return -1;
1946   if ((m=parse_stringlist(filter,&hdr))!=1)
1947     {
1948     if (m==0) filter->errmsg=CUS "header string list expected";
1949     return -1;
1950     }
1951   if (parse_white(filter)==-1) return -1;
1952   if ((m=parse_stringlist(filter,&key))!=1)
1953     {
1954     if (m==0) filter->errmsg=CUS "key string list expected";
1955     return -1;
1956     }
1957   *cond=0;
1958   for (h=hdr; h->length!=-1 && !*cond; ++h)
1959     {
1960     if (!is_header(h))
1961       {
1962       filter->errmsg=CUS "invalid header field";
1963       return -1;
1964       }
1965     if (exec)
1966       {
1967       struct String header_value;
1968       uschar *header_def;
1969
1970       expand_header(&header_value,h);
1971       header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
1972       if (header_value.character == NULL || header_def == NULL)
1973         {
1974         filter->errmsg=CUS "header string expansion failed";
1975         return -1;
1976         }
1977       for (k=key; k->length!=-1; ++k)
1978         {
1979         if (Ustrcmp(header_def,"true")==0)
1980           {
1981           *cond=compare(filter,k,&header_value,comparator,matchType);
1982           if (*cond==-1) return -1;
1983           if (*cond) break;
1984           }
1985         }
1986       }
1987     }
1988   return 1;
1989   }
1990 else if (parse_identifier(filter,CUS "not"))
1991   {
1992   if (parse_white(filter)==-1) return -1;
1993   switch (parse_test(filter,cond,exec))
1994     {
1995     case -1: return -1;
1996     case 0: filter->errmsg=CUS "missing test"; return -1;
1997     default: *cond=!*cond; return 1;
1998     }
1999   }
2000 else if (parse_identifier(filter,CUS "size"))
2001   {
2002   /*
2003   relop = ":over" / ":under"
2004   size-test = "size" relop <limit: number>
2005   */
2006
2007   unsigned long limit;
2008   int overNotUnder;
2009
2010   if (parse_white(filter)==-1) return -1;
2011   if (parse_identifier(filter,CUS ":over")) overNotUnder=1;
2012   else if (parse_identifier(filter,CUS ":under")) overNotUnder=0;
2013   else
2014     {
2015     filter->errmsg=CUS "missing :over or :under";
2016     return -1;
2017     }
2018   if (parse_white(filter)==-1) return -1;
2019   if (parse_number(filter,&limit)==-1) return -1;
2020   *cond=(overNotUnder ? (message_size>limit) : (message_size<limit));
2021   return 1;
2022   }
2023 else if (parse_identifier(filter,CUS "true"))
2024   {
2025   *cond=1;
2026   return 1;
2027   }
2028 else if (parse_identifier(filter,CUS "envelope"))
2029   {
2030   /*
2031   envelope-test = "envelope" { [comparator] [address-part] [match-type] }
2032                   <envelope-part: string-list> <key-list: string-list>
2033
2034   envelope-part is case insensitive "from" or "to"
2035 #ifdef ENVELOPE_AUTH
2036   envelope-part =/ "auth"
2037 #endif
2038   */
2039
2040   enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2041   enum AddressPart addressPart=ADDRPART_ALL;
2042   enum MatchType matchType=MATCH_IS;
2043   struct String *env,*e,*key,*k;
2044   int m;
2045   int co=0,ap=0,mt=0;
2046
2047   if (!filter->require_envelope)
2048     {
2049     filter->errmsg=CUS "missing previous require \"envelope\";";
2050     return -1;
2051     }
2052   for (;;)
2053     {
2054     if (parse_white(filter)==-1) return -1;
2055     if ((m=parse_comparator(filter,&comparator))!=0)
2056       {
2057       if (m==-1) return -1;
2058       if (co)
2059         {
2060         filter->errmsg=CUS "comparator already specified";
2061         return -1;
2062         }
2063       else co=1;
2064       }
2065     else if ((m=parse_addresspart(filter,&addressPart))!=0)
2066       {
2067       if (m==-1) return -1;
2068       if (ap)
2069         {
2070         filter->errmsg=CUS "address part already specified";
2071         return -1;
2072         }
2073       else ap=1;
2074       }
2075     else if ((m=parse_matchtype(filter,&matchType))!=0)
2076       {
2077       if (m==-1) return -1;
2078       if (mt)
2079         {
2080         filter->errmsg=CUS "match type already specified";
2081         return -1;
2082         }
2083       else mt=1;
2084       }
2085     else break;
2086     }
2087   if (parse_white(filter)==-1) return -1;
2088   if ((m=parse_stringlist(filter,&env))!=1)
2089     {
2090     if (m==0) filter->errmsg=CUS "envelope string list expected";
2091     return -1;
2092     }
2093   if (parse_white(filter)==-1) return -1;
2094   if ((m=parse_stringlist(filter,&key))!=1)
2095     {
2096     if (m==0) filter->errmsg=CUS "key string list expected";
2097     return -1;
2098     }
2099   *cond=0;
2100   for (e=env; e->length!=-1 && !*cond; ++e)
2101     {
2102     const uschar *envelopeExpr=CUS 0;
2103     uschar *envelope=US 0;
2104
2105     if (eq_asciicase(e,&str_from,0))
2106       {
2107       switch (addressPart)
2108         {
2109         case ADDRPART_ALL: envelopeExpr=CUS "$sender_address"; break;
2110 #ifdef SUBADDRESS
2111         case ADDRPART_USER:
2112 #endif
2113         case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$sender_address}"; break;
2114         case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$sender_address}"; break;
2115 #ifdef SUBADDRESS
2116         case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2117 #endif
2118         }
2119       }
2120     else if (eq_asciicase(e,&str_to,0))
2121       {
2122       switch (addressPart)
2123         {
2124         case ADDRPART_ALL: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix@$domain"; break;
2125 #ifdef SUBADDRESS
2126         case ADDRPART_USER: envelopeExpr=filter->useraddress; break;
2127         case ADDRPART_DETAIL: envelopeExpr=filter->subaddress; break;
2128 #endif
2129         case ADDRPART_LOCALPART: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix"; break;
2130         case ADDRPART_DOMAIN: envelopeExpr=CUS "$domain"; break;
2131         }
2132       }
2133 #ifdef ENVELOPE_AUTH
2134     else if (eq_asciicase(e,&str_auth,0))
2135       {
2136       switch (addressPart)
2137         {
2138         case ADDRPART_ALL: envelopeExpr=CUS "$authenticated_sender"; break;
2139 #ifdef SUBADDRESS
2140         case ADDRPART_USER:
2141 #endif
2142         case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$authenticated_sender}"; break;
2143         case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$authenticated_sender}"; break;
2144 #ifdef SUBADDRESS
2145         case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2146 #endif
2147         }
2148       }
2149 #endif
2150     else
2151       {
2152       filter->errmsg=CUS "invalid envelope string";
2153       return -1;
2154       }
2155     if (exec && envelopeExpr)
2156       {
2157       if ((envelope=expand_string(US envelopeExpr)) == NULL)
2158         {
2159         filter->errmsg=CUS "header string expansion failed";
2160         return -1;
2161         }
2162       for (k=key; k->length!=-1; ++k)
2163         {
2164         struct String envelopeStr;
2165
2166         envelopeStr.character=envelope;
2167         envelopeStr.length=Ustrlen(envelope);
2168         *cond=compare(filter,k,&envelopeStr,comparator,matchType);
2169         if (*cond==-1) return -1;
2170         if (*cond) break;
2171         }
2172       }
2173     }
2174   return 1;
2175   }
2176 else return 0;
2177 }
2178
2179
2180 /*************************************************
2181 *     Parse and interpret an optional block      *
2182 *************************************************/
2183
2184 /*
2185 Arguments:
2186   filter      points to the Sieve filter including its state
2187   exec        Execute parsed statements
2188   generated   where to hang newly-generated addresses
2189
2190 Returns:      2                success by stop
2191               1                other success
2192               0                no block command found
2193               -1               syntax or execution error
2194 */
2195
2196 static int parse_block(struct Sieve *filter, int exec,
2197   address_item **generated)
2198 {
2199 int r;
2200
2201 if (parse_white(filter)==-1) return -1;
2202 if (*filter->pc=='{')
2203   {
2204   ++filter->pc;
2205   if ((r=parse_commands(filter,exec,generated))==-1 || r==2) return r;
2206   if (*filter->pc=='}')
2207     {
2208     ++filter->pc;
2209     return 1;
2210     }
2211   else
2212     {
2213     filter->errmsg=CUS "expecting command or closing brace";
2214     return -1;
2215     }
2216   }
2217 else return 0;
2218 }
2219
2220
2221 /*************************************************
2222 *           Match a semicolon                    *
2223 *************************************************/
2224
2225 /*
2226 Arguments:
2227   filter      points to the Sieve filter including its state
2228
2229 Returns:      1                success
2230               -1               syntax error
2231 */
2232
2233 static int parse_semicolon(struct Sieve *filter)
2234 {
2235   if (parse_white(filter)==-1) return -1;
2236   if (*filter->pc==';')
2237   {
2238     ++filter->pc;
2239     return 1;
2240   }
2241   else
2242   {
2243     filter->errmsg=CUS "missing semicolon";
2244     return -1;
2245   }
2246 }
2247
2248
2249 /*************************************************
2250 *     Parse and interpret a Sieve command        *
2251 *************************************************/
2252
2253 /*
2254 Arguments:
2255   filter      points to the Sieve filter including its state
2256   exec        Execute parsed statements
2257   generated   where to hang newly-generated addresses
2258
2259 Returns:      2                success by stop
2260               1                other success
2261               -1               syntax or execution error
2262 */
2263 static int parse_commands(struct Sieve *filter, int exec,
2264   address_item **generated)
2265 {
2266 while (*filter->pc)
2267   {
2268   if (parse_white(filter)==-1) return -1;
2269   if (parse_identifier(filter,CUS "if"))
2270     {
2271     /*
2272     if-command = "if" test block *( "elsif" test block ) [ else block ]
2273     */
2274
2275     int cond,m,unsuccessful;
2276
2277     /* test block */
2278     if (parse_white(filter)==-1) return -1;
2279     if ((m=parse_test(filter,&cond,exec))==-1) return -1;
2280     if (m==0)
2281       {
2282       filter->errmsg=CUS "missing test";
2283       return -1;
2284       }
2285     if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2286         (debug_selector & D_filter) != 0)
2287       {
2288       if (exec) debug_printf("if %s\n",cond?"true":"false");
2289       }
2290     m=parse_block(filter,exec ? cond : 0, generated);
2291     if (m==-1 || m==2) return m;
2292     if (m==0)
2293       {
2294       filter->errmsg=CUS "missing block";
2295       return -1;
2296       }
2297     unsuccessful = !cond;
2298     for (;;) /* elsif test block */
2299       {
2300       if (parse_white(filter)==-1) return -1;
2301       if (parse_identifier(filter,CUS "elsif"))
2302         {
2303         if (parse_white(filter)==-1) return -1;
2304         m=parse_test(filter,&cond,exec && unsuccessful);
2305         if (m==-1 || m==2) return m;
2306         if (m==0)
2307           {
2308           filter->errmsg=CUS "missing test";
2309           return -1;
2310           }
2311         if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2312             (debug_selector & D_filter) != 0)
2313           {
2314           if (exec) debug_printf("elsif %s\n",cond?"true":"false");
2315           }
2316         m=parse_block(filter,exec && unsuccessful ? cond : 0, generated);
2317         if (m==-1 || m==2) return m;
2318         if (m==0)
2319           {
2320           filter->errmsg=CUS "missing block";
2321           return -1;
2322           }
2323         if (exec && unsuccessful && cond) unsuccessful = 0;
2324         }
2325       else break;
2326       }
2327     /* else block */
2328     if (parse_white(filter)==-1) return -1;
2329     if (parse_identifier(filter,CUS "else"))
2330       {
2331       m=parse_block(filter,exec && unsuccessful, generated);
2332       if (m==-1 || m==2) return m;
2333       if (m==0)
2334         {
2335         filter->errmsg=CUS "missing block";
2336         return -1;
2337         }
2338       }
2339     }
2340   else if (parse_identifier(filter,CUS "stop"))
2341     {
2342     /*
2343     stop-command     =  "stop" { stop-options } ";"
2344     stop-options     =
2345     */
2346
2347     if (parse_semicolon(filter)==-1) return -1;
2348     if (exec)
2349       {
2350       filter->pc+=Ustrlen(filter->pc);
2351       return 2;
2352       }
2353     }
2354   else if (parse_identifier(filter,CUS "keep"))
2355     {
2356     /*
2357     keep-command     =  "keep" { keep-options } ";"
2358     keep-options     =
2359     */
2360
2361     if (parse_semicolon(filter)==-1) return -1;
2362     if (exec)
2363       {
2364       add_addr(generated,US"inbox",1,0,0,0);
2365       filter->keep = 0;
2366       }
2367     }
2368   else if (parse_identifier(filter,CUS "discard"))
2369     {
2370     /*
2371     discard-command  =  "discard" { discard-options } ";"
2372     discard-options  =
2373     */
2374
2375     if (parse_semicolon(filter)==-1) return -1;
2376     if (exec) filter->keep=0;
2377     }
2378   else if (parse_identifier(filter,CUS "redirect"))
2379     {
2380     /*
2381     redirect-command =  "redirect" redirect-options "string" ";"
2382     redirect-options =
2383     redirect-options =) ":copy"
2384     */
2385
2386     struct String recipient;
2387     int m;
2388     int copy=0;
2389
2390     for (;;)
2391       {
2392       if (parse_white(filter)==-1) return -1;
2393       if (parse_identifier(filter,CUS ":copy")==1)
2394         {
2395         if (!filter->require_copy)
2396           {
2397           filter->errmsg=CUS "missing previous require \"copy\";";
2398           return -1;
2399           }
2400           copy=1;
2401         }
2402       else break;
2403       }
2404     if (parse_white(filter)==-1) return -1;
2405     if ((m=parse_string(filter,&recipient))!=1)
2406       {
2407       if (m==0) filter->errmsg=CUS "missing redirect recipient string";
2408       return -1;
2409       }
2410     if (strchr(CCS recipient.character,'@')==(char*)0)
2411       {
2412       filter->errmsg=CUS "unqualified recipient address";
2413       return -1;
2414       }
2415     if (exec)
2416       {
2417       add_addr(generated,recipient.character,0,0,0,0);
2418       if (!copy) filter->keep = 0;
2419       }
2420     if (parse_semicolon(filter)==-1) return -1;
2421     }
2422   else if (parse_identifier(filter,CUS "fileinto"))
2423     {
2424     /*
2425     fileinto-command =  "fileinto" { fileinto-options } string ";"
2426     fileinto-options =
2427     fileinto-options =) [ ":copy" ]
2428     */
2429
2430     struct String folder;
2431     uschar *s;
2432     int m;
2433     unsigned long maxage, maxmessages, maxstorage;
2434     int copy=0;
2435
2436     maxage = maxmessages = maxstorage = 0;
2437     if (!filter->require_fileinto)
2438       {
2439       filter->errmsg=CUS "missing previous require \"fileinto\";";
2440       return -1;
2441       }
2442     for (;;)
2443       {
2444       if (parse_white(filter)==-1) return -1;
2445       if (parse_identifier(filter,CUS ":copy")==1)
2446         {
2447         if (!filter->require_copy)
2448           {
2449           filter->errmsg=CUS "missing previous require \"copy\";";
2450           return -1;
2451           }
2452           copy=1;
2453         }
2454       else break;
2455       }
2456     if (parse_white(filter)==-1) return -1;
2457     if ((m=parse_string(filter,&folder))!=1)
2458       {
2459       if (m==0) filter->errmsg=CUS "missing fileinto folder string";
2460       return -1;
2461       }
2462     m=0; s=folder.character;
2463     if (folder.length==0) m=1;
2464     if (Ustrcmp(s,"..")==0 || Ustrncmp(s,"../",3)==0) m=1;
2465     else while (*s)
2466       {
2467       if (Ustrcmp(s,"/..")==0 || Ustrncmp(s,"/../",4)==0) { m=1; break; }
2468       ++s;
2469       }
2470     if (m)
2471       {
2472       filter->errmsg=CUS "invalid folder";
2473       return -1;
2474       }
2475     if (exec)
2476       {
2477       add_addr(generated, folder.character, 1, maxage, maxmessages, maxstorage);
2478       if (!copy) filter->keep = 0;
2479       }
2480     if (parse_semicolon(filter)==-1) return -1;
2481     }
2482 #ifdef NOTIFY
2483   else if (parse_identifier(filter,CUS "notify"))
2484     {
2485     /*
2486     notify-command =  "notify" { notify-options } ";"
2487     notify-options =  [":method" string]
2488                       [":priority" string]
2489                       [":message" string]
2490     */
2491
2492     int m;
2493     struct String method;
2494     struct String priority;
2495     struct String message;
2496     struct Notification *already;
2497     string_item *recipient;
2498     struct String body;
2499     uschar *envelope_from,*envelope_to;
2500
2501     if (!filter->require_notify)
2502       {
2503       filter->errmsg=CUS "missing previous require \"notify\";";
2504       return -1;
2505       }
2506     method.character=(uschar*)0;
2507     method.length=-1;
2508     priority.character=(uschar*)0;
2509     priority.length=-1;
2510     message.character=(uschar*)0;
2511     message.length=-1;
2512     recipient=NULL;
2513     body.length=-1;
2514     body.character=(uschar*)0;
2515     envelope_from=expand_string("$sender_address");
2516     envelope_to=expand_string("$local_part_prefix$local_part$local_part_suffix@$domain");
2517     for (;;)
2518       {
2519       if (parse_white(filter)==-1) return -1;
2520       if (parse_identifier(filter,CUS ":method")==1)
2521         {
2522         if (parse_white(filter)==-1) return -1;
2523         if ((m=parse_string(filter,&method))!=1)
2524           {
2525           if (m==0) filter->errmsg=CUS "method string expected";
2526           return -1;
2527           }
2528         if (method.length>7 && strncmp(method.character,"mailto:",7)==0)
2529           {
2530           if (parse_mailto_uri(filter,method.character+7,&recipient,&body)==-1) return -1;
2531           }
2532         }
2533       else if (parse_identifier(filter,CUS ":priority")==1)
2534         {
2535         if (parse_white(filter)==-1) return -1;
2536         if ((m=parse_string(filter,&priority))!=1)
2537           {
2538           if (m==0) filter->errmsg=CUS "priority string expected";
2539           return -1;
2540           }
2541         }
2542       else if (parse_identifier(filter,CUS ":message")==1)
2543         {
2544         if (parse_white(filter)==-1) return -1;
2545         if ((m=parse_string(filter,&message))!=1)
2546           {
2547           if (m==0) filter->errmsg=CUS "message string expected";
2548           return -1;
2549           }
2550         }
2551       else break;
2552       }
2553     if (parse_semicolon(filter)==-1) return -1;
2554
2555     if (method.length==-1)
2556       {
2557         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2558           {
2559           debug_printf("Ignoring method-less notification.\n");
2560           }
2561       }
2562     else
2563       {
2564       for (already=filter->notified; already; already=already->next)
2565         {
2566         if (already->method.length==method.length
2567             && (method.length==-1 || strcmp(already->method.character,method.character)==0)
2568             && already->priority.length==priority.length
2569             && (priority.length==-1 || strcmp(already->priority.character,priority.character)==0)
2570             && already->message.length==message.length
2571             && (message.length==-1 || strcmp(already->message.character,message.character)==0))
2572           break;
2573         }
2574       if (already==(struct Notification*)0)
2575         /* New notification, process it */
2576         {
2577         struct Notification *sent;
2578         sent=store_get(sizeof(struct Notification));
2579         sent->method=method;
2580         sent->priority=priority;
2581         sent->message=message;
2582         sent->next=filter->notified;
2583         filter->notified=sent;
2584         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2585           {
2586           debug_printf("Notification to `%s'.\n",method.character);
2587           }
2588 #ifndef COMPILE_SYNTAX_CHECKER
2589         if (exec)
2590           {
2591           string_item *p;
2592           header_line *h;
2593           int pid,fd;
2594
2595           if ((pid = child_open_exim2(&fd,envelope_to,envelope_to))>=1)
2596             {
2597             FILE *f;
2598
2599             f = fdopen(fd, "wb");
2600             fprintf(f,"From: %s\n",envelope_to);
2601             for (p=recipient; p; p=p->next) fprintf(f,"To: %s\n",p->text);
2602             for (h = header_list; h != NULL; h = h->next)
2603               if (h->type == htype_received) fprintf(f,"%s",h->text);
2604             fprintf(f,"Subject: %s\n",message.length==-1 ? CUS "notification" : message.character);
2605             fprintf(f,"\n");
2606             if (body.length>0) fprintf(f,"%s\n",body.character);
2607             fflush(f);
2608             (void)fclose(f);
2609             (void)child_close(pid, 0);
2610             }
2611           }
2612 #endif
2613         }
2614       else
2615         {
2616         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2617           {
2618           debug_printf("Repeated notification to `%s' ignored.\n",method.character);
2619           }
2620         }
2621       }
2622     }
2623 #endif
2624 #ifdef VACATION
2625   else if (parse_identifier(filter,CUS "vacation"))
2626     {
2627     /*
2628     vacation-command =  "vacation" { vacation-options } <reason: string> ";"
2629     vacation-options =  [":days" number]
2630                         [":subject" string]
2631                         [":from" string]
2632                         [":addresses" string-list]
2633                         [":mime"]
2634                         [":handle" string]
2635     */
2636
2637     int m;
2638     unsigned long days;
2639     struct String subject;
2640     struct String from;
2641     struct String *addresses;
2642     int reason_is_mime;
2643     string_item *aliases;
2644     struct String handle;
2645     struct String reason;
2646
2647     if (!filter->require_vacation)
2648       {
2649       filter->errmsg=CUS "missing previous require \"vacation\";";
2650       return -1;
2651       }
2652     if (exec)
2653       {
2654       if (filter->vacation_ran)
2655         {
2656         filter->errmsg=CUS "trying to execute vacation more than once";
2657         return -1;
2658         }
2659       filter->vacation_ran=1;
2660       }
2661     days=VACATION_MIN_DAYS>7 ? VACATION_MIN_DAYS : 7;
2662     subject.character=(uschar*)0;
2663     subject.length=-1;
2664     from.character=(uschar*)0;
2665     from.length=-1;
2666     addresses=(struct String*)0;
2667     aliases=NULL;
2668     reason_is_mime=0;
2669     handle.character=(uschar*)0;
2670     handle.length=-1;
2671     for (;;)
2672       {
2673       if (parse_white(filter)==-1) return -1;
2674       if (parse_identifier(filter,CUS ":days")==1)
2675         {
2676         if (parse_white(filter)==-1) return -1;
2677         if (parse_number(filter,&days)==-1) return -1;
2678         if (days<VACATION_MIN_DAYS) days=VACATION_MIN_DAYS;
2679         else if (days>VACATION_MAX_DAYS) days=VACATION_MAX_DAYS;
2680         }
2681       else if (parse_identifier(filter,CUS ":subject")==1)
2682         {
2683         if (parse_white(filter)==-1) return -1;
2684         if ((m=parse_string(filter,&subject))!=1)
2685           {
2686           if (m==0) filter->errmsg=CUS "subject string expected";
2687           return -1;
2688           }
2689         }
2690       else if (parse_identifier(filter,CUS ":from")==1)
2691         {
2692         int start, end, domain;
2693         uschar *error,*ss;
2694
2695         if (parse_white(filter)==-1) return -1;
2696         if ((m=parse_string(filter,&from))!=1)
2697           {
2698           if (m==0) filter->errmsg=CUS "from string expected";
2699           return -1;
2700           }
2701         if (from.length>0)
2702           {
2703           ss = parse_extract_address(from.character, &error, &start, &end, &domain,
2704             FALSE);
2705           if (ss == NULL)
2706             {
2707             filter->errmsg=string_sprintf("malformed address \"%s\" in "
2708               "Sieve filter: %s", from.character, error);
2709             return -1;
2710             }
2711           }
2712         else
2713           {
2714           filter->errmsg=CUS "empty :from address in Sieve filter";
2715           return -1;
2716           }
2717         }
2718       else if (parse_identifier(filter,CUS ":addresses")==1)
2719         {
2720         struct String *a;
2721
2722         if (parse_white(filter)==-1) return -1;
2723         if ((m=parse_stringlist(filter,&addresses))!=1)
2724           {
2725           if (m==0) filter->errmsg=CUS "addresses string list expected";
2726           return -1;
2727           }
2728         for (a=addresses; a->length!=-1; ++a)
2729           {
2730           string_item *new;
2731
2732           new=store_get(sizeof(string_item));
2733           new->text=store_get(a->length+1);
2734           if (a->length) memcpy(new->text,a->character,a->length);
2735           new->text[a->length]='\0';
2736           new->next=aliases;
2737           aliases=new;
2738           }
2739         }
2740       else if (parse_identifier(filter,CUS ":mime")==1)
2741         reason_is_mime=1;
2742       else if (parse_identifier(filter,CUS ":handle")==1)
2743         {
2744         if (parse_white(filter)==-1) return -1;
2745         if ((m=parse_string(filter,&from))!=1)
2746           {
2747           if (m==0) filter->errmsg=CUS "handle string expected";
2748           return -1;
2749           }
2750         }
2751       else break;
2752       }
2753     if (parse_white(filter)==-1) return -1;
2754     if ((m=parse_string(filter,&reason))!=1)
2755       {
2756       if (m==0) filter->errmsg=CUS "missing reason string";
2757       return -1;
2758       }
2759     if (reason_is_mime)
2760       {
2761       uschar *s,*end;
2762
2763       for (s=reason.character,end=reason.character+reason.length; s<end && (*s&0x80)==0; ++s);
2764       if (s<end)
2765         {
2766         filter->errmsg=CUS "MIME reason string contains 8bit text";
2767         return -1;
2768         }
2769       }
2770     if (parse_semicolon(filter)==-1) return -1;
2771
2772     if (exec)
2773       {
2774       address_item *addr;
2775       int capacity,start;
2776       uschar *buffer;
2777       int buffer_capacity;
2778       struct String key;
2779       md5 base;
2780       uschar digest[16];
2781       uschar hexdigest[33];
2782       int i;
2783       uschar *once;
2784
2785       if (filter_personal(aliases,TRUE))
2786         {
2787         if (filter_test == FTEST_NONE)
2788           {
2789           /* ensure oncelog directory exists; failure will be detected later */
2790
2791           (void)directory_make(NULL, filter->vacation_directory, 0700, FALSE);
2792           }
2793         /* build oncelog filename */
2794
2795         key.character=(uschar*)0;
2796         key.length=0;
2797         capacity=0;
2798         if (handle.length==-1)
2799           {
2800           if (subject.length!=-1) key.character=string_cat(key.character,&capacity,&key.length,subject.character,subject.length);
2801           if (from.length!=-1) key.character=string_cat(key.character,&capacity,&key.length,from.character,from.length);
2802           key.character=string_cat(key.character,&capacity,&key.length,reason_is_mime?US"1":US"0",1);
2803           key.character=string_cat(key.character,&capacity,&key.length,reason.character,reason.length);
2804           }
2805         else
2806           key=handle;
2807         md5_start(&base);
2808         md5_end(&base, key.character, key.length, digest);
2809         for (i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]);
2810         if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2811           {
2812           debug_printf("Sieve: mail was personal, vacation file basename: %s\n", hexdigest);
2813           }
2814         if (filter_test == FTEST_NONE)
2815           {
2816           capacity=Ustrlen(filter->vacation_directory);
2817           start=capacity;
2818           once=string_cat(filter->vacation_directory,&capacity,&start,US"/",1);
2819           once=string_cat(once,&capacity,&start,hexdigest,33);
2820           once[start] = '\0';
2821
2822           /* process subject */
2823
2824           if (subject.length==-1)
2825             {
2826             uschar *subject_def;
2827
2828             subject_def=expand_string(US"${if def:header_subject {true}{false}}");
2829             if (Ustrcmp(subject_def,"true")==0)
2830               {
2831               expand_header(&subject,&str_subject);
2832               capacity=6;
2833               start=6;
2834               subject.character=string_cat(US"Auto: ",&capacity,&start,subject.character,subject.length);
2835               subject.length=start;
2836               }
2837             else
2838               {
2839               subject.character=US"Automated reply";
2840               subject.length=Ustrlen(subject.character);
2841               }
2842             }
2843
2844           /* add address to list of generated addresses */
2845
2846           addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
2847           setflag(addr, af_pfr);
2848           setflag(addr, af_ignore_error);
2849           addr->next = *generated;
2850           *generated = addr;
2851           addr->reply = store_get(sizeof(reply_item));
2852           memset(addr->reply,0,sizeof(reply_item)); /* XXX */
2853           addr->reply->to = string_copy(sender_address);
2854           if (from.length==-1)
2855             addr->reply->from = expand_string(US"$local_part@$domain");
2856           else
2857             addr->reply->from = from.character;
2858           /* Allocation is larger than neccessary, but enough even for split MIME words */
2859           buffer_capacity=32+4*subject.length;
2860           buffer=store_get(buffer_capacity);
2861           addr->reply->subject=parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE);
2862           addr->reply->oncelog=once;
2863           addr->reply->once_repeat=days*86400;
2864
2865           /* build body and MIME headers */
2866
2867           if (reason_is_mime)
2868             {
2869             uschar *mime_body,*reason_end;
2870             static const uschar nlnl[]="\r\n\r\n";
2871
2872             for
2873               (
2874               mime_body=reason.character,reason_end=reason.character+reason.length;
2875               mime_body<(reason_end-(sizeof(nlnl)-1)) && memcmp(mime_body,nlnl,(sizeof(nlnl)-1));
2876               ++mime_body
2877               );
2878             capacity = 0;
2879             start = 0;
2880             addr->reply->headers = string_cat(NULL,&capacity,&start,reason.character,mime_body-reason.character);
2881             addr->reply->headers[start] = '\0';
2882             capacity = 0;
2883             start = 0;
2884             if (mime_body+(sizeof(nlnl)-1)<reason_end) mime_body+=(sizeof(nlnl)-1);
2885             else mime_body=reason_end-1;
2886             addr->reply->text = string_cat(NULL,&capacity,&start,mime_body,reason_end-mime_body);
2887             addr->reply->text[start] = '\0';
2888             }
2889           else
2890             {
2891             struct String qp = { NULL, 0 };  /* Keep compiler happy (PH) */
2892
2893             capacity = 0;
2894             start = reason.length;
2895             addr->reply->headers = US"MIME-Version: 1.0\n"
2896                                    "Content-Type: text/plain;\n"
2897                                    "\tcharset=\"utf-8\"\n"
2898                                    "Content-Transfer-Encoding: quoted-printable";
2899             addr->reply->text = quoted_printable_encode(&reason,&qp)->character;
2900             }
2901           }
2902         }
2903         else if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2904           {
2905           debug_printf("Sieve: mail was not personal, vacation would ignore it\n");
2906           }
2907       }
2908     }
2909     else break;
2910 #endif
2911   }
2912 return 1;
2913 }
2914
2915
2916 /*************************************************
2917 *       Parse and interpret a sieve filter       *
2918 *************************************************/
2919
2920 /*
2921 Arguments:
2922   filter      points to the Sieve filter including its state
2923   exec        Execute parsed statements
2924   generated   where to hang newly-generated addresses
2925
2926 Returns:      1                success
2927               -1               syntax or execution error
2928 */
2929
2930 static int parse_start(struct Sieve *filter, int exec,
2931   address_item **generated)
2932 {
2933 filter->pc=filter->filter;
2934 filter->line=1;
2935 filter->keep=1;
2936 filter->require_envelope=0;
2937 filter->require_fileinto=0;
2938 #ifdef ENVELOPE_AUTH
2939 filter->require_envelope_auth=0;
2940 #endif
2941 #ifdef NOTIFY
2942 filter->require_notify=0;
2943 filter->notified=(struct Notification*)0;
2944 #endif
2945 #ifdef SUBADDRESS
2946 filter->require_subaddress=0;
2947 #endif
2948 #ifdef VACATION
2949 filter->require_vacation=0;
2950 filter->vacation_ran=0;
2951 #endif
2952 filter->require_copy=0;
2953 filter->require_iascii_numeric=0;
2954
2955 if (parse_white(filter)==-1) return -1;
2956
2957 if (exec && filter->vacation_directory != NULL && filter_test == FTEST_NONE)
2958   {
2959   DIR *oncelogdir;
2960   struct dirent *oncelog;
2961   struct stat properties;
2962   time_t now;
2963
2964   /* clean up old vacation log databases */
2965
2966   oncelogdir=opendir(CS filter->vacation_directory);
2967
2968   if (oncelogdir ==(DIR*)0 && errno != ENOENT)
2969     {
2970     filter->errmsg=CUS "unable to open vacation directory";
2971     return -1;
2972     }
2973
2974   if (oncelogdir != NULL)
2975     {
2976     time(&now);
2977
2978     while ((oncelog=readdir(oncelogdir))!=(struct dirent*)0)
2979       {
2980       if (strlen(oncelog->d_name)==32)
2981         {
2982         uschar *s=string_sprintf("%s/%s",filter->vacation_directory,oncelog->d_name);
2983         if (Ustat(s,&properties)==0 && (properties.st_mtime+VACATION_MAX_DAYS*86400)<now)
2984           Uunlink(s);
2985         }
2986       }
2987     closedir(oncelogdir);
2988     }
2989   }
2990
2991 while (parse_identifier(filter,CUS "require"))
2992   {
2993   /*
2994   require-command = "require" <capabilities: string-list>
2995   */
2996
2997   struct String *cap,*check;
2998   int m;
2999
3000   if (parse_white(filter)==-1) return -1;
3001   if ((m=parse_stringlist(filter,&cap))!=1)
3002     {
3003     if (m==0) filter->errmsg=CUS "capability string list expected";
3004     return -1;
3005     }
3006   for (check=cap; check->character; ++check)
3007     {
3008     if (eq_octet(check,&str_envelope,0)) filter->require_envelope=1;
3009     else if (eq_octet(check,&str_fileinto,0)) filter->require_fileinto=1;
3010 #ifdef ENVELOPE_AUTH
3011     else if (eq_octet(check,&str_envelope_auth,0)) filter->require_envelope_auth=1;
3012 #endif
3013 #ifdef NOTIFY
3014     else if (eq_octet(check,&str_notify,0)) filter->require_notify=1;
3015 #endif
3016 #ifdef SUBADDRESS
3017     else if (eq_octet(check,&str_subaddress,0)) filter->require_subaddress=1;
3018 #endif
3019 #ifdef VACATION
3020     else if (eq_octet(check,&str_vacation,0))
3021       {
3022       if (filter_test == FTEST_NONE && filter->vacation_directory == NULL)
3023         {
3024         filter->errmsg=CUS "vacation disabled";
3025         return -1;
3026         }
3027       filter->require_vacation=1;
3028       }
3029 #endif
3030     else if (eq_octet(check,&str_copy,0)) filter->require_copy=1;
3031     else if (eq_octet(check,&str_comparator_ioctet,0)) ;
3032     else if (eq_octet(check,&str_comparator_iascii_casemap,0)) ;
3033     else if (eq_octet(check,&str_comparator_enascii_casemap,0)) ;
3034     else if (eq_octet(check,&str_comparator_iascii_numeric,0)) filter->require_iascii_numeric=1;
3035     else
3036       {
3037       filter->errmsg=CUS "unknown capability";
3038       return -1;
3039       }
3040     }
3041     if (parse_semicolon(filter)==-1) return -1;
3042   }
3043   if (parse_commands(filter,exec,generated)==-1) return -1;
3044   if (*filter->pc)
3045     {
3046     filter->errmsg=CUS "syntax error";
3047     return -1;
3048     }
3049   return 1;
3050 }
3051
3052
3053 /*************************************************
3054 *            Interpret a sieve filter file       *
3055 *************************************************/
3056
3057 /*
3058 Arguments:
3059   filter      points to the entire file, read into store as a single string
3060   options     controls whether various special things are allowed, and requests
3061               special actions (not currently used)
3062   sieve_vacation_directory  where to store vacation "once" files
3063   useraddress string expression for :user part of address
3064   subaddress  string expression for :subaddress part of address
3065   generated   where to hang newly-generated addresses
3066   error       where to pass back an error text
3067
3068 Returns:      FF_DELIVERED     success, a significant action was taken
3069               FF_NOTDELIVERED  success, no significant action
3070               FF_DEFER         defer requested
3071               FF_FAIL          fail requested
3072               FF_FREEZE        freeze requested
3073               FF_ERROR         there was a problem
3074 */
3075
3076 int
3077 sieve_interpret(uschar *filter, int options, uschar *vacation_directory,
3078   uschar *useraddress, uschar *subaddress, address_item **generated, uschar **error)
3079 {
3080 struct Sieve sieve;
3081 int r;
3082 uschar *msg;
3083
3084 options = options; /* Keep picky compilers happy */
3085 error = error;
3086
3087 DEBUG(D_route) debug_printf("Sieve: start of processing\n");
3088 sieve.filter=filter;
3089
3090 if (vacation_directory == NULL)
3091   sieve.vacation_directory = NULL;
3092 else
3093   {
3094   sieve.vacation_directory=expand_string(vacation_directory);
3095   if (sieve.vacation_directory == NULL)
3096     {
3097     *error = string_sprintf("failed to expand \"%s\" "
3098       "(sieve_vacation_directory): %s", vacation_directory,
3099       expand_string_message);
3100     return FF_ERROR;
3101     }
3102   }
3103
3104 sieve.useraddress = useraddress == NULL ? CUS "$local_part_prefix$local_part$local_part_suffix" : useraddress;
3105 sieve.subaddress = subaddress;
3106
3107 #ifdef COMPILE_SYNTAX_CHECKER
3108 if (parse_start(&sieve,0,generated)==1)
3109 #else
3110 if (parse_start(&sieve,1,generated)==1)
3111 #endif
3112   {
3113   if (sieve.keep)
3114     {
3115     add_addr(generated,US"inbox",1,0,0,0);
3116     msg = string_sprintf("Implicit keep");
3117     r = FF_DELIVERED;
3118     }
3119   else
3120     {
3121     msg = string_sprintf("No implicit keep");
3122     r = FF_DELIVERED;
3123     }
3124   }
3125 else
3126   {
3127   msg = string_sprintf("Sieve error: %s in line %d",sieve.errmsg,sieve.line);
3128 #ifdef COMPILE_SYNTAX_CHECKER
3129   r = FF_ERROR;
3130   *error = msg;
3131 #else
3132   add_addr(generated,US"inbox",1,0,0,0);
3133   r = FF_DELIVERED;
3134 #endif
3135   }
3136
3137 #ifndef COMPILE_SYNTAX_CHECKER
3138 if (filter_test != FTEST_NONE) printf("%s\n", (const char*) msg);
3139   else debug_printf("%s\n", msg);
3140 #endif
3141
3142 DEBUG(D_route) debug_printf("Sieve: end of processing\n");
3143 return r;
3144 }