}
}
-/*
- * We found the Sieve configuration for this user.
- * Now do something with it.
- */
-void get_sieve_config_backend(long msgnum, void *userdata) {
- struct sdm_userdata *u = (struct sdm_userdata *) userdata;
- struct CtdlMessage *msg;
- char *conf;
- long conflen;
- u->config_msgnum = msgnum;
- msg = CtdlFetchMessage(msgnum, 1, 1);
- if (msg == NULL) {
- u->config_msgnum = (-1) ;
- return;
- }
-
- CM_GetAsField(msg, eMesageText, &conf, &conflen);
- CM_Free(msg);
-
- if (conf != NULL) {
- parse_sieve_config(conf, u);
- free(conf);
- }
-
-}
/*
rewrite_ctdl_sieve_config(&u, (u.lastproc > orig_lastproc) ) ;
}
+#endif
-#endif
+/*
+ * A user account is identified as requring inbox processing.
+ * Do it.
+ */
+void do_inbox_processing_for_user(long usernum) {
+ 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);
+ CM_Free(msg);
+
+ if (conf == NULL) {
+ return; // config message exists but body is null
+ }
+
+
+ syslog(LOG_DEBUG, "RULEZ for %s", CC->user.fullname);
+ syslog(LOG_DEBUG, "%s", conf);
+
+ // do something now
+
+ free(conf);
+ }
+}
+
+
+/*
+ * Here is an array of users (by number) who have received messages in their inbox and may require processing.
+*/
+long *users_requiring_inbox_processing = NULL;
+int num_urip = 0;
+int num_urip_alloc = 0;
+/*
+ * Perform inbox processing for all rooms which require it
+ */
+void perform_inbox_processing(void) {
+ if (num_urip == 0) {
+ return; // no action required
+ }
+
+ for (int i=0; i<num_urip; ++i) {
+ do_inbox_processing_for_user(users_requiring_inbox_processing[i]);
+ }
+
+ free(users_requiring_inbox_processing);
+ users_requiring_inbox_processing = NULL;
+ num_urip = 0;
+ num_urip_alloc = 0;
+}
+
+
+/*
+ * This function is called after a message is saved to a room.
+ * If it's someone's inbox, we have to check for inbox rules
+ */
+int serv_inboxrules_roomhook(struct ctdlroom *room) {
+
+ // Is this someone's inbox?
+ if (!strcasecmp(&room->QRname[11], MAILROOM)) {
+ long usernum = atol(room->QRname);
+ if (usernum > 0) {
+
+ // first check to see if this user is already on the list
+ if (num_urip > 0) {
+ for (int i=0; i<=num_urip; ++i) {
+ if (users_requiring_inbox_processing[i] == usernum) { // already on the list!
+ return(0);
+ }
+ }
+ }
+
+ // make room if we need to
+ if (num_urip_alloc == 0) {
+ num_urip_alloc = 100;
+ users_requiring_inbox_processing = malloc(sizeof(long) * num_urip_alloc);
+ }
+ else if (num_urip >= num_urip_alloc) {
+ num_urip_alloc += 100;
+ users_requiring_inbox_processing = realloc(users_requiring_inbox_processing, (sizeof(long) * num_urip_alloc));
+ }
+
+ // now add the user to the list
+ users_requiring_inbox_processing[num_urip++] = usernum;
+ }
+ }
+
+ // No errors are possible from this function.
+ return(0);
+}
+
+
+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; i<ibr->num_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.
+}
/*
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))) {
{
if (!threading)
{
- // ctdl_sieve_init();
CtdlRegisterProtoHook(cmd_gibr, "GIBR", "Get InBox Rules");
CtdlRegisterProtoHook(cmd_pibr, "PIBR", "Put InBox Rules");
- // CtdlRegisterSessionHook(perform_sieve_processing, EVT_HOUSE, PRIO_HOUSE + 10);
- // CtdlRegisterCleanupHook(cleanup_sieve);
+ CtdlRegisterRoomHook(serv_inboxrules_roomhook);
+ CtdlRegisterSessionHook(perform_inbox_processing, EVT_HOUSE, PRIO_HOUSE + 10);
}
/* return our module name for the log */