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