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