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