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