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