]> granicus.if.org Git - neomutt/commitdiff
Abstract the SPAM_LIST as a generic REPLACE_LIST
authorDavid Champion <dgc@bikeshed.us>
Tue, 24 Jan 2017 03:01:36 +0000 (19:01 -0800)
committerRichard Russon <rich@flatcap.org>
Fri, 10 Feb 2017 03:32:55 +0000 (03:32 +0000)
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
hcache.c
init.c
mutt.h
muttlib.c
protos.h

index b51c558d8f228a7e4d9ef01337749d66f5559a26..4326fcec0ff3d592fc5d20dc2342d8174a043f8a 100644 (file)
--- 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);
 
 
index 418a8f2516df6029eb8ea3457c7a8beacc524517..1d73c1e949008a4b0f59e525e5c0c421d0e7e812 100644 (file)
--- 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 30f0cb54b715a85b1efa1e6e4563af6f98adcea3..0e14f0dda4fca779ee6b90521e605547f60205c1 100644 (file)
--- 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 3b1f878a7621a82c27e8723735ec3f7e1ef40abb..3440021e7ecb9029e822e905cc1ed59bb4172f82 100644 (file)
--- 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 *);
index c9a0bed356a0e4ea25a376d88a18d4624439d006..ec751846c7cecba161afb3d8259ffecb9313d6c0 100644 (file)
--- 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;
index 952887487018e4ba40a67b9666c1cf1ed6dd67f4..7653c82548e1569ea6ed21c17547fc538e5d3797 100644 (file)
--- 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 *);