<<< Date Index >>>     <<< Thread Index >>>

Re: Lists and Subscribe commands, what part of address do they look in?



On Thu, Jan 22, 2004 at 05:11:34AM EST, Chris Green wrote:

> I have a problem with the lists and subscribe commands, what part of
> the address do they search for a matching string?  Is it only the part
> before the @ sign, it's not clear from the documentation.

As the CVS code stands now, there are two behaviors:

1) If the string begins with an "@" sign, it'll match all addresses at
that domain.  ("lists @bugs.guug.de" will match all bug report addys
for Mutt; "lists @bts.debian.org" will match all Debian bug reports;
"lists @mutt.org" will match all Mutt lists; etc.)

2) Otherwise, the string is compared character-by-character with the
address, and if the equivalent of strncmp(addy,string,strlen(string))
holds true (i.e., if strncmp(3) would return 0), the address matches
the string.  In plain English, the string is treated as a prefix to
match on :-)

> I generate my 'lists' and 'subscribe' lines automatically in my muttrc
> file by having a specific .mutt/lists file containing aliases for the
> lists I'm subsribed to.  A simple awk command in my muttrc extracts a
> list of list names for the 'lists' and 'subscribe' commands.

<plug type="shameless">
You may want to check out my makenewlistsrc script [1], which is probably
a version of yours on steroids (and if it isn't, I'd like to make it one).
</plug>

<hint>
If yours does anything mine doesn't, just tell me what it is, and I'll
add it in.
</hint>

> I also
> use procmail to route the list mail to individual mailboxes which have
> the same names as the list aliases.

My send-hooks (generated automatically by the same script) don't rely on
separate mailboxes (although separate mailboxes don't hurt, of course), so
if you decide to forward a message from one list to another, your "From:"
name and address will be set correctly for the list you're forwarding to.
(Yes, your "From:" addy is nondestructively mangled by default depending
on the list you're sending to, so your SPAM can tell you where the
harvester got his addys from if he didn't bother to strip resources.
Of course, you can replace the "+" with a "-" or some other character,
and make the SPAMmer's job more difficult ... and you can always just
assign your "From:" address on a per-list basis (using the "my_addy"
field), if all else fails.)

> The problem is one list which doesn't have anything remotely related
> to the name of the list in the part of the address to the left of the
> @ sign.  Its address is main@xxxxxxxxxxxxxxxxx, I have an alias for
> the list called 'alug', however the lists and subscribe commands don't
> recognise 'alug' as a list.

If you want that type of thing, you're looking for regexps.  Thomas
Roessler's got just what you're looking for (attached): it turns a
bunch of statements/variables that take a list of values into taking a
list of regexps.  (It's the only Mutt patch I have on my current Mutt,
well worth using, IMHO.  He'll apply it to the official CVS if enough
people use it, hopefully ... right, Thomas?)

> I can't really add 'main' to the lists and subscribe commands in
> muttrc as that could potentially collect all sorts of rubbish.

You bet!

...but come to think of it, if a guy's personal addy for posting on the
mutt-users list is mutt-users@xxxxxxxxxxxxx, mutt-users may be a dangerous
argument to the lists/subscribe commands, too ... which is why. . .

> Can on
> specify the whole list address in 'lists' and 'subscribe' as that
> would be an option.

...which is why one should nearly always specify the whole list address
in lists/subscribe commands ... or in other words, the answer is a rather
emphatic Yes :-)

HTH,
 - Dave

[1]
http://www.bigfatdave.com/dave/mutt/muttdir/makenewlistsrc
takes input from:
http://www.bigfatdave.com/dave/mutt/muttdir/newlists
and produces:
http://www.bigfatdave.com/dave/mutt/muttdir/newlistsrc
as output :-)
The makefile is rather important, as it does some stuff all by itself:
http://www.bigfatdave.com/dave/mutt/muttdir/Makefile
The entire config may be found here (symlinks to my live config):
http://www.bigfatdave.com/dave/mutt/muttdir/
...and a short page (getting out-of-date, since I script faster than I
document) introducing my config:
http://www.bigfatdave.com/dave/mutt/

-- 
Uncle Cosmo, why do they call this a word processor?
It's simple, Skyler.  You've seen what food processors do to food, right?

Please visit this link:
http://rotter.net/israel
Index: alias.c
===================================================================
RCS file: /cvs/mutt/mutt/alias.c,v
retrieving revision 3.8
diff -u -r3.8 alias.c
--- alias.c     24 Jul 2003 18:40:50 -0000      3.8
+++ alias.c     12 Jan 2004 22:11:27 -0000
@@ -545,8 +545,7 @@
   if (From && !ascii_strcasecmp (From->mailbox, addr->mailbox))
     return 1;
 
-  if (Alternates.pattern &&
-      regexec (Alternates.rx, addr->mailbox, 0, NULL, 0) == 0)
+  if (mutt_match_rx_list (addr->mailbox, Alternates))
     return 1;
   
   return 0;
Index: globals.h
===================================================================
RCS file: /cvs/mutt/mutt/globals.h,v
retrieving revision 3.6
diff -u -r3.6 globals.h
--- globals.h   15 Jul 2003 11:41:32 -0000      3.6
+++ globals.h   12 Jan 2004 22:11:27 -0000
@@ -121,8 +121,10 @@
 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: hdrline.c
===================================================================
RCS file: /cvs/mutt/mutt/hdrline.c,v
retrieving revision 3.10
diff -u -r3.10 hdrline.c
--- hdrline.c   4 Jan 2004 10:51:49 -0000       3.10
+++ hdrline.c   12 Jan 2004 22:11:28 -0000
@@ -28,31 +28,14 @@
 #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.
Index: init.c
===================================================================
RCS file: /cvs/mutt/mutt/init.c,v
retrieving revision 3.17
diff -u -r3.17 init.c
--- init.c      4 Jan 2004 11:10:21 -0000       3.17
+++ init.c      12 Jan 2004 22:11:32 -0000
@@ -320,6 +320,52 @@
   }
 }
 
+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_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 @@
   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 @@
   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 @@
   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));
 
Index: init.h
===================================================================
RCS file: /cvs/mutt/mutt/init.h,v
retrieving revision 3.42
diff -u -r3.42 init.h
--- init.h      4 Jan 2004 10:55:20 -0000       3.42
+++ init.h      12 Jan 2004 22:11:45 -0000
@@ -157,13 +157,6 @@
   ** 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 @@
   ** 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 @@
   { "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 @@
 /* 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 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 @@
   { "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 @@
   { "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 }
 };
Index: mutt.h
===================================================================
RCS file: /cvs/mutt/mutt/mutt.h,v
retrieving revision 3.22
diff -u -r3.22 mutt.h
--- mutt.h      30 Dec 2003 13:04:20 -0000      3.22
+++ mutt.h      12 Jan 2004 22:11:52 -0000
@@ -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 @@
   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 @@
   HEADER *sort_key;
 } THREAD;
 
-#include "mutt_regex.h"
 
 /* flag to mutt_pattern_comp() */
 #define M_FULL_MSG     1       /* enable body and header matching */
Index: mutt_regex.h
===================================================================
RCS file: /cvs/mutt/mutt/mutt_regex.h,v
retrieving revision 3.1
diff -u -r3.1 mutt_regex.h
--- mutt_regex.h        11 Dec 2002 11:19:40 -0000      3.1
+++ mutt_regex.h        12 Jan 2004 22:11:52 -0000
@@ -46,7 +46,6 @@
   int not;             /* do not match */
 } REGEXP;
 
-WHERE REGEXP Alternates;
 WHERE REGEXP Mask;
 WHERE REGEXP QuoteRegexp;
 WHERE REGEXP ReplyRegexp;
Index: muttlib.c
===================================================================
RCS file: /cvs/mutt/mutt/muttlib.c,v
retrieving revision 3.17
diff -u -r3.17 muttlib.c
--- muttlib.c   4 Oct 2003 20:34:59 -0000       3.17
+++ muttlib.c   12 Jan 2004 22:11:52 -0000
@@ -1346,3 +1346,51 @@
   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: protos.h
===================================================================
RCS file: /cvs/mutt/mutt/protos.h,v
retrieving revision 3.18
diff -u -r3.18 protos.h
--- protos.h    4 Oct 2003 20:34:59 -0000       3.18
+++ protos.h    12 Jan 2004 22:11:52 -0000
@@ -136,6 +136,8 @@
 
 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_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_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 *);
Index: doc/muttrc.man.head
===================================================================
RCS file: /cvs/mutt/mutt/doc/muttrc.man.head,v
retrieving revision 3.9
diff -u -r3.9 muttrc.man.head
--- doc/muttrc.man.head 29 Sep 2003 16:34:32 -0000      3.9
+++ doc/muttrc.man.head 12 Jan 2004 22:11:52 -0000
@@ -76,6 +76,17 @@
 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 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@xxxxxxxx and
-mutt-users@xxxxxxxxx
+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

Attachment: pgp0ACsu5sIIy.pgp
Description: PGP signature