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