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