Sort out group syntax problems, particularly with verify=header_sender.
[exim.git] / src / src / sieve.c
1 /* $Cambridge: exim/src/src/sieve.c,v 1.23 2006/10/10 15:36:50 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 parse_allow_group = FALSE;
1830 parse_found_group = FALSE;
1831 }
1832 }
1833 return 1;
1834 }
1835 else if (parse_identifier(filter,CUS "allof"))
1836 {
1837 /*
1838 allof-test = "allof" <tests: test-list>
1839 */
1840
1841 int n,true;
1842
1843 switch (parse_testlist(filter,&n,&true,exec))
1844 {
1845 case -1: return -1;
1846 case 0: filter->errmsg=CUS "missing test list"; return -1;
1847 default: *cond=(n==true); return 1;
1848 }
1849 }
1850 else if (parse_identifier(filter,CUS "anyof"))
1851 {
1852 /*
1853 anyof-test = "anyof" <tests: test-list>
1854 */
1855
1856 int n,true;
1857
1858 switch (parse_testlist(filter,&n,&true,exec))
1859 {
1860 case -1: return -1;
1861 case 0: filter->errmsg=CUS "missing test list"; return -1;
1862 default: *cond=(true>0); return 1;
1863 }
1864 }
1865 else if (parse_identifier(filter,CUS "exists"))
1866 {
1867 /*
1868 exists-test = "exists" <header-names: string-list>
1869 */
1870
1871 struct String *hdr,*h;
1872 int m;
1873
1874 if (parse_white(filter)==-1) return -1;
1875 if ((m=parse_stringlist(filter,&hdr))!=1)
1876 {
1877 if (m==0) filter->errmsg=CUS "header string list expected";
1878 return -1;
1879 }
1880 if (exec)
1881 {
1882 *cond=1;
1883 for (h=hdr; h->length!=-1 && *cond; ++h)
1884 {
1885 uschar *header_def;
1886
1887 header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
1888 if (header_def == NULL)
1889 {
1890 filter->errmsg=CUS "header string expansion failed";
1891 return -1;
1892 }
1893 if (Ustrcmp(header_def,"false")==0) *cond=0;
1894 }
1895 }
1896 return 1;
1897 }
1898 else if (parse_identifier(filter,CUS "false"))
1899 {
1900 /*
1901 false-test = "false"
1902 */
1903
1904 *cond=0;
1905 return 1;
1906 }
1907 else if (parse_identifier(filter,CUS "header"))
1908 {
1909 /*
1910 header-test = "header" { [comparator] [match-type] }
1911 <header-names: string-list> <key-list: string-list>
1912 */
1913
1914 enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
1915 enum MatchType matchType=MATCH_IS;
1916 struct String *hdr,*h,*key,*k;
1917 int m;
1918 int co=0,mt=0;
1919
1920 for (;;)
1921 {
1922 if (parse_white(filter)==-1) return -1;
1923 if ((m=parse_comparator(filter,&comparator))!=0)
1924 {
1925 if (m==-1) return -1;
1926 if (co)
1927 {
1928 filter->errmsg=CUS "comparator already specified";
1929 return -1;
1930 }
1931 else co=1;
1932 }
1933 else if ((m=parse_matchtype(filter,&matchType))!=0)
1934 {
1935 if (m==-1) return -1;
1936 if (mt)
1937 {
1938 filter->errmsg=CUS "match type already specified";
1939 return -1;
1940 }
1941 else mt=1;
1942 }
1943 else break;
1944 }
1945 if (parse_white(filter)==-1) return -1;
1946 if ((m=parse_stringlist(filter,&hdr))!=1)
1947 {
1948 if (m==0) filter->errmsg=CUS "header string list expected";
1949 return -1;
1950 }
1951 if (parse_white(filter)==-1) return -1;
1952 if ((m=parse_stringlist(filter,&key))!=1)
1953 {
1954 if (m==0) filter->errmsg=CUS "key string list expected";
1955 return -1;
1956 }
1957 *cond=0;
1958 for (h=hdr; h->length!=-1 && !*cond; ++h)
1959 {
1960 if (!is_header(h))
1961 {
1962 filter->errmsg=CUS "invalid header field";
1963 return -1;
1964 }
1965 if (exec)
1966 {
1967 struct String header_value;
1968 uschar *header_def;
1969
1970 expand_header(&header_value,h);
1971 header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
1972 if (header_value.character == NULL || header_def == NULL)
1973 {
1974 filter->errmsg=CUS "header string expansion failed";
1975 return -1;
1976 }
1977 for (k=key; k->length!=-1; ++k)
1978 {
1979 if (Ustrcmp(header_def,"true")==0)
1980 {
1981 *cond=compare(filter,k,&header_value,comparator,matchType);
1982 if (*cond==-1) return -1;
1983 if (*cond) break;
1984 }
1985 }
1986 }
1987 }
1988 return 1;
1989 }
1990 else if (parse_identifier(filter,CUS "not"))
1991 {
1992 if (parse_white(filter)==-1) return -1;
1993 switch (parse_test(filter,cond,exec))
1994 {
1995 case -1: return -1;
1996 case 0: filter->errmsg=CUS "missing test"; return -1;
1997 default: *cond=!*cond; return 1;
1998 }
1999 }
2000 else if (parse_identifier(filter,CUS "size"))
2001 {
2002 /*
2003 relop = ":over" / ":under"
2004 size-test = "size" relop <limit: number>
2005 */
2006
2007 unsigned long limit;
2008 int overNotUnder;
2009
2010 if (parse_white(filter)==-1) return -1;
2011 if (parse_identifier(filter,CUS ":over")) overNotUnder=1;
2012 else if (parse_identifier(filter,CUS ":under")) overNotUnder=0;
2013 else
2014 {
2015 filter->errmsg=CUS "missing :over or :under";
2016 return -1;
2017 }
2018 if (parse_white(filter)==-1) return -1;
2019 if (parse_number(filter,&limit)==-1) return -1;
2020 *cond=(overNotUnder ? (message_size>limit) : (message_size<limit));
2021 return 1;
2022 }
2023 else if (parse_identifier(filter,CUS "true"))
2024 {
2025 *cond=1;
2026 return 1;
2027 }
2028 else if (parse_identifier(filter,CUS "envelope"))
2029 {
2030 /*
2031 envelope-test = "envelope" { [comparator] [address-part] [match-type] }
2032 <envelope-part: string-list> <key-list: string-list>
2033
2034 envelope-part is case insensitive "from" or "to"
2035 #ifdef ENVELOPE_AUTH
2036 envelope-part =/ "auth"
2037 #endif
2038 */
2039
2040 enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2041 enum AddressPart addressPart=ADDRPART_ALL;
2042 enum MatchType matchType=MATCH_IS;
2043 struct String *env,*e,*key,*k;
2044 int m;
2045 int co=0,ap=0,mt=0;
2046
2047 if (!filter->require_envelope)
2048 {
2049 filter->errmsg=CUS "missing previous require \"envelope\";";
2050 return -1;
2051 }
2052 for (;;)
2053 {
2054 if (parse_white(filter)==-1) return -1;
2055 if ((m=parse_comparator(filter,&comparator))!=0)
2056 {
2057 if (m==-1) return -1;
2058 if (co)
2059 {
2060 filter->errmsg=CUS "comparator already specified";
2061 return -1;
2062 }
2063 else co=1;
2064 }
2065 else if ((m=parse_addresspart(filter,&addressPart))!=0)
2066 {
2067 if (m==-1) return -1;
2068 if (ap)
2069 {
2070 filter->errmsg=CUS "address part already specified";
2071 return -1;
2072 }
2073 else ap=1;
2074 }
2075 else if ((m=parse_matchtype(filter,&matchType))!=0)
2076 {
2077 if (m==-1) return -1;
2078 if (mt)
2079 {
2080 filter->errmsg=CUS "match type already specified";
2081 return -1;
2082 }
2083 else mt=1;
2084 }
2085 else break;
2086 }
2087 if (parse_white(filter)==-1) return -1;
2088 if ((m=parse_stringlist(filter,&env))!=1)
2089 {
2090 if (m==0) filter->errmsg=CUS "envelope string list expected";
2091 return -1;
2092 }
2093 if (parse_white(filter)==-1) return -1;
2094 if ((m=parse_stringlist(filter,&key))!=1)
2095 {
2096 if (m==0) filter->errmsg=CUS "key string list expected";
2097 return -1;
2098 }
2099 *cond=0;
2100 for (e=env; e->length!=-1 && !*cond; ++e)
2101 {
2102 const uschar *envelopeExpr=CUS 0;
2103 uschar *envelope=US 0;
2104
2105 if (eq_asciicase(e,&str_from,0))
2106 {
2107 switch (addressPart)
2108 {
2109 case ADDRPART_ALL: envelopeExpr=CUS "$sender_address"; break;
2110 #ifdef SUBADDRESS
2111 case ADDRPART_USER:
2112 #endif
2113 case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$sender_address}"; break;
2114 case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$sender_address}"; break;
2115 #ifdef SUBADDRESS
2116 case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2117 #endif
2118 }
2119 }
2120 else if (eq_asciicase(e,&str_to,0))
2121 {
2122 switch (addressPart)
2123 {
2124 case ADDRPART_ALL: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix@$domain"; break;
2125 #ifdef SUBADDRESS
2126 case ADDRPART_USER: envelopeExpr=filter->useraddress; break;
2127 case ADDRPART_DETAIL: envelopeExpr=filter->subaddress; break;
2128 #endif
2129 case ADDRPART_LOCALPART: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix"; break;
2130 case ADDRPART_DOMAIN: envelopeExpr=CUS "$domain"; break;
2131 }
2132 }
2133 #ifdef ENVELOPE_AUTH
2134 else if (eq_asciicase(e,&str_auth,0))
2135 {
2136 switch (addressPart)
2137 {
2138 case ADDRPART_ALL: envelopeExpr=CUS "$authenticated_sender"; break;
2139 #ifdef SUBADDRESS
2140 case ADDRPART_USER:
2141 #endif
2142 case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$authenticated_sender}"; break;
2143 case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$authenticated_sender}"; break;
2144 #ifdef SUBADDRESS
2145 case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2146 #endif
2147 }
2148 }
2149 #endif
2150 else
2151 {
2152 filter->errmsg=CUS "invalid envelope string";
2153 return -1;
2154 }
2155 if (exec && envelopeExpr)
2156 {
2157 if ((envelope=expand_string(US envelopeExpr)) == NULL)
2158 {
2159 filter->errmsg=CUS "header string expansion failed";
2160 return -1;
2161 }
2162 for (k=key; k->length!=-1; ++k)
2163 {
2164 struct String envelopeStr;
2165
2166 envelopeStr.character=envelope;
2167 envelopeStr.length=Ustrlen(envelope);
2168 *cond=compare(filter,k,&envelopeStr,comparator,matchType);
2169 if (*cond==-1) return -1;
2170 if (*cond) break;
2171 }
2172 }
2173 }
2174 return 1;
2175 }
2176 else return 0;
2177 }
2178
2179
2180 /*************************************************
2181 * Parse and interpret an optional block *
2182 *************************************************/
2183
2184 /*
2185 Arguments:
2186 filter points to the Sieve filter including its state
2187 exec Execute parsed statements
2188 generated where to hang newly-generated addresses
2189
2190 Returns: 2 success by stop
2191 1 other success
2192 0 no block command found
2193 -1 syntax or execution error
2194 */
2195
2196 static int parse_block(struct Sieve *filter, int exec,
2197 address_item **generated)
2198 {
2199 int r;
2200
2201 if (parse_white(filter)==-1) return -1;
2202 if (*filter->pc=='{')
2203 {
2204 ++filter->pc;
2205 if ((r=parse_commands(filter,exec,generated))==-1 || r==2) return r;
2206 if (*filter->pc=='}')
2207 {
2208 ++filter->pc;
2209 return 1;
2210 }
2211 else
2212 {
2213 filter->errmsg=CUS "expecting command or closing brace";
2214 return -1;
2215 }
2216 }
2217 else return 0;
2218 }
2219
2220
2221 /*************************************************
2222 * Match a semicolon *
2223 *************************************************/
2224
2225 /*
2226 Arguments:
2227 filter points to the Sieve filter including its state
2228
2229 Returns: 1 success
2230 -1 syntax error
2231 */
2232
2233 static int parse_semicolon(struct Sieve *filter)
2234 {
2235 if (parse_white(filter)==-1) return -1;
2236 if (*filter->pc==';')
2237 {
2238 ++filter->pc;
2239 return 1;
2240 }
2241 else
2242 {
2243 filter->errmsg=CUS "missing semicolon";
2244 return -1;
2245 }
2246 }
2247
2248
2249 /*************************************************
2250 * Parse and interpret a Sieve command *
2251 *************************************************/
2252
2253 /*
2254 Arguments:
2255 filter points to the Sieve filter including its state
2256 exec Execute parsed statements
2257 generated where to hang newly-generated addresses
2258
2259 Returns: 2 success by stop
2260 1 other success
2261 -1 syntax or execution error
2262 */
2263 static int parse_commands(struct Sieve *filter, int exec,
2264 address_item **generated)
2265 {
2266 while (*filter->pc)
2267 {
2268 if (parse_white(filter)==-1) return -1;
2269 if (parse_identifier(filter,CUS "if"))
2270 {
2271 /*
2272 if-command = "if" test block *( "elsif" test block ) [ else block ]
2273 */
2274
2275 int cond,m,unsuccessful;
2276
2277 /* test block */
2278 if (parse_white(filter)==-1) return -1;
2279 if ((m=parse_test(filter,&cond,exec))==-1) return -1;
2280 if (m==0)
2281 {
2282 filter->errmsg=CUS "missing test";
2283 return -1;
2284 }
2285 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2286 (debug_selector & D_filter) != 0)
2287 {
2288 if (exec) debug_printf("if %s\n",cond?"true":"false");
2289 }
2290 m=parse_block(filter,exec ? cond : 0, generated);
2291 if (m==-1 || m==2) return m;
2292 if (m==0)
2293 {
2294 filter->errmsg=CUS "missing block";
2295 return -1;
2296 }
2297 unsuccessful = !cond;
2298 for (;;) /* elsif test block */
2299 {
2300 if (parse_white(filter)==-1) return -1;
2301 if (parse_identifier(filter,CUS "elsif"))
2302 {
2303 if (parse_white(filter)==-1) return -1;
2304 m=parse_test(filter,&cond,exec && unsuccessful);
2305 if (m==-1 || m==2) return m;
2306 if (m==0)
2307 {
2308 filter->errmsg=CUS "missing test";
2309 return -1;
2310 }
2311 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2312 (debug_selector & D_filter) != 0)
2313 {
2314 if (exec) debug_printf("elsif %s\n",cond?"true":"false");
2315 }
2316 m=parse_block(filter,exec && unsuccessful ? cond : 0, generated);
2317 if (m==-1 || m==2) return m;
2318 if (m==0)
2319 {
2320 filter->errmsg=CUS "missing block";
2321 return -1;
2322 }
2323 if (exec && unsuccessful && cond) unsuccessful = 0;
2324 }
2325 else break;
2326 }
2327 /* else block */
2328 if (parse_white(filter)==-1) return -1;
2329 if (parse_identifier(filter,CUS "else"))
2330 {
2331 m=parse_block(filter,exec && unsuccessful, generated);
2332 if (m==-1 || m==2) return m;
2333 if (m==0)
2334 {
2335 filter->errmsg=CUS "missing block";
2336 return -1;
2337 }
2338 }
2339 }
2340 else if (parse_identifier(filter,CUS "stop"))
2341 {
2342 /*
2343 stop-command = "stop" { stop-options } ";"
2344 stop-options =
2345 */
2346
2347 if (parse_semicolon(filter)==-1) return -1;
2348 if (exec)
2349 {
2350 filter->pc+=Ustrlen(filter->pc);
2351 return 2;
2352 }
2353 }
2354 else if (parse_identifier(filter,CUS "keep"))
2355 {
2356 /*
2357 keep-command = "keep" { keep-options } ";"
2358 keep-options =
2359 */
2360
2361 if (parse_semicolon(filter)==-1) return -1;
2362 if (exec)
2363 {
2364 add_addr(generated,US"inbox",1,0,0,0);
2365 filter->keep = 0;
2366 }
2367 }
2368 else if (parse_identifier(filter,CUS "discard"))
2369 {
2370 /*
2371 discard-command = "discard" { discard-options } ";"
2372 discard-options =
2373 */
2374
2375 if (parse_semicolon(filter)==-1) return -1;
2376 if (exec) filter->keep=0;
2377 }
2378 else if (parse_identifier(filter,CUS "redirect"))
2379 {
2380 /*
2381 redirect-command = "redirect" redirect-options "string" ";"
2382 redirect-options =
2383 redirect-options =) ":copy"
2384 */
2385
2386 struct String recipient;
2387 int m;
2388 int copy=0;
2389
2390 for (;;)
2391 {
2392 if (parse_white(filter)==-1) return -1;
2393 if (parse_identifier(filter,CUS ":copy")==1)
2394 {
2395 if (!filter->require_copy)
2396 {
2397 filter->errmsg=CUS "missing previous require \"copy\";";
2398 return -1;
2399 }
2400 copy=1;
2401 }
2402 else break;
2403 }
2404 if (parse_white(filter)==-1) return -1;
2405 if ((m=parse_string(filter,&recipient))!=1)
2406 {
2407 if (m==0) filter->errmsg=CUS "missing redirect recipient string";
2408 return -1;
2409 }
2410 if (strchr(CCS recipient.character,'@')==(char*)0)
2411 {
2412 filter->errmsg=CUS "unqualified recipient address";
2413 return -1;
2414 }
2415 if (exec)
2416 {
2417 add_addr(generated,recipient.character,0,0,0,0);
2418 if (!copy) filter->keep = 0;
2419 }
2420 if (parse_semicolon(filter)==-1) return -1;
2421 }
2422 else if (parse_identifier(filter,CUS "fileinto"))
2423 {
2424 /*
2425 fileinto-command = "fileinto" { fileinto-options } string ";"
2426 fileinto-options =
2427 fileinto-options =) [ ":copy" ]
2428 */
2429
2430 struct String folder;
2431 uschar *s;
2432 int m;
2433 unsigned long maxage, maxmessages, maxstorage;
2434 int copy=0;
2435
2436 maxage = maxmessages = maxstorage = 0;
2437 if (!filter->require_fileinto)
2438 {
2439 filter->errmsg=CUS "missing previous require \"fileinto\";";
2440 return -1;
2441 }
2442 for (;;)
2443 {
2444 if (parse_white(filter)==-1) return -1;
2445 if (parse_identifier(filter,CUS ":copy")==1)
2446 {
2447 if (!filter->require_copy)
2448 {
2449 filter->errmsg=CUS "missing previous require \"copy\";";
2450 return -1;
2451 }
2452 copy=1;
2453 }
2454 else break;
2455 }
2456 if (parse_white(filter)==-1) return -1;
2457 if ((m=parse_string(filter,&folder))!=1)
2458 {
2459 if (m==0) filter->errmsg=CUS "missing fileinto folder string";
2460 return -1;
2461 }
2462 m=0; s=folder.character;
2463 if (folder.length==0) m=1;
2464 if (Ustrcmp(s,"..")==0 || Ustrncmp(s,"../",3)==0) m=1;
2465 else while (*s)
2466 {
2467 if (Ustrcmp(s,"/..")==0 || Ustrncmp(s,"/../",4)==0) { m=1; break; }
2468 ++s;
2469 }
2470 if (m)
2471 {
2472 filter->errmsg=CUS "invalid folder";
2473 return -1;
2474 }
2475 if (exec)
2476 {
2477 add_addr(generated, folder.character, 1, maxage, maxmessages, maxstorage);
2478 if (!copy) filter->keep = 0;
2479 }
2480 if (parse_semicolon(filter)==-1) return -1;
2481 }
2482 #ifdef NOTIFY
2483 else if (parse_identifier(filter,CUS "notify"))
2484 {
2485 /*
2486 notify-command = "notify" { notify-options } ";"
2487 notify-options = [":method" string]
2488 [":priority" string]
2489 [":message" string]
2490 */
2491
2492 int m;
2493 struct String method;
2494 struct String priority;
2495 struct String message;
2496 struct Notification *already;
2497 string_item *recipient;
2498 struct String body;
2499 uschar *envelope_from,*envelope_to;
2500
2501 if (!filter->require_notify)
2502 {
2503 filter->errmsg=CUS "missing previous require \"notify\";";
2504 return -1;
2505 }
2506 method.character=(uschar*)0;
2507 method.length=-1;
2508 priority.character=(uschar*)0;
2509 priority.length=-1;
2510 message.character=(uschar*)0;
2511 message.length=-1;
2512 recipient=NULL;
2513 body.length=-1;
2514 body.character=(uschar*)0;
2515 envelope_from=expand_string("$sender_address");
2516 envelope_to=expand_string("$local_part_prefix$local_part$local_part_suffix@$domain");
2517 for (;;)
2518 {
2519 if (parse_white(filter)==-1) return -1;
2520 if (parse_identifier(filter,CUS ":method")==1)
2521 {
2522 if (parse_white(filter)==-1) return -1;
2523 if ((m=parse_string(filter,&method))!=1)
2524 {
2525 if (m==0) filter->errmsg=CUS "method string expected";
2526 return -1;
2527 }
2528 if (method.length>7 && strncmp(method.character,"mailto:",7)==0)
2529 {
2530 if (parse_mailto_uri(filter,method.character+7,&recipient,&body)==-1) return -1;
2531 }
2532 }
2533 else if (parse_identifier(filter,CUS ":priority")==1)
2534 {
2535 if (parse_white(filter)==-1) return -1;
2536 if ((m=parse_string(filter,&priority))!=1)
2537 {
2538 if (m==0) filter->errmsg=CUS "priority string expected";
2539 return -1;
2540 }
2541 }
2542 else if (parse_identifier(filter,CUS ":message")==1)
2543 {
2544 if (parse_white(filter)==-1) return -1;
2545 if ((m=parse_string(filter,&message))!=1)
2546 {
2547 if (m==0) filter->errmsg=CUS "message string expected";
2548 return -1;
2549 }
2550 }
2551 else break;
2552 }
2553 if (parse_semicolon(filter)==-1) return -1;
2554
2555 if (method.length==-1)
2556 {
2557 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2558 {
2559 debug_printf("Ignoring method-less notification.\n");
2560 }
2561 }
2562 else
2563 {
2564 for (already=filter->notified; already; already=already->next)
2565 {
2566 if (already->method.length==method.length
2567 && (method.length==-1 || strcmp(already->method.character,method.character)==0)
2568 && already->priority.length==priority.length
2569 && (priority.length==-1 || strcmp(already->priority.character,priority.character)==0)
2570 && already->message.length==message.length
2571 && (message.length==-1 || strcmp(already->message.character,message.character)==0))
2572 break;
2573 }
2574 if (already==(struct Notification*)0)
2575 /* New notification, process it */
2576 {
2577 struct Notification *sent;
2578 sent=store_get(sizeof(struct Notification));
2579 sent->method=method;
2580 sent->priority=priority;
2581 sent->message=message;
2582 sent->next=filter->notified;
2583 filter->notified=sent;
2584 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2585 {
2586 debug_printf("Notification to `%s'.\n",method.character);
2587 }
2588 #ifndef COMPILE_SYNTAX_CHECKER
2589 if (exec)
2590 {
2591 string_item *p;
2592 header_line *h;
2593 int pid,fd;
2594
2595 if ((pid = child_open_exim2(&fd,envelope_to,envelope_to))>=1)
2596 {
2597 FILE *f;
2598
2599 f = fdopen(fd, "wb");
2600 fprintf(f,"From: %s\n",envelope_to);
2601 for (p=recipient; p; p=p->next) fprintf(f,"To: %s\n",p->text);
2602 for (h = header_list; h != NULL; h = h->next)
2603 if (h->type == htype_received) fprintf(f,"%s",h->text);
2604 fprintf(f,"Subject: %s\n",message.length==-1 ? CUS "notification" : message.character);
2605 fprintf(f,"\n");
2606 if (body.length>0) fprintf(f,"%s\n",body.character);
2607 fflush(f);
2608 (void)fclose(f);
2609 (void)child_close(pid, 0);
2610 }
2611 }
2612 #endif
2613 }
2614 else
2615 {
2616 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2617 {
2618 debug_printf("Repeated notification to `%s' ignored.\n",method.character);
2619 }
2620 }
2621 }
2622 }
2623 #endif
2624 #ifdef VACATION
2625 else if (parse_identifier(filter,CUS "vacation"))
2626 {
2627 /*
2628 vacation-command = "vacation" { vacation-options } <reason: string> ";"
2629 vacation-options = [":days" number]
2630 [":subject" string]
2631 [":from" string]
2632 [":addresses" string-list]
2633 [":mime"]
2634 [":handle" string]
2635 */
2636
2637 int m;
2638 unsigned long days;
2639 struct String subject;
2640 struct String from;
2641 struct String *addresses;
2642 int reason_is_mime;
2643 string_item *aliases;
2644 struct String handle;
2645 struct String reason;
2646
2647 if (!filter->require_vacation)
2648 {
2649 filter->errmsg=CUS "missing previous require \"vacation\";";
2650 return -1;
2651 }
2652 if (exec)
2653 {
2654 if (filter->vacation_ran)
2655 {
2656 filter->errmsg=CUS "trying to execute vacation more than once";
2657 return -1;
2658 }
2659 filter->vacation_ran=1;
2660 }
2661 days=VACATION_MIN_DAYS>7 ? VACATION_MIN_DAYS : 7;
2662 subject.character=(uschar*)0;
2663 subject.length=-1;
2664 from.character=(uschar*)0;
2665 from.length=-1;
2666 addresses=(struct String*)0;
2667 aliases=NULL;
2668 reason_is_mime=0;
2669 handle.character=(uschar*)0;
2670 handle.length=-1;
2671 for (;;)
2672 {
2673 if (parse_white(filter)==-1) return -1;
2674 if (parse_identifier(filter,CUS ":days")==1)
2675 {
2676 if (parse_white(filter)==-1) return -1;
2677 if (parse_number(filter,&days)==-1) return -1;
2678 if (days<VACATION_MIN_DAYS) days=VACATION_MIN_DAYS;
2679 else if (days>VACATION_MAX_DAYS) days=VACATION_MAX_DAYS;
2680 }
2681 else if (parse_identifier(filter,CUS ":subject")==1)
2682 {
2683 if (parse_white(filter)==-1) return -1;
2684 if ((m=parse_string(filter,&subject))!=1)
2685 {
2686 if (m==0) filter->errmsg=CUS "subject string expected";
2687 return -1;
2688 }
2689 }
2690 else if (parse_identifier(filter,CUS ":from")==1)
2691 {
2692 int start, end, domain;
2693 uschar *error,*ss;
2694
2695 if (parse_white(filter)==-1) return -1;
2696 if ((m=parse_string(filter,&from))!=1)
2697 {
2698 if (m==0) filter->errmsg=CUS "from string expected";
2699 return -1;
2700 }
2701 if (from.length>0)
2702 {
2703 ss = parse_extract_address(from.character, &error, &start, &end, &domain,
2704 FALSE);
2705 if (ss == NULL)
2706 {
2707 filter->errmsg=string_sprintf("malformed address \"%s\" in "
2708 "Sieve filter: %s", from.character, error);
2709 return -1;
2710 }
2711 }
2712 else
2713 {
2714 filter->errmsg=CUS "empty :from address in Sieve filter";
2715 return -1;
2716 }
2717 }
2718 else if (parse_identifier(filter,CUS ":addresses")==1)
2719 {
2720 struct String *a;
2721
2722 if (parse_white(filter)==-1) return -1;
2723 if ((m=parse_stringlist(filter,&addresses))!=1)
2724 {
2725 if (m==0) filter->errmsg=CUS "addresses string list expected";
2726 return -1;
2727 }
2728 for (a=addresses; a->length!=-1; ++a)
2729 {
2730 string_item *new;
2731
2732 new=store_get(sizeof(string_item));
2733 new->text=store_get(a->length+1);
2734 if (a->length) memcpy(new->text,a->character,a->length);
2735 new->text[a->length]='\0';
2736 new->next=aliases;
2737 aliases=new;
2738 }
2739 }
2740 else if (parse_identifier(filter,CUS ":mime")==1)
2741 reason_is_mime=1;
2742 else if (parse_identifier(filter,CUS ":handle")==1)
2743 {
2744 if (parse_white(filter)==-1) return -1;
2745 if ((m=parse_string(filter,&from))!=1)
2746 {
2747 if (m==0) filter->errmsg=CUS "handle string expected";
2748 return -1;
2749 }
2750 }
2751 else break;
2752 }
2753 if (parse_white(filter)==-1) return -1;
2754 if ((m=parse_string(filter,&reason))!=1)
2755 {
2756 if (m==0) filter->errmsg=CUS "missing reason string";
2757 return -1;
2758 }
2759 if (reason_is_mime)
2760 {
2761 uschar *s,*end;
2762
2763 for (s=reason.character,end=reason.character+reason.length; s<end && (*s&0x80)==0; ++s);
2764 if (s<end)
2765 {
2766 filter->errmsg=CUS "MIME reason string contains 8bit text";
2767 return -1;
2768 }
2769 }
2770 if (parse_semicolon(filter)==-1) return -1;
2771
2772 if (exec)
2773 {
2774 address_item *addr;
2775 int capacity,start;
2776 uschar *buffer;
2777 int buffer_capacity;
2778 struct String key;
2779 md5 base;
2780 uschar digest[16];
2781 uschar hexdigest[33];
2782 int i;
2783 uschar *once;
2784
2785 if (filter_personal(aliases,TRUE))
2786 {
2787 if (filter_test == FTEST_NONE)
2788 {
2789 /* ensure oncelog directory exists; failure will be detected later */
2790
2791 (void)directory_make(NULL, filter->vacation_directory, 0700, FALSE);
2792 }
2793 /* build oncelog filename */
2794
2795 key.character=(uschar*)0;
2796 key.length=0;
2797 capacity=0;
2798 if (handle.length==-1)
2799 {
2800 if (subject.length!=-1) key.character=string_cat(key.character,&capacity,&key.length,subject.character,subject.length);
2801 if (from.length!=-1) key.character=string_cat(key.character,&capacity,&key.length,from.character,from.length);
2802 key.character=string_cat(key.character,&capacity,&key.length,reason_is_mime?US"1":US"0",1);
2803 key.character=string_cat(key.character,&capacity,&key.length,reason.character,reason.length);
2804 }
2805 else
2806 key=handle;
2807 md5_start(&base);
2808 md5_end(&base, key.character, key.length, digest);
2809 for (i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]);
2810 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2811 {
2812 debug_printf("Sieve: mail was personal, vacation file basename: %s\n", hexdigest);
2813 }
2814 if (filter_test == FTEST_NONE)
2815 {
2816 capacity=Ustrlen(filter->vacation_directory);
2817 start=capacity;
2818 once=string_cat(filter->vacation_directory,&capacity,&start,US"/",1);
2819 once=string_cat(once,&capacity,&start,hexdigest,33);
2820 once[start] = '\0';
2821
2822 /* process subject */
2823
2824 if (subject.length==-1)
2825 {
2826 uschar *subject_def;
2827
2828 subject_def=expand_string(US"${if def:header_subject {true}{false}}");
2829 if (Ustrcmp(subject_def,"true")==0)
2830 {
2831 expand_header(&subject,&str_subject);
2832 capacity=6;
2833 start=6;
2834 subject.character=string_cat(US"Auto: ",&capacity,&start,subject.character,subject.length);
2835 subject.length=start;
2836 }
2837 else
2838 {
2839 subject.character=US"Automated reply";
2840 subject.length=Ustrlen(subject.character);
2841 }
2842 }
2843
2844 /* add address to list of generated addresses */
2845
2846 addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
2847 setflag(addr, af_pfr);
2848 setflag(addr, af_ignore_error);
2849 addr->next = *generated;
2850 *generated = addr;
2851 addr->reply = store_get(sizeof(reply_item));
2852 memset(addr->reply,0,sizeof(reply_item)); /* XXX */
2853 addr->reply->to = string_copy(sender_address);
2854 if (from.length==-1)
2855 addr->reply->from = expand_string(US"$local_part@$domain");
2856 else
2857 addr->reply->from = from.character;
2858 /* Allocation is larger than neccessary, but enough even for split MIME words */
2859 buffer_capacity=32+4*subject.length;
2860 buffer=store_get(buffer_capacity);
2861 addr->reply->subject=parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE);
2862 addr->reply->oncelog=once;
2863 addr->reply->once_repeat=days*86400;
2864
2865 /* build body and MIME headers */
2866
2867 if (reason_is_mime)
2868 {
2869 uschar *mime_body,*reason_end;
2870 static const uschar nlnl[]="\r\n\r\n";
2871
2872 for
2873 (
2874 mime_body=reason.character,reason_end=reason.character+reason.length;
2875 mime_body<(reason_end-(sizeof(nlnl)-1)) && memcmp(mime_body,nlnl,(sizeof(nlnl)-1));
2876 ++mime_body
2877 );
2878 capacity = 0;
2879 start = 0;
2880 addr->reply->headers = string_cat(NULL,&capacity,&start,reason.character,mime_body-reason.character);
2881 addr->reply->headers[start] = '\0';
2882 capacity = 0;
2883 start = 0;
2884 if (mime_body+(sizeof(nlnl)-1)<reason_end) mime_body+=(sizeof(nlnl)-1);
2885 else mime_body=reason_end-1;
2886 addr->reply->text = string_cat(NULL,&capacity,&start,mime_body,reason_end-mime_body);
2887 addr->reply->text[start] = '\0';
2888 }
2889 else
2890 {
2891 struct String qp = { NULL, 0 }; /* Keep compiler happy (PH) */
2892
2893 capacity = 0;
2894 start = reason.length;
2895 addr->reply->headers = US"MIME-Version: 1.0\n"
2896 "Content-Type: text/plain;\n"
2897 "\tcharset=\"utf-8\"\n"
2898 "Content-Transfer-Encoding: quoted-printable";
2899 addr->reply->text = quoted_printable_encode(&reason,&qp)->character;
2900 }
2901 }
2902 }
2903 else if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
2904 {
2905 debug_printf("Sieve: mail was not personal, vacation would ignore it\n");
2906 }
2907 }
2908 }
2909 else break;
2910 #endif
2911 }
2912 return 1;
2913 }
2914
2915
2916 /*************************************************
2917 * Parse and interpret a sieve filter *
2918 *************************************************/
2919
2920 /*
2921 Arguments:
2922 filter points to the Sieve filter including its state
2923 exec Execute parsed statements
2924 generated where to hang newly-generated addresses
2925
2926 Returns: 1 success
2927 -1 syntax or execution error
2928 */
2929
2930 static int parse_start(struct Sieve *filter, int exec,
2931 address_item **generated)
2932 {
2933 filter->pc=filter->filter;
2934 filter->line=1;
2935 filter->keep=1;
2936 filter->require_envelope=0;
2937 filter->require_fileinto=0;
2938 #ifdef ENVELOPE_AUTH
2939 filter->require_envelope_auth=0;
2940 #endif
2941 #ifdef NOTIFY
2942 filter->require_notify=0;
2943 filter->notified=(struct Notification*)0;
2944 #endif
2945 #ifdef SUBADDRESS
2946 filter->require_subaddress=0;
2947 #endif
2948 #ifdef VACATION
2949 filter->require_vacation=0;
2950 filter->vacation_ran=0;
2951 #endif
2952 filter->require_copy=0;
2953 filter->require_iascii_numeric=0;
2954
2955 if (parse_white(filter)==-1) return -1;
2956
2957 if (exec && filter->vacation_directory != NULL && filter_test == FTEST_NONE)
2958 {
2959 DIR *oncelogdir;
2960 struct dirent *oncelog;
2961 struct stat properties;
2962 time_t now;
2963
2964 /* clean up old vacation log databases */
2965
2966 oncelogdir=opendir(CS filter->vacation_directory);
2967
2968 if (oncelogdir ==(DIR*)0 && errno != ENOENT)
2969 {
2970 filter->errmsg=CUS "unable to open vacation directory";
2971 return -1;
2972 }
2973
2974 if (oncelogdir != NULL)
2975 {
2976 time(&now);
2977
2978 while ((oncelog=readdir(oncelogdir))!=(struct dirent*)0)
2979 {
2980 if (strlen(oncelog->d_name)==32)
2981 {
2982 uschar *s=string_sprintf("%s/%s",filter->vacation_directory,oncelog->d_name);
2983 if (Ustat(s,&properties)==0 && (properties.st_mtime+VACATION_MAX_DAYS*86400)<now)
2984 Uunlink(s);
2985 }
2986 }
2987 closedir(oncelogdir);
2988 }
2989 }
2990
2991 while (parse_identifier(filter,CUS "require"))
2992 {
2993 /*
2994 require-command = "require" <capabilities: string-list>
2995 */
2996
2997 struct String *cap,*check;
2998 int m;
2999
3000 if (parse_white(filter)==-1) return -1;
3001 if ((m=parse_stringlist(filter,&cap))!=1)
3002 {
3003 if (m==0) filter->errmsg=CUS "capability string list expected";
3004 return -1;
3005 }
3006 for (check=cap; check->character; ++check)
3007 {
3008 if (eq_octet(check,&str_envelope,0)) filter->require_envelope=1;
3009 else if (eq_octet(check,&str_fileinto,0)) filter->require_fileinto=1;
3010 #ifdef ENVELOPE_AUTH
3011 else if (eq_octet(check,&str_envelope_auth,0)) filter->require_envelope_auth=1;
3012 #endif
3013 #ifdef NOTIFY
3014 else if (eq_octet(check,&str_notify,0)) filter->require_notify=1;
3015 #endif
3016 #ifdef SUBADDRESS
3017 else if (eq_octet(check,&str_subaddress,0)) filter->require_subaddress=1;
3018 #endif
3019 #ifdef VACATION
3020 else if (eq_octet(check,&str_vacation,0))
3021 {
3022 if (filter_test == FTEST_NONE && filter->vacation_directory == NULL)
3023 {
3024 filter->errmsg=CUS "vacation disabled";
3025 return -1;
3026 }
3027 filter->require_vacation=1;
3028 }
3029 #endif
3030 else if (eq_octet(check,&str_copy,0)) filter->require_copy=1;
3031 else if (eq_octet(check,&str_comparator_ioctet,0)) ;
3032 else if (eq_octet(check,&str_comparator_iascii_casemap,0)) ;
3033 else if (eq_octet(check,&str_comparator_enascii_casemap,0)) ;
3034 else if (eq_octet(check,&str_comparator_iascii_numeric,0)) filter->require_iascii_numeric=1;
3035 else
3036 {
3037 filter->errmsg=CUS "unknown capability";
3038 return -1;
3039 }
3040 }
3041 if (parse_semicolon(filter)==-1) return -1;
3042 }
3043 if (parse_commands(filter,exec,generated)==-1) return -1;
3044 if (*filter->pc)
3045 {
3046 filter->errmsg=CUS "syntax error";
3047 return -1;
3048 }
3049 return 1;
3050 }
3051
3052
3053 /*************************************************
3054 * Interpret a sieve filter file *
3055 *************************************************/
3056
3057 /*
3058 Arguments:
3059 filter points to the entire file, read into store as a single string
3060 options controls whether various special things are allowed, and requests
3061 special actions (not currently used)
3062 sieve_vacation_directory where to store vacation "once" files
3063 useraddress string expression for :user part of address
3064 subaddress string expression for :subaddress part of address
3065 generated where to hang newly-generated addresses
3066 error where to pass back an error text
3067
3068 Returns: FF_DELIVERED success, a significant action was taken
3069 FF_NOTDELIVERED success, no significant action
3070 FF_DEFER defer requested
3071 FF_FAIL fail requested
3072 FF_FREEZE freeze requested
3073 FF_ERROR there was a problem
3074 */
3075
3076 int
3077 sieve_interpret(uschar *filter, int options, uschar *vacation_directory,
3078 uschar *useraddress, uschar *subaddress, address_item **generated, uschar **error)
3079 {
3080 struct Sieve sieve;
3081 int r;
3082 uschar *msg;
3083
3084 options = options; /* Keep picky compilers happy */
3085 error = error;
3086
3087 DEBUG(D_route) debug_printf("Sieve: start of processing\n");
3088 sieve.filter=filter;
3089
3090 if (vacation_directory == NULL)
3091 sieve.vacation_directory = NULL;
3092 else
3093 {
3094 sieve.vacation_directory=expand_string(vacation_directory);
3095 if (sieve.vacation_directory == NULL)
3096 {
3097 *error = string_sprintf("failed to expand \"%s\" "
3098 "(sieve_vacation_directory): %s", vacation_directory,
3099 expand_string_message);
3100 return FF_ERROR;
3101 }
3102 }
3103
3104 sieve.useraddress = useraddress == NULL ? CUS "$local_part_prefix$local_part$local_part_suffix" : useraddress;
3105 sieve.subaddress = subaddress;
3106
3107 #ifdef COMPILE_SYNTAX_CHECKER
3108 if (parse_start(&sieve,0,generated)==1)
3109 #else
3110 if (parse_start(&sieve,1,generated)==1)
3111 #endif
3112 {
3113 if (sieve.keep)
3114 {
3115 add_addr(generated,US"inbox",1,0,0,0);
3116 msg = string_sprintf("Implicit keep");
3117 r = FF_DELIVERED;
3118 }
3119 else
3120 {
3121 msg = string_sprintf("No implicit keep");
3122 r = FF_DELIVERED;
3123 }
3124 }
3125 else
3126 {
3127 msg = string_sprintf("Sieve error: %s in line %d",sieve.errmsg,sieve.line);
3128 #ifdef COMPILE_SYNTAX_CHECKER
3129 r = FF_ERROR;
3130 *error = msg;
3131 #else
3132 add_addr(generated,US"inbox",1,0,0,0);
3133 r = FF_DELIVERED;
3134 #endif
3135 }
3136
3137 #ifndef COMPILE_SYNTAX_CHECKER
3138 if (filter_test != FTEST_NONE) printf("%s\n", (const char*) msg);
3139 else debug_printf("%s\n", msg);
3140 #endif
3141
3142 DEBUG(D_route) debug_printf("Sieve: end of processing\n");
3143 return r;
3144 }