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