]> granicus.if.org Git - mutt/commitdiff
Implement ungroup command. Closes #3304.
authorRocco Rutte <pdmef@gmx.net>
Thu, 23 Jul 2009 14:49:30 +0000 (16:49 +0200)
committerRocco Rutte <pdmef@gmx.net>
Thu, 23 Jul 2009 14:49:30 +0000 (16:49 +0200)
group.c
group.h [new file with mode: 0644]
init.c
init.h
pattern.c
protos.h
rfc822.c
rfc822.h

diff --git a/group.c b/group.c
index 7f8206bacab47c932d3aefc1c6dfc47d3a945996..1e50d360462908fd9ecee1461fe9e3578213c926 100644 (file)
--- a/group.c
+++ b/group.c
@@ -1,20 +1,21 @@
 /*
  * Copyright (C) 2006 Thomas Roessler <roessler@does-not-exist.org>
- * 
+ * Copyright (C) 2009 Rocco Rutte <pdmef@gmx.net>
+ *
  *     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.
- */ 
+ */
 
 #if HAVE_CONFIG_H
 # include "config.h"
 group_t *mutt_pattern_group (const char *k)
 {
   group_t *p;
-  
+
   if (!k)
     return 0;
-  
+
   if (!(p = hash_find (Groups, k)))
   {
     dprint (2, (debugfile, "mutt_pattern_group: Creating group %s.\n", k));
@@ -48,10 +49,46 @@ group_t *mutt_pattern_group (const char *k)
     p->name = safe_strdup (k);
     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;
+}
+
 void mutt_group_context_add (group_context_t **ctx, group_t *group)
 {
   for (; *ctx; ctx = &((*ctx)->next))
@@ -59,7 +96,7 @@ void mutt_group_context_add (group_context_t **ctx, group_t *group)
     if ((*ctx)->g == group)
       return;
   }
-  
+
   *ctx = safe_calloc (1, sizeof (group_context_t));
   (*ctx)->g = group;
 }
@@ -82,40 +119,88 @@ void mutt_group_add_adrlist (group_t *g, ADDRESS *a)
     return;
   if (!a)
     return;
-  
+
   for (p = &g->as; *p; p = &((*p)->next))
     ;
-  
+
   q = rfc822_cpy_adr (a, 0);
   q = mutt_remove_xrefs (g->as, q);
   *p = q;
 }
 
+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);
+}
+
 void mutt_group_context_add_adrlist (group_context_t *ctx, ADDRESS *a)
 {
   for (; ctx; ctx = ctx->next)
     mutt_group_add_adrlist (ctx->g, a);
 }
 
+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);
 
   return rv;
 }
 
+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)
   {
     if (mutt_match_rx_list (s, g->rs))
diff --git a/group.h b/group.h
new file mode 100644 (file)
index 0000000..460884f
--- /dev/null
+++ b/group.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006 Thomas Roessler <roessler@does-not-exist.org>
+ * Copyright (C) 2009 Rocco Rutte <pdmef@gmx.net>
+ *
+ *     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_ */
diff --git a/init.c b/init.c
index 46a94e25ce234567d2f281fff00db4c5f0dcbdd6..000575092af7c37e29f2807831f5d73c172766a7 100644 (file)
--- a/init.c
+++ b/init.c
@@ -31,6 +31,7 @@
 #include "charset.h"
 #include "mutt_crypt.h"
 #include "mutt_idna.h"
+#include "group.h"
 
 #if defined(USE_SSL)
 #include "mutt_ssl.h"
@@ -833,60 +834,70 @@ static int parse_group (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
   group_state_t state = NONE;
   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 
+    else
     {
-      switch (state) 
+      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;
       }
     }
   } 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;
-}
-
 /* always wise to do what someone else did before */
 static void _attachments_clean (void)
 {
diff --git a/init.h b/init.h
index 4c8213c133d12561ae574584b391d38526e417e0..c0f3d8cbc791ebbe172a6193bdd4b5d28b530a86 100644 (file)
--- a/init.h
+++ b/init.h
@@ -3419,7 +3419,6 @@ static int parse_spam_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 static int parse_unlist (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 
 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 *);
 static int parse_unlists (BUFFER *, BUFFER *, unsigned long, BUFFER *);
@@ -3472,8 +3471,8 @@ struct command_t Commands[] = {
   { "fcc-hook",                mutt_parse_hook,        M_FCCHOOK },
   { "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
   { "iconv-hook",      mutt_parse_hook,        M_ICONVHOOK },
index e92c95d7b9d2b49fb99f2569dd1b653b08f8a084..b58f76592a005230f0e074aa8ea8e52765c08b54 100644 (file)
--- a/pattern.c
+++ b/pattern.c
@@ -35,6 +35,7 @@
 
 #include "mutt_crypt.h"
 #include "mutt_curses.h"
+#include "group.h"
 
 #ifdef USE_IMAP
 #include "mx.h"
index d0e1d3f125c586994de0112c0c90921006a6b517..fe00ea84d38f8ef866fb12dd44c05653c6fefb1d 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -75,11 +75,6 @@ typedef const char * format_t (char *, size_t, size_t, char, const char *, const
 void mutt_FormatString (char *, size_t, size_t, const char *, format_t *, unsigned long, format_flag);
 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 **);
 
@@ -311,8 +306,6 @@ int mutt_get_field_unbuffered (char *, char *, size_t, int);
 #define mutt_get_password(A,B,C) mutt_get_field_unbuffered(A,B,C,M_PASS)
 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);
 int mutt_is_autoview (BODY *, const char *);
index b14200a17fb44cc1b8789e6a4fa2193ca0b5794c..89737b5c1e759589fb36c95f95eeff9f5808e641 100644 (file)
--- a/rfc822.c
+++ b/rfc822.c
@@ -82,6 +82,45 @@ static void rfc822_dequote_comment (char *s)
   *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);
+}
+
 void rfc822_free_address (ADDRESS **p)
 {
   ADDRESS *t;
index 2f43bbdec7c5bae49daaad00690c00d5cf3cc67f..4684e97124c4ef6030be791f63de11f7263c1f2d 100644 (file)
--- a/rfc822.h
+++ b/rfc822.h
@@ -57,6 +57,7 @@ void rfc822_write_address_single (char *, size_t, ADDRESS *, int);
 void rfc822_free_address (ADDRESS **addr);
 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;
 extern const char *RFC822Errors[];