mini rfc2047 decoder for the text client
[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
541         serv_puts("MSIV listscripts");
542         Line = NewStrBuf();
543         StrBuf_ServGetln(Line);
544         if (GetServerStatus(Line, NULL) == 1) 
545         {
546                 WCC->KnownSieveScripts = NewHash(1, Flathash);
547
548                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
549                         if ( (StrLength(Line)==3) && 
550                              !strcmp(ChrPtr(Line), "000")) 
551                         {
552                                 Done = 1;
553                         }
554                         else
555                         {
556                                 pch = NULL;
557                                 Ruleset = (SieveListing *) malloc(sizeof(SieveListing));
558                                 Ruleset->Name = NewStrBufPlain(NULL, StrLength(Line));
559                                 StrBufExtract_NextToken(Ruleset->Name, Line, &pch, '|');
560                                 Ruleset->IsActive = StrBufExtractNext_int(Line, &pch, '|'); 
561                                 Ruleset->Content = NULL;
562
563                                 if (!strcasecmp(ChrPtr(Ruleset->Name), RULES_SCRIPT))
564                                 {
565                                         Ruleset->IsRulesScript = 1;
566                                         have_rules_script = 1;
567                                         if (Ruleset->IsActive)
568                                         {
569                                                 rules_script_active = 1;
570                                                 PutBstr(HKEY("__SIEVE:RULESSCRIPT"), NewStrBufPlain(HKEY("1")));
571                                         }
572                                 }
573                                 Put(WCC->KnownSieveScripts, IKEY(num_scripts), Ruleset, FreeSieveListing);
574
575                                 ++num_scripts;
576                         }
577         }
578         if ((num_scripts > 0) && (rules_script_active == 0))
579                 PutBstr(HKEY("__SIEVE:EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
580
581         if (num_scripts > have_rules_script)
582         {
583                 long rc = 0;
584                 long len;
585                 const char *Key;
586                 void *vRuleset;
587
588                 /* 
589                  * ok; we have custom scripts, expose that via bstr, and load the payload.
590                  */
591                 PutBstr(HKEY("__SIEVE:HAVE_EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
592
593                 it = GetNewHashPos(WCC->KnownSieveScripts, 0);
594                 while (GetNextHashPos(WCC->KnownSieveScripts, it, &len, &Key, &vRuleset) && 
595                        (vRuleset != NULL))
596                 {
597                         Ruleset = (SieveListing *) vRuleset;
598
599                         /*
600                          * its the webcit rule? we don't need to load that here.
601                          */
602                         if (Ruleset->IsRulesScript)
603                                 continue;
604
605                         if (!serv_printf("MSIV getscript|%s", ChrPtr(Ruleset->Name)))
606                                 break;
607                         StrBuf_ServGetln(Line);
608                         if (GetServerStatus(Line, NULL) == 1) 
609                         {
610                                 Ruleset->Content = NewStrBuf();
611                                 while(!Done && (rc = StrBuf_ServGetln(Line), rc >= 0) )
612                                         if ( (StrLength(Line)==3) && 
613                                              !strcmp(ChrPtr(Line), "000")) 
614                                         {
615                                                 Done = 1;
616                                         }
617                                         else
618                                         {
619                                                 if (StrLength(Ruleset->Content)>0)
620                                                         StrBufAppendBufPlain(Ruleset->Content, HKEY("\n"), 0);
621                                                 StrBufAppendBuf(Ruleset->Content, Line, 0);
622                                         }
623                                 if (rc < 0) break;
624                         }
625                 }
626         }
627         FreeStrBuf(&Line);
628         return WCC->KnownSieveScripts;
629 }
630
631
632 typedef enum __eSieveHfield 
633 {
634         from,           
635         tocc,           
636         subject,        
637         replyto,        
638         sender, 
639         resentfrom,     
640         resentto,       
641         envfrom,        
642         envto,  
643         xmailer,        
644         xspamflag,      
645         xspamstatus,    
646         listid, 
647         size,           
648         all
649 } eSieveHfield;
650
651 typedef enum __eSieveCompare {
652         contains,
653         notcontains,
654         is,
655         isnot,
656         matches,
657         notmatches
658 } eSieveCompare;
659
660 typedef enum __eSieveAction {
661         keep,
662         discard,
663         reject,
664         fileinto,
665         redirect,
666         vacation
667 } eSieveAction;
668
669
670 typedef enum __eSieveSizeComp {
671         larger,
672         smaller
673 } eSieveSizeComp;
674
675 typedef enum __eSieveFinal {
676         econtinue,
677         estop
678 } eSieveFinal;
679
680
681 typedef struct __SieveRule {
682         int active;
683         int sizeval;
684         eSieveHfield hfield;
685         eSieveCompare compare;
686         StrBuf *htext;
687         eSieveSizeComp sizecomp;
688         eSieveAction Action;
689         StrBuf *fileinto;
690         StrBuf *redirect;
691         StrBuf *automsg;
692         eSieveFinal final;
693 }SieveRule;
694
695
696
697 int ConditionalSieveRule_hfield(StrBuf *Target, WCTemplputParams *TP)
698 {
699         SieveRule     *Rule = (SieveRule *)CTX;
700         
701         return GetTemplateTokenNumber(Target, 
702                                       TP, 
703                                       3, 
704                                       from)
705                 ==
706                 Rule->hfield;
707 }
708 int ConditionalSieveRule_compare(StrBuf *Target, WCTemplputParams *TP)
709 {
710         SieveRule     *Rule = (SieveRule *)CTX;
711         return GetTemplateTokenNumber(Target, 
712                                       TP, 
713                                       3, 
714                                       contains)
715                 ==
716                 Rule->compare;
717 }
718 int ConditionalSieveRule_action(StrBuf *Target, WCTemplputParams *TP)
719 {
720         SieveRule     *Rule = (SieveRule *)CTX;
721         return GetTemplateTokenNumber(Target, 
722                                       TP, 
723                                       3, 
724                                       keep)
725                 ==
726                 Rule->Action; 
727 }
728 int ConditionalSieveRule_sizecomp(StrBuf *Target, WCTemplputParams *TP)
729 {
730         SieveRule     *Rule = (SieveRule *)CTX;
731         return GetTemplateTokenNumber(Target, 
732                                       TP, 
733                                       3, 
734                                       larger)
735                 ==
736                 Rule->sizecomp;
737 }
738 int ConditionalSieveRule_final(StrBuf *Target, WCTemplputParams *TP)
739 {
740         SieveRule     *Rule = (SieveRule *)CTX;
741         return GetTemplateTokenNumber(Target, 
742                                       TP, 
743                                       3, 
744                                       econtinue)
745                 ==
746                 Rule->final;
747 }
748 int ConditionalSieveRule_ThisRoom(StrBuf *Target, WCTemplputParams *TP)
749 {
750         SieveRule     *Rule = (SieveRule *)CTX;
751         return GetTemplateTokenNumber(Target, 
752                                       TP, 
753                                       3, 
754                                       econtinue)
755                 ==
756                 Rule->final;
757 }
758 int ConditionalSieveRule_Active(StrBuf *Target, WCTemplputParams *TP)
759 {
760         SieveRule     *Rule = (SieveRule *)CTX;
761         return Rule->active;
762 }
763 void tmplput_SieveRule_htext(StrBuf *Target, WCTemplputParams *TP) 
764 {
765         SieveRule     *Rule = (SieveRule *)CTX;
766         StrBufAppendTemplate(Target, TP, Rule->htext, 0);
767 }
768 void tmplput_SieveRule_fileinto(StrBuf *Target, WCTemplputParams *TP) 
769 {
770         SieveRule     *Rule = (SieveRule *)CTX;
771         StrBufAppendTemplate(Target, TP, Rule->fileinto, 0);
772 }
773 void tmplput_SieveRule_redirect(StrBuf *Target, WCTemplputParams *TP) 
774 {
775         SieveRule     *Rule = (SieveRule *)CTX;
776         StrBufAppendTemplate(Target, TP, Rule->redirect, 0);
777 }
778 void tmplput_SieveRule_automsg(StrBuf *Target, WCTemplputParams *TP) 
779 {
780         SieveRule     *Rule = (SieveRule *)CTX;
781         StrBufAppendTemplate(Target, TP, Rule->automsg, 0);
782 }
783 void tmplput_SieveRule_sizeval(StrBuf *Target, WCTemplputParams *TP) 
784 {
785         SieveRule     *Rule = (SieveRule *)CTX;
786         StrBufAppendPrintf(Target, "%d", Rule->sizeval);
787 }
788
789 void tmplput_SieveRule_lookup_FileIntoRoom(StrBuf *Target, WCTemplputParams *TP) 
790 {
791         void *vRoom;
792         SieveRule     *Rule = (SieveRule *)CTX;
793         wcsession *WCC = WC;
794         HashList *Rooms = GetRoomListHashLKRA(Target, TP);
795
796         GetHash(Rooms, SKEY(Rule->fileinto), &vRoom);
797         WCC->ThisRoom = (folder*) vRoom;
798 }
799
800 void FreeSieveRule(void *vRule)
801 {
802         SieveRule *Rule = (SieveRule*) vRule;
803
804         FreeStrBuf(&Rule->htext);
805         FreeStrBuf(&Rule->fileinto);
806         FreeStrBuf(&Rule->redirect);
807         FreeStrBuf(&Rule->automsg);
808         
809         free(Rule);
810 }
811
812 #define WC_RULE_HEADER "# WEBCIT_RULE|"
813 HashList *GetSieveRules(StrBuf *Target, WCTemplputParams *TP)
814 {
815         StrBuf *Line = NULL;
816         StrBuf *EncodedRule = NULL;
817         int n = 0;
818         const char *pch = NULL;
819         HashList *SieveRules = NULL;
820         int Done = 0;
821         SieveRule *Rule = NULL;
822
823         SieveRules = NewHash(1, Flathash);
824         serv_printf("MSIV getscript|"RULES_SCRIPT);
825         Line = NewStrBuf();
826         EncodedRule = NewStrBuf();
827         StrBuf_ServGetln(Line);
828         if (GetServerStatus(Line, NULL) == 1) 
829         {
830                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
831                         if ( (StrLength(Line)==3) && 
832                              !strcmp(ChrPtr(Line), "000")) 
833                         {
834                                 Done = 1;
835                         }
836                         else
837                         {
838                                 pch = NULL;
839                                 /* We just care for our encoded header and skip everything else */
840                                 if ((StrLength(Line) > sizeof(WC_RULE_HEADER) - 1) &&
841                                     (!strncasecmp(ChrPtr(Line), HKEY(WC_RULE_HEADER))))
842                                 {
843                                         StrBufSkip_NTokenS(Line, &pch, '|', 1);
844                                         n = StrBufExtractNext_int(Line, &pch, '|'); 
845                                         StrBufExtract_NextToken(EncodedRule, Line, &pch, '|');
846                                         StrBufDecodeBase64(EncodedRule);
847
848                                         Rule = (SieveRule*) malloc(sizeof(SieveRule));
849
850                                         Rule->htext = NewStrBufPlain (NULL, StrLength(EncodedRule));
851
852                                         Rule->fileinto = NewStrBufPlain (NULL, StrLength(EncodedRule));
853                                         Rule->redirect = NewStrBufPlain (NULL, StrLength(EncodedRule));
854                                         Rule->automsg = NewStrBufPlain (NULL, StrLength(EncodedRule));
855
856                                         /* Grab our existing values to populate */
857                                         pch = NULL;
858                                         Rule->active = StrBufExtractNext_int(EncodedRule, &pch, '|');
859                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
860                                         
861                                         Rule->hfield = (eSieveHfield) GetTokenDefine(SKEY(Line), tocc);
862                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
863                                         Rule->compare = (eSieveCompare) GetTokenDefine(SKEY(Line), contains);
864                                         StrBufExtract_NextToken(Rule->htext, EncodedRule, &pch, '|');
865                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
866                                         Rule->sizecomp = (eSieveSizeComp) GetTokenDefine(SKEY(Line), larger);
867                                         Rule->sizeval = StrBufExtractNext_int(EncodedRule, &pch, '|');
868                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
869                                         Rule->Action = (eSieveAction) GetTokenDefine(SKEY(Line), keep);
870                                         StrBufExtract_NextToken(Rule->fileinto, EncodedRule, &pch, '|');
871                                         StrBufExtract_NextToken(Rule->redirect, EncodedRule, &pch, '|');
872                                         StrBufExtract_NextToken(Rule->automsg, EncodedRule, &pch, '|');
873                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
874                                         Rule->final = (eSieveFinal) GetTokenDefine(SKEY(Line), econtinue);
875                                         Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
876                                         n++;
877                                 }
878                         }
879         }
880
881         while (n < MAX_RULES) {
882                 Rule = (SieveRule*) malloc(sizeof(SieveRule));
883                 memset(Rule, 0, sizeof(SieveRule));
884                 Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
885             
886                 n++;
887         }
888
889
890         FreeStrBuf(&EncodedRule);
891         FreeStrBuf(&Line);
892         return SieveRules;
893 }
894
895 void
896 SessionDetachModule_SIEVE
897 (wcsession *sess)
898 {
899         DeleteHash(&sess->KnownSieveScripts);
900 }
901
902 void 
903 InitModule_SIEVE
904 (void)
905 {
906         REGISTERTokenParamDefine(from);         
907         REGISTERTokenParamDefine(tocc);         
908         REGISTERTokenParamDefine(subject);      
909         REGISTERTokenParamDefine(replyto);      
910         REGISTERTokenParamDefine(sender);       
911         REGISTERTokenParamDefine(resentfrom);   
912         REGISTERTokenParamDefine(resentto);     
913         REGISTERTokenParamDefine(envfrom);      
914         REGISTERTokenParamDefine(envto);        
915         REGISTERTokenParamDefine(xmailer);      
916         REGISTERTokenParamDefine(xspamflag);    
917         REGISTERTokenParamDefine(xspamstatus);  
918         REGISTERTokenParamDefine(listid);       
919         REGISTERTokenParamDefine(size);         
920         REGISTERTokenParamDefine(all);
921
922         REGISTERTokenParamDefine(contains);
923         REGISTERTokenParamDefine(notcontains);
924         REGISTERTokenParamDefine(is);
925         REGISTERTokenParamDefine(isnot);
926         REGISTERTokenParamDefine(matches);
927         REGISTERTokenParamDefine(notmatches);
928
929         REGISTERTokenParamDefine(keep);
930         REGISTERTokenParamDefine(discard);
931         REGISTERTokenParamDefine(reject);
932         REGISTERTokenParamDefine(fileinto);
933         REGISTERTokenParamDefine(redirect);
934         REGISTERTokenParamDefine(vacation);
935
936         REGISTERTokenParamDefine(larger);
937         REGISTERTokenParamDefine(smaller);
938
939         /* these are c-keyworads, so do it by hand. */
940         RegisterTokenParamDefine(HKEY("continue"), econtinue);
941         RegisterTokenParamDefine(HKEY("stop"), estop);
942
943         RegisterIterator("SIEVE:SCRIPTS", 0, NULL, GetSieveScriptListing, NULL, NULL, CTX_SIEVELIST, CTX_NONE, IT_NOFLAG);
944
945         RegisterConditional(HKEY("COND:SIEVE:SCRIPT:ACTIVE"), 0, ConditionalSieveScriptIsActive, CTX_SIEVELIST);
946         RegisterConditional(HKEY("COND:SIEVE:SCRIPT:ISRULES"), 0, ConditionalSieveScriptIsRulesScript, CTX_SIEVELIST);
947         RegisterNamespace("SIEVE:SCRIPT:NAME", 0, 1, tmplput_SieveScriptName, NULL, CTX_SIEVELIST);
948         RegisterNamespace("SIEVE:SCRIPT:CONTENT", 0, 1, tmplput_SieveScriptContent, NULL, CTX_SIEVELIST);
949
950  
951         RegisterIterator("SIEVE:RULES", 0, NULL, GetSieveRules, NULL, DeleteHash, CTX_SIEVESCRIPT, CTX_NONE, IT_NOFLAG);
952
953         RegisterConditional(HKEY("COND:SIEVE:ACTIVE"), 1, ConditionalSieveRule_Active, CTX_SIEVESCRIPT);
954         RegisterConditional(HKEY("COND:SIEVE:HFIELD"), 1, ConditionalSieveRule_hfield, CTX_SIEVESCRIPT);
955         RegisterConditional(HKEY("COND:SIEVE:COMPARE"), 1, ConditionalSieveRule_compare, CTX_SIEVESCRIPT);
956         RegisterConditional(HKEY("COND:SIEVE:ACTION"), 1, ConditionalSieveRule_action, CTX_SIEVESCRIPT);
957         RegisterConditional(HKEY("COND:SIEVE:SIZECOMP"), 1, ConditionalSieveRule_sizecomp, CTX_SIEVESCRIPT);
958         RegisterConditional(HKEY("COND:SIEVE:FINAL"), 1, ConditionalSieveRule_final, CTX_SIEVESCRIPT);
959         RegisterConditional(HKEY("COND:SIEVE:THISROOM"), 1, ConditionalSieveRule_ThisRoom, CTX_SIEVESCRIPT);
960
961         RegisterNamespace("SIEVE:SCRIPT:HTEXT", 0, 1, tmplput_SieveRule_htext, NULL, CTX_SIEVESCRIPT);
962         RegisterNamespace("SIEVE:SCRIPT:SIZE", 0, 1, tmplput_SieveRule_sizeval, NULL, CTX_SIEVESCRIPT);
963         RegisterNamespace("SIEVE:SCRIPT:FILEINTO", 0, 1, tmplput_SieveRule_fileinto, NULL, CTX_SIEVESCRIPT);
964         RegisterNamespace("SIEVE:SCRIPT:REDIRECT", 0, 1, tmplput_SieveRule_redirect, NULL, CTX_SIEVESCRIPT);
965         RegisterNamespace("SIEVE:SCRIPT:AUTOMSG", 0, 1, tmplput_SieveRule_automsg, NULL, CTX_SIEVESCRIPT);
966
967         /* fetch our room into WCC->ThisRoom, to evaluate while iterating over rooms with COND:THIS:THAT:ROOM */
968         RegisterNamespace("SIEVE:SCRIPT:LOOKUP_FILEINTO", 0, 1, tmplput_SieveRule_lookup_FileIntoRoom, NULL, CTX_SIEVESCRIPT);
969         WebcitAddUrlHandler(HKEY("save_sieve"), "", 0, save_sieve, 0);
970         WebcitAddUrlHandler(HKEY("create_script"), "", 0, create_script, 0);
971         WebcitAddUrlHandler(HKEY("delete_script"), "", 0, delete_script, 0);
972 }