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