From 551a34918a27acfe110cb958044bfbc3c7b2d3d9 Mon Sep 17 00:00:00 2001 From: David Champion Date: Thu, 15 Jul 2004 08:08:32 +0000 Subject: [PATCH] v3 of the generic spam detection patch. --- doc/manual.sgml.head | 21 ++++-- init.c | 154 +++++++++++++++++++++++++++++++++---------- init.h | 6 +- mutt.h | 3 + 4 files changed, 139 insertions(+), 45 deletions(-) diff --git a/doc/manual.sgml.head b/doc/manual.sgml.head index 3dfb89a3..6698dcb9 100644 --- a/doc/manual.sgml.head +++ b/doc/manual.sgml.head @@ -1575,15 +1575,24 @@ priority than ``z''. Clearly, in general, sorting by spam tags is most effective when you can coerce your filter to give you a raw number. But in case you can't, mutt can still do something useful. -Finally, the spam "^From: .*MAILER-DAEMON" "999" diff --git a/init.c b/init.c index 4196aa0b..c07df0e1 100644 --- a/init.c +++ b/init.c @@ -368,7 +368,7 @@ static int add_to_rx_list (RX_LIST **list, const char *s, int flags, BUFFER *err static int add_to_spam_list (SPAM_LIST **list, const char *pat, const char *templ, BUFFER *err) { - SPAM_LIST *t, *last = NULL; + SPAM_LIST *t = NULL, *last = NULL; REGEXP *rx; int n; const char *p; @@ -387,49 +387,89 @@ static int add_to_spam_list (SPAM_LIST **list, const char *pat, const char *temp { if (ascii_strcasecmp (rx->pattern, last->rx->pattern) == 0) { - /* already on the list, so just ignore it */ - last = NULL; + /* Already on the list. Formerly we just skipped this case, but + * now we're supporting removals, which means we're supporting + * re-adds conceptually. So we probably want this to imply a + * removal, then do an add. We can achieve the removal by freeing + * the template, and leaving t pointed at the current item. + */ + t = last; + safe_free(&t->template); break; } if (!last->next) break; } - if (!*list || last) + /* If t is set, it's pointing into an extant SPAM_LIST* that we want to + * update. Otherwise we want to make a new one to link at the list's end. + */ + if (!t) { t = mutt_new_spam_list(); t->rx = rx; - t->template = safe_strdup(templ); + if (last) + last->next = t; + else + *list = t; + } - /* find highest match number in template string */ - t->nmatch = 0; - for (p = templ; *p;) + /* Now t is the SPAM_LIST* that we want to modify. It is prepared. */ + t->template = safe_strdup(templ); + + /* Find highest match number in template string */ + t->nmatch = 0; + for (p = templ; *p;) + { + if (*p == '%') { - if (*p == '%') - { - n = atoi(++p); - if (n > t->nmatch) - t->nmatch = n; - while (*p && isdigit(*p)) - ++p; - } - else - ++p; + n = atoi(++p); + if (n > t->nmatch) + t->nmatch = n; + while (*p && isdigit((int)*p)) + ++p; } - t->nmatch++; /* match 0 is always the whole expr */ + else + ++p; + } + t->nmatch++; /* match 0 is always the whole expr */ - if (last) + return 0; +} + +static int remove_from_spam_list (SPAM_LIST **list, const char *pat) +{ + SPAM_LIST *spam, *prev; + int nremoved = 0; + + /* Being first is a special case. */ + spam = *list; + if (spam->rx && !mutt_strcmp(spam->rx->pattern, pat)) + { + *list = spam->next; + mutt_free_regexp(&spam->rx); + safe_free(&spam->template); + safe_free(&spam); + return 1; + } + + prev = spam; + for (spam = prev->next; spam;) + { + if (!mutt_strcmp(spam->rx->pattern, pat)) { - last->next = t; - last = last->next; + prev->next = spam->next; + mutt_free_regexp(&spam->rx); + safe_free(&spam->template); + safe_free(&spam); + spam = prev->next; + ++nremoved; } else - *list = last = t; + spam = spam->next; } - else /* duplicate */ - mutt_free_regexp (&rx); - return 0; + return nremoved; } @@ -577,29 +617,71 @@ static int parse_spam_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER * memset(&templ, 0, sizeof(templ)); + /* Insist on at least one parameter */ if (!MoreArgs(s)) { - strfcpy(err->data, _("spam: no matching pattern"), err->dsize); + if (data == M_SPAM) + strfcpy(err->data, _("spam: no matching pattern"), err->dsize); + else + strfcpy(err->data, _("nospam: no matching pattern"), err->dsize); return -1; } + + /* Extract the first token, a regexp */ mutt_extract_token (buf, s, 0); - if (MoreArgs(s)) + /* data should be either M_SPAM or M_NOSPAM. M_SPAM is for spam commands. */ + if (data == M_SPAM) { - mutt_extract_token (&templ, s, 0); + /* If there's a second parameter, it's a template for the spam tag. */ + if (MoreArgs(s)) + { + mutt_extract_token (&templ, s, 0); + + /* Add to the spam list. */ + if (add_to_spam_list (&SpamList, buf->data, templ.data, err) != 0) + return -1; + } + + /* If not, try to remove from the nospam list. */ + else + { + remove_from_rx_list(&NoSpamList, buf->data); + } + + return 0; } - else + + /* M_NOSPAM is for nospam commands. */ + else if (data == M_NOSPAM) { - templ.data = NULL; - templ.dsize = 0; - } + /* nospam only ever has one parameter. */ + + /* "*" is a special case. */ + if (!mutt_strcmp(buf->data, "*")) + { + mutt_free_spam_list (&SpamList); + mutt_free_rx_list (&NoSpamList); + return 0; + } + + /* If it's on the spam list, just remove it. */ + if (remove_from_spam_list(&SpamList, buf->data) != 0) + return 0; - if (add_to_spam_list ((SPAM_LIST **) data, buf->data, templ.data, err) != 0) + /* Otherwise, add it to the nospam list. */ + if (add_to_rx_list (&NoSpamList, buf->data, REG_ICASE, err) != 0) return -1; - - return 0; + + return 0; + } + + /* This should not happen. */ + strfcpy(err->data, "This is no good at all.", err->dsize); + return -1; } + static int parse_unlist (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { do diff --git a/init.h b/init.h index 1a1633f9..59e1bf91 100644 --- a/init.h +++ b/init.h @@ -2434,7 +2434,7 @@ struct option_t MuttVars[] = { ** the message whether or not this is the case, as long as the ** non-``$$reply_regexp'' parts of both messages are identical. */ - { "spam_separator", DT_STR, R_NONE, UL &SpamSep, UL 0 }, + { "spam_separator", DT_STR, R_NONE, UL &SpamSep, UL "," }, /* ** .pp ** ``$spam_separator'' controls what happens when multiple spam headers @@ -2860,8 +2860,8 @@ struct command_t Commands[] = { { "send-hook", mutt_parse_hook, M_SENDHOOK }, { "set", parse_set, 0 }, { "source", parse_source, 0 }, - { "spam", parse_spam_list, UL &SpamList }, - { "nospam", parse_rx_list, UL &NoSpamList }, + { "spam", parse_spam_list, M_SPAM }, + { "nospam", parse_spam_list, M_NOSPAM }, { "subscribe", parse_subscribe, 0 }, { "toggle", parse_set, M_SET_INV }, { "unalias", parse_unalias, 0 }, diff --git a/mutt.h b/mutt.h index cfd60755..e26865ed 100644 --- a/mutt.h +++ b/mutt.h @@ -316,6 +316,9 @@ enum #define M_SEL_MULTI (1<<1) #define M_SEL_FOLDER (1<<2) +/* flags for parse_spam_list */ +#define M_SPAM 1 +#define M_NOSPAM 2 /* boolean vars */ enum -- 2.40.0