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