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