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