{
/* 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;
}
<sect1>Mailing lists<label id="lists">
<p>
-Usage: <tt/[un]lists/ <em/address/ [ <em/address/ ... ]<newline>
-Usage: <tt/[un]subscribe/ <em/address/ [ <em/address/ ... ]
+Usage: <tt/[un]lists/ <em/regexp/ [ <em/regexp/ ... ]<newline>
+Usage: <tt/[un]subscribe/ <em/regexp/ [ <em/regexp/ ... ]
Mutt has a few nice features for <ref id="using_lists" name="handling
mailing lists">. In order to take advantage of them, you must
of the Mail-Followup-To header is controlled by the <ref id="followup_to"
name="$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
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/ [!]<em/pattern/ <em/mailbox/
~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
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
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
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
#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.
}
}
+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;
}
}
+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
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
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));
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));
** 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
** 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 },
{ "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 },
/*
/* 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 *);
};
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
{ "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 },
{ "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 }
};
#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? */
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 */
HEADER *sort_key;
} THREAD;
-#include "mutt_regex.h"
/* flag to mutt_pattern_comp() */
#define M_FULL_MSG 1 /* enable body and header matching */
int not; /* do not match */
} REGEXP;
-WHERE REGEXP Alternates;
WHERE REGEXP Mask;
WHERE REGEXP QuoteRegexp;
WHERE REGEXP ReplyRegexp;
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;
+}
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);
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 *);
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 *);