http://dev.mutt.org/trac/changeset/77ac8b5c2be6 http://dev.mutt.org/trac/ticket/3304 Implement ungroup command. Closes #3304. requires 7c4484ba9e4b (patch added) Move remove_from_rx_list() to muttlib.c, name it mutt_remove_from_rx_list() Index: group.c =================================================================== --- group.c (revision 5801:19e62bd1549b) +++ group.c (revision 5989:77ac8b5c2be6) @@ -49,6 +50,42 @@ hash_insert (Groups, p->name, p, 0); } - + return p; +} + +static void group_free (void *p) +{ + group_t *g = (group_t *)p; + + if (!g) + return; + FREE(&g->name); + rfc822_free_address (&g->as); + mutt_free_rx_list (&g->rs); + FREE(&g); +} + +int mutt_group_remove (group_t * g, BUFFER * err) +{ + int h; + + if (!g) + return -1; + h = Groups->hash_string ((const unsigned char *)g->name, Groups->nelem); + if (!hash_find_hash (Groups, h, g->name)) + { + if (err) + snprintf (err->data, err->dsize, _("No such group: %s"), g->name); + return -1; + } + hash_delete_hash (Groups, h, g->name, g, group_free); + return 0; +} + +static int empty_group (group_t *g) +{ + if (!g) + return -1; + return !g->as && !g->rs; } @@ -92,7 +129,27 @@ } +static int mutt_group_remove_adrlist (group_t *g, ADDRESS *a) +{ + ADDRESS *p; + + if (!g) + return -1; + if (!a) + return -1; + + for (p = a; p; p = p->next) + rfc822_remove_from_adrlist (&g->as, p->mailbox); + + return 0; +} + static int mutt_group_add_rx (group_t *g, const char *s, int flags, BUFFER *err) { return mutt_add_to_rx_list (&g->rs, s, flags, err); +} + +static int mutt_group_remove_rx (group_t *g, const char *s) +{ + return mutt_remove_from_rx_list (&g->rs, s); } @@ -103,8 +160,22 @@ } +int mutt_group_context_remove_adrlist (group_context_t *ctx, ADDRESS * a) +{ + int rv = 0; + + for (; (!rv) && ctx; ctx = ctx->next) + { + rv = mutt_group_remove_adrlist (ctx->g, a); + if (empty_group (ctx->g)) + mutt_group_remove (ctx->g, NULL); + } + + return rv; +} + int mutt_group_context_add_rx (group_context_t *ctx, const char *s, int flags, BUFFER *err) { int rv = 0; - + for (; (!rv) && ctx; ctx = ctx->next) rv = mutt_group_add_rx (ctx->g, s, flags, err); @@ -113,8 +184,22 @@ } +int mutt_group_context_remove_rx (group_context_t *ctx, const char *s) +{ + int rv = 0; + + for (; (!rv) && ctx; ctx = ctx->next) + { + rv = mutt_group_remove_rx (ctx->g, s); + if (empty_group (ctx->g)) + mutt_group_remove (ctx->g, NULL); + } + + return rv; +} + int mutt_group_match (group_t *g, const char *s) { ADDRESS *ap; - + if (s && g) { Index: group.h =================================================================== --- group.h (revision 5989:77ac8b5c2be6) +++ group.h (revision 5989:77ac8b5c2be6) @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006 Thomas Roessler + * Copyright (C) 2009 Rocco Rutte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MUTT_GROUP_H_ +#define _MUTT_GROUP_H_ 1 + +#define M_GROUP 0 +#define M_UNGROUP 1 + +void mutt_group_add_adrlist (group_t *g, ADDRESS *a); + +void mutt_group_context_add (group_context_t **ctx, group_t *group); +void mutt_group_context_destroy (group_context_t **ctx); +void mutt_group_context_add_adrlist (group_context_t *ctx, ADDRESS *a); +int mutt_group_context_add_rx (group_context_t *ctx, const char *s, int flags, BUFFER *err); + +int mutt_group_match (group_t *g, const char *s); + +int mutt_group_remove (group_t *, BUFFER *); +int mutt_group_context_remove_rx (group_context_t *ctx, const char *s); +int mutt_group_context_remove_adrlist (group_context_t *ctx, ADDRESS *); + +#endif /* _MUTT_GROUP_H_ */ Index: init.c =================================================================== --- init.c (revision 5988:7c4484ba9e4b) +++ init.c (revision 5989:77ac8b5c2be6) @@ -32,4 +32,5 @@ #include "mutt_crypt.h" #include "mutt_idna.h" +#include "group.h" #if defined(USE_SSL) @@ -834,38 +835,53 @@ ADDRESS *addr = NULL; char *estr = NULL; - - do + + do { mutt_extract_token (buf, s, 0); if (parse_group_context (&gc, buf, s, data, err) == -1) goto bail; - + + if (data == M_UNGROUP && !mutt_strcasecmp (buf->data, "*")) + { + if (mutt_group_remove (gc->g, err) < 0) + goto bail; + goto out; + } + if (!mutt_strcasecmp (buf->data, "-rx")) state = RX; else if (!mutt_strcasecmp (buf->data, "-addr")) state = ADDR; - else - { - switch (state) + else + { + switch (state) { case NONE: - strfcpy (err->data, _("Missing -rx or -addr."), err->dsize); + snprintf (err->data, err->dsize, _("%sgroup: missing -rx or -addr."), + data == M_UNGROUP ? "un" : ""); goto bail; - + case RX: - if (mutt_group_context_add_rx (gc, buf->data, REG_ICASE, err) != 0) + if (data == M_GROUP && + mutt_group_context_add_rx (gc, buf->data, REG_ICASE, err) != 0) + goto bail; + else if (data == M_UNGROUP && + mutt_group_context_remove_rx (gc, buf->data) < 0) goto bail; break; - + case ADDR: if ((addr = mutt_parse_adrlist (NULL, buf->data)) == NULL) goto bail; - if (mutt_addrlist_to_idna (addr, &estr)) - { - snprintf (err->data, err->dsize, _("Warning: Bad IDN '%s'.\n"), - estr); + if (mutt_addrlist_to_idna (addr, &estr)) + { + snprintf (err->data, err->dsize, _("%sgroup: warning: bad IDN '%s'.\n"), + data == 1 ? "un" : "", estr); goto bail; } - mutt_group_context_add_adrlist (gc, addr); + if (data == M_GROUP) + mutt_group_context_add_adrlist (gc, addr); + else if (data == M_UNGROUP) + mutt_group_context_remove_adrlist (gc, addr); rfc822_free_address (&addr); break; @@ -874,15 +890,10 @@ } while (MoreArgs (s)); +out: mutt_group_context_destroy (&gc); return 0; - bail: +bail: mutt_group_context_destroy (&gc); - return -1; -} - -static int parse_ungroup (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) -{ - strfcpy (err->data, "not implemented", err->dsize); return -1; } Index: init.h =================================================================== --- init.h (revision 5976:376545d6909c) +++ init.h (revision 5989:77ac8b5c2be6) @@ -3420,5 +3420,4 @@ static int parse_group (BUFFER *, BUFFER *, unsigned long, BUFFER *); -static int parse_ungroup (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_lists (BUFFER *, BUFFER *, unsigned long, BUFFER *); @@ -3473,6 +3472,6 @@ { "fcc-save-hook", mutt_parse_hook, M_FCCHOOK | M_SAVEHOOK }, { "folder-hook", mutt_parse_hook, M_FOLDERHOOK }, - { "group", parse_group, 0 }, - { "ungroup", parse_ungroup, 0 }, + { "group", parse_group, M_GROUP }, + { "ungroup", parse_group, M_UNGROUP }, { "hdr_order", parse_list, UL &HeaderOrderList }, #ifdef HAVE_ICONV Index: pattern.c =================================================================== --- pattern.c (revision 5930:ed7eb5de7536) +++ pattern.c (revision 5989:77ac8b5c2be6) @@ -36,4 +36,5 @@ #include "mutt_crypt.h" #include "mutt_curses.h" +#include "group.h" #ifdef USE_IMAP Index: protos.h =================================================================== --- protos.h (revision 5977:f161c2f00d84) +++ protos.h (revision 5989:77ac8b5c2be6) @@ -76,9 +76,4 @@ void mutt_parse_content_type (char *, BODY *); void mutt_generate_boundary (PARAMETER **); -void mutt_group_add_adrlist (group_t *, ADDRESS *); -void mutt_group_context_add (group_context_t **ctx, group_t *group); -void mutt_group_context_destroy (group_context_t **ctx); -void mutt_group_add_adrlist (group_t *g, ADDRESS *a); -void mutt_group_context_add_adrlist (group_context_t *ctx, ADDRESS *a); void mutt_delete_parameter (const char *attribute, PARAMETER **p); void mutt_set_parameter (const char *, const char *, PARAMETER **); @@ -312,6 +307,4 @@ int mutt_get_postponed (CONTEXT *, HEADER *, HEADER **, char *, size_t); int mutt_get_tmp_attachment (BODY *); -int mutt_group_match (group_t *g, const char *s); -int mutt_group_context_add_rx (group_context_t *ctx, const char *s, int flags, BUFFER *err); int mutt_index_menu (void); int mutt_invoke_sendmail (ADDRESS *, ADDRESS *, ADDRESS *, ADDRESS *, const char *, int); Index: rfc822.c =================================================================== --- rfc822.c (revision 5923:ee3d174297bb) +++ rfc822.c (revision 5989:77ac8b5c2be6) @@ -81,4 +81,43 @@ } *w = 0; +} + +static void free_address (ADDRESS *a) +{ + FREE(&a->personal); + FREE(&a->mailbox); +#ifdef EXACT_ADDRESS + FREE(&a->val); +#endif +} + +int rfc822_remove_from_adrlist (ADDRESS **a, const char *mailbox) +{ + ADDRESS *p, *last = NULL, *t; + int rv = -1; + + p = *a; + last = NULL; + while (p) + { + if (ascii_strcasecmp (mailbox, p->mailbox) == 0) + { + if (last) + last->next = p->next; + else + (*a) = p->next; + t = p; + p = p->next; + free_address (t); + rv = 0; + } + else + { + last = p; + p = p->next; + } + } + + return (rv); } Index: rfc822.h =================================================================== --- rfc822.h (revision 5986:848f08512bf3) +++ rfc822.h (revision 5989:77ac8b5c2be6) @@ -58,4 +58,5 @@ void rfc822_cat (char *, size_t, const char *, const char *); int rfc822_valid_msgid (const char *msgid); +int rfc822_remove_from_adrlist (ADDRESS **a, const char *mailbox); extern int RFC822Error; Index: init.c =================================================================== --- init.c (revision 5903:b5ed5d96c775) +++ init.c (revision 5988:7c4484ba9e4b) @@ -600,40 +600,4 @@ } -static int remove_from_rx_list (RX_LIST **l, const char *str) -{ - RX_LIST *p, *last = NULL; - int rv = -1; - - if (mutt_strcmp ("*", str) == 0) - { - mutt_free_rx_list (l); /* ``unCMD *'' means delete all current entries */ - rv = 0; - } - 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); - rv = 0; - } - else - { - last = p; - p = p->next; - } - } - } - return (rv); -} - static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { @@ -701,5 +665,5 @@ goto bail; - remove_from_rx_list (&UnAlternates, buf->data); + mutt_remove_from_rx_list (&UnAlternates, buf->data); if (mutt_add_to_rx_list (&Alternates, buf->data, REG_ICASE, err) != 0) @@ -725,5 +689,5 @@ { mutt_extract_token (buf, s, 0); - remove_from_rx_list (&Alternates, buf->data); + mutt_remove_from_rx_list (&Alternates, buf->data); if (mutt_strcmp (buf->data, "*") && @@ -775,5 +739,5 @@ else { - remove_from_rx_list(&NoSpamList, buf->data); + mutt_remove_from_rx_list(&NoSpamList, buf->data); } @@ -842,5 +806,5 @@ goto bail; - remove_from_rx_list (&UnMailLists, buf->data); + mutt_remove_from_rx_list (&UnMailLists, buf->data); if (mutt_add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0) @@ -1194,6 +1158,6 @@ { mutt_extract_token (buf, s, 0); - remove_from_rx_list (&SubscribedLists, buf->data); - remove_from_rx_list (&MailLists, buf->data); + mutt_remove_from_rx_list (&SubscribedLists, buf->data); + mutt_remove_from_rx_list (&MailLists, buf->data); if (mutt_strcmp (buf->data, "*") && @@ -1217,6 +1181,6 @@ goto bail; - remove_from_rx_list (&UnMailLists, buf->data); - remove_from_rx_list (&UnSubscribedLists, buf->data); + mutt_remove_from_rx_list (&UnMailLists, buf->data); + mutt_remove_from_rx_list (&UnSubscribedLists, buf->data); if (mutt_add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0) @@ -1242,5 +1206,5 @@ { mutt_extract_token (buf, s, 0); - remove_from_rx_list (&SubscribedLists, buf->data); + mutt_remove_from_rx_list (&SubscribedLists, buf->data); if (mutt_strcmp (buf->data, "*") && Index: mutt.h =================================================================== --- mutt.h (revision 5956:ef6523d11f24) +++ mutt.h (revision 5988:7c4484ba9e4b) @@ -555,4 +555,5 @@ LIST *mutt_add_list_n (LIST*, const void *, size_t); LIST *mutt_find_list (LIST *, const char *); +int mutt_remove_from_rx_list (RX_LIST **l, const char *str); void mutt_init (int, LIST *); Index: muttlib.c =================================================================== --- muttlib.c (revision 5977:f161c2f00d84) +++ muttlib.c (revision 5988:7c4484ba9e4b) @@ -266,4 +266,40 @@ } return NULL; +} + +int mutt_remove_from_rx_list (RX_LIST **l, const char *str) +{ + RX_LIST *p, *last = NULL; + int rv = -1; + + if (mutt_strcmp ("*", str) == 0) + { + mutt_free_rx_list (l); /* ``unCMD *'' means delete all current entries */ + rv = 0; + } + 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); + rv = 0; + } + else + { + last = p; + p = p->next; + } + } + } + return (rv); }