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