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