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