2 * Copyright (c) 1996-2020 by the citadel.org team
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.
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.
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...
21 CtxType CTX_SIEVELIST = CTX_NONE;
22 CtxType CTX_SIEVESCRIPT = CTX_NONE;
24 #define MAX_SCRIPTS 100
26 #define RULES_SCRIPT "__WebCit_Generated_Script__"
30 * Translate the fields from the rule editor into something we can save...
32 void parse_fields_from_rule_editor(void) {
49 char encoded_rule[4096];
50 char my_addresses[4096];
52 /* Enumerate my email addresses in case they are needed for a vacation rule */
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");
60 strcat(my_addresses, "\"");
61 strcat(my_addresses, buf);
62 strcat(my_addresses, "\"");
65 /* Now generate the script and write it to the Citadel server */
67 serv_getln(buf, sizeof buf);
72 for (i=0; i<MAX_RULES; ++i) {
76 sprintf(fname, "active%d", i);
77 active = !strcasecmp(BSTR(fname), "on") ;
81 sprintf(fname, "hfield%d", i);
82 safestrncpy(hfield, BSTR(fname), sizeof hfield);
84 sprintf(fname, "compare%d", i);
85 safestrncpy(compare, BSTR(fname), sizeof compare);
87 sprintf(fname, "htext%d", i);
88 safestrncpy(htext, BSTR(fname), sizeof htext);
90 sprintf(fname, "sizecomp%d", i);
91 safestrncpy(sizecomp, BSTR(fname), sizeof sizecomp);
93 sprintf(fname, "sizeval%d", i);
94 sizeval = IBSTR(fname);
96 sprintf(fname, "action%d", i);
97 safestrncpy(action, BSTR(fname), sizeof action);
99 sprintf(fname, "fileinto%d", i);
100 safestrncpy(fileinto, BSTR(fname), sizeof fileinto);
102 sprintf(fname, "redirect%d", i);
103 safestrncpy(redirect, BSTR(fname), sizeof redirect);
105 sprintf(fname, "automsg%d", i);
106 safestrncpy(automsg, BSTR(fname), sizeof automsg);
108 sprintf(fname, "final%d", i);
109 safestrncpy(final, BSTR(fname), sizeof final);
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
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';
120 serv_printf("rule|%d|%s|", i, encoded_rule);
132 void save_sieve(void) {
134 if (!havebstr("save_button")) {
135 AppendImportantMessage(_("Cancelled. Changes were not saved."), -1);
140 parse_fields_from_rule_editor();
142 AppendImportantMessage(_("Your changes have been saved."), -1);
148 void display_sieve_add_or_delete(void) {
149 output_headers(1, 1, 2, 0, 0, 0);
150 do_template("sieve_add");
157 * dummy panel indicating to the user that the server doesn't support Sieve
159 void display_no_sieve(void) {
161 output_headers(1, 1, 1, 0, 0, 0);
162 do_template("sieve_none");
167 typedef struct __SieveListing {
174 int ConditionalSieveScriptIsActive(StrBuf *Target, WCTemplputParams *TP)
176 SieveListing *SieveList = (SieveListing *)CTX(CTX_SIEVELIST);
177 return SieveList->IsActive;
179 int ConditionalSieveScriptIsRulesScript(StrBuf *Target, WCTemplputParams *TP)
181 SieveListing *SieveList = (SieveListing *)CTX(CTX_SIEVELIST);
182 return SieveList->IsActive;
184 void tmplput_SieveScriptName(StrBuf *Target, WCTemplputParams *TP)
186 SieveListing *SieveList = (SieveListing *)CTX(CTX_SIEVELIST);
187 StrBufAppendTemplate(Target, TP, SieveList->Name, 0);
189 void tmplput_SieveScriptContent(StrBuf *Target, WCTemplputParams *TP)
191 SieveListing *SieveList = (SieveListing *)CTX(CTX_SIEVELIST);
192 StrBufAppendTemplate(Target, TP, SieveList->Content, 0);
194 void FreeSieveListing(void *vSieveListing)
196 SieveListing *List = (SieveListing*) vSieveListing;
198 FreeStrBuf(&List->Name);
202 HashList *GetSieveScriptListing(StrBuf *Target, WCTemplputParams *TP)
207 int rules_script_active = 0;
208 int have_rules_script = 0;
212 SieveListing *Ruleset;
214 if (WCC->KnownSieveScripts != NULL) {
215 return WCC->KnownSieveScripts;
218 serv_puts("MSIV listscripts");
220 StrBuf_ServGetln(Line);
221 if (GetServerStatus(Line, NULL) == 1)
223 WCC->KnownSieveScripts = NewHash(1, Flathash);
225 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
226 if ( (StrLength(Line)==3) &&
227 !strcmp(ChrPtr(Line), "000"))
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;
240 if (!strcasecmp(ChrPtr(Ruleset->Name), RULES_SCRIPT))
242 Ruleset->IsRulesScript = 1;
243 have_rules_script = 1;
244 if (Ruleset->IsActive)
246 rules_script_active = 1;
247 PutBstr(HKEY("__SIEVE:RULESSCRIPT"), NewStrBufPlain(HKEY("1")));
250 Put(WCC->KnownSieveScripts, IKEY(num_scripts), Ruleset, FreeSieveListing);
256 if ((num_scripts > 0) && (rules_script_active == 0)) {
257 PutBstr(HKEY("__SIEVE:EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
260 if (num_scripts > have_rules_script)
268 * ok; we have custom scripts, expose that via bstr, and load the payload.
270 PutBstr(HKEY("__SIEVE:HAVE_EXTERNAL_SCRIPT"), NewStrBufPlain(HKEY("1")));
272 it = GetNewHashPos(WCC->KnownSieveScripts, 0);
273 while (GetNextHashPos(WCC->KnownSieveScripts, it, &len, &Key, &vRuleset) &&
276 Ruleset = (SieveListing *) vRuleset;
277 serv_printf("MSIV getscript|%s", ChrPtr(Ruleset->Name));
278 StrBuf_ServGetln(Line);
279 if (GetServerStatus(Line, NULL) == 1)
281 Ruleset->Content = NewStrBuf();
283 while(!Done && (rc = StrBuf_ServGetln(Line), rc >= 0) )
284 if ( (StrLength(Line)==3) &&
285 !strcmp(ChrPtr(Line), "000"))
291 if (StrLength(Ruleset->Content)>0)
292 StrBufAppendBufPlain(Ruleset->Content, HKEY("\n"), 0);
293 StrBufAppendBuf(Ruleset->Content, Line, 0);
300 return WCC->KnownSieveScripts;
304 typedef enum __eSieveHfield
323 typedef enum __eSieveCompare {
332 typedef enum __eSieveAction {
342 typedef enum __eSieveSizeComp {
347 typedef enum __eSieveFinal {
353 typedef struct __SieveRule {
357 eSieveCompare compare;
359 eSieveSizeComp sizecomp;
369 int ConditionalSieveRule_hfield(StrBuf *Target, WCTemplputParams *TP)
371 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
373 return GetTemplateTokenNumber(Target,
380 int ConditionalSieveRule_compare(StrBuf *Target, WCTemplputParams *TP)
382 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
383 return GetTemplateTokenNumber(Target,
390 int ConditionalSieveRule_action(StrBuf *Target, WCTemplputParams *TP)
392 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
393 return GetTemplateTokenNumber(Target,
400 int ConditionalSieveRule_sizecomp(StrBuf *Target, WCTemplputParams *TP)
402 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
403 return GetTemplateTokenNumber(Target,
410 int ConditionalSieveRule_final(StrBuf *Target, WCTemplputParams *TP)
412 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
413 return GetTemplateTokenNumber(Target,
420 int ConditionalSieveRule_ThisRoom(StrBuf *Target, WCTemplputParams *TP)
422 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
423 return GetTemplateTokenNumber(Target,
430 int ConditionalSieveRule_Active(StrBuf *Target, WCTemplputParams *TP)
432 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
435 void tmplput_SieveRule_htext(StrBuf *Target, WCTemplputParams *TP)
437 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
438 StrBufAppendTemplate(Target, TP, Rule->htext, 0);
440 void tmplput_SieveRule_fileinto(StrBuf *Target, WCTemplputParams *TP)
442 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
443 StrBufAppendTemplate(Target, TP, Rule->fileinto, 0);
445 void tmplput_SieveRule_redirect(StrBuf *Target, WCTemplputParams *TP)
447 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
448 StrBufAppendTemplate(Target, TP, Rule->redirect, 0);
450 void tmplput_SieveRule_automsg(StrBuf *Target, WCTemplputParams *TP)
452 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
453 StrBufAppendTemplate(Target, TP, Rule->automsg, 0);
455 void tmplput_SieveRule_sizeval(StrBuf *Target, WCTemplputParams *TP)
457 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
458 StrBufAppendPrintf(Target, "%d", Rule->sizeval);
461 void tmplput_SieveRule_lookup_FileIntoRoom(StrBuf *Target, WCTemplputParams *TP)
464 SieveRule *Rule = (SieveRule *)CTX(CTX_SIEVESCRIPT);
466 HashList *Rooms = GetRoomListHashLKRA(Target, TP);
468 GetHash(Rooms, SKEY(Rule->fileinto), &vRoom);
469 WCC->ThisRoom = (folder*) vRoom;
472 void FreeSieveRule(void *vRule)
474 SieveRule *Rule = (SieveRule*) vRule;
476 FreeStrBuf(&Rule->htext);
477 FreeStrBuf(&Rule->fileinto);
478 FreeStrBuf(&Rule->redirect);
479 FreeStrBuf(&Rule->automsg);
484 #define WC_RULE_HEADER "rule|"
485 HashList *GetSieveRules(StrBuf *Target, WCTemplputParams *TP)
488 StrBuf *EncodedRule = NULL;
490 const char *pch = NULL;
491 HashList *SieveRules = NULL;
493 SieveRule *Rule = NULL;
495 SieveRules = NewHash(1, Flathash);
498 EncodedRule = NewStrBuf();
499 StrBuf_ServGetln(Line);
500 if (GetServerStatus(Line, NULL) == 1)
502 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
503 if ( (StrLength(Line)==3) &&
504 !strcmp(ChrPtr(Line), "000"))
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))))
514 StrBufSkip_NTokenS(Line, &pch, '|', 1);
515 n = StrBufExtractNext_int(Line, &pch, '|');
516 StrBufExtract_NextToken(EncodedRule, Line, &pch, '|');
517 StrBufDecodeBase64(EncodedRule);
519 Rule = (SieveRule*) malloc(sizeof(SieveRule));
521 Rule->htext = NewStrBufPlain (NULL, StrLength(EncodedRule));
523 Rule->fileinto = NewStrBufPlain (NULL, StrLength(EncodedRule));
524 Rule->redirect = NewStrBufPlain (NULL, StrLength(EncodedRule));
525 Rule->automsg = NewStrBufPlain (NULL, StrLength(EncodedRule));
527 /* Grab our existing values to populate */
529 Rule->active = StrBufExtractNext_int(EncodedRule, &pch, '|');
530 StrBufExtract_NextToken(Line, EncodedRule, &pch, '|');
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);
552 while (n < MAX_RULES) {
553 Rule = (SieveRule*) malloc(sizeof(SieveRule));
554 memset(Rule, 0, sizeof(SieveRule));
555 Put(SieveRules, IKEY(n), Rule, FreeSieveRule);
561 FreeStrBuf(&EncodedRule);
567 SessionDetachModule_SIEVE
570 DeleteHash(&sess->KnownSieveScripts);
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);
595 REGISTERTokenParamDefine(contains);
596 REGISTERTokenParamDefine(notcontains);
597 REGISTERTokenParamDefine(is);
598 REGISTERTokenParamDefine(isnot);
599 REGISTERTokenParamDefine(matches);
600 REGISTERTokenParamDefine(notmatches);
602 REGISTERTokenParamDefine(keep);
603 REGISTERTokenParamDefine(discard);
604 REGISTERTokenParamDefine(reject);
605 REGISTERTokenParamDefine(fileinto);
606 REGISTERTokenParamDefine(redirect);
607 REGISTERTokenParamDefine(vacation);
609 REGISTERTokenParamDefine(larger);
610 REGISTERTokenParamDefine(smaller);
612 /* these are c-keyworads, so do it by hand. */
613 RegisterTokenParamDefine(HKEY("continue"), econtinue);
614 RegisterTokenParamDefine(HKEY("stop"), estop);
616 RegisterIterator("SIEVE:SCRIPTS", 0, NULL, GetSieveScriptListing, NULL, NULL, CTX_SIEVELIST, CTX_NONE, IT_NOFLAG);
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);
624 RegisterIterator("SIEVE:RULES", 0, NULL, GetSieveRules, NULL, DeleteHash, CTX_SIEVESCRIPT, CTX_NONE, IT_NOFLAG);
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);
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);
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);