X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Finboxrules%2Fserv_inboxrules.c;h=676662068098619cff99e172403bc8491662b65c;hb=37f40684d11b6206a0f26fafa7a7615cdf404319;hp=3705c9508e3f44dc0821c10ff9bb081cdf0fd54b;hpb=bfecf1bd874e7dc697631d430711415d9c8905ee;p=citadel.git diff --git a/citadel/modules/inboxrules/serv_inboxrules.c b/citadel/modules/inboxrules/serv_inboxrules.c index 3705c9508..676662068 100644 --- a/citadel/modules/inboxrules/serv_inboxrules.c +++ b/citadel/modules/inboxrules/serv_inboxrules.c @@ -424,7 +424,6 @@ int ctdl_getheaders(sieve2_context_t *s, void *my) { } - /* * Perform sieve processing for one message (called by sieve_do_room() for each message) */ @@ -819,41 +818,295 @@ BAIL: #endif +/* + * The next sections are enums and keys that drive the serialize/deserialize functions for the inbox rules/state configuration. + */ + +// Fields to be compared +enum { + field_from, + field_tocc, + field_subject, + field_replyto, + field_sender, + field_resentfrom, + field_resentto, + field_envfrom, + field_envto, + field_xmailer, + field_xspamflag, + field_xspamstatus, + field_listid, + field_size, + field_all +}; +char *field_keys[] = { + "from", + "tocc", + "subject", + "replyto", + "sender", + "resentfrom", + "resentto", + "envfrom", + "envto", + "xmailer", + "xspamflag", + "xspamstatus", + "listid", + "size", + "all" +}; + +// Field comparison operators +enum { + fcomp_contains, + fcomp_notcontains, + fcomp_is, + fcomp_isnot, + fcomp_matches, + fcomp_notmatches +}; +char *fcomp_keys[] = { + "contains", + "notcontains", + "is", + "isnot", + "matches", + "notmatches" +}; + +// Actions +enum { + action_keep, + action_discard, + action_reject, + action_fileinto, + action_redirect, + action_vacation +}; +char *action_keys[] = { + "keep", + "discard", + "reject", + "fileinto", + "redirect", + "vacation" +}; + +// Size comparison operators +enum { + scomp_larger, + scomp_smaller +}; +char *scomp_keys[] = { + "larger", + "smaller" +}; + +// Final actions +enum { + final_continue, + final_stop +}; +char *final_keys[] = { + "continue", + "stop" +}; + +// This data structure represents ONE inbox rule within the configuration. +struct irule { + int field_compare_op; + int compared_field; + char compared_value[128]; + int size_compare_op; + long compared_size; + int action; + char file_into[ROOMNAMELEN]; + char redirect_to[1024]; + char autoreply_message[SIZ]; + int final_action; +}; + +// This data structure represents the entire inbox rules configuration AND current state for a single user. +struct inboxrules { + long lastproc; + int num_rules; + struct irule *rules; +}; + + +// Destructor for 'struct inboxrules' +void free_inbox_rules(struct inboxrules *ibr) { + free(ibr->rules); + free(ibr); +} + + +// Constructor for 'struct inboxrules' that deserializes the configuration from text input. +struct inboxrules *deserialize_inbox_rules(char *serialized_rules) { + int i; + + if (!serialized_rules) { + return NULL; + } + + /* Make a copy of the supplied buffer because we're going to shit all over it with strtok_r() */ + char *sr = strdup(serialized_rules); + if (!sr) { + return NULL; + } + + struct inboxrules *ibr = malloc(sizeof(struct inboxrules)); + if (ibr == NULL) { + return NULL; + } + memset(ibr, 0, sizeof(struct inboxrules)); + + char *token; + char *rest = sr; + while ((token = strtok_r(rest, "\n", &rest))) { + + // For backwards compatibility, "# WEBCIT_RULE" is an alias for "rule". + // Prior to version 930, WebCit converted its rules to Sieve scripts, but saved the rules as comments for later re-editing. + // Now, the rules hidden in the comments become the real rules. + if (!strncasecmp(token, "# WEBCIT_RULE|", 14)) { + strcpy(token, "rule|"); + strcpy(&token[5], &token[14]); + } + + // Lines containing actual rules are double-serialized with Base64. It seemed like a good idea at the time :( + if (!strncasecmp(token, "rule|", 5)) { + remove_token(&token[5], 0, '|'); + char *decoded_rule = malloc(strlen(token)); + CtdlDecodeBase64(decoded_rule, &token[5], strlen(&token[5])); + ibr->num_rules++; + ibr->rules = realloc(ibr->rules, (sizeof(struct irule) * ibr->num_rules)); + struct irule *new_rule = &ibr->rules[ibr->num_rules - 1]; + memset(new_rule, 0, sizeof(struct irule)); + + // We have a rule , now parse it + char rtoken[SIZ]; + int nt = num_tokens(decoded_rule, '|'); + for (int t=0; tcompared_field = i; + } + } + break; + case 2: // field comparison operation + for (i=0; i<=fcomp_notmatches; ++i) { + if (!strcasecmp(rtoken, fcomp_keys[i])) { + new_rule->field_compare_op = i; + } + } + break; + case 3: // field comparison value + safestrncpy(new_rule->compared_value, rtoken, sizeof(new_rule->compared_value)); + break; + case 4: // size comparison operation + for (i=0; i<=scomp_smaller; ++i) { + if (!strcasecmp(rtoken, scomp_keys[i])) { + new_rule->size_compare_op = i; + } + } + break; + case 5: // size comparison value + new_rule->compared_size = atol(rtoken); + break; + case 6: // action + for (i=0; i<=action_vacation; ++i) { + if (!strcasecmp(rtoken, action_keys[i])) { + new_rule->action = i; + } + } + break; + case 7: // file into (target room) + safestrncpy(new_rule->file_into, rtoken, sizeof(new_rule->file_into)); + break; + case 8: // redirect to (target address) + safestrncpy(new_rule->redirect_to, rtoken, sizeof(new_rule->redirect_to)); + break; + case 9: // autoreply message + safestrncpy(new_rule->autoreply_message, rtoken, sizeof(new_rule->autoreply_message)); + break; + case 10: // final_action; + for (i=0; i<=final_stop; ++i) { + if (!strcasecmp(rtoken, final_keys[i])) { + new_rule->final_action = i; + } + } + break; + default: + break; + } + } + free(decoded_rule); + + // if we re-serialized this now, what would it look like? + //syslog(LOG_DEBUG, "test reserialize: 0|%s|%s|%s|%s|%ld|%s|%s|%s|%s|%s", + //field_keys[new_rule->compared_field], + //fcomp_keys[new_rule->field_compare_op], + //new_rule->compared_value, + //scomp_keys[new_rule->size_compare_op], + //new_rule->compared_size, + //action_keys[new_rule->action], + //new_rule->file_into, + //new_rule->redirect_to, + //new_rule->autoreply_message, + //final_keys[new_rule->final_action] + //); + // delete the above after moving it to a reserialize function + + } + + // "lastproc" indicates the newest message number in the inbox that was previously processed by our inbox rules. + else if (!strncasecmp(token, "lastproc|", 5)) { + ibr->lastproc = atol(&token[9]); + } + + } + + free(sr); // free our copy of the source buffer that has now been trashed with null bytes... + return(ibr); // and return our complex data type to the caller. +} + /* * A user account is identified as requring inbox processing. * Do it. */ void do_inbox_processing_for_user(long usernum) { + struct CtdlMessage *msg; + struct inboxrules *ii; + if (CtdlGetUserByNumber(&CC->user, usernum) == 0) { - TRACE; if (CC->user.msgnum_inboxrules <= 0) { return; // this user has no inbox rules } - struct CtdlMessage *msg; - char *conf; - long conflen; - msg = CtdlFetchMessage(CC->user.msgnum_inboxrules, 1, 1); if (msg == NULL) { return; // config msgnum is set but that message does not exist } - CM_GetAsField(msg, eMesageText, &conf, &conflen); + ii = deserialize_inbox_rules(msg->cm_fields[eMesageText]); CM_Free(msg); - if (conf == NULL) { + if (ii == NULL) { return; // config message exists but body is null } - + TRACE; syslog(LOG_DEBUG, "RULEZ for %s", CC->user.fullname); - syslog(LOG_DEBUG, "%s", conf); - - // do something now - free(conf); + // do something now FIXME actually write this + free_inbox_rules(ii); } } @@ -925,111 +1178,13 @@ int serv_inboxrules_roomhook(struct ctdlroom *room) { } -struct irule { - int field_compare_op; - char *compared_field; - char *compared_value; - int size_compare_op; - long compared_size; - int action; - char *file_into; - char *redirect_to; - char *autoreply_message; - int final_action; -}; - -struct inboxrules { - long lastproc; - int num_rules; - struct irule *rules; -}; - - -void free_inbox_rules(struct inboxrules *ibr) { - int i; - - if (ibr->num_rules > 0) { - for (i=0; inum_rules; ++i) { - if (ibr->rules[i].compared_field) free(ibr->rules[i].compared_field); - if (ibr->rules[i].compared_value) free(ibr->rules[i].compared_value); - if (ibr->rules[i].file_into) free(ibr->rules[i].file_into); - if (ibr->rules[i].redirect_to) free(ibr->rules[i].autoreply_message); - if (ibr->rules[i].autoreply_message) free(ibr->rules[i].autoreply_message); - } - } - - free(ibr->rules); - free(ibr); -} - - -/* - * Convert the serialized inbox rules message to a data type. - */ -struct inboxrules *deserialize_inbox_rules(char *serialized_rules) { - - if (!serialized_rules) { - return NULL; - } - - /* Make a copy of the supplied buffer because we're going to shit all over it with strtok_r() */ - char *sr = strdup(serialized_rules); - if (!sr) { - return NULL; - } - - struct inboxrules *ibr = malloc(sizeof(struct inboxrules)); - if (ibr == NULL) { - return NULL; - } - memset(ibr, 0, sizeof(struct inboxrules)); - - char *token; - char *rest = sr; - while ((token = strtok_r(rest, "\n", &rest))) { - - // For backwards compatibility, "# WEBCIT_RULE" is an alias for "rule". - // Prior to version 930, WebCit converted its rules to Sieve scripts, but saved the rules as comments for later re-editing. - // Now, the rules hidden in the comments are the real rules. - if (!strncasecmp(token, "# WEBCIT_RULE|", 14)) { - strcpy(token, "rule|"); - strcpy(&token[5], &token[14]); - } - - // Lines containing actual rules are double-serialized with Base64. It seemed like a good idea at the time :( - if (!strncasecmp(token, "rule|", 5)) { - syslog(LOG_DEBUG, "rule: %s", &token[5]); - remove_token(&token[5], 0, '|'); - char *decoded_rule = malloc(strlen(token)); - CtdlDecodeBase64(decoded_rule, &token[5], strlen(&token[5])); - TRACE; - syslog(LOG_DEBUG, "%s", decoded_rule); - - ibr->num_rules++; - ibr->rules = realloc(ibr->rules, (sizeof(struct irule) * ibr->num_rules)); - struct irule *new_rule = &ibr->rules[ibr->num_rules - 1]; - memset(new_rule, 0, sizeof(struct irule)); - - free(decoded_rule); - } - - // "lastproc" indicates the newest message number in the inbox that was previously processed by our inbox rules. - else if (!strncasecmp(token, "lastproc|", 5)) { - ibr->lastproc = atol(&token[9]); - syslog(LOG_DEBUG, "lastsent: %ld", ibr->lastproc); - } - - } - - free(sr); // free our copy of the source buffer that has now been trashed with null bytes... - return(ibr); // and return our complex data type to the caller. -} - /* * Get InBox Rules * * This is a client-facing function which fetches the user's inbox rules -- it omits all lines containing anything other than a rule. + * + * hmmmmm ... should we try to rebuild this in terms of deserialize_inbox_rules() instread? */ void cmd_gibr(char *argbuf) { @@ -1040,11 +1195,6 @@ void cmd_gibr(char *argbuf) { struct CtdlMessage *msg = CtdlFetchMessage(CC->user.msgnum_inboxrules, 1, 1); if (msg != NULL) { if (!CM_IsEmpty(msg, eMesageText)) { - - - struct inboxrules *ii = deserialize_inbox_rules(msg->cm_fields[eMesageText]); - free_inbox_rules(ii); - char *token; char *rest = msg->cm_fields[eMesageText]; while ((token = strtok_r(rest, "\n", &rest))) {