diff -pruNd mutt-1.4.orig/globals.h mutt-1.4/globals.h --- mutt-1.4.orig/globals.h Thu Jan 3 21:57:19 2002 +++ mutt-1.4/globals.h Mon Jun 17 17:22:55 2002 @@ -170,6 +170,7 @@ WHERE int CurrentMenu; WHERE ALIAS *Aliases INITVAL (0); WHERE LIST *UserHeader INITVAL (0); +WHERE MY_LIST *UserList INITVAL (0); #ifdef DEBUG WHERE FILE *debugfile INITVAL (0); diff -pruNd mutt-1.4.orig/init.c mutt-1.4/init.c --- mutt-1.4.orig/init.c Mon Feb 11 10:58:54 2002 +++ mutt-1.4/init.c Mon Jun 17 17:22:55 2002 @@ -352,6 +352,26 @@ static void remove_from_list (LIST **l, } } +/* add/remove a string or a user defined list */ +static int _to_list (LIST **list, char *str, BUFFER *err, + void (func) (LIST **, const char *)) +{ + LIST *tmp; + + if (*str == '%') + { + if ((tmp = mutt_lookup_my_list (str + 1, err)) == NULL) + return -1; + + for (; tmp; tmp = tmp->next) + func (list, tmp->data); + } + else + func (list, str); + + return 0; +} + static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { do @@ -387,7 +407,8 @@ static int parse_list (BUFFER *buf, BUFF do { mutt_extract_token (buf, s, 0); - add_to_list ((LIST **) data, buf->data); + if (_to_list ((LIST **) data, buf->data, err, add_to_list) == -1) + return -1; } while (MoreArgs (s)); @@ -399,7 +420,8 @@ static int parse_unlist (BUFFER *buf, BU do { mutt_extract_token (buf, s, 0); - remove_from_list ((LIST **) data, buf->data); + if (_to_list ((LIST **) data, buf->data, err, remove_from_list) == -1) + return -1; } while (MoreArgs (s)); @@ -412,8 +434,9 @@ static int parse_unlists (BUFFER *buf, B do { mutt_extract_token (buf, s, 0); - remove_from_list (&MailLists, buf->data); - remove_from_list (&SubscribedLists, buf->data); + if ((_to_list (&MailLists, buf->data, err, remove_from_list) == -1) || + (_to_list (&SubscribedLists, buf->data, err, remove_from_list) == -1)) + return -1; } while (MoreArgs (s)); @@ -425,8 +448,9 @@ static int parse_subscribe (BUFFER *buf, do { mutt_extract_token (buf, s, 0); - add_to_list (&MailLists, buf->data); - add_to_list (&SubscribedLists, buf->data); + if ((_to_list (&MailLists, buf->data, err, add_to_list) == -1) || + (_to_list (&SubscribedLists, buf->data, err, add_to_list) == -1)) + return -1; } while (MoreArgs (s)); @@ -623,6 +647,53 @@ static int parse_my_hdr (BUFFER *buf, BU return 0; } +static int parse_my_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) +{ + MY_LIST *tmp; + + if (*s->dptr == '%') + s->dptr++; + + mutt_extract_token (buf, s, 0); + + if (!MoreArgs (s)) { + strfcpy (err->data, _("my_list: too few arguments"), err->dsize); + return (-1); + } + + if (UserList) { + /* see if this user-defined list already exists */ + for (tmp = UserList; ; tmp = tmp->next) + { + if (ascii_strcasecmp (buf->data, tmp->name) == 0) + break; + if (!tmp->next) + { + tmp->next = safe_calloc (1, sizeof (MY_LIST)); + tmp = tmp->next; + tmp->name = safe_strdup (buf->data); + break; + } + } + } + else + { + tmp = safe_calloc (1, sizeof (MY_LIST)); + tmp->name = safe_strdup (buf->data); + UserList = tmp; + } + + do + { + mutt_extract_token (buf, s, 0); + /* XXX no regexp validity check at declaration time; only when executing */ + add_to_list ((LIST **) &tmp->data, buf->data); + } + while (MoreArgs (s)); + + return 0; +} + static int parse_sort (short *val, const char *s, const struct mapping_t *map, BUFFER *err) { @@ -1701,6 +1772,21 @@ static int mutt_execute_commands (LIST * } FREE (&token.data); return 0; +} + +LIST *mutt_lookup_my_list (char *s, BUFFER *err) +{ + MY_LIST *tmp; + + for (tmp = UserList; tmp; tmp = tmp->next) + { + if (ascii_strcasecmp (s, tmp->name) == 0) + return tmp->data; + if (!tmp->next) + break; + } + snprintf (err->data, err->dsize, _("%s: invalid list"), s); + return NULL; } void mutt_init (int skip_sys_rc, LIST *commands) diff -pruNd mutt-1.4.orig/init.h mutt-1.4/init.h --- mutt-1.4.orig/init.h Thu Apr 25 15:26:37 2002 +++ mutt-1.4/init.h Mon Jun 17 17:22:55 2002 @@ -2441,6 +2441,7 @@ static int parse_unignore (BUFFER *, BUF static int parse_source (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_set (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_my_hdr (BUFFER *, BUFFER *, unsigned long, BUFFER *); +static int parse_my_list (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_unmy_hdr (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_subscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *); @@ -2480,6 +2481,7 @@ struct command_t Commands[] = { { "mbox-hook", mutt_parse_hook, M_MBOXHOOK }, { "mono", mutt_parse_mono, 0 }, { "my_hdr", parse_my_hdr, 0 }, + { "my_list", parse_my_list, 0 }, #ifdef HAVE_PGP { "pgp-hook", mutt_parse_hook, M_PGPHOOK }, #endif /* HAVE_PGP */ diff -pruNd mutt-1.4.orig/mutt.h mutt-1.4/mutt.h --- mutt-1.4.orig/mutt.h Thu Feb 28 09:24:13 2002 +++ mutt-1.4/mutt.h Mon Jun 17 17:22:55 2002 @@ -723,6 +723,13 @@ typedef struct pattern_t regex_t *rx; } pattern_t; +typedef struct my_list_t +{ + char *name; + LIST *data; + struct my_list_t *next; +} MY_LIST; + typedef struct { char *path; diff -pruNd mutt-1.4.orig/pattern.c mutt-1.4/pattern.c --- mutt-1.4.orig/pattern.c Sat May 18 07:39:18 2002 +++ mutt-1.4/pattern.c Mon Jun 17 17:22:55 2002 @@ -671,6 +671,58 @@ static struct pattern_flags *lookup_tag return NULL; } +static LIST *_mutt_lookup_my_list (BUFFER *s, BUFFER *err) +{ + BUFFER buf; + + memset (&buf, 0, sizeof (buf)); + if ((mutt_extract_token (&buf, s, 0) != 0) || !buf.data) + { + snprintf (err->data, err->dsize, _("error in expression")); + return NULL; + } + return mutt_lookup_my_list (buf.data, err); +} + +/* pat ~= ( ~op a1 | ~op a2 | ... ) */ +int mutt_expand_my_list (pattern_t *pat, LIST *list, int op, int path, BUFFER *err) +{ + int r; + pattern_t *p = NULL, *tail = NULL; + char buf[STRING]; + + while (list) + { + p = new_pattern (); + p->op = op; + + strfcpy (buf, list->data, sizeof (buf)); + if (path) + _mutt_expand_path (buf, sizeof (buf), 1); + + p->rx = safe_malloc (sizeof (regex_t)); + r = REGCOMP (p->rx, buf, REG_NEWLINE | REG_NOSUB | mutt_which_case (buf)); + if (r) + { + regerror (r, p->rx, err->data, err->dsize); + regfree (p->rx); + FREE (&p->rx); + FREE (&p); + return (-1); + } + + if (tail) + tail->next = p; + else + pat->child = p; + + tail = p; + + list = list->next; + } + return 0; +} + static /* const */ char *find_matching_paren (/* const */ char *s) { int level = 1; @@ -803,13 +855,34 @@ pattern_t *mutt_pattern_comp (/* const * mutt_pattern_free (&curlist); return NULL; } - tmp->op = entry->op; ps.dptr++; /* eat the operator and any optional whitespace */ SKIPWS (ps.dptr); - if (entry->eat_arg) - { + if (*ps.dptr == '%') + { /* user-defined list of arguments */ + LIST *my_list; + + ps.dptr++; + tmp->op = M_OR; + + if ((my_list = _mutt_lookup_my_list (&ps, err)) == NULL) + { + mutt_pattern_free (&curlist); + return NULL; + } + + if (mutt_expand_my_list (tmp, my_list, entry->op, 0, err) == -1) + { + mutt_pattern_free (&tmp); + mutt_pattern_free (&curlist); + return NULL; + } + } + else if (entry->eat_arg) + { /* regexp */ + tmp->op = entry->op; + if (!*ps.dptr) { snprintf (err->data, err->dsize, _("missing parameter")); @@ -822,6 +895,9 @@ pattern_t *mutt_pattern_comp (/* const * return NULL; } } + else /* noarg operation */ + tmp->op = entry->op; + implicit = 1; break; case '(': diff -pruNd mutt-1.4.orig/protos.h mutt-1.4/protos.h --- mutt-1.4.orig/protos.h Mon Apr 29 19:12:12 2002 +++ mutt-1.4/protos.h Mon Jun 17 17:22:55 2002 @@ -94,6 +94,7 @@ CONTENT *mutt_get_content_info (const ch HASH *mutt_make_id_hash (CONTEXT *); HASH *mutt_make_subj_hash (CONTEXT *); +LIST *mutt_lookup_my_list (char *, BUFFER *); LIST *mutt_make_references(ENVELOPE *e); ENVELOPE *mutt_read_rfc822_header (FILE *, HEADER *, short, short); @@ -256,6 +257,7 @@ int mutt_decode_save_attachment (FILE *, int mutt_display_message (HEADER *h); int mutt_edit_attachment(BODY *); int mutt_edit_message (CONTEXT *, HEADER *); +int mutt_expand_my_list (pattern_t *, LIST *, int, int, BUFFER *); int mutt_fetch_recips (ENVELOPE *out, ENVELOPE *in, int flags); int mutt_chscmp (const char *s, const char *chs); #define mutt_is_utf8(a) mutt_chscmp (a, "utf-8") diff -pruNd mutt-1.4.orig/buffy.c mutt-1.4/buffy.c --- mutt-1.4.orig/buffy.c Mon Mar 25 12:30:08 2002 +++ mutt-1.4/buffy.c Mon Jun 17 17:22:55 2002 @@ -160,7 +160,7 @@ void mutt_update_mailbox (BUFFY * b) } #endif -int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *err) +static void mailboxes_add_incoming (char *path) { BUFFY **tmp; char buf[_POSIX_PATH_MAX]; @@ -168,49 +168,66 @@ int mutt_parse_mailboxes (BUFFER *path, struct stat sb; #endif /* BUFFY_SIZE */ - while (MoreArgs (s)) - { - mutt_extract_token (path, s, 0); - strfcpy (buf, path->data, sizeof (buf)); - mutt_expand_path (buf, sizeof (buf)); + strfcpy (buf, path, sizeof (buf)); + mutt_expand_path (buf, sizeof (buf)); - /* Skip empty tokens. */ - if(!*buf) continue; + /* Skip empty tokens. */ + if(!*buf) return; - /* simple check to avoid duplicates */ - for (tmp = &Incoming; *tmp; tmp = &((*tmp)->next)) - { - if (mutt_strcmp (buf, (*tmp)->path) == 0) - break; - } + /* simple check to avoid duplicates */ + for (tmp = &Incoming; *tmp; tmp = &((*tmp)->next)) + { + if (mutt_strcmp (buf, (*tmp)->path) == 0) + break; + } - if (!*tmp) - { - *tmp = (BUFFY *) safe_calloc (1, sizeof (BUFFY)); - (*tmp)->path = safe_strdup (buf); - (*tmp)->next = NULL; - /* it is tempting to set magic right here */ - (*tmp)->magic = 0; - - } + if (!*tmp) + { + *tmp = (BUFFY *) safe_calloc (1, sizeof (BUFFY)); + (*tmp)->path = safe_strdup (buf); + (*tmp)->next = NULL; + /* it is tempting to set magic right here */ + (*tmp)->magic = 0; + + } - (*tmp)->new = 0; - (*tmp)->notified = 1; - (*tmp)->newly_created = 0; + (*tmp)->new = 0; + (*tmp)->notified = 1; + (*tmp)->newly_created = 0; #ifdef BUFFY_SIZE - /* for buffy_size, it is important that if the folder is new (tested by - * reading it), the size is set to 0 so that later when we check we see - * that it increased . without buffy_size we probably don't care. - */ - if (stat ((*tmp)->path, &sb) == 0 && !test_new_folder ((*tmp)->path)) + /* for buffy_size, it is important that if the folder is new (tested by + * reading it), the size is set to 0 so that later when we check we see + * that it increased . without buffy_size we probably don't care. + */ + if (stat ((*tmp)->path, &sb) == 0 && !test_new_folder ((*tmp)->path)) + { + /* some systems out there don't have an off_t type */ + (*tmp)->size = (long) sb.st_size; + } + else + (*tmp)->size = 0; +#endif /* BUFFY_SIZE */ +} + +int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *err) +{ + LIST *list; + + while MoreArgs (s) + { + mutt_extract_token (path, s, 0); + + if (*path->data == '%') { - /* some systems out there don't have an off_t type */ - (*tmp)->size = (long) sb.st_size; + if ((list = mutt_lookup_my_list (path->data + 1, err)) == NULL) + return -1; + + for (; list; list = list->next) + mailboxes_add_incoming (list->data); } else - (*tmp)->size = 0; -#endif /* BUFFY_SIZE */ + mailboxes_add_incoming (path->data); } return 0; } diff -pruNd mutt-1.4.orig/hook.c mutt-1.4/hook.c --- mutt-1.4.orig/hook.c Fri Jun 29 12:06:14 2001 +++ mutt-1.4/hook.c Mon Jun 17 17:22:55 2002 @@ -42,6 +42,7 @@ int mutt_parse_hook (BUFFER *buf, BUFFER { HOOK *ptr; BUFFER command, pattern; + LIST *my_list = NULL; int rc, not = 0; regex_t *rx = NULL; pattern_t *pat = NULL; @@ -59,6 +60,12 @@ int mutt_parse_hook (BUFFER *buf, BUFFER mutt_extract_token (&pattern, s, 0); + if ((data & M_FOLDERHOOK) && (*pattern.data == '%')) + { + if ((my_list = mutt_lookup_my_list (pattern.data + 1, err)) == NULL) + goto error; + } + if (!MoreArgs (s)) { strfcpy (err->data, _("too few arguments"), err->dsize); @@ -79,7 +86,7 @@ int mutt_parse_hook (BUFFER *buf, BUFFER goto error; } - if (data & (M_FOLDERHOOK | M_MBOXHOOK)) + if ((data & (M_FOLDERHOOK | M_MBOXHOOK)) && !my_list) { strfcpy (path, pattern.data, sizeof (path)); _mutt_expand_path (path, sizeof (path), 1); @@ -151,6 +158,17 @@ int mutt_parse_hook (BUFFER *buf, BUFFER err)) == NULL) goto error; } + else if (my_list) + { /* user defined list in a folder-hook */ + pat = new_pattern (); + pat->op = M_OR; + + if (mutt_expand_my_list (pat, my_list, /* n/a */ 0, 1, err) == -1) + { + mutt_pattern_free (&pat); + goto error; + } + } else { rx = safe_malloc (sizeof (regex_t)); @@ -265,17 +283,37 @@ int mutt_parse_unhook (BUFFER *buf, BUFF return 0; } -void mutt_folder_hook (char *path) +static int _mutt_folder_hook (char *path, regex_t *rx, char *command, int not) { - HOOK *tmp = Hooks; BUFFER err, token; char buf[STRING]; - current_hook_type = M_FOLDERHOOK; - err.data = buf; err.dsize = sizeof (buf); memset (&token, 0, sizeof (token)); + + if ((regexec (rx, path, 0, NULL, 0) == 0) ^ not) + { + if (mutt_parse_rc_line (command, &token, &err) == -1) + { + mutt_error ("%s", err.data); + FREE (&token.data); + mutt_sleep (1); /* pause a moment to let the user see the error */ + current_hook_type = 0; + return -1; + } + } + FREE (&token.data); + return 0; +} + +void mutt_folder_hook (char *path) +{ + HOOK *tmp = Hooks; + pattern_t *pat; + + current_hook_type = M_FOLDERHOOK; + for (; tmp; tmp = tmp->next) { if(!tmp->command) @@ -283,21 +321,18 @@ void mutt_folder_hook (char *path) if (tmp->type & M_FOLDERHOOK) { - if ((regexec (tmp->rx.rx, path, 0, NULL, 0) == 0) ^ tmp->rx.not) + if (tmp->pattern) { - if (mutt_parse_rc_line (tmp->command, &token, &err) == -1) - { - mutt_error ("%s", err.data); - FREE (&token.data); - mutt_sleep (1); /* pause a moment to let the user see the error */ - current_hook_type = 0; - return; - } + for (pat = tmp->pattern->child; pat; pat = pat->next) + if (_mutt_folder_hook (path, pat->rx, tmp->command, pat->not)) + goto out; } + else if (_mutt_folder_hook (path, tmp->rx.rx, tmp->command, tmp->rx.not)) + goto out; } } - FREE (&token.data); - + + out: current_hook_type = 0; } diff -pruNd mutt-1.4.orig/doc/manual.sgml.head mutt-1.4/doc/manual.sgml.head --- mutt-1.4.orig/doc/manual.sgml.head Mon May 6 13:26:44 2002 +++ mutt-1.4/doc/manual.sgml.head Mon Jun 17 17:22:55 2002 @@ -963,10 +963,10 @@ Usage: specifying in which mailboxes + to execute at the beginning of the pattern, you must place it @@ -1189,6 +1189,8 @@ 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''. +You can also use to specify +addresses with these commands. Using Multiple spool mailboxes