]> granicus.if.org Git - neomutt/commitdiff
Turn alternates, lists, and subscribe into regular expression lists.
authorThomas Roessler <roessler@does-not-exist.org>
Sun, 1 Feb 2004 17:10:43 +0000 (17:10 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Sun, 1 Feb 2004 17:10:43 +0000 (17:10 +0000)
alias.c
doc/manual.sgml.head
doc/muttrc.man.head
globals.h
hdrline.c
init.c
init.h
mutt.h
mutt_regex.h
muttlib.c
protos.h

diff --git a/alias.c b/alias.c
index 6be0baf5a73b8fac1ba2c55f937e66f72e40bebc..508e24b6eb3d8b650589d7e6deac65d5d12b007a 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -529,25 +529,49 @@ int mutt_addr_is_user (ADDRESS *addr)
 {
   /* NULL address is assumed to be the user. */
   if (!addr)
+  {
+    dprint (5, (debugfile, "mail_addr_is_user: yes, NULL address\n"));
     return 1;
+  }
   if (!addr->mailbox)
+  {
+    dprint (5, (debugfile, "mail_addr_is_user: no, no mailbox\n"));
     return 0;
+  }
 
   if (ascii_strcasecmp (addr->mailbox, Username) == 0)
+  {
+    dprint (5, (debugfile, "mail_addr_is_user: yes, %s = %s\n", addr->mailbox, Username));
     return 1;
+  }
   if (string_is_address(addr->mailbox, Username, Hostname))
+  {
+    dprint (5, (debugfile, "mail_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, Hostname));
     return 1;
+  }
   if (string_is_address(addr->mailbox, Username, mutt_fqdn(0)))
+  {
+    dprint (5, (debugfile, "mail_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, mutt_fqdn (0)));
     return 1;
+  }
   if (string_is_address(addr->mailbox, Username, mutt_fqdn(1)))
+  {
+    dprint (5, (debugfile, "mail_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, mutt_fqdn (1)));
     return 1;
+  }
 
   if (From && !ascii_strcasecmp (From->mailbox, addr->mailbox))
+  {
+    dprint (5, (debugfile, "mail_addr_is_user: yes, %s = %s\n", addr->mailbox, From->mailbox));
     return 1;
+  }
 
-  if (Alternates.pattern &&
-      regexec (Alternates.rx, addr->mailbox, 0, NULL, 0) == 0)
+  if (mutt_match_rx_list (addr->mailbox, Alternates))
+  {
+    dprint (5, (debugfile, "mail_addr_is_user: yes, %s matched by alternates.\n", addr->mailbox));
     return 1;
+  }
   
+  dprint (5, (debugfile, "mail_addr_is_user: no, all failed.\n"));
   return 0;
 }
index 035e5db16eff7f3018e441f9638ec861ef7c07c6..576d3c311ea4b754a216f03e2454529cb015e8ac 100644 (file)
@@ -1167,8 +1167,8 @@ unignore posted-to:
 
 <sect1>Mailing lists<label id="lists">
 <p>
-Usage: <tt/&lsqb;un&rsqb;lists/ <em/address/ &lsqb; <em/address/ ... &rsqb;<newline>
-Usage: <tt/&lsqb;un&rsqb;subscribe/ <em/address/ &lsqb; <em/address/ ... &rsqb;
+Usage: <tt/&lsqb;un&rsqb;lists/ <em/regexp/ &lsqb; <em/regexp/ ... &rsqb;<newline>
+Usage: <tt/&lsqb;un&rsqb;subscribe/ <em/regexp/ &lsqb; <em/regexp/ ... &rsqb;
 
 Mutt has a few nice features for <ref id="using_lists" name="handling
 mailing lists">.  In order to take advantage of them, you must
@@ -1184,10 +1184,16 @@ receiving personal CCs of list messages.  Also note that the generation
 of the Mail-Followup-To header is controlled by the <ref id="followup_to"
 name="&dollar;followup_to"> configuration variable.
 
-More precisely, Mutt maintains lists of known and subscribed mailing
-lists.  Every subscribed mailing list is known.  To mark
-a mailing list as known, use the ``lists'' command.  To mark it as
-subscribed, use ``subscribe''.
+More precisely, Mutt maintains lists of patterns for the addresses
+of known and subscribed mailing lists.  Every subscribed mailing
+list is known. To mark a mailing list as known, use the ``lists''
+command.  To mark it as subscribed, use ``subscribe''.
+
+You can use regular expressions with both commands.  To mark all
+messages sent to a specific bug report's address on mutt's bug
+tracking system as list mail, for instance, you could say
+``subscribe [0-9]*@bugs.guug.de''.  Often, it's sufficient to just
+give a portion of the list's e-mail address.
 
 Specify as much of the address as you need to to remove ambiguity.  For
 example, if you've subscribed to the Mutt mailing list, you will receive mail
@@ -1207,7 +1213,6 @@ tokens.
 To remove a mailing list from the list of subscribed mailing lists,
 but keep it on the list of known mailing lists, use ``unsubscribe''.
 
-
 <sect1>Using Multiple spool mailboxes<label id="mbox-hook">
 <p>
 Usage: <tt/mbox-hook/ &lsqb;!&rsqb;<em/pattern/ <em/mailbox/
@@ -1741,8 +1746,8 @@ messages:
 ~n [MIN]-[MAX]  messages with a score in the range MIN to MAX *)
 ~N              new messages
 ~O              old messages
-~p              message is addressed to you (consults $alternates)
-~P              message is from you (consults $alternates)
+~p              message is addressed to you (consults alternates)
+~P              message is from you (consults alternates)
 ~Q              messages which have been replied to
 ~R              read messages
 ~r [MIN]-[MAX]  messages with ``date-received'' in a Date range
index 533554082a3fb535327e399960d44626010ac70d..5e9350a63c7101bb15bad066d880bd98ad69ed1b 100644 (file)
@@ -76,6 +76,17 @@ like sh and bash: Prepend the name of the environment by a dollar
 all aliases when \(lq\fB*\fP\(rq is used as an argument.
 .PP
 .nf
+\fBalternates\fP \fIregexp\fP [ \fB,\fP \fIregexp\fP [ ... ]]
+\fBunalternates\fP [\fB * \fP | \fIregexp\fP [ \fB,\fP \fIregexp\fP [ ... ]] ]
+.fi
+.IP
+\fBalternates\fP is used to inform mutt about alternate addresses
+where you receive mail; you can use regular expressions to specify
+alternate addresses.  This affects mutt's idea about messages
+from you, and messages addressed to you.  \fBunalternates\fP removes
+a regular expression from the list of known alternates.
+.PP
+.nf
 \fBalternative_order\fP \fItype\fP[\fB/\fP\fIsubtype\fP] [ ... ]
 \fBunalternative_order\fP [\fB * \fP | \fItype\fP/\fIsubtype\fP] [...]
 .fi
@@ -213,18 +224,15 @@ The \fBunignore\fP command permits you to define exceptions from
 the above mentioned list of ignored headers.
 .PP
 .nf
-\fBlists\fP \fIaddress\fP [ \fIaddress\fP ... ]
-\fBunlists\fP \fIaddress\fP [ \fIaddress\fP ... ]
-\fBsubscribe\fP \fIaddress\fP [ \fIaddress\fP ... ]
-\fBunsubscribe\fP \fIaddress\fP [ \fIaddress\fP ... ]
+\fBlists\fP \fIregexp\fP [ \fIregexp\fP ... ]
+\fBunlists\fP \fIregexp\fP [ \fIregexp\fP ... ]
+\fBsubscribe\fP \fIregexp\fP [ \fIregexp\fP ... ]
+\fBunsubscribe\fP \fIregexp\fP [ \fIregexp\fP ... ]
 .fi
 .IP
-Mutt maintains two lists of mailing list addresses, a list of
+Mutt maintains two lists of mailing list address patterns, a list of
 subscribed mailing lists, and a list of known mailing lists.  All
-subscribed mailing lists are known.  A mail address matches a
-mailing list if it begins with the given address.  For example, the
-lists pattern \(lqmutt-\(rq will match mutt-dev@mutt.org and
-mutt-users@mutt.org.
+subscribed mailing lists are known.  Patterns use regular expressions.
 .IP
 The \fBlists\fP command adds a mailing list address to the list of
 known mailing lists.  The \fBunlists\fP command removes a mailing
index dca04c1d15062e47b628ff4bf7a1cf7551ccd5af..3774797f6745ed4a1faf719a82d26b19ad1cbf58 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -121,8 +121,10 @@ WHERE LIST *HeaderOrderList INITVAL(0);
 WHERE LIST *Ignore INITVAL(0);
 WHERE LIST *MimeLookupList INITVAL(0);
 WHERE LIST *UnIgnore INITVAL(0);
-WHERE LIST *MailLists INITVAL(0);
-WHERE LIST *SubscribedLists INITVAL(0);
+
+WHERE RX_LIST *Alternates INITVAL(0);
+WHERE RX_LIST *MailLists INITVAL(0);
+WHERE RX_LIST *SubscribedLists INITVAL(0);
 
 /* bit vector for boolean variables */
 #ifdef MAIN_C
index d400c7398b8bd0f5da17f204227061757057c872..931bd42848515d41ec7c848b627e6c5665c39796 100644 (file)
--- a/hdrline.c
+++ b/hdrline.c
 #include <string.h>
 #include <locale.h>
 
-static int _mutt_is_mail_list (ADDRESS *addr, LIST *p)
-{
-  char *s;
-  if (addr->mailbox)
-  {
-    for (;p; p = p->next)
-    {
-      if (mutt_strncasecmp (addr->mailbox, p->data, mutt_strlen (p->data)) == 0)
-       return 1;
-      else if (*p->data == '@' && (s = strchr (addr->mailbox, '@')))
-       if (mutt_strncasecmp (s, p->data, mutt_strlen (p->data)) == 0)
-         return 1;
-    }
-  }
-  return 0;
-}
-
 int mutt_is_mail_list (ADDRESS *addr)
 {
-  return _mutt_is_mail_list (addr, MailLists);
+  return mutt_match_rx_list (addr->mailbox, MailLists);
 }
 
 int mutt_is_subscribed_list (ADDRESS *addr)
 {
-  return _mutt_is_mail_list (addr, SubscribedLists);
+  return mutt_match_rx_list (addr->mailbox, SubscribedLists);
 }
 
 /* Search for a mailing list in the list of addresses pointed to by adr.
diff --git a/init.c b/init.c
index 94ee7a47e40d6fe20606051a32203c4a2bb47f26..db636b4a9631b993ad6e8af4fbb43b51906965de 100644 (file)
--- a/init.c
+++ b/init.c
@@ -320,6 +320,52 @@ static void add_to_list (LIST **list, const char *str)
   }
 }
 
+static int add_to_rx_list (RX_LIST **list, const char *s, int flags, BUFFER *err)
+{
+  RX_LIST *t, *last = NULL;
+  REGEXP *rx;
+
+  if (!s || !*s)
+    return 0;
+
+  if (!(rx = mutt_compile_regexp (s, flags)))
+  {
+    snprintf (err->data, err->dsize, "Bad regexp: %s\n", s);
+    return -1;
+  }
+
+  /* check to make sure the item is not already on this list */
+  for (last = *list; last; last = last->next)
+  {
+    if (ascii_strcasecmp (rx->pattern, last->rx->pattern) == 0)
+    {
+      /* already on the list, so just ignore it */
+      last = NULL;
+      break;
+    }
+    if (!last->next)
+      break;
+  }
+
+  if (!*list || last)
+  {
+    t = mutt_new_rx_list();
+    t->rx = rx;
+    if (last)
+    {
+      last->next = t;
+      last = last->next;
+    }
+    else
+      *list = last = t;
+  }
+  else /* duplicate */
+    mutt_free_regexp (&rx);
+
+  return 0;
+}
+
+
 static void remove_from_list (LIST **l, const char *str)
 {
   LIST *p, *last = NULL;
@@ -350,6 +396,36 @@ static void remove_from_list (LIST **l, const char *str)
   }
 }
 
+static void remove_from_rx_list (RX_LIST **l, const char *str)
+{
+  RX_LIST *p, *last = NULL;
+
+  if (mutt_strcmp ("*", str) == 0)
+    mutt_free_rx_list (l);    /* ``unCMD *'' means delete all current entries */
+  else
+  {
+    p = *l;
+    last = NULL;
+    while (p)
+    {
+      if (ascii_strcasecmp (str, p->rx->pattern) == 0)
+      {
+       mutt_free_regexp (&p->rx);
+       if (last)
+         last->next = p->next;
+       else
+         (*l) = p->next;
+       FREE (&p);
+      }
+      else
+      {
+       last = p;
+       p = p->next;
+      }
+    }
+  }
+}
+
 static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
 {
   do
@@ -392,6 +468,42 @@ static int parse_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
   return 0;
 }
 
+static int _parse_rx_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err, int flags)
+{
+  do 
+  {
+    mutt_extract_token (buf, s, 0);
+    if (add_to_rx_list ((RX_LIST **) data, buf->data, flags, err) != 0)
+      return -1;
+       
+  }
+  while (MoreArgs (s));
+  
+  return 0;
+}
+
+static int parse_rx_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
+{
+  return _parse_rx_list (buf, s, data, err, REG_ICASE);
+}
+
+static int parse_rx_unlist (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
+{
+  do
+  {
+    mutt_extract_token (buf, s, 0);
+    if (mutt_strcmp (buf->data, "*") == 0)
+    {
+      mutt_free_rx_list ((RX_LIST **) data);
+      break;
+    }
+    remove_from_rx_list ((RX_LIST **) data, buf->data);
+  }
+  while (MoreArgs (s));
+  
+  return 0;
+}
+
 static int parse_unlist (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
 {
   do
@@ -418,8 +530,8 @@ static int parse_unlists (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *er
   do
   {
     mutt_extract_token (buf, s, 0);
-    remove_from_list (&MailLists, buf->data);
-    remove_from_list (&SubscribedLists, buf->data);
+    remove_from_rx_list (&MailLists, buf->data);
+    remove_from_rx_list (&SubscribedLists, buf->data);
   }
   while (MoreArgs (s));
 
@@ -431,8 +543,10 @@ static int parse_subscribe (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *
   do
   {
     mutt_extract_token (buf, s, 0);
-    add_to_list (&MailLists, buf->data);
-    add_to_list (&SubscribedLists, buf->data);
+    if (add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0)
+      return -1;
+    if (add_to_rx_list (&SubscribedLists, buf->data, REG_ICASE, err) != 0)
+      return -1;
   }
   while (MoreArgs (s));
 
diff --git a/init.h b/init.h
index 2f48f456b7bf7330c6d5b58a87758dac5fd39783..7d2c772ffbbba1a3ce18ab725122731b91d88070 100644 (file)
--- a/init.h
+++ b/init.h
@@ -157,13 +157,6 @@ struct option_t MuttVars[] = {
   ** message could include a line like "[-- PGP output follows ..." and
   ** give it the same color as your attachment color.
   */
-  { "alternates",      DT_RX,   R_BOTH, UL &Alternates, 0 },
-  /*
-  ** .pp
-  ** A regexp that allows you to specify \fIalternate\fP addresses where
-  ** you receive mail.  This affects Mutt's idea about messages from you
-  ** and addressed to you.
-  */
   { "arrow_cursor",    DT_BOOL, R_BOTH, OPTARROWCURSOR, 0 },
   /*
   ** .pp
@@ -402,7 +395,7 @@ struct option_t MuttVars[] = {
   ** variable at the time the hook is declared.  The default value matches
   ** if the message is either from a user matching the regular expression
   ** given, or if it is from you (if the from address matches
-  ** ``$$alternates'') and is to or cc'ed to a user matching the given
+  ** ``alternates'') and is to or cc'ed to a user matching the given
   ** regular expression.
   */
   { "delete",          DT_QUAD, R_NONE, OPT_DELETE, M_ASKYES },
@@ -1034,8 +1027,8 @@ struct option_t MuttVars[] = {
   { "metoo",           DT_BOOL, R_NONE, OPTMETOO, 0 },
   /*
   ** .pp
-  ** If unset, Mutt will remove your address (see the ``$$alternates''
-  ** variable) from the list of recipients when replying to a message.
+  ** If unset, Mutt will remove your address (see the ``alternates''
+  ** command) from the list of recipients when replying to a message.
   */
   { "menu_scroll",     DT_BOOL, R_NONE, OPTMENUSCROLL, 0 },
   /*
@@ -2734,7 +2727,10 @@ const struct mapping_t SortKeyMethods[] = {
 /* functions used to parse commands in a rc file */
 
 static int parse_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+static int parse_rx_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 static int parse_unlist (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+static int parse_rx_unlist (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+
 static int parse_unlists (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 static int parse_alias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 static int parse_unalias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
@@ -2754,6 +2750,8 @@ struct command_t
 };
 
 struct command_t Commands[] = {
+  { "alternates",      parse_rx_list,          UL &Alternates },
+  { "unalternates",    parse_rx_unlist,        UL &Alternates },
 #ifdef USE_SOCKET
   { "account-hook",     mutt_parse_hook,        M_ACCOUNTHOOK },
 #endif
@@ -2775,7 +2773,7 @@ struct command_t Commands[] = {
   { "iconv-hook",      mutt_parse_hook,        M_ICONVHOOK }, 
 #endif
   { "ignore",          parse_ignore,           0 },
-  { "lists",           parse_list,             UL &MailLists },
+  { "lists",           parse_rx_list,          UL &MailLists },
   { "macro",           mutt_parse_macro,       0 },
   { "mailboxes",       mutt_parse_mailboxes,   M_MAILBOXES },
   { "unmailboxes",     mutt_parse_mailboxes,   M_UNMAILBOXES },
@@ -2808,6 +2806,6 @@ struct command_t Commands[] = {
   { "unmy_hdr",                parse_unmy_hdr,         0 },
   { "unscore",         mutt_parse_unscore,     0 },
   { "unset",           parse_set,              M_SET_UNSET },
-  { "unsubscribe",     parse_unlist,           UL &SubscribedLists },
+  { "unsubscribe",     parse_rx_unlist,        UL &SubscribedLists },
   { NULL }
 };
diff --git a/mutt.h b/mutt.h
index eeed5dfc7432fd7a182c62f61ab39925121879db..93f7af72a50904e7e0b4c18e4ff7eb1beaff6207 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -75,6 +75,8 @@
 #define INITVAL(x) 
 #endif
 
+#include "mutt_regex.h"
+
 /* flags for mutt_copy_header() */
 #define CH_UPDATE      1      /* update the status and x-status fields? */
 #define CH_WEED                (1<<1) /* weed the headers? */
@@ -504,8 +506,16 @@ typedef struct list_t
   struct list_t *next;
 } LIST;
 
+typedef struct rx_list_t
+{
+  REGEXP *rx;
+  struct rx_list_t *next;
+} RX_LIST;
+
 #define mutt_new_list() safe_calloc (1, sizeof (LIST))
+#define mutt_new_rx_list() safe_calloc (1, sizeof (RX_LIST))
 void mutt_free_list (LIST **);
+void mutt_free_rx_list (RX_LIST **);
 int mutt_matches_ignore (const char *, LIST *);
 
 /* add an element to a list */
@@ -720,7 +730,6 @@ typedef struct thread
   HEADER *sort_key;
 } THREAD;
 
-#include "mutt_regex.h"
 
 /* flag to mutt_pattern_comp() */
 #define M_FULL_MSG     1       /* enable body and header matching */
index 9a0e6f5e265fa93778c4a336ca6b4172e197524f..0f37d9d1875df6681699b4439fc8a1a6358a176d 100644 (file)
@@ -46,7 +46,6 @@ typedef struct
   int not;             /* do not match */
 } REGEXP;
 
-WHERE REGEXP Alternates;
 WHERE REGEXP Mask;
 WHERE REGEXP QuoteRegexp;
 WHERE REGEXP ReplyRegexp;
index 7d4120894424f25709dfeb3458e3a70753ce7ec5..4d282c22847b3cb9eef11c14f85499f36c575f5b 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -1346,3 +1346,51 @@ const char *mutt_make_version (void)
   return vstring;
 }
 
+REGEXP *mutt_compile_regexp (const char *s, int flags)
+{
+  REGEXP *pp = safe_calloc (sizeof (REGEXP), 1);
+  pp->pattern = safe_strdup (s);
+  pp->rx = safe_calloc (sizeof (regex_t), 1);
+  if (REGCOMP (pp->rx, NONULL(s), flags) != 0)
+    mutt_free_regexp (&pp);
+
+  return pp;
+}
+
+void mutt_free_regexp (REGEXP **pp)
+{
+  FREE (&(*pp)->pattern);
+  regfree ((*pp)->rx);
+  FREE (&(*pp)->rx);
+  FREE (pp);
+}
+
+void mutt_free_rx_list (RX_LIST **list)
+{
+  RX_LIST *p;
+  
+  if (!list) return;
+  while (*list)
+  {
+    p = *list;
+    *list = (*list)->next;
+    mutt_free_regexp (&p->rx);
+    FREE (&p);
+  }
+}
+
+int mutt_match_rx_list (const char *s, RX_LIST *l)
+{
+  if (!s)  return 0;
+  
+  for (; l; l = l->next)
+  {
+    if (regexec (l->rx->rx, s, (size_t) 0, (regmatch_t *) 0, (int) 0) == 0)
+    {
+      dprint (5, (debugfile, "mutt_match_rx_list: %s matches %s\n", s, l->rx->pattern));
+      return 1;
+    }
+  }
+
+  return 0;
+}
index 8a4722cd927e5e552a9eabce663c52be03b6f271..5aab3d53c8953d9193002692ac8058a04e4ccb5a 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -136,6 +136,8 @@ const char *mutt_make_version (void);
 
 const char *mutt_fqdn(short);
 
+REGEXP *mutt_compile_regexp (const char *, int);
+
 void mutt_account_hook (const char* url);
 void mutt_add_to_reference_headers (ENVELOPE *env, ENVELOPE *curenv, LIST ***pp, LIST ***qq);
 void mutt_adv_mktemp (char *, size_t);
@@ -181,6 +183,7 @@ void mutt_free_enter_state (ENTER_STATE **);
 void mutt_free_envelope (ENVELOPE **);
 void mutt_free_header (HEADER **);
 void mutt_free_parameter (PARAMETER **);
+void mutt_free_regexp (REGEXP **);
 void mutt_generate_header (char *, size_t, HEADER *, int);
 void mutt_help (int);
 void mutt_draw_tree (CONTEXT *);
@@ -287,6 +290,7 @@ int mutt_is_subscribed_list (ADDRESS *);
 int mutt_is_text_part (BODY *);
 int mutt_is_valid_mailbox (const char *);
 int mutt_lookup_mime_type (BODY *, const char *);
+int mutt_match_rx_list (const char *, RX_LIST *);
 int mutt_messages_in_thread (CONTEXT *, HEADER *, int);
 int mutt_multi_choice (char *prompt, char *letters);
 int mutt_needs_mailcap (BODY *);