1 /*
2 ** Copyright 2000-2010 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5
6 #include "config.h"
7 #include "maildirfilter.h"
8 #include "maildirfiltertypelist.h"
9 #include "maildirgetquota.h"
10 #include "mailbot.h"
11
12 #include "autoresponse.h"
13 #include "numlib/numlib.h"
14 #include <courier-unicode.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <sys/types.h>
21 #include "maildirmisc.h"
22
23 #if HAVE_SYSEXITS_H
24 #include <sysexits.h>
25 #else
26 #define EX_SOFTWARE 70
27 #endif
28
29 #if HAVE_PCRE_H
30 #include <pcre.h>
31 #else
32 #if HAVE_PCRE_PCRE_H
33 #include <pcre/pcre.h>
34 #define HAVE_PCRE_H 1
35 #endif
36 #endif
37
38 #if HAVE_SYS_STAT_H
39 #include <sys/stat.h>
40 #endif
41 #if HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44
45
maildir_filter_appendrule(struct maildirfilter * r,const char * name,enum maildirfiltertype type,int flags,const char * header,const char * value,const char * folder,const char * fromhdr,const char * charset,int * errcode)46 struct maildirfilterrule *maildir_filter_appendrule(struct maildirfilter *r,
47 const char *name,
48 enum maildirfiltertype type,
49 int flags,
50 const char *header,
51 const char *value,
52 const char *folder,
53 const char *fromhdr,
54 const char *charset,
55 int *errcode)
56 {
57 struct maildirfilterrule *p=malloc(sizeof(struct maildirfilterrule));
58
59 *errcode=MF_ERR_INTERNAL;
60
61 if (!p) return (0);
62 memset(p, 0, sizeof(*p));
63
64 if ((p->prev=r->last) != 0)
65 p->prev->next=p;
66 else
67 r->first=p;
68 r->last=p;
69
70 if (maildir_filter_ruleupdate(r, p, name, type, flags,
71 header, value, folder, fromhdr, charset,
72 errcode))
73 {
74 maildir_filter_ruledel(r, p);
75 return (0);
76 }
77 return (p);
78 }
79
80 static int maildir_filter_ruleupdate_utf8(struct maildirfilter *r,
81 struct maildirfilterrule *p,
82 const char *name,
83 enum maildirfiltertype type,
84 int flags,
85 const char *header,
86 const char *value,
87 const char *folder,
88 const char *fromhdr,
89 int *errcode);
90
maildir_filter_ruleupdate(struct maildirfilter * r,struct maildirfilterrule * p,const char * name,enum maildirfiltertype type,int flags,const char * header,const char * value,const char * folder,const char * fromhdr,const char * charset,int * errcode)91 int maildir_filter_ruleupdate(struct maildirfilter *r,
92 struct maildirfilterrule *p,
93 const char *name,
94 enum maildirfiltertype type,
95 int flags,
96 const char *header,
97 const char *value,
98 const char *folder,
99 const char *fromhdr,
100 const char *charset,
101 int *errcode)
102 {
103 char *name_utf8;
104 char *header_utf8;
105 char *value_utf8;
106 int rc;
107
108 name_utf8=unicode_convert_toutf8(name ? name:"", charset, NULL);
109
110 if (!name_utf8)
111 {
112 *errcode=MF_ERR_BADRULENAME;
113 return -1;
114 }
115
116 header_utf8=unicode_convert_toutf8(header ? header:"", charset, NULL);
117
118 if (!header_utf8)
119 {
120 free(name_utf8);
121 *errcode=MF_ERR_BADRULEHEADER;
122 return -1;
123 }
124
125 value_utf8=unicode_convert_toutf8(value ? value:"", charset, NULL);
126
127 if (!value_utf8)
128 {
129 free(name_utf8);
130 free(header_utf8);
131 *errcode=MF_ERR_BADRULEVALUE;
132 return -1;
133 }
134 rc=maildir_filter_ruleupdate_utf8(r, p, name_utf8, type, flags,
135 header_utf8,
136 value_utf8,
137 folder,
138 fromhdr,
139 errcode);
140 free(name_utf8);
141 free(value_utf8);
142 free(header_utf8);
143 return rc;
144 }
145
maildir_filter_ruleupdate_utf8(struct maildirfilter * r,struct maildirfilterrule * p,const char * name,enum maildirfiltertype type,int flags,const char * header,const char * value,const char * folder,const char * fromhdr,int * errcode)146 static int maildir_filter_ruleupdate_utf8(struct maildirfilter *r,
147 struct maildirfilterrule *p,
148 const char *name,
149 enum maildirfiltertype type,
150 int flags,
151 const char *header,
152 const char *value,
153 const char *folder,
154 const char *fromhdr,
155 int *errcode)
156 {
157 const char *c;
158 struct maildirfilterrule *pom;
159
160 /*
161 ** Before creating a new rule, validate all input.
162 */
163
164 *errcode=0;
165
166 /* rule name: may not contain quotes or control characters. */
167 *errcode=MF_ERR_BADRULENAME;
168 if (!*name || strlen(name) > 200)
169 return (-1);
170
171 for (c=name; *c; c++)
172 if ((unsigned char)*c < ' ' || *c == '\'' || *c == '"' ||
173 *c == '`')
174 return (-1);
175
176 /* rule name: may not already exist */
177 *errcode=MF_ERR_EXISTS;
178
179 for (pom=r->first; pom->next; pom=pom->next) {
180 if (p!=pom && !strcmp(name, pom->rulename_utf8))
181 return (-1);
182 }
183
184 /* rule type: we must know what it is */
185
186 switch (type) {
187 case startswith:
188 case endswith:
189 case contains:
190 case hasrecipient:
191 case mimemultipart:
192 case textplain:
193 case islargerthan:
194 case anymessage:
195 break;
196 default:
197 *errcode=MF_ERR_BADRULETYPE;
198 break;
199 } ;
200
201 /* header: */
202
203 *errcode=MF_ERR_BADRULEHEADER;
204
205 c=header;
206 if (strlen(c) > 200) return (-1);
207 if (*c == 0)
208 {
209 switch (type) {
210 case hasrecipient:
211 case islargerthan:
212 case mimemultipart:
213 case textplain:
214 case anymessage:
215 break;
216 case contains:
217 case startswith:
218 case endswith:
219 if (flags & MFR_BODY)
220 break;
221 /* FALLTHRU */
222 default:
223 /* required */
224
225 return (-1);
226 }
227 }
228 else for ( ; *c; c++)
229 {
230 /* no control characters */
231 if ((unsigned char)*c <= ' ' || *c == MDIRSEP[0] ||
232 *c == '\'' ||
233 *c == '\\' || *c == '"' || *c == '`' || *c == '/')
234 return (-1);
235 }
236
237 /* rule pattern */
238
239 *errcode=MF_ERR_BADRULEVALUE;
240
241 c=value;
242 if (strlen(c) > 200) return (-1);
243 if (*c == 0)
244 {
245 switch (type) {
246 case mimemultipart:
247 case textplain:
248 case anymessage:
249 break;
250 default:
251 /* required */
252
253 return (-1);
254 }
255 }
256 else if (!(flags & MFR_PLAINSTRING))
257 {
258 /*
259 ** Let PCRE decide if this is a valid pattern.
260 **
261 ** One exception: the forward slash character, and some other
262 ** special characters, must always be escaped.
263 */
264
265 while (*c)
266 {
267 if (*c == '/' || *c == '$' || *c == '!'
268 || *c == '`' || (int)(unsigned char)*c < ' '
269 || *c == '\'' || *c == '"') return (-1);
270 /* must be escaped */
271
272 if (type == islargerthan)
273 {
274 if (!isdigit((int)(unsigned char)*c))
275 return (-1);
276 }
277
278 if (*c == '(')
279 {
280 if (type == hasrecipient) return (-1);
281 ++c;
282 if (*c == ')') return (-1);
283 continue;
284 }
285 if (*c == ')')
286 {
287 if (type == hasrecipient) return (-1);
288 ++c;
289 continue;
290 }
291 if (*c == '[') /* This is a set */
292 {
293 if (type == hasrecipient) return (-1);
294 ++c;
295 for (;;)
296 {
297 if (*c == '\'' || *c == '"' ||
298 *c == '`')
299 return (-1); /* must be quoted*/
300 if (*c == '\\')
301 ++c;
302 if (!*c) return (-1);
303 if ((int)(unsigned char)*c < ' ')
304 return (-1);
305 ++c;
306 if (*c == ']') break;
307 if (*c != '-') continue;
308 ++c;
309
310 if (*c == '\'' || *c == '"' ||
311 *c == '`')
312 return (-1); /* must be quoted*/
313 if (*c == '\\')
314 ++c;
315 if ((int)(unsigned char)*c < ' ')
316 return (-1);
317 if (!*c) return (-1);
318 ++c;
319 if (*c == ']') break;
320 }
321 ++c;
322 continue;
323 }
324
325 if (*c == '\\')
326 {
327 if (type == hasrecipient) return (-1);
328 ++c;
329 }
330 if (!*c) return (-1);
331 ++c;
332 }
333
334 #if HAVE_PCRE_H
335 switch (type) {
336 case contains:
337 case startswith:
338 case endswith:
339 {
340 const char *errptr;
341 int errindex;
342
343 pcre *p=pcre_compile(value, PCRE_UTF8,
344 &errptr,
345 &errindex,
346 0);
347
348
349 if (p == NULL)
350 return -1;
351 pcre_free(p);
352 }
353 break;
354 default:
355 break;
356 }
357 #endif
358 }
359
360 /* validate FROM header */
361
362 *errcode=MF_ERR_BADFROMHDR;
363
364 while (fromhdr && *fromhdr && isspace((int)(unsigned char)*fromhdr))
365 ++fromhdr;
366
367 for (c=fromhdr; *c; c++)
368 if ((int)(unsigned char)*c < ' ')
369 return (-1);
370
371 *errcode=MF_ERR_BADRULEFOLDER;
372
373 /* validate name of destination folder */
374
375 c=folder;
376 if (!c) return (-1);
377 if (strlen(c) > 200) return (-1);
378
379 if (*c == '*' || *c == '!')
380 {
381 /* Forward, or bounce with an error */
382
383 ++c;
384 for ( ; *c; c++)
385 {
386 if (strchr("'\"$\\`;(){}#&<>~", *c) ||
387 (unsigned char)*c < ' ')
388 return (-1);
389 }
390 }
391 else if (*c == '+') /* Autorespond */
392 {
393 struct maildir_filter_autoresp_info ai;
394
395 if (maildir_filter_autoresp_info_init_str(&ai, c+1))
396 return (-1);
397
398 maildir_filter_autoresp_info_free(&ai);
399 }
400 else if (strcmp(c, "exit") == 0) /* Purge */
401 {
402 }
403 else
404 {
405 char *s;
406
407 if (strcmp(c, INBOX) &&
408 strncmp(c, INBOX ".", sizeof(INBOX)))
409 return -1;
410
411 s=maildir_name2dir(".", c);
412
413 if (!s)
414 return -1;
415 free(s);
416 }
417
418 /* OK, we're good */
419
420 *errcode=MF_ERR_INTERNAL;
421
422 if (p->rulename_utf8) free(p->rulename_utf8);
423 if ((p->rulename_utf8=strdup(name)) == 0) return (-1);
424 p->type=type;
425 if (p->fieldname_utf8) free(p->fieldname_utf8);
426 if ((p->fieldname_utf8=strdup(header ? header:"")) == 0) return (-1);
427 if (p->fieldvalue_utf8) free(p->fieldvalue_utf8);
428 if ((p->fieldvalue_utf8=strdup(value ? value:"")) == 0) return (-1);
429 if (p->tofolder) free(p->tofolder);
430 if ((p->tofolder=malloc(strlen(folder)+1)) == 0) return (-1);
431 strcpy(p->tofolder, folder);
432
433 if (p->fromhdr) free(p->fromhdr);
434 if ((p->fromhdr=strdup(fromhdr ? fromhdr:"")) == NULL)
435 return (-1);
436
437 p->flags=flags;
438 return (0);
439 }
440
maildir_filter_ruledel(struct maildirfilter * r,struct maildirfilterrule * p)441 void maildir_filter_ruledel(struct maildirfilter *r, struct maildirfilterrule *p)
442 {
443 if (p->prev) p->prev->next=p->next;
444 else r->first=p->next;
445
446 if (p->next) p->next->prev=p->prev;
447 else r->last=p->prev;
448
449 if (p->rulename_utf8) free(p->rulename_utf8);
450 if (p->fieldname_utf8) free(p->fieldname_utf8);
451 if (p->fieldvalue_utf8) free(p->fieldvalue_utf8);
452 if (p->tofolder) free(p->tofolder);
453 if (p->fromhdr) free(p->fromhdr);
454 free(p);
455 }
456
maildir_filter_ruleup(struct maildirfilter * r,struct maildirfilterrule * p)457 void maildir_filter_ruleup(struct maildirfilter *r, struct maildirfilterrule *p)
458 {
459 struct maildirfilterrule *q;
460
461 q=p->prev;
462 if (!q) return;
463 q->next=p->next;
464 if (p->next) p->next->prev=q;
465 else r->last=q;
466
467 if ((p->prev=q->prev) != 0) p->prev->next=p;
468 else r->first=p;
469
470 p->next=q;
471 q->prev=p;
472 }
473
maildir_filter_ruledown(struct maildirfilter * r,struct maildirfilterrule * p)474 void maildir_filter_ruledown(struct maildirfilter *r, struct maildirfilterrule *p)
475 {
476 struct maildirfilterrule *q;
477
478 q=p->next;
479 if (!q) return;
480 q->prev=p->prev;
481 if (q->prev) q->prev->next=q;
482 else r->first=q;
483
484 if ((p->next=q->next) != 0) p->next->prev=p;
485 else r->last=p;
486
487 p->prev=q;
488 q->next=p;
489 }
490
print_pattern(FILE * f,int flags,const char * v)491 static void print_pattern(FILE *f, int flags, const char *v)
492 {
493 if (!(flags & MFR_PLAINSTRING))
494 {
495 fprintf(f, "%s%s",
496 *v && isspace((int)(unsigned char)*v) ? "\\":"", v);
497 return;
498 }
499
500 while (*v)
501 {
502 if (((int)(unsigned char)*v) <= 0x80 &&
503 !isalnum((int)(unsigned char)*v))
504 putc('\\', f);
505 putc((int)(unsigned char)*v, f);
506 ++v;
507 }
508 }
509
maildir_filter_saverules(struct maildirfilter * r,const char * filename,const char * maildirpath,const char * fromaddr)510 int maildir_filter_saverules(struct maildirfilter *r, const char *filename,
511 const char *maildirpath, const char *fromaddr)
512 {
513 FILE *f=fopen(filename, "w");
514 struct maildirfilterrule *p;
515
516 if (!f) return (-1);
517
518 fprintf(f, "#MFMAILDROP=2\n"
519 "#\n"
520 "# DO NOT EDIT THIS FILE. This is an automatically"
521 " generated filter.\n"
522 "\n");
523
524 for (fprintf(f, "FROM='"); *fromaddr; fromaddr++)
525 {
526 if (*fromaddr == '\'' || *fromaddr == '\\')
527 putc('\\', f);
528 putc(*fromaddr, f);
529 }
530 fprintf(f, "\'\n");
531
532 for (p=r->first; p; p=p->next)
533 {
534 const char *fieldname=p->fieldname_utf8 ? p->fieldname_utf8:"";
535 const char *fieldvalue=p->fieldvalue_utf8 ? p->fieldvalue_utf8:"";
536 const char *tofolder=p->tofolder ? p->tofolder:"";
537
538 fprintf(f, "##Op:%s\n",
539 typelist[p->type].name);
540 fprintf(f, "##Header:%s\n", fieldname);
541 fprintf(f, "##Value:%s\n", fieldvalue);
542 fprintf(f, "##Folder:%s\n",
543 strcmp(tofolder, INBOX) == 0 ? ".":
544 strncmp(tofolder, INBOX ".", sizeof(INBOX)) == 0
545 ? strchr(tofolder, '.'):tofolder);
546 fprintf(f, "##From:%s\n", p->fromhdr ? p->fromhdr:"");
547
548 if (p->flags & MFR_PLAINSTRING)
549 fprintf(f, "##PlainString\n");
550 if (p->flags & MFR_DOESNOT)
551 fprintf(f, "##DoesNot\n");
552 if (p->flags & MFR_BODY)
553 fprintf(f, "##Body\n");
554 if (p->flags & MFR_CONTINUE)
555 fprintf(f, "##Continue\n");
556
557 fprintf(f, "##Name:%s\n\n", p->rulename_utf8 ? p->rulename_utf8:"");
558
559 fprintf(f, "\nif (");
560
561 if (p->flags & MFR_DOESNOT)
562 fprintf(f, "!");
563 fprintf(f, "(");
564
565 switch (p->type) {
566 case startswith:
567 if (p->flags & MFR_BODY)
568 {
569 fprintf(f, "/^");
570 print_pattern(f, p->flags, fieldvalue);
571 fprintf(f, "/:b");
572 }
573 else
574 {
575 fprintf(f, "/^%s: *", fieldname);
576 print_pattern(f, p->flags, fieldvalue);
577 fprintf(f, "/");
578 }
579 break;
580 case endswith:
581 if (p->flags & MFR_BODY)
582 {
583 fprintf(f, "/");
584 print_pattern(f, p->flags, fieldvalue);
585 fprintf(f, "$/:b");
586 }
587 else
588 {
589 fprintf(f, "/^%s:.*", fieldname);
590 print_pattern(f, p->flags, fieldvalue);
591 fprintf(f, "$/");
592 }
593 break;
594 case contains:
595 if (p->flags & MFR_BODY)
596 {
597 fprintf(f, "/");
598 print_pattern(f, p->flags, fieldvalue);
599 fprintf(f, "/:b");
600 }
601 else
602 {
603 fprintf(f, "/^%s:.*", fieldname);
604 print_pattern(f, p->flags, fieldvalue);
605 fprintf(f, "/");
606 }
607 break;
608 case hasrecipient:
609 fprintf(f, "hasaddr(\"%s\")", fieldvalue);
610 break;
611 case mimemultipart:
612 fprintf(f, "/^Content-Type: *multipart\\/mixed/");
613 break;
614 case textplain:
615 fprintf(f, " (! /^Content-Type:/) || "
616 "/^Content-Type: text\\/plain$/ || "
617 "/^Content-Type: text\\/plain;/");
618 break;
619 case islargerthan:
620 fprintf(f, "$SIZE > %s", fieldvalue);
621 break;
622 case anymessage:
623 fprintf(f, "1");
624 break;
625 }
626 fprintf(f, "))\n"
627 "{\n");
628
629 if (*tofolder == '!')
630 {
631 fprintf(f, " %s \"| $SENDMAIL -f \" '\"\"' \" %s\"\n",
632 p->flags & MFR_CONTINUE ? "cc":"to",
633 tofolder+1);
634 }
635 else if (*tofolder == '*')
636 {
637 fprintf(f, " echo \"%s\"\n"
638 " EXITCODE=%d\n"
639 " exit\n", tofolder+1, EX_SOFTWARE);
640 }
641 else if (*tofolder == '+')
642 {
643 struct maildir_filter_autoresp_info ai;
644
645 if (maildir_filter_autoresp_info_init_str(&ai, tofolder+1) == 0)
646 {
647 if (p->fromhdr && p->fromhdr[0])
648 {
649 const char *cp;
650
651 fprintf(f, " AUTOREPLYFROM='");
652
653
654 for (cp=p->fromhdr; *cp; ++cp)
655 {
656 if (*cp == '\'' || *cp == '\\')
657 putc('\\', f);
658 putc(*cp, f);
659 }
660 fprintf(f, "'\n");
661 }
662 else
663 fprintf(f, " AUTOREPLYFROM=\"$FROM\"\n"
664 );
665
666 fprintf(f, " `%s -A \"X-Sender: $FROM\""
667 " -A \"From: $AUTOREPLYFROM\"",
668 MAILBOT);
669 if (ai.dsnflag)
670 fprintf(f, " -M \"$FROM\"");
671 fprintf(f, " -m \"%s/autoresponses/%s\"",
672 maildirpath, ai.name);
673 if (ai.noquote)
674 fprintf(f, " -N");
675 if (ai.days > 0)
676 fprintf(f,
677 " -d \"%s/autoresponses/"
678 "%s.dat\" -D %u",
679 maildirpath, ai.name, ai.days);
680 fprintf(f, " $SENDMAIL -t -f \"\"`\n");
681 maildir_filter_autoresp_info_free(&ai);
682 }
683 }
684 else if (strcmp(tofolder, "exit") == 0)
685 {
686 fprintf(f, " exit\n");
687 }
688 else
689 {
690 char *s;
691
692 s=maildir_name2dir(maildirpath, tofolder);
693
694 if (!s)
695 fprintf(f, " # INTERNAL ERROR in maildir_name2dir\n");
696 else
697 {
698 fprintf(f,
699 " %s \"%s/.\"\n",
700 p->flags & MFR_CONTINUE ? "cc":"to",
701 s);
702 free(s);
703 }
704 }
705 fprintf(f, "}\n\n");
706 }
707 fflush(f);
708 if (ferror(f))
709 {
710 fclose(f);
711 return (-1);
712 }
713 fprintf(f, "to \"%s/.\"\n", maildirpath);
714 if (fclose(f))
715 return (-1);
716 if (chmod(filename, 0600))
717 return (-1);
718
719 return (0);
720 }
721
maildir_filter_loadrules(struct maildirfilter * r,const char * filename)722 int maildir_filter_loadrules(struct maildirfilter *r, const char *filename)
723 {
724 FILE *f=fopen(filename, "r");
725 char buf[BUFSIZ];
726 char *p;
727
728 enum maildirfiltertype new_type;
729 char new_header[256];
730 char new_value[256];
731 char new_folder[256];
732 char new_autoreplyfrom[512];
733
734 int flags;
735
736 if (!f) return (MF_LOADNOTFOUND);
737
738 if (fgets(buf, sizeof(buf), f) == 0 ||
739 strncmp(buf, "#MFMAILDROP=", 12))
740 {
741 fclose(f);
742 return (MF_LOADFOREIGN);
743 }
744
745 flags=atoi(buf+12);
746 if (flags != 1 && flags != 2)
747 {
748 fclose(f);
749 return (MF_LOADFOREIGN);
750 }
751
752 new_type=contains;
753 new_header[0]=0;
754 new_value[0]=0;
755 new_folder[0]=0;
756 new_autoreplyfrom[0]=0;
757 flags=0;
758
759 #define SET(f,b) { f[0]=0; strncat( (f), (b), sizeof(f)-1); }
760
761 while ( fgets(buf, sizeof(buf), f))
762 {
763 int i;
764
765 p=strchr(buf, '\n');
766 if (p) *p=0;
767 if (strncmp(buf, "##", 2)) continue;
768 p=buf+2;
769 while ( *p && isspace((int)(unsigned char)*p))
770 ++p;
771
772 if (strncasecmp(p, "From:", 5) == 0)
773 {
774 p += 5;
775 SET(new_autoreplyfrom, p);
776 continue;
777 }
778
779
780 if (strncasecmp(p, "Op:", 3) == 0)
781 {
782 p += 3;
783
784 for (i=0; typelist[i].name; i++)
785 if (strcasecmp(typelist[i].name, p) == 0)
786 break;
787 if (!typelist[i].name)
788 {
789 fclose(f);
790 return (MF_LOADFOREIGN);
791 }
792 new_type=typelist[i].type;
793 continue;
794 }
795
796 if (strncasecmp(p, "Header:", 7) == 0)
797 {
798 p += 7;
799 SET(new_header, p);
800 continue;
801 }
802
803 if (strncasecmp(p, "Value:", 6) == 0)
804 {
805 p += 6;
806 SET(new_value, p);
807 continue;
808 }
809
810 if (strncasecmp(p, "Folder:", 7) == 0)
811 {
812 p += 7;
813
814 if (*p == '.')
815 {
816 strcpy(new_folder, INBOX);
817 }
818 else
819 new_folder[0]=0;
820
821 if (strcmp(p, "."))
822 strncat(new_folder, p,
823 sizeof(new_folder)-1-strlen(new_folder));
824 continue;
825 }
826
827 if (strcasecmp(p, "plainstring") == 0)
828 {
829 flags |= MFR_PLAINSTRING;
830 continue;
831 }
832
833 if (strcasecmp(p, "doesnot") == 0)
834 {
835 flags |= MFR_DOESNOT;
836 continue;
837 }
838
839 if (strcasecmp(p, "continue") == 0)
840 {
841 flags |= MFR_CONTINUE;
842 continue;
843 }
844
845 if (strcasecmp(p, "body") == 0)
846 {
847 flags |= MFR_BODY;
848 continue;
849 }
850
851 if (strncasecmp(p, "Name:", 5) == 0)
852 {
853 int dummy;
854
855 p += 5;
856 maildir_filter_appendrule(r, p, new_type, flags,
857 new_header,
858 new_value, new_folder,
859 new_autoreplyfrom,
860 "utf-8", &dummy);
861 new_type=contains;
862 new_header[0]=0;
863 new_value[0]=0;
864 new_folder[0]=0;
865 new_autoreplyfrom[0]=0;
866 flags=0;
867 }
868 }
869 fclose(f);
870 return (MF_LOADOK);
871 }
872
maildir_filter_autoresp_info_init(struct maildir_filter_autoresp_info * i,const char * c)873 int maildir_filter_autoresp_info_init(struct maildir_filter_autoresp_info *i, const char *c)
874 {
875 memset(i, 0, sizeof(*i));
876
877 if (maildir_autoresponse_validate(NULL, c))
878 return (-1);
879 i->name=strdup(c);
880 if (!(i->name))
881 return (-1);
882 return (0);
883 }
884
maildir_filter_autoresp_info_init_str(struct maildir_filter_autoresp_info * i,const char * c)885 int maildir_filter_autoresp_info_init_str(struct maildir_filter_autoresp_info *i, const char *c)
886 {
887 char *p;
888
889 memset(i, 0, sizeof(*i));
890 i->name=strdup(c);
891 if (!(i->name))
892 return (-1);
893
894 if (strtok(i->name, " \t\r\n") == NULL)
895 {
896 errno=EINVAL;
897 free(i->name);
898 i->name=0;
899 return (-1);
900 }
901
902 while ((p=strtok(NULL, " \t\r\n")) != NULL)
903 {
904 if (strncmp(p, "dsn=", 4) == 0)
905 i->dsnflag=atoi(p+4) ? 1:0;
906 else if (strncmp(p, "days=", 5) == 0)
907 i->days=atoi(p+5);
908 else if (strcmp(p, "noquote") == 0)
909 i->noquote=1;
910 }
911 return (0);
912 }
913
maildir_filter_autoresp_info_free(struct maildir_filter_autoresp_info * i)914 void maildir_filter_autoresp_info_free(struct maildir_filter_autoresp_info *i)
915 {
916 if (i->name)
917 {
918 free(i->name);
919 i->name=0;
920 }
921 }
922
maildir_filter_autoresp_info_asstr(struct maildir_filter_autoresp_info * i)923 char *maildir_filter_autoresp_info_asstr(struct maildir_filter_autoresp_info *i)
924 {
925 char days_buf[NUMBUFSIZE+10];
926
927 const char *dsn_arg="";
928 const char *days_arg="";
929 const char *noquote_arg="";
930
931 char *p;
932
933 if (i->dsnflag)
934 dsn_arg=" dsn=1";
935 if (i->days > 0)
936 {
937 strcpy(days_buf, " days=");
938 libmail_str_size_t(i->days, days_buf+6);
939 days_arg=days_buf;
940 }
941
942 if (i->noquote)
943 noquote_arg=" noquote";
944
945 p=malloc(strlen(i->name)+1+strlen(dsn_arg)+strlen(days_arg)+
946 strlen(noquote_arg));
947 if (!p)
948 return (NULL);
949
950 strcat(strcat(strcat(strcpy(p, i->name), dsn_arg), days_arg),
951 noquote_arg);
952 return (p);
953 }
954