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