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