Removed the commented-out code in sieve.c
[citadel.git] / webcit / sieve.c
1 /*
2  * Copyright (c) 1996-2012 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 version 3.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12
13 #include "webcit.h"
14
15 #define MAX_SCRIPTS     100
16 #define MAX_RULES       50
17 #define RULES_SCRIPT    "__WebCit_Generated_Script__"
18
19 /*
20  * Helper function for output_sieve_rule() to output strings with quotes escaped
21  */
22 void osr_sanitize(char *str) {
23         int i, len;
24
25         if (str == NULL) return;
26         len = strlen(str);
27         for (i=0; i<len; ++i) {
28                 if (str[i]=='\"') {
29                         str[i] = '\'' ;
30                 }
31                 else if (isspace(str[i])) {
32                         str[i] = ' ';
33                 }
34         }
35 }
36
37 void display_add_remove_scripts(char *message);
38 void display_rules_editor_inner_div(void);
39
40
41 /*
42  * Output parseable Sieve script code based on rules input
43  */
44 void output_sieve_rule(char *hfield, char *compare, char *htext, char *sizecomp, int sizeval,
45                         char *action, char *fileinto, char *redirect, char *automsg, char *final,
46                         char *my_addresses)
47 {
48         char *comp1 = "";
49         char *comp2 = "";
50
51         osr_sanitize(htext);
52         osr_sanitize(fileinto);
53         osr_sanitize(redirect);
54         osr_sanitize(automsg);
55
56         /* Prepare negation and match operators that will be used iff we apply a conditional */
57
58         if (!strcasecmp(compare, "contains")) {
59                 comp1 = "";
60                 comp2 = ":contains";
61         }
62         else if (!strcasecmp(compare, "notcontains")) {
63                 comp1 = "not";
64                 comp2 = ":contains";
65         }
66         else if (!strcasecmp(compare, "is")) {
67                 comp1 = "";
68                 comp2 = ":is";
69         }
70         else if (!strcasecmp(compare, "isnot")) {
71                 comp1 = "not";
72                 comp2 = ":is";
73         }
74         else if (!strcasecmp(compare, "matches")) {
75                 comp1 = "";
76                 comp2 = ":matches";
77         }
78         else if (!strcasecmp(compare, "notmatches")) {
79                 comp1 = "not";
80                 comp2 = ":matches";
81         }
82
83         /* Now do the conditional */
84
85         if (!strcasecmp(hfield, "from")) {
86                 serv_printf("if%s header %s \"From\" \"%s\"",
87                         comp1, comp2,
88                         htext
89                 );
90         }
91
92         else if (!strcasecmp(hfield, "tocc")) {
93                 serv_printf("if%s header %s [\"To\", \"Cc\"] \"%s\"",
94                         comp1, comp2,
95                         htext
96                 );
97         }
98
99         else if (!strcasecmp(hfield, "subject")) {
100                 serv_printf("if%s header %s \"Subject\" \"%s\"",
101                         comp1, comp2,
102                         htext
103                 );
104         }
105
106         else if (!strcasecmp(hfield, "replyto")) {
107                 serv_printf("if%s header %s \"Reply-to\" \"%s\"",
108                         comp1, comp2,
109                         htext
110                 );
111         }
112
113         else if (!strcasecmp(hfield, "sender")) {
114                 serv_printf("if%s header %s \"Sender\" \"%s\"",
115                         comp1, comp2,
116                         htext
117                 );
118         }
119
120         else if (!strcasecmp(hfield, "resentfrom")) {
121                 serv_printf("if%s header %s \"Resent-from\" \"%s\"",
122                         comp1, comp2,
123                         htext
124                 );
125         }
126
127         else if (!strcasecmp(hfield, "resentto")) {
128                 serv_printf("if%s header %s \"Resent-to\" \"%s\"",
129                         comp1, comp2,
130                         htext
131                 );
132         }
133
134         else if (!strcasecmp(hfield, "xmailer")) {
135                 serv_printf("if%s header %s \"X-Mailer\" \"%s\"",
136                         comp1, comp2,
137                         htext
138                 );
139         }
140
141         else if (!strcasecmp(hfield, "xspamflag")) {
142                 serv_printf("if%s header %s \"X-Spam-Flag\" \"%s\"",
143                         comp1, comp2,
144                         htext
145                 );
146         }
147
148         else if (!strcasecmp(hfield, "xspamstatus")) {
149                 serv_printf("if%s header %s \"X-Spam-Status\" \"%s\"",
150                         comp1, comp2,
151                         htext
152                 );
153         }
154
155         else if (!strcasecmp(hfield, "listid")) {
156                 serv_printf("if%s header %s \"List-ID\" \"%s\"",
157                         comp1, comp2,
158                         htext
159                 );
160         }
161
162         else if (!strcasecmp(hfield, "envfrom")) {
163                 serv_printf("if%s envelope %s \"From\" \"%s\"",
164                         comp1, comp2,
165                         htext
166                 );
167         }
168
169         else if (!strcasecmp(hfield, "envto")) {
170                 serv_printf("if%s envelope %s \"To\" \"%s\"",
171                         comp1, comp2,
172                         htext
173                 );
174         }
175
176         else if (!strcasecmp(hfield, "size")) {
177                 if (!strcasecmp(sizecomp, "larger")) {
178                         serv_printf("if size :over %d", sizeval);
179                 }
180                 else if (!strcasecmp(sizecomp, "smaller")) {
181                         serv_printf("if size :under %d", sizeval);
182                 }
183                 else {  /* failsafe - should never get here, but just in case... */
184                         serv_printf("if size :over 1");
185                 }
186         }
187
188         /* Open braces if we're in a conditional loop */
189
190         if (strcasecmp(hfield, "all")) {
191                 serv_printf("{");
192         }
193
194
195         /* Do action */
196
197         if (!strcasecmp(action, "keep")) {
198                 serv_printf("keep;");
199         }
200
201         else if (!strcasecmp(action, "discard")) {
202                 serv_printf("discard;");
203         }
204
205         else if (!strcasecmp(action, "reject")) {
206                 serv_printf("reject \"%s\";", automsg);
207         }
208
209         else if (!strcasecmp(action, "fileinto")) {
210                 serv_printf("fileinto \"%s\";", fileinto);
211         }
212
213         else if (!strcasecmp(action, "redirect")) {
214                 serv_printf("redirect \"%s\";", redirect);
215         }
216
217         else if (!strcasecmp(action, "vacation")) {
218                 serv_printf("vacation :addresses [%s]\n\"%s\";", my_addresses, automsg);
219         }
220
221
222         /* Do 'final' action */
223
224         if (!strcasecmp(final, "stop")) {
225                 serv_printf("stop;");
226         }
227
228
229         /* Close the braces if we're in a conditional loop */
230
231         if (strcasecmp(hfield, "all")) {
232                 serv_printf("}");
233         }
234
235
236         /* End of rule. */
237 }
238
239
240
241 /*
242  * Translate the fields from the rule editor into something we can save...
243  */
244 void parse_fields_from_rule_editor(void) {
245
246         int active;
247         char hfield[256];
248         char compare[32];
249         char htext[256];
250         char sizecomp[32];
251         int sizeval;
252         char action[32];
253         char fileinto[128];
254         char redirect[256];
255         char automsg[1024];
256         char final[32];
257         int i;
258         char buf[256];
259         char fname[256];
260         char rule[2048];
261         char encoded_rule[4096];
262         char my_addresses[4096];
263         
264         /* Enumerate my email addresses in case they are needed for a vacation rule */
265         my_addresses[0] = 0;
266         serv_puts("GVEA");
267         serv_getln(buf, sizeof buf);
268         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
269                 if (!IsEmptyStr(my_addresses)) {
270                         strcat(my_addresses, ",\n");
271                 }
272                 strcat(my_addresses, "\"");
273                 strcat(my_addresses, buf);
274                 strcat(my_addresses, "\"");
275         }
276
277         /* Now generate the script and write it to the Citadel server */
278         serv_printf("MSIV putscript|%s|", RULES_SCRIPT);
279         serv_getln(buf, sizeof buf);
280         if (buf[0] != '4') {
281                 return;
282         }
283
284         serv_puts("# THIS SCRIPT WAS AUTOMATICALLY GENERATED BY WEBCIT.");
285         serv_puts("# ");
286         serv_puts("# Do not attempt to manually edit it.  If you do so,");
287         serv_puts("# your changes will be overwritten the next time WebCit");
288         serv_puts("# saves its mail filtering rule set.  If you really want");
289         serv_puts("# to use these rules as the basis for another script,");
290         serv_puts("# copy them to another script and save that instead.");
291         serv_puts("");
292         serv_puts("require \"fileinto\";");
293         serv_puts("require \"reject\";");
294         serv_puts("require \"vacation\";");
295         serv_puts("require \"envelope\";");
296         serv_puts("");
297
298         for (i=0; i<MAX_RULES; ++i) {
299                 
300                 strcpy(rule, "");
301
302                 sprintf(fname, "active%d", i);
303                 active = !strcasecmp(BSTR(fname), "on") ;
304
305                 if (active) {
306
307                         sprintf(fname, "hfield%d", i);
308                         safestrncpy(hfield, BSTR(fname), sizeof hfield);
309         
310                         sprintf(fname, "compare%d", i);
311                         safestrncpy(compare, BSTR(fname), sizeof compare);
312         
313                         sprintf(fname, "htext%d", i);
314                         safestrncpy(htext, BSTR(fname), sizeof htext);
315         
316                         sprintf(fname, "sizecomp%d", i);
317                         safestrncpy(sizecomp, BSTR(fname), sizeof sizecomp);
318         
319                         sprintf(fname, "sizeval%d", i);
320                         sizeval = IBSTR(fname);
321         
322                         sprintf(fname, "action%d", i);
323                         safestrncpy(action, BSTR(fname), sizeof action);
324         
325                         sprintf(fname, "fileinto%d", i);
326                         safestrncpy(fileinto, BSTR(fname), sizeof fileinto);
327         
328                         sprintf(fname, "redirect%d", i);
329                         safestrncpy(redirect, BSTR(fname), sizeof redirect);
330         
331                         sprintf(fname, "automsg%d", i);
332                         safestrncpy(automsg, BSTR(fname), sizeof automsg);
333         
334                         sprintf(fname, "final%d", i);
335                         safestrncpy(final, BSTR(fname), sizeof final);
336         
337                         snprintf(rule, sizeof rule, "%d|%s|%s|%s|%s|%d|%s|%s|%s|%s|%s",
338                                 active, hfield, compare, htext, sizecomp, sizeval, action, fileinto,
339                                 redirect, automsg, final
340                         );
341         
342                         CtdlEncodeBase64(encoded_rule, rule, strlen(rule)+1, 0);
343                         serv_printf("# WEBCIT_RULE|%d|%s|", i, encoded_rule);
344                         output_sieve_rule(hfield, compare, htext, sizecomp, sizeval,
345                                         action, fileinto, redirect, automsg, final, my_addresses);
346                         serv_puts("");
347                 }
348
349
350         }
351
352         serv_puts("stop;");
353         serv_puts("000");
354 }
355
356
357
358 /*
359  * save sieve config
360  */
361 void save_sieve(void) {
362         int bigaction;
363         char script_names[MAX_SCRIPTS][64];
364         int num_scripts = 0;
365         int active_script = (-1);       /* this throws a 'set but not used' warning , check this ! */
366         int i;
367         char this_name[64];
368         char buf[256];
369
370         if (!havebstr("save_button")) {
371                 AppendImportantMessage(_("Cancelled.  Changes were not saved."), -1);
372                 display_main_menu();
373                 return;
374         }
375
376         parse_fields_from_rule_editor();
377
378         serv_puts("MSIV listscripts");
379         serv_getln(buf, sizeof(buf));
380         if (buf[0] == '1') while (serv_getln(buf, sizeof(buf)), strcmp(buf, "000")) {
381                 if (num_scripts < MAX_SCRIPTS) {
382                         extract_token(script_names[num_scripts], buf, 0, '|', 64);
383                         if (extract_int(buf, 1) > 0) {
384                                 active_script = num_scripts;
385                         }
386                         ++num_scripts;
387                 }
388         }
389
390         bigaction = ibstr("bigaction");
391
392         if (bigaction == 0) {
393                 serv_puts("MSIV setactive||");
394                 serv_getln(buf, sizeof buf);
395         }
396
397         else if (bigaction == 1) {
398                 serv_printf("MSIV setactive|%s|", RULES_SCRIPT);
399                 serv_getln(buf, sizeof buf);
400         }
401
402         else if (bigaction == 2) {
403                 serv_printf("MSIV setactive|%s|", bstr("active_script"));
404                 serv_getln(buf, sizeof buf);
405         }
406
407         if (num_scripts > 0) {
408                 for (i=0; i<num_scripts; ++i) {
409                         /*
410                          * We only want to save the scripts from the "manually edited scripts"
411                          * screen.  The script that WebCit generates from its ruleset will be
412                          * auto-generated by parse_fields_from_rule_editor() and saved there.
413                          */
414                         if (strcasecmp(script_names[i], RULES_SCRIPT)) {
415                                 serv_printf("MSIV putscript|%s|", script_names[i]);
416                                 serv_getln(buf, sizeof buf);
417                                 if (buf[0] == '4') {
418                                         snprintf(this_name, sizeof this_name, "text_%s", script_names[i]);
419                                         striplt((char *)BSTR(this_name)); /* TODO: get rid of typecast*/
420                                         serv_write(BSTR(this_name), strlen(BSTR(this_name)));
421                                         serv_puts("\n000");
422                                 }
423                         }
424                 }
425         }
426
427         AppendImportantMessage(_("Your changes have been saved."), -1);
428         display_main_menu();
429         return;
430 }
431
432 /*
433  * create a new script
434  * take the web environment script name and create it on the citadel server
435  */
436 void create_script(void) {
437         char buf[256];
438
439         serv_printf("MSIV getscript|%s", bstr("script_name"));
440         serv_getln(buf, sizeof buf);
441         if (buf[0] == '1') {
442                 while (serv_getln(buf, sizeof(buf)), strcmp(buf, "000")) {
443                         /* flush */
444                 }
445                 return;
446         }
447         
448         serv_printf("MSIV putscript|%s", bstr("script_name"));
449         serv_getln(buf, sizeof buf);
450         if (buf[0] == '4') {
451                 serv_puts("keep;");
452                 serv_puts("000");
453         output_headers(1, 1, 2, 0, 0, 0);
454         do_template("sieve_add");
455         wDumpContent(1);
456                 return;
457         }
458
459         output_headers(1, 1, 2, 0, 0, 0);
460         do_template("sieve_add");
461         wDumpContent(1);
462 }
463
464
465
466
467 /*
468  * delete a script
469  */
470 void delete_script(void) {
471         char buf[256];
472
473         serv_printf("MSIV deletescript|%s", bstr("script_name"));
474         serv_getln(buf, sizeof buf);
475         output_headers(1, 1, 2, 0, 0, 0);
476         do_template("sieve_add");
477         wDumpContent(1);
478 }
479                 
480
481
482 /*
483  * dummy panel indicating to the user that the server doesn't support Sieve
484  */
485 void display_no_sieve(void) {
486
487         output_headers(1, 1, 2, 0, 0, 0);
488         do_template("sieve_none");
489         wDumpContent(1);
490 }
491
492
493 typedef struct __SieveListing {
494         int IsActive;
495         int IsRulesScript;
496         StrBuf *Name;
497         StrBuf *Content;
498 } SieveListing;
499
500 int ConditionalSieveScriptIsActive(StrBuf *Target, WCTemplputParams *TP)
501 {
502         SieveListing     *SieveList = (SieveListing *)CTX;
503         return SieveList->IsActive;
504 }
505 int ConditionalSieveScriptIsRulesScript(StrBuf *Target, WCTemplputParams *TP)
506 {
507         SieveListing     *SieveList = (SieveListing *)CTX;
508         return SieveList->IsActive;
509 }
510 void tmplput_SieveScriptName(StrBuf *Target, WCTemplputParams *TP) 
511 {
512         SieveListing     *SieveList = (SieveListing *)CTX;
513         StrBufAppendTemplate(Target, TP, SieveList->Name, 0);
514 }
515 void tmplput_SieveScriptContent(StrBuf *Target, WCTemplputParams *TP) 
516 {
517         SieveListing     *SieveList = (SieveListing *)CTX;
518         StrBufAppendTemplate(Target, TP, SieveList->Content, 0);
519 }
520 void FreeSieveListing(void *vSieveListing)
521 {
522         SieveListing *List = (SieveListing*) vSieveListing;
523
524         FreeStrBuf(&List->Name);
525         free(List);
526 }
527
528 HashList *GetSieveScriptListing(StrBuf *Target, WCTemplputParams *TP)
529 {
530         wcsession *WCC = WC;
531         StrBuf *Line;
532         int num_scripts = 0;
533         int rules_script_active = 0;
534         int have_rules_script = 0;
535         const char *pch;
536         HashPos  *it;
537         int Done = 0;
538         SieveListing *Ruleset;
539
540         if (WCC->KnownSieveScripts != NULL)
541                 return WCC->KnownSieveScripts;
542
543         serv_puts("MSIV listscripts");
544         Line = NewStrBuf();
545         StrBuf_ServGetln(Line);
546         if (GetServerStatus(Line, NULL) == 1) 
547         {
548                 WCC->KnownSieveScripts = NewHash(1, Flathash);
549
550                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
551                         if ( (StrLength(Line)==3) && 
552                              !strcmp(ChrPtr(Line), "000")) 
553                         {
554                                 Done = 1;
555                         }
556                         else
557                         {
558                                 pch = NULL;
559                                 Ruleset = (SieveListing *) malloc(sizeof(SieveListing));
560                                 Ruleset->Name = NewStrBufPlain(NULL, StrLength(Line));
561                                 StrBufExtract_NextToken(Ruleset->Name, Line, &pch, '|');
562                                 Ruleset->IsActive = StrBufExtractNext_int(Line, &pch, '|'); 
563                                 Ruleset->Content = NULL;
564
565                                 if (!strcasecmp(ChrPtr(Ruleset->Name), RULES_SCRIPT))
566                                 {
567                                         Ruleset->IsRulesScript = 1;
568                                         have_rules_script = 1;
569                                         if (Ruleset->IsActive)
570                                         {
571                                                 rules_script_active = 1;
572                                                 PutBstr(HKEY("__SIEVE:RULESSCRIPT"), NewStrBufPlain(HKEY("1")));
573                                         }
574                                 }
575                                 Put(WCC->KnownSieveScripts, IKEY(num_scripts), Ruleset, FreeSieveListing);
576
577                                 ++num_scripts;
578                         }
579         }
580         if ((num_scripts > 0) && (rules_script_active == 0))
581                 PutBstr(HKEY("__SIEVE:EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
582
583         if (num_scripts > have_rules_script)
584         {
585                 long rc = 0;
586                 long len;
587                 const char *Key;
588                 void *vRuleset;
589
590                 /* 
591                  * ok; we have custom scripts, expose that via bstr, and load the payload.
592                  */
593                 PutBstr(HKEY("__SIEVE:HAVE_EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
594
595                 it = GetNewHashPos(WCC->KnownSieveScripts, 0);
596                 while (GetNextHashPos(WCC->KnownSieveScripts, it, &len, &Key, &vRuleset) && 
597                        (vRuleset != NULL))
598                 {
599                         Ruleset = (SieveListing *) vRuleset;
600
601                         /*
602                          * its the webcit rule? we don't need to load that here.
603                          */
604                         if (Ruleset->IsRulesScript)
605                                 continue;
606
607                         if (!serv_printf("MSIV getscript|%s", ChrPtr(Ruleset->Name)))
608                                 break;
609                         StrBuf_ServGetln(Line);
610                         if (GetServerStatus(Line, NULL) == 1) 
611                         {
612                                 Ruleset->Content = NewStrBuf();
613                                 while(!Done && (rc = StrBuf_ServGetln(Line), rc >= 0) )
614                                         if ( (StrLength(Line)==3) && 
615                                              !strcmp(ChrPtr(Line), "000")) 
616                                         {
617                                                 Done = 1;
618                                         }
619                                         else
620                                         {
621                                                 if (StrLength(Ruleset->Content)>0)
622                                                         StrBufAppendBufPlain(Ruleset->Content, HKEY("\n"), 0);
623                                                 StrBufAppendBuf(Ruleset->Content, Line, 0);
624                                         }
625                                 if (rc < 0) break;
626                         }
627                 }
628         }
629         FreeStrBuf(&Line);
630         return WCC->KnownSieveScripts;
631 }
632
633
634 typedef enum __eSieveHfield 
635 {
636         from,           
637         tocc,           
638         subject,        
639         replyto,        
640         sender, 
641         resentfrom,     
642         resentto,       
643         envfrom,        
644         envto,  
645         xmailer,        
646         xspamflag,      
647         xspamstatus,    
648         listid, 
649         size,           
650         all
651 } eSieveHfield;
652
653 typedef enum __eSieveCompare {
654         contains,
655         notcontains,
656         is,
657         isnot,
658         matches,
659         notmatches
660 } eSieveCompare;
661
662 typedef enum __eSieveAction {
663         keep,
664         discard,
665         reject,
666         fileinto,
667         redirect,
668         vacation
669 } eSieveAction;
670
671
672 typedef enum __eSieveSizeComp {
673         larger,
674         smaller
675 } eSieveSizeComp;
676
677 typedef enum __eSieveFinal {
678         econtinue,
679         estop
680 } eSieveFinal;
681
682
683 typedef struct __SieveRule {
684         int active;
685         int sizeval;
686         eSieveHfield hfield;
687         eSieveCompare compare;
688         StrBuf *htext;
689         eSieveSizeComp sizecomp;
690         eSieveAction Action;
691         StrBuf *fileinto;
692         StrBuf *redirect;
693         StrBuf *automsg;
694         eSieveFinal final;
695 }SieveRule;
696
697
698
699 int ConditionalSieveRule_hfield(StrBuf *Target, WCTemplputParams *TP)
700 {
701         SieveRule     *Rule = (SieveRule *)CTX;
702         
703         return GetTemplateTokenNumber(Target, 
704                                       TP, 
705                                       3, 
706                                       from)
707                 ==
708                 Rule->hfield;
709 }
710 int ConditionalSieveRule_compare(StrBuf *Target, WCTemplputParams *TP)
711 {
712         SieveRule     *Rule = (SieveRule *)CTX;
713         return GetTemplateTokenNumber(Target, 
714                                       TP, 
715                                       3, 
716                                       contains)
717                 ==
718                 Rule->compare;
719 }
720 int ConditionalSieveRule_action(StrBuf *Target, WCTemplputParams *TP)
721 {
722         SieveRule     *Rule = (SieveRule *)CTX;
723         return GetTemplateTokenNumber(Target, 
724                                       TP, 
725                                       3, 
726                                       keep)
727                 ==
728                 Rule->Action; 
729 }
730 int ConditionalSieveRule_sizecomp(StrBuf *Target, WCTemplputParams *TP)
731 {
732         SieveRule     *Rule = (SieveRule *)CTX;
733         return GetTemplateTokenNumber(Target, 
734                                       TP, 
735                                       3, 
736                                       larger)
737                 ==
738                 Rule->sizecomp;
739 }
740 int ConditionalSieveRule_final(StrBuf *Target, WCTemplputParams *TP)
741 {
742         SieveRule     *Rule = (SieveRule *)CTX;
743         return GetTemplateTokenNumber(Target, 
744                                       TP, 
745                                       3, 
746                                       econtinue)
747                 ==
748                 Rule->final;
749 }
750 int ConditionalSieveRule_ThisRoom(StrBuf *Target, WCTemplputParams *TP)
751 {
752         SieveRule     *Rule = (SieveRule *)CTX;
753         return GetTemplateTokenNumber(Target, 
754                                       TP, 
755                                       3, 
756                                       econtinue)
757                 ==
758                 Rule->final;
759 }
760 int ConditionalSieveRule_Active(StrBuf *Target, WCTemplputParams *TP)
761 {
762         SieveRule     *Rule = (SieveRule *)CTX;
763         return Rule->active;
764 }
765 void tmplput_SieveRule_htext(StrBuf *Target, WCTemplputParams *TP) 
766 {
767         SieveRule     *Rule = (SieveRule *)CTX;
768         StrBufAppendTemplate(Target, TP, Rule->htext, 0);
769 }
770 void tmplput_SieveRule_fileinto(StrBuf *Target, WCTemplputParams *TP) 
771 {
772         SieveRule     *Rule = (SieveRule *)CTX;
773         StrBufAppendTemplate(Target, TP, Rule->fileinto, 0);
774 }
775 void tmplput_SieveRule_redirect(StrBuf *Target, WCTemplputParams *TP) 
776 {
777         SieveRule     *Rule = (SieveRule *)CTX;
778         StrBufAppendTemplate(Target, TP, Rule->redirect, 0);
779 }
780 void tmplput_SieveRule_automsg(StrBuf *Target, WCTemplputParams *TP) 
781 {
782         SieveRule     *Rule = (SieveRule *)CTX;
783         StrBufAppendTemplate(Target, TP, Rule->automsg, 0);
784 }
785 void tmplput_SieveRule_sizeval(StrBuf *Target, WCTemplputParams *TP) 
786 {
787         SieveRule     *Rule = (SieveRule *)CTX;
788         StrBufAppendPrintf(Target, "%d", Rule->sizeval);
789 }
790
791 void tmplput_SieveRule_lookup_FileIntoRoom(StrBuf *Target, WCTemplputParams *TP) 
792 {
793         void *vRoom;
794         SieveRule     *Rule = (SieveRule *)CTX;
795         wcsession *WCC = WC;
796         HashList *Rooms = GetRoomListHashLKRA(Target, TP);
797
798         GetHash(Rooms, SKEY(Rule->fileinto), &vRoom);
799         WCC->ThisRoom = (folder*) vRoom;
800 }
801
802 void FreeSieveRule(void *vRule)
803 {
804         SieveRule *Rule = (SieveRule*) vRule;
805
806         FreeStrBuf(&Rule->htext);
807         FreeStrBuf(&Rule->fileinto);
808         FreeStrBuf(&Rule->redirect);
809         FreeStrBuf(&Rule->automsg);
810         
811         free(Rule);
812 }
813
814 #define WC_RULE_HEADER "# WEBCIT_RULE|"
815 HashList *GetSieveRules(StrBuf *Target, WCTemplputParams *TP)
816 {
817         StrBuf *Line = NULL;
818         StrBuf *EncodedRule = NULL;
819         int n = 0;
820         const char *pch = NULL;
821         HashList *SieveRules = NULL;
822         int Done = 0;
823         SieveRule *Rule = NULL;
824
825         SieveRules = NewHash(1, Flathash);
826         serv_printf("MSIV getscript|"RULES_SCRIPT);
827         Line = NewStrBuf();
828         EncodedRule = NewStrBuf();
829         StrBuf_ServGetln(Line);
830         if (GetServerStatus(Line, NULL) == 1) 
831         {
832                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
833                         if ( (StrLength(Line)==3) && 
834                              !strcmp(ChrPtr(Line), "000")) 
835                         {
836                                 Done = 1;
837                         }
838                         else
839                         {
840                                 pch = NULL;
841                                 /* We just care for our encoded header and skip everything else */
842                                 if ((StrLength(Line) > sizeof(WC_RULE_HEADER) - 1) &&
843                                     (!strncasecmp(ChrPtr(Line), HKEY(WC_RULE_HEADER))))
844                                 {
845                                         StrBufSkip_NTokenS(Line, &pch, '|', 1);
846                                         n = StrBufExtractNext_int(Line, &pch, '|'); 
847                                         StrBufExtract_NextToken(EncodedRule, Line, &pch, '|');
848                                         StrBufDecodeBase64(EncodedRule);
849
850                                         Rule = (SieveRule*) malloc(sizeof(SieveRule));
851
852                                         Rule->htext = NewStrBufPlain (NULL, StrLength(EncodedRule));
853
854                                         Rule->fileinto = NewStrBufPlain (NULL, StrLength(EncodedRule));
855                                         Rule->redirect = NewStrBufPlain (NULL, StrLength(EncodedRule));
856                                         Rule->automsg = NewStrBufPlain (NULL, StrLength(EncodedRule));
857
858                                         /* Grab our existing values to populate */
859                                         pch = NULL;
860                                         Rule->active = StrBufExtractNext_int(EncodedRule, &pch, '|');
861                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
862                                         
863                                         Rule->hfield = (eSieveHfield) GetTokenDefine(SKEY(Line), tocc);
864                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
865                                         Rule->compare = (eSieveCompare) GetTokenDefine(SKEY(Line), contains);
866                                         StrBufExtract_NextToken(Rule->htext, EncodedRule, &pch, '|');
867                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
868                                         Rule->sizecomp = (eSieveSizeComp) GetTokenDefine(SKEY(Line), larger);
869                                         Rule->sizeval = StrBufExtractNext_int(EncodedRule, &pch, '|');
870                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
871                                         Rule->Action = (eSieveAction) GetTokenDefine(SKEY(Line), keep);
872                                         StrBufExtract_NextToken(Rule->fileinto, EncodedRule, &pch, '|');
873                                         StrBufExtract_NextToken(Rule->redirect, EncodedRule, &pch, '|');
874                                         StrBufExtract_NextToken(Rule->automsg, EncodedRule, &pch, '|');
875                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
876                                         Rule->final = (eSieveFinal) GetTokenDefine(SKEY(Line), econtinue);
877                                         Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
878                                         n++;
879                                 }
880                         }
881         }
882
883         while (n < MAX_RULES) {
884                 Rule = (SieveRule*) malloc(sizeof(SieveRule));
885                 memset(Rule, 0, sizeof(SieveRule));
886                 Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
887             
888                 n++;
889         }
890
891
892         FreeStrBuf(&EncodedRule);
893         FreeStrBuf(&Line);
894         return SieveRules;
895 }
896
897 void
898 SessionDetachModule_SIEVE
899 (wcsession *sess)
900 {
901         DeleteHash(&sess->KnownSieveScripts);
902 }
903
904 void 
905 InitModule_SIEVE
906 (void)
907 {
908         REGISTERTokenParamDefine(from);         
909         REGISTERTokenParamDefine(tocc);         
910         REGISTERTokenParamDefine(subject);      
911         REGISTERTokenParamDefine(replyto);      
912         REGISTERTokenParamDefine(sender);       
913         REGISTERTokenParamDefine(resentfrom);   
914         REGISTERTokenParamDefine(resentto);     
915         REGISTERTokenParamDefine(envfrom);      
916         REGISTERTokenParamDefine(envto);        
917         REGISTERTokenParamDefine(xmailer);      
918         REGISTERTokenParamDefine(xspamflag);    
919         REGISTERTokenParamDefine(xspamstatus);  
920         REGISTERTokenParamDefine(listid);       
921         REGISTERTokenParamDefine(size);         
922         REGISTERTokenParamDefine(all);
923
924         REGISTERTokenParamDefine(contains);
925         REGISTERTokenParamDefine(notcontains);
926         REGISTERTokenParamDefine(is);
927         REGISTERTokenParamDefine(isnot);
928         REGISTERTokenParamDefine(matches);
929         REGISTERTokenParamDefine(notmatches);
930
931         REGISTERTokenParamDefine(keep);
932         REGISTERTokenParamDefine(discard);
933         REGISTERTokenParamDefine(reject);
934         REGISTERTokenParamDefine(fileinto);
935         REGISTERTokenParamDefine(redirect);
936         REGISTERTokenParamDefine(vacation);
937
938         REGISTERTokenParamDefine(larger);
939         REGISTERTokenParamDefine(smaller);
940
941         /* these are c-keyworads, so do it by hand. */
942         RegisterTokenParamDefine(HKEY("continue"), econtinue);
943         RegisterTokenParamDefine(HKEY("stop"), estop);
944
945         RegisterIterator("SIEVE:SCRIPTS", 0, NULL, GetSieveScriptListing, NULL, NULL, CTX_SIEVELIST, CTX_NONE, IT_NOFLAG);
946
947         RegisterConditional(HKEY("COND:SIEVE:SCRIPT:ACTIVE"), 0, ConditionalSieveScriptIsActive, CTX_SIEVELIST);
948         RegisterConditional(HKEY("COND:SIEVE:SCRIPT:ISRULES"), 0, ConditionalSieveScriptIsRulesScript, CTX_SIEVELIST);
949         RegisterNamespace("SIEVE:SCRIPT:NAME", 0, 1, tmplput_SieveScriptName, NULL, CTX_SIEVELIST);
950         RegisterNamespace("SIEVE:SCRIPT:CONTENT", 0, 1, tmplput_SieveScriptContent, NULL, CTX_SIEVELIST);
951
952  
953         RegisterIterator("SIEVE:RULES", 0, NULL, GetSieveRules, NULL, DeleteHash, CTX_SIEVESCRIPT, CTX_NONE, IT_NOFLAG);
954
955         RegisterConditional(HKEY("COND:SIEVE:ACTIVE"), 1, ConditionalSieveRule_Active, CTX_SIEVESCRIPT);
956         RegisterConditional(HKEY("COND:SIEVE:HFIELD"), 1, ConditionalSieveRule_hfield, CTX_SIEVESCRIPT);
957         RegisterConditional(HKEY("COND:SIEVE:COMPARE"), 1, ConditionalSieveRule_compare, CTX_SIEVESCRIPT);
958         RegisterConditional(HKEY("COND:SIEVE:ACTION"), 1, ConditionalSieveRule_action, CTX_SIEVESCRIPT);
959         RegisterConditional(HKEY("COND:SIEVE:SIZECOMP"), 1, ConditionalSieveRule_sizecomp, CTX_SIEVESCRIPT);
960         RegisterConditional(HKEY("COND:SIEVE:FINAL"), 1, ConditionalSieveRule_final, CTX_SIEVESCRIPT);
961         RegisterConditional(HKEY("COND:SIEVE:THISROOM"), 1, ConditionalSieveRule_ThisRoom, CTX_SIEVESCRIPT);
962
963         RegisterNamespace("SIEVE:SCRIPT:HTEXT", 0, 1, tmplput_SieveRule_htext, NULL, CTX_SIEVESCRIPT);
964         RegisterNamespace("SIEVE:SCRIPT:SIZE", 0, 1, tmplput_SieveRule_sizeval, NULL, CTX_SIEVESCRIPT);
965         RegisterNamespace("SIEVE:SCRIPT:FILEINTO", 0, 1, tmplput_SieveRule_fileinto, NULL, CTX_SIEVESCRIPT);
966         RegisterNamespace("SIEVE:SCRIPT:REDIRECT", 0, 1, tmplput_SieveRule_redirect, NULL, CTX_SIEVESCRIPT);
967         RegisterNamespace("SIEVE:SCRIPT:AUTOMSG", 0, 1, tmplput_SieveRule_automsg, NULL, CTX_SIEVESCRIPT);
968
969         /* fetch our room into WCC->ThisRoom, to evaluate while iterating over rooms with COND:THIS:THAT:ROOM */
970         RegisterNamespace("SIEVE:SCRIPT:LOOKUP_FILEINTO", 0, 1, tmplput_SieveRule_lookup_FileIntoRoom, NULL, CTX_SIEVESCRIPT);
971         WebcitAddUrlHandler(HKEY("save_sieve"), "", 0, save_sieve, 0);
972         WebcitAddUrlHandler(HKEY("create_script"), "", 0, create_script, 0);
973         WebcitAddUrlHandler(HKEY("delete_script"), "", 0, delete_script, 0);
974 }