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