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