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