From dde4d5ad6c30e07cce1a727ac7a590d6ae241d06 Mon Sep 17 00:00:00 2001 From: David Champion Date: Mon, 23 Jan 2017 19:01:36 -0800 Subject: [PATCH] Abstract the SPAM_LIST as a generic REPLACE_LIST REPLACE_LIST can be used more generally as a list of pattern match-replace settings. SPAM_LIST was a special case of this, so spam handling has been been changed to use REPLACE_LIST instead, and SPAM_LIST was removed. A generic function for performing a REPLACE_LIST replacement has been added in mutt_apply_replace(). Commited by Kevin McCarthy with some buffer overflow fixes in mutt_apply_replace(). --- globals.h | 2 +- hcache.c | 2 +- init.c | 58 +++++++++++++++---------------- mutt.h | 12 +++---- muttlib.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++--- protos.h | 3 +- 6 files changed, 135 insertions(+), 42 deletions(-) diff --git a/globals.h b/globals.h index b51c558d8..4326fcec0 100644 --- a/globals.h +++ b/globals.h @@ -205,7 +205,7 @@ WHERE RX_LIST *MailLists INITVAL(0); WHERE RX_LIST *UnMailLists INITVAL(0); WHERE RX_LIST *SubscribedLists INITVAL(0); WHERE RX_LIST *UnSubscribedLists INITVAL(0); -WHERE SPAM_LIST *SpamList INITVAL(0); +WHERE REPLACE_LIST *SpamList INITVAL(0); WHERE RX_LIST *NoSpamList INITVAL(0); diff --git a/hcache.c b/hcache.c index 418a8f251..1d73c1e94 100644 --- a/hcache.c +++ b/hcache.c @@ -755,7 +755,7 @@ mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer) unsigned int intval; } digest; struct md5_ctx ctx; - SPAM_LIST *spam; + REPLACE_LIST *spam; RX_LIST *nospam; hcachever = HCACHEVER; diff --git a/init.c b/init.c index 30f0cb54b..0e14f0dda 100644 --- a/init.c +++ b/init.c @@ -462,11 +462,11 @@ int mutt_add_to_rx_list (RX_LIST **list, const char *s, int flags, BUFFER *err) return 0; } -static int remove_from_spam_list (SPAM_LIST **list, const char *pat); +static int remove_from_replace_list (REPLACE_LIST **list, const char *pat); -static int add_to_spam_list (SPAM_LIST **list, const char *pat, const char *templ, BUFFER *err) +static int add_to_replace_list (REPLACE_LIST **list, const char *pat, const char *templ, BUFFER *err) { - SPAM_LIST *t = NULL, *last = NULL; + REPLACE_LIST *t = NULL, *last = NULL; REGEXP *rx; int n; const char *p; @@ -499,12 +499,12 @@ static int add_to_spam_list (SPAM_LIST **list, const char *pat, const char *temp break; } - /* If t is set, it's pointing into an extant SPAM_LIST* that we want to + /* If t is set, it's pointing into an extant REPLACE_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 = mutt_new_replace_list(); t->rx = rx; if (last) last->next = t; @@ -512,7 +512,7 @@ static int add_to_spam_list (SPAM_LIST **list, const char *pat, const char *temp *list = t; } - /* Now t is the SPAM_LIST* that we want to modify. It is prepared. */ + /* Now t is the REPLACE_LIST* that we want to modify. It is prepared. */ t->template = safe_strdup(templ); /* Find highest match number in template string */ @@ -533,9 +533,9 @@ static int add_to_spam_list (SPAM_LIST **list, const char *pat, const char *temp if (t->nmatch > t->rx->rx->re_nsub) { - snprintf (err->data, err->dsize, _("Not enough subexpressions for spam " + snprintf (err->data, err->dsize, _("Not enough subexpressions for " "template")); - remove_from_spam_list(list, pat); + remove_from_replace_list(list, pat); return -1; } @@ -544,38 +544,38 @@ static int add_to_spam_list (SPAM_LIST **list, const char *pat, const char *temp return 0; } -static int remove_from_spam_list (SPAM_LIST **list, const char *pat) +static int remove_from_replace_list (REPLACE_LIST **list, const char *pat) { - SPAM_LIST *spam, *prev; + REPLACE_LIST *cur, *prev; int nremoved = 0; /* Being first is a special case. */ - spam = *list; - if (!spam) + cur = *list; + if (!cur) return 0; - if (spam->rx && !mutt_strcmp(spam->rx->pattern, pat)) + if (cur->rx && !mutt_strcmp(cur->rx->pattern, pat)) { - *list = spam->next; - mutt_free_regexp(&spam->rx); - FREE(&spam->template); - FREE(&spam); + *list = cur->next; + mutt_free_regexp(&cur->rx); + FREE(&cur->template); + FREE(&cur); return 1; } - prev = spam; - for (spam = prev->next; spam;) + prev = cur; + for (cur = prev->next; cur;) { - if (!mutt_strcmp(spam->rx->pattern, pat)) + if (!mutt_strcmp(cur->rx->pattern, pat)) { - prev->next = spam->next; - mutt_free_regexp(&spam->rx); - FREE(&spam->template); - FREE(&spam); - spam = prev->next; + prev->next = cur->next; + mutt_free_regexp(&cur->rx); + FREE(&cur->template); + FREE(&cur); + cur = prev->next; ++nremoved; } else - spam = spam->next; + cur = cur->next; } return nremoved; @@ -912,7 +912,7 @@ static int parse_spam_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER * mutt_extract_token (&templ, s, 0); /* Add to the spam list. */ - if (add_to_spam_list (&SpamList, buf->data, templ.data, err) != 0) { + if (add_to_replace_list (&SpamList, buf->data, templ.data, err) != 0) { FREE(&templ.data); return -1; } @@ -936,13 +936,13 @@ static int parse_spam_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER * /* "*" is a special case. */ if (!mutt_strcmp(buf->data, "*")) { - mutt_free_spam_list (&SpamList); + mutt_free_replace_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) + if (remove_from_replace_list(&SpamList, buf->data) != 0) return 0; /* Otherwise, add it to the nospam list. */ diff --git a/mutt.h b/mutt.h index 3b1f878a7..3440021e7 100644 --- a/mutt.h +++ b/mutt.h @@ -646,13 +646,13 @@ typedef struct rx_list_t struct rx_list_t *next; } RX_LIST; -typedef struct spam_list_t +typedef struct replace_list_t { REGEXP *rx; int nmatch; char *template; - struct spam_list_t *next; -} SPAM_LIST; + struct replace_list_t *next; +} REPLACE_LIST; inline LIST *mutt_new_list() { @@ -664,14 +664,14 @@ inline RX_LIST *mutt_new_rx_list() return safe_calloc (1, sizeof (RX_LIST)); } -inline SPAM_LIST *mutt_new_spam_list() +inline REPLACE_LIST *mutt_new_replace_list() { - return safe_calloc (1, sizeof (SPAM_LIST)); + return safe_calloc (1, sizeof (REPLACE_LIST)); } void mutt_free_list (LIST **); void mutt_free_rx_list (RX_LIST **); -void mutt_free_spam_list (SPAM_LIST **); +void mutt_free_replace_list (REPLACE_LIST **); LIST *mutt_copy_list (LIST *); int mutt_matches_ignore (const char *); int mutt_matches_list (const char *, LIST *); diff --git a/muttlib.c b/muttlib.c index c9a0bed35..ec751846c 100644 --- a/muttlib.c +++ b/muttlib.c @@ -58,7 +58,7 @@ */ extern LIST *mutt_new_list(); extern RX_LIST *mutt_new_rx_list(); -extern SPAM_LIST *mutt_new_spam_list(); +extern REPLACE_LIST *mutt_new_replace_list(); extern PARAMETER *mutt_new_parameter(); extern HEADER *mutt_new_header(); extern ENVELOPE *mutt_new_envelope(); @@ -1222,6 +1222,98 @@ void mutt_safe_path (char *s, size_t l, ADDRESS *a) *p = '_'; } +/* Note this function uses a fixed size buffer of LONG_STRING and so + * should only be used for visual modifications, such as disp_subj. */ +char *mutt_apply_replace (char *dbuf, size_t dlen, char *sbuf, REPLACE_LIST *rlist) +{ + REPLACE_LIST *l; + static regmatch_t *pmatch = NULL; + static int nmatch = 0; + static char twinbuf[2][LONG_STRING]; + int switcher = 0; + char *p; + int i, n; + size_t cpysize, tlen; + char *src, *dst; + + if (dbuf && dlen) + dbuf[0] = '\0'; + + if (sbuf == NULL || *sbuf == '\0' || (dbuf && !dlen)) + return dbuf; + + twinbuf[0][0] = '\0'; + twinbuf[1][0] = '\0'; + src = twinbuf[switcher]; + dst = src; + + strfcpy(src, sbuf, LONG_STRING); + + for (l = rlist; l; l = l->next) + { + /* If this pattern needs more matches, expand pmatch. */ + if (l->nmatch > nmatch) + { + safe_realloc (&pmatch, l->nmatch * sizeof(regmatch_t)); + nmatch = l->nmatch; + } + + if (regexec (l->rx->rx, src, l->nmatch, pmatch, 0) == 0) + { + tlen = 0; + switcher ^= 1; + dst = twinbuf[switcher]; + + mutt_debug (5, "mutt_apply_replace: %s matches %s\n", src, l->rx->pattern); + + /* Copy into other twinbuf with substitutions */ + if (l->template) + { + for (p = l->template; *p && (tlen < LONG_STRING - 1); ) + { + if (*p == '%') + { + p++; + if (*p == 'L') + { + p++; + cpysize = MIN (pmatch[0].rm_so, LONG_STRING - tlen - 1); + strncpy(&dst[tlen], src, cpysize); + tlen += cpysize; + } + else if (*p == 'R') + { + p++; + cpysize = MIN (strlen (src) - pmatch[0].rm_eo, LONG_STRING - tlen - 1); + strncpy(&dst[tlen], &src[pmatch[0].rm_eo], cpysize); + tlen += cpysize; + } + else + { + n = strtoul(p, &p, 10); /* get subst number */ + while (isdigit((unsigned char)*p)) /* skip subst token */ + ++p; + for (i = pmatch[n].rm_so; (i < pmatch[n].rm_eo) && (tlen < LONG_STRING-1); i++) + dst[tlen++] = src[i]; + } + } + else + dst[tlen++] = *p++; + } + } + dst[tlen] = '\0'; + mutt_debug (5, "mutt_apply_replace: subst %s\n", dst); + } + src = dst; + } + + if (dbuf) + strfcpy(dbuf, dst, dlen); + else + dbuf = safe_strdup(dst); + return dbuf; +} + void mutt_FormatString (char *dest, /* output buffer */ size_t destlen, /* output buffer len */ @@ -2106,9 +2198,9 @@ void mutt_free_rx_list (RX_LIST **list) } } -void mutt_free_spam_list (SPAM_LIST **list) +void mutt_free_replace_list (REPLACE_LIST **list) { - SPAM_LIST *p; + REPLACE_LIST *p; if (!list) return; while (*list) @@ -2144,7 +2236,7 @@ int mutt_match_rx_list (const char *s, RX_LIST *l) * * Returns 1 if the argument `s` matches a pattern in the spam list, otherwise * 0. */ -int mutt_match_spam_list (const char *s, SPAM_LIST *l, char *text, int textsize) +int mutt_match_spam_list (const char *s, REPLACE_LIST *l, char *text, int textsize) { static regmatch_t *pmatch = NULL; static int nmatch = 0; diff --git a/protos.h b/protos.h index 952887487..7653c8254 100644 --- a/protos.h +++ b/protos.h @@ -287,6 +287,7 @@ void mutt_alias_add_reverse (ALIAS *t); void mutt_alias_delete_reverse (ALIAS *t); int mutt_alloc_color (int fg, int bg); int mutt_any_key_to_continue (const char *); +char *mutt_apply_replace (char *, size_t, char *, REPLACE_LIST *); int mutt_buffy_check (int); int mutt_buffy_notify (void); int mutt_builtin_editor (const char *, HEADER *, HEADER *); @@ -347,7 +348,7 @@ int mutt_is_valid_mailbox (const char *); int mutt_link_threads (HEADER *, HEADER *, CONTEXT *); int mutt_lookup_mime_type (BODY *, const char *); int mutt_match_rx_list (const char *, RX_LIST *); -int mutt_match_spam_list (const char *, SPAM_LIST *, char *, int); +int mutt_match_spam_list (const char *, REPLACE_LIST *, char *, int); int mutt_messages_in_thread (CONTEXT *, HEADER *, int); int mutt_multi_choice (char *prompt, char *letters); int mutt_needs_mailcap (BODY *); -- 2.40.0