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