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