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