Compilation warnings shushing
[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 = {NULL, 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 add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage)
1050 {
1051 address_item *new_addr;
1052
1053 for (new_addr=*generated; new_addr; new_addr=new_addr->next)
1054 {
1055 if (Ustrcmp(new_addr->address,addr)==0 && (file ? testflag(new_addr, af_pfr|af_file) : 1))
1056 {
1057 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
1058 {
1059 debug_printf("Repeated %s `%s' ignored.\n",file ? "fileinto" : "redirect", addr);
1060 }
1061 return;
1062 }
1063 }
1064
1065 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
1066 {
1067 debug_printf("%s `%s'\n",file ? "fileinto" : "redirect", addr);
1068 }
1069 new_addr=deliver_make_addr(addr,TRUE);
1070 if (file)
1071 {
1072 setflag(new_addr, af_pfr|af_file);
1073 new_addr->mode = 0;
1074 }
1075 new_addr->prop.errors_address = NULL;
1076 new_addr->next = *generated;
1077 *generated = new_addr;
1078 }
1079
1080
1081 /*************************************************
1082 * Return decoded header field *
1083 *************************************************/
1084
1085 /*
1086 Unfold the header field as described in RFC 2822 and remove all
1087 leading and trailing white space, then perform MIME decoding and
1088 translate the header field to UTF-8.
1089
1090 Arguments:
1091 value returned value of the field
1092 header name of the header field
1093
1094 Returns: nothing The expanded string is empty
1095 in case there is no such header
1096 */
1097
1098 static void expand_header(struct String *value, const struct String *header)
1099 {
1100 uschar *s,*r,*t;
1101 uschar *errmsg;
1102
1103 value->length=0;
1104 value->character=(uschar*)0;
1105
1106 t=r=s=expand_string(string_sprintf("$rheader_%s",quote(header)));
1107 while (*r==' ' || *r=='\t') ++r;
1108 while (*r)
1109 {
1110 if (*r=='\n')
1111 ++r;
1112 else
1113 *t++=*r++;
1114 }
1115 while (t>s && (*(t-1)==' ' || *(t-1)=='\t')) --t;
1116 *t='\0';
1117 value->character=rfc2047_decode(s,check_rfc2047_length,US"utf-8",'\0',&value->length,&errmsg);
1118 }
1119
1120
1121 /*************************************************
1122 * Parse remaining hash comment *
1123 *************************************************/
1124
1125 /*
1126 Token definition:
1127 Comment up to terminating CRLF
1128
1129 Arguments:
1130 filter points to the Sieve filter including its state
1131
1132 Returns: 1 success
1133 -1 syntax error
1134 */
1135
1136 static int parse_hashcomment(struct Sieve *filter)
1137 {
1138 ++filter->pc;
1139 while (*filter->pc)
1140 {
1141 #ifdef RFC_EOL
1142 if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1143 #else
1144 if (*filter->pc=='\n')
1145 #endif
1146 {
1147 #ifdef RFC_EOL
1148 filter->pc+=2;
1149 #else
1150 ++filter->pc;
1151 #endif
1152 ++filter->line;
1153 return 1;
1154 }
1155 else ++filter->pc;
1156 }
1157 filter->errmsg=CUS "missing end of comment";
1158 return -1;
1159 }
1160
1161
1162 /*************************************************
1163 * Parse remaining C-style comment *
1164 *************************************************/
1165
1166 /*
1167 Token definition:
1168 Everything up to star slash
1169
1170 Arguments:
1171 filter points to the Sieve filter including its state
1172
1173 Returns: 1 success
1174 -1 syntax error
1175 */
1176
1177 static int parse_comment(struct Sieve *filter)
1178 {
1179 filter->pc+=2;
1180 while (*filter->pc)
1181 {
1182 if (*filter->pc=='*' && *(filter->pc+1)=='/')
1183 {
1184 filter->pc+=2;
1185 return 1;
1186 }
1187 else ++filter->pc;
1188 }
1189 filter->errmsg=CUS "missing end of comment";
1190 return -1;
1191 }
1192
1193
1194 /*************************************************
1195 * Parse optional white space *
1196 *************************************************/
1197
1198 /*
1199 Token definition:
1200 Spaces, tabs, CRLFs, hash comments or C-style comments
1201
1202 Arguments:
1203 filter points to the Sieve filter including its state
1204
1205 Returns: 1 success
1206 -1 syntax error
1207 */
1208
1209 static int parse_white(struct Sieve *filter)
1210 {
1211 while (*filter->pc)
1212 {
1213 if (*filter->pc==' ' || *filter->pc=='\t') ++filter->pc;
1214 #ifdef RFC_EOL
1215 else if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1216 #else
1217 else if (*filter->pc=='\n')
1218 #endif
1219 {
1220 #ifdef RFC_EOL
1221 filter->pc+=2;
1222 #else
1223 ++filter->pc;
1224 #endif
1225 ++filter->line;
1226 }
1227 else if (*filter->pc=='#')
1228 {
1229 if (parse_hashcomment(filter)==-1) return -1;
1230 }
1231 else if (*filter->pc=='/' && *(filter->pc+1)=='*')
1232 {
1233 if (parse_comment(filter)==-1) return -1;
1234 }
1235 else break;
1236 }
1237 return 1;
1238 }
1239
1240
1241 #ifdef ENCODED_CHARACTER
1242 /*************************************************
1243 * Decode hex-encoded-character string *
1244 *************************************************/
1245
1246 /*
1247 Encoding definition:
1248 blank = SP / TAB / CRLF
1249 hex-pair-seq = *blank hex-pair *(1*blank hex-pair) *blank
1250 hex-pair = 1*2HEXDIG
1251
1252 Arguments:
1253 src points to a hex-pair-seq
1254 end points to its end
1255 dst points to the destination of the decoded octets,
1256 optionally to (uschar*)0 for checking only
1257
1258 Returns: >=0 number of decoded octets
1259 -1 syntax error
1260 */
1261
1262 static int hex_decode(uschar *src, uschar *end, uschar *dst)
1263 {
1264 int decoded=0;
1265
1266 while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1267 do
1268 {
1269 int x,d,n;
1270
1271 for (x=0,d=0; d<2 && src<end && isxdigit(n=tolower(*src)); x=(x<<4)|(n>='0' && n<='9' ? n-'0' : 10+(n-'a')),++d,++src);
1272 if (d==0) return -1;
1273 if (dst) *dst++=x;
1274 ++decoded;
1275 if (src==end) return decoded;
1276 if (*src==' ' || *src=='\t' || *src=='\n')
1277 while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1278 else
1279 return -1;
1280 }
1281 while (src<end);
1282 return decoded;
1283 }
1284
1285
1286 /*************************************************
1287 * Decode unicode-encoded-character string *
1288 *************************************************/
1289
1290 /*
1291 Encoding definition:
1292 blank = SP / TAB / CRLF
1293 unicode-hex-seq = *blank unicode-hex *(blank unicode-hex) *blank
1294 unicode-hex = 1*HEXDIG
1295
1296 It is an error for a script to use a hexadecimal value that isn't in
1297 either the range 0 to D7FF or the range E000 to 10FFFF.
1298
1299 At this time, strings are already scanned, thus the CRLF is converted
1300 to the internally used \n (should RFC_EOL have been used).
1301
1302 Arguments:
1303 src points to a unicode-hex-seq
1304 end points to its end
1305 dst points to the destination of the decoded octets,
1306 optionally to (uschar*)0 for checking only
1307
1308 Returns: >=0 number of decoded octets
1309 -1 syntax error
1310 -2 semantic error (character range violation)
1311 */
1312
1313 static int unicode_decode(uschar *src, uschar *end, uschar *dst)
1314 {
1315 int decoded=0;
1316
1317 while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1318 do
1319 {
1320 uschar *hex_seq;
1321 int c,d,n;
1322
1323 unicode_hex:
1324 for (hex_seq=src; src<end && *src=='0'; ++src);
1325 for (c=0,d=0; d<7 && src<end && isxdigit(n=tolower(*src)); c=(c<<4)|(n>='0' && n<='9' ? n-'0' : 10+(n-'a')),++d,++src);
1326 if (src==hex_seq) return -1;
1327 if (d==7 || (!((c>=0 && c<=0xd7ff) || (c>=0xe000 && c<=0x10ffff)))) return -2;
1328 if (c<128)
1329 {
1330 if (dst) *dst++=c;
1331 ++decoded;
1332 }
1333 else if (c>=0x80 && c<=0x7ff)
1334 {
1335 if (dst)
1336 {
1337 *dst++=192+(c>>6);
1338 *dst++=128+(c&0x3f);
1339 }
1340 decoded+=2;
1341 }
1342 else if (c>=0x800 && c<=0xffff)
1343 {
1344 if (dst)
1345 {
1346 *dst++=224+(c>>12);
1347 *dst++=128+((c>>6)&0x3f);
1348 *dst++=128+(c&0x3f);
1349 }
1350 decoded+=3;
1351 }
1352 else if (c>=0x10000 && c<=0x1fffff)
1353 {
1354 if (dst)
1355 {
1356 *dst++=240+(c>>18);
1357 *dst++=128+((c>>10)&0x3f);
1358 *dst++=128+((c>>6)&0x3f);
1359 *dst++=128+(c&0x3f);
1360 }
1361 decoded+=4;
1362 }
1363 if (*src==' ' || *src=='\t' || *src=='\n')
1364 {
1365 while (*src==' ' || *src=='\t' || *src=='\n') ++src;
1366 if (src==end) return decoded;
1367 goto unicode_hex;
1368 }
1369 }
1370 while (src<end);
1371 return decoded;
1372 }
1373
1374
1375 /*************************************************
1376 * Decode encoded-character string *
1377 *************************************************/
1378
1379 /*
1380 Encoding definition:
1381 encoded-arb-octets = "${hex:" hex-pair-seq "}"
1382 encoded-unicode-char = "${unicode:" unicode-hex-seq "}"
1383
1384 Arguments:
1385 encoded points to an encoded string, returns decoded string
1386 filter points to the Sieve filter including its state
1387
1388 Returns: 1 success
1389 -1 syntax error
1390 */
1391
1392 static int string_decode(struct Sieve *filter, struct String *data)
1393 {
1394 uschar *src,*dst,*end;
1395
1396 src=data->character;
1397 dst=src;
1398 end=data->character+data->length;
1399 while (src<end)
1400 {
1401 uschar *brace;
1402
1403 if (
1404 strncmpic(src,US "${hex:",6)==0
1405 && (brace=Ustrchr(src+6,'}'))!=(uschar*)0
1406 && (hex_decode(src+6,brace,(uschar*)0))>=0
1407 )
1408 {
1409 dst+=hex_decode(src+6,brace,dst);
1410 src=brace+1;
1411 }
1412 else if (
1413 strncmpic(src,US "${unicode:",10)==0
1414 && (brace=Ustrchr(src+10,'}'))!=(uschar*)0
1415 )
1416 {
1417 switch (unicode_decode(src+10,brace,(uschar*)0))
1418 {
1419 case -2:
1420 {
1421 filter->errmsg=CUS "unicode character out of range";
1422 return -1;
1423 }
1424 case -1:
1425 {
1426 *dst++=*src++;
1427 break;
1428 }
1429 default:
1430 {
1431 dst+=unicode_decode(src+10,brace,dst);
1432 src=brace+1;
1433 }
1434 }
1435 }
1436 else *dst++=*src++;
1437 }
1438 data->length=dst-data->character;
1439 *dst='\0';
1440 return 1;
1441 }
1442 #endif
1443
1444
1445 /*************************************************
1446 * Parse an optional string *
1447 *************************************************/
1448
1449 /*
1450 Token definition:
1451 quoted-string = DQUOTE *CHAR DQUOTE
1452 ;; in general, \ CHAR inside a string maps to CHAR
1453 ;; so \" maps to " and \\ maps to \
1454 ;; note that newlines and other characters are all allowed
1455 ;; in strings
1456
1457 multi-line = "text:" *(SP / HTAB) (hash-comment / CRLF)
1458 *(multi-line-literal / multi-line-dotstuff)
1459 "." CRLF
1460 multi-line-literal = [CHAR-NOT-DOT *CHAR-NOT-CRLF] CRLF
1461 multi-line-dotstuff = "." 1*CHAR-NOT-CRLF CRLF
1462 ;; A line containing only "." ends the multi-line.
1463 ;; Remove a leading '.' if followed by another '.'.
1464 string = quoted-string / multi-line
1465
1466 Arguments:
1467 filter points to the Sieve filter including its state
1468 id specifies identifier to match
1469
1470 Returns: 1 success
1471 -1 syntax error
1472 0 identifier not matched
1473 */
1474
1475 static int parse_string(struct Sieve *filter, struct String *data)
1476 {
1477 int dataCapacity=0;
1478
1479 data->length=0;
1480 data->character=(uschar*)0;
1481 if (*filter->pc=='"') /* quoted string */
1482 {
1483 ++filter->pc;
1484 while (*filter->pc)
1485 {
1486 if (*filter->pc=='"') /* end of string */
1487 {
1488 int foo=data->length;
1489
1490 ++filter->pc;
1491 /* that way, there will be at least one character allocated */
1492 data->character=string_catn(data->character,&dataCapacity,&foo,CUS "",1);
1493 #ifdef ENCODED_CHARACTER
1494 if (filter->require_encoded_character
1495 && string_decode(filter,data)==-1)
1496 return -1;
1497 #endif
1498 return 1;
1499 }
1500 else if (*filter->pc=='\\' && *(filter->pc+1)) /* quoted character */
1501 {
1502 data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc+1,1);
1503 filter->pc+=2;
1504 }
1505 else /* regular character */
1506 {
1507 #ifdef RFC_EOL
1508 if (*filter->pc=='\r' && *(filter->pc+1)=='\n') ++filter->line;
1509 #else
1510 if (*filter->pc=='\n')
1511 {
1512 data->character=string_catn(data->character,&dataCapacity,&data->length,US"\r",1);
1513 ++filter->line;
1514 }
1515 #endif
1516 data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc,1);
1517 filter->pc++;
1518 }
1519 }
1520 filter->errmsg=CUS "missing end of string";
1521 return -1;
1522 }
1523 else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */
1524 {
1525 filter->pc+=5;
1526 /* skip optional white space followed by hashed comment or CRLF */
1527 while (*filter->pc==' ' || *filter->pc=='\t') ++filter->pc;
1528 if (*filter->pc=='#')
1529 {
1530 if (parse_hashcomment(filter)==-1) return -1;
1531 }
1532 #ifdef RFC_EOL
1533 else if (*filter->pc=='\r' && *(filter->pc+1)=='\n')
1534 #else
1535 else if (*filter->pc=='\n')
1536 #endif
1537 {
1538 #ifdef RFC_EOL
1539 filter->pc+=2;
1540 #else
1541 ++filter->pc;
1542 #endif
1543 ++filter->line;
1544 }
1545 else
1546 {
1547 filter->errmsg=CUS "syntax error";
1548 return -1;
1549 }
1550 while (*filter->pc)
1551 {
1552 #ifdef RFC_EOL
1553 if (*filter->pc=='\r' && *(filter->pc+1)=='\n') /* end of line */
1554 #else
1555 if (*filter->pc=='\n') /* end of line */
1556 #endif
1557 {
1558 data->character=string_catn(data->character,&dataCapacity,&data->length,CUS "\r\n",2);
1559 #ifdef RFC_EOL
1560 filter->pc+=2;
1561 #else
1562 ++filter->pc;
1563 #endif
1564 ++filter->line;
1565 #ifdef RFC_EOL
1566 if (*filter->pc=='.' && *(filter->pc+1)=='\r' && *(filter->pc+2)=='\n') /* end of string */
1567 #else
1568 if (*filter->pc=='.' && *(filter->pc+1)=='\n') /* end of string */
1569 #endif
1570 {
1571 int foo=data->length;
1572
1573 /* that way, there will be at least one character allocated */
1574 data->character=string_catn(data->character,&dataCapacity,&foo,CUS "",1);
1575 #ifdef RFC_EOL
1576 filter->pc+=3;
1577 #else
1578 filter->pc+=2;
1579 #endif
1580 ++filter->line;
1581 #ifdef ENCODED_CHARACTER
1582 if (filter->require_encoded_character
1583 && string_decode(filter,data)==-1)
1584 return -1;
1585 #endif
1586 return 1;
1587 }
1588 else if (*filter->pc=='.' && *(filter->pc+1)=='.') /* remove dot stuffing */
1589 {
1590 data->character=string_catn(data->character,&dataCapacity,&data->length,CUS ".",1);
1591 filter->pc+=2;
1592 }
1593 }
1594 else /* regular character */
1595 {
1596 data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc,1);
1597 filter->pc++;
1598 }
1599 }
1600 filter->errmsg=CUS "missing end of multi line string";
1601 return -1;
1602 }
1603 else return 0;
1604 }
1605
1606
1607 /*************************************************
1608 * Parse a specific identifier *
1609 *************************************************/
1610
1611 /*
1612 Token definition:
1613 identifier = (ALPHA / "_") *(ALPHA DIGIT "_")
1614
1615 Arguments:
1616 filter points to the Sieve filter including its state
1617 id specifies identifier to match
1618
1619 Returns: 1 success
1620 0 identifier not matched
1621 */
1622
1623 static int parse_identifier(struct Sieve *filter, const uschar *id)
1624 {
1625 size_t idlen=Ustrlen(id);
1626
1627 if (strncmpic(US filter->pc,US id,idlen)==0)
1628 {
1629 uschar next=filter->pc[idlen];
1630
1631 if ((next>='A' && next<='Z') || (next>='a' && next<='z') || next=='_' || (next>='0' && next<='9')) return 0;
1632 filter->pc+=idlen;
1633 return 1;
1634 }
1635 else return 0;
1636 }
1637
1638
1639 /*************************************************
1640 * Parse a number *
1641 *************************************************/
1642
1643 /*
1644 Token definition:
1645 number = 1*DIGIT [QUANTIFIER]
1646 QUANTIFIER = "K" / "M" / "G"
1647
1648 Arguments:
1649 filter points to the Sieve filter including its state
1650 data returns value
1651
1652 Returns: 1 success
1653 -1 no string list found
1654 */
1655
1656 static int parse_number(struct Sieve *filter, unsigned long *data)
1657 {
1658 unsigned long d,u;
1659
1660 if (*filter->pc>='0' && *filter->pc<='9')
1661 {
1662 uschar *e;
1663
1664 errno=0;
1665 d=Ustrtoul(filter->pc,&e,10);
1666 if (errno==ERANGE)
1667 {
1668 filter->errmsg=CUstrerror(ERANGE);
1669 return -1;
1670 }
1671 filter->pc=e;
1672 u=1;
1673 if (*filter->pc=='K') { u=1024; ++filter->pc; }
1674 else if (*filter->pc=='M') { u=1024*1024; ++filter->pc; }
1675 else if (*filter->pc=='G') { u=1024*1024*1024; ++filter->pc; }
1676 if (d>(ULONG_MAX/u))
1677 {
1678 filter->errmsg=CUstrerror(ERANGE);
1679 return -1;
1680 }
1681 d*=u;
1682 *data=d;
1683 return 1;
1684 }
1685 else
1686 {
1687 filter->errmsg=CUS "missing number";
1688 return -1;
1689 }
1690 }
1691
1692
1693 /*************************************************
1694 * Parse a string list *
1695 *************************************************/
1696
1697 /*
1698 Grammar:
1699 string-list = "[" string *("," string) "]" / string
1700
1701 Arguments:
1702 filter points to the Sieve filter including its state
1703 data returns string list
1704
1705 Returns: 1 success
1706 -1 no string list found
1707 */
1708
1709 static int
1710 parse_stringlist(struct Sieve *filter, struct String **data)
1711 {
1712 const uschar *orig=filter->pc;
1713 int dataCapacity = 0;
1714 int dataLength = 0;
1715 struct String *d = NULL;
1716 int m;
1717
1718 if (*filter->pc=='[') /* string list */
1719 {
1720 ++filter->pc;
1721 for (;;)
1722 {
1723 if (parse_white(filter)==-1) goto error;
1724 if (dataLength+1 >= dataCapacity) /* increase buffer */
1725 {
1726 struct String *new;
1727 int newCapacity; /* Don't amalgamate with next line; some compilers grumble */
1728
1729 dataCapacity = dataCapacity ? dataCapacity * 2 : 4;
1730 new = store_get(sizeof(struct String) * dataCapacity);
1731
1732 if (d) memcpy(new,d,sizeof(struct String)*dataLength);
1733 d = new;
1734 }
1735
1736 m=parse_string(filter,&d[dataLength]);
1737 if (m==0)
1738 {
1739 if (dataLength==0) break;
1740 else
1741 {
1742 filter->errmsg=CUS "missing string";
1743 goto error;
1744 }
1745 }
1746 else if (m==-1) goto error;
1747 else ++dataLength;
1748 if (parse_white(filter)==-1) goto error;
1749 if (*filter->pc==',') ++filter->pc;
1750 else break;
1751 }
1752 if (*filter->pc==']')
1753 {
1754 d[dataLength].character=(uschar*)0;
1755 d[dataLength].length=-1;
1756 ++filter->pc;
1757 *data=d;
1758 return 1;
1759 }
1760 else
1761 {
1762 filter->errmsg=CUS "missing closing bracket";
1763 goto error;
1764 }
1765 }
1766 else /* single string */
1767 {
1768 if ((d=store_get(sizeof(struct String)*2))==(struct String*)0)
1769 {
1770 return -1;
1771 }
1772 m=parse_string(filter,&d[0]);
1773 if (m==-1)
1774 {
1775 return -1;
1776 }
1777 else if (m==0)
1778 {
1779 filter->pc=orig;
1780 return 0;
1781 }
1782 else
1783 {
1784 d[1].character=(uschar*)0;
1785 d[1].length=-1;
1786 *data=d;
1787 return 1;
1788 }
1789 }
1790 error:
1791 filter->errmsg=CUS "missing string list";
1792 return -1;
1793 }
1794
1795
1796 /*************************************************
1797 * Parse an optional address part specifier *
1798 *************************************************/
1799
1800 /*
1801 Grammar:
1802 address-part = ":localpart" / ":domain" / ":all"
1803 address-part =/ ":user" / ":detail"
1804
1805 Arguments:
1806 filter points to the Sieve filter including its state
1807 a returns address part specified
1808
1809 Returns: 1 success
1810 0 no comparator found
1811 -1 syntax error
1812 */
1813
1814 static int parse_addresspart(struct Sieve *filter, enum AddressPart *a)
1815 {
1816 #ifdef SUBADDRESS
1817 if (parse_identifier(filter,CUS ":user")==1)
1818 {
1819 if (!filter->require_subaddress)
1820 {
1821 filter->errmsg=CUS "missing previous require \"subaddress\";";
1822 return -1;
1823 }
1824 *a=ADDRPART_USER;
1825 return 1;
1826 }
1827 else if (parse_identifier(filter,CUS ":detail")==1)
1828 {
1829 if (!filter->require_subaddress)
1830 {
1831 filter->errmsg=CUS "missing previous require \"subaddress\";";
1832 return -1;
1833 }
1834 *a=ADDRPART_DETAIL;
1835 return 1;
1836 }
1837 else
1838 #endif
1839 if (parse_identifier(filter,CUS ":localpart")==1)
1840 {
1841 *a=ADDRPART_LOCALPART;
1842 return 1;
1843 }
1844 else if (parse_identifier(filter,CUS ":domain")==1)
1845 {
1846 *a=ADDRPART_DOMAIN;
1847 return 1;
1848 }
1849 else if (parse_identifier(filter,CUS ":all")==1)
1850 {
1851 *a=ADDRPART_ALL;
1852 return 1;
1853 }
1854 else return 0;
1855 }
1856
1857
1858 /*************************************************
1859 * Parse an optional comparator *
1860 *************************************************/
1861
1862 /*
1863 Grammar:
1864 comparator = ":comparator" <comparator-name: string>
1865
1866 Arguments:
1867 filter points to the Sieve filter including its state
1868 c returns comparator
1869
1870 Returns: 1 success
1871 0 no comparator found
1872 -1 incomplete comparator found
1873 */
1874
1875 static int parse_comparator(struct Sieve *filter, enum Comparator *c)
1876 {
1877 struct String comparator_name;
1878
1879 if (parse_identifier(filter,CUS ":comparator")==0) return 0;
1880 if (parse_white(filter)==-1) return -1;
1881 switch (parse_string(filter,&comparator_name))
1882 {
1883 case -1: return -1;
1884 case 0:
1885 {
1886 filter->errmsg=CUS "missing comparator";
1887 return -1;
1888 }
1889 default:
1890 {
1891 int match;
1892
1893 if (eq_asciicase(&comparator_name,&str_ioctet,0))
1894 {
1895 *c=COMP_OCTET;
1896 match=1;
1897 }
1898 else if (eq_asciicase(&comparator_name,&str_iascii_casemap,0))
1899 {
1900 *c=COMP_EN_ASCII_CASEMAP;
1901 match=1;
1902 }
1903 else if (eq_asciicase(&comparator_name,&str_enascii_casemap,0))
1904 {
1905 *c=COMP_EN_ASCII_CASEMAP;
1906 match=1;
1907 }
1908 else if (eq_asciicase(&comparator_name,&str_iascii_numeric,0))
1909 {
1910 *c=COMP_ASCII_NUMERIC;
1911 match=1;
1912 }
1913 else
1914 {
1915 filter->errmsg=CUS "invalid comparator";
1916 match=-1;
1917 }
1918 return match;
1919 }
1920 }
1921 }
1922
1923
1924 /*************************************************
1925 * Parse an optional match type *
1926 *************************************************/
1927
1928 /*
1929 Grammar:
1930 match-type = ":is" / ":contains" / ":matches"
1931
1932 Arguments:
1933 filter points to the Sieve filter including its state
1934 m returns match type
1935
1936 Returns: 1 success
1937 0 no match type found
1938 */
1939
1940 static int parse_matchtype(struct Sieve *filter, enum MatchType *m)
1941 {
1942 if (parse_identifier(filter,CUS ":is")==1)
1943 {
1944 *m=MATCH_IS;
1945 return 1;
1946 }
1947 else if (parse_identifier(filter,CUS ":contains")==1)
1948 {
1949 *m=MATCH_CONTAINS;
1950 return 1;
1951 }
1952 else if (parse_identifier(filter,CUS ":matches")==1)
1953 {
1954 *m=MATCH_MATCHES;
1955 return 1;
1956 }
1957 else return 0;
1958 }
1959
1960
1961 /*************************************************
1962 * Parse and interpret an optional test list *
1963 *************************************************/
1964
1965 /*
1966 Grammar:
1967 test-list = "(" test *("," test) ")"
1968
1969 Arguments:
1970 filter points to the Sieve filter including its state
1971 n total number of tests
1972 num_true number of passed tests
1973 exec Execute parsed statements
1974
1975 Returns: 1 success
1976 0 no test list found
1977 -1 syntax or execution error
1978 */
1979
1980 static int parse_testlist(struct Sieve *filter, int *n, int *num_true, int exec)
1981 {
1982 if (parse_white(filter)==-1) return -1;
1983 if (*filter->pc=='(')
1984 {
1985 ++filter->pc;
1986 *n=0;
1987 *num_true=0;
1988 for (;;)
1989 {
1990 int cond;
1991
1992 switch (parse_test(filter,&cond,exec))
1993 {
1994 case -1: return -1;
1995 case 0: filter->errmsg=CUS "missing test"; return -1;
1996 default: ++*n; if (cond) ++*num_true; break;
1997 }
1998 if (parse_white(filter)==-1) return -1;
1999 if (*filter->pc==',') ++filter->pc;
2000 else break;
2001 }
2002 if (*filter->pc==')')
2003 {
2004 ++filter->pc;
2005 return 1;
2006 }
2007 else
2008 {
2009 filter->errmsg=CUS "missing closing paren";
2010 return -1;
2011 }
2012 }
2013 else return 0;
2014 }
2015
2016
2017 /*************************************************
2018 * Parse and interpret an optional test *
2019 *************************************************/
2020
2021 /*
2022 Arguments:
2023 filter points to the Sieve filter including its state
2024 cond returned condition status
2025 exec Execute parsed statements
2026
2027 Returns: 1 success
2028 0 no test found
2029 -1 syntax or execution error
2030 */
2031
2032 static int parse_test(struct Sieve *filter, int *cond, int exec)
2033 {
2034 if (parse_white(filter)==-1) return -1;
2035 if (parse_identifier(filter,CUS "address"))
2036 {
2037 /*
2038 address-test = "address" { [address-part] [comparator] [match-type] }
2039 <header-list: string-list> <key-list: string-list>
2040
2041 header-list From, To, Cc, Bcc, Sender, Resent-From, Resent-To
2042 */
2043
2044 enum AddressPart addressPart=ADDRPART_ALL;
2045 enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2046 enum MatchType matchType=MATCH_IS;
2047 struct String *hdr,*h,*key,*k;
2048 int m;
2049 int ap=0,co=0,mt=0;
2050
2051 for (;;)
2052 {
2053 if (parse_white(filter)==-1) return -1;
2054 if ((m=parse_addresspart(filter,&addressPart))!=0)
2055 {
2056 if (m==-1) return -1;
2057 if (ap)
2058 {
2059 filter->errmsg=CUS "address part already specified";
2060 return -1;
2061 }
2062 else ap=1;
2063 }
2064 else if ((m=parse_comparator(filter,&comparator))!=0)
2065 {
2066 if (m==-1) return -1;
2067 if (co)
2068 {
2069 filter->errmsg=CUS "comparator already specified";
2070 return -1;
2071 }
2072 else co=1;
2073 }
2074 else if ((m=parse_matchtype(filter,&matchType))!=0)
2075 {
2076 if (m==-1) return -1;
2077 if (mt)
2078 {
2079 filter->errmsg=CUS "match type already specified";
2080 return -1;
2081 }
2082 else mt=1;
2083 }
2084 else break;
2085 }
2086 if (parse_white(filter)==-1) return -1;
2087 if ((m=parse_stringlist(filter,&hdr))!=1)
2088 {
2089 if (m==0) filter->errmsg=CUS "header string list expected";
2090 return -1;
2091 }
2092 if (parse_white(filter)==-1) return -1;
2093 if ((m=parse_stringlist(filter,&key))!=1)
2094 {
2095 if (m==0) filter->errmsg=CUS "key string list expected";
2096 return -1;
2097 }
2098 *cond=0;
2099 for (h=hdr; h->length!=-1 && !*cond; ++h)
2100 {
2101 uschar *header_value=(uschar*)0,*extracted_addr,*end_addr;
2102
2103 if
2104 (
2105 !eq_asciicase(h,&str_from,0)
2106 && !eq_asciicase(h,&str_to,0)
2107 && !eq_asciicase(h,&str_cc,0)
2108 && !eq_asciicase(h,&str_bcc,0)
2109 && !eq_asciicase(h,&str_sender,0)
2110 && !eq_asciicase(h,&str_resent_from,0)
2111 && !eq_asciicase(h,&str_resent_to,0)
2112 )
2113 {
2114 filter->errmsg=CUS "invalid header field";
2115 return -1;
2116 }
2117 if (exec)
2118 {
2119 /* We are only interested in addresses below, so no MIME decoding */
2120 header_value=expand_string(string_sprintf("$rheader_%s",quote(h)));
2121 if (header_value == NULL)
2122 {
2123 filter->errmsg=CUS "header string expansion failed";
2124 return -1;
2125 }
2126 parse_allow_group = TRUE;
2127 while (*header_value && !*cond)
2128 {
2129 uschar *error;
2130 int start, end, domain;
2131 int saveend;
2132 uschar *part=NULL;
2133
2134 end_addr = parse_find_address_end(header_value, FALSE);
2135 saveend = *end_addr;
2136 *end_addr = 0;
2137 extracted_addr = parse_extract_address(header_value, &error, &start, &end, &domain, FALSE);
2138
2139 if (extracted_addr) switch (addressPart)
2140 {
2141 case ADDRPART_ALL: part=extracted_addr; break;
2142 #ifdef SUBADDRESS
2143 case ADDRPART_USER:
2144 #endif
2145 case ADDRPART_LOCALPART: part=extracted_addr; part[domain-1]='\0'; break;
2146 case ADDRPART_DOMAIN: part=extracted_addr+domain; break;
2147 #ifdef SUBADDRESS
2148 case ADDRPART_DETAIL: part=NULL; break;
2149 #endif
2150 }
2151
2152 *end_addr = saveend;
2153 if (part)
2154 {
2155 for (k=key; k->length!=-1; ++k)
2156 {
2157 struct String partStr;
2158
2159 partStr.character=part;
2160 partStr.length=Ustrlen(part);
2161 if (extracted_addr)
2162 {
2163 *cond=compare(filter,k,&partStr,comparator,matchType);
2164 if (*cond==-1) return -1;
2165 if (*cond) break;
2166 }
2167 }
2168 }
2169 if (saveend == 0) break;
2170 header_value = end_addr + 1;
2171 }
2172 parse_allow_group = FALSE;
2173 parse_found_group = FALSE;
2174 }
2175 }
2176 return 1;
2177 }
2178 else if (parse_identifier(filter,CUS "allof"))
2179 {
2180 /*
2181 allof-test = "allof" <tests: test-list>
2182 */
2183
2184 int n,num_true;
2185
2186 switch (parse_testlist(filter,&n,&num_true,exec))
2187 {
2188 case -1: return -1;
2189 case 0: filter->errmsg=CUS "missing test list"; return -1;
2190 default: *cond=(n==num_true); return 1;
2191 }
2192 }
2193 else if (parse_identifier(filter,CUS "anyof"))
2194 {
2195 /*
2196 anyof-test = "anyof" <tests: test-list>
2197 */
2198
2199 int n,num_true;
2200
2201 switch (parse_testlist(filter,&n,&num_true,exec))
2202 {
2203 case -1: return -1;
2204 case 0: filter->errmsg=CUS "missing test list"; return -1;
2205 default: *cond=(num_true>0); return 1;
2206 }
2207 }
2208 else if (parse_identifier(filter,CUS "exists"))
2209 {
2210 /*
2211 exists-test = "exists" <header-names: string-list>
2212 */
2213
2214 struct String *hdr,*h;
2215 int m;
2216
2217 if (parse_white(filter)==-1) return -1;
2218 if ((m=parse_stringlist(filter,&hdr))!=1)
2219 {
2220 if (m==0) filter->errmsg=CUS "header string list expected";
2221 return -1;
2222 }
2223 if (exec)
2224 {
2225 *cond=1;
2226 for (h=hdr; h->length!=-1 && *cond; ++h)
2227 {
2228 uschar *header_def;
2229
2230 header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
2231 if (header_def == NULL)
2232 {
2233 filter->errmsg=CUS "header string expansion failed";
2234 return -1;
2235 }
2236 if (Ustrcmp(header_def,"false")==0) *cond=0;
2237 }
2238 }
2239 return 1;
2240 }
2241 else if (parse_identifier(filter,CUS "false"))
2242 {
2243 /*
2244 false-test = "false"
2245 */
2246
2247 *cond=0;
2248 return 1;
2249 }
2250 else if (parse_identifier(filter,CUS "header"))
2251 {
2252 /*
2253 header-test = "header" { [comparator] [match-type] }
2254 <header-names: string-list> <key-list: string-list>
2255 */
2256
2257 enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2258 enum MatchType matchType=MATCH_IS;
2259 struct String *hdr,*h,*key,*k;
2260 int m;
2261 int co=0,mt=0;
2262
2263 for (;;)
2264 {
2265 if (parse_white(filter)==-1) return -1;
2266 if ((m=parse_comparator(filter,&comparator))!=0)
2267 {
2268 if (m==-1) return -1;
2269 if (co)
2270 {
2271 filter->errmsg=CUS "comparator already specified";
2272 return -1;
2273 }
2274 else co=1;
2275 }
2276 else if ((m=parse_matchtype(filter,&matchType))!=0)
2277 {
2278 if (m==-1) return -1;
2279 if (mt)
2280 {
2281 filter->errmsg=CUS "match type already specified";
2282 return -1;
2283 }
2284 else mt=1;
2285 }
2286 else break;
2287 }
2288 if (parse_white(filter)==-1) return -1;
2289 if ((m=parse_stringlist(filter,&hdr))!=1)
2290 {
2291 if (m==0) filter->errmsg=CUS "header string list expected";
2292 return -1;
2293 }
2294 if (parse_white(filter)==-1) return -1;
2295 if ((m=parse_stringlist(filter,&key))!=1)
2296 {
2297 if (m==0) filter->errmsg=CUS "key string list expected";
2298 return -1;
2299 }
2300 *cond=0;
2301 for (h=hdr; h->length!=-1 && !*cond; ++h)
2302 {
2303 if (!is_header(h))
2304 {
2305 filter->errmsg=CUS "invalid header field";
2306 return -1;
2307 }
2308 if (exec)
2309 {
2310 struct String header_value;
2311 uschar *header_def;
2312
2313 expand_header(&header_value,h);
2314 header_def=expand_string(string_sprintf("${if def:header_%s {true}{false}}",quote(h)));
2315 if (header_value.character == NULL || header_def == NULL)
2316 {
2317 filter->errmsg=CUS "header string expansion failed";
2318 return -1;
2319 }
2320 for (k=key; k->length!=-1; ++k)
2321 {
2322 if (Ustrcmp(header_def,"true")==0)
2323 {
2324 *cond=compare(filter,k,&header_value,comparator,matchType);
2325 if (*cond==-1) return -1;
2326 if (*cond) break;
2327 }
2328 }
2329 }
2330 }
2331 return 1;
2332 }
2333 else if (parse_identifier(filter,CUS "not"))
2334 {
2335 if (parse_white(filter)==-1) return -1;
2336 switch (parse_test(filter,cond,exec))
2337 {
2338 case -1: return -1;
2339 case 0: filter->errmsg=CUS "missing test"; return -1;
2340 default: *cond=!*cond; return 1;
2341 }
2342 }
2343 else if (parse_identifier(filter,CUS "size"))
2344 {
2345 /*
2346 relop = ":over" / ":under"
2347 size-test = "size" relop <limit: number>
2348 */
2349
2350 unsigned long limit;
2351 int overNotUnder;
2352
2353 if (parse_white(filter)==-1) return -1;
2354 if (parse_identifier(filter,CUS ":over")) overNotUnder=1;
2355 else if (parse_identifier(filter,CUS ":under")) overNotUnder=0;
2356 else
2357 {
2358 filter->errmsg=CUS "missing :over or :under";
2359 return -1;
2360 }
2361 if (parse_white(filter)==-1) return -1;
2362 if (parse_number(filter,&limit)==-1) return -1;
2363 *cond=(overNotUnder ? (message_size>limit) : (message_size<limit));
2364 return 1;
2365 }
2366 else if (parse_identifier(filter,CUS "true"))
2367 {
2368 *cond=1;
2369 return 1;
2370 }
2371 else if (parse_identifier(filter,CUS "envelope"))
2372 {
2373 /*
2374 envelope-test = "envelope" { [comparator] [address-part] [match-type] }
2375 <envelope-part: string-list> <key-list: string-list>
2376
2377 envelope-part is case insensitive "from" or "to"
2378 #ifdef ENVELOPE_AUTH
2379 envelope-part =/ "auth"
2380 #endif
2381 */
2382
2383 enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2384 enum AddressPart addressPart=ADDRPART_ALL;
2385 enum MatchType matchType=MATCH_IS;
2386 struct String *env,*e,*key,*k;
2387 int m;
2388 int co=0,ap=0,mt=0;
2389
2390 if (!filter->require_envelope)
2391 {
2392 filter->errmsg=CUS "missing previous require \"envelope\";";
2393 return -1;
2394 }
2395 for (;;)
2396 {
2397 if (parse_white(filter)==-1) return -1;
2398 if ((m=parse_comparator(filter,&comparator))!=0)
2399 {
2400 if (m==-1) return -1;
2401 if (co)
2402 {
2403 filter->errmsg=CUS "comparator already specified";
2404 return -1;
2405 }
2406 else co=1;
2407 }
2408 else if ((m=parse_addresspart(filter,&addressPart))!=0)
2409 {
2410 if (m==-1) return -1;
2411 if (ap)
2412 {
2413 filter->errmsg=CUS "address part already specified";
2414 return -1;
2415 }
2416 else ap=1;
2417 }
2418 else if ((m=parse_matchtype(filter,&matchType))!=0)
2419 {
2420 if (m==-1) return -1;
2421 if (mt)
2422 {
2423 filter->errmsg=CUS "match type already specified";
2424 return -1;
2425 }
2426 else mt=1;
2427 }
2428 else break;
2429 }
2430 if (parse_white(filter)==-1) return -1;
2431 if ((m=parse_stringlist(filter,&env))!=1)
2432 {
2433 if (m==0) filter->errmsg=CUS "envelope string list expected";
2434 return -1;
2435 }
2436 if (parse_white(filter)==-1) return -1;
2437 if ((m=parse_stringlist(filter,&key))!=1)
2438 {
2439 if (m==0) filter->errmsg=CUS "key string list expected";
2440 return -1;
2441 }
2442 *cond=0;
2443 for (e=env; e->length!=-1 && !*cond; ++e)
2444 {
2445 const uschar *envelopeExpr=CUS 0;
2446 uschar *envelope=US 0;
2447
2448 if (eq_asciicase(e,&str_from,0))
2449 {
2450 switch (addressPart)
2451 {
2452 case ADDRPART_ALL: envelopeExpr=CUS "$sender_address"; break;
2453 #ifdef SUBADDRESS
2454 case ADDRPART_USER:
2455 #endif
2456 case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$sender_address}"; break;
2457 case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$sender_address}"; break;
2458 #ifdef SUBADDRESS
2459 case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2460 #endif
2461 }
2462 }
2463 else if (eq_asciicase(e,&str_to,0))
2464 {
2465 switch (addressPart)
2466 {
2467 case ADDRPART_ALL: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix@$domain"; break;
2468 #ifdef SUBADDRESS
2469 case ADDRPART_USER: envelopeExpr=filter->useraddress; break;
2470 case ADDRPART_DETAIL: envelopeExpr=filter->subaddress; break;
2471 #endif
2472 case ADDRPART_LOCALPART: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix"; break;
2473 case ADDRPART_DOMAIN: envelopeExpr=CUS "$domain"; break;
2474 }
2475 }
2476 #ifdef ENVELOPE_AUTH
2477 else if (eq_asciicase(e,&str_auth,0))
2478 {
2479 switch (addressPart)
2480 {
2481 case ADDRPART_ALL: envelopeExpr=CUS "$authenticated_sender"; break;
2482 #ifdef SUBADDRESS
2483 case ADDRPART_USER:
2484 #endif
2485 case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$authenticated_sender}"; break;
2486 case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$authenticated_sender}"; break;
2487 #ifdef SUBADDRESS
2488 case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
2489 #endif
2490 }
2491 }
2492 #endif
2493 else
2494 {
2495 filter->errmsg=CUS "invalid envelope string";
2496 return -1;
2497 }
2498 if (exec && envelopeExpr)
2499 {
2500 if ((envelope=expand_string(US envelopeExpr)) == NULL)
2501 {
2502 filter->errmsg=CUS "header string expansion failed";
2503 return -1;
2504 }
2505 for (k=key; k->length!=-1; ++k)
2506 {
2507 struct String envelopeStr;
2508
2509 envelopeStr.character=envelope;
2510 envelopeStr.length=Ustrlen(envelope);
2511 *cond=compare(filter,k,&envelopeStr,comparator,matchType);
2512 if (*cond==-1) return -1;
2513 if (*cond) break;
2514 }
2515 }
2516 }
2517 return 1;
2518 }
2519 #ifdef ENOTIFY
2520 else if (parse_identifier(filter,CUS "valid_notify_method"))
2521 {
2522 /*
2523 valid_notify_method = "valid_notify_method"
2524 <notification-uris: string-list>
2525 */
2526
2527 struct String *uris,*u;
2528 int m;
2529
2530 if (!filter->require_enotify)
2531 {
2532 filter->errmsg=CUS "missing previous require \"enotify\";";
2533 return -1;
2534 }
2535 if (parse_white(filter)==-1) return -1;
2536 if ((m=parse_stringlist(filter,&uris))!=1)
2537 {
2538 if (m==0) filter->errmsg=CUS "URI string list expected";
2539 return -1;
2540 }
2541 if (exec)
2542 {
2543 *cond=1;
2544 for (u=uris; u->length!=-1 && *cond; ++u)
2545 {
2546 string_item *recipient;
2547 struct String header,subject,body;
2548
2549 recipient=NULL;
2550 header.length=-1;
2551 header.character=(uschar*)0;
2552 subject.length=-1;
2553 subject.character=(uschar*)0;
2554 body.length=-1;
2555 body.character=(uschar*)0;
2556 if (parse_mailto_uri(filter,u->character,&recipient,&header,&subject,&body)!=1)
2557 *cond=0;
2558 }
2559 }
2560 return 1;
2561 }
2562 else if (parse_identifier(filter,CUS "notify_method_capability"))
2563 {
2564 /*
2565 notify_method_capability = "notify_method_capability" [COMPARATOR] [MATCH-TYPE]
2566 <notification-uri: string>
2567 <notification-capability: string>
2568 <key-list: string-list>
2569 */
2570
2571 int m;
2572 int co=0,mt=0;
2573
2574 enum Comparator comparator=COMP_EN_ASCII_CASEMAP;
2575 enum MatchType matchType=MATCH_IS;
2576 struct String uri,capa,*keys,*k;
2577
2578 if (!filter->require_enotify)
2579 {
2580 filter->errmsg=CUS "missing previous require \"enotify\";";
2581 return -1;
2582 }
2583 for (;;)
2584 {
2585 if (parse_white(filter)==-1) return -1;
2586 if ((m=parse_comparator(filter,&comparator))!=0)
2587 {
2588 if (m==-1) return -1;
2589 if (co)
2590 {
2591 filter->errmsg=CUS "comparator already specified";
2592 return -1;
2593 }
2594 else co=1;
2595 }
2596 else if ((m=parse_matchtype(filter,&matchType))!=0)
2597 {
2598 if (m==-1) return -1;
2599 if (mt)
2600 {
2601 filter->errmsg=CUS "match type already specified";
2602 return -1;
2603 }
2604 else mt=1;
2605 }
2606 else break;
2607 }
2608 if ((m=parse_string(filter,&uri))!=1)
2609 {
2610 if (m==0) filter->errmsg=CUS "missing notification URI string";
2611 return -1;
2612 }
2613 if (parse_white(filter)==-1) return -1;
2614 if ((m=parse_string(filter,&capa))!=1)
2615 {
2616 if (m==0) filter->errmsg=CUS "missing notification capability string";
2617 return -1;
2618 }
2619 if (parse_white(filter)==-1) return -1;
2620 if ((m=parse_stringlist(filter,&keys))!=1)
2621 {
2622 if (m==0) filter->errmsg=CUS "missing key string list";
2623 return -1;
2624 }
2625 if (exec)
2626 {
2627 string_item *recipient;
2628 struct String header,subject,body;
2629
2630 *cond=0;
2631 recipient=NULL;
2632 header.length=-1;
2633 header.character=(uschar*)0;
2634 subject.length=-1;
2635 subject.character=(uschar*)0;
2636 body.length=-1;
2637 body.character=(uschar*)0;
2638 if (parse_mailto_uri(filter,uri.character,&recipient,&header,&subject,&body)==1)
2639 {
2640 if (eq_asciicase(&capa,&str_online,0)==1)
2641 for (k=keys; k->length!=-1; ++k)
2642 {
2643 *cond=compare(filter,k,&str_maybe,comparator,matchType);
2644 if (*cond==-1) return -1;
2645 if (*cond) break;
2646 }
2647 }
2648 }
2649 return 1;
2650 }
2651 #endif
2652 else return 0;
2653 }
2654
2655
2656 /*************************************************
2657 * Parse and interpret an optional block *
2658 *************************************************/
2659
2660 /*
2661 Arguments:
2662 filter points to the Sieve filter including its state
2663 exec Execute parsed statements
2664 generated where to hang newly-generated addresses
2665
2666 Returns: 2 success by stop
2667 1 other success
2668 0 no block command found
2669 -1 syntax or execution error
2670 */
2671
2672 static int parse_block(struct Sieve *filter, int exec,
2673 address_item **generated)
2674 {
2675 int r;
2676
2677 if (parse_white(filter)==-1) return -1;
2678 if (*filter->pc=='{')
2679 {
2680 ++filter->pc;
2681 if ((r=parse_commands(filter,exec,generated))==-1 || r==2) return r;
2682 if (*filter->pc=='}')
2683 {
2684 ++filter->pc;
2685 return 1;
2686 }
2687 else
2688 {
2689 filter->errmsg=CUS "expecting command or closing brace";
2690 return -1;
2691 }
2692 }
2693 else return 0;
2694 }
2695
2696
2697 /*************************************************
2698 * Match a semicolon *
2699 *************************************************/
2700
2701 /*
2702 Arguments:
2703 filter points to the Sieve filter including its state
2704
2705 Returns: 1 success
2706 -1 syntax error
2707 */
2708
2709 static int parse_semicolon(struct Sieve *filter)
2710 {
2711 if (parse_white(filter)==-1) return -1;
2712 if (*filter->pc==';')
2713 {
2714 ++filter->pc;
2715 return 1;
2716 }
2717 else
2718 {
2719 filter->errmsg=CUS "missing semicolon";
2720 return -1;
2721 }
2722 }
2723
2724
2725 /*************************************************
2726 * Parse and interpret a Sieve command *
2727 *************************************************/
2728
2729 /*
2730 Arguments:
2731 filter points to the Sieve filter including its state
2732 exec Execute parsed statements
2733 generated where to hang newly-generated addresses
2734
2735 Returns: 2 success by stop
2736 1 other success
2737 -1 syntax or execution error
2738 */
2739 static int
2740 parse_commands(struct Sieve *filter, int exec, address_item **generated)
2741 {
2742 while (*filter->pc)
2743 {
2744 if (parse_white(filter)==-1) return -1;
2745 if (parse_identifier(filter,CUS "if"))
2746 {
2747 /*
2748 if-command = "if" test block *( "elsif" test block ) [ else block ]
2749 */
2750
2751 int cond,m,unsuccessful;
2752
2753 /* test block */
2754 if (parse_white(filter)==-1) return -1;
2755 if ((m=parse_test(filter,&cond,exec))==-1) return -1;
2756 if (m==0)
2757 {
2758 filter->errmsg=CUS "missing test";
2759 return -1;
2760 }
2761 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2762 (debug_selector & D_filter) != 0)
2763 {
2764 if (exec) debug_printf("if %s\n",cond?"true":"false");
2765 }
2766 m=parse_block(filter,exec ? cond : 0, generated);
2767 if (m==-1 || m==2) return m;
2768 if (m==0)
2769 {
2770 filter->errmsg=CUS "missing block";
2771 return -1;
2772 }
2773 unsuccessful = !cond;
2774 for (;;) /* elsif test block */
2775 {
2776 if (parse_white(filter)==-1) return -1;
2777 if (parse_identifier(filter,CUS "elsif"))
2778 {
2779 if (parse_white(filter)==-1) return -1;
2780 m=parse_test(filter,&cond,exec && unsuccessful);
2781 if (m==-1 || m==2) return m;
2782 if (m==0)
2783 {
2784 filter->errmsg=CUS "missing test";
2785 return -1;
2786 }
2787 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
2788 (debug_selector & D_filter) != 0)
2789 {
2790 if (exec) debug_printf("elsif %s\n",cond?"true":"false");
2791 }
2792 m=parse_block(filter,exec && unsuccessful ? cond : 0, generated);
2793 if (m==-1 || m==2) return m;
2794 if (m==0)
2795 {
2796 filter->errmsg=CUS "missing block";
2797 return -1;
2798 }
2799 if (exec && unsuccessful && cond) unsuccessful = 0;
2800 }
2801 else break;
2802 }
2803 /* else block */
2804 if (parse_white(filter)==-1) return -1;
2805 if (parse_identifier(filter,CUS "else"))
2806 {
2807 m=parse_block(filter,exec && unsuccessful, generated);
2808 if (m==-1 || m==2) return m;
2809 if (m==0)
2810 {
2811 filter->errmsg=CUS "missing block";
2812 return -1;
2813 }
2814 }
2815 }
2816 else if (parse_identifier(filter,CUS "stop"))
2817 {
2818 /*
2819 stop-command = "stop" { stop-options } ";"
2820 stop-options =
2821 */
2822
2823 if (parse_semicolon(filter)==-1) return -1;
2824 if (exec)
2825 {
2826 filter->pc+=Ustrlen(filter->pc);
2827 return 2;
2828 }
2829 }
2830 else if (parse_identifier(filter,CUS "keep"))
2831 {
2832 /*
2833 keep-command = "keep" { keep-options } ";"
2834 keep-options =
2835 */
2836
2837 if (parse_semicolon(filter)==-1) return -1;
2838 if (exec)
2839 {
2840 add_addr(generated,US"inbox",1,0,0,0);
2841 filter->keep = 0;
2842 }
2843 }
2844 else if (parse_identifier(filter,CUS "discard"))
2845 {
2846 /*
2847 discard-command = "discard" { discard-options } ";"
2848 discard-options =
2849 */
2850
2851 if (parse_semicolon(filter)==-1) return -1;
2852 if (exec) filter->keep=0;
2853 }
2854 else if (parse_identifier(filter,CUS "redirect"))
2855 {
2856 /*
2857 redirect-command = "redirect" redirect-options "string" ";"
2858 redirect-options =
2859 redirect-options =) ":copy"
2860 */
2861
2862 struct String recipient;
2863 int m;
2864 int copy=0;
2865
2866 for (;;)
2867 {
2868 if (parse_white(filter)==-1) return -1;
2869 if (parse_identifier(filter,CUS ":copy")==1)
2870 {
2871 if (!filter->require_copy)
2872 {
2873 filter->errmsg=CUS "missing previous require \"copy\";";
2874 return -1;
2875 }
2876 copy=1;
2877 }
2878 else break;
2879 }
2880 if (parse_white(filter)==-1) return -1;
2881 if ((m=parse_string(filter,&recipient))!=1)
2882 {
2883 if (m==0) filter->errmsg=CUS "missing redirect recipient string";
2884 return -1;
2885 }
2886 if (strchr(CCS recipient.character,'@')==(char*)0)
2887 {
2888 filter->errmsg=CUS "unqualified recipient address";
2889 return -1;
2890 }
2891 if (exec)
2892 {
2893 add_addr(generated,recipient.character,0,0,0,0);
2894 if (!copy) filter->keep = 0;
2895 }
2896 if (parse_semicolon(filter)==-1) return -1;
2897 }
2898 else if (parse_identifier(filter,CUS "fileinto"))
2899 {
2900 /*
2901 fileinto-command = "fileinto" { fileinto-options } string ";"
2902 fileinto-options =
2903 fileinto-options =) [ ":copy" ]
2904 */
2905
2906 struct String folder;
2907 uschar *s;
2908 int m;
2909 unsigned long maxage, maxmessages, maxstorage;
2910 int copy=0;
2911
2912 maxage = maxmessages = maxstorage = 0;
2913 if (!filter->require_fileinto)
2914 {
2915 filter->errmsg=CUS "missing previous require \"fileinto\";";
2916 return -1;
2917 }
2918 for (;;)
2919 {
2920 if (parse_white(filter)==-1) return -1;
2921 if (parse_identifier(filter,CUS ":copy")==1)
2922 {
2923 if (!filter->require_copy)
2924 {
2925 filter->errmsg=CUS "missing previous require \"copy\";";
2926 return -1;
2927 }
2928 copy=1;
2929 }
2930 else break;
2931 }
2932 if (parse_white(filter)==-1) return -1;
2933 if ((m=parse_string(filter,&folder))!=1)
2934 {
2935 if (m==0) filter->errmsg=CUS "missing fileinto folder string";
2936 return -1;
2937 }
2938 m=0; s=folder.character;
2939 if (folder.length==0) m=1;
2940 if (Ustrcmp(s,"..")==0 || Ustrncmp(s,"../",3)==0) m=1;
2941 else while (*s)
2942 {
2943 if (Ustrcmp(s,"/..")==0 || Ustrncmp(s,"/../",4)==0) { m=1; break; }
2944 ++s;
2945 }
2946 if (m)
2947 {
2948 filter->errmsg=CUS "invalid folder";
2949 return -1;
2950 }
2951 if (exec)
2952 {
2953 add_addr(generated, folder.character, 1, maxage, maxmessages, maxstorage);
2954 if (!copy) filter->keep = 0;
2955 }
2956 if (parse_semicolon(filter)==-1) return -1;
2957 }
2958 #ifdef ENOTIFY
2959 else if (parse_identifier(filter,CUS "notify"))
2960 {
2961 /*
2962 notify-command = "notify" { notify-options } <method: string> ";"
2963 notify-options = [":from" string]
2964 [":importance" <"1" / "2" / "3">]
2965 [":options" 1*(string-list / number)]
2966 [":message" string]
2967 */
2968
2969 int m;
2970 struct String from;
2971 struct String importance;
2972 struct String message;
2973 struct String method;
2974 struct Notification *already;
2975 string_item *recipient;
2976 struct String header;
2977 struct String subject;
2978 struct String body;
2979 uschar *envelope_from;
2980 struct String auto_submitted_value;
2981 uschar *auto_submitted_def;
2982
2983 if (!filter->require_enotify)
2984 {
2985 filter->errmsg=CUS "missing previous require \"enotify\";";
2986 return -1;
2987 }
2988 from.character=(uschar*)0;
2989 from.length=-1;
2990 importance.character=(uschar*)0;
2991 importance.length=-1;
2992 message.character=(uschar*)0;
2993 message.length=-1;
2994 recipient=NULL;
2995 header.length=-1;
2996 header.character=(uschar*)0;
2997 subject.length=-1;
2998 subject.character=(uschar*)0;
2999 body.length=-1;
3000 body.character=(uschar*)0;
3001 envelope_from=(sender_address && sender_address[0]) ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : US "";
3002 for (;;)
3003 {
3004 if (parse_white(filter)==-1) return -1;
3005 if (parse_identifier(filter,CUS ":from")==1)
3006 {
3007 if (parse_white(filter)==-1) return -1;
3008 if ((m=parse_string(filter,&from))!=1)
3009 {
3010 if (m==0) filter->errmsg=CUS "from string expected";
3011 return -1;
3012 }
3013 }
3014 else if (parse_identifier(filter,CUS ":importance")==1)
3015 {
3016 if (parse_white(filter)==-1) return -1;
3017 if ((m=parse_string(filter,&importance))!=1)
3018 {
3019 if (m==0) filter->errmsg=CUS "importance string expected";
3020 return -1;
3021 }
3022 if (importance.length!=1 || importance.character[0]<'1' || importance.character[0]>'3')
3023 {
3024 filter->errmsg=CUS "invalid importance";
3025 return -1;
3026 }
3027 }
3028 else if (parse_identifier(filter,CUS ":options")==1)
3029 {
3030 if (parse_white(filter)==-1) return -1;
3031 }
3032 else if (parse_identifier(filter,CUS ":message")==1)
3033 {
3034 if (parse_white(filter)==-1) return -1;
3035 if ((m=parse_string(filter,&message))!=1)
3036 {
3037 if (m==0) filter->errmsg=CUS "message string expected";
3038 return -1;
3039 }
3040 }
3041 else break;
3042 }
3043 if (parse_white(filter)==-1) return -1;
3044 if ((m=parse_string(filter,&method))!=1)
3045 {
3046 if (m==0) filter->errmsg=CUS "missing method string";
3047 return -1;
3048 }
3049 if (parse_semicolon(filter)==-1) return -1;
3050 if (parse_mailto_uri(filter,method.character,&recipient,&header,&subject,&body)!=1)
3051 return -1;
3052 if (exec)
3053 {
3054 if (message.length==-1) message=subject;
3055 if (message.length==-1) expand_header(&message,&str_subject);
3056 expand_header(&auto_submitted_value,&str_auto_submitted);
3057 auto_submitted_def=expand_string(string_sprintf("${if def:header_auto-submitted {true}{false}}"));
3058 if (auto_submitted_value.character == NULL || auto_submitted_def == NULL)
3059 {
3060 filter->errmsg=CUS "header string expansion failed";
3061 return -1;
3062 }
3063 if (Ustrcmp(auto_submitted_def,"true")!=0 || Ustrcmp(auto_submitted_value.character,"no")==0)
3064 {
3065 for (already=filter->notified; already; already=already->next)
3066 {
3067 if (already->method.length==method.length
3068 && (method.length==-1 || Ustrcmp(already->method.character,method.character)==0)
3069 && already->importance.length==importance.length
3070 && (importance.length==-1 || Ustrcmp(already->importance.character,importance.character)==0)
3071 && already->message.length==message.length
3072 && (message.length==-1 || Ustrcmp(already->message.character,message.character)==0))
3073 break;
3074 }
3075 if (already==(struct Notification*)0)
3076 /* New notification, process it */
3077 {
3078 struct Notification *sent;
3079 sent=store_get(sizeof(struct Notification));
3080 sent->method=method;
3081 sent->importance=importance;
3082 sent->message=message;
3083 sent->next=filter->notified;
3084 filter->notified=sent;
3085 #ifndef COMPILE_SYNTAX_CHECKER
3086 if (filter_test == FTEST_NONE)
3087 {
3088 string_item *p;
3089 int pid,fd;
3090
3091 if ((pid = child_open_exim2(&fd,envelope_from,envelope_from))>=1)
3092 {
3093 FILE *f;
3094 uschar *buffer;
3095 int buffer_capacity;
3096
3097 f = fdopen(fd, "wb");
3098 fprintf(f,"From: %s\n",from.length==-1 ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : from.character);
3099 for (p=recipient; p; p=p->next) fprintf(f,"To: %s\n",p->text);
3100 fprintf(f,"Auto-Submitted: auto-notified; %s\n",filter->enotify_mailto_owner);
3101 if (header.length>0) fprintf(f,"%s",header.character);
3102 if (message.length==-1)
3103 {
3104 message.character=US"Notification";
3105 message.length=Ustrlen(message.character);
3106 }
3107 /* Allocation is larger than necessary, but enough even for split MIME words */
3108 buffer_capacity=32+4*message.length;
3109 buffer=store_get(buffer_capacity);
3110 if (message.length!=-1) fprintf(f,"Subject: %s\n",parse_quote_2047(message.character, message.length, US"utf-8", buffer, buffer_capacity, TRUE));
3111 fprintf(f,"\n");
3112 if (body.length>0) fprintf(f,"%s\n",body.character);
3113 fflush(f);
3114 (void)fclose(f);
3115 (void)child_close(pid, 0);
3116 }
3117 }
3118 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3119 {
3120 debug_printf("Notification to `%s': '%s'.\n",method.character,message.length!=-1 ? message.character : CUS "");
3121 }
3122 #endif
3123 }
3124 else
3125 {
3126 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3127 {
3128 debug_printf("Repeated notification to `%s' ignored.\n",method.character);
3129 }
3130 }
3131 }
3132 else
3133 {
3134 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3135 {
3136 debug_printf("Ignoring notification, triggering message contains Auto-submitted: field.\n");
3137 }
3138 }
3139 }
3140 }
3141 #endif
3142 #ifdef VACATION
3143 else if (parse_identifier(filter,CUS "vacation"))
3144 {
3145 /*
3146 vacation-command = "vacation" { vacation-options } <reason: string> ";"
3147 vacation-options = [":days" number]
3148 [":subject" string]
3149 [":from" string]
3150 [":addresses" string-list]
3151 [":mime"]
3152 [":handle" string]
3153 */
3154
3155 int m;
3156 unsigned long days;
3157 struct String subject;
3158 struct String from;
3159 struct String *addresses;
3160 int reason_is_mime;
3161 string_item *aliases;
3162 struct String handle;
3163 struct String reason;
3164
3165 if (!filter->require_vacation)
3166 {
3167 filter->errmsg=CUS "missing previous require \"vacation\";";
3168 return -1;
3169 }
3170 if (exec)
3171 {
3172 if (filter->vacation_ran)
3173 {
3174 filter->errmsg=CUS "trying to execute vacation more than once";
3175 return -1;
3176 }
3177 filter->vacation_ran=1;
3178 }
3179 days=VACATION_MIN_DAYS>7 ? VACATION_MIN_DAYS : 7;
3180 subject.character=(uschar*)0;
3181 subject.length=-1;
3182 from.character=(uschar*)0;
3183 from.length=-1;
3184 addresses=(struct String*)0;
3185 aliases=NULL;
3186 reason_is_mime=0;
3187 handle.character=(uschar*)0;
3188 handle.length=-1;
3189 for (;;)
3190 {
3191 if (parse_white(filter)==-1) return -1;
3192 if (parse_identifier(filter,CUS ":days")==1)
3193 {
3194 if (parse_white(filter)==-1) return -1;
3195 if (parse_number(filter,&days)==-1) return -1;
3196 if (days<VACATION_MIN_DAYS) days=VACATION_MIN_DAYS;
3197 else if (days>VACATION_MAX_DAYS) days=VACATION_MAX_DAYS;
3198 }
3199 else if (parse_identifier(filter,CUS ":subject")==1)
3200 {
3201 if (parse_white(filter)==-1) return -1;
3202 if ((m=parse_string(filter,&subject))!=1)
3203 {
3204 if (m==0) filter->errmsg=CUS "subject string expected";
3205 return -1;
3206 }
3207 }
3208 else if (parse_identifier(filter,CUS ":from")==1)
3209 {
3210 if (parse_white(filter)==-1) return -1;
3211 if ((m=parse_string(filter,&from))!=1)
3212 {
3213 if (m==0) filter->errmsg=CUS "from string expected";
3214 return -1;
3215 }
3216 if (check_mail_address(filter,&from)!=1)
3217 return -1;
3218 }
3219 else if (parse_identifier(filter,CUS ":addresses")==1)
3220 {
3221 struct String *a;
3222
3223 if (parse_white(filter)==-1) return -1;
3224 if ((m=parse_stringlist(filter,&addresses))!=1)
3225 {
3226 if (m==0) filter->errmsg=CUS "addresses string list expected";
3227 return -1;
3228 }
3229 for (a=addresses; a->length!=-1; ++a)
3230 {
3231 string_item *new;
3232
3233 new=store_get(sizeof(string_item));
3234 new->text=store_get(a->length+1);
3235 if (a->length) memcpy(new->text,a->character,a->length);
3236 new->text[a->length]='\0';
3237 new->next=aliases;
3238 aliases=new;
3239 }
3240 }
3241 else if (parse_identifier(filter,CUS ":mime")==1)
3242 reason_is_mime=1;
3243 else if (parse_identifier(filter,CUS ":handle")==1)
3244 {
3245 if (parse_white(filter)==-1) return -1;
3246 if ((m=parse_string(filter,&from))!=1)
3247 {
3248 if (m==0) filter->errmsg=CUS "handle string expected";
3249 return -1;
3250 }
3251 }
3252 else break;
3253 }
3254 if (parse_white(filter)==-1) return -1;
3255 if ((m=parse_string(filter,&reason))!=1)
3256 {
3257 if (m==0) filter->errmsg=CUS "missing reason string";
3258 return -1;
3259 }
3260 if (reason_is_mime)
3261 {
3262 uschar *s,*end;
3263
3264 for (s=reason.character,end=reason.character+reason.length; s<end && (*s&0x80)==0; ++s);
3265 if (s<end)
3266 {
3267 filter->errmsg=CUS "MIME reason string contains 8bit text";
3268 return -1;
3269 }
3270 }
3271 if (parse_semicolon(filter)==-1) return -1;
3272
3273 if (exec)
3274 {
3275 address_item *addr;
3276 int capacity,start;
3277 uschar *buffer;
3278 int buffer_capacity;
3279 struct String key;
3280 md5 base;
3281 uschar digest[16];
3282 uschar hexdigest[33];
3283 int i;
3284 uschar *once;
3285
3286 if (filter_personal(aliases,TRUE))
3287 {
3288 if (filter_test == FTEST_NONE)
3289 {
3290 /* ensure oncelog directory exists; failure will be detected later */
3291
3292 (void)directory_make(NULL, filter->vacation_directory, 0700, FALSE);
3293 }
3294 /* build oncelog filename */
3295
3296 key.character=(uschar*)0;
3297 key.length=0;
3298 capacity=0;
3299 if (handle.length==-1)
3300 {
3301 if (subject.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,subject.character,subject.length);
3302 if (from.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,from.character,from.length);
3303 key.character=string_catn(key.character,&capacity,&key.length,reason_is_mime?US"1":US"0",1);
3304 key.character=string_catn(key.character,&capacity,&key.length,reason.character,reason.length);
3305 }
3306 else
3307 key=handle;
3308 md5_start(&base);
3309 md5_end(&base, key.character, key.length, digest);
3310 for (i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]);
3311 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3312 {
3313 debug_printf("Sieve: mail was personal, vacation file basename: %s\n", hexdigest);
3314 }
3315 if (filter_test == FTEST_NONE)
3316 {
3317 capacity=Ustrlen(filter->vacation_directory);
3318 start=capacity;
3319 once=string_catn(filter->vacation_directory,&capacity,&start,US"/",1);
3320 once=string_catn(once,&capacity,&start,hexdigest,33);
3321 once[start] = '\0';
3322
3323 /* process subject */
3324
3325 if (subject.length==-1)
3326 {
3327 uschar *subject_def;
3328
3329 subject_def=expand_string(US"${if def:header_subject {true}{false}}");
3330 if (Ustrcmp(subject_def,"true")==0)
3331 {
3332 expand_header(&subject,&str_subject);
3333 capacity=6;
3334 start=6;
3335 subject.character=string_catn(US"Auto: ",&capacity,&start,subject.character,subject.length);
3336 subject.length=start;
3337 }
3338 else
3339 {
3340 subject.character=US"Automated reply";
3341 subject.length=Ustrlen(subject.character);
3342 }
3343 }
3344
3345 /* add address to list of generated addresses */
3346
3347 addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
3348 setflag(addr, af_pfr);
3349 setflag(addr, af_ignore_error);
3350 addr->next = *generated;
3351 *generated = addr;
3352 addr->reply = store_get(sizeof(reply_item));
3353 memset(addr->reply,0,sizeof(reply_item)); /* XXX */
3354 addr->reply->to = string_copy(sender_address);
3355 if (from.length==-1)
3356 addr->reply->from = expand_string(US"$local_part@$domain");
3357 else
3358 addr->reply->from = from.character;
3359 /* Allocation is larger than necessary, but enough even for split MIME words */
3360 buffer_capacity=32+4*subject.length;
3361 buffer=store_get(buffer_capacity);
3362 /* deconst cast safe as we pass in a non-const item */
3363 addr->reply->subject = US parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE);
3364 addr->reply->oncelog=once;
3365 addr->reply->once_repeat=days*86400;
3366
3367 /* build body and MIME headers */
3368
3369 if (reason_is_mime)
3370 {
3371 uschar *mime_body,*reason_end;
3372 static const uschar nlnl[]="\r\n\r\n";
3373
3374 for
3375 (
3376 mime_body=reason.character,reason_end=reason.character+reason.length;
3377 mime_body<(reason_end-(sizeof(nlnl)-1)) && memcmp(mime_body,nlnl,(sizeof(nlnl)-1));
3378 ++mime_body
3379 );
3380 capacity = 0;
3381 start = 0;
3382 addr->reply->headers = string_catn(NULL,&capacity,&start,reason.character,mime_body-reason.character);
3383 addr->reply->headers[start] = '\0';
3384 capacity = 0;
3385 start = 0;
3386 if (mime_body+(sizeof(nlnl)-1)<reason_end) mime_body+=(sizeof(nlnl)-1);
3387 else mime_body=reason_end-1;
3388 addr->reply->text = string_catn(NULL,&capacity,&start,mime_body,reason_end-mime_body);
3389 addr->reply->text[start] = '\0';
3390 }
3391 else
3392 {
3393 struct String qp = { NULL, 0 }; /* Keep compiler happy (PH) */
3394
3395 capacity = 0;
3396 start = reason.length;
3397 addr->reply->headers = US"MIME-Version: 1.0\n"
3398 "Content-Type: text/plain;\n"
3399 "\tcharset=\"utf-8\"\n"
3400 "Content-Transfer-Encoding: quoted-printable";
3401 addr->reply->text = quoted_printable_encode(&reason,&qp)->character;
3402 }
3403 }
3404 }
3405 else if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
3406 {
3407 debug_printf("Sieve: mail was not personal, vacation would ignore it\n");
3408 }
3409 }
3410 }
3411 else break;
3412 #endif
3413 }
3414 return 1;
3415 }
3416
3417
3418 /*************************************************
3419 * Parse and interpret a sieve filter *
3420 *************************************************/
3421
3422 /*
3423 Arguments:
3424 filter points to the Sieve filter including its state
3425 exec Execute parsed statements
3426 generated where to hang newly-generated addresses
3427
3428 Returns: 1 success
3429 -1 syntax or execution error
3430 */
3431
3432 static int
3433 parse_start(struct Sieve *filter, int exec, address_item **generated)
3434 {
3435 filter->pc=filter->filter;
3436 filter->line=1;
3437 filter->keep=1;
3438 filter->require_envelope=0;
3439 filter->require_fileinto=0;
3440 #ifdef ENCODED_CHARACTER
3441 filter->require_encoded_character=0;
3442 #endif
3443 #ifdef ENVELOPE_AUTH
3444 filter->require_envelope_auth=0;
3445 #endif
3446 #ifdef ENOTIFY
3447 filter->require_enotify=0;
3448 filter->notified=(struct Notification*)0;
3449 #endif
3450 #ifdef SUBADDRESS
3451 filter->require_subaddress=0;
3452 #endif
3453 #ifdef VACATION
3454 filter->require_vacation=0;
3455 filter->vacation_ran=0;
3456 #endif
3457 filter->require_copy=0;
3458 filter->require_iascii_numeric=0;
3459
3460 if (parse_white(filter)==-1) return -1;
3461
3462 if (exec && filter->vacation_directory != NULL && filter_test == FTEST_NONE)
3463 {
3464 DIR *oncelogdir;
3465 struct dirent *oncelog;
3466 struct stat properties;
3467 time_t now;
3468
3469 /* clean up old vacation log databases */
3470
3471 oncelogdir=opendir(CS filter->vacation_directory);
3472
3473 if (oncelogdir ==(DIR*)0 && errno != ENOENT)
3474 {
3475 filter->errmsg=CUS "unable to open vacation directory";
3476 return -1;
3477 }
3478
3479 if (oncelogdir != NULL)
3480 {
3481 time(&now);
3482
3483 while ((oncelog=readdir(oncelogdir))!=(struct dirent*)0)
3484 {
3485 if (strlen(oncelog->d_name)==32)
3486 {
3487 uschar *s=string_sprintf("%s/%s",filter->vacation_directory,oncelog->d_name);
3488 if (Ustat(s,&properties)==0 && (properties.st_mtime+VACATION_MAX_DAYS*86400)<now)
3489 Uunlink(s);
3490 }
3491 }
3492 closedir(oncelogdir);
3493 }
3494 }
3495
3496 while (parse_identifier(filter,CUS "require"))
3497 {
3498 /*
3499 require-command = "require" <capabilities: string-list>
3500 */
3501
3502 struct String *cap,*check;
3503 int m;
3504
3505 if (parse_white(filter)==-1) return -1;
3506 if ((m=parse_stringlist(filter,&cap))!=1)
3507 {
3508 if (m==0) filter->errmsg=CUS "capability string list expected";
3509 return -1;
3510 }
3511 for (check=cap; check->character; ++check)
3512 {
3513 if (eq_octet(check,&str_envelope,0)) filter->require_envelope=1;
3514 else if (eq_octet(check,&str_fileinto,0)) filter->require_fileinto=1;
3515 #ifdef ENCODED_CHARACTER
3516 else if (eq_octet(check,&str_encoded_character,0)) filter->require_encoded_character=1;
3517 #endif
3518 #ifdef ENVELOPE_AUTH
3519 else if (eq_octet(check,&str_envelope_auth,0)) filter->require_envelope_auth=1;
3520 #endif
3521 #ifdef ENOTIFY
3522 else if (eq_octet(check,&str_enotify,0))
3523 {
3524 if (filter->enotify_mailto_owner == NULL)
3525 {
3526 filter->errmsg=CUS "enotify disabled";
3527 return -1;
3528 }
3529 filter->require_enotify=1;
3530 }
3531 #endif
3532 #ifdef SUBADDRESS
3533 else if (eq_octet(check,&str_subaddress,0)) filter->require_subaddress=1;
3534 #endif
3535 #ifdef VACATION
3536 else if (eq_octet(check,&str_vacation,0))
3537 {
3538 if (filter_test == FTEST_NONE && filter->vacation_directory == NULL)
3539 {
3540 filter->errmsg=CUS "vacation disabled";
3541 return -1;
3542 }
3543 filter->require_vacation=1;
3544 }
3545 #endif
3546 else if (eq_octet(check,&str_copy,0)) filter->require_copy=1;
3547 else if (eq_octet(check,&str_comparator_ioctet,0)) ;
3548 else if (eq_octet(check,&str_comparator_iascii_casemap,0)) ;
3549 else if (eq_octet(check,&str_comparator_enascii_casemap,0)) ;
3550 else if (eq_octet(check,&str_comparator_iascii_numeric,0)) filter->require_iascii_numeric=1;
3551 else
3552 {
3553 filter->errmsg=CUS "unknown capability";
3554 return -1;
3555 }
3556 }
3557 if (parse_semicolon(filter)==-1) return -1;
3558 }
3559 if (parse_commands(filter,exec,generated)==-1) return -1;
3560 if (*filter->pc)
3561 {
3562 filter->errmsg=CUS "syntax error";
3563 return -1;
3564 }
3565 return 1;
3566 }
3567
3568
3569 /*************************************************
3570 * Interpret a sieve filter file *
3571 *************************************************/
3572
3573 /*
3574 Arguments:
3575 filter points to the entire file, read into store as a single string
3576 options controls whether various special things are allowed, and requests
3577 special actions (not currently used)
3578 vacation_directory where to store vacation "once" files
3579 enotify_mailto_owner owner of mailto notifications
3580 useraddress string expression for :user part of address
3581 subaddress string expression for :subaddress part of address
3582 generated where to hang newly-generated addresses
3583 error where to pass back an error text
3584
3585 Returns: FF_DELIVERED success, a significant action was taken
3586 FF_NOTDELIVERED success, no significant action
3587 FF_DEFER defer requested
3588 FF_FAIL fail requested
3589 FF_FREEZE freeze requested
3590 FF_ERROR there was a problem
3591 */
3592
3593 int
3594 sieve_interpret(uschar *filter, int options, uschar *vacation_directory,
3595 uschar *enotify_mailto_owner, uschar *useraddress, uschar *subaddress,
3596 address_item **generated, uschar **error)
3597 {
3598 struct Sieve sieve;
3599 int r;
3600 uschar *msg;
3601
3602 options = options; /* Keep picky compilers happy */
3603 error = error;
3604
3605 DEBUG(D_route) debug_printf("Sieve: start of processing\n");
3606 sieve.filter=filter;
3607
3608 if (vacation_directory == NULL)
3609 sieve.vacation_directory = NULL;
3610 else
3611 {
3612 sieve.vacation_directory=expand_string(vacation_directory);
3613 if (sieve.vacation_directory == NULL)
3614 {
3615 *error = string_sprintf("failed to expand \"%s\" "
3616 "(sieve_vacation_directory): %s", vacation_directory,
3617 expand_string_message);
3618 return FF_ERROR;
3619 }
3620 }
3621
3622 if (enotify_mailto_owner == NULL)
3623 sieve.enotify_mailto_owner = NULL;
3624 else
3625 {
3626 sieve.enotify_mailto_owner=expand_string(enotify_mailto_owner);
3627 if (sieve.enotify_mailto_owner == NULL)
3628 {
3629 *error = string_sprintf("failed to expand \"%s\" "
3630 "(sieve_enotify_mailto_owner): %s", enotify_mailto_owner,
3631 expand_string_message);
3632 return FF_ERROR;
3633 }
3634 }
3635
3636 sieve.useraddress = useraddress == NULL ? CUS "$local_part_prefix$local_part$local_part_suffix" : useraddress;
3637 sieve.subaddress = subaddress;
3638
3639 #ifdef COMPILE_SYNTAX_CHECKER
3640 if (parse_start(&sieve,0,generated)==1)
3641 #else
3642 if (parse_start(&sieve,1,generated)==1)
3643 #endif
3644 {
3645 if (sieve.keep)
3646 {
3647 add_addr(generated,US"inbox",1,0,0,0);
3648 msg = string_sprintf("Implicit keep");
3649 r = FF_DELIVERED;
3650 }
3651 else
3652 {
3653 msg = string_sprintf("No implicit keep");
3654 r = FF_DELIVERED;
3655 }
3656 }
3657 else
3658 {
3659 msg = string_sprintf("Sieve error: %s in line %d",sieve.errmsg,sieve.line);
3660 #ifdef COMPILE_SYNTAX_CHECKER
3661 r = FF_ERROR;
3662 *error = msg;
3663 #else
3664 add_addr(generated,US"inbox",1,0,0,0);
3665 r = FF_DELIVERED;
3666 #endif
3667 }
3668
3669 #ifndef COMPILE_SYNTAX_CHECKER
3670 if (filter_test != FTEST_NONE) printf("%s\n", (const char*) msg);
3671 else debug_printf("%s\n", msg);
3672 #endif
3673
3674 DEBUG(D_route) debug_printf("Sieve: end of processing\n");
3675 return r;
3676 }