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