}
-
/*
* Perform sieve processing for one message (called by sieve_do_room() for each message)
*/
#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 FIXME actually write this
-
- 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
+ * The next sections are enums and keys that drive the serialize/deserialize functions for the inbox rules/state configuration.
*/
-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);
-}
-
+// Fields to be compared
enum {
field_from,
field_tocc,
"all"
};
-
+// Field comparison operators
enum {
fcomp_contains,
fcomp_notcontains,
"notmatches"
};
+// Actions
enum {
action_keep,
action_discard,
"vacation"
};
+// Size comparison operators
enum {
scomp_larger,
scomp_smaller
"smaller"
};
+// Final actions
enum {
final_continue,
final_stop
"stop"
};
+// This data structure represents ONE inbox rule within the configuration.
struct irule {
int field_compare_op;
int compared_field;
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;
};
+// Destructor for 'struct inboxrules'
void free_inbox_rules(struct inboxrules *ibr) {
free(ibr->rules);
free(ibr);
}
-/*
- * Convert the serialized inbox rules message to a data type.
- */
+// Constructor for 'struct inboxrules' that deserializes the configuration from text input.
struct inboxrules *deserialize_inbox_rules(char *serialized_rules) {
int i;
// 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.
+ // 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)) {
- 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));
// We have a rule , now parse it
- syslog(LOG_DEBUG, "Detokenizing: %s", decoded_rule);
char rtoken[SIZ];
int nt = num_tokens(decoded_rule, '|');
for (int t=0; t<nt; ++t) {
extract_token(rtoken, decoded_rule, t, '|', sizeof(rtoken));
striplt(rtoken);
- syslog(LOG_DEBUG, "Token %d : %s", t, rtoken);
switch(t) {
case 1: // field to compare
for (i=0; i<=field_all; ++i) {
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]
- );
+ //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
}
}
free(sr); // free our copy of the source buffer that has now been trashed with null bytes...
- abort();
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) {
+ if (CC->user.msgnum_inboxrules <= 0) {
+ return; // this user has no inbox rules
+ }
+
+ msg = CtdlFetchMessage(CC->user.msgnum_inboxrules, 1, 1);
+ if (msg == NULL) {
+ return; // config msgnum is set but that message does not exist
+ }
+
+ ii = deserialize_inbox_rules(msg->cm_fields[eMesageText]);
+ CM_Free(msg);
+
+ if (ii == NULL) {
+ return; // config message exists but body is null
+ }
+
+ TRACE;
+ syslog(LOG_DEBUG, "RULEZ for %s", CC->user.fullname);
+
+ // do something now FIXME actually write this
+ free_inbox_rules(ii);
+ }
+}
+
+
+/*
+ * 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);
+}
+
+
+
/*
* 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) {
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))) {