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