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