Templatize sieve rules editor; return success/fail state of serverwrite
[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 /*
27  * Helper function for output_sieve_rule() to output strings with quotes escaped
28  */
29 void osr_sanitize(char *str) {
30         int i, len;
31
32         if (str == NULL) return;
33         len = strlen(str);
34         for (i=0; i<len; ++i) {
35                 if (str[i]=='\"') {
36                         str[i] = '\'' ;
37                 }
38                 else if (isspace(str[i])) {
39                         str[i] = ' ';
40                 }
41         }
42 }
43
44 void display_add_remove_scripts(char *message);
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 #endif
470                 return;
471         }
472
473 #if FOO
474         display_add_remove_scripts(&buf[4]);
475 #endif
476 }
477
478
479
480
481 /*
482  * delete a script
483  */
484 void delete_script(void) {
485         char buf[256];
486
487         serv_printf("MSIV deletescript|%s", bstr("script_name"));
488         serv_getln(buf, sizeof buf);
489 #if FOO
490         display_add_remove_scripts(&buf[4]);
491 #endif
492 }
493                 
494
495
496 /*
497  * dummy panel indicating to the user that the server doesn't support Sieve
498  */
499 void display_no_sieve(void) {
500
501         output_headers(1, 1, 2, 0, 0, 0);
502         do_template("sieve_none");
503         wDumpContent(1);
504 }
505
506 #if FOO
507 /*
508  * view/edit sieve config
509  */
510 void display_sieve(void)
511 {
512         char script_names[MAX_SCRIPTS][64];
513         int num_scripts = 0;
514         int active_script = (-1);
515         char buf[SIZ];          /* Don't make this buffer smaller or it will restrict line length */
516         int i;
517         int rules_script_is_active = 0;
518
519         if (!WC->serv_info->serv_supports_sieve) {
520                 display_no_sieve();
521                 return;
522         }
523
524         memset(script_names, 0, sizeof script_names);
525
526         serv_puts("MSIV listscripts");
527         serv_getln(buf, sizeof(buf));
528         if (buf[0] == '1') while (serv_getln(buf, sizeof(buf)), strcmp(buf, "000")) {
529                 if (num_scripts < MAX_SCRIPTS) {
530                         extract_token(script_names[num_scripts], buf, 0, '|', 64);
531                         if (extract_int(buf, 1) > 0) {
532                                 active_script = num_scripts;
533                                 if (!strcasecmp(script_names[num_scripts], RULES_SCRIPT)) {
534                                         rules_script_is_active = 1;
535                                 }
536                         }
537                         ++num_scripts;
538                 }
539         }
540
541         output_headers(1, 1, 2, 0, 0, 0);
542
543         wc_printf("<script type=\"text/javascript\">                                    \n"
544                 "                                                                       \n"
545                 "var previously_active_script;                                          \n"
546                 "                                                                       \n"
547                 "function ToggleSievePanels() {                                         \n"
548                 " d = ($('sieveform').bigaction.options[$('sieveform').bigaction.selectedIndex].value); \n"
549                 " for (i=0; i<3; ++i) {                                                 \n"
550                 "  if (i == d) {                                                        \n"
551                 "   $('sievediv' + i).style.display = 'block';                          \n"
552                 "  }                                                                    \n"
553                 "  else {                                                               \n"
554                 "   $('sievediv' + i).style.display = 'none';                           \n"
555                 "  }                                                                    \n"
556                 " }                                                                     \n"
557                 "}                                                                      \n"
558                 "                                                                       \n"
559                 "function ToggleScriptPanels() {                                        \n"
560                 " d = ($('sieveform').active_script.options[$('sieveform').active_script.selectedIndex].value); \n"
561                 " if ($('script_' + previously_active_script)) {                        \n"
562                 "  $('script_' + previously_active_script).style.display = 'none';      \n"
563                 " }                                                                     \n"
564                 " $('script_' + d).style.display = 'block';                             \n"
565                 " previously_active_script = d;                                         \n"
566                 "}                                                                      \n"
567                 "                                                                       \n"
568                 "</script>                                                              \n"
569         );
570
571         wc_printf("<div id=\"banner\">\n");
572         wc_printf("<img src=\"static/advanpage2_48x.gif\">");
573         wc_printf("<h1>");
574         wc_printf(_("View/edit server-side mail filters"));
575         wc_printf("</h1>\n");
576         wc_printf("</div>\n");
577
578         wc_printf("<div id=\"content\" class=\"service\">\n");
579
580         wc_printf("<table class=\"sieve_background\">"
581                 "<tr><td valign=top>\n");
582
583
584         wc_printf("<form id=\"sieveform\" method=\"post\" action=\"save_sieve\">\n");
585         wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
586
587         wc_printf(_("When new mail arrives: "));
588         wc_printf("<select name=\"bigaction\" size=1 onChange=\"ToggleSievePanels();\">\n");
589
590         wc_printf("<option %s value=\"0\">", ((active_script < 0) ? "selected" : ""));
591         wc_printf(_("Leave it in my inbox without filtering"));
592         wc_printf("</option>\n");
593
594         wc_printf("<option %s value=\"1\">", ((rules_script_is_active) ? "selected" : ""));
595         wc_printf(_("Filter it according to rules selected below"));
596         wc_printf("</option>\n");
597
598         wc_printf("<option %s value=\"2\">",
599                         (((active_script >= 0) && (!rules_script_is_active)) ? "selected" : ""));
600         wc_printf(_("Filter it through a manually edited script (advanced users only)"));
601         wc_printf("</option>\n");
602
603         wc_printf("</select>");
604
605
606
607         /* The "no filtering" div */
608
609         wc_printf("<div id=\"sievediv0\" style=\"display:none\">\n");
610         wc_printf("<div align=\"center\"><br><br>");
611         wc_printf(_("Your incoming mail will not be filtered through any scripts."));
612         wc_printf("<br><br></div>\n");
613         wc_printf("</div>\n");
614
615         /* The "webcit managed scripts" div */
616
617         wc_printf("<div id=\"sievediv1\" style=\"display:none\">\n");
618         display_rules_editor_inner_div();
619         wc_printf("</div>\n");
620
621         /* The "I'm smart and can write my own Sieve scripts" div */
622
623         wc_printf("<div id=\"sievediv2\" style=\"display:none\">\n");
624
625         if (num_scripts > 0) {
626                 wc_printf(_("The currently active script is: "));
627                 wc_printf("<select name=\"active_script\" size=1 onChange=\"ToggleScriptPanels();\">\n");
628                 for (i=0; i<num_scripts; ++i) {
629                         if (strcasecmp(script_names[i], RULES_SCRIPT)) {
630                                 wc_printf("<option %s value=\"%s\">%s</option>\n",
631                                         ((active_script == i) ? "selected" : ""),
632                                         script_names[i],
633                                         script_names[i]
634                                 );
635                         }
636                 }
637                 wc_printf("</select>\n");
638         }
639
640         wc_printf("&nbsp;&nbsp;&nbsp;");
641         wc_printf("<a href=\"display_add_remove_scripts\">%s</a>\n", _("Add or delete scripts"));
642
643         wc_printf("<br>\n");
644
645         if (num_scripts > 0) {
646                 for (i=0; i<num_scripts; ++i) {
647                         if (strcasecmp(script_names[i], RULES_SCRIPT)) {
648                                 wc_printf("<div id=\"script_%s\" style=\"display:none\">\n", script_names[i]);
649                                 wc_printf("<textarea name=\"text_%s\" wrap=soft rows=20 cols=80 width=80>\n",
650                                         script_names[i]);
651                                 serv_printf("MSIV getscript|%s", script_names[i]);
652                                 serv_getln(buf, sizeof buf);
653                                 if (buf[0] == '1') while(serv_getln(buf, sizeof (buf)), strcmp(buf, "000")) {
654                                         wc_printf("%s\n", buf);
655                                 }
656                                 wc_printf("</textarea>\n");
657                                 wc_printf("</div>\n");
658                         }
659                 }
660         }
661
662         wc_printf("<script type=\"text/javascript\">    \n"
663                 "ToggleScriptPanels();                  \n"
664                 "</script>                              \n"
665         );
666
667         wc_printf("</div>\n");
668
669
670         /* The rest of this is common for all panels... */
671
672         wc_printf("<div align=\"center\"><br>");
673         wc_printf("<input type=\"submit\" name=\"save_button\" value=\"%s\">", _("Save changes"));
674         wc_printf("&nbsp;");
675         wc_printf("<input type=\"submit\" name=\"cancel_button\" value=\"%s\">\n", _("Cancel"));
676         wc_printf("</div></form>\n");
677
678         wc_printf("</td></tr></table>\n");
679
680         wc_printf("<script type=\"text/javascript\">    \n"
681                 "ToggleSievePanels();                   \n"
682                 "</script>                              \n"
683         );
684
685         wDumpContent(1);
686
687 }
688
689
690
691
692 /*
693  * show a list of available scripts to add/remove them
694  */
695 void display_add_remove_scripts(char *message)
696 {
697         char buf[256];
698         char script_name[256];
699
700         output_headers(1, 1, 2, 0, 0, 0);
701         wc_printf("<div id=\"banner\">\n");
702         wc_printf("<img src=\"static/icons/essen/32x32/config.png\">");
703         wc_printf(_("Add or delete scripts"));
704         wc_printf("</h1>\n");
705         wc_printf("</div>\n");
706         
707         wc_printf("<div id=\"content\" class=\"service\">\n");
708
709         if (message != NULL) {
710                 wc_printf("%s", message);
711         }
712
713         wc_printf("<table border=0 cellspacing=10><tr valign=top><td>\n");
714
715         do_template("beginbox_1");
716         StrBufAppendBufPlain(WC->WBuf, _("Add a new script"), -1, 0);
717         do_template("beginbox_2");
718
719         wc_printf(_("To create a new script, enter the desired "
720                 "script name in the box below and click 'Create'."));
721         wc_printf("<br><br>");
722
723         wc_printf("<center><form method=\"POST\" action=\"create_script\">\n");
724         wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
725         wc_printf(_("Script name: "));
726         wc_printf("<input type=\"text\" name=\"script_name\"><br>\n"
727                 "<input type=\"submit\" name=\"create_button\" value=\"%s\">"
728                 "</form></center>\n", _("Create"));
729
730         do_template("endbox");
731
732         do_template("beginbox_1");
733         StrBufAppendBufPlain(WC->WBuf, _("Edit scripts"), -1, 0);
734         do_template("beginbox_2");
735         wc_printf("<br><div align=center><a href=\"display_sieve\">%s</a><br><br>\n",
736                 _("Return to the script editing screen")
737         );
738         do_template("endbox");
739
740         wc_printf("</td><td>");
741
742         do_template("beginbox_1");
743         StrBufAppendBufPlain(WC->WBuf, _("Delete scripts"), -1, 0);
744         do_template("beginbox_2");
745
746         wc_printf(_("To delete an existing script, select the script "
747                 "name from the list and click 'Delete'."));
748         wc_printf("<br><br>");
749         
750         wc_printf("<center>"
751                 "<form method=\"POST\" action=\"delete_script\">\n");
752         wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
753         wc_printf("<select name=\"script_name\" size=10 style=\"width:100%%\">\n");
754
755         serv_puts("MSIV listscripts");
756         serv_getln(buf, sizeof buf);
757         if (buf[0] == '1') {
758                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
759                         extract_token(script_name, buf, 0, '|', sizeof script_name);
760                         if ( (extract_int(buf, 1) == 0) && (strcasecmp(script_name, RULES_SCRIPT)) ) {
761                                 wc_printf("<option>");
762                                 escputs(script_name);
763                                 wc_printf("</option>\n");
764                         }
765                 }
766         }
767         wc_printf("</select><br>\n");
768
769         wc_printf("<input type=\"submit\" name=\"delete_button\" value=\"%s\" "
770                 "onClick=\"return confirm('%s');\">", _("Delete script"), _("Delete this script?"));
771         wc_printf("</form></center>\n");
772         do_template("endbox");
773
774         wc_printf("</td></tr></table>\n");
775
776         wDumpContent(1);
777 }
778
779
780
781
782
783
784 void display_rules_editor_inner_div(void) {
785         int i, j;
786         char buf[4096];
787         char rules[MAX_RULES][2048];
788
789         struct {
790                 char name[128];
791         } *rooms = NULL;
792         int num_roomnames = 0;
793         int num_roomnames_alloc = 0;
794
795         int active;
796         char hfield[256];
797         char compare[32];
798         char htext[256];
799         char sizecomp[32];
800         int sizeval;
801         char action[32];
802         char fileinto[128];
803         char redirect[256];
804         char automsg[1024];
805         char final[32];
806
807         /* load the rules */
808         memset(rules, 0, sizeof rules);
809         serv_printf("MSIV getscript|%s", RULES_SCRIPT);
810         serv_getln(buf, sizeof buf);
811         if (buf[0] == '1') while(serv_getln(buf, sizeof (buf)), strcmp(buf, "000")) {
812                 if (!strncasecmp(buf, "# WEBCIT_RULE|", 14)) {
813                         j = extract_int(buf, 1);
814                         remove_token(buf, 0, '|');
815                         remove_token(buf, 0, '|');
816                         CtdlDecodeBase64(rules[j], buf, strlen(buf));
817                 }
818         }
819
820         /* load the roomnames */
821         serv_puts("LKRA");
822         serv_getln(buf, sizeof buf);
823         if (buf[0] == '1') {
824                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
825                         ++num_roomnames;
826                         if (num_roomnames > num_roomnames_alloc) {
827                                 num_roomnames_alloc += 250;
828                                 rooms = realloc(rooms, (num_roomnames_alloc * 128));
829                         }
830                         extract_token(rooms[num_roomnames-1].name, buf, 0, '|', 128);
831                 }
832         }
833
834
835 /*
836  * This script should get called by every onChange event...
837  *
838  */
839         wc_printf("<script type=\"text/javascript\">                                    \n"
840                 "                                                                       \n"
841                 "var highest_active_rule = (-1);                                        \n"
842                 "                                                                       \n"
843                 "function UpdateRules() {                                               \n");
844 /*
845  * Show only the active rows...
846  */
847         wc_printf("  highest_active_rule = (-1);                                                \n");
848         wc_printf("  for (i=0; i<%d; ++i) {                                             \n", MAX_RULES);
849         wc_printf("   if ($('active'+i).checked) {                                      \n"
850                 "     $('rule' + i).style.display = 'block';                            \n"
851                 "     highest_active_rule = i;                                          \n"
852                 "   }                                                                   \n"
853                 "   else {                                                              \n"
854                 "     $('rule' + i).style.display = 'none';                             \n"
855                 "   }                                                                   \n"
856                 "  }                                                                    \n");
857 /*
858  * Show only the fields relevant to the rules...
859  */
860         wc_printf("  for (i=0; i<=highest_active_rule; ++i) {                           \n"
861                 "    d = ($('movedown'+i));                                             \n"
862                 "    if (i < highest_active_rule) {                                     \n"
863                 "      d.style.display = 'block';                                       \n"
864                 "    }                                                                  \n"
865                 "    else {                                                             \n"
866                 "      d.style.display = 'none';                                        \n"
867                 "    }                                                                  \n"
868                 "    d = ($('hfield'+i).options[$('hfield'+i).selectedIndex].value);    \n"
869                 "    if (d == 'all') {                                                  \n"
870                 "      $('div_size'+i).style.display = 'none';                          \n"
871                 "      $('div_compare'+i).style.display = 'none';                       \n"
872                 "      $('div_nocompare'+i).style.display = 'block';                    \n"
873                 "    }                                                                  \n"
874                 "    else if (d == 'size') {                                            \n"
875                 "      $('div_size'+i).style.display = 'block';                         \n"
876                 "      $('div_compare'+i).style.display = 'none';                       \n"
877                 "      $('div_nocompare'+i).style.display = 'none';                     \n"
878                 "    }                                                                  \n"
879                 "    else {                                                             \n"
880                 "      $('div_size'+i).style.display = 'none';                          \n"
881                 "      $('div_compare'+i).style.display = 'block';                      \n"
882                 "      $('div_nocompare'+i).style.display = 'none';                     \n"
883                 "    }                                                                  \n"
884                 "    d = ($('action'+i).options[$('action'+i).selectedIndex].value);    \n"
885                 "    if (d == 'fileinto') {                                             \n"
886                 "      $('div_fileinto'+i).style.display = 'block';                     \n"
887                 "      $('div_redirect'+i).style.display = 'none';                      \n"
888                 "      $('div_automsg'+i).style.display = 'none';                       \n"
889                 "    } else if (d == 'redirect') {                                      \n"
890                 "      $('div_fileinto'+i).style.display = 'none';                      \n"
891                 "      $('div_redirect'+i).style.display = 'block';                     \n"
892                 "      $('div_automsg'+i).style.display = 'none';                       \n"
893                 "    } else if ((d == 'reject') || (d == 'vacation'))  {                \n"
894                 "      $('div_fileinto'+i).style.display = 'none';                      \n"
895                 "      $('div_redirect'+i).style.display = 'none';                      \n"
896                 "      $('div_automsg'+i).style.display = 'block';                      \n"
897                 "    } else {                                                           \n"
898                 "      $('div_fileinto'+i).style.display = 'none';                      \n"
899                 "      $('div_redirect'+i).style.display = 'none';                      \n"
900                 "      $('div_automsg'+i).style.display = 'none';                       \n"
901                 "    }                                                                  \n"
902                 "    if (highest_active_rule < %d) {                                    \n", MAX_RULES-1 );
903         wc_printf("      $('div_addrule').style.display = 'block';                      \n"
904                 "    } else {                                                           \n"
905                 "      $('div_addrule').style.display = 'none';                         \n"
906                 "    }                                                                  \n"
907                 "  }                                                                    \n"
908                 "}                                                                      \n"
909 /*
910  * Add a rule (really, just un-hide it)
911  */
912                 "function AddRule() {                                                   \n"
913                 "  highest_active_rule = highest_active_rule + 1;                       \n"
914                 "  $('active'+highest_active_rule).checked = true;                      \n"
915                 "  UpdateRules();                                                       \n"
916                 "}                                                                      \n"
917 /*
918  * Swap two rules
919  */
920                 "function SwapRules(ra, rb) {                                           \n"
921                 "                                                                       \n"
922                 "  var things = new Array();                                            \n"
923                 "  things[0] = 'hfield';                                                \n"
924                 "  things[1] = 'compare';                                               \n"
925                 "  things[2] = 'htext';                                                 \n"
926                 "  things[3] = 'action';                                                \n"
927                 "  things[4] = 'fileinto';                                              \n"
928                 "  things[5] = 'redirect';                                              \n"
929                 "  things[6] = 'final';                                                 \n"
930                 "  things[7] = 'sizecomp';                                              \n"
931                 "  things[8] = 'sizeval';                                               \n"
932                 "  things[9] = 'automsg';                                               \n"
933                 "                                                                       \n"
934                 "  for (i=0; i<=9; ++i) {                                               \n"
935                 "    tempval=$(things[i]+ra).value;                                     \n"
936                 "    $(things[i]+ra).value = $(things[i]+rb).value;                     \n"
937                 "    $(things[i]+rb).value = tempval;                                   \n"
938                 "  }                                                                    \n"
939                 "}                                                                      \n"
940 /*
941  * Delete a rule (percolate the deleted rule out to the end, then deactivate it)
942  */
943                 "function DeleteRule(rd) {                                              \n"
944                 "  for (j=rd; j<=highest_active_rule; ++j) {                            \n"
945                 "    SwapRules(j, (j+1));                                               \n"
946                 "  }                                                                    \n"
947                 "  $('active'+highest_active_rule).checked = false;                     \n"
948                 "}                                                                      \n"
949                 "</script>                                                              \n"
950         );
951
952
953         wc_printf("<br>");
954
955         wc_printf("<table cellpadding=2 width=100%%>");
956
957         for (i=0; i<MAX_RULES; ++i) {
958
959                 /* Grab our existing values to populate */
960                 active = extract_int(rules[i], 0);
961                 extract_token(hfield, rules[i], 1, '|', sizeof hfield);
962                 extract_token(compare, rules[i], 2, '|', sizeof compare);
963                 extract_token(htext, rules[i], 3, '|', sizeof htext);
964                 extract_token(sizecomp, rules[i], 4, '|', sizeof sizecomp);
965                 sizeval = extract_int(rules[i], 5);
966                 extract_token(action, rules[i], 6, '|', sizeof action);
967                 extract_token(fileinto, rules[i], 7, '|', sizeof fileinto);
968                 extract_token(redirect, rules[i], 8, '|', sizeof redirect);
969                 extract_token(automsg, rules[i], 9, '|', sizeof automsg);
970                 extract_token(final, rules[i], 10, '|', sizeof final);
971                 
972                 /* now generate the table row */
973
974                 wc_printf("<tr id=\"rule%d\" bgcolor=\"#%s\">",
975                         i,
976                         ((i%2) ? "DDDDDD" : "FFFFFF")
977                 );
978
979                 wc_printf("<td width=5%% align=\"center\">");
980
981                 wc_printf("<div style=\"display:none\">");
982                 wc_printf("<input type=\"checkbox\" name=\"active%d\" id=\"active%d\" %s>",
983                         i, i,
984                         (active ? "checked" : "")
985                 );
986                 wc_printf("</div>");
987
988                 if (i>0) wc_printf("<a href=\"javascript:SwapRules(%d,%d);UpdateRules();\">"
989                         "<img border=\"0\" src=\"static/icons/up_pointer.gif\" "
990                         "title=\"%s\"/></a>",
991                         i-1, i, _("Move rule up") );
992
993                 wc_printf("<a href=\"javascript:SwapRules(%d,%d);UpdateRules();\">"
994                         "<img id=\"movedown%d\" border=\"0\" src=\"static/icons/down_pointer.gif\" "
995                         "title=\"%s\"/></a>",
996                         i, i+1, i, _("Move rule down") );
997
998                 wc_printf("<a href=\"javascript:DeleteRule(%d);UpdateRules();\">"
999                         "<img id=\"delete%d\" border=\"0\" src=\"static/icons/delete.gif\" "
1000                         "title=\"%s\"/></a>",
1001                         i, i, _("Delete rule") );
1002
1003                 wc_printf("</td>");
1004
1005                 wc_printf("<td width=5%% align=\"center\">");
1006                 wc_printf("<font size=+2>%d</font>", i+1);
1007                 wc_printf("</td>");
1008
1009                 wc_printf("<td width=20%%>%s ", _("If") );
1010
1011                 char *hfield_values[15][2] = {
1012                         {       "from",         _("From")               },
1013                         {       "tocc",         _("To or Cc")           },
1014                         {       "subject",      _("Subject")            },
1015                         {       "replyto",      _("Reply-to")           },
1016                         {       "sender",       _("Sender")             },
1017                         {       "resentfrom",   _("Resent-From")        },
1018                         {       "resentto",     _("Resent-To")          },
1019                         {       "envfrom",      _("Envelope From")      },
1020                         {       "envto",        _("Envelope To")        },
1021                         {       "xmailer",      _("X-Mailer")           },
1022                         {       "xspamflag",    _("X-Spam-Flag")        },
1023                         {       "xspamstatus",  _("X-Spam-Status")      },
1024                         {       "listid",       _("List-ID")            },
1025                         {       "size",         _("Message size")       },
1026                         {       "all",          _("All")                }
1027                 };
1028
1029                 wc_printf("<select id=\"hfield%d\" name=\"hfield%d\" size=1 onChange=\"UpdateRules();\">",
1030                         i, i);
1031                 for (j=0; j<15; ++j) {
1032                         wc_printf("<option %s value=\"%s\">%s</option>",
1033                                 ( (!strcasecmp(hfield, hfield_values[j][0])) ? "selected" : ""),
1034                                 hfield_values[j][0],
1035                                 hfield_values[j][1]
1036                         );
1037                 }
1038
1039                 wc_printf("</select>");
1040                 wc_printf("</td>");
1041
1042                 wc_printf("<td width=20%%>");
1043
1044                 char *compare_values[6][2] = {
1045                         {       "contains",     _("contains")           },
1046                         {       "notcontains",  _("does not contain")   },
1047                         {       "is",           _("is")                 },
1048                         {       "isnot",        _("is not")             },
1049                         {       "matches",      _("matches")            },
1050                         {       "notmatches",   _("does not match")     }
1051                 };
1052
1053                 wc_printf("<div id=\"div_compare%d\">", i);
1054                 wc_printf("<select id=\"compare%d\" name=\"compare%d\" size=1 onChange=\"UpdateRules();\">",
1055                         i, i);
1056                 for (j=0; j<6; ++j) {
1057                         wc_printf("<option %s value=\"%s\">%s</option>",
1058                                 ( (!strcasecmp(compare, compare_values[j][0])) ? "selected" : ""),
1059                                 compare_values[j][0],
1060                                 compare_values[j][1]
1061                         );
1062                 }
1063                 wc_printf("</select>");
1064
1065                 wc_printf("<input type=\"text\" id=\"htext%d\" name=\"htext%d\" value=\"", i, i);
1066                 escputs(htext);
1067                 wc_printf("\"></div>");
1068
1069                 wc_printf("<div id=\"div_nocompare%d\">", i);
1070                 wc_printf("%s", _("(All messages)"));
1071                 wc_printf("</div>");
1072
1073                 char *sizecomp_values[2][2] = {
1074                         {       "larger",       _("is larger than")     },
1075                         {       "smaller",      _("is smaller than")    }
1076                 };
1077
1078                 wc_printf("<div id=\"div_size%d\">", i);
1079                 wc_printf("<select id=\"sizecomp%d\" name=\"sizecomp%d\" size=1 onChange=\"UpdateRules();\">",
1080                         i, i);
1081                 for (j=0; j<2; ++j) {
1082                         wc_printf("<option %s value=\"%s\">%s</option>",
1083                                 ( (!strcasecmp(sizecomp, sizecomp_values[j][0])) ? "selected" : ""),
1084                                 sizecomp_values[j][0],
1085                                 sizecomp_values[j][1]
1086                         );
1087                 }
1088                 wc_printf("</select>");
1089
1090                 wc_printf("<input type=\"text\" id=\"sizeval%d\" name=\"sizeval%d\" value=\"%d\">",
1091                         i, i, sizeval);
1092                 wc_printf("bytes");
1093                 wc_printf("</div>");
1094
1095                 wc_printf("</td>");
1096
1097                 char *action_values[6][2] = {
1098                         {       "keep",         _("Keep")               },
1099                         {       "discard",      _("Discard silently")   },
1100                         {       "reject",       _("Reject")             },
1101                         {       "fileinto",     _("Move message to")    },
1102                         {       "redirect",     _("Forward to")         },
1103                         {       "vacation",     _("Vacation")           }
1104                 };
1105
1106                 wc_printf("<td width=20%%>");
1107                 wc_printf("<select id=\"action%d\" name=\"action%d\" size=1 onChange=\"UpdateRules();\">",
1108                         i, i);
1109                 for (j=0; j<6; ++j) {
1110                         wc_printf("<option %s value=\"%s\">%s</option>",
1111                                 ( (!strcasecmp(action, action_values[j][0])) ? "selected" : ""),
1112                                 action_values[j][0],
1113                                 action_values[j][1]
1114                         );
1115                 }
1116                 wc_printf("</select>");
1117
1118                 wc_printf("<div id=\"div_fileinto%d\">", i);
1119                 wc_printf("<select name=\"fileinto%d\" id=\"fileinto%d\">", i, i);
1120                 for (j=0; j<num_roomnames; ++j) {
1121                         wc_printf("<option ");
1122                         if (!strcasecmp(rooms[j].name, fileinto)) {
1123                                 wc_printf("selected ");
1124                         }
1125                         wc_printf("value=\"");
1126                         escputs(rooms[j].name);
1127                         wc_printf("\">");
1128                         escputs(rooms[j].name);
1129                         wc_printf("</option>\n");
1130                 }
1131                 wc_printf("</select>\n");
1132                 wc_printf("</div>");
1133
1134                 wc_printf("<div id=\"div_redirect%d\">", i);
1135                 wc_printf("<input type=\"text\" id=\"redirect%d\" name=\"redirect%d\" value=\"", i, i);
1136                 escputs(redirect);
1137                 wc_printf("\"></div>");
1138
1139                 wc_printf("<div id=\"div_automsg%d\">", i);
1140                 wc_printf(_("Message:"));
1141                 wc_printf("<br>");
1142                 wc_printf("<textarea name=\"automsg%d\" id=\"automsg%d\" wrap=soft rows=5>\n", i, i);
1143                 escputs(automsg);
1144                 wc_printf("</textarea>");
1145                 wc_printf("</div>");
1146
1147                 wc_printf("</td>");
1148
1149                 char *final_values[2][2] = {
1150                         {       "continue",     _("continue processing")        },
1151                         {       "stop",         _("stop")                       }
1152                 };
1153
1154                 wc_printf("<td width=10%% align=\"center\">%s</td>", _("and then") );
1155
1156                 wc_printf("<td width=20%%>");
1157                 wc_printf("<select name=\"final%d\" id=\"final%d\" size=1 onChange=\"UpdateRules();\">",
1158                         i, i);
1159                 for (j=0; j<2; ++j) {
1160                         wc_printf("<option %s value=\"%s\">%s</option>",
1161                                 ( (!strcasecmp(final, final_values[j][0])) ? "selected" : ""),
1162                                 final_values[j][0],
1163                                 final_values[j][1]
1164                         );
1165                 }
1166                 wc_printf("</select>");
1167                 wc_printf("</td>");
1168
1169                 wc_printf("</tr>\n");
1170
1171         }
1172
1173         wc_printf("</table>");
1174         wc_printf("<div id=\"div_addrule\"><a href=\"javascript:AddRule();\">%s</a><br></div>\n",
1175                 _("Add rule")
1176         );
1177
1178         wc_printf("<script type=\"text/javascript\">                                    \n");
1179         wc_printf("UpdateRules();                                                               \n");
1180         wc_printf("</script>                                                            \n");
1181
1182         free(rooms);
1183 }
1184 void _display_add_remove_scripts(void) {display_add_remove_scripts(NULL);}
1185 #endif
1186
1187
1188 typedef struct __SieveListing {
1189         int IsActive;
1190         int IsRulesScript;
1191         StrBuf *Name;
1192         StrBuf *Content;
1193 } SieveListing;
1194
1195 int ConditionalSieveScriptIsActive(StrBuf *Target, WCTemplputParams *TP)
1196 {
1197         SieveListing     *SieveList = (SieveListing *)CTX;
1198         return SieveList->IsActive;
1199 }
1200 int ConditionalSieveScriptIsRulesScript(StrBuf *Target, WCTemplputParams *TP)
1201 {
1202         SieveListing     *SieveList = (SieveListing *)CTX;
1203         return SieveList->IsActive;
1204 }
1205 void tmplput_SieveScriptName(StrBuf *Target, WCTemplputParams *TP) 
1206 {
1207         SieveListing     *SieveList = (SieveListing *)CTX;
1208         StrBufAppendTemplate(Target, TP, SieveList->Name, 0);
1209 }
1210 void tmplput_SieveScriptContent(StrBuf *Target, WCTemplputParams *TP) 
1211 {
1212         SieveListing     *SieveList = (SieveListing *)CTX;
1213         StrBufAppendTemplate(Target, TP, SieveList->Content, 0);
1214 }
1215 void FreeSieveListing(void *vSieveListing)
1216 {
1217         SieveListing *List = (SieveListing*) vSieveListing;
1218
1219         FreeStrBuf(&List->Name);
1220         free(List);
1221 }
1222
1223 HashList *GetSieveScriptListing(StrBuf *Target, WCTemplputParams *TP)
1224 {
1225         wcsession *WCC = WC;
1226         StrBuf *Line;
1227         int num_scripts = 0;
1228         int rules_script_active = 0;
1229         int have_rules_script = 0;
1230         const char *pch;
1231         HashPos  *it;
1232         int Done = 0;
1233         SieveListing *Ruleset;
1234
1235         if (WCC->KnownSieveScripts != NULL)
1236                 return WCC->KnownSieveScripts;
1237
1238         serv_puts("MSIV listscripts");
1239         Line = NewStrBuf();
1240         StrBuf_ServGetln(Line);
1241         if (GetServerStatus(Line, NULL) == 1) 
1242         {
1243                 WCC->KnownSieveScripts = NewHash(1, Flathash);
1244
1245                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
1246                         if ( (StrLength(Line)==3) && 
1247                              !strcmp(ChrPtr(Line), "000")) 
1248                         {
1249                                 Done = 1;
1250                         }
1251                         else
1252                         {
1253                                 pch = NULL;
1254                                 Ruleset = (SieveListing *) malloc(sizeof(SieveListing));
1255                                 Ruleset->Name = NewStrBufPlain(NULL, StrLength(Line));
1256                                 StrBufExtract_NextToken(Ruleset->Name, Line, &pch, '|');
1257                                 Ruleset->IsActive = StrBufExtractNext_int(Line, &pch, '|'); 
1258
1259                                 if (!strcasecmp(ChrPtr(Ruleset->Name), RULES_SCRIPT))
1260                                 {
1261                                         Ruleset->IsRulesScript = 1;
1262                                         have_rules_script = 1;
1263                                         if (Ruleset->IsActive)
1264                                         {
1265                                                 rules_script_active = 1;
1266                                                 PutBstr(HKEY("__SIEVE:RULESSCRIPT"), NewStrBufPlain(HKEY("1")));
1267                                         }
1268                                 }
1269                                 Put(WCC->KnownSieveScripts, IKEY(num_scripts), Ruleset, FreeSieveListing);
1270
1271                                 ++num_scripts;
1272                         }
1273         }
1274         if ((num_scripts > 0) && (rules_script_active == 0))
1275                 PutBstr(HKEY("__SIEVE:EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
1276
1277         if (num_scripts > have_rules_script)
1278         {
1279                 long rc;
1280                 long len;
1281                 const char *Key;
1282                 void *vRuleset;
1283
1284                 /* 
1285                  * ok; we have custom scripts, expose that via bstr, and load the payload.
1286                  */
1287                 PutBstr(HKEY("__SIEVE:HAVE_EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
1288
1289                 it = GetNewHashPos(WCC->KnownSieveScripts, 0);
1290                 while (GetNextHashPos(WCC->KnownSieveScripts, it, &len, &Key, &vRuleset) && 
1291                        (vRuleset != NULL))
1292                 {
1293                         Ruleset = (SieveListing *) vRuleset;
1294
1295                         /*
1296                          * its the webcit rule? we don't need to load that here.
1297                          */
1298                         if (Ruleset->IsRulesScript)
1299                                 continue;
1300
1301                         if (!serv_printf("MSIV getscript|%s", ChrPtr(Ruleset->Name)))
1302                                 break;
1303                         StrBuf_ServGetln(Line);
1304                         if (GetServerStatus(Line, NULL) == 1) 
1305                         {
1306                                 Ruleset->Content = NewStrBuf();
1307                                 while(!Done && (rc = StrBuf_ServGetln(Line), rc >= 0) )
1308                                         if ( (StrLength(Line)==3) && 
1309                                              !strcmp(ChrPtr(Line), "000")) 
1310                                         {
1311                                                 Done = 1;
1312                                         }
1313                                         else
1314                                         {
1315                                                 if (StrLength(Ruleset->Content)>0)
1316                                                         StrBufAppendBufPlain(Ruleset->Content, HKEY("\n"), 0);
1317                                                 StrBufAppendBuf(Ruleset->Content, Line, 0);
1318                                         }
1319                                 if (rc < 0) break;
1320                         }
1321                 }
1322         }
1323         FreeStrBuf(&Line);
1324         return WCC->KnownSieveScripts;
1325 }
1326
1327
1328 typedef enum __eSieveHfield 
1329 {
1330         from,           
1331         tocc,           
1332         subject,        
1333         replyto,        
1334         sender, 
1335         resentfrom,     
1336         resentto,       
1337         envfrom,        
1338         envto,  
1339         xmailer,        
1340         xspamflag,      
1341         xspamstatus,    
1342         listid, 
1343         size,           
1344         all
1345 } eSieveHfield;
1346
1347 typedef enum __eSieveCompare {
1348         contains,
1349         notcontains,
1350         is,
1351         isnot,
1352         matches,
1353         notmatches
1354 } eSieveCompare;
1355
1356 typedef enum __eSieveAction {
1357         keep,
1358         discard,
1359         reject,
1360         fileinto,
1361         redirect,
1362         vacation
1363 } eSieveAction;
1364
1365
1366 typedef enum __eSieveSizeComp {
1367         larger,
1368         smaller
1369 } eSieveSizeComp;
1370
1371 typedef enum __eSieveFinal {
1372         econtinue,
1373         estop
1374 } eSieveFinal;
1375
1376
1377 typedef struct __SieveRule {
1378         int active;
1379         int sizeval;
1380         eSieveHfield hfield;
1381         eSieveCompare compare;
1382         StrBuf *htext;
1383         eSieveSizeComp sizecomp;
1384         eSieveAction Action;
1385         StrBuf *fileinto;
1386         StrBuf *redirect;
1387         StrBuf *automsg;
1388         eSieveFinal final;
1389 }SieveRule;
1390
1391
1392
1393 int ConditionalSieveRule_hfield(StrBuf *Target, WCTemplputParams *TP)
1394 {
1395         SieveRule     *Rule = (SieveRule *)CTX;
1396         
1397         return GetTemplateTokenNumber(Target, 
1398                                       TP, 
1399                                       3, 
1400                                       from)
1401                 ==
1402                 Rule->hfield;
1403 }
1404 int ConditionalSieveRule_compare(StrBuf *Target, WCTemplputParams *TP)
1405 {
1406         SieveRule     *Rule = (SieveRule *)CTX;
1407         return GetTemplateTokenNumber(Target, 
1408                                       TP, 
1409                                       3, 
1410                                       contains)
1411                 ==
1412                 Rule->compare;
1413 }
1414 int ConditionalSieveRule_action(StrBuf *Target, WCTemplputParams *TP)
1415 {
1416         SieveRule     *Rule = (SieveRule *)CTX;
1417         return GetTemplateTokenNumber(Target, 
1418                                       TP, 
1419                                       3, 
1420                                       keep)
1421                 ==
1422                 Rule->Action; 
1423 }
1424 int ConditionalSieveRule_sizecomp(StrBuf *Target, WCTemplputParams *TP)
1425 {
1426         SieveRule     *Rule = (SieveRule *)CTX;
1427         return GetTemplateTokenNumber(Target, 
1428                                       TP, 
1429                                       3, 
1430                                       larger)
1431                 ==
1432                 Rule->sizecomp;
1433 }
1434 int ConditionalSieveRule_final(StrBuf *Target, WCTemplputParams *TP)
1435 {
1436         SieveRule     *Rule = (SieveRule *)CTX;
1437         return GetTemplateTokenNumber(Target, 
1438                                       TP, 
1439                                       3, 
1440                                       econtinue)
1441                 ==
1442                 Rule->final;
1443 }
1444 int ConditionalSieveRule_ThisRoom(StrBuf *Target, WCTemplputParams *TP)
1445 {
1446         SieveRule     *Rule = (SieveRule *)CTX;
1447         return GetTemplateTokenNumber(Target, 
1448                                       TP, 
1449                                       3, 
1450                                       econtinue)
1451                 ==
1452                 Rule->final;
1453 }
1454 int ConditionalSieveRule_Active(StrBuf *Target, WCTemplputParams *TP)
1455 {
1456         SieveRule     *Rule = (SieveRule *)CTX;
1457         return Rule->active;
1458 }
1459
1460
1461 /*
1462 void tmplput_SieveRule_hfield(StrBuf *Target, WCTemplputParams *TP) 
1463 {
1464         SieveRule     *Rule = (SieveRule *)CTX;
1465         StrBufAppendTemplate(Target, TP, Rule->hfield, 0);
1466 }
1467 void tmplput_SieveRule_compare(StrBuf *Target, WCTemplputParams *TP) 
1468 {
1469         SieveRule     *Rule = (SieveRule *)CTX;
1470         StrBufAppendTemplate(Target, TP, Rule->compare, 0);
1471 }
1472 */
1473 void tmplput_SieveRule_htext(StrBuf *Target, WCTemplputParams *TP) 
1474 {
1475         SieveRule     *Rule = (SieveRule *)CTX;
1476         StrBufAppendTemplate(Target, TP, Rule->htext, 0);
1477 }
1478 /*
1479 void tmplput_SieveRule_sizecomp(StrBuf *Target, WCTemplputParams *TP) 
1480 {
1481         SieveRule     *Rule = (SieveRule *)CTX;
1482         StrBufAppendTemplate(Target, TP, Rule->sizecomp, 0);
1483 }
1484 void tmplput_SieveRule_action(StrBuf *Target, WCTemplputParams *TP) 
1485 {
1486         SieveRule     *Rule = (SieveRule *)CTX;
1487         StrBufAppendTemplate(Target, TP, Rule->action, 0);
1488         }*/
1489 void tmplput_SieveRule_fileinto(StrBuf *Target, WCTemplputParams *TP) 
1490 {
1491         SieveRule     *Rule = (SieveRule *)CTX;
1492         StrBufAppendTemplate(Target, TP, Rule->fileinto, 0);
1493 }
1494 void tmplput_SieveRule_redirect(StrBuf *Target, WCTemplputParams *TP) 
1495 {
1496         SieveRule     *Rule = (SieveRule *)CTX;
1497         StrBufAppendTemplate(Target, TP, Rule->redirect, 0);
1498 }
1499 void tmplput_SieveRule_automsg(StrBuf *Target, WCTemplputParams *TP) 
1500 {
1501         SieveRule     *Rule = (SieveRule *)CTX;
1502         StrBufAppendTemplate(Target, TP, Rule->automsg, 0);
1503 }
1504 /*
1505 void tmplput_SieveRule_final(StrBuf *Target, WCTemplputParams *TP) 
1506 {
1507         SieveRule     *Rule = (SieveRule *)CTX;
1508         StrBufAppendTemplate(Target, TP, Rule->final, 0);
1509 }
1510 */
1511 void FreeSieveRule(void *vRule)
1512 {
1513         SieveRule *Rule = (SieveRule*) Rule;
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                                 }
1589                         }
1590         }
1591
1592         FreeStrBuf(&EncodedRule);
1593         FreeStrBuf(&Line);
1594         return SieveRules;
1595 }
1596
1597 void
1598 SessionDetachModule_SIEVE
1599 (wcsession *sess)
1600 {
1601         DeleteHash(&sess->KnownSieveScripts);
1602 }
1603
1604 void 
1605 InitModule_SIEVE
1606 (void)
1607 {
1608         REGISTERTokenParamDefine(from);         
1609         REGISTERTokenParamDefine(tocc);         
1610         REGISTERTokenParamDefine(subject);      
1611         REGISTERTokenParamDefine(replyto);      
1612         REGISTERTokenParamDefine(sender);       
1613         REGISTERTokenParamDefine(resentfrom);   
1614         REGISTERTokenParamDefine(resentto);     
1615         REGISTERTokenParamDefine(envfrom);      
1616         REGISTERTokenParamDefine(envto);        
1617         REGISTERTokenParamDefine(xmailer);      
1618         REGISTERTokenParamDefine(xspamflag);    
1619         REGISTERTokenParamDefine(xspamstatus);  
1620         REGISTERTokenParamDefine(listid);       
1621         REGISTERTokenParamDefine(size);         
1622         REGISTERTokenParamDefine(all);
1623
1624         REGISTERTokenParamDefine(contains);
1625         REGISTERTokenParamDefine(notcontains);
1626         REGISTERTokenParamDefine(is);
1627         REGISTERTokenParamDefine(isnot);
1628         REGISTERTokenParamDefine(matches);
1629         REGISTERTokenParamDefine(notmatches);
1630
1631         REGISTERTokenParamDefine(keep);
1632         REGISTERTokenParamDefine(discard);
1633         REGISTERTokenParamDefine(reject);
1634         REGISTERTokenParamDefine(fileinto);
1635         REGISTERTokenParamDefine(redirect);
1636         REGISTERTokenParamDefine(vacation);
1637
1638         REGISTERTokenParamDefine(larger);
1639         REGISTERTokenParamDefine(smaller);
1640
1641         /* these are c-keyworads, so do it by hand. */
1642         RegisterTokenParamDefine(HKEY("continue"), econtinue);
1643         RegisterTokenParamDefine(HKEY("stop"), estop);
1644
1645         RegisterIterator("SIEVE:SCRIPTS", 0, NULL, GetSieveRules, NULL, NULL, CTX_SIEVELIST, CTX_NONE, IT_NOFLAG);
1646
1647         RegisterIterator("SIEVE:RULES", 0, NULL, GetSieveRules, NULL, DeleteHash, CTX_SIEVESCRIPT, CTX_NONE, IT_NOFLAG);
1648
1649         RegisterConditional(HKEY("COND:SIEVE:SCRIPT:ACTIVE"), 0, ConditionalSieveScriptIsActive, CTX_SIEVELIST);
1650         RegisterConditional(HKEY("COND:SIEVE:SCRIPT:ISRULES"), 0, ConditionalSieveScriptIsRulesScript, CTX_SIEVELIST);
1651         RegisterNamespace("SIEVE:SCRIPT:NAME", 0, 1, tmplput_SieveScriptName, NULL, CTX_ROOMS);
1652         RegisterNamespace("SIEVE:SCRIPT:CONTENT", 0, 1, tmplput_SieveScriptContent, NULL, CTX_SIEVELIST);
1653
1654  
1655         RegisterConditional(HKEY("COND:SIEVE:ACTIVE"), 1, ConditionalSieveRule_Active, CTX_SIEVESCRIPT);
1656         RegisterConditional(HKEY("COND:SIEVE:HFIELD"), 1, ConditionalSieveRule_hfield, CTX_SIEVESCRIPT);
1657         RegisterConditional(HKEY("COND:SIEVE:COMPARE"), 1, ConditionalSieveRule_compare, CTX_SIEVESCRIPT);
1658         RegisterConditional(HKEY("COND:SIEVE:ACTION"), 1, ConditionalSieveRule_action, CTX_SIEVESCRIPT);
1659         RegisterConditional(HKEY("COND:SIEVE:SIZECOMP"), 1, ConditionalSieveRule_sizecomp, CTX_SIEVESCRIPT);
1660         RegisterConditional(HKEY("COND:SIEVE:FINAL"), 1, ConditionalSieveRule_final, CTX_SIEVESCRIPT);
1661         RegisterConditional(HKEY("COND:SIEVE:THISROOM"), 1, ConditionalSieveRule_ThisRoom, CTX_SIEVESCRIPT);
1662
1663         //RegisterNamespace("SIEVE:SCRIPT:HFIELD", 0, 1, tmplput_SieveRule_hfield, NULL, CTX_SIEVESCRIPT);
1664         //RegisterNamespace("SIEVE:SCRIPT:COMPARE", 0, 1, tmplput_SieveRule_compare, NULL, CTX_SIEVESCRIPT);
1665         RegisterNamespace("SIEVE:SCRIPT:HTEXT", 0, 1, tmplput_SieveRule_htext, NULL, CTX_SIEVESCRIPT);
1666         //RegisterNamespace("SIEVE:SCRIPT:SIZECOMP", 0, 1, tmplput_SieveRule_sizecomp, NULL, CTX_SIEVESCRIPT);
1667         ///RegisterNamespace("SIEVE:SCRIPT:ACTION", 0, 1, tmplput_SieveRule_action, NULL, CTX_SIEVESCRIPT);
1668         RegisterNamespace("SIEVE:SCRIPT:FILEINTO", 0, 1, tmplput_SieveRule_fileinto, NULL, CTX_SIEVESCRIPT);
1669         RegisterNamespace("SIEVE:SCRIPT:REDIRECT", 0, 1, tmplput_SieveRule_redirect, NULL, CTX_SIEVESCRIPT);
1670         RegisterNamespace("SIEVE:SCRIPT:AUTOMSG", 0, 1, tmplput_SieveRule_automsg, NULL, CTX_SIEVESCRIPT);
1671         ///RegisterNamespace("SIEVE:SCRIPT:FINAL", 0, 1, tmplput_SieveRule_final, NULL, CTX_SIEVESCRIPT);
1672
1673 #if FOO
1674         WebcitAddUrlHandler(HKEY("display_sieve"), "", 0, display_sieve, 0);
1675         WebcitAddUrlHandler(HKEY("display_add_remove_scripts"), "", 0, _display_add_remove_scripts, 0);
1676 #endif
1677         WebcitAddUrlHandler(HKEY("save_sieve"), "", 0, save_sieve, 0);
1678
1679         WebcitAddUrlHandler(HKEY("create_script"), "", 0, create_script, 0);
1680         WebcitAddUrlHandler(HKEY("delete_script"), "", 0, delete_script, 0);
1681 }