dd4e3e93a866f608a35c93307c46952e72896ec7
[citadel.git] / webcit / sieve.c
1 /*
2  * Copyright (c) 1996-2011 by the citadel.org team
3  *
4  * This program is open source software.  You can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18
19 #include "webcit.h"
20
21 #define MAX_SCRIPTS     100
22 #define MAX_RULES       50
23 #define RULES_SCRIPT    "__WebCit_Generated_Script__"
24
25 /*#define FOO 1*/
26
27 /*
28  * Helper function for output_sieve_rule() to output strings with quotes escaped
29  */
30 void osr_sanitize(char *str) {
31         int i, len;
32
33         if (str == NULL) return;
34         len = strlen(str);
35         for (i=0; i<len; ++i) {
36                 if (str[i]=='\"') {
37                         str[i] = '\'' ;
38                 }
39                 else if (isspace(str[i])) {
40                         str[i] = ' ';
41                 }
42         }
43 }
44
45 void display_add_remove_scripts(char *message);
46 void display_rules_editor_inner_div(void);
47
48
49
50
51
52
53 /*
54  * Output parseable Sieve script code based on rules input
55  */
56 void output_sieve_rule(char *hfield, char *compare, char *htext, char *sizecomp, int sizeval,
57                         char *action, char *fileinto, char *redirect, char *automsg, char *final,
58                         char *my_addresses)
59 {
60         char *comp1 = "";
61         char *comp2 = "";
62
63         osr_sanitize(htext);
64         osr_sanitize(fileinto);
65         osr_sanitize(redirect);
66         osr_sanitize(automsg);
67
68         /* Prepare negation and match operators that will be used iff we apply a conditional */
69
70         if (!strcasecmp(compare, "contains")) {
71                 comp1 = "";
72                 comp2 = ":contains";
73         }
74         else if (!strcasecmp(compare, "notcontains")) {
75                 comp1 = "not";
76                 comp2 = ":contains";
77         }
78         else if (!strcasecmp(compare, "is")) {
79                 comp1 = "";
80                 comp2 = ":is";
81         }
82         else if (!strcasecmp(compare, "isnot")) {
83                 comp1 = "not";
84                 comp2 = ":is";
85         }
86         else if (!strcasecmp(compare, "matches")) {
87                 comp1 = "";
88                 comp2 = ":matches";
89         }
90         else if (!strcasecmp(compare, "notmatches")) {
91                 comp1 = "not";
92                 comp2 = ":matches";
93         }
94
95         /* Now do the conditional */
96
97         if (!strcasecmp(hfield, "from")) {
98                 serv_printf("if%s header %s \"From\" \"%s\"",
99                         comp1, comp2,
100                         htext
101                 );
102         }
103
104         else if (!strcasecmp(hfield, "tocc")) {
105                 serv_printf("if%s header %s [\"To\", \"Cc\"] \"%s\"",
106                         comp1, comp2,
107                         htext
108                 );
109         }
110
111         else if (!strcasecmp(hfield, "subject")) {
112                 serv_printf("if%s header %s \"Subject\" \"%s\"",
113                         comp1, comp2,
114                         htext
115                 );
116         }
117
118         else if (!strcasecmp(hfield, "replyto")) {
119                 serv_printf("if%s header %s \"Reply-to\" \"%s\"",
120                         comp1, comp2,
121                         htext
122                 );
123         }
124
125         else if (!strcasecmp(hfield, "sender")) {
126                 serv_printf("if%s header %s \"Sender\" \"%s\"",
127                         comp1, comp2,
128                         htext
129                 );
130         }
131
132         else if (!strcasecmp(hfield, "resentfrom")) {
133                 serv_printf("if%s header %s \"Resent-from\" \"%s\"",
134                         comp1, comp2,
135                         htext
136                 );
137         }
138
139         else if (!strcasecmp(hfield, "resentto")) {
140                 serv_printf("if%s header %s \"Resent-to\" \"%s\"",
141                         comp1, comp2,
142                         htext
143                 );
144         }
145
146         else if (!strcasecmp(hfield, "xmailer")) {
147                 serv_printf("if%s header %s \"X-Mailer\" \"%s\"",
148                         comp1, comp2,
149                         htext
150                 );
151         }
152
153         else if (!strcasecmp(hfield, "xspamflag")) {
154                 serv_printf("if%s header %s \"X-Spam-Flag\" \"%s\"",
155                         comp1, comp2,
156                         htext
157                 );
158         }
159
160         else if (!strcasecmp(hfield, "xspamstatus")) {
161                 serv_printf("if%s header %s \"X-Spam-Status\" \"%s\"",
162                         comp1, comp2,
163                         htext
164                 );
165         }
166
167         else if (!strcasecmp(hfield, "listid")) {
168                 serv_printf("if%s header %s \"List-ID\" \"%s\"",
169                         comp1, comp2,
170                         htext
171                 );
172         }
173
174         else if (!strcasecmp(hfield, "envfrom")) {
175                 serv_printf("if%s envelope %s \"From\" \"%s\"",
176                         comp1, comp2,
177                         htext
178                 );
179         }
180
181         else if (!strcasecmp(hfield, "envto")) {
182                 serv_printf("if%s envelope %s \"To\" \"%s\"",
183                         comp1, comp2,
184                         htext
185                 );
186         }
187
188         else if (!strcasecmp(hfield, "size")) {
189                 if (!strcasecmp(sizecomp, "larger")) {
190                         serv_printf("if size :over %d", sizeval);
191                 }
192                 else if (!strcasecmp(sizecomp, "smaller")) {
193                         serv_printf("if size :under %d", sizeval);
194                 }
195                 else {  /* failsafe - should never get here, but just in case... */
196                         serv_printf("if size :over 1");
197                 }
198         }
199
200         /* Open braces if we're in a conditional loop */
201
202         if (strcasecmp(hfield, "all")) {
203                 serv_printf("{");
204         }
205
206
207         /* Do action */
208
209         if (!strcasecmp(action, "keep")) {
210                 serv_printf("keep;");
211         }
212
213         else if (!strcasecmp(action, "discard")) {
214                 serv_printf("discard;");
215         }
216
217         else if (!strcasecmp(action, "reject")) {
218                 serv_printf("reject \"%s\";", automsg);
219         }
220
221         else if (!strcasecmp(action, "fileinto")) {
222                 serv_printf("fileinto \"%s\";", fileinto);
223         }
224
225         else if (!strcasecmp(action, "redirect")) {
226                 serv_printf("redirect \"%s\";", redirect);
227         }
228
229         else if (!strcasecmp(action, "vacation")) {
230                 serv_printf("vacation :addresses [%s]\n\"%s\";", my_addresses, automsg);
231         }
232
233
234         /* Do 'final' action */
235
236         if (!strcasecmp(final, "stop")) {
237                 serv_printf("stop;");
238         }
239
240
241         /* Close the braces if we're in a conditional loop */
242
243         if (strcasecmp(hfield, "all")) {
244                 serv_printf("}");
245         }
246
247
248         /* End of rule. */
249 }
250
251
252
253 /*
254  * Translate the fields from the rule editor into something we can save...
255  */
256 void parse_fields_from_rule_editor(void) {
257
258         int active;
259         char hfield[256];
260         char compare[32];
261         char htext[256];
262         char sizecomp[32];
263         int sizeval;
264         char action[32];
265         char fileinto[128];
266         char redirect[256];
267         char automsg[1024];
268         char final[32];
269         int i;
270         char buf[256];
271         char fname[256];
272         char rule[2048];
273         char encoded_rule[4096];
274         char my_addresses[4096];
275         
276         /* Enumerate my email addresses in case they are needed for a vacation rule */
277         my_addresses[0] = 0;
278         serv_puts("GVEA");
279         serv_getln(buf, sizeof buf);
280         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
281                 if (!IsEmptyStr(my_addresses)) {
282                         strcat(my_addresses, ",\n");
283                 }
284                 strcat(my_addresses, "\"");
285                 strcat(my_addresses, buf);
286                 strcat(my_addresses, "\"");
287         }
288
289         /* Now generate the script and write it to the Citadel server */
290         serv_printf("MSIV putscript|%s|", RULES_SCRIPT);
291         serv_getln(buf, sizeof buf);
292         if (buf[0] != '4') {
293                 return;
294         }
295
296         serv_puts("# THIS SCRIPT WAS AUTOMATICALLY GENERATED BY WEBCIT.");
297         serv_puts("# ");
298         serv_puts("# Do not attempt to manually edit it.  If you do so,");
299         serv_puts("# your changes will be overwritten the next time WebCit");
300         serv_puts("# saves its mail filtering rule set.  If you really want");
301         serv_puts("# to use these rules as the basis for another script,");
302         serv_puts("# copy them to another script and save that instead.");
303         serv_puts("");
304         serv_puts("require \"fileinto\";");
305         serv_puts("require \"reject\";");
306         serv_puts("require \"vacation\";");
307         serv_puts("require \"envelope\";");
308         serv_puts("");
309
310         for (i=0; i<MAX_RULES; ++i) {
311                 
312                 strcpy(rule, "");
313
314                 sprintf(fname, "active%d", i);
315                 active = !strcasecmp(BSTR(fname), "on") ;
316
317                 if (active) {
318
319                         sprintf(fname, "hfield%d", i);
320                         safestrncpy(hfield, BSTR(fname), sizeof hfield);
321         
322                         sprintf(fname, "compare%d", i);
323                         safestrncpy(compare, BSTR(fname), sizeof compare);
324         
325                         sprintf(fname, "htext%d", i);
326                         safestrncpy(htext, BSTR(fname), sizeof htext);
327         
328                         sprintf(fname, "sizecomp%d", i);
329                         safestrncpy(sizecomp, BSTR(fname), sizeof sizecomp);
330         
331                         sprintf(fname, "sizeval%d", i);
332                         sizeval = IBSTR(fname);
333         
334                         sprintf(fname, "action%d", i);
335                         safestrncpy(action, BSTR(fname), sizeof action);
336         
337                         sprintf(fname, "fileinto%d", i);
338                         safestrncpy(fileinto, BSTR(fname), sizeof fileinto);
339         
340                         sprintf(fname, "redirect%d", i);
341                         safestrncpy(redirect, BSTR(fname), sizeof redirect);
342         
343                         sprintf(fname, "automsg%d", i);
344                         safestrncpy(automsg, BSTR(fname), sizeof automsg);
345         
346                         sprintf(fname, "final%d", i);
347                         safestrncpy(final, BSTR(fname), sizeof final);
348         
349                         snprintf(rule, sizeof rule, "%d|%s|%s|%s|%s|%d|%s|%s|%s|%s|%s",
350                                 active, hfield, compare, htext, sizecomp, sizeval, action, fileinto,
351                                 redirect, automsg, final
352                         );
353         
354                         CtdlEncodeBase64(encoded_rule, rule, strlen(rule)+1, 0);
355                         serv_printf("# WEBCIT_RULE|%d|%s|", i, encoded_rule);
356                         output_sieve_rule(hfield, compare, htext, sizecomp, sizeval,
357                                         action, fileinto, redirect, automsg, final, my_addresses);
358                         serv_puts("");
359                 }
360
361
362         }
363
364         serv_puts("stop;");
365         serv_puts("000");
366 }
367
368
369
370 /*
371  * save sieve config
372  */
373 void save_sieve(void) {
374         int bigaction;
375         char script_names[MAX_SCRIPTS][64];
376         int num_scripts = 0;
377         int active_script = (-1);
378         int i;
379         char this_name[64];
380         char buf[256];
381
382         if (!havebstr("save_button")) {
383                 strcpy(WC->ImportantMessage,
384                         _("Cancelled.  Changes were not saved."));
385                 display_main_menu();
386                 return;
387         }
388
389         parse_fields_from_rule_editor();
390
391         serv_puts("MSIV listscripts");
392         serv_getln(buf, sizeof(buf));
393         if (buf[0] == '1') while (serv_getln(buf, sizeof(buf)), strcmp(buf, "000")) {
394                 if (num_scripts < MAX_SCRIPTS) {
395                         extract_token(script_names[num_scripts], buf, 0, '|', 64);
396                         if (extract_int(buf, 1) > 0) {
397                                 active_script = num_scripts;
398                         }
399                         ++num_scripts;
400                 }
401         }
402
403         bigaction = ibstr("bigaction");
404
405         if (bigaction == 0) {
406                 serv_puts("MSIV setactive||");
407                 serv_getln(buf, sizeof buf);
408         }
409
410         else if (bigaction == 1) {
411                 serv_printf("MSIV setactive|%s|", RULES_SCRIPT);
412                 serv_getln(buf, sizeof buf);
413         }
414
415         else if (bigaction == 2) {
416                 serv_printf("MSIV setactive|%s|", bstr("active_script"));
417                 serv_getln(buf, sizeof buf);
418         }
419
420         if (num_scripts > 0) {
421                 for (i=0; i<num_scripts; ++i) {
422                         /*
423                          * We only want to save the scripts from the "manually edited scripts"
424                          * screen.  The script that WebCit generates from its ruleset will be
425                          * auto-generated by parse_fields_from_rule_editor() and saved there.
426                          */
427                         if (strcasecmp(script_names[i], RULES_SCRIPT)) {
428                                 serv_printf("MSIV putscript|%s|", script_names[i]);
429                                 serv_getln(buf, sizeof buf);
430                                 if (buf[0] == '4') {
431                                         snprintf(this_name, sizeof this_name, "text_%s", script_names[i]);
432                                         striplt((char *)BSTR(this_name)); /* TODO: get rid of typecast*/
433                                         serv_write(BSTR(this_name), strlen(BSTR(this_name)));
434                                         serv_puts("\n000");
435                                 }
436                         }
437                 }
438         }
439
440         strcpy(WC->ImportantMessage, _("Your changes have been saved."));
441         display_main_menu();
442         return;
443 }
444
445 /*
446  * create a new script
447  * take the web environment script name and create it on the citadel server
448  */
449 void create_script(void) {
450         char buf[256];
451
452         serv_printf("MSIV getscript|%s", bstr("script_name"));
453         serv_getln(buf, sizeof buf);
454         if (buf[0] == '1') {
455                 while (serv_getln(buf, sizeof(buf)), strcmp(buf, "000")) {
456                         /* flush */
457                 }
458 #if FOO
459                 display_add_remove_scripts(_("A script by that name already exists."));
460 #endif
461                 return;
462         }
463         
464         serv_printf("MSIV putscript|%s", bstr("script_name"));
465         serv_getln(buf, sizeof buf);
466         if (buf[0] == '4') {
467                 serv_puts("keep;");
468                 serv_puts("000");
469 #if FOO
470                 display_add_remove_scripts(_("A new script has been created.  Return to the script editing screen to edit and activate it."));
471 #else
472         output_headers(1, 1, 2, 0, 0, 0);
473         do_template("sieve_add");
474         wDumpContent(1);
475 #endif
476                 return;
477         }
478
479 #if FOO
480         display_add_remove_scripts(&buf[4]);
481 #else
482         output_headers(1, 1, 2, 0, 0, 0);
483         do_template("sieve_add");
484         wDumpContent(1);
485 #endif
486 }
487
488
489
490
491 /*
492  * delete a script
493  */
494 void delete_script(void) {
495         char buf[256];
496
497         serv_printf("MSIV deletescript|%s", bstr("script_name"));
498         serv_getln(buf, sizeof buf);
499 #if FOO
500         display_add_remove_scripts(&buf[4]);
501 #else
502         output_headers(1, 1, 2, 0, 0, 0);
503         do_template("sieve_add");
504         wDumpContent(1);
505 #endif
506 }
507                 
508
509
510 /*
511  * dummy panel indicating to the user that the server doesn't support Sieve
512  */
513 void display_no_sieve(void) {
514
515         output_headers(1, 1, 2, 0, 0, 0);
516         do_template("sieve_none");
517         wDumpContent(1);
518 }
519
520 #if FOO
521 /*
522  * view/edit sieve config
523  */
524 void display_sieve(void)
525 {
526         char script_names[MAX_SCRIPTS][64];
527         int num_scripts = 0;
528         int active_script = (-1);
529         char buf[SIZ];          /* Don't make this buffer smaller or it will restrict line length */
530         int i;
531         int rules_script_is_active = 0;
532
533         if (!WC->serv_info->serv_supports_sieve) {
534                 display_no_sieve();
535                 return;
536         }
537
538         memset(script_names, 0, sizeof script_names);
539
540         serv_puts("MSIV listscripts");
541         serv_getln(buf, sizeof(buf));
542         if (buf[0] == '1') while (serv_getln(buf, sizeof(buf)), strcmp(buf, "000")) {
543                 if (num_scripts < MAX_SCRIPTS) {
544                         extract_token(script_names[num_scripts], buf, 0, '|', 64);
545                         if (extract_int(buf, 1) > 0) {
546                                 active_script = num_scripts;
547                                 if (!strcasecmp(script_names[num_scripts], RULES_SCRIPT)) {
548                                         rules_script_is_active = 1;
549                                 }
550                         }
551                         ++num_scripts;
552                 }
553         }
554
555         output_headers(1, 1, 2, 0, 0, 0);
556
557         wc_printf("<script type=\"text/javascript\">\n"
558                   "\n"
559                   "var previously_active_script;\n"
560                   "\n"
561                   "function ToggleSievePanels() {\n"
562                   " d = ($('sieveform').bigaction.options[$('sieveform').bigaction.selectedIndex].value);\n"
563                   " for (i=0; i<3; ++i) {\n"
564                   "  if (i == d) {\n"
565                   "   $('sievediv' + i).style.display = 'block';\n"
566                   "  }\n"
567                   "  else {\n"
568                   "   $('sievediv' + i).style.display = 'none';\n"
569                   "  }\n"
570                   " }\n"
571                   "}\n"
572                   "\n"
573                   "function ToggleScriptPanels() {\n"
574                   " d = ($('sieveform').active_script.options[$('sieveform').active_script.selectedIndex].value);\n"
575                   " if ($('script_' + previously_active_script)) {\n"
576                   "  $('script_' + previously_active_script).style.display = 'none';\n"
577                   " }\n"
578                   " $('script_' + d).style.display = 'block';\n"
579                   " previously_active_script = d;\n"
580                   "}\n"
581                   "\n"
582                   "</script>\n"
583 );
584
585         wc_printf("<div id=\"banner\">\n");
586         wc_printf("<img src=\"static/webcit_icons/essen/32x32/config.png\">");
587         wc_printf("<h1>");
588         wc_printf(_("View/edit server-side mail filters"));
589         wc_printf("</h1>\n");
590         wc_printf("</div>\n");
591
592         wc_printf("<div id=\"content\" class=\"service\">\n");
593
594         wc_printf("<table class=\"sieve_background\">\n"
595                 "<tr>\n<td valign=top>\n");
596
597
598         wc_printf("<form id=\"sieveform\" method=\"post\" action=\"save_sieve\">\n");
599         wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
600
601         wc_printf(_("When new mail arrives: "));
602         wc_printf("<select name=\"bigaction\" size=1 onChange=\"ToggleSievePanels();\">\n");
603
604         wc_printf("<option %s value=\"0\">", ((active_script < 0) ? "selected" : ""));
605         wc_printf(_("Leave it in my inbox without filtering"));
606         wc_printf("</option>\n");
607
608         wc_printf("<option %s value=\"1\">", ((rules_script_is_active) ? "selected" : ""));
609         wc_printf(_("Filter it according to rules selected below"));
610         wc_printf("</option>\n");
611
612         wc_printf("<option %s value=\"2\">",
613                         (((active_script >= 0) && (!rules_script_is_active)) ? "selected" : ""));
614         wc_printf(_("Filter it through a manually edited script (advanced users only)"));
615         wc_printf("</option>\n");
616
617         wc_printf("</select>\n\n");
618
619
620
621         /* The "no filtering" div */
622
623         wc_printf("<div id=\"sievediv0\" style=\"display:none\">\n");
624         wc_printf("<div align=\"center\"><br><br>");
625         wc_printf(_("Your incoming mail will not be filtered through any scripts."));
626         wc_printf("<br><br></div>\n");
627         wc_printf("</div>\n");
628
629         /* The "webcit managed scripts" div */
630
631         wc_printf("<div id=\"sievediv1\" style=\"display:none\">\n");
632         display_rules_editor_inner_div();
633         wc_printf("</div>\n");
634
635         /* The "I'm smart and can write my own Sieve scripts" div */
636
637         wc_printf("<div id=\"sievediv2\" style=\"display:none\">\n");
638
639         if (num_scripts > 0) {
640                 wc_printf(_("The currently active script is: "));
641                 wc_printf("<select name=\"active_script\" size=1 onChange=\"ToggleScriptPanels();\">\n");
642                 for (i=0; i<num_scripts; ++i) {
643                         if (strcasecmp(script_names[i], RULES_SCRIPT)) {
644                                 wc_printf("<option %s value=\"%s\">%s</option>\n",
645                                         ((active_script == i) ? "selected" : ""),
646                                         script_names[i],
647                                         script_names[i]
648                                 );
649                         }
650                 }
651                 wc_printf("</select>\n\n");
652         }
653
654         wc_printf("&nbsp;&nbsp;&nbsp;");
655         wc_printf("<a href=\"display_add_remove_scripts\">%s</a>\n", _("Add or delete scripts"));
656
657         wc_printf("<br>\n");
658
659         if (num_scripts > 0) {
660                 for (i=0; i<num_scripts; ++i) {
661                         if (strcasecmp(script_names[i], RULES_SCRIPT)) {
662                                 wc_printf("<div id=\"script_%s\" style=\"display:none\">\n", script_names[i]);
663                                 wc_printf("<textarea name=\"text_%s\" wrap=soft rows=20 cols=80 width=80>\n",
664                                         script_names[i]);
665                                 serv_printf("MSIV getscript|%s", script_names[i]);
666                                 serv_getln(buf, sizeof buf);
667                                 if (buf[0] == '1') while(serv_getln(buf, sizeof (buf)), strcmp(buf, "000")) {
668                                         wc_printf("%s\n", buf);
669                                 }
670                                 wc_printf("</textarea>\n");
671                                 wc_printf("</div>\n");
672                         }
673                 }
674         }
675
676         wc_printf("<script type=\"text/javascript\">    \n"
677                 "ToggleScriptPanels();                  \n"
678                 "</script>                              \n"
679         );
680
681         wc_printf("</div>\n");
682
683
684         /* The rest of this is common for all panels... */
685
686         wc_printf("<div align=\"center\"><br>");
687         wc_printf("<input type=\"submit\" name=\"save_button\" value=\"%s\">", _("Save changes"));
688         wc_printf("&nbsp;");
689         wc_printf("<input type=\"submit\" name=\"cancel_button\" value=\"%s\">\n", _("Cancel"));
690         wc_printf("</div></form>\n");
691
692         wc_printf("</td></tr></table>\n");
693
694         wc_printf("<script type=\"text/javascript\">    \n"
695                 "ToggleSievePanels();                   \n"
696                 "</script>                              \n"
697         );
698
699         wDumpContent(1);
700
701 }
702
703
704
705
706 /*
707  * show a list of available scripts to add/remove them
708  */
709 void display_add_remove_scripts(char *message)
710 {
711         char buf[256];
712         char script_name[256];
713
714         output_headers(1, 1, 2, 0, 0, 0);
715         wc_printf("<div id=\"banner\">\n");
716         wc_printf("<img src=\"static/webcit_icons/essen/32x32/config.png\">");
717         wc_printf(_("Add or delete scripts"));
718         wc_printf("</h1>\n");
719         wc_printf("</div>\n");
720         
721         wc_printf("<div id=\"content\" class=\"service\">\n");
722
723         if (message != NULL) {
724                 wc_printf("%s", message);
725         }
726
727         wc_printf("<table border=0 cellspacing=10><tr valign=top><td>\n");
728
729         do_template("box_begin_1");
730         StrBufAppendBufPlain(WC->WBuf, _("Add a new script"), -1, 0);
731         do_template("box_begin_2");
732
733         wc_printf(_("To create a new script, enter the desired "
734                 "script name in the box below and click 'Create'."));
735         wc_printf("<br><br>");
736
737         wc_printf("<center><form method=\"POST\" action=\"create_script\">\n");
738         wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
739         wc_printf(_("Script name: "));
740         wc_printf("<input type=\"text\" name=\"script_name\"><br>\n"
741                 "<input type=\"submit\" name=\"create_button\" value=\"%s\">"
742                 "</form></center>\n", _("Create"));
743
744         do_template("box_end");
745
746         do_template("box_begin_1");
747         StrBufAppendBufPlain(WC->WBuf, _("Edit scripts"), -1, 0);
748         do_template("box_begin_2");
749         wc_printf("<br><div align=center><a href=\"display_sieve\">%s</a><br><br>\n",
750                 _("Return to the script editing screen")
751         );
752         do_template("box_end");
753
754         wc_printf("</td><td>");
755
756         do_template("box_begin_1");
757         StrBufAppendBufPlain(WC->WBuf, _("Delete scripts"), -1, 0);
758         do_template("box_begin_2");
759
760         wc_printf(_("To delete an existing script, select the script "
761                 "name from the list and click 'Delete'."));
762         wc_printf("<br><br>");
763         
764         wc_printf("<center>"
765                 "<form method=\"POST\" action=\"delete_script\">\n");
766         wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
767         wc_printf("<select name=\"script_name\" size=10 style=\"width:100%%\">\n");
768
769         serv_puts("MSIV listscripts");
770         serv_getln(buf, sizeof buf);
771         if (buf[0] == '1') {
772                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
773                         extract_token(script_name, buf, 0, '|', sizeof script_name);
774                         if ( (extract_int(buf, 1) == 0) && (strcasecmp(script_name, RULES_SCRIPT)) ) {
775                                 wc_printf("<option>");
776                                 escputs(script_name);
777                                 wc_printf("</option>\n");
778                         }
779                 }
780         }
781         wc_printf("</select>\n\n<br>\n");
782
783         wc_printf("<input type=\"submit\" name=\"delete_button\" value=\"%s\" "
784                 "onClick=\"return confirm('%s');\">", _("Delete script"), _("Delete this script?"));
785         wc_printf("</form></center>\n");
786         do_template("box_end");
787
788         wc_printf("</td></tr></table>\n");
789
790         wDumpContent(1);
791 }
792
793
794
795
796
797
798 void display_rules_editor_inner_div(void) {
799         int i, j;
800         char buf[4096];
801         char rules[MAX_RULES][2048];
802
803         struct {
804                 char name[128];
805         } *rooms = NULL;
806         int num_roomnames = 0;
807         int num_roomnames_alloc = 0;
808
809         int active;
810         char hfield[256];
811         char compare[32];
812         char htext[256];
813         char sizecomp[32];
814         int sizeval;
815         char action[32];
816         char fileinto[128];
817         char redirect[256];
818         char automsg[1024];
819         char final[32];
820
821         /* load the rules */
822         memset(rules, 0, sizeof rules);
823         serv_printf("MSIV getscript|%s", RULES_SCRIPT);
824         serv_getln(buf, sizeof buf);
825         if (buf[0] == '1') while(serv_getln(buf, sizeof (buf)), strcmp(buf, "000")) {
826                 if (!strncasecmp(buf, "# WEBCIT_RULE|", 14)) {
827                         j = extract_int(buf, 1);
828                         remove_token(buf, 0, '|');
829                         remove_token(buf, 0, '|');
830                         CtdlDecodeBase64(rules[j], buf, strlen(buf));
831                 }
832         }
833
834         /* load the roomnames */
835         serv_puts("LKRA");
836         serv_getln(buf, sizeof buf);
837         if (buf[0] == '1') {
838                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
839                         ++num_roomnames;
840                         if (num_roomnames > num_roomnames_alloc) {
841                                 num_roomnames_alloc += 250;
842                                 rooms = realloc(rooms, (num_roomnames_alloc * 128));
843                         }
844                         extract_token(rooms[num_roomnames-1].name, buf, 0, '|', 128);
845                 }
846         }
847
848
849 /*
850  * This script should get called by every onChange event...
851  *
852  */
853         wc_printf("<script type=\"text/javascript\">\n"
854                   "\n"
855                   "var highest_active_rule = (-1);\n"
856                   "\n"
857                   "function UpdateRules() {\n");
858 /*
859  * Show only the active rows...
860  */
861         wc_printf("  highest_active_rule = (-1);\n");
862         wc_printf("  for (i=0; i<%d; ++i) {\n", MAX_RULES);
863         wc_printf("   if ($('active'+i).checked) {\n"
864                   "     $('rule' + i).style.display = 'block';\n"
865                   "     highest_active_rule = i;\n"
866                   "   }\n"
867                   "   else {\n"
868                   "     $('rule' + i).style.display = 'none';\n"
869                   "   }\n"
870                   "  }\n");
871 /*
872  * Show only the fields relevant to the rules...
873  */
874         wc_printf("  for (i=0; i<=highest_active_rule; ++i) {\n"
875                   "    d = ($('movedown'+i));\n"
876                   "    if (i < highest_active_rule) {\n"
877                   "      d.style.display = 'block';\n"
878                   "    }\n"
879                   "    else {\n"
880                   "      d.style.display = 'none';\n"
881                   "    }\n"
882                   "    d = ($('hfield'+i).options[$('hfield'+i).selectedIndex].value);\n"
883                   "    if (d == 'all') {\n"
884                   "      $('div_size'+i).style.display = 'none'; \n"
885                   "      $('div_compare'+i).style.display = 'none';\n"
886                   "      $('div_nocompare'+i).style.display = 'block';\n"
887                   "    }\n"
888                   "    else if (d == 'size') {\n"
889                   "      $('div_size'+i).style.display = 'block'; \n"
890                   "      $('div_compare'+i).style.display = 'none';\n"
891                   "      $('div_nocompare'+i).style.display = 'none';\n"
892                   "    }\n"
893                   "    else {\n"
894                   "      $('div_size'+i).style.display = 'none'; \n"
895                   "      $('div_compare'+i).style.display = 'block';\n"
896                   "      $('div_nocompare'+i).style.display = 'none';\n"
897                   "    }\n"
898                   "    d = ($('action'+i).options[$('action'+i).selectedIndex].value);\n"
899                   "    if (d == 'fileinto') {\n"
900                   "      $('div_fileinto'+i).style.display = 'block';\n"
901                   "      $('div_redirect'+i).style.display = 'none';\n"
902                   "      $('div_automsg'+i).style.display = 'none';\n"
903                   "    } else if (d == 'redirect') {\n"
904                   "      $('div_fileinto'+i).style.display = 'none';\n"
905                   "      $('div_redirect'+i).style.display = 'block';\n"
906                   "      $('div_automsg'+i).style.display = 'none';\n"
907                   "    } else if ((d == 'reject') || (d == 'vacation'))  {\n"
908                   "      $('div_fileinto'+i).style.display = 'none';\n"
909                   "      $('div_redirect'+i).style.display = 'none';\n"
910                   "      $('div_automsg'+i).style.display = 'block';\n"
911                   "    } else {\n"
912                   "      $('div_fileinto'+i).style.display = 'none';\n"
913                   "      $('div_redirect'+i).style.display = 'none';\n"
914                   "      $('div_automsg'+i).style.display = 'none';\n"
915                   "    }\n"
916                   "    if (highest_active_rule < %d) {\n", MAX_RULES-1 );
917         wc_printf("      $('div_addrule').style.display = 'block';\n"
918                   "    } else {\n"
919                   "      $('div_addrule').style.display = 'none';\n"
920                   "    }\n"
921                   "  }\n"
922                   "}\n"
923 /*
924  * Add a rule (really, just un-hide it)
925  */
926                   "function AddRule() {\n"
927                   "  highest_active_rule = highest_active_rule + 1;\n"
928                   "  $('active'+highest_active_rule).checked = true;\n"
929                   "  UpdateRules();\n"
930                   "}\n"
931 /*
932  * Swap two rules
933  */
934                   "function SwapRules(ra, rb) {\n"
935                   "\n"
936                   "  var things = new Array();\n"
937                   "  things[0] = 'hfield';\n"
938                   "  things[1] = 'compare';\n"
939                   "  things[2] = 'htext';\n"
940                   "  things[3] = 'action';\n"
941                   "  things[4] = 'fileinto';\n"
942                   "  things[5] = 'redirect';\n"
943                   "  things[6] = 'final';\n"
944                   "  things[7] = 'sizecomp';\n"
945                   "  things[8] = 'sizeval';\n"
946                   "  things[9] = 'automsg';\n"
947                   "\n"
948                   "  for (i=0; i<=9; ++i) {\n"
949                   "    tempval=$(things[i]+ra).value;\n"
950                   "    $(things[i]+ra).value = $(things[i]+rb).value;\n"
951                   "    $(things[i]+rb).value = tempval;\n"
952                   "  }\n"
953                   "}\n"
954 /*
955  * Delete a rule (percolate the deleted rule out to the end, then deactivate it)
956  */
957                   "function DeleteRule(rd) {\n"
958                   "  for (j=rd; j<=highest_active_rule; ++j) {\n"
959                   "    SwapRules(j, (j+1));\n"
960                   "  }\n"
961                   "  $('active'+highest_active_rule).checked = false;\n"
962                   "}\n"
963                   "</script>\n"
964                 );
965
966
967         wc_printf("<br>");
968
969         wc_printf("<table cellpadding=2 width=100%%>");
970
971         for (i=0; i<MAX_RULES; ++i) {
972
973                 /* Grab our existing values to populate */
974                 active = extract_int(rules[i], 0);
975                 extract_token(hfield, rules[i], 1, '|', sizeof hfield);
976                 extract_token(compare, rules[i], 2, '|', sizeof compare);
977                 extract_token(htext, rules[i], 3, '|', sizeof htext);
978                 extract_token(sizecomp, rules[i], 4, '|', sizeof sizecomp);
979                 sizeval = extract_int(rules[i], 5);
980                 extract_token(action, rules[i], 6, '|', sizeof action);
981                 extract_token(fileinto, rules[i], 7, '|', sizeof fileinto);
982                 extract_token(redirect, rules[i], 8, '|', sizeof redirect);
983                 extract_token(automsg, rules[i], 9, '|', sizeof automsg);
984                 extract_token(final, rules[i], 10, '|', sizeof final);
985                 
986                 /* now generate the table row */
987
988                 wc_printf("<tr id=\"rule%d\" class=\"%s\">",
989                         i,
990                         ((i%2) ? "odd" : "even")
991                 );
992
993                 wc_printf("<td width=5%% align=\"center\">\n");
994
995                 wc_printf("<div style=\"display:none\">\n");
996                 wc_printf("<input type=\"checkbox\" name=\"active%d\" id=\"active%d\" %s>\n",
997                         i, i,
998                         (active ? "checked" : "")
999                 );
1000                 wc_printf("</div>\n");
1001
1002                 if (i>0) wc_printf("<a href=\"javascript:SwapRules(%d,%d);UpdateRules();\">"
1003                         "<img border=\"0\" src=\"static/webcit_icons/up_pointer.gif\" "
1004                         "title=\"%s\"/></a>\n",
1005                         i-1, i, _("Move rule up") );
1006
1007                 wc_printf("<a href=\"javascript:SwapRules(%d,%d);UpdateRules();\">"
1008                         "<img id=\"movedown%d\" border=\"0\" src=\"static/webcit_icons/down_pointer.gif\" "
1009                         "title=\"%s\"/></a>\n",
1010                         i, i+1, i, _("Move rule down") );
1011
1012                 wc_printf("<a href=\"javascript:DeleteRule(%d);UpdateRules();\">"
1013                         "<img id=\"delete%d\" border=\"0\" src=\"static/webcit_icons/delete.gif\" "
1014                         "title=\"%s\"/></a>\n",
1015                         i, i, _("Delete rule") );
1016
1017                 wc_printf("</td>\n\n\n");
1018
1019                 wc_printf("<td width=5%% align=\"center\">\n");
1020                 wc_printf("<font size=+2>%d</font>\n", i+1);
1021                 wc_printf("</td>\n");
1022
1023                 wc_printf("<td width=20%%>%s ", _("If") );
1024
1025                 char *hfield_values[15][2] = {
1026                         {       "from",         _("From")               },
1027                         {       "tocc",         _("To or Cc")           },
1028                         {       "subject",      _("Subject")            },
1029                         {       "replyto",      _("Reply-to")           },
1030                         {       "sender",       _("Sender")             },
1031                         {       "resentfrom",   _("Resent-From")        },
1032                         {       "resentto",     _("Resent-To")          },
1033                         {       "envfrom",      _("Envelope From")      },
1034                         {       "envto",        _("Envelope To")        },
1035                         {       "xmailer",      _("X-Mailer")           },
1036                         {       "xspamflag",    _("X-Spam-Flag")        },
1037                         {       "xspamstatus",  _("X-Spam-Status")      },
1038                         {       "listid",       _("List-ID")            },
1039                         {       "size",         _("Message size")       },
1040                         {       "all",          _("All")                }
1041                 };
1042
1043                 wc_printf("<select id=\"hfield%d\" name=\"hfield%d\" size=1 onChange=\"UpdateRules();\">",
1044                         i, i);
1045                 for (j=0; j<15; ++j) {
1046                         wc_printf("<option %s value=\"%s\">%s</option>\n",
1047                                 ( (!strcasecmp(hfield, hfield_values[j][0])) ? "selected" : ""),
1048                                 hfield_values[j][0],
1049                                 hfield_values[j][1]
1050                         );
1051                 }
1052
1053                 wc_printf("</select>\n\n");
1054                 wc_printf("</td>");
1055
1056                 wc_printf("<td width=20%%>");
1057
1058                 char *compare_values[6][2] = {
1059                         {       "contains",     _("contains")           },
1060                         {       "notcontains",  _("does not contain")   },
1061                         {       "is",           _("is")                 },
1062                         {       "isnot",        _("is not")             },
1063                         {       "matches",      _("matches")            },
1064                         {       "notmatches",   _("does not match")     }
1065                 };
1066
1067                 wc_printf("<div id=\"div_compare%d\">\n", i);
1068                 wc_printf("<select id=\"compare%d\" name=\"compare%d\" size=1 onChange=\"UpdateRules();\">\n",
1069                         i, i);
1070                 for (j=0; j<6; ++j) {
1071                         wc_printf("<option %s value=\"%s\">%s</option>\n",
1072                                 ( (!strcasecmp(compare, compare_values[j][0])) ? "selected" : ""),
1073                                 compare_values[j][0],
1074                                 compare_values[j][1]
1075                         );
1076                 }
1077                 wc_printf("</select>\n\n");
1078
1079                 wc_printf("<input type=\"text\" id=\"htext%d\" name=\"htext%d\" value=\"", i, i);
1080                 escputs(htext);
1081                 wc_printf("\">\n</div>\n");
1082
1083                 wc_printf("<div id=\"div_nocompare%d\">", i);
1084                 wc_printf("%s", _("(All messages)"));
1085                 wc_printf("</div>\n");
1086
1087                 char *sizecomp_values[2][2] = {
1088                         {       "larger",       _("is larger than")     },
1089                         {       "smaller",      _("is smaller than")    }
1090                 };
1091
1092                 wc_printf("<div id=\"div_size%d\">\n", i);
1093                 wc_printf("<select id=\"sizecomp%d\" name=\"sizecomp%d\" size=1 onChange=\"UpdateRules();\">\n",
1094                         i, i);
1095                 for (j=0; j<2; ++j) {
1096                         wc_printf("<option %s value=\"%s\">%s</option>\n",
1097                                 ( (!strcasecmp(sizecomp, sizecomp_values[j][0])) ? "selected" : ""),
1098                                 sizecomp_values[j][0],
1099                                 sizecomp_values[j][1]
1100                         );
1101                 }
1102                 wc_printf("</select>\n\n");
1103
1104                 wc_printf("<input type=\"text\" id=\"sizeval%d\" name=\"sizeval%d\" value=\"%d\">",
1105                         i, i, sizeval);
1106                 wc_printf("bytes");
1107                 wc_printf("</div>");
1108
1109                 wc_printf("</td>");
1110
1111                 char *action_values[6][2] = {
1112                         {       "keep",         _("Keep")               },
1113                         {       "discard",      _("Discard silently")   },
1114                         {       "reject",       _("Reject")             },
1115                         {       "fileinto",     _("Move message to")    },
1116                         {       "redirect",     _("Forward to")         },
1117                         {       "vacation",     _("Vacation")           }
1118                 };
1119
1120                 wc_printf("<td width=20%%>\n");
1121                 wc_printf("<select id=\"action%d\" name=\"action%d\" size=1 onChange=\"UpdateRules();\">\n",
1122                         i, i);
1123                 for (j=0; j<6; ++j) {
1124                         wc_printf("<option %s value=\"%s\">%s</option>\n",
1125                                 ( (!strcasecmp(action, action_values[j][0])) ? "selected" : ""),
1126                                 action_values[j][0],
1127                                 action_values[j][1]
1128                         );
1129                 }
1130                 wc_printf("</select>\n\n");
1131
1132                 wc_printf("<div id=\"div_fileinto%d\">\n", i);
1133                 wc_printf("<select name=\"fileinto%d\" id=\"fileinto%d\">\n", i, i);
1134                 for (j=0; j<num_roomnames; ++j) {
1135                         wc_printf("<option ");
1136                         if (!strcasecmp(rooms[j].name, fileinto)) {
1137                                 wc_printf("selected ");
1138                         }
1139                         wc_printf("value=\"");
1140                         escputs(rooms[j].name);
1141                         wc_printf("\">");
1142                         escputs(rooms[j].name);
1143                         wc_printf("</option>\n");
1144                 }
1145                 wc_printf("</select>\n\n");
1146                 wc_printf("</div>");
1147
1148                 wc_printf("<div id=\"div_redirect%d\">\n", i);
1149                 wc_printf("<input type=\"text\" id=\"redirect%d\" name=\"redirect%d\" value=\"", i, i);
1150                 escputs(redirect);
1151                 wc_printf("\">\n</div>\n");
1152
1153                 wc_printf("<div id=\"div_automsg%d\">\n", i);
1154                 wc_printf(_("Message:"));
1155                 wc_printf("<br>\n");
1156                 wc_printf("<textarea name=\"automsg%d\" id=\"automsg%d\" wrap=soft rows=5>\n", i, i);
1157                 escputs(automsg);
1158                 wc_printf("</textarea>");
1159                 wc_printf("</div>\n");
1160
1161                 wc_printf("</td>\n");
1162
1163                 char *final_values[2][2] = {
1164                         {       "continue",     _("continue processing")        },
1165                         {       "stop",         _("stop")                       }
1166                 };
1167
1168                 wc_printf("<td width=10%% align=\"center\">%s</td>\n", _("and then") );
1169
1170                 wc_printf("<td width=20%%>\n");
1171                 wc_printf("<select name=\"final%d\" id=\"final%d\" size=1 onChange=\"UpdateRules();\">\n",
1172                         i, i);
1173                 for (j=0; j<2; ++j) {
1174                         wc_printf("<option %s value=\"%s\">%s</option>\n",
1175                                 ( (!strcasecmp(final, final_values[j][0])) ? "selected" : ""),
1176                                 final_values[j][0],
1177                                 final_values[j][1]
1178                         );
1179                 }
1180                 wc_printf("</select>\n\n");
1181                 wc_printf("</td>\n");
1182
1183                 wc_printf("</tr>\n");
1184
1185         }
1186
1187         wc_printf("</table>\n");
1188         wc_printf("<div id=\"div_addrule\"><a href=\"javascript:AddRule();\">%s</a><br></div>\n",
1189                 _("Add rule")
1190         );
1191
1192         wc_printf("<script type=\"text/javascript\">\n");
1193         wc_printf("UpdateRules();\n");
1194         wc_printf("</script>\n");
1195
1196         free(rooms);
1197 }
1198 void _display_add_remove_scripts(void) {display_add_remove_scripts(NULL);}
1199 #endif
1200
1201
1202 typedef struct __SieveListing {
1203         int IsActive;
1204         int IsRulesScript;
1205         StrBuf *Name;
1206         StrBuf *Content;
1207 } SieveListing;
1208
1209 int ConditionalSieveScriptIsActive(StrBuf *Target, WCTemplputParams *TP)
1210 {
1211         SieveListing     *SieveList = (SieveListing *)CTX;
1212         return SieveList->IsActive;
1213 }
1214 int ConditionalSieveScriptIsRulesScript(StrBuf *Target, WCTemplputParams *TP)
1215 {
1216         SieveListing     *SieveList = (SieveListing *)CTX;
1217         return SieveList->IsActive;
1218 }
1219 void tmplput_SieveScriptName(StrBuf *Target, WCTemplputParams *TP) 
1220 {
1221         SieveListing     *SieveList = (SieveListing *)CTX;
1222         StrBufAppendTemplate(Target, TP, SieveList->Name, 0);
1223 }
1224 void tmplput_SieveScriptContent(StrBuf *Target, WCTemplputParams *TP) 
1225 {
1226         SieveListing     *SieveList = (SieveListing *)CTX;
1227         StrBufAppendTemplate(Target, TP, SieveList->Content, 0);
1228 }
1229 void FreeSieveListing(void *vSieveListing)
1230 {
1231         SieveListing *List = (SieveListing*) vSieveListing;
1232
1233         FreeStrBuf(&List->Name);
1234         free(List);
1235 }
1236
1237 HashList *GetSieveScriptListing(StrBuf *Target, WCTemplputParams *TP)
1238 {
1239         wcsession *WCC = WC;
1240         StrBuf *Line;
1241         int num_scripts = 0;
1242         int rules_script_active = 0;
1243         int have_rules_script = 0;
1244         const char *pch;
1245         HashPos  *it;
1246         int Done = 0;
1247         SieveListing *Ruleset;
1248
1249         if (WCC->KnownSieveScripts != NULL)
1250                 return WCC->KnownSieveScripts;
1251
1252         serv_puts("MSIV listscripts");
1253         Line = NewStrBuf();
1254         StrBuf_ServGetln(Line);
1255         if (GetServerStatus(Line, NULL) == 1) 
1256         {
1257                 WCC->KnownSieveScripts = NewHash(1, Flathash);
1258
1259                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
1260                         if ( (StrLength(Line)==3) && 
1261                              !strcmp(ChrPtr(Line), "000")) 
1262                         {
1263                                 Done = 1;
1264                         }
1265                         else
1266                         {
1267                                 pch = NULL;
1268                                 Ruleset = (SieveListing *) malloc(sizeof(SieveListing));
1269                                 Ruleset->Name = NewStrBufPlain(NULL, StrLength(Line));
1270                                 StrBufExtract_NextToken(Ruleset->Name, Line, &pch, '|');
1271                                 Ruleset->IsActive = StrBufExtractNext_int(Line, &pch, '|'); 
1272                                 Ruleset->Content = NULL;
1273
1274                                 if (!strcasecmp(ChrPtr(Ruleset->Name), RULES_SCRIPT))
1275                                 {
1276                                         Ruleset->IsRulesScript = 1;
1277                                         have_rules_script = 1;
1278                                         if (Ruleset->IsActive)
1279                                         {
1280                                                 rules_script_active = 1;
1281                                                 PutBstr(HKEY("__SIEVE:RULESSCRIPT"), NewStrBufPlain(HKEY("1")));
1282                                         }
1283                                 }
1284                                 Put(WCC->KnownSieveScripts, IKEY(num_scripts), Ruleset, FreeSieveListing);
1285
1286                                 ++num_scripts;
1287                         }
1288         }
1289         if ((num_scripts > 0) && (rules_script_active == 0))
1290                 PutBstr(HKEY("__SIEVE:EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
1291
1292         if (num_scripts > have_rules_script)
1293         {
1294                 long rc = 0;
1295                 long len;
1296                 const char *Key;
1297                 void *vRuleset;
1298
1299                 /* 
1300                  * ok; we have custom scripts, expose that via bstr, and load the payload.
1301                  */
1302                 PutBstr(HKEY("__SIEVE:HAVE_EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
1303
1304                 it = GetNewHashPos(WCC->KnownSieveScripts, 0);
1305                 while (GetNextHashPos(WCC->KnownSieveScripts, it, &len, &Key, &vRuleset) && 
1306                        (vRuleset != NULL))
1307                 {
1308                         Ruleset = (SieveListing *) vRuleset;
1309
1310                         /*
1311                          * its the webcit rule? we don't need to load that here.
1312                          */
1313                         if (Ruleset->IsRulesScript)
1314                                 continue;
1315
1316                         if (!serv_printf("MSIV getscript|%s", ChrPtr(Ruleset->Name)))
1317                                 break;
1318                         StrBuf_ServGetln(Line);
1319                         if (GetServerStatus(Line, NULL) == 1) 
1320                         {
1321                                 Ruleset->Content = NewStrBuf();
1322                                 while(!Done && (rc = StrBuf_ServGetln(Line), rc >= 0) )
1323                                         if ( (StrLength(Line)==3) && 
1324                                              !strcmp(ChrPtr(Line), "000")) 
1325                                         {
1326                                                 Done = 1;
1327                                         }
1328                                         else
1329                                         {
1330                                                 if (StrLength(Ruleset->Content)>0)
1331                                                         StrBufAppendBufPlain(Ruleset->Content, HKEY("\n"), 0);
1332                                                 StrBufAppendBuf(Ruleset->Content, Line, 0);
1333                                         }
1334                                 if (rc < 0) break;
1335                         }
1336                 }
1337         }
1338         FreeStrBuf(&Line);
1339         return WCC->KnownSieveScripts;
1340 }
1341
1342
1343 typedef enum __eSieveHfield 
1344 {
1345         from,           
1346         tocc,           
1347         subject,        
1348         replyto,        
1349         sender, 
1350         resentfrom,     
1351         resentto,       
1352         envfrom,        
1353         envto,  
1354         xmailer,        
1355         xspamflag,      
1356         xspamstatus,    
1357         listid, 
1358         size,           
1359         all
1360 } eSieveHfield;
1361
1362 typedef enum __eSieveCompare {
1363         contains,
1364         notcontains,
1365         is,
1366         isnot,
1367         matches,
1368         notmatches
1369 } eSieveCompare;
1370
1371 typedef enum __eSieveAction {
1372         keep,
1373         discard,
1374         reject,
1375         fileinto,
1376         redirect,
1377         vacation
1378 } eSieveAction;
1379
1380
1381 typedef enum __eSieveSizeComp {
1382         larger,
1383         smaller
1384 } eSieveSizeComp;
1385
1386 typedef enum __eSieveFinal {
1387         econtinue,
1388         estop
1389 } eSieveFinal;
1390
1391
1392 typedef struct __SieveRule {
1393         int active;
1394         int sizeval;
1395         eSieveHfield hfield;
1396         eSieveCompare compare;
1397         StrBuf *htext;
1398         eSieveSizeComp sizecomp;
1399         eSieveAction Action;
1400         StrBuf *fileinto;
1401         StrBuf *redirect;
1402         StrBuf *automsg;
1403         eSieveFinal final;
1404 }SieveRule;
1405
1406
1407
1408 int ConditionalSieveRule_hfield(StrBuf *Target, WCTemplputParams *TP)
1409 {
1410         SieveRule     *Rule = (SieveRule *)CTX;
1411         
1412         return GetTemplateTokenNumber(Target, 
1413                                       TP, 
1414                                       3, 
1415                                       from)
1416                 ==
1417                 Rule->hfield;
1418 }
1419 int ConditionalSieveRule_compare(StrBuf *Target, WCTemplputParams *TP)
1420 {
1421         SieveRule     *Rule = (SieveRule *)CTX;
1422         return GetTemplateTokenNumber(Target, 
1423                                       TP, 
1424                                       3, 
1425                                       contains)
1426                 ==
1427                 Rule->compare;
1428 }
1429 int ConditionalSieveRule_action(StrBuf *Target, WCTemplputParams *TP)
1430 {
1431         SieveRule     *Rule = (SieveRule *)CTX;
1432         return GetTemplateTokenNumber(Target, 
1433                                       TP, 
1434                                       3, 
1435                                       keep)
1436                 ==
1437                 Rule->Action; 
1438 }
1439 int ConditionalSieveRule_sizecomp(StrBuf *Target, WCTemplputParams *TP)
1440 {
1441         SieveRule     *Rule = (SieveRule *)CTX;
1442         return GetTemplateTokenNumber(Target, 
1443                                       TP, 
1444                                       3, 
1445                                       larger)
1446                 ==
1447                 Rule->sizecomp;
1448 }
1449 int ConditionalSieveRule_final(StrBuf *Target, WCTemplputParams *TP)
1450 {
1451         SieveRule     *Rule = (SieveRule *)CTX;
1452         return GetTemplateTokenNumber(Target, 
1453                                       TP, 
1454                                       3, 
1455                                       econtinue)
1456                 ==
1457                 Rule->final;
1458 }
1459 int ConditionalSieveRule_ThisRoom(StrBuf *Target, WCTemplputParams *TP)
1460 {
1461         SieveRule     *Rule = (SieveRule *)CTX;
1462         return GetTemplateTokenNumber(Target, 
1463                                       TP, 
1464                                       3, 
1465                                       econtinue)
1466                 ==
1467                 Rule->final;
1468 }
1469 int ConditionalSieveRule_Active(StrBuf *Target, WCTemplputParams *TP)
1470 {
1471         SieveRule     *Rule = (SieveRule *)CTX;
1472         return Rule->active;
1473 }
1474 void tmplput_SieveRule_htext(StrBuf *Target, WCTemplputParams *TP) 
1475 {
1476         SieveRule     *Rule = (SieveRule *)CTX;
1477         StrBufAppendTemplate(Target, TP, Rule->htext, 0);
1478 }
1479 void tmplput_SieveRule_fileinto(StrBuf *Target, WCTemplputParams *TP) 
1480 {
1481         SieveRule     *Rule = (SieveRule *)CTX;
1482         StrBufAppendTemplate(Target, TP, Rule->fileinto, 0);
1483 }
1484 void tmplput_SieveRule_redirect(StrBuf *Target, WCTemplputParams *TP) 
1485 {
1486         SieveRule     *Rule = (SieveRule *)CTX;
1487         StrBufAppendTemplate(Target, TP, Rule->redirect, 0);
1488 }
1489 void tmplput_SieveRule_automsg(StrBuf *Target, WCTemplputParams *TP) 
1490 {
1491         SieveRule     *Rule = (SieveRule *)CTX;
1492         StrBufAppendTemplate(Target, TP, Rule->automsg, 0);
1493 }
1494 void tmplput_SieveRule_sizeval(StrBuf *Target, WCTemplputParams *TP) 
1495 {
1496         SieveRule     *Rule = (SieveRule *)CTX;
1497         StrBufAppendPrintf(Target, "%d", Rule->sizeval);
1498 }
1499
1500 void tmplput_SieveRule_lookup_FileIntoRoom(StrBuf *Target, WCTemplputParams *TP) 
1501 {
1502         void *vRoom;
1503         SieveRule     *Rule = (SieveRule *)CTX;
1504         wcsession *WCC = WC;
1505         HashList *Rooms = GetRoomListHashLKRA(Target, TP);
1506
1507         GetHash(Rooms, SKEY(Rule->fileinto), &vRoom);
1508         WCC->ThisRoom = (folder*) vRoom;
1509 }
1510
1511 void FreeSieveRule(void *vRule)
1512 {
1513         SieveRule *Rule = (SieveRule*) vRule;
1514
1515         FreeStrBuf(&Rule->htext);
1516         FreeStrBuf(&Rule->fileinto);
1517         FreeStrBuf(&Rule->redirect);
1518         FreeStrBuf(&Rule->automsg);
1519         
1520         free(Rule);
1521 }
1522
1523 #define WC_RULE_HEADER "# WEBCIT_RULE|"
1524 HashList *GetSieveRules(StrBuf *Target, WCTemplputParams *TP)
1525 {
1526         StrBuf *Line;
1527         StrBuf *EncodedRule;
1528         int n;
1529         const char *pch;
1530         HashList *SieveRules = NULL;
1531         int Done = 0;
1532         SieveRule *Rule;
1533
1534         serv_printf("MSIV getscript|"RULES_SCRIPT);
1535         Line = NewStrBuf();
1536         EncodedRule = NewStrBuf();
1537         StrBuf_ServGetln(Line);
1538         if (GetServerStatus(Line, NULL) == 1) 
1539         {
1540                 SieveRules = NewHash(1, Flathash);
1541
1542                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
1543                         if ( (StrLength(Line)==3) && 
1544                              !strcmp(ChrPtr(Line), "000")) 
1545                         {
1546                                 Done = 1;
1547                         }
1548                         else
1549                         {
1550                                 pch = NULL;
1551                                 /* We just care for our encoded header and skip everything else */
1552                                 if ((StrLength(Line) > sizeof(WC_RULE_HEADER) - 1) &&
1553                                     (!strncasecmp(ChrPtr(Line), HKEY(WC_RULE_HEADER))))
1554                                 {
1555                                         StrBufSkip_NTokenS(Line, &pch, '|', 1);
1556                                         n = StrBufExtractNext_int(Line, &pch, '|'); 
1557                                         StrBufExtract_NextToken(EncodedRule, Line, &pch, '|');
1558                                         StrBufDecodeBase64(EncodedRule);
1559
1560                                         Rule = (SieveRule*) malloc(sizeof(SieveRule));
1561
1562                                         Rule->htext = NewStrBufPlain (NULL, StrLength(EncodedRule));
1563
1564                                         Rule->fileinto = NewStrBufPlain (NULL, StrLength(EncodedRule));
1565                                         Rule->redirect = NewStrBufPlain (NULL, StrLength(EncodedRule));
1566                                         Rule->automsg = NewStrBufPlain (NULL, StrLength(EncodedRule));
1567
1568                                         /* Grab our existing values to populate */
1569                                         pch = NULL;
1570                                         Rule->active = StrBufExtractNext_int(EncodedRule, &pch, '|');
1571                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
1572                                         
1573                                         Rule->hfield = (eSieveHfield) GetTokenDefine(SKEY(Line), tocc);
1574                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
1575                                         Rule->compare = (eSieveCompare) GetTokenDefine(SKEY(Line), contains);
1576                                         StrBufExtract_NextToken(Rule->htext, EncodedRule, &pch, '|');
1577                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
1578                                         Rule->sizecomp = (eSieveSizeComp) GetTokenDefine(SKEY(Line), larger);
1579                                         Rule->sizeval = StrBufExtractNext_int(EncodedRule, &pch, '|');
1580                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
1581                                         Rule->Action = (eSieveAction) GetTokenDefine(SKEY(Line), keep);
1582                                         StrBufExtract_NextToken(Rule->fileinto, EncodedRule, &pch, '|');
1583                                         StrBufExtract_NextToken(Rule->redirect, EncodedRule, &pch, '|');
1584                                         StrBufExtract_NextToken(Rule->automsg, EncodedRule, &pch, '|');
1585                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
1586                                         Rule->final = (eSieveFinal) GetTokenDefine(SKEY(Line), econtinue);
1587                                         Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
1588                                         n++;
1589                                 }
1590                         }
1591         }
1592
1593         while (n < MAX_RULES) {
1594                 Rule = (SieveRule*) malloc(sizeof(SieveRule));
1595                 memset(Rule, 0, sizeof(SieveRule));
1596                 Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
1597             
1598                 n++;
1599         }
1600
1601
1602         FreeStrBuf(&EncodedRule);
1603         FreeStrBuf(&Line);
1604         return SieveRules;
1605 }
1606
1607 void
1608 SessionDetachModule_SIEVE
1609 (wcsession *sess)
1610 {
1611         DeleteHash(&sess->KnownSieveScripts);
1612 }
1613
1614 void 
1615 InitModule_SIEVE
1616 (void)
1617 {
1618         REGISTERTokenParamDefine(from);         
1619         REGISTERTokenParamDefine(tocc);         
1620         REGISTERTokenParamDefine(subject);      
1621         REGISTERTokenParamDefine(replyto);      
1622         REGISTERTokenParamDefine(sender);       
1623         REGISTERTokenParamDefine(resentfrom);   
1624         REGISTERTokenParamDefine(resentto);     
1625         REGISTERTokenParamDefine(envfrom);      
1626         REGISTERTokenParamDefine(envto);        
1627         REGISTERTokenParamDefine(xmailer);      
1628         REGISTERTokenParamDefine(xspamflag);    
1629         REGISTERTokenParamDefine(xspamstatus);  
1630         REGISTERTokenParamDefine(listid);       
1631         REGISTERTokenParamDefine(size);         
1632         REGISTERTokenParamDefine(all);
1633
1634         REGISTERTokenParamDefine(contains);
1635         REGISTERTokenParamDefine(notcontains);
1636         REGISTERTokenParamDefine(is);
1637         REGISTERTokenParamDefine(isnot);
1638         REGISTERTokenParamDefine(matches);
1639         REGISTERTokenParamDefine(notmatches);
1640
1641         REGISTERTokenParamDefine(keep);
1642         REGISTERTokenParamDefine(discard);
1643         REGISTERTokenParamDefine(reject);
1644         REGISTERTokenParamDefine(fileinto);
1645         REGISTERTokenParamDefine(redirect);
1646         REGISTERTokenParamDefine(vacation);
1647
1648         REGISTERTokenParamDefine(larger);
1649         REGISTERTokenParamDefine(smaller);
1650
1651         /* these are c-keyworads, so do it by hand. */
1652         RegisterTokenParamDefine(HKEY("continue"), econtinue);
1653         RegisterTokenParamDefine(HKEY("stop"), estop);
1654
1655         RegisterIterator("SIEVE:SCRIPTS", 0, NULL, GetSieveScriptListing, NULL, NULL, CTX_SIEVELIST, CTX_NONE, IT_NOFLAG);
1656
1657         RegisterConditional(HKEY("COND:SIEVE:SCRIPT:ACTIVE"), 0, ConditionalSieveScriptIsActive, CTX_SIEVELIST);
1658         RegisterConditional(HKEY("COND:SIEVE:SCRIPT:ISRULES"), 0, ConditionalSieveScriptIsRulesScript, CTX_SIEVELIST);
1659         RegisterNamespace("SIEVE:SCRIPT:NAME", 0, 1, tmplput_SieveScriptName, NULL, CTX_SIEVELIST);
1660         RegisterNamespace("SIEVE:SCRIPT:CONTENT", 0, 1, tmplput_SieveScriptContent, NULL, CTX_SIEVELIST);
1661
1662  
1663         RegisterIterator("SIEVE:RULES", 0, NULL, GetSieveRules, NULL, DeleteHash, CTX_SIEVESCRIPT, CTX_NONE, IT_NOFLAG);
1664
1665         RegisterConditional(HKEY("COND:SIEVE:ACTIVE"), 1, ConditionalSieveRule_Active, CTX_SIEVESCRIPT);
1666         RegisterConditional(HKEY("COND:SIEVE:HFIELD"), 1, ConditionalSieveRule_hfield, CTX_SIEVESCRIPT);
1667         RegisterConditional(HKEY("COND:SIEVE:COMPARE"), 1, ConditionalSieveRule_compare, CTX_SIEVESCRIPT);
1668         RegisterConditional(HKEY("COND:SIEVE:ACTION"), 1, ConditionalSieveRule_action, CTX_SIEVESCRIPT);
1669         RegisterConditional(HKEY("COND:SIEVE:SIZECOMP"), 1, ConditionalSieveRule_sizecomp, CTX_SIEVESCRIPT);
1670         RegisterConditional(HKEY("COND:SIEVE:FINAL"), 1, ConditionalSieveRule_final, CTX_SIEVESCRIPT);
1671         RegisterConditional(HKEY("COND:SIEVE:THISROOM"), 1, ConditionalSieveRule_ThisRoom, CTX_SIEVESCRIPT);
1672
1673         RegisterNamespace("SIEVE:SCRIPT:HTEXT", 0, 1, tmplput_SieveRule_htext, NULL, CTX_SIEVESCRIPT);
1674         RegisterNamespace("SIEVE:SCRIPT:SIZE", 0, 1, tmplput_SieveRule_sizeval, NULL, CTX_SIEVESCRIPT);
1675         RegisterNamespace("SIEVE:SCRIPT:FILEINTO", 0, 1, tmplput_SieveRule_fileinto, NULL, CTX_SIEVESCRIPT);
1676         RegisterNamespace("SIEVE:SCRIPT:REDIRECT", 0, 1, tmplput_SieveRule_redirect, NULL, CTX_SIEVESCRIPT);
1677         RegisterNamespace("SIEVE:SCRIPT:AUTOMSG", 0, 1, tmplput_SieveRule_automsg, NULL, CTX_SIEVESCRIPT);
1678
1679         /* fetch our room into WCC->ThisRoom, to evaluate while iterating over rooms with COND:THIS:THAT:ROOM */
1680         RegisterNamespace("SIEVE:SCRIPT:LOOKUP_FILEINTO", 0, 1, tmplput_SieveRule_lookup_FileIntoRoom, NULL, CTX_SIEVESCRIPT);
1681
1682 #if FOO
1683         WebcitAddUrlHandler(HKEY("display_sieve"), "", 0, display_sieve, 0);
1684         WebcitAddUrlHandler(HKEY("display_add_remove_scripts"), "", 0, _display_add_remove_scripts, 0);
1685 #endif
1686         WebcitAddUrlHandler(HKEY("save_sieve"), "", 0, save_sieve, 0);
1687
1688         WebcitAddUrlHandler(HKEY("create_script"), "", 0, create_script, 0);
1689         WebcitAddUrlHandler(HKEY("delete_script"), "", 0, delete_script, 0);
1690 }