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