1 #include "config.h"
2 /*
3 */
4
5 /*
6 ** Copyright 2000-2010 Double Precision, Inc. See COPYING for
7 ** distribution information.
8 */
9
10 #include "mailfilter.h"
11 #include "sqwebmail.h"
12 #include "maildir.h"
13 #include "auth.h"
14 #include "maildir/maildirmisc.h"
15 #include "maildir/maildirfilter.h"
16 #include "maildir/autoresponse.h"
17 #include "numlib/numlib.h"
18 #include "cgi/cgi.h"
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22
23 extern void list_folder(const char *);
24 extern void output_attrencoded(const char *);
25 extern const char *sqwebmail_content_charset;
26
27 static const char *internal_err=0;
28
clrfields()29 static void clrfields()
30 {
31 cgi_put("currentfilternum", "");
32 cgi_put("rulename", "");
33 cgi_put("filtertype", "");
34 cgi_put("hasrecipienttype", "");
35 cgi_put("hasrecipientaddr", "");
36 cgi_put("headername", "");
37 cgi_put("headervalue", "");
38 cgi_put("headermatchtype", "");
39 cgi_put("action", "");
40 cgi_put("forwardaddy", "");
41 cgi_put("bouncemsg", "");
42 cgi_put("savefolder", "");
43 cgi_put("sizecompare", "");
44 cgi_put("bytecount", "");
45 cgi_put("continuefiltering", "");
46 cgi_put("autoresponse_choose", "");
47 cgi_put("autoresponse_dsn", "");
48 cgi_put("autoresponse_regexp", "");
49 cgi_put("autoresponse_dupe", "");
50 cgi_put("autoresponse_days", "");
51 cgi_put("autoresponse_from", "");
52 cgi_put("autoresponse_noquote", "");
53 }
54
mailfilter_list()55 void mailfilter_list()
56 {
57 struct maildirfilter mf;
58 struct maildirfilterrule *r;
59 unsigned cnt;
60
61 memset(&mf, 0, sizeof(mf));
62
63 if (maildir_filter_loadmaildirfilter(&mf, "."))
64 {
65 maildir_filter_freerules(&mf);
66 return;
67 }
68
69 for (cnt=0, r=mf.first; r; r=r->next, ++cnt)
70 {
71 char *p=unicode_convert_fromutf8(r->rulename_utf8,
72 sqwebmail_content_charset,
73 NULL);
74
75 printf("<option value=\"%u\">", cnt);
76 output_attrencoded(p ? p:r->rulename_utf8);
77 printf("</option>");
78 if (p)
79 free(p);
80 }
81 maildir_filter_freerules(&mf);
82 }
83
mailfilter_init()84 void mailfilter_init()
85 {
86 const char *p;
87 unsigned n;
88 struct maildirfilter mf;
89 struct maildirfilterrule *r;
90
91 if (*cgi("import"))
92 {
93 if (maildir_filter_importmaildirfilter("."))
94 {
95 printf("%s", getarg("BADIMPORT"));
96 return;
97 }
98 }
99
100 if (*cgi("internalerr"))
101 {
102 const char *p=internal_err;
103
104 if (*cgi("currentfilternum"))
105 printf("<input name=\"currentfilternum\""
106 " type=\"hidden\""
107 " value=\"%s\" />", cgi("currentfilternum"));
108 if (p)
109 printf("%s", getarg(p));
110 }
111 internal_err=0;
112
113 if (*cgi("do.save"))
114 {
115 if (maildir_filter_exportmaildirfilter(".") ||
116 maildir_filter_importmaildirfilter("."))
117 printf("%s", getarg("INTERNAL"));
118 else
119 printf("%s", getarg("UPDATED"));
120 clrfields();
121 }
122
123 if (*cgi("do.add"))
124 clrfields();
125 memset(&mf, 0, sizeof(mf));
126
127 if (maildir_filter_loadmaildirfilter(&mf, "."))
128 {
129 maildir_filter_freerules(&mf);
130 printf("%s", getarg("BADIMPORT"));
131 return;
132 }
133 if (*(p=cgi("currentfilter")) == 0)
134 {
135 maildir_filter_freerules(&mf);
136 return;
137 }
138 n=atoi(p);
139
140 for (r=mf.first; n && r; r=r->next)
141 --n;
142 if (!r)
143 {
144 maildir_filter_freerules(&mf);
145 return;
146 }
147
148 if (*cgi("do.moveup") && r)
149 {
150 maildir_filter_ruleup(&mf, r);
151 maildir_filter_savemaildirfilter(&mf, ".", login_returnaddr());
152 clrfields();
153 }
154 else if (*cgi("do.movedown") && r)
155 {
156 maildir_filter_ruledown(&mf, r);
157 maildir_filter_savemaildirfilter(&mf, ".", login_returnaddr());
158 clrfields();
159 }
160 else if (*cgi("do.delete") && r)
161 {
162 maildir_filter_ruledel(&mf, r);
163 maildir_filter_savemaildirfilter(&mf, ".", login_returnaddr());
164 clrfields();
165 }
166 else if (*cgi("do.edit"))
167 {
168 static char *namebuf=0;
169 static char *headernamebuf=0;
170 static char *headervaluebuf=0;
171 static char *actionbuf=0;
172 char numbuf[NUMBUFSIZE+1];
173
174 printf("<input name=\"currentfilternum\""
175 " type=\"hidden\""
176 " value=\"%s\" />", p);
177
178 cgi_put("filtertype",
179 r->type == startswith ||
180 r->type == endswith ||
181 r->type == contains ?
182 r->flags & MFR_BODY ? "body":"header":
183 r->type == hasrecipient
184 ? "hasrecipient":
185 r->type == mimemultipart ?
186 r->flags & MFR_DOESNOT ?
187 "nothasmultipart":
188 "hasmultipart":
189 r->type == islargerthan ? "hassize":
190 r->type == anymessage
191 ? "anymessage":
192 r->type == textplain ?
193 r->flags & MFR_DOESNOT ?
194 "nothastextplain":
195 "hastextplain":""
196 ) ;
197
198 cgi_put("continuefiltering",
199 r->flags & MFR_CONTINUE ? "1":"");
200
201 cgi_put("headermatch",
202 r->type == startswith ?
203 r->flags & MFR_DOESNOT ? "notstartswith":"startswith":
204 r->type == endswith ?
205 r->flags & MFR_DOESNOT ? "notendswith":"endswith":
206 r->type == contains ?
207 r->flags & MFR_DOESNOT ? "notcontains":"contains":"");
208
209 if (namebuf) free(namebuf);
210 p=r->rulename_utf8 ? r->rulename_utf8:"";
211
212 namebuf=unicode_convert_fromutf8(p, sqwebmail_content_charset,
213 NULL);
214
215 if (!namebuf) enomem();
216 cgi_put("rulename", namebuf);
217
218 p=r->fieldname_utf8 ? r->fieldname_utf8:"";
219 if (r->type != startswith &&
220 r->type != endswith &&
221 r->type != contains) p="";
222 if (r->flags & MFR_BODY) p="";
223
224 if (headernamebuf) free(headernamebuf);
225 headernamebuf=unicode_convert_fromutf8(p,
226 sqwebmail_content_charset,
227 NULL);
228 if (!headernamebuf) enomem();
229 cgi_put("headername", headernamebuf);
230
231 p=r->fieldvalue_utf8 ? r->fieldvalue_utf8:"";
232 if (r->type != startswith &&
233 r->type != endswith &&
234 r->type != contains &&
235 r->type != hasrecipient &&
236 r->type != islargerthan) p="";
237
238 if (r->type == islargerthan)
239 p=libmail_str_size_t( atol(p)+( r->flags & MFR_DOESNOT ? 1:0),
240 numbuf);
241
242 if (headervaluebuf) free(headervaluebuf);
243
244 headervaluebuf=
245 unicode_convert_fromutf8(p,
246 sqwebmail_content_charset,
247 NULL);
248 if (!headervaluebuf) enomem();
249
250 cgi_put("hasrecipientaddr", "");
251 cgi_put("headervalue", "");
252 cgi_put("bytecount", "");
253 cgi_put("sizecompare", "");
254
255 cgi_put(r->type == hasrecipient ? "hasrecipientaddr":
256 r->type == islargerthan ? "bytecount":
257 "headervalue", headervaluebuf);
258
259 if (r->type == hasrecipient)
260 cgi_put("hasrecipienttype",
261 r->flags & MFR_DOESNOT ? "nothasrecipient":
262 "hasrecipient");
263 if (r->type == islargerthan)
264 cgi_put("sizecompare",
265 r->flags & MFR_DOESNOT
266 ? "issmallerthan":"islargerthan");
267 if (actionbuf) actionbuf=0;
268 p=r->tofolder;
269 if (!p) p="";
270 actionbuf=malloc(strlen(p)+1);
271 if (!actionbuf) enomem();
272 strcpy(actionbuf, p);
273
274 cgi_put("bouncemsg", "");
275 cgi_put("forwardaddy", "");
276 cgi_put("savefolder", "");
277
278 cgi_put("autoresponse_regexp",
279 r->flags & MFR_PLAINSTRING ? "":"1");
280
281 if (actionbuf[0] == '!')
282 {
283 cgi_put("action", "forwardto");
284 cgi_put("forwardaddy", actionbuf+1);
285 }
286 else if (actionbuf[0] == '*')
287 {
288 cgi_put("action", "bounce");
289 cgi_put("bouncemsg", actionbuf+1);
290 }
291 else if (actionbuf[0] == '+')
292 {
293 struct maildir_filter_autoresp_info mfai;
294 static char *autoresp_name_buf=0;
295 static char days_buf[NUMBUFSIZE];
296 static char *fromhdr=0;
297
298 if (maildir_filter_autoresp_info_init_str(&mfai, actionbuf+1))
299 enomem();
300
301 if (autoresp_name_buf)
302 free(autoresp_name_buf);
303
304 if ((autoresp_name_buf=strdup(mfai.name)) == NULL)
305 enomem();
306
307 cgi_put("action", "autoresponse");
308 cgi_put("autoresponse_choose", autoresp_name_buf);
309 cgi_put("autoresponse_dsn",
310 mfai.dsnflag ? "1":"");
311
312 cgi_put("autoresponse_dupe",
313 mfai.days > 0 ? "1":"");
314
315 libmail_str_size_t(mfai.days, days_buf);
316 cgi_put("autoresponse_days", mfai.days ?
317 days_buf:"");
318 maildir_filter_autoresp_info_free(&mfai);
319
320 if (fromhdr)
321 free(fromhdr);
322 fromhdr=strdup(r->fromhdr ? r->fromhdr:"");
323 if (!fromhdr)
324 enomem();
325 cgi_put("autoresponse_from", fromhdr);
326
327 if (mfai.noquote)
328 cgi_put("autoresponse_noquote", "1");
329 }
330 else if (strcmp(actionbuf, "exit") == 0)
331 {
332 cgi_put("action", "purge");
333 }
334 else
335 {
336 cgi_put("action", "savefolder");
337 cgi_put("savefolder",
338 strcmp(actionbuf, ".") == 0 ? INBOX:
339 *actionbuf == '.' ? actionbuf+1:actionbuf);
340 }
341 }
342 else if (*(p=cgi("currentfilternum")) != 0)
343 {
344 printf("<input name=\"currentfilternum\""
345 " type=\"hidden\""
346 " value=\"%s\" />", p);
347 }
348
349
350
351 maildir_filter_freerules(&mf);
352 }
353
mailfilter_listfolders()354 void mailfilter_listfolders()
355 {
356 char **folders;
357 int i;
358 const char *f=cgi("savefolder");
359
360 printf("<select name=\"savefolder\">");
361
362 maildir_listfolders(INBOX, ".", &folders);
363
364 for (i=0; folders[i]; i++)
365 {
366 const char *p=folders[i];
367 int selected=0;
368
369 if (strcmp(p, INBOX) &&
370 strncmp(p, INBOX ".", sizeof(INBOX)))
371 continue;
372
373 printf("<option value=\"");
374 output_attrencoded(p);
375 if (strcmp(p, f) == 0)
376 selected=1;
377
378 if (strcmp(p, INBOX) == 0)
379 {
380 p=getarg("INBOX");
381 selected=0;
382 if (strcmp(f, ".") == 0)
383 selected=1;
384 }
385 else if (strcmp(p, INBOX "." DRAFTS) == 0)
386 p=getarg("DRAFTS");
387 else if (strcmp(p, INBOX "." TRASH) == 0)
388 p=getarg("TRASH");
389 else if (strcmp(p, INBOX "." SENT) == 0)
390 p=getarg("SENT");
391 else
392 p=strchr(p, '.')+1;
393
394 printf("\"");
395 if (selected)
396 printf(" selected='selected'");
397 printf(">");
398 list_folder(p);
399 printf("</option>\n");
400 }
401
402 maildir_freefolders(&folders);
403 printf("</select>");
404 }
405
mailfilter_submit()406 void mailfilter_submit()
407 {
408 struct maildirfilter mf;
409 struct maildirfilterrule *r;
410 const char *p;
411 enum maildirfiltertype type;
412 int flags=0;
413 const char *rulename=0;
414 const char *fieldname=0;
415 const char *fieldvalue=0;
416 char *tofolder=0;
417 char *fieldname_cpy;
418 int err_num;
419 char numbuf[NUMBUFSIZE];
420 const char *autoreply_from="";
421
422 memset(&mf, 0, sizeof(mf));
423 if (maildir_filter_loadmaildirfilter(&mf, "."))
424 {
425 maildir_filter_freerules(&mf);
426 return;
427 }
428
429 r=0;
430 p=cgi("currentfilternum");
431 if (*p)
432 {
433 unsigned n=atoi(p);
434
435 for (r=mf.first; r && n; r=r->next)
436 --n;
437 }
438
439 rulename=cgi("rulename");
440
441 p=cgi("filtertype");
442 if (strcmp(p, "hasrecipient") == 0)
443 {
444 type=hasrecipient;
445 if (strcmp(cgi("hasrecipienttype"), "nothasrecipient") == 0)
446 flags |= MFR_DOESNOT;
447
448 fieldvalue=cgi("hasrecipientaddr");
449 }
450 else if (strcmp(p, "hastextplain") == 0)
451 {
452 type=textplain;
453 }
454 else if (strcmp(p, "nothastextplain") == 0)
455 {
456 type=textplain;
457 flags |= MFR_DOESNOT;
458 }
459 else if (strcmp(p, "hasmultipart") == 0)
460 {
461 type=mimemultipart;
462 }
463 else if (strcmp(p, "nothasmultipart") == 0)
464 {
465 type=mimemultipart;
466 flags |= MFR_DOESNOT;
467 }
468 else if (strcmp(p, "hassize") == 0)
469 {
470 unsigned long n=atol(cgi("bytecount"));
471
472 type=islargerthan;
473 if (strcmp(cgi("sizecompare"), "issmallerthan") == 0)
474 {
475 flags |= MFR_DOESNOT;
476 if (n) --n;
477 }
478 fieldvalue=libmail_str_size_t(n, numbuf);
479 }
480 else if (strcmp(p, "anymessage") == 0)
481 {
482 type=anymessage;
483 }
484 else
485 {
486 if (strcmp(p, "body") == 0)
487 flags |= MFR_BODY;
488
489 fieldname=cgi("headername");
490 p=cgi("headermatchtype");
491 type=strcmp(p, "startswith") == 0 ||
492 strcmp(p, "notstartswith") == 0 ? startswith:
493 strcmp(p, "contains") == 0 ||
494 strcmp(p, "notcontains") == 0 ? contains:endswith;
495 if (strncmp(p, "not", 3) == 0)
496 flags |= MFR_DOESNOT;
497 fieldvalue=cgi("headervalue");
498 }
499
500 if (*cgi("continuefiltering"))
501 flags |= MFR_CONTINUE;
502
503 if (!*cgi("autoresponse_regexp"))
504 flags |= MFR_PLAINSTRING;
505
506 p=cgi("action");
507 if (strcmp(p, "forwardto") == 0)
508 {
509 p=cgi("forwardaddy");
510 tofolder=malloc(strlen(p)+2);
511 if (!tofolder) enomem();
512 strcat(strcpy(tofolder, "!"), p);
513 }
514 else if (strcmp(p, "bounce") == 0)
515 {
516 p=cgi("bouncemsg");
517 tofolder=malloc(strlen(p)+2);
518 if (!tofolder) enomem();
519 strcat(strcpy(tofolder, "*"), p);
520 }
521 else if (strcmp(p, "autoresponse") == 0)
522 {
523 struct maildir_filter_autoresp_info mfaii;
524 char *q;
525
526 p=cgi("autoresponse_choose");
527
528 if (maildir_filter_autoresp_info_init(&mfaii, p))
529 {
530 internal_err="AUTOREPLY";
531 cgi_put("internal_err", "1");
532 return;
533 }
534
535 p=cgi("autoresponse_dsn");
536
537 if (*p)
538 mfaii.dsnflag=1;
539
540 p=cgi("autoresponse_dupe");
541 if (*p)
542 {
543 p=cgi("autoresponse_days");
544 mfaii.days=atoi(p);
545 }
546
547 p=cgi("autoresponse_noquote");
548
549 if (*p)
550 mfaii.noquote=1;
551
552 q=maildir_filter_autoresp_info_asstr(&mfaii);
553 maildir_filter_autoresp_info_free(&mfaii);
554
555 if (!q)
556 enomem();
557
558 if (!(tofolder=malloc(strlen(q)+2)))
559 {
560 free(q);
561 enomem();
562 }
563
564 tofolder[0]='+';
565 strcpy(tofolder+1, q);
566 free(q);
567 autoreply_from=cgi("autoresponse_from");
568 }
569 else if (strcmp(p, "purge") == 0)
570 {
571 tofolder = strdup("exit");
572 if (!tofolder) enomem();
573 }
574 else
575 {
576 tofolder=strdup(cgi("savefolder"));
577 if (!tofolder) enomem();
578 }
579
580 fieldname_cpy=NULL;
581
582 if (fieldname)
583 {
584 char *p;
585
586 fieldname_cpy=strdup(fieldname);
587
588 p=strrchr(fieldname_cpy, ':');
589
590 if (p && p[1] == 0)
591 *p=0;
592 }
593
594 if (!r)
595 r=maildir_filter_appendrule(&mf, rulename, type, flags, fieldname_cpy,
596 fieldvalue, tofolder, autoreply_from, sqwebmail_content_charset, &err_num);
597 else if (maildir_filter_ruleupdate(&mf, r, rulename, type, flags, fieldname_cpy,
598 fieldvalue, tofolder, autoreply_from, sqwebmail_content_charset, &err_num))
599 r=0;
600 free(tofolder);
601 if (fieldname_cpy)
602 free(fieldname_cpy);
603 if (r)
604 {
605 maildir_filter_savemaildirfilter(&mf, ".", login_returnaddr());
606 maildir_filter_freerules(&mf);
607 clrfields();
608 return;
609 }
610 maildir_filter_freerules(&mf);
611
612 internal_err="INTERNAL";
613 if (err_num == MF_ERR_BADRULENAME)
614 internal_err= "BADRULENAME";
615 if (err_num == MF_ERR_EXISTS)
616 internal_err= "EXISTS";
617 if (err_num == MF_ERR_BADRULEHEADER)
618 internal_err= "BADHEADER";
619 if (err_num == MF_ERR_BADRULEVALUE)
620 internal_err= "BADVALUE";
621 if (err_num == MF_ERR_BADRULEFOLDER)
622 internal_err= "ERRTOFOLDER";
623 if (err_num == MF_ERR_BADFROMHDR)
624 internal_err= "FROMHDR";
625
626 cgi_put("internalerr", "1");
627 }
628
mailfilter_folderused(const char * foldername)629 int mailfilter_folderused(const char *foldername)
630 {
631 struct maildirfilter mf;
632 struct maildirfilterrule *r;
633 int rc;
634
635 memset(&mf, 0, sizeof(mf));
636 if (maildir_filter_hasmaildirfilter(".") ||
637 maildir_filter_importmaildirfilter(".")) return (0);
638
639 rc=maildir_filter_loadmaildirfilter(&mf, ".");
640 maildir_filter_endmaildirfilter(".");
641 if (rc)
642 {
643 maildir_filter_freerules(&mf);
644 return (0);
645 }
646
647 for (r=mf.first; r; r=r->next)
648 {
649 if (r->tofolder == 0) continue;
650 if (strcmp(foldername, r->tofolder) == 0)
651 {
652 maildir_filter_freerules(&mf);
653 return (-1);
654 }
655 }
656 maildir_filter_freerules(&mf);
657 return (0);
658 }
659
mailfilter_autoreplyused(const char * autoreply)660 int mailfilter_autoreplyused(const char *autoreply)
661 {
662 struct maildirfilter mf;
663 struct maildirfilterrule *r;
664 int rc;
665
666 memset(&mf, 0, sizeof(mf));
667 if (maildir_filter_hasmaildirfilter(".") ||
668 maildir_filter_importmaildirfilter(".")) return (0);
669
670 rc=maildir_filter_loadmaildirfilter(&mf, ".");
671 maildir_filter_endmaildirfilter(".");
672 if (rc)
673 {
674 maildir_filter_freerules(&mf);
675 return (0);
676 }
677
678 for (r=mf.first; r; r=r->next)
679 {
680 struct maildir_filter_autoresp_info mfai;
681
682 if (r->tofolder == 0) continue;
683 if (r->tofolder[0] != '+')
684 continue;
685
686 if (maildir_filter_autoresp_info_init_str(&mfai, r->tofolder+1))
687 enomem();
688
689 if (strcmp(autoreply, mfai.name) == 0)
690 {
691 maildir_filter_autoresp_info_free(&mfai);
692 maildir_filter_freerules(&mf);
693 return (-1);
694 }
695 maildir_filter_autoresp_info_free(&mfai);
696 }
697 maildir_filter_freerules(&mf);
698 return (0);
699 }
700
mailfilter_cleanup()701 void mailfilter_cleanup()
702 {
703 internal_err=0;
704 }
705