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