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