Mailing list header changes (fuck you Google)
[citadel.git] / webcit / sieve.c
1 /*
2  * Copyright (c) 1996-2020 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  * Implementation note: this was kind of hacked up when we switched from Sieve to custom rules.
14  * As a result there's probably some cruft in here...
15  * ajc 2020jul12
16  *
17  */
18
19 #include "webcit.h"
20
21 CtxType CTX_SIEVELIST = CTX_NONE;
22 CtxType CTX_SIEVESCRIPT = CTX_NONE;
23
24 #define MAX_SCRIPTS     100
25 #define MAX_RULES       50
26 #define RULES_SCRIPT    "__WebCit_Generated_Script__"
27
28
29 /*
30  * Translate the fields from the rule editor into something we can save...
31  */
32 void parse_fields_from_rule_editor(void) {
33
34         int active;
35         char hfield[256];
36         char compare[32];
37         char htext[256];
38         char sizecomp[32];
39         int sizeval;
40         char action[32];
41         char fileinto[128];
42         char redirect[256];
43         char automsg[1024];
44         char final[32];
45         int i;
46         char buf[256];
47         char fname[256];
48         char rule[2048];
49         char encoded_rule[4096];
50         char my_addresses[4096];
51         
52         /* Enumerate my email addresses in case they are needed for a vacation rule */
53         my_addresses[0] = 0;
54         serv_puts("GVEA");
55         serv_getln(buf, sizeof buf);
56         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
57                 if (!IsEmptyStr(my_addresses)) {
58                         strcat(my_addresses, ",\n");
59                 }
60                 strcat(my_addresses, "\"");
61                 strcat(my_addresses, buf);
62                 strcat(my_addresses, "\"");
63         }
64
65         /* Now generate the script and write it to the Citadel server */
66         serv_printf("PIBR");
67         serv_getln(buf, sizeof buf);
68         if (buf[0] != '4') {
69                 return;
70         }
71
72         for (i=0; i<MAX_RULES; ++i) {
73                 
74                 strcpy(rule, "");
75
76                 sprintf(fname, "active%d", i);
77                 active = !strcasecmp(BSTR(fname), "on") ;
78
79                 if (active) {
80
81                         sprintf(fname, "hfield%d", i);
82                         safestrncpy(hfield, BSTR(fname), sizeof hfield);
83         
84                         sprintf(fname, "compare%d", i);
85                         safestrncpy(compare, BSTR(fname), sizeof compare);
86         
87                         sprintf(fname, "htext%d", i);
88                         safestrncpy(htext, BSTR(fname), sizeof htext);
89         
90                         sprintf(fname, "sizecomp%d", i);
91                         safestrncpy(sizecomp, BSTR(fname), sizeof sizecomp);
92         
93                         sprintf(fname, "sizeval%d", i);
94                         sizeval = IBSTR(fname);
95         
96                         sprintf(fname, "action%d", i);
97                         safestrncpy(action, BSTR(fname), sizeof action);
98         
99                         sprintf(fname, "fileinto%d", i);
100                         safestrncpy(fileinto, BSTR(fname), sizeof fileinto);
101         
102                         sprintf(fname, "redirect%d", i);
103                         safestrncpy(redirect, BSTR(fname), sizeof redirect);
104         
105                         sprintf(fname, "automsg%d", i);
106                         safestrncpy(automsg, BSTR(fname), sizeof automsg);
107         
108                         sprintf(fname, "final%d", i);
109                         safestrncpy(final, BSTR(fname), sizeof final);
110         
111                         snprintf(rule, sizeof rule, "%d|%s|%s|%s|%s|%d|%s|%s|%s|%s|%s",
112                                 active, hfield, compare, htext, sizecomp, sizeval, action, fileinto,
113                                 redirect, automsg, final
114                         );
115         
116                         size_t len = CtdlEncodeBase64(encoded_rule, rule, strlen(rule)+1, 0);
117                         if (encoded_rule[len - 1] == '\n') {
118                                 encoded_rule[len - 1] = '\0';
119                         }
120                         serv_printf("rule|%d|%s|", i, encoded_rule);
121                         serv_puts("");
122                 }
123         }
124
125         serv_puts("000");
126 }
127
128
129 /*
130  * save sieve config
131  */
132 void save_sieve(void) {
133
134         if (!havebstr("save_button")) {
135                 AppendImportantMessage(_("Cancelled.  Changes were not saved."), -1);
136                 display_main_menu();
137                 return;
138         }
139
140         parse_fields_from_rule_editor();
141
142         AppendImportantMessage(_("Your changes have been saved."), -1);
143         display_main_menu();
144         return;
145 }
146
147
148 void display_sieve_add_or_delete(void) {
149         output_headers(1, 1, 2, 0, 0, 0);
150         do_template("sieve_add");
151         wDumpContent(1);
152 }
153
154
155
156 /*
157  * dummy panel indicating to the user that the server doesn't support Sieve
158  */
159 void display_no_sieve(void) {
160
161         output_headers(1, 1, 1, 0, 0, 0);
162         do_template("sieve_none");
163         wDumpContent(1);
164 }
165
166
167 typedef struct __SieveListing {
168         int IsActive;
169         int IsRulesScript;
170         StrBuf *Name;
171         StrBuf *Content;
172 } SieveListing;
173
174 int ConditionalSieveScriptIsActive(StrBuf *Target, WCTemplputParams *TP)
175 {
176         SieveListing     *SieveList = (SieveListing *)CTX(CTX_SIEVELIST);
177         return SieveList->IsActive;
178 }
179 int ConditionalSieveScriptIsRulesScript(StrBuf *Target, WCTemplputParams *TP)
180 {
181         SieveListing     *SieveList = (SieveListing *)CTX(CTX_SIEVELIST);
182         return SieveList->IsActive;
183 }
184 void tmplput_SieveScriptName(StrBuf *Target, WCTemplputParams *TP) 
185 {
186         SieveListing     *SieveList = (SieveListing *)CTX(CTX_SIEVELIST);
187         StrBufAppendTemplate(Target, TP, SieveList->Name, 0);
188 }
189 void tmplput_SieveScriptContent(StrBuf *Target, WCTemplputParams *TP) 
190 {
191         SieveListing     *SieveList = (SieveListing *)CTX(CTX_SIEVELIST);
192         StrBufAppendTemplate(Target, TP, SieveList->Content, 0);
193 }
194 void FreeSieveListing(void *vSieveListing)
195 {
196         SieveListing *List = (SieveListing*) vSieveListing;
197
198         FreeStrBuf(&List->Name);
199         free(List);
200 }
201
202 HashList *GetSieveScriptListing(StrBuf *Target, WCTemplputParams *TP)
203 {
204         wcsession *WCC = WC;
205         StrBuf *Line;
206         int num_scripts = 0;
207         int rules_script_active = 0;
208         int have_rules_script = 0;
209         const char *pch;
210         HashPos  *it;
211         int Done = 0;
212         SieveListing *Ruleset;
213
214         if (WCC->KnownSieveScripts != NULL) {
215                 return WCC->KnownSieveScripts;
216         }
217
218         serv_puts("MSIV listscripts");
219         Line = NewStrBuf();
220         StrBuf_ServGetln(Line);
221         if (GetServerStatus(Line, NULL) == 1) 
222         {
223                 WCC->KnownSieveScripts = NewHash(1, Flathash);
224
225                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
226                         if ( (StrLength(Line)==3) && 
227                              !strcmp(ChrPtr(Line), "000")) 
228                         {
229                                 Done = 1;
230                         }
231                         else
232                         {
233                                 pch = NULL;
234                                 Ruleset = (SieveListing *) malloc(sizeof(SieveListing));
235                                 Ruleset->Name = NewStrBufPlain(NULL, StrLength(Line));
236                                 StrBufExtract_NextToken(Ruleset->Name, Line, &pch, '|');
237                                 Ruleset->IsActive = StrBufExtractNext_int(Line, &pch, '|'); 
238                                 Ruleset->Content = NULL;
239
240                                 if (!strcasecmp(ChrPtr(Ruleset->Name), RULES_SCRIPT))
241                                 {
242                                         Ruleset->IsRulesScript = 1;
243                                         have_rules_script = 1;
244                                         if (Ruleset->IsActive)
245                                         {
246                                                 rules_script_active = 1;
247                                                 PutBstr(HKEY("__SIEVE:RULESSCRIPT"), NewStrBufPlain(HKEY("1")));
248                                         }
249                                 }
250                                 Put(WCC->KnownSieveScripts, IKEY(num_scripts), Ruleset, FreeSieveListing);
251
252                                 ++num_scripts;
253                         }
254         }
255
256         if ((num_scripts > 0) && (rules_script_active == 0)) {
257                 PutBstr(HKEY("__SIEVE:EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
258         }
259
260         if (num_scripts > have_rules_script)
261         {
262                 long rc = 0;
263                 long len;
264                 const char *Key;
265                 void *vRuleset;
266
267                 /* 
268                  * ok; we have custom scripts, expose that via bstr, and load the payload.
269                  */
270                 PutBstr(HKEY("__SIEVE:HAVE_EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
271
272                 it = GetNewHashPos(WCC->KnownSieveScripts, 0);
273                 while (GetNextHashPos(WCC->KnownSieveScripts, it, &len, &Key, &vRuleset) && 
274                        (vRuleset != NULL))
275                 {
276                         Ruleset = (SieveListing *) vRuleset;
277                         serv_printf("MSIV getscript|%s", ChrPtr(Ruleset->Name));
278                         StrBuf_ServGetln(Line);
279                         if (GetServerStatus(Line, NULL) == 1) 
280                         {
281                                 Ruleset->Content = NewStrBuf();
282                                 Done = 0;
283                                 while(!Done && (rc = StrBuf_ServGetln(Line), rc >= 0) )
284                                         if ( (StrLength(Line)==3) && 
285                                              !strcmp(ChrPtr(Line), "000")) 
286                                         {
287                                                 Done = 1;
288                                         }
289                                         else
290                                         {
291                                                 if (StrLength(Ruleset->Content)>0)
292                                                         StrBufAppendBufPlain(Ruleset->Content, HKEY("\n"), 0);
293                                                 StrBufAppendBuf(Ruleset->Content, Line, 0);
294                                         }
295                                 if (rc < 0) break;
296                         }
297                 }
298         }
299         FreeStrBuf(&Line);
300         return WCC->KnownSieveScripts;
301 }
302
303
304 typedef enum __eSieveHfield 
305 {
306         from,           
307         tocc,           
308         subject,        
309         replyto,        
310         sender, 
311         resentfrom,     
312         resentto,       
313         envfrom,        
314         envto,  
315         xmailer,        
316         xspamflag,      
317         xspamstatus,    
318         listid, 
319         size,           
320         all
321 } eSieveHfield;
322
323 typedef enum __eSieveCompare {
324         contains,
325         notcontains,
326         is,
327         isnot,
328         matches,
329         notmatches
330 } eSieveCompare;
331
332 typedef enum __eSieveAction {
333         keep,
334         discard,
335         reject,
336         fileinto,
337         redirect,
338         vacation
339 } eSieveAction;
340
341
342 typedef enum __eSieveSizeComp {
343         larger,
344         smaller
345 } eSieveSizeComp;
346
347 typedef enum __eSieveFinal {
348         econtinue,
349         estop
350 } eSieveFinal;
351
352
353 typedef struct __SieveRule {
354         int active;
355         int sizeval;
356         eSieveHfield hfield;
357         eSieveCompare compare;
358         StrBuf *htext;
359         eSieveSizeComp sizecomp;
360         eSieveAction Action;
361         StrBuf *fileinto;
362         StrBuf *redirect;
363         StrBuf *automsg;
364         eSieveFinal final;
365 }SieveRule;
366
367
368
369 int ConditionalSieveRule_hfield(StrBuf *Target, WCTemplputParams *TP)
370 {
371         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
372         
373         return GetTemplateTokenNumber(Target, 
374                                       TP, 
375                                       3, 
376                                       from)
377                 ==
378                 Rule->hfield;
379 }
380 int ConditionalSieveRule_compare(StrBuf *Target, WCTemplputParams *TP)
381 {
382         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
383         return GetTemplateTokenNumber(Target, 
384                                       TP, 
385                                       3, 
386                                       contains)
387                 ==
388                 Rule->compare;
389 }
390 int ConditionalSieveRule_action(StrBuf *Target, WCTemplputParams *TP)
391 {
392         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
393         return GetTemplateTokenNumber(Target, 
394                                       TP, 
395                                       3, 
396                                       keep)
397                 ==
398                 Rule->Action; 
399 }
400 int ConditionalSieveRule_sizecomp(StrBuf *Target, WCTemplputParams *TP)
401 {
402         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
403         return GetTemplateTokenNumber(Target, 
404                                       TP, 
405                                       3, 
406                                       larger)
407                 ==
408                 Rule->sizecomp;
409 }
410 int ConditionalSieveRule_final(StrBuf *Target, WCTemplputParams *TP)
411 {
412         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
413         return GetTemplateTokenNumber(Target, 
414                                       TP, 
415                                       3, 
416                                       econtinue)
417                 ==
418                 Rule->final;
419 }
420 int ConditionalSieveRule_ThisRoom(StrBuf *Target, WCTemplputParams *TP)
421 {
422         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
423         return GetTemplateTokenNumber(Target, 
424                                       TP, 
425                                       3, 
426                                       econtinue)
427                 ==
428                 Rule->final;
429 }
430 int ConditionalSieveRule_Active(StrBuf *Target, WCTemplputParams *TP)
431 {
432         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
433         return Rule->active;
434 }
435 void tmplput_SieveRule_htext(StrBuf *Target, WCTemplputParams *TP) 
436 {
437         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
438         StrBufAppendTemplate(Target, TP, Rule->htext, 0);
439 }
440 void tmplput_SieveRule_fileinto(StrBuf *Target, WCTemplputParams *TP) 
441 {
442         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
443         StrBufAppendTemplate(Target, TP, Rule->fileinto, 0);
444 }
445 void tmplput_SieveRule_redirect(StrBuf *Target, WCTemplputParams *TP) 
446 {
447         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
448         StrBufAppendTemplate(Target, TP, Rule->redirect, 0);
449 }
450 void tmplput_SieveRule_automsg(StrBuf *Target, WCTemplputParams *TP) 
451 {
452         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
453         StrBufAppendTemplate(Target, TP, Rule->automsg, 0);
454 }
455 void tmplput_SieveRule_sizeval(StrBuf *Target, WCTemplputParams *TP) 
456 {
457         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
458         StrBufAppendPrintf(Target, "%d", Rule->sizeval);
459 }
460
461 void tmplput_SieveRule_lookup_FileIntoRoom(StrBuf *Target, WCTemplputParams *TP) 
462 {
463         void *vRoom;
464         SieveRule     *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
465         wcsession *WCC = WC;
466         HashList *Rooms = GetRoomListHashLKRA(Target, TP);
467
468         GetHash(Rooms, SKEY(Rule->fileinto), &vRoom);
469         WCC->ThisRoom = (folder*) vRoom;
470 }
471
472 void FreeSieveRule(void *vRule)
473 {
474         SieveRule *Rule = (SieveRule*) vRule;
475
476         FreeStrBuf(&Rule->htext);
477         FreeStrBuf(&Rule->fileinto);
478         FreeStrBuf(&Rule->redirect);
479         FreeStrBuf(&Rule->automsg);
480         
481         free(Rule);
482 }
483
484 #define WC_RULE_HEADER "rule|"
485 HashList *GetSieveRules(StrBuf *Target, WCTemplputParams *TP)
486 {
487         StrBuf *Line = NULL;
488         StrBuf *EncodedRule = NULL;
489         int n = 0;
490         const char *pch = NULL;
491         HashList *SieveRules = NULL;
492         int Done = 0;
493         SieveRule *Rule = NULL;
494
495         SieveRules = NewHash(1, Flathash);
496         serv_printf("GIBR");
497         Line = NewStrBuf();
498         EncodedRule = NewStrBuf();
499         StrBuf_ServGetln(Line);
500         if (GetServerStatus(Line, NULL) == 1) 
501         {
502                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
503                         if ( (StrLength(Line)==3) && 
504                              !strcmp(ChrPtr(Line), "000")) 
505                         {
506                                 Done = 1;
507                         }
508                         else
509                         {
510                                 pch = NULL;
511                                 /* We just care for our encoded header and skip everything else */
512                                 if ((StrLength(Line) > sizeof(WC_RULE_HEADER) - 1) && (!strncasecmp(ChrPtr(Line), HKEY(WC_RULE_HEADER))))
513                                 {
514                                         StrBufSkip_NTokenS(Line, &pch, '|', 1);
515                                         n = StrBufExtractNext_int(Line, &pch, '|'); 
516                                         StrBufExtract_NextToken(EncodedRule, Line, &pch, '|');
517                                         StrBufDecodeBase64(EncodedRule);
518
519                                         Rule = (SieveRule*) malloc(sizeof(SieveRule));
520
521                                         Rule->htext = NewStrBufPlain (NULL, StrLength(EncodedRule));
522
523                                         Rule->fileinto = NewStrBufPlain (NULL, StrLength(EncodedRule));
524                                         Rule->redirect = NewStrBufPlain (NULL, StrLength(EncodedRule));
525                                         Rule->automsg = NewStrBufPlain (NULL, StrLength(EncodedRule));
526
527                                         /* Grab our existing values to populate */
528                                         pch = NULL;
529                                         Rule->active = StrBufExtractNext_int(EncodedRule, &pch, '|');
530                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
531                                         
532                                         Rule->hfield = (eSieveHfield) GetTokenDefine(SKEY(Line), tocc);
533                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
534                                         Rule->compare = (eSieveCompare) GetTokenDefine(SKEY(Line), contains);
535                                         StrBufExtract_NextToken(Rule->htext, EncodedRule, &pch, '|');
536                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
537                                         Rule->sizecomp = (eSieveSizeComp) GetTokenDefine(SKEY(Line), larger);
538                                         Rule->sizeval = StrBufExtractNext_int(EncodedRule, &pch, '|');
539                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
540                                         Rule->Action = (eSieveAction) GetTokenDefine(SKEY(Line), keep);
541                                         StrBufExtract_NextToken(Rule->fileinto, EncodedRule, &pch, '|');
542                                         StrBufExtract_NextToken(Rule->redirect, EncodedRule, &pch, '|');
543                                         StrBufExtract_NextToken(Rule->automsg, EncodedRule, &pch, '|');
544                                         StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
545                                         Rule->final = (eSieveFinal) GetTokenDefine(SKEY(Line), econtinue);
546                                         Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
547                                         n++;
548                                 }
549                         }
550         }
551
552         while (n < MAX_RULES) {
553                 Rule = (SieveRule*) malloc(sizeof(SieveRule));
554                 memset(Rule, 0, sizeof(SieveRule));
555                 Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
556             
557                 n++;
558         }
559
560
561         FreeStrBuf(&EncodedRule);
562         FreeStrBuf(&Line);
563         return SieveRules;
564 }
565
566 void
567 SessionDetachModule_SIEVE
568 (wcsession *sess)
569 {
570         DeleteHash(&sess->KnownSieveScripts);
571 }
572
573 void 
574 InitModule_SIEVE
575 (void)
576 {
577         RegisterCTX(CTX_SIEVELIST);
578         RegisterCTX(CTX_SIEVESCRIPT);
579         REGISTERTokenParamDefine(from);         
580         REGISTERTokenParamDefine(tocc);         
581         REGISTERTokenParamDefine(subject);      
582         REGISTERTokenParamDefine(replyto);      
583         REGISTERTokenParamDefine(sender);       
584         REGISTERTokenParamDefine(resentfrom);   
585         REGISTERTokenParamDefine(resentto);     
586         REGISTERTokenParamDefine(envfrom);      
587         REGISTERTokenParamDefine(envto);        
588         REGISTERTokenParamDefine(xmailer);      
589         REGISTERTokenParamDefine(xspamflag);    
590         REGISTERTokenParamDefine(xspamstatus);  
591         REGISTERTokenParamDefine(listid);       
592         REGISTERTokenParamDefine(size);         
593         REGISTERTokenParamDefine(all);
594
595         REGISTERTokenParamDefine(contains);
596         REGISTERTokenParamDefine(notcontains);
597         REGISTERTokenParamDefine(is);
598         REGISTERTokenParamDefine(isnot);
599         REGISTERTokenParamDefine(matches);
600         REGISTERTokenParamDefine(notmatches);
601
602         REGISTERTokenParamDefine(keep);
603         REGISTERTokenParamDefine(discard);
604         REGISTERTokenParamDefine(reject);
605         REGISTERTokenParamDefine(fileinto);
606         REGISTERTokenParamDefine(redirect);
607         REGISTERTokenParamDefine(vacation);
608
609         REGISTERTokenParamDefine(larger);
610         REGISTERTokenParamDefine(smaller);
611
612         /* these are c-keyworads, so do it by hand. */
613         RegisterTokenParamDefine(HKEY("continue"), econtinue);
614         RegisterTokenParamDefine(HKEY("stop"), estop);
615
616         RegisterIterator("SIEVE:SCRIPTS", 0, NULL, GetSieveScriptListing, NULL, NULL, CTX_SIEVELIST, CTX_NONE, IT_NOFLAG);
617
618         RegisterConditional("COND:SIEVE:SCRIPT:ACTIVE", 0, ConditionalSieveScriptIsActive, CTX_SIEVELIST);
619         RegisterConditional("COND:SIEVE:SCRIPT:ISRULES", 0, ConditionalSieveScriptIsRulesScript, CTX_SIEVELIST);
620         RegisterNamespace("SIEVE:SCRIPT:NAME", 0, 1, tmplput_SieveScriptName, NULL, CTX_SIEVELIST);
621         RegisterNamespace("SIEVE:SCRIPT:CONTENT", 0, 1, tmplput_SieveScriptContent, NULL, CTX_SIEVELIST);
622
623  
624         RegisterIterator("SIEVE:RULES", 0, NULL, GetSieveRules, NULL, DeleteHash, CTX_SIEVESCRIPT, CTX_NONE, IT_NOFLAG);
625
626         RegisterConditional("COND:SIEVE:ACTIVE", 1, ConditionalSieveRule_Active, CTX_SIEVESCRIPT);
627         RegisterConditional("COND:SIEVE:HFIELD", 1, ConditionalSieveRule_hfield, CTX_SIEVESCRIPT);
628         RegisterConditional("COND:SIEVE:COMPARE", 1, ConditionalSieveRule_compare, CTX_SIEVESCRIPT);
629         RegisterConditional("COND:SIEVE:ACTION", 1, ConditionalSieveRule_action, CTX_SIEVESCRIPT);
630         RegisterConditional("COND:SIEVE:SIZECOMP", 1, ConditionalSieveRule_sizecomp, CTX_SIEVESCRIPT);
631         RegisterConditional("COND:SIEVE:FINAL", 1, ConditionalSieveRule_final, CTX_SIEVESCRIPT);
632         RegisterConditional("COND:SIEVE:THISROOM", 1, ConditionalSieveRule_ThisRoom, CTX_SIEVESCRIPT);
633
634         RegisterNamespace("SIEVE:SCRIPT:HTEXT", 0, 1, tmplput_SieveRule_htext, NULL, CTX_SIEVESCRIPT);
635         RegisterNamespace("SIEVE:SCRIPT:SIZE", 0, 1, tmplput_SieveRule_sizeval, NULL, CTX_SIEVESCRIPT);
636         RegisterNamespace("SIEVE:SCRIPT:FILEINTO", 0, 1, tmplput_SieveRule_fileinto, NULL, CTX_SIEVESCRIPT);
637         RegisterNamespace("SIEVE:SCRIPT:REDIRECT", 0, 1, tmplput_SieveRule_redirect, NULL, CTX_SIEVESCRIPT);
638         RegisterNamespace("SIEVE:SCRIPT:AUTOMSG", 0, 1, tmplput_SieveRule_automsg, NULL, CTX_SIEVESCRIPT);
639
640         /* fetch our room into WCC->ThisRoom, to evaluate while iterating over rooms with COND:THIS:THAT:ROOM */
641         RegisterNamespace("SIEVE:SCRIPT:LOOKUP_FILEINTO", 0, 1, tmplput_SieveRule_lookup_FileIntoRoom, NULL, CTX_SIEVESCRIPT);
642         WebcitAddUrlHandler(HKEY("save_sieve"), "", 0, save_sieve, 0);
643         WebcitAddUrlHandler(HKEY("display_sieve_add_or_delete"), "", 0, display_sieve_add_or_delete, 0);
644 }