commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-2.2-558-ga01bb41


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-558-ga01bb41
Date: Fri, 30 Dec 2011 18:35:41 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=a01bb419262e90164a558075e3607fb3b0514443

The branch, master has been updated
       via  a01bb419262e90164a558075e3607fb3b0514443 (commit)
       via  26cfa2197d5a2866f1a08c48f94d65504fdef7b1 (commit)
      from  e7ab6892fa88d513d83945121c9b6864db4b30f7 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a01bb419262e90164a558075e3607fb3b0514443
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Dec 30 19:52:49 2011 +0200

    Improve msgset interface.  Use it in MH.
    
    * libmailutils/msgset/Makefile.am (libmsgset_la_SOURCES): Add new files.
    * libmailutils/msgset/addset.c: New file.
    * libmailutils/msgset/count.c: New file.
    * libmailutils/msgset/foreachmsgno.c: New file.
    * libmailutils/msgset/foreachuid.c: New file.
    * libmailutils/msgset/isempty.c: New file.
    * libmailutils/msgset/subset.c: New file.
    * libmailutils/msgset/trans.c: New file.
    * libmailutils/msgset/add.c (mu_msgset_add_range): Take fourth argument
    specifying the conversion mode. Translate numbers as necessary.
    * libmailutils/msgset/foreachmsg.c: Translate numbers as necessary.
    * libmailutils/msgset/foreachnum.c: Rewrite.
    * libmailutils/msgset/negate.c (_invert_range)
    (mu_msgset_add_range): Update calls to mu_msgset_add_range.
    * libmailutils/msgset/parse.c (parse_msgnum_env)<mode>: New member.
    (parse_msgrange): Update calls to mu_msgset_add_range.
    (mu_msgset_parse_imap): Change signature. All callers updated.
    * libmailutils/msgset/sub.c (mu_msgset_sub_range): Take fourth argument
    specifying the conversion mode. Translate numbers as necessary.
    
    * imap4d/copy.c (imap4d_copy0): Update calls to mu_msgset_create
    and mu_msgset_parse_imap.
    * imap4d/fetch.c (fetch_thunk): Likewise.
    * imap4d/search.c (parse_simple_key): Likewise.
    * imap4d/store.c (store_thunk): Likewise.
    * include/mailutils/msgset.h (MU_MSGSET_NUM,MU_MSGSET_UID): New defines.
    (mu_msgset_add,mu_msgset_sub): New protos.
    (mu_msgset_add_range,mu_msgset_sub_range): Take 4 arguments. All callers
    changed.
    * include/mailutils/sys/msgset.h (_mu_msgset_translate_pair)
    (_mu_msgset_translate_range): New protos.
    
    * libmailutils/tests/msgset.c: Reflect the above changes.
    * testsuite/msgset.c: Likewise.
    * libproto/imap/mbox.c: Update calls to mu_msgset functions.
    
    * mh/mh.h (mh_msgset_t): Remove.
    (mh_iterator_fp): Remove typedef.
    (mh_msgset_parse): Change signature.
    (mh_msgset_member,mh_msgset_reverse,mh_msgset_negate)
    (mh_msgset_current,mh_msgset_free,mh_msgset_uids): Remove protos.
    (mh_msgset_parse_string): New proto.
    (mh_msgset_first_current,mh_msgset_first): New proto.
    (mh_iterate: Remove proto. Use mu_msgset_foreach* functions instead.
    (mh_seq_add,mh_seq_delete): Change signatures.
    * mh/mh_init.c (mh_iterate): Remove.
    * mh/mh_msgset.c: Rewrite using mu_msgset_t.
    * mh/mh_sequence.c: Likewise.
    
    * mh/anno.c: Use new msgset functions.
    * mh/burst.c: Likewise.
    * mh/comp.c: Likewise.
    * mh/folder.c: Likewise.
    * mh/forw.c: Likewise.
    * mh/mark.c: Likewise.
    * mh/mhn.c: Likewise.
    * mh/mhpath.c: Likewise.
    * mh/mhseq.c: Likewise.
    * mh/pick.c: Likewise.
    * mh/refile.c: Likewise.
    * mh/repl.c: Likewise.
    * mh/rmm.c: Likewise.
    * mh/scan.c: Likewise.
    * mh/send.c: Likewise.
    * mh/sortm.c: Likewise.
    * mh/whatnowenv.c: Likewise.
    * mh/tests/mark.at: Reflect changes in the format of the saved
    sequences, which may contain ranges now.
    
    * mu/imap.c: Update calls to mu_msgset functions.

commit 26cfa2197d5a2866f1a08c48f94d65504fdef7b1
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Dec 28 12:04:30 2011 +0200

    msgset: implement "foreach" calls.
    
    * imap4d/copy.c (copy_env) <src>: Remove. Not needed now.
    (size_sum,do_copy): Change to a mu_msgset_message_action_t.
    (try_copy,safe_copy): Change signature; use mu_msgset_foreach_message.
    * imap4d/fetch.c (_fetch_from_message): Change to a
    mu_msgset_message_action_t.
    (imap4d_fetch0): Use mu_msgset_foreach_message.
    * imap4d/imap4d.h (imap4d_message_action_t): Remove typedef.
    (util_foreach_message): Remove. Use mu_msgset_foreach_message.
    * imap4d/store.c (_do_store): Change to a mu_msgset_message_action_t.
    (imap4d_store0): Use mu_msgset_foreach_message.
    * imap4d/util.c (util_foreach_message): Remove.
    * include/mailutils/list.h (mu_list_foreach_dir): New proto.
    * include/mailutils/msgset.h (mu_msgset_msgno_action_t)
    (mu_msgset_message_action_t): New typedefs.
    (mu_msgset_negate,mu_msgset_foreach_dir_msgno)
    (mu_msgset_foreach_msgno,mu_msgset_foreach_dir_message)
    (mu_msgset_foreach_message): New protos.
    * libmailutils/list/foreachdir.c: New file.
    * libmailutils/list/Makefile.am (liblist_la_SOURCES): Add foreachdir.c.
    * libmailutils/list/head.c (mu_list_head): Fix conditional.
    * libmailutils/list/tail.c (mu_list_tail): Likewise.
    * libmailutils/msgset/foreachmsg.c: New file.
    * libmailutils/msgset/foreachnum.c: New file.
    * libmailutils/msgset/negate.c: New file.
    * libmailutils/msgset/Makefile.am (libmsgset_la_SOURCES): Add
    new files.
    * libmailutils/msgset/getitr.c (mu_msgset_get_iterator): Call
    mu_msgset_aggregate before doing anything.
    * libmailutils/msgset/getlist.c (mu_msgset_get_list): Likewise.
    * libmailutils/msgset/locate.c (mu_msgset_locate): Likewise.
    * libmailutils/msgset/parse.c (parse_msgrange): Remove duplicated
    code.
    * testsuite/msgset.c: Implement -neg option.

-----------------------------------------------------------------------

Summary of changes:
 imap4d/copy.c                                  |   59 ++---
 imap4d/fetch.c                                 |   25 +-
 imap4d/imap4d.h                                |    5 -
 imap4d/search.c                                |   14 +-
 imap4d/store.c                                 |   13 +-
 imap4d/util.c                                  |   36 ---
 include/mailutils/list.h                       |    7 +-
 include/mailutils/msgset.h                     |   58 ++++-
 include/mailutils/sys/msgset.h                 |    5 +
 libmailutils/list/Makefile.am                  |    1 +
 libmailutils/list/{foreach.c => foreachdir.c}  |   31 +--
 libmailutils/list/head.c                       |    2 +-
 libmailutils/list/tail.c                       |    2 +-
 libmailutils/msgset/Makefile.am                |   12 +-
 libmailutils/msgset/add.c                      |   14 +-
 libmailutils/msgset/{locate.c => addset.c}     |   26 ++-
 libmailutils/msgset/{add.c => count.c}         |   31 ++-
 libmailutils/msgset/foreachmsg.c               |  105 ++++++++
 libmailutils/msgset/{free.c => foreachmsgno.c} |   32 +--
 libmailutils/msgset/foreachnum.c               |  106 ++++++++
 libmailutils/msgset/{getitr.c => foreachuid.c} |   23 +-
 libmailutils/msgset/getitr.c                   |    4 +
 libmailutils/msgset/getlist.c                  |    4 +
 libmailutils/msgset/{clear.c => isempty.c}     |   10 +-
 libmailutils/msgset/locate.c                   |    4 +
 libmailutils/msgset/negate.c                   |   97 +++++++
 libmailutils/msgset/parse.c                    |   34 +--
 libmailutils/msgset/sub.c                      |   19 +-
 libmailutils/msgset/{locate.c => subset.c}     |   26 ++-
 libmailutils/msgset/trans.c                    |   99 +++++++
 libmailutils/tests/msgset.c                    |   73 ++++--
 libproto/imap/mbox.c                           |   29 +-
 mh/anno.c                                      |   21 +-
 mh/burst.c                                     |   83 ++++---
 mh/comp.c                                      |   21 +-
 mh/folder.c                                    |   39 ++-
 mh/forw.c                                      |   48 ++--
 mh/mark.c                                      |   10 +-
 mh/mh.h                                        |   35 +--
 mh/mh_init.c                                   |   39 +---
 mh/mh_msgset.c                                 |  328 +++++++++++-------------
 mh/mh_sequence.c                               |  189 +++++++-------
 mh/mhn.c                                       |   30 ++-
 mh/mhpath.c                                    |   15 +-
 mh/mhseq.c                                     |   19 +-
 mh/pick.c                                      |   48 +---
 mh/refile.c                                    |   11 +-
 mh/repl.c                                      |   18 +-
 mh/rmm.c                                       |   11 +-
 mh/scan.c                                      |   19 +-
 mh/send.c                                      |   46 ++--
 mh/sortm.c                                     |   83 +++++--
 mh/tests/mark.at                               |    6 +-
 mh/whatnowenv.c                                |   38 +--
 mu/imap.c                                      |    4 +-
 testsuite/msgset.c                             |  155 ++++++++++--
 56 files changed, 1451 insertions(+), 871 deletions(-)
 copy libmailutils/list/{foreach.c => foreachdir.c} (68%)
 copy libmailutils/msgset/{locate.c => addset.c} (67%)
 copy libmailutils/msgset/{add.c => count.c} (71%)
 create mode 100644 libmailutils/msgset/foreachmsg.c
 copy libmailutils/msgset/{free.c => foreachmsgno.c} (61%)
 create mode 100644 libmailutils/msgset/foreachnum.c
 copy libmailutils/msgset/{getitr.c => foreachuid.c} (61%)
 copy libmailutils/msgset/{clear.c => isempty.c} (86%)
 create mode 100644 libmailutils/msgset/negate.c
 copy libmailutils/msgset/{locate.c => subset.c} (67%)
 create mode 100644 libmailutils/msgset/trans.c

diff --git a/imap4d/copy.c b/imap4d/copy.c
index f2c2314..63f262d 100644
--- a/imap4d/copy.c
+++ b/imap4d/copy.c
@@ -58,57 +58,35 @@ imap4d_copy (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
 struct copy_env
 {
   mu_mailbox_t dst;
-  mu_mailbox_t src;
   mu_off_t total;
   int ret;
   char **err_text;
 };
 
 static int
-size_sum (size_t msgno, void *data)
+size_sum (size_t msgno, mu_message_t msg, void *data)
 {
   struct copy_env *env = data;
-  mu_message_t msg = NULL;
   int rc;
   
-  rc = mu_mailbox_get_message (env->src, msgno, &msg);
+  size_t size;
+  rc = mu_message_size (msg, &size);
   if (rc)
     {
-      mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
-      env->ret = RESP_NO;
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_message_size", NULL, rc);
+      env->ret = RESP_BAD;
       return MU_ERR_FAILURE;
     }
-  else 
-    {
-      size_t size;
-      rc = mu_message_size (msg, &size);
-      if (rc)
-       {
-         mu_diag_funcall (MU_DIAG_ERROR, "mu_message_size", NULL, rc);
-         env->ret = RESP_BAD;
-         return MU_ERR_FAILURE;
-       }
-      env->total += size;
-    }
+  env->total += size;
   return 0;
 }
 
 static int
-do_copy (size_t msgno, void *data)
+do_copy (size_t msgno, mu_message_t msg, void *data)
 {
   struct copy_env *env = data;
-  mu_message_t msg = NULL;
   int status;
 
-  status = mu_mailbox_get_message (env->src, msgno, &msg);
-  if (status)
-    {
-      mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL,
-                      status);
-      env->ret = RESP_BAD;
-      return MU_ERR_FAILURE;
-    }
-
   imap4d_enter_critical ();
   status = mu_mailbox_append_message (env->dst, msg);
   imap4d_leave_critical ();
@@ -124,14 +102,12 @@ do_copy (size_t msgno, void *data)
 }
 
 static int
-try_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t msgset,
-         char **err_text)
+try_copy (mu_mailbox_t dst, mu_msgset_t msgset, char **err_text)
 {
   int rc;
   struct copy_env env;
 
   env.dst = dst;
-  env.src = src;
   env.total = 0;
   env.ret = RESP_OK;
   env.err_text = err_text;
@@ -139,7 +115,7 @@ try_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t 
msgset,
   *env.err_text = "Operation failed";
 
   /* Check size */
-  rc = util_foreach_message (msgset, size_sum, &env);
+  rc = mu_msgset_foreach_message (msgset, size_sum, &env);
   if (rc)
     return RESP_NO;
   if (env.ret != RESP_OK)
@@ -151,7 +127,7 @@ try_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t 
msgset,
       return RESP_NO;
     }
   env.total = 0;
-  rc = util_foreach_message (msgset, do_copy, &env);
+  rc = mu_msgset_foreach_message (msgset, do_copy, &env);
   quota_update (env.total);
   if (rc)
     return RESP_NO;
@@ -159,8 +135,7 @@ try_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t 
msgset,
 }
   
 static int
-safe_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t msgset,
-          char **err_text)
+safe_copy (mu_mailbox_t dst, mu_msgset_t msgset, char **err_text)
 {
   size_t nmesg;
   int status;
@@ -174,7 +149,7 @@ safe_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t 
msgset,
       return RESP_NO;
     }
 
-  status = try_copy (dst, src, msgset, err_text);
+  status = try_copy (dst, msgset, err_text);
   if (status != RESP_OK)
     {
       size_t maxmesg;
@@ -236,7 +211,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char 
**err_text)
   mu_mailbox_t cmbox = NULL;
   int arg = IMAP4_ARG_1 + !!isuid;
   int ns;
-
+  
   *err_text = NULL;
   if (imap4d_tokbuf_argc (tok) != arg + 2)
     {
@@ -246,14 +221,16 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char 
**err_text)
   
   msgset_str = imap4d_tokbuf_getarg (tok, arg);
   name = imap4d_tokbuf_getarg (tok, arg + 1);
-  status = mu_msgset_create (&msgset, mbox, isuid ? MU_MSGSET_UID : 0);
+  status = mu_msgset_create (&msgset, mbox, MU_MSGSET_NUM);
   if (!status)
     {
       *err_text = "Software error";
       return RESP_BAD;
     }
     
-  status = mu_msgset_parse_imap (msgset, msgset_str, &end);
+  status = mu_msgset_parse_imap (msgset,
+                                isuid ? MU_MSGSET_UID : MU_MSGSET_NUM,
+                                msgset_str, &end);
   if (status)
     {
       mu_msgset_free (msgset);
@@ -283,7 +260,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char 
**err_text)
          mu_list_t msglist;
          mu_msgset_get_list (msgset, &msglist);
          if (!mu_list_is_empty (msglist))
-           status = safe_copy (cmbox, mbox, msgset, err_text);
+           status = safe_copy (cmbox, msgset, err_text);
          mu_mailbox_close (cmbox);
        }
       mu_mailbox_destroy (&cmbox);
diff --git a/imap4d/fetch.c b/imap4d/fetch.c
index 46cb835..a73d169 100644
--- a/imap4d/fetch.c
+++ b/imap4d/fetch.c
@@ -1759,13 +1759,14 @@ fetch_thunk (imap4d_parsebuf_t pb)
   
   mstr = imap4d_parsebuf_next (pb, 1);
 
-  status = mu_msgset_create (&pclos->msgset, mbox,
-                            pclos->isuid ? MU_MSGSET_UID : 0);
+  status = mu_msgset_create (&pclos->msgset, mbox, MU_MSGSET_NUM);
   if (status)
     imap4d_parsebuf_exit (pb, "Software error");
   
   /* Parse sequence numbers. */
-  status = mu_msgset_parse_imap (pclos->msgset, mstr, &end);
+  status = mu_msgset_parse_imap (pclos->msgset,
+                                pclos->isuid ? MU_MSGSET_UID : MU_MSGSET_NUM,
+                                mstr, &end);
   if (status)
     imap4d_parsebuf_exit (pb, "Failed to parse message set");
   
@@ -1783,19 +1784,19 @@ fetch_thunk (imap4d_parsebuf_t pb)
 }
 
 int
-_fetch_from_message (size_t msgno, void *data)
+_fetch_from_message (size_t msgno, mu_message_t msg, void *data)
 {
   int rc = 0;
   struct fetch_runtime_closure *frc = data;
 
   frc->msgno = msgno;
-  if (mu_mailbox_get_message (mbox, msgno, &frc->msg) == 0)
-    {
-      io_sendf ("* %lu FETCH (", (unsigned long) msgno);
-      frc->eltno = 0;
-      rc = mu_list_foreach (frc->fnlist, _do_fetch, frc);
-      io_sendf (")\n");
-    }
+  frc->msg = msg;
+
+  io_sendf ("* %lu FETCH (", (unsigned long) msgno);
+  frc->eltno = 0;
+  rc = mu_list_foreach (frc->fnlist, _do_fetch, frc);
+  io_sendf (")\n");
+
   return rc;
 }
 
@@ -1833,7 +1834,7 @@ imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char 
**err_text)
         loop below */
       frc.err_text = "Completed";
 
-      util_foreach_message (pclos.msgset, _fetch_from_message, &frc);
+      mu_msgset_foreach_message (pclos.msgset, _fetch_from_message, &frc);
       mu_list_destroy (&frc.msglist);
     }
   
diff --git a/imap4d/imap4d.h b/imap4d/imap4d.h
index 22b3b28..a737363 100644
--- a/imap4d/imap4d.h
+++ b/imap4d/imap4d.h
@@ -372,11 +372,6 @@ extern char *util_getfullpath (const char *);
 extern struct imap4d_command *util_getcommand (char *, 
                                                struct imap4d_command []);
 
-typedef int (*imap4d_message_action_t) (size_t, void *);
-
-int util_foreach_message (mu_msgset_t list, imap4d_message_action_t action,
-                         void *data);
-
 enum datetime_parse_mode     /* how to parse date/time strings */
   {
     datetime_default,        /* default mode */
diff --git a/imap4d/search.c b/imap4d/search.c
index 2441810..69f4bae 100644
--- a/imap4d/search.c
+++ b/imap4d/search.c
@@ -608,10 +608,11 @@ parse_simple_key (struct parsebuf *pb)
   
   if (!condp->name)
     {
-      mu_msgset_t msgset = parse_msgset_create (pb, mbox,
-                                               pb->isuid ? MU_MSGSET_UID : 0);
+      mu_msgset_t msgset = parse_msgset_create (pb, mbox, MU_MSGSET_NUM);
       
-      if (mu_msgset_parse_imap (msgset, pb->token, NULL) == 0) 
+      if (mu_msgset_parse_imap (msgset,
+                               pb->isuid ? MU_MSGSET_UID : MU_MSGSET_NUM,
+                               pb->token, NULL) == 0) 
        {
          struct search_node *np = parse_alloc (pb, sizeof *np);
          np->type = node_value;
@@ -696,9 +697,10 @@ parse_simple_key (struct parsebuf *pb)
              break;
              
            case 'u': /* UID message set */
-             arg->v.value.v.msgset = parse_msgset_create (pb, NULL, 0);
-             if (mu_msgset_parse_imap (arg->v.value.v.msgset, pb->token,
-                                       NULL)) 
+             arg->v.value.v.msgset = parse_msgset_create (pb, NULL,
+                                                          MU_MSGSET_NUM);
+             if (mu_msgset_parse_imap (arg->v.value.v.msgset, MU_MSGSET_UID,
+                                       pb->token, NULL)) 
                {
                  mu_msgset_free (arg->v.value.v.msgset);
                  pb->err_mesg = "Bogus number set";
diff --git a/imap4d/store.c b/imap4d/store.c
index 0fe425d..21bc86a 100644
--- a/imap4d/store.c
+++ b/imap4d/store.c
@@ -69,13 +69,14 @@ store_thunk (imap4d_parsebuf_t p)
        imap4d_parsebuf_exit (p, "Bogus data suffix");
     }
 
-  status = mu_msgset_create (&pclos->msgset, mbox,
-                            pclos->isuid ? MU_MSGSET_UID : 0);
+  status = mu_msgset_create (&pclos->msgset, mbox, MU_MSGSET_NUM);
   if (status)
     imap4d_parsebuf_exit (p, "Software error");
   
   /* Get the message numbers in set[].  */
-  status = mu_msgset_parse_imap (pclos->msgset, mstr, &end);
+  status = mu_msgset_parse_imap (pclos->msgset,
+                                pclos->isuid ? MU_MSGSET_UID : MU_MSGSET_NUM,
+                                mstr, &end);
   if (status)
     imap4d_parsebuf_exit (p, "Failed to parse message set");
 
@@ -91,13 +92,11 @@ store_thunk (imap4d_parsebuf_t p)
 }
 
 static int
-_do_store (size_t msgno, void *data)
+_do_store (size_t msgno, mu_message_t msg, void *data)
 {
   struct store_parse_closure *pclos = data;
-  mu_message_t msg = NULL;
   mu_attribute_t attr = NULL;
       
-  mu_mailbox_get_message (mbox, msgno, &msg);
   mu_message_get_attribute (msg, &attr);
              
   switch (pclos->how)
@@ -154,7 +153,7 @@ imap4d_store0 (imap4d_tokbuf_t tok, int isuid, char **ptext)
                             ptext);
   if (rc == RESP_OK)
     {
-      util_foreach_message (pclos.msgset, _do_store, &pclos);
+      mu_msgset_foreach_message (pclos.msgset, _do_store, &pclos);
     
       *ptext = "Completed";
     }
diff --git a/imap4d/util.c b/imap4d/util.c
index c5341de..1a09610 100644
--- a/imap4d/util.c
+++ b/imap4d/util.c
@@ -39,42 +39,6 @@ util_getfullpath (const char *name)
   return mu_normalize_path (exp);
 }
 
-struct action_closure
-{
-  imap4d_message_action_t action;
-  void *data;
-};
-
-static int
-procrange (void *item, void *data)
-{
-  struct mu_msgrange *mp = item;
-  struct action_closure *clos = data;
-  size_t i;
-
-  for (i = mp->msg_beg; i <= mp->msg_end; i++)
-    {
-      int rc = clos->action (i, clos->data);
-      if (rc)
-       return rc;
-    }
-  return 0;
-}
-
-/* Apply ACTION to each message number from LIST. */
-int
-util_foreach_message (mu_msgset_t msgset, imap4d_message_action_t action,
-                     void *data)
-{
-  mu_list_t list;
-  struct action_closure clos;
-  
-  clos.action = action;
-  clos.data = data;
-  mu_msgset_get_list (msgset, &list);
-  return mu_list_foreach (list, procrange, &clos);
-}
-
 int
 util_do_command (imap4d_tokbuf_t tok)
 {
diff --git a/include/mailutils/list.h b/include/mailutils/list.h
index 184c7ec..6194f10 100644
--- a/include/mailutils/list.h
+++ b/include/mailutils/list.h
@@ -144,10 +144,15 @@ int mu_list_get_iterator (mu_list_t _list, mu_iterator_t 
*_pitr);
 typedef int (*mu_list_action_t) (void *_item, void *_data);
 
   /* Execute _action for each element in _list.  Use _data as the call-specific
-     data. */
+     data.  If _dir is 0, traverse the list from head to tail.  If it is 1,
+     traverse it in the reverse direction */
+int mu_list_foreach_dir (mu_list_t _list, int _dir, mu_list_action_t _action,
+                        void *_cbdata);
+  /* Same as mu_list_foreach_dir with _dir==0. */
 int mu_list_foreach (mu_list_t _list, mu_list_action_t _action, void *_data);
   /* A historical alias to the above. */
 int mu_list_do (mu_list_t, mu_list_action_t, void *) MU_DEPRECATED;
+  
 
   /* ************************************************* */
   /* Functions for combining two lists.                */
diff --git a/include/mailutils/msgset.h b/include/mailutils/msgset.h
index f9ae5b2..b665143 100644
--- a/include/mailutils/msgset.h
+++ b/include/mailutils/msgset.h
@@ -18,6 +18,8 @@
 #ifndef _MAILUTILS_MSGSET_H
 #define _MAILUTILS_MSGSET_H
 
+# include <mailutils/types.h>
+  
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -31,28 +33,68 @@ struct mu_msgrange
 /* Message numbers start with 1.  MU_MSGNO_LAST denotes the last
    message. */
 #define MU_MSGNO_LAST   0
+
+#define MU_MSGSET_NUM   0      /* Message set operates on sequence numbers */  
 
+#define MU_MSGSET_UID   1      /* Message set operates on UIDs */
+
+#define MU_MSGSET_MODE_MASK 0x0f
   
-#define MU_MSGSET_UID   0x01   /* Message set operates on UIDs */
-  
-int mu_msgset_create (mu_msgset_t *pmsgset, mu_mailbox_t mbox, int flags);
+int mu_msgset_create (mu_msgset_t *pmsgset, mu_mailbox_t mbox, int mode);
 int mu_msgset_get_list (mu_msgset_t msgset, mu_list_t *plist);
 int mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr);
 
-int mu_msgset_add_range (mu_msgset_t list, size_t beg, size_t end);
-int mu_msgset_sub_range (mu_msgset_t list, size_t beg, size_t end);
-  /*int mu_msgset_add_set (mu_msgset_t a, mu_msgset_t b);*/
-  /*int mu_msgset_sub_set (mu_msgset_t a, mu_msgset_t b);*/
+int mu_msgset_add_range (mu_msgset_t set, size_t beg, size_t end, int mode);
+int mu_msgset_sub_range (mu_msgset_t set, size_t beg, size_t end, int mode);
+int mu_msgset_add (mu_msgset_t a, mu_msgset_t b);
+int mu_msgset_sub (mu_msgset_t a, mu_msgset_t b);
 int mu_msgset_aggregate (mu_msgset_t set);
 int mu_msgset_clear (mu_msgset_t set);
 void mu_msgset_free (mu_msgset_t set);
 void mu_msgset_destroy (mu_msgset_t *set);
   
-int mu_msgset_parse_imap (mu_msgset_t set, const char *s, char **end);
+int mu_msgset_parse_imap (mu_msgset_t set, int mode, const char *s, char 
**end);
 
 int mu_msgset_print (mu_stream_t str, mu_msgset_t msgset);
   
 int mu_msgset_locate (mu_msgset_t msgset, size_t n,
                      struct mu_msgrange const **prange);
+
+int mu_msgset_negate (mu_msgset_t msgset, mu_msgset_t *pnset);
+
+int mu_msgset_count (mu_msgset_t mset, size_t *pcount);
+int mu_msgset_is_empty (mu_msgset_t mset);
+  
+typedef int (*mu_msgset_msgno_action_t) (size_t _n, void *_call_data);
+typedef int (*mu_msgset_message_action_t) (size_t _n, mu_message_t _msg,
+                                          void *_call_data);
+
+#define MU_MSGSET_FOREACH_FORWARD  0x00
+#define MU_MSGSET_FOREACH_BACKWARD 0x10
+
+int mu_msgset_foreach_num (mu_msgset_t _msgset, int _flags,
+                          mu_msgset_msgno_action_t _action,
+                          void *_call_data);
+  
+int mu_msgset_foreach_dir_msgno (mu_msgset_t _msgset, int _dir,
+                                mu_msgset_msgno_action_t _action,
+                                void *_data);
+int mu_msgset_foreach_msgno (mu_msgset_t _msgset,
+                            mu_msgset_msgno_action_t _action,
+                            void *_call_data);
+int mu_msgset_foreach_dir_msguid (mu_msgset_t _msgset, int _dir,
+                                 mu_msgset_msgno_action_t _action,
+                                 void *_data);
+int mu_msgset_foreach_msguid (mu_msgset_t _msgset,
+                             mu_msgset_msgno_action_t _action,
+                             void *_data);
+  
+int mu_msgset_foreach_dir_message (mu_msgset_t _msgset, int _dir,
+                                  mu_msgset_message_action_t _action,
+                                  void *_call_data);
+int mu_msgset_foreach_message (mu_msgset_t _msgset,
+                              mu_msgset_message_action_t _action,
+                              void *_call_data);
+
   
 #ifdef __cplusplus
 }
diff --git a/include/mailutils/sys/msgset.h b/include/mailutils/sys/msgset.h
index 9ecb053..7de6d61 100644
--- a/include/mailutils/sys/msgset.h
+++ b/include/mailutils/sys/msgset.h
@@ -28,4 +28,9 @@ struct _mu_msgset
   int flags;                /* Message set flags */
 };
 
+int _mu_msgset_translate_pair (mu_msgset_t mset, int mode,
+                              size_t *beg, size_t *end);
+int _mu_msgset_translate_range (mu_msgset_t mset, int mode,
+                               struct mu_msgrange *r);
+
 #endif
diff --git a/libmailutils/list/Makefile.am b/libmailutils/list/Makefile.am
index 21a600b..e583fc7 100644
--- a/libmailutils/list/Makefile.am
+++ b/libmailutils/list/Makefile.am
@@ -29,6 +29,7 @@ liblist_la_SOURCES = \
  foreach.c\
  get.c\
  getcomp.c\
+ foreachdir.c\
  gmap.c\
  head.c\
  insert.c\
diff --git a/libmailutils/list/foreach.c b/libmailutils/list/foreachdir.c
similarity index 68%
copy from libmailutils/list/foreach.c
copy to libmailutils/list/foreachdir.c
index 8c0d2a3..7baa3b5 100644
--- a/libmailutils/list/foreach.c
+++ b/libmailutils/list/foreachdir.c
@@ -24,32 +24,29 @@
 #include <mailutils/errno.h>
 
 int
-mu_list_foreach (mu_list_t list, mu_list_action_t action, void *cbdata)
+mu_list_foreach_dir (mu_list_t list, int dir,
+                    mu_list_action_t action, void *cbdata)
 {
   mu_iterator_t itr;
   int status = 0;
-
+  
   if (list == NULL || action == NULL)
     return EINVAL;
   status = mu_list_get_iterator (list, &itr);
   if (status)
     return status;
-  for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
-       mu_iterator_next (itr))
-    {
-      void *item;
-      mu_iterator_current (itr, &item);
-      if ((status = action (item, cbdata)))
-       break;
-    }
+
+  status = mu_iterator_ctl (itr, mu_itrctl_set_direction, &dir);
+  if (status == 0)
+    for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
+        mu_iterator_next (itr))
+      {
+       void *item;
+       mu_iterator_current (itr, &item);
+       if ((status = action (item, cbdata)))
+         break;
+      }
   mu_iterator_destroy (&itr);
   return status;
 }
 
-/* Retained for compatibility with previous versions.
-   In the future it will be removed, or changed to a define or weak alias. */
-int
-mu_list_do (mu_list_t list, mu_list_action_t action, void *cbdata)
-{
-  return mu_list_foreach (list, action, cbdata);
-}
diff --git a/libmailutils/list/head.c b/libmailutils/list/head.c
index 7c52b89..fd5790b 100644
--- a/libmailutils/list/head.c
+++ b/libmailutils/list/head.c
@@ -29,7 +29,7 @@ mu_list_head (mu_list_t list, void **pitem)
     return EINVAL;
   if (pitem == NULL)
     return MU_ERR_OUT_PTR_NULL;
-  if (!list->head.next)
+  if (list->head.next == &list->head)
     return MU_ERR_NOENT;
   *pitem = list->head.next->item;
   return 0;
diff --git a/libmailutils/list/tail.c b/libmailutils/list/tail.c
index a8d1472..f44a2cb 100644
--- a/libmailutils/list/tail.c
+++ b/libmailutils/list/tail.c
@@ -29,7 +29,7 @@ mu_list_tail (mu_list_t list, void **pitem)
     return EINVAL;
   if (pitem == NULL)
     return MU_ERR_OUT_PTR_NULL;
-  if (!list->head.prev)
+  if (list->head.prev == &list->head)
     return MU_ERR_NOENT;
   *pitem = list->head.prev->item;
   return 0;
diff --git a/libmailutils/msgset/Makefile.am b/libmailutils/msgset/Makefile.am
index 398806d..56582e4 100644
--- a/libmailutils/msgset/Makefile.am
+++ b/libmailutils/msgset/Makefile.am
@@ -19,16 +19,26 @@ noinst_LTLIBRARIES = libmsgset.la
 
 libmsgset_la_SOURCES = \
  add.c\
+ addset.c\
  aggr.c\
  clear.c\
  create.c\
+ count.c\
  getitr.c\
  getlist.c\
+ foreachnum.c\
+ foreachmsgno.c\
+ foreachuid.c\
+ foreachmsg.c\
  free.c\
+ isempty.c\
  locate.c\
+ negate.c\
  parse.c\
  print.c\
- sub.c
+ sub.c\
+ subset.c\
+ trans.c
 
 INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
 
diff --git a/libmailutils/msgset/add.c b/libmailutils/msgset/add.c
index 9d97707..3623768 100644
--- a/libmailutils/msgset/add.c
+++ b/libmailutils/msgset/add.c
@@ -23,18 +23,30 @@
 #include <mailutils/sys/msgset.h>
 
 int
-mu_msgset_add_range (mu_msgset_t mset, size_t beg, size_t end)
+mu_msgset_add_range (mu_msgset_t mset, size_t beg, size_t end, int mode)
 {
   int rc;
   struct mu_msgrange *range;
   
   if (!mset || beg == 0)
     return EINVAL;
+  if (end && beg > end)
+    {
+      size_t t = end;
+      end = beg;
+      beg = t;
+    }
   range = calloc (1, sizeof (*range));
   if (!range)
     return ENOMEM;
   range->msg_beg = beg;
   range->msg_end = end;
+  rc = _mu_msgset_translate_range (mset, mode, range);
+  if (rc)
+    {
+      free (range);
+      return rc;
+    }
   rc = mu_list_append (mset->list, range);
   if (rc)
     free (range);
diff --git a/libmailutils/msgset/locate.c b/libmailutils/msgset/addset.c
similarity index 67%
copy from libmailutils/msgset/locate.c
copy to libmailutils/msgset/addset.c
index 7b94ece..e897a7e 100644
--- a/libmailutils/msgset/locate.c
+++ b/libmailutils/msgset/addset.c
@@ -22,11 +22,29 @@
 #include <mailutils/msgset.h>
 #include <mailutils/sys/msgset.h>
 
+struct add_closure
+{
+  int mode;
+  mu_msgset_t dest;
+};
+
+static int
+add_range (void *item, void *data)
+{
+  struct mu_msgrange *r = item;
+  struct add_closure *clos = data;
+  return mu_msgset_add_range (clos->dest, r->msg_beg, r->msg_end, clos->mode);
+}
+
 int
-mu_msgset_locate (mu_msgset_t msgset, size_t n,
-                 struct mu_msgrange const **prange)
+mu_msgset_add (mu_msgset_t a, mu_msgset_t b)
 {
-  if (!msgset || n == 0)
+  struct add_closure closure;
+  if (!a)
     return EINVAL;
-  return mu_list_locate (msgset->list, &n, (void**)prange);
+  if (!b)
+    return 0;
+  closure.mode = b->flags;
+  closure.dest = a;
+  return mu_list_foreach (b->list, add_range, &closure);
 }
diff --git a/libmailutils/msgset/add.c b/libmailutils/msgset/count.c
similarity index 71%
copy from libmailutils/msgset/add.c
copy to libmailutils/msgset/count.c
index 9d97707..2eefaa4 100644
--- a/libmailutils/msgset/add.c
+++ b/libmailutils/msgset/count.c
@@ -22,22 +22,27 @@
 #include <mailutils/msgset.h>
 #include <mailutils/sys/msgset.h>
 
+static int
+count_messages (void *item, void *data)
+{
+  struct mu_msgrange *r = item;
+  size_t *count = data;
+  *count += r->msg_end - r->msg_beg + 1;
+  return 0;
+}
+  
 int
-mu_msgset_add_range (mu_msgset_t mset, size_t beg, size_t end)
+mu_msgset_count (mu_msgset_t mset, size_t *pcount)
 {
   int rc;
-  struct mu_msgrange *range;
-  
-  if (!mset || beg == 0)
+  size_t count = 0;
+
+  if (!mset)
     return EINVAL;
-  range = calloc (1, sizeof (*range));
-  if (!range)
-    return ENOMEM;
-  range->msg_beg = beg;
-  range->msg_end = end;
-  rc = mu_list_append (mset->list, range);
-  if (rc)
-    free (range);
-  mset->flags &= ~_MU_MSGSET_AGGREGATED;
+  if (!pcount)
+    return MU_ERR_OUT_PTR_NULL;
+  rc = mu_list_foreach (mset->list, count_messages, &count);
+  if (rc == 0)
+    *pcount = count;
   return rc;
 }
diff --git a/libmailutils/msgset/foreachmsg.c b/libmailutils/msgset/foreachmsg.c
new file mode 100644
index 0000000..f5fa981
--- /dev/null
+++ b/libmailutils/msgset/foreachmsg.c
@@ -0,0 +1,105 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   GNU Mailutils 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 3, or (at your option)
+   any later version.
+
+   GNU Mailutils 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 GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/errno.h>
+#include <mailutils/list.h>
+#include <mailutils/msgset.h>
+#include <mailutils/mailbox.h>
+#include <mailutils/sys/msgset.h>
+
+struct action_closure
+{
+  mu_msgset_message_action_t action;
+  void *data;
+  mu_msgset_t msgset;
+  int dir;
+};
+
+static int
+call_action (struct action_closure *clos, size_t i)
+{
+  int rc;
+  mu_message_t msg = NULL;
+  size_t n;
+
+  if (clos->msgset->flags == MU_MSGSET_UID)
+    {
+      rc = mu_mailbox_translate (clos->msgset->mbox, MU_MAILBOX_UID_TO_MSGNO,
+                                i, &n);
+      if (rc == MU_ERR_NOENT)
+       return 0;
+      else if (rc)
+       return rc;
+    }
+  else
+    n = i;
+  
+  rc = mu_mailbox_get_message (clos->msgset->mbox, n, &msg);
+  if (rc == MU_ERR_NOENT)
+    return 0;
+  else if (rc == 0)
+    rc = clos->action (i, msg, clos->data);
+  return rc;
+}
+
+static int
+procrange (void *item, void *data)
+{
+  struct mu_msgrange *mp = item;
+  struct action_closure *clos = data;
+  size_t i;
+  int rc = 0;
+  
+  if (clos->dir)
+    for (i = mp->msg_end; rc == 0 && i >= mp->msg_beg; i--)
+      rc = call_action (clos, i);
+  else
+    for (i = mp->msg_beg; i <= mp->msg_end; i++)
+      rc = call_action (clos, i);
+  return rc;
+}
+
+/* Apply ACTION to each message number from MSGSET. */
+int
+mu_msgset_foreach_dir_message (mu_msgset_t msgset, int dir,
+                              mu_msgset_message_action_t action,
+                              void *data)
+{
+  int rc;
+  struct action_closure clos;
+
+  if (!msgset->mbox)
+    return MU_ERR_NOT_OPEN;
+  rc = mu_msgset_aggregate (msgset);
+  if (rc)
+    return rc;
+  clos.action = action;
+  clos.data = data;
+  clos.msgset = msgset;
+  clos.dir = dir;
+  return mu_list_foreach_dir (msgset->list, dir, procrange, &clos);
+}
+
+int
+mu_msgset_foreach_message (mu_msgset_t msgset,
+                          mu_msgset_message_action_t action,
+                          void *data)
+{
+  return mu_msgset_foreach_dir_message (msgset, 0, action, data);
+}
diff --git a/libmailutils/msgset/free.c b/libmailutils/msgset/foreachmsgno.c
similarity index 61%
copy from libmailutils/msgset/free.c
copy to libmailutils/msgset/foreachmsgno.c
index 77a348e..200a81f 100644
--- a/libmailutils/msgset/free.c
+++ b/libmailutils/msgset/foreachmsgno.c
@@ -15,28 +15,24 @@
    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <stdlib.h>
-#include <mailutils/list.h>
 #include <mailutils/msgset.h>
-#include <mailutils/sys/msgset.h>
 
-void
-mu_msgset_free (mu_msgset_t mset)
+/* Apply ACTION to each message number from MSGSET. */
+int
+mu_msgset_foreach_dir_msgno (mu_msgset_t msgset, int dir,
+                            mu_msgset_msgno_action_t action,
+                            void *data)
 {
-  if (mset)
-    {
-      mu_list_destroy (&mset->list);
-      free (mset);
-    }
+  return mu_msgset_foreach_num (msgset,
+              (dir ? MU_MSGSET_FOREACH_BACKWARD : MU_MSGSET_FOREACH_FORWARD)|
+              MU_MSGSET_NUM,
+              action, data);
 }
 
-void
-mu_msgset_destroy (mu_msgset_t *pset)
+int
+mu_msgset_foreach_msgno (mu_msgset_t msgset,
+                        mu_msgset_msgno_action_t action,
+                        void *data)
 {
-  if (pset)
-    {
-      mu_msgset_free (*pset);
-      *pset = NULL;
-    }
+  return mu_msgset_foreach_dir_msgno (msgset, 0, action, data);
 }
-  
diff --git a/libmailutils/msgset/foreachnum.c b/libmailutils/msgset/foreachnum.c
new file mode 100644
index 0000000..3bb2314
--- /dev/null
+++ b/libmailutils/msgset/foreachnum.c
@@ -0,0 +1,106 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   GNU Mailutils 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 3, or (at your option)
+   any later version.
+
+   GNU Mailutils 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 GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/errno.h>
+#include <mailutils/list.h>
+#include <mailutils/msgset.h>
+#include <mailutils/mailbox.h>
+#include <mailutils/sys/msgset.h>
+
+struct action_closure
+{
+  mu_msgset_msgno_action_t action;
+  void *data;
+  mu_msgset_t msgset;
+  int flags;
+};
+
+static int
+call_action (struct action_closure *clos, size_t i)
+{
+  size_t n;
+  int cmd;
+  
+  if (clos->msgset->flags != (clos->flags & MU_MSGSET_MODE_MASK))
+    {
+      int rc;
+
+      switch (clos->flags & MU_MSGSET_MODE_MASK)
+       {
+       case MU_MSGSET_NUM:
+         cmd = MU_MAILBOX_UID_TO_MSGNO;
+         break;
+         
+       case MU_MSGSET_UID:
+         cmd = MU_MAILBOX_MSGNO_TO_UID;
+         break;
+         
+       default:
+         return EINVAL;
+       }
+      
+      rc = mu_mailbox_translate (clos->msgset->mbox, cmd, i, &n);
+      if (rc == MU_ERR_NOENT)
+       return 0;
+      if (rc)
+       return rc;
+    }
+  else
+    n = i;
+  return clos->action (n, clos->data);
+}
+    
+
+static int
+procrange (void *item, void *data)
+{
+  struct mu_msgrange *mp = item;
+  struct action_closure *clos = data;
+  size_t i;
+  int rc = 0;
+  
+  if (clos->flags & MU_MSGSET_FOREACH_BACKWARD)
+    for (i = mp->msg_end; rc == 0 && i >= mp->msg_beg; i--)
+      rc = call_action (clos, i);
+  else
+    for (i = mp->msg_beg; rc == 0 && i <= mp->msg_end; i++)
+      rc = call_action (clos, i);
+  return rc;
+}
+
+/* Apply ACTION to each message number or UID from MSGSET. */
+int
+mu_msgset_foreach_num (mu_msgset_t msgset, int flags,
+                      mu_msgset_msgno_action_t action,
+                      void *data)
+{
+  int rc;
+  struct action_closure clos;
+  
+  rc = mu_msgset_aggregate (msgset);
+  if (rc)
+    return rc;
+  clos.action = action;
+  clos.data = data;
+  clos.flags = flags;
+  clos.msgset = msgset;
+  return mu_list_foreach_dir (msgset->list,
+                             !!(flags & MU_MSGSET_FOREACH_BACKWARD),
+                             procrange, &clos);
+}
diff --git a/libmailutils/msgset/getitr.c b/libmailutils/msgset/foreachuid.c
similarity index 61%
copy from libmailutils/msgset/getitr.c
copy to libmailutils/msgset/foreachuid.c
index 75cfb3d..7fc36ed 100644
--- a/libmailutils/msgset/getitr.c
+++ b/libmailutils/msgset/foreachuid.c
@@ -15,16 +15,23 @@
    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <mailutils/types.h>
-#include <mailutils/errno.h>
-#include <mailutils/list.h>
 #include <mailutils/msgset.h>
-#include <mailutils/sys/msgset.h>
 
+/* Apply ACTION to each message number from MSGSET. */
 int
-mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr)
+mu_msgset_foreach_dir_msguid (mu_msgset_t msgset, int dir,
+                             mu_msgset_msgno_action_t action,
+                             void *data)
 {
-  if (!msgset)
-    return EINVAL;
-  return mu_list_get_iterator (msgset->list, pitr);
+  return mu_msgset_foreach_num (msgset,
+           (dir ? MU_MSGSET_FOREACH_BACKWARD : MU_MSGSET_FOREACH_FORWARD) |
+           MU_MSGSET_UID, action, data);
+}
+
+int
+mu_msgset_foreach_msguid (mu_msgset_t msgset,
+                         mu_msgset_msgno_action_t action,
+                         void *data)
+{
+  return mu_msgset_foreach_dir_msguid (msgset, 0, action, data);
 }
diff --git a/libmailutils/msgset/getitr.c b/libmailutils/msgset/getitr.c
index 75cfb3d..9d770f4 100644
--- a/libmailutils/msgset/getitr.c
+++ b/libmailutils/msgset/getitr.c
@@ -24,7 +24,11 @@
 int
 mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr)
 {
+  int rc;
   if (!msgset)
     return EINVAL;
+  rc = mu_msgset_aggregate (msgset);
+  if (rc)
+    return rc;
   return mu_list_get_iterator (msgset->list, pitr);
 }
diff --git a/libmailutils/msgset/getlist.c b/libmailutils/msgset/getlist.c
index 5f7370d..9f98c11 100644
--- a/libmailutils/msgset/getlist.c
+++ b/libmailutils/msgset/getlist.c
@@ -24,10 +24,14 @@
 int
 mu_msgset_get_list (mu_msgset_t msgset, mu_list_t *plist)
 {
+  int rc;
   if (!msgset)
     return EINVAL;
   if (!plist)
     return MU_ERR_OUT_PTR_NULL;
+  rc = mu_msgset_aggregate (msgset);
+  if (rc)
+    return rc;
   *plist = msgset->list;
   return 0;
 }
diff --git a/libmailutils/msgset/clear.c b/libmailutils/msgset/isempty.c
similarity index 86%
copy from libmailutils/msgset/clear.c
copy to libmailutils/msgset/isempty.c
index f3f7ef8..c1e4052 100644
--- a/libmailutils/msgset/clear.c
+++ b/libmailutils/msgset/isempty.c
@@ -15,18 +15,14 @@
    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
+#include <stdlib.h>
 #include <mailutils/types.h>
-#include <mailutils/errno.h>
 #include <mailutils/list.h>
 #include <mailutils/msgset.h>
 #include <mailutils/sys/msgset.h>
 
 int
-mu_msgset_clear (mu_msgset_t mset)
+mu_msgset_is_empty (mu_msgset_t mset)
 {
-  if (!mset)
-    return EINVAL;
-  mu_list_clear (mset->list);
-  return 0;
+  return mset == NULL || mu_list_is_empty (mset->list);
 }
-
diff --git a/libmailutils/msgset/locate.c b/libmailutils/msgset/locate.c
index 7b94ece..0d7155e 100644
--- a/libmailutils/msgset/locate.c
+++ b/libmailutils/msgset/locate.c
@@ -26,7 +26,11 @@ int
 mu_msgset_locate (mu_msgset_t msgset, size_t n,
                  struct mu_msgrange const **prange)
 {
+  int rc;
   if (!msgset || n == 0)
     return EINVAL;
+  rc = mu_msgset_aggregate (msgset);
+  if (rc)
+    return rc;
   return mu_list_locate (msgset->list, &n, (void**)prange);
 }
diff --git a/libmailutils/msgset/negate.c b/libmailutils/msgset/negate.c
new file mode 100644
index 0000000..75a454d
--- /dev/null
+++ b/libmailutils/msgset/negate.c
@@ -0,0 +1,97 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   GNU Mailutils 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 3, or (at your option)
+   any later version.
+
+   GNU Mailutils 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 GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/errno.h>
+#include <mailutils/list.h>
+#include <mailutils/mailbox.h>
+#include <mailutils/msgset.h>
+#include <mailutils/sys/msgset.h>
+
+struct invert_closure
+{
+  mu_msgset_t nset;
+  size_t next_num;
+};
+
+static int
+_invert_range (void *item, void *data)
+{
+  struct mu_msgrange *range = item;
+  struct invert_closure *clos = data;
+  int rc;
+  
+  if (clos->next_num < range->msg_beg - 1)
+    {
+      rc = mu_msgset_add_range (clos->nset,
+                               clos->next_num, range->msg_beg - 1,
+                               clos->nset->flags);
+      if (rc)
+       return rc;
+    }
+  clos->next_num = range->msg_end + 1;
+  return 0;
+}
+
+/* Negate the message set: on return PNSET consists of the messages
+   _not contained_ in the input message set. */
+int
+mu_msgset_negate (mu_msgset_t msgset, mu_msgset_t *pnset)
+{
+  int rc;
+  struct invert_closure clos;
+  size_t total;
+  
+  if (!msgset)
+    return EINVAL;
+  if (!msgset->mbox)
+    return MU_ERR_NOT_OPEN;
+
+  rc = mu_msgset_aggregate (msgset);
+  if (rc)
+    return rc;
+  rc = mu_mailbox_messages_count (msgset->mbox, &total);
+  if (rc)
+    return rc;
+  if (msgset->flags == MU_MSGSET_UID)
+    {
+      rc = mu_mailbox_translate (msgset->mbox,
+                                MU_MAILBOX_MSGNO_TO_UID,
+                                total, &total);
+      if (rc)
+       return rc;
+    }
+  rc = mu_msgset_create (&clos.nset, msgset->mbox, msgset->flags);
+  if (rc)
+    return rc;
+  clos.next_num = 1;
+  rc = mu_list_foreach (msgset->list, _invert_range, &clos);
+  if (rc == 0)
+    {
+      if (clos.next_num < total)
+       rc = mu_msgset_add_range (clos.nset, clos.next_num, total,
+                                 clos.nset->flags);
+    }
+  
+  if (rc)
+    mu_msgset_free (clos.nset);
+  else
+    *pnset = clos.nset;
+
+  return rc;
+}
diff --git a/libmailutils/msgset/parse.c b/libmailutils/msgset/parse.c
index c522478..cc064d6 100644
--- a/libmailutils/msgset/parse.c
+++ b/libmailutils/msgset/parse.c
@@ -33,6 +33,7 @@ struct parse_msgnum_env
   size_t minval;         /* Min. sequence number or UID */
   size_t maxval;         /* Max. sequence number or UID */
   mu_msgset_t msgset;    /* Message set being built. */
+  int mode;              /* Operation mode (num/uid) */
 };
 
 /* Get a single message number/UID from env->s and store it into *PN.
@@ -95,28 +96,8 @@ parse_msgrange (struct parse_msgnum_env *env)
       msgrange.msg_beg = tmp;
     }
 
-  if ((env->msgset->flags & MU_MSGSET_UID) && env->msgset->mbox)
-    {
-      int rc;
-
-      rc = mu_mailbox_translate (env->msgset->mbox,
-                                MU_MAILBOX_UID_TO_MSGNO,
-                                msgrange.msg_beg, &msgrange.msg_beg);
-      if (rc == MU_ERR_NOENT)
-       msgrange.msg_beg = env->minval;
-      else if (rc)
-       return rc;
-      
-      rc = mu_mailbox_translate (env->msgset->mbox,
-                                MU_MAILBOX_UID_TO_MSGNO,
-                                msgrange.msg_end, &msgrange.msg_end);
-      if (rc == MU_ERR_NOENT)
-       msgrange.msg_end = env->maxval;
-      else if (rc)
-       return rc;
-    }      
-
-  return mu_msgset_add_range (env->msgset, msgrange.msg_beg, msgrange.msg_end);
+  return mu_msgset_add_range (env->msgset, msgrange.msg_beg, msgrange.msg_end,
+                             env->mode);
 }
 
 /* Parse IMAP-style message set specification S.
@@ -125,13 +106,15 @@ parse_msgrange (struct parse_msgnum_env *env)
    On error, return error code and point END to the position in the input
    string where parsing has failed. */
 int
-mu_msgset_parse_imap (mu_msgset_t mset, const char *s, char **end)
+mu_msgset_parse_imap (mu_msgset_t mset, int mode, const char *s, char **end)
 {
   int rc;
   struct parse_msgnum_env env;
   
   if (!s || !mset)
     return EINVAL;
+  if (end)
+    *end = (char*) s;
   if (!*s)
     return MU_ERR_PARSE;
 
@@ -139,9 +122,8 @@ mu_msgset_parse_imap (mu_msgset_t mset, const char *s, char 
**end)
   env.s = s;
   env.msgset = mset;
   env.minval = 1;
+  env.mode = mode;
   
-  if (end)
-    *end = (char*) s;
   if (mset->mbox)
     {
       size_t lastmsgno;      /* Max. sequence number. */
@@ -149,7 +131,7 @@ mu_msgset_parse_imap (mu_msgset_t mset, const char *s, char 
**end)
       rc = mu_mailbox_messages_count (mset->mbox, &lastmsgno);
       if (rc == 0)
        {
-         if (mset->flags & MU_MSGSET_UID)
+         if (mode == MU_MSGSET_UID)
            {
              rc = mu_mailbox_translate (mset->mbox, MU_MAILBOX_MSGNO_TO_UID,
                                         lastmsgno, &env.maxval);
diff --git a/libmailutils/msgset/sub.c b/libmailutils/msgset/sub.c
index 2840781..d069568 100644
--- a/libmailutils/msgset/sub.c
+++ b/libmailutils/msgset/sub.c
@@ -112,7 +112,7 @@ sub_msgno_last (mu_msgset_t mset, size_t beg)
 }
 
 int
-mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t end)
+mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t end, int mode)
 {
   int rc;
   mu_iterator_t itr;
@@ -122,6 +122,19 @@ mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t 
end)
     return EINVAL;
   if (mu_list_is_empty (mset->list))
     return MU_ERR_NOENT;
+  if (end && beg > end)
+    {
+      size_t t = end;
+      end = beg;
+      beg = t;
+    }
+
+  rc = _mu_msgset_translate_pair (mset, mode, &beg, &end);
+  if (rc == MU_ERR_NOENT)
+    return 0;
+  else if (rc)
+    return rc;
+  
   rc = mu_msgset_aggregate (mset);
   if (rc)
     return rc;
@@ -138,8 +151,6 @@ mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t 
end)
   if (beg < mr->msg_beg)
     beg = mr->msg_beg;
   
-  if (rc)
-    return rc;
   rc = mu_list_tail (mset->list, (void**) &mr);
   if (mr->msg_end != MU_MSGNO_LAST)
     {
@@ -148,7 +159,7 @@ mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t 
end)
       if (end > mr->msg_end)
        end = mr->msg_end;
     }
-  
+
   rc = mu_list_get_iterator (mset->list, &itr);
   if (rc)
     return rc;
diff --git a/libmailutils/msgset/locate.c b/libmailutils/msgset/subset.c
similarity index 67%
copy from libmailutils/msgset/locate.c
copy to libmailutils/msgset/subset.c
index 7b94ece..87b7cc0 100644
--- a/libmailutils/msgset/locate.c
+++ b/libmailutils/msgset/subset.c
@@ -22,11 +22,29 @@
 #include <mailutils/msgset.h>
 #include <mailutils/sys/msgset.h>
 
+struct sub_closure
+{
+  int mode;
+  mu_msgset_t dest;
+};
+
+static int
+sub_range (void *item, void *data)
+{
+  struct mu_msgrange *r = item;
+  struct sub_closure *clos = data;
+  return mu_msgset_sub_range (clos->dest, r->msg_beg, r->msg_end, clos->mode);
+}
+
 int
-mu_msgset_locate (mu_msgset_t msgset, size_t n,
-                 struct mu_msgrange const **prange)
+mu_msgset_sub (mu_msgset_t a, mu_msgset_t b)
 {
-  if (!msgset || n == 0)
+  struct sub_closure closure;
+  if (!a)
     return EINVAL;
-  return mu_list_locate (msgset->list, &n, (void**)prange);
+  if (!b)
+    return 0;
+  closure.mode = b->flags;
+  closure.dest = a;
+  return mu_list_foreach (b->list, sub_range, &closure);
 }
diff --git a/libmailutils/msgset/trans.c b/libmailutils/msgset/trans.c
new file mode 100644
index 0000000..df7df42
--- /dev/null
+++ b/libmailutils/msgset/trans.c
@@ -0,0 +1,99 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   GNU Mailutils 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 3, or (at your option)
+   any later version.
+
+   GNU Mailutils 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 GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/errno.h>
+#include <mailutils/list.h>
+#include <mailutils/msgset.h>
+#include <mailutils/mailbox.h>
+#include <mailutils/sys/msgset.h>
+
+int
+_mu_msgset_translate_pair (mu_msgset_t mset, int mode,
+                          size_t *pbeg, size_t *pend)
+{
+  if (mode != mset->flags && mset->mbox)
+    {
+      int cmd, rc;
+      size_t n;
+      size_t beg = *pbeg;
+      size_t end = *pend;
+      
+      switch (mset->flags)
+       {
+       case MU_MSGSET_NUM:
+         cmd = MU_MAILBOX_UID_TO_MSGNO;
+         break;
+
+       case MU_MSGSET_UID:
+         cmd = MU_MAILBOX_MSGNO_TO_UID;
+         break;
+
+       default:
+         return EINVAL;
+       }
+
+      rc = mu_mailbox_translate (mset->mbox, cmd, beg, &n);
+      if (rc)
+       {
+         if (rc == MU_ERR_NOENT && cmd == MU_MAILBOX_UID_TO_MSGNO)
+           {
+             size_t x;
+             
+             if (end == MU_MSGNO_LAST)
+               {
+                 rc = mu_mailbox_uidnext (mset->mbox, &x);
+                 if (rc)
+                   return rc;
+               }
+             else
+               x = end;
+             for (; rc == MU_ERR_NOENT && beg < x; beg++)
+               rc = mu_mailbox_translate (mset->mbox, cmd, beg, &n);
+           }
+         if (rc)
+           return rc;
+       }
+
+      *pbeg = n;
+      
+      if (beg == end)
+       *pend = n;
+      else if (end != MU_MSGNO_LAST)
+       {
+         rc = mu_mailbox_translate (mset->mbox, cmd, end, &n);
+         if (rc == MU_ERR_NOENT && cmd == MU_MAILBOX_UID_TO_MSGNO)
+           {
+             for (; rc == MU_ERR_NOENT && beg < end; end--)
+               rc = mu_mailbox_translate (mset->mbox, cmd, end, &n);
+             
+           }
+         if (rc)
+           return rc;
+         *pend = n;
+       }
+    }
+  return 0;
+}
+
+int
+_mu_msgset_translate_range (mu_msgset_t mset, int mode, struct mu_msgrange *r)
+{
+  return _mu_msgset_translate_pair (mset, mode, &r->msg_beg, &r->msg_end);
+}
+
diff --git a/libmailutils/tests/msgset.c b/libmailutils/tests/msgset.c
index 91db029..19549ac 100644
--- a/libmailutils/tests/msgset.c
+++ b/libmailutils/tests/msgset.c
@@ -19,7 +19,7 @@
 #include <mailutils/mailutils.h>
 
 static void
-parse_msgset (char *arg, struct mu_msgrange *range)
+parse_msgrange (char *arg, struct mu_msgrange *range)
 {
   size_t msgnum;
   char *p;
@@ -52,13 +52,33 @@ parse_msgset (char *arg, struct mu_msgrange *range)
   range->msg_end = msgnum;
 }
 
+mu_msgset_t
+parse_msgset (const char *arg)
+{
+  int rc;
+  mu_msgset_t msgset;
+  char *end;
+
+  MU_ASSERT (mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM));
+  if (arg)
+    {
+      rc = mu_msgset_parse_imap (msgset, MU_MSGSET_NUM, arg, &end);
+      if (rc)
+       {
+         mu_error ("mu_msgset_parse_imap: %s near %s",
+                   mu_strerror (rc), end);
+         exit (1);
+       }
+    }
+  return msgset;
+}
+
 int
 main (int argc, char **argv)
 {
   int i;
   char *msgset_string = NULL;
   mu_msgset_t msgset;
-  int rc;
   
   mu_set_program_name (argv[0]);
   for (i = 1; i < argc; i++)
@@ -67,7 +87,8 @@ main (int argc, char **argv)
 
       if (strcmp (arg, "-h") == 0 || strcmp (arg, "-help") == 0)
        {
-         mu_printf ("usage: %s [-msgset=SET] [-add X[:Y]] [-del X:[Y]]...\n",
+         mu_printf ("usage: %s [-msgset=SET] [-add=X[:Y]] [-del=X[:Y]] "
+                    "[-addset=SET] [-delset=SET] ...\n",
                     mu_program_name);
          return 0;
        }
@@ -77,18 +98,7 @@ main (int argc, char **argv)
        break;
     }
 
-  MU_ASSERT (mu_msgset_create (&msgset, NULL, 0));
-  if (msgset_string)
-    {
-      char *end;
-      rc = mu_msgset_parse_imap (msgset, msgset_string, &end);
-      if (rc)
-       {
-         mu_error ("mu_msgset_parse_imap: %s near %s",
-                   mu_strerror (rc), end);
-         return 1;
-       }
-    }
+  msgset = parse_msgset (msgset_string);
   
   for (; i < argc; i++)
     {
@@ -97,15 +107,40 @@ main (int argc, char **argv)
       
       if (strncmp (arg, "-add=", 5) == 0)
        {
-         parse_msgset (arg + 5, &range);
+         parse_msgrange (arg + 5, &range);
          MU_ASSERT (mu_msgset_add_range (msgset, range.msg_beg,
-                                         range.msg_end));
+                                         range.msg_end, MU_MSGSET_NUM));
        }
       else if (strncmp (arg, "-sub=", 5) == 0)
        {
-         parse_msgset (arg + 5, &range);
+         parse_msgrange (arg + 5, &range);
          MU_ASSERT (mu_msgset_sub_range (msgset, range.msg_beg,
-                                         range.msg_end));
+                                         range.msg_end, MU_MSGSET_NUM));
+       }
+      else if (strncmp (arg, "-addset=", 8) == 0)
+       {
+         mu_msgset_t tset = parse_msgset (arg + 8);
+         if (!msgset)
+           msgset = tset;
+         else
+           {
+             MU_ASSERT (mu_msgset_add (msgset, tset));
+             mu_msgset_free (tset);
+           }
+       }
+      else if (strncmp (arg, "-subset=", 8) == 0)
+       {
+         mu_msgset_t tset = parse_msgset (arg + 8);
+         if (!msgset)
+           {
+             mu_error ("no initial message set");
+             exit (1);
+           }
+         else
+           {
+             MU_ASSERT (mu_msgset_sub (msgset, tset));
+             mu_msgset_free (tset);
+           }
        }
       else
        {
diff --git a/libproto/imap/mbox.c b/libproto/imap/mbox.c
index 1613ba3..b4582cb 100644
--- a/libproto/imap/mbox.c
+++ b/libproto/imap/mbox.c
@@ -175,7 +175,7 @@ __imap_msg_get_stream (struct _mu_imap_message *imsg, 
size_t msgno,
       if (rc)
        return rc;
 
-      rc = mu_msgset_create (&msgset, NULL, 0);
+      rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
       if (rc == 0)
        {
          struct save_closure clos;
@@ -183,7 +183,7 @@ __imap_msg_get_stream (struct _mu_imap_message *imsg, 
size_t msgno,
          clos.imsg = imsg;
          clos.save_stream = imbx->cache;
 
-         rc = mu_msgset_add_range (msgset, msgno, msgno);
+         rc = mu_msgset_add_range (msgset, msgno, msgno, MU_MSGSET_NUM);
          if (rc == 0)
            {
              _imap_mbx_clrerr (imbx);
@@ -370,10 +370,10 @@ _imap_hdr_fill (void *data, char **pbuf, size_t *plen)
   unsigned long msgno = _imap_msg_no (imsg);
   int rc;
 
-  rc = mu_msgset_create (&msgset, NULL, 0);
+  rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
   if (rc == 0)
     {
-      rc = mu_msgset_add_range (msgset, msgno, msgno);
+      rc = mu_msgset_add_range (msgset, msgno, msgno, MU_MSGSET_NUM);
       if (rc == 0)
        {
          clos.imsg = imsg;
@@ -619,11 +619,11 @@ _imap_msg_bodystructure (mu_message_t msg, struct 
mu_bodystructure **pbs)
   int rc;
   mu_msgset_t msgset;
 
-  rc = mu_msgset_create (&msgset, NULL, 0);
+  rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
   if (rc == 0)
     {
       size_t msgno = _imap_msg_no (imsg);
-      rc = mu_msgset_add_range (msgset, msgno, msgno);
+      rc = mu_msgset_add_range (msgset, msgno, msgno, MU_MSGSET_NUM);
       if (rc == 0)
        rc = _imap_fetch_with_callback (imap, msgset, "BODYSTRUCTURE",
                                        _imap_bodystructure_callback, pbs);
@@ -949,7 +949,7 @@ _imap_mbx_gensync (mu_mailbox_t mbox, int *pdel)
   struct attr_tab *tab;
   size_t count;
 
-  rc = mu_msgset_create (&msgset, NULL, 0);
+  rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
   if (rc)
     return rc;
 
@@ -962,7 +962,7 @@ _imap_mbx_gensync (mu_mailbox_t mbox, int *pdel)
          if (imbx->msgs[i].flags & _MU_IMAP_MSG_ATTRCHG)
            {
              mu_msgset_clear (msgset);
-             mu_msgset_add_range (msgset, i + 1, i + 1);
+             mu_msgset_add_range (msgset, i + 1, i + 1, MU_MSGSET_NUM);
              if (rc)
                break;
              rc = mu_imap_store_flags (imap, 0, msgset,
@@ -994,12 +994,13 @@ _imap_mbx_gensync (mu_mailbox_t mbox, int *pdel)
                }
            }
          if (tab[i].end == tab[i].start)
-           rc = mu_msgset_add_range (msgset, tab[i].start + 1,
-                                     tab[i].start + 1);
+           rc = mu_msgset_add_range (msgset,
+                                     tab[i].start + 1, tab[i].start + 1,
+                                     MU_MSGSET_NUM);
          else
            rc = mu_msgset_add_range (msgset,
-                                     tab[i].start + 1,
-                                     tab[i].end + 1);
+                                     tab[i].start + 1, tab[i].end + 1,
+                                     MU_MSGSET_NUM);
          if (rc)
            break;
        }
@@ -1192,10 +1193,10 @@ _imap_mbx_scan (mu_mailbox_t mbox, size_t msgno, size_t 
*pcount)
   
   mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
            (_("scanning mailbox %s"), mu_url_to_string (mbox->url)));
-  rc = mu_msgset_create (&msgset, NULL, 0);
+  rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
   if (rc)
     return rc;
-  rc = mu_msgset_add_range (msgset, msgno, MU_MSGNO_LAST);
+  rc = mu_msgset_add_range (msgset, msgno, MU_MSGNO_LAST, MU_MSGSET_NUM);
   if (rc)
     {
       mu_msgset_free (msgset);
diff --git a/mh/anno.c b/mh/anno.c
index 1b113fb..0851f75 100644
--- a/mh/anno.c
+++ b/mh/anno.c
@@ -95,10 +95,11 @@ opt_handler (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
-void
-anno (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+int
+anno (size_t n, mu_message_t msg, void *call_data)
 {
   mh_annotate (msg, component, anno_text, anno_date);
+  return 0;
 }
 
 int
@@ -107,7 +108,7 @@ main (int argc, char **argv)
   int rc;
   int index;
   mu_mailbox_t mbox;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
   size_t len;
 
   MU_APP_INIT_NLS ();
@@ -154,10 +155,16 @@ main (int argc, char **argv)
   argc -= index;
   argv += index;
   
-  mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
-  rc = mh_iterate (mbox, &msgset, anno, NULL);
-
-  mh_msgset_current (mbox, &msgset, 0);
+  mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
+  rc = mu_msgset_foreach_message (msgset, anno, NULL);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_foreach_message", NULL, rc);
+      exit (1);
+    }
+      
+  mh_msgset_first_current (mbox, msgset);
+  mu_msgset_free (msgset);
   mh_global_save_state ();
   mu_mailbox_sync (mbox);
   mu_mailbox_close (mbox);
diff --git a/mh/burst.c b/mh/burst.c
index d731bfa..98851b1 100644
--- a/mh/burst.c
+++ b/mh/burst.c
@@ -578,8 +578,8 @@ burst_or_copy (mu_message_t msg, int recursive, int copy)
   return 1;
 }
 
-void
-burst (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+int
+burst (size_t num, mu_message_t msg, void *data)
 {
   memset (&map, 0, sizeof (map));
   mh_message_number (msg, &map.msgno);
@@ -599,36 +599,38 @@ burst (mu_mailbox_t mbox, mu_message_t msg, size_t num, 
void *data)
     }
   else if (!quiet)
     mu_error (_("message %s not in digest format"), mu_umaxtostr (0, num));
+  return 0;
 }
 
 
 /* Inplace handling */
+struct rename_env
+{
+  size_t lastuid;
+  size_t idx;
+};
 
-void
-burst_rename (mh_msgset_t *ms, size_t lastuid)
+  
+static int
+_rename (size_t msgno, void *data)
 {
-  size_t i, j;
+  struct rename_env *rp = data;
+  
+  if (msgno == burst_map[rp->idx].msgno)
+    {
+      rp->lastuid -= burst_map[rp->idx].count;
+      burst_map[rp->idx].msgno = rp->lastuid;
+      rp->idx--;
+    }
 
-  VERBOSE ((_("Renaming messages")));
-  j = burst_count - 1;
-  for (i = ms->count; i > 0; i--)
+  if (msgno != rp->lastuid)
     {
       const char *from;
       const char *to;
 
-      if (ms->list[i-1] == burst_map[j].msgno)
-       {
-         lastuid -= burst_map[j].count;
-         burst_map[j].msgno = lastuid;
-         j--;
-       }
-
-      if (ms->list[i-1] == lastuid)
-       continue;
-      
-      from = mu_umaxtostr (0, ms->list[i-1]);
-      to   = mu_umaxtostr (1, lastuid);
-      --lastuid;
+      from = mu_umaxtostr (0, msgno);
+      to   = mu_umaxtostr (1, rp->lastuid);
+      --rp->lastuid;
 
       VERBOSE((_("message %s becomes message %s"), from, to));
               
@@ -639,6 +641,18 @@ burst_rename (mh_msgset_t *ms, size_t lastuid)
          exit (1);
        }
     }
+  return 0;
+}
+
+void
+burst_rename (mu_msgset_t ms, size_t lastuid)
+{
+  struct rename_env renv;
+
+  VERBOSE ((_("Renaming messages")));
+  renv.lastuid = lastuid;
+  renv.idx = burst_count - 1;
+  mu_msgset_foreach_dir_msguid (ms, 1, _rename, &renv);
 }  
 
 void
@@ -705,7 +719,7 @@ main (int argc, char **argv)
 {
   int index, rc;
   mu_mailbox_t mbox;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
   const char *tempfolder = mh_global_profile_get ("Temp-Folder", ".temp");
   
   /* Native Language Support */
@@ -720,7 +734,7 @@ main (int argc, char **argv)
 
   VERBOSE ((_("Opening folder `%s'"), mh_current_folder ()));
   mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
-  mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
+  mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
 
   if (inplace)
     {
@@ -744,7 +758,7 @@ main (int argc, char **argv)
   else
     tmpbox = mbox;
 
-  rc = mh_iterate (mbox, &msgset, burst, NULL);
+  rc = mu_msgset_foreach_message (msgset, burst, NULL);
   if (rc)
     return rc;
 
@@ -752,8 +766,8 @@ main (int argc, char **argv)
     {
       mu_url_t dst_url = NULL;
       size_t i, next_uid, last_uid;
-      mh_msgset_t ms;
-      char *xargv[2];
+      mu_msgset_t ms;
+      size_t count;
       const char *dir;
       
       burst_map = obstack_finish (&stk);
@@ -763,11 +777,14 @@ main (int argc, char **argv)
        last_uid += burst_map[i].count;
       VERBOSE ((_("Estimated last UID: %s"), mu_umaxtostr (0, last_uid)));
 
-      mu_asprintf (&xargv[0], "%s-last", mu_umaxtostr (0, burst_map[0].msgno));
-      xargv[1] = NULL;
-      mh_msgset_parse (mbox, &ms, 1, xargv, NULL);
-      free (xargv[0]);
-      mh_msgset_uids (mbox, &ms);
+      rc = mu_msgset_create (&ms, mbox, MU_MSGSET_NUM);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_create", NULL, rc);
+         exit (1);
+       }
+      mu_mailbox_messages_count (mbox, &count);
+      mu_msgset_add_range (ms, burst_map[0].msgno, count, MU_MSGSET_NUM);
        
       mu_mailbox_get_url (mbox, &dst_url);
       mu_url_sget_path (dst_url, &dir);
@@ -779,8 +796,8 @@ main (int argc, char **argv)
        }
       mu_mailbox_close (mbox);
 
-      burst_rename (&ms, last_uid);
-      mh_msgset_free (&ms);
+      burst_rename (ms, last_uid);
+      mu_msgset_free (ms);
 
       finalize_inplace (last_uid);
 
diff --git a/mh/comp.c b/mh/comp.c
index 336b348..8adc2cd 100644
--- a/mh/comp.c
+++ b/mh/comp.c
@@ -246,22 +246,21 @@ main (int argc, char **argv)
             `-draftfolder +folder'  treat this arguments  as `msg'. */
          if (use_draft || index < argc)
            {
-             mh_msgset_t msgset;
+             mu_msgset_t msgset;
              mu_mailbox_t mbox;
              
              mbox = mh_open_folder (draftfolder, 
                                      MU_STREAM_RDWR|MU_STREAM_CREAT);
-             mh_msgset_parse (mbox, &msgset, 
+             mh_msgset_parse (&msgset, mbox, 
                               argc - index, argv + index,
                               use_draft ? "cur" : "new");
-              mh_msgset_uids (mbox, &msgset);  
-             if (msgset.count != 1)
+             if (!mh_msgset_single_message (msgset))
                {
                  mu_error (_("only one message at a time!"));
                  return 1;
                }
-             draftmessage = mu_umaxtostr (0, msgset.list[0]);
-             mh_msgset_free (&msgset);
+             draftmessage = mu_umaxtostr (0, mh_msgset_first_uid (msgset));
+             mu_msgset_free (msgset);
              mu_mailbox_destroy (&mbox);
            }
          if (mh_draft_message (draftfolder, draftmessage,
@@ -273,20 +272,20 @@ main (int argc, char **argv)
 
   if (folder_set && index < argc)
     {
-      mh_msgset_t msgset;
+      mu_msgset_t msgset;
       mu_mailbox_t mbox;
       
       mbox = mh_open_folder (mh_current_folder (), MU_STREAM_READ);
-      mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
-      if (msgset.count != 1)
+      mh_msgset_parse (&msgset, mbox, argc - index, argv + index, "cur");
+      if (!mh_msgset_single_message (msgset))
        {
          mu_error (_("only one message at a time!"));
          return 1;
        }
       unlink (wh_env.file);
-      copy_message (mbox, msgset.list[0], wh_env.file);
+      copy_message (mbox, mh_msgset_first (msgset), wh_env.file);
       mu_mailbox_destroy (&mbox);
-      mh_msgset_free (&msgset);
+      mu_msgset_free (msgset);
     }
   else
     {
diff --git a/mh/folder.c b/mh/folder.c
index 756015f..bc952c1 100644
--- a/mh/folder.c
+++ b/mh/folder.c
@@ -773,9 +773,10 @@ pack_xlate (struct pack_tab *pack_tab, size_t count, 
size_t n)
 static int
 _fixup (const char *name, const char *value, struct fixup_data *fd, int flags)
 {
-  size_t i, j;
+  size_t i;
+  int rc;
   struct mu_wordsplit ws;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
 
   if (verbose)
     fprintf (stderr, "Sequence `%s'...\n", name);
@@ -787,20 +788,32 @@ _fixup (const char *name, const char *value, struct 
fixup_data *fd, int flags)
       return 0;
     }
 
-  msgset.list = xcalloc (ws.ws_wordc, sizeof msgset.list[0]);
-  for (i = j = 0; i < ws.ws_wordc; i++)
+  rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_UID);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_create", NULL, rc);
+      exit (1);
+    }
+  
+  for (i = 0; i < ws.ws_wordc; i++)
     {
       size_t n = pack_xlate (fd->pack_tab, fd->count,
                             strtoul (ws.ws_wordv[i], NULL, 0));
       if (n)
-       msgset.list[j++] = n;
+       {
+         rc = mu_msgset_add_range (msgset, n, n, MU_MSGSET_UID);
+         if (rc)
+           {
+             mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_add_range", NULL, rc);
+             exit (1);
+           }
+       }
     }
-  msgset.count = j;
 
   mu_wordsplit_free (&ws);
   
-  mh_seq_add (fd->mbox, name, &msgset, flags | SEQ_ZERO);
-  free (msgset.list);
+  mh_seq_add (fd->mbox, name, msgset, flags | SEQ_ZERO);
+  mu_msgset_free (msgset);
 
   if (verbose)
     {
@@ -944,7 +957,7 @@ int
 main (int argc, char **argv)
 {
   int index = 0;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
 
   /* Native Language Support */
   MU_APP_INIT_NLS ();
@@ -971,9 +984,11 @@ main (int argc, char **argv)
     
   if (argc - index == 1)
     {
-      mu_mailbox_t mbox = mh_open_folder (mh_current_folder (), 
MU_STREAM_RDWR);
-      mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
-      mh_msgset_current (mbox, &msgset, 0);
+      mu_mailbox_t mbox = mh_open_folder (mh_current_folder (),
+                                         MU_STREAM_RDWR);
+      mh_msgset_parse (&msgset, mbox, argc - index, argv + index, "cur");
+      mh_msgset_first_current (mbox, msgset);
+      mu_msgset_free (msgset);
       mh_global_save_state ();
       mu_mailbox_close (mbox);
       mu_mailbox_destroy (&mbox);
diff --git a/mh/forw.c b/mh/forw.c
index 4f3726b..5824e8a 100644
--- a/mh/forw.c
+++ b/mh/forw.c
@@ -116,7 +116,7 @@ static char *draftmessage = "new";
 static const char *draftfolder = NULL;
 static char *input_file;        /* input file name (--file option) */
 
-static mh_msgset_t msgset;
+static mu_msgset_t msgset;
 static mu_mailbox_t mbox;
 
 static int
@@ -331,15 +331,27 @@ format_message (mu_stream_t outstr, mu_message_t msg, int 
num,
     }
 }
 
-void
-format_message_itr (mu_mailbox_t mbox MU_ARG_UNUSED,
-                   mu_message_t msg, size_t num, void *data)
+int
+format_message_itr (size_t num, mu_message_t msg, void *data)
 {
   struct format_data *fp = data;
 
   format_message (fp->stream, msg, fp->num, fp->format);
   if (fp->num)
     fp->num++;
+  return 0;
+}
+
+static int
+_proc_forwards (size_t n, mu_message_t msg, void *call_data)
+{
+  mu_stream_t stream = call_data;
+  size_t num;
+             
+  if (annotate)
+    mu_list_append (wh_env.anno_list, msg);
+  mh_message_number (msg, &num);
+  return mu_stream_printf (stream, " %lu", (unsigned long) num);
 }
 
 void
@@ -411,36 +423,22 @@ finish_draft ()
        {
          mu_url_t url;
          const char *mbox_path;
-         const char *p;
-         size_t i;
       
          mu_mailbox_get_url (mbox, &url);
          mu_url_sget_path (url, &mbox_path);
          mu_asprintf (&str, "#forw [] +%s", mbox_path);
          rc = mu_stream_write (stream, str, strlen (str), NULL);
          free (str);
-         for (i = 0; rc == 0 && i < msgset.count; i++)
-           {
-             mu_message_t msg;
-             size_t num;
-             
-             mu_mailbox_get_message (mbox, msgset.list[i], &msg);
-             if (annotate)
-               mu_list_append (wh_env.anno_list, msg);
-             mh_message_number (msg, &num);
-             p = mu_umaxtostr (0, num);
-             rc = mu_stream_write (stream, " ", 1, NULL);
-             if (rc)
-               break;
-             rc = mu_stream_write (stream, p, strlen (p), NULL);
-           }
+         mu_msgset_foreach_message (msgset, _proc_forwards, stream);
        }
       else
        {
+         int single_message = mh_msgset_single_message (msgset);
+         
          str = "\n------- ";
          rc = mu_stream_write (stream, str, strlen (str), NULL);
          
-         if (msgset.count == 1)
+         if (single_message)
            {
              fd.num = 0;
              str = (char*) _("Forwarded message\n");
@@ -454,12 +452,12 @@ finish_draft ()
          rc = mu_stream_write (stream, str, strlen (str), NULL);
          fd.stream = stream;
          fd.format = format;
-         rc = mh_iterate (mbox, &msgset, format_message_itr, &fd);
+         rc = mu_msgset_foreach_message (msgset, format_message_itr, &fd);
       
          str = "\n------- ";
          rc = mu_stream_write (stream, str, strlen (str), NULL);
          
-         if (msgset.count == 1)
+         if (single_message)
            str = (char*) _("End of Forwarded message");
          else
            str = (char*) _("End of Forwarded messages");
@@ -504,7 +502,7 @@ main (int argc, char **argv)
   else
     {
       mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
-      mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
+      mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
     }
   
   if (build_only || !draftfolder)
diff --git a/mh/mark.c b/mh/mark.c
index da9297e..b4224db 100644
--- a/mh/mark.c
+++ b/mh/mark.c
@@ -121,7 +121,7 @@ opt_handler (int key, char *arg, struct argp_state *state)
 struct mark_closure
 {
   mu_mailbox_t mbox;
-  mh_msgset_t *msgset;
+  mu_msgset_t msgset;
 };
 
 static int
@@ -191,7 +191,7 @@ int
 main (int argc, char **argv)
 {
   int index;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
   mu_mailbox_t mbox;
   mu_url_t url;
   struct mark_closure clos;
@@ -209,11 +209,11 @@ main (int argc, char **argv)
        
   argc -= index;
   argv += index;
-  mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
-  mh_msgset_uids (mbox, &msgset);
+  mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
   
   clos.mbox = mbox;
-  clos.msgset = &msgset;
+  clos.msgset = msgset;
+  //FIXME: msgset operates on UIDs but there's no way to inform it about that.
   switch (action)
     {
     case ARG_ADD:
diff --git a/mh/mh.h b/mh/mh.h
index 2e0f812..bca11a2 100644
--- a/mh/mh.h
+++ b/mh/mh.h
@@ -60,6 +60,7 @@
 #include <mailutils/mh.h>
 #include <mailutils/stdstream.h>
 #include <mailutils/datetime.h>
+#include <mailutils/msgset.h>
 
 #include <mu_umaxtostr.h>
 
@@ -194,19 +195,6 @@ typedef struct
   mu_header_t header;
 } mh_context_t;
 
-#define MH_MSGSET_UID   0x01
-
-typedef struct
-{
-  int flags;
-  size_t *list;
-  size_t count;
-  size_t size;
-} mh_msgset_t;
-
-typedef void (*mh_iterator_fp) (mu_mailbox_t mbox, mu_message_t msg,
-                               size_t num, void *data);
-
 /* Recipient masks */
 #define RCPT_NONE 0
 #define RCPT_TO   0x0001
@@ -303,14 +291,14 @@ int mh_message_number (mu_message_t msg, size_t *pnum);
 
 mu_mailbox_t mh_open_folder (const char *folder, int flags);
 
-void mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
+void mh_msgset_parse (mu_msgset_t *msgset, mu_mailbox_t mbox, 
                      int argc, char **argv, char *def);
-int mh_msgset_member (mh_msgset_t *msgset, size_t num);
-void mh_msgset_reverse (mh_msgset_t *msgset);
-void mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset);
-void mh_msgset_current (mu_mailbox_t mbox, mh_msgset_t *msgset, int index);
-void mh_msgset_free (mh_msgset_t *msgset);
-void mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset);
+void mh_msgset_parse_string (mu_msgset_t *msgset, mu_mailbox_t mbox, 
+                            const char *string, char *def);
+void mh_msgset_first_current (mu_mailbox_t mbox, mu_msgset_t msgset);
+size_t mh_msgset_first (mu_msgset_t msgset);
+size_t mh_msgset_first_uid (mu_msgset_t msgset);
+int mh_msgset_single_message (mu_msgset_t msgset);
 
 char *mh_get_dir (void);
 int mh_find_file (const char *name, char **resolved_name);
@@ -323,9 +311,6 @@ void mh_expand_aliases (mu_message_t msg, mu_address_t 
*addr_to,
 int mh_is_my_name (const char *name);
 char * mh_my_email (void);
 
-int mh_iterate (mu_mailbox_t mbox, mh_msgset_t *msgset,
-               mh_iterator_fp itr, void *data);
-
 size_t mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg);
 
 int mh_decode_rcpt_flag (const char *arg);
@@ -372,9 +357,9 @@ int mhl_format_run (mu_list_t fmt, int width, int length, 
int flags,
                    mu_message_t msg, mu_stream_t output);
 void mhl_format_destroy (mu_list_t *fmt);
 
-void mh_seq_add (mu_mailbox_t mbox, const char *name, mh_msgset_t *mset,
+void mh_seq_add (mu_mailbox_t mbox, const char *name, mu_msgset_t mset,
                 int flags);
-int mh_seq_delete (mu_mailbox_t mbox, const char *name, mh_msgset_t *mset,
+int mh_seq_delete (mu_mailbox_t mbox, const char *name, mu_msgset_t mset,
                   int flags);
 const char *mh_seq_read (mu_mailbox_t mbox, const char *name, int flags);
 
diff --git a/mh/mh_init.c b/mh/mh_init.c
index fc1934a..7fef8f9 100644
--- a/mh/mh_init.c
+++ b/mh/mh_init.c
@@ -577,32 +577,6 @@ mh_find_file (const char *name, char **resolved_name)
 }
 
 int
-mh_iterate (mu_mailbox_t mbox, mh_msgset_t *msgset,
-           mh_iterator_fp itr, void *data)
-{
-  int rc;
-  size_t i;
-
-  for (i = 0; i < msgset->count; i++)
-    {
-      mu_message_t msg;
-      size_t num;
-
-      num = msgset->list[i];
-      if ((rc = mu_mailbox_get_message (mbox, num, &msg)) != 0)
-       {
-         mu_error (_("cannot get message %lu: %s"),
-                   (unsigned long) num, mu_strerror (rc));
-         return 1;
-       }
-
-      itr (mbox, msg, num, data);
-    }
-
-  return 0;
-}
-
-int
 mh_spawnp (const char *prog, const char *file)
 {
   struct mu_wordsplit ws;
@@ -1039,19 +1013,16 @@ mh_draft_message (const char *name, const char 
*msgspec, char **pname)
   else
     {
       char *argv[2];
-      mh_msgset_t msgset;
+      mu_msgset_t msgset;
       
       argv[0] = (char*) msgspec;
       argv[1] = NULL;
-      mh_msgset_parse (mbox, &msgset, 1, argv, "cur");
-      if (msgset.count > 1)
+      mh_msgset_parse (&msgset, mbox, 1, argv, "cur");
+      if (!mh_msgset_single_message (msgset))
        mu_error (_("only one message at a time!"));
       else
-       {
-         mh_msgset_uids (mbox, &msgset);
-         uid = msgset.list[0];
-       }
-      mh_msgset_free (&msgset);
+       uid = mh_msgset_first_uid (msgset);
+      mu_msgset_free (msgset);
     }
 
   mu_url_sget_path (url, &path);
diff --git a/mh/mh_msgset.c b/mh/mh_msgset.c
index 49ed35a..5392d5f 100644
--- a/mh/mh_msgset.c
+++ b/mh/mh_msgset.c
@@ -18,169 +18,91 @@
 /* MH message sets. */
 
 #include <mh.h>
+#include <mailutils/sys/msgset.h>
 
-void
-mh_msgset_init (mh_msgset_t *msgset)
-{
-  memset (msgset, 0, sizeof (*msgset));
-}
-
-void
-mh_msgset_expand (mh_msgset_t *msgset, size_t count)
+size_t
+mh_msgset_first (mu_msgset_t msgset)
 {
-  size_t rest = msgset->size - msgset->count;
-
-  if (rest < count)
+  mu_list_t list;
+  struct mu_msgrange *r;
+  int rc;
+  
+  rc = mu_msgset_get_list (msgset, &list);
+  if (rc)
     {
-      msgset->size += count;
-      msgset->list = xrealloc (msgset->list,
-                              msgset->size * sizeof (msgset->list[0]));
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_get_list", NULL, rc);
+      exit (1);
     }
-}
-
-void
-mh_msgset_add (mh_msgset_t *msgset, size_t n)
-{
-  mh_msgset_expand (msgset, 1);
-  msgset->list[msgset->count++] = n;
-}
-
-static int
-comp_mesg (const void *a, const void *b)
-{
-  size_t an = *(size_t*)a;
-  size_t bn = *(size_t*)b;
-  if (an > bn)
-    return 1;
-  else if (an < bn)
-    return -1;
-  return 0;
-}
-
-void
-mh_msgset_optimize (mh_msgset_t *msgset)
-{
-  size_t i, msgno;
-  size_t msgcnt = msgset->count;
-  size_t *msglist = msgset->list;
-      
-  /* Sort the resulting message set */
-  qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
-
-  /* Remove duplicates. */
-  for (i = 0, msgno = 1; i < msgset->count; i++)
-    if (msglist[msgno-1] != msglist[i])
-      msglist[msgno++] = msglist[i];
-  msgset->count = msgno;
-}
-
-/* Check if message with ordinal number `num' is contained in the
-   message set. */
-int
-mh_msgset_member (mh_msgset_t *msgset, size_t num)
-{
-  size_t i;
-
-  for (i = 0; i < msgset->count; i++)
-    if (msgset->list[i] == num)
-      return i + 1;
-  return 0;
-}
-
-/* Reverse the order of messages in the message set */
-void
-mh_msgset_reverse (mh_msgset_t *msgset)
-{
-  int head, tail;
-
-  for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
+  rc = mu_list_head (list, (void**)&r);
+  if (rc)
     {
-      size_t val = msgset->list[head];
-      msgset->list[head] = msgset->list[tail];
-      msgset->list[tail] = val;
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_list_get", NULL, rc);
+      exit (1);
     }
+  return r->msg_beg;
 }
 
-/* Set the current message to that contained at position `index'
-   in the given message set */
-void
-mh_msgset_current (mu_mailbox_t mbox, mh_msgset_t *msgset, int index)
+size_t
+mh_msgset_first_uid (mu_msgset_t msgset)
 {
-  mu_message_t msg = NULL;
   int rc;
   size_t cur;
-  
-  rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
+
+  cur = mh_msgset_first (msgset);
+  rc = mu_mailbox_translate (msgset->mbox, MU_MAILBOX_MSGNO_TO_UID, cur, &cur);
   if (rc)
     {
-      mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_translate", NULL, rc);
       exit (1);
     }
-  mh_message_number (msg, &cur);
-  mh_mailbox_set_cur (mbox, cur);
+  return cur;
 }
 
-/* Free memory allocated for the message set. Note, that the msgset
-   itself is supposed to reside in the statically allocated memory and
-   therefore is not freed */
+/* Set the current message to that contained at position 0
+   in the given message set.
+   FIXME: mbox is superfluous
+*/
 void
-mh_msgset_free (mh_msgset_t *msgset)
+mh_msgset_first_current (mu_mailbox_t mbox, mu_msgset_t msgset)
 {
-  if (msgset->count)
-    free (msgset->list);
+  mh_mailbox_set_cur (mbox, mh_msgset_first_uid (msgset));
 }
 
-/* Negate the message set: on return `msgset' consists of the messages
-   _not contained_ in the input message set. Any memory associated with
-   the input message set is freed */
-void
-mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset)
+int
+mh_msgset_single_message (mu_msgset_t msgset)
 {
-  size_t i, total = 0, msgno;
-  size_t *list;
-
-  mu_mailbox_messages_count (mbox, &total);
-  list = calloc (total, sizeof (list[0]));
-  if (!list)
-    mh_err_memory (1);
-  for (i = 1, msgno = 0; i <= total; i++)
+  int rc;
+  mu_list_t list;
+  struct mu_msgrange *r;
+  size_t count;
+  
+  rc = mu_msgset_get_list (msgset, &list);
+  if (rc)
     {
-      if (!mh_msgset_member (msgset, i))
-       list[msgno++] = i;
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_get_list", NULL, rc);
+      exit (1);
     }
-
-  list = realloc (list, sizeof (list[0]) * msgno);
-  if (!list)
+  rc = mu_list_count (list, &count);
+  if (rc)
     {
-      mu_error (_("not enough memory"));
-      abort ();
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_list_count", NULL, rc);
+      exit (1);
     }
-  mh_msgset_free (msgset);
-  msgset->count = msgno;
-  msgset->list = list;
-}
-
-void
-mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
-{
-  size_t i;
-
-  if (msgset->flags & MH_MSGSET_UID)
-    return;
-  for (i = 0; i < msgset->count; i++)
+  if (count != 1)
+    return 0;
+  rc = mu_list_head (list, (void**)&r);
+  if (rc)
     {
-      mu_message_t msg;
-      mu_mailbox_get_message (mbox, msgset->list[i], &msg);
-      mh_message_number (msg, &msgset->list[i]);
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_list_get", NULL, rc);
+      exit (1);
     }
-  msgset->flags |= MH_MSGSET_UID;
+  return r->msg_beg == r->msg_end;
 }
 
 
 struct msgset_parser
 {
-  mu_mailbox_t mbox;
-  mh_msgset_t *msgset;
+  mu_msgset_t msgset;
   char *curp;
   int argc;
   char **argv;
@@ -192,10 +114,16 @@ struct msgset_parser
 
 static void
 msgset_parser_init (struct msgset_parser *parser, mu_mailbox_t mbox,
-                   mh_msgset_t *msgset, int argc, char **argv)
+                   int argc, char **argv)
 {
-  parser->mbox = mbox;
-  parser->msgset = msgset;
+  int rc;
+  
+  rc = mu_msgset_create (&parser->msgset, mbox, MU_MSGSET_NUM);//FIXME: flags?
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_create", NULL, rc);
+      exit (1);
+    }
   parser->argc = argc;
   parser->argv = argv;
   parser->curp = "";
@@ -238,7 +166,7 @@ _expand_sequence (struct msgset_parser *parser, char *term)
   const char *listp;
   int negate = 0;
 
-  listp = mh_global_sequences_get (parser->mbox, term, NULL);
+  listp = mh_global_sequences_get (parser->msgset->mbox, term, NULL);
   if (!listp)
     {
       int len;
@@ -249,7 +177,7 @@ _expand_sequence (struct msgset_parser *parser, char *term)
       if (strncmp (term, neg, len))
        return 1;
       negate = 1;
-      listp = mh_global_sequences_get (parser->mbox, term + len, NULL);
+      listp = mh_global_sequences_get (parser->msgset->mbox, term + len, NULL);
       if (!listp)
        return 1;
     }
@@ -262,16 +190,35 @@ _expand_sequence (struct msgset_parser *parser, char 
*term)
     }
   else
     {
+      int rc;
       struct msgset_parser clone;
-      
-      msgset_parser_init (&clone, parser->mbox,  parser->msgset,
+
+      msgset_parser_init (&clone, parser->msgset->mbox,
                          ws.ws_wordc, ws.ws_wordv);
       msgset_parser_run (&clone);
       mu_wordsplit_free (&ws);
+      if (negate)
+       {
+         mu_msgset_t negset;
+         
+         rc = mu_msgset_negate (clone.msgset, &negset);
+         if (rc)
+           {
+             mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_negate", NULL, rc);
+             exit (1);
+           }
+         mu_msgset_free (clone.msgset);
+         clone.msgset = negset;
+       }
+      rc = mu_msgset_add (parser->msgset, clone.msgset);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_add", NULL, rc);
+         exit (1);
+       }
+      mu_msgset_free (clone.msgset);
     }
   
-  if (negate)
-    mh_msgset_negate (parser->mbox, parser->msgset);
   return 0;
 }
 
@@ -310,7 +257,7 @@ static int
 msgset_last (mu_mailbox_t mbox, size_t *pnum)
 {
   int rc;
-
+  
   rc = mu_mailbox_messages_count (mbox, pnum);
   if (rc)
     {
@@ -406,8 +353,11 @@ parse_term (struct msgset_parser *parser, int seq)
       for (p = keywords; p->name; p++)
        if (tlen == p->len && memcmp (p->name, term, tlen) == 0)
          {
-           if (p->handler (parser->mbox, &parser->number))
+           size_t num;
+           
+           if (p->handler (parser->msgset->mbox, &num))
              msgset_abort (term);
+           parser->number = num;
            parser->sign = p->sign;
            parser->validuid = 1;
            return PARSE_MORE;
@@ -428,7 +378,8 @@ parse_term (struct msgset_parser *parser, int seq)
       if (endp != parser->curp)
        msgset_abort (term);
       
-      if (mu_mailbox_translate (parser->mbox, MU_MAILBOX_UID_TO_MSGNO,
+      if (mu_mailbox_translate (parser->msgset->mbox,
+                               MU_MAILBOX_UID_TO_MSGNO,
                                num, &parser->number))
        {
          parser->validuid = 0;
@@ -447,48 +398,37 @@ static void
 add_messages (struct msgset_parser *parser, size_t start, size_t count,
              int sign)
 {
-  size_t i;
+  int rc;
 
   if (start == 0)
     start = 1;
-  mh_msgset_expand (parser->msgset, count);
   if (sign)
     {
       if (count > start)
        count = start;
-      for (i = 0; i < count; i++, start--)
-       parser->msgset->list[parser->msgset->count++] = start;
+      rc = mu_msgset_add_range (parser->msgset, start, start - count + 1,
+                               MU_MSGSET_NUM);
     }
   else
     {
       size_t total;
   
-      mu_mailbox_messages_count (parser->mbox, &total);
+      mu_mailbox_messages_count (parser->msgset->mbox, &total);
       if (start + count > total)
-       count = total - start + 1;
-      for (i = 0; i < count; i++, start++)
-       parser->msgset->list[parser->msgset->count++] = start;
+       {
+         count = total - start + 1;
+         if (count == 0)
+           emptyrange_abort (parser->argv[-1]);
+       }
+      rc = mu_msgset_add_range (parser->msgset, start, start + count - 1,
+                               MU_MSGSET_NUM);
     }
-  if (count == 0)
-    emptyrange_abort (parser->argv[-1]);
-}
 
-static void
-add_message_range (struct msgset_parser *parser, size_t start, size_t end)
-{
-  if (end == start)
-    emptyrange_abort (parser->argv[-1]);
-
-  if (end < start)
+  if (rc)
     {
-      size_t t = start;
-      start = end;
-      end = t;
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_add_range", NULL, rc);
+      exit (1);
     }
-  mh_msgset_expand (parser->msgset, end - start + 1);
-
-  for (; start <= end; start++)
-    parser->msgset->list[parser->msgset->count++] = start;
 }
 
 /* range: term '-' term
@@ -527,8 +467,9 @@ parse_range (struct msgset_parser *parser)
       if (!validuid)
        {
          size_t total, lastuid;
-         msgset_last (parser->mbox, &total);
-         mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
+         msgset_last (parser->msgset->mbox, &total);
+         mu_mailbox_translate (parser->msgset->mbox,
+                               MU_MAILBOX_MSGNO_TO_UID,
                                total, &lastuid);
          if (start > lastuid)
            {
@@ -550,6 +491,7 @@ parse_range (struct msgset_parser *parser)
     {
       size_t lastuid = 0;
       int validuid = parser->validuid;
+      int rc;
       
       parser->curp++;
       if (parse_term (parser, 0) == PARSE_EOF)
@@ -558,8 +500,8 @@ parse_range (struct msgset_parser *parser)
        {
          size_t total;
 
-         msgset_last (parser->mbox, &total);
-         mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
+         msgset_last (parser->msgset->mbox, &total);
+         mu_mailbox_translate (parser->msgset->mbox, MU_MAILBOX_MSGNO_TO_UID,
                                total, &lastuid);
 
          if (parser->number > lastuid)
@@ -572,15 +514,22 @@ parse_range (struct msgset_parser *parser)
          if (!lastuid)
            {
              size_t total;
-             msgset_last (parser->mbox, &total);
-             mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
+             msgset_last (parser->msgset->mbox, &total);
+             mu_mailbox_translate (parser->msgset->mbox,
+                                   MU_MAILBOX_MSGNO_TO_UID,
                                    total, &lastuid);
            }
          if (start > lastuid && !parser->validuid)
            emptyrange_abort (parser->argv[-1]);
          start = 1;
        }
-      add_message_range (parser, start, parser->number);
+      rc = mu_msgset_add_range (parser->msgset, start, parser->number,
+                               MU_MSGSET_NUM);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_add_range", NULL, rc);
+         exit (1);
+       }
     }
   else if (!parser->validuid)
     {
@@ -588,13 +537,12 @@ parse_range (struct msgset_parser *parser)
       exit (1);
     }
   else
-    mh_msgset_add (parser->msgset, start);
+    mu_msgset_add_range (parser->msgset, start, start, MU_MSGSET_NUM);
   return 1;
 }
   
   
-/* Parse a message specification. The composed msgset is
-   not sorted nor optimised */
+/* Parse a message specification saved in a configured PARSER. */
 static void
 msgset_parser_run (struct msgset_parser *parser)
 {
@@ -602,11 +550,9 @@ msgset_parser_run (struct msgset_parser *parser)
     ;
 }
 
-/* Parse a message specification from (argc;argv). Returned msgset is
-   sorted and optimised (i.e. it does not contain duplicate message
-   numbers) */
+/* Parse a message specification from (argc;argv).  */
 void
-mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, 
+mh_msgset_parse (mu_msgset_t *msgset, mu_mailbox_t mbox, 
                 int argc, char **argv, char *def)
 {
   struct msgset_parser parser;
@@ -629,11 +575,25 @@ mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
       argv[1] = NULL;
     }
   
-  mh_msgset_init (msgset);
-  msgset_parser_init (&parser, mbox, msgset, argc, argv);
+  msgset_parser_init (&parser, mbox, argc, argv);
   msgset_parser_run (&parser);
+  *msgset = parser.msgset;
+}
 
-  mh_msgset_optimize (msgset);
+void
+mh_msgset_parse_string (mu_msgset_t *msgset, mu_mailbox_t mbox, 
+                       const char *string, char *def)
+{
+  struct mu_wordsplit ws;
+  
+  if (mu_wordsplit (string, &ws, MU_WRDSF_DEFFLAGS))
+    {
+      mu_error (_("cannot split line `%s': %s"), string,
+               mu_wordsplit_strerror (&ws));
+      exit (1);
+    }
+  mh_msgset_parse (msgset, mbox, ws.ws_wordc, ws.ws_wordv, def);
+  mu_wordsplit_free (&ws);
 }
 
 
diff --git a/mh/mh_sequence.c b/mh/mh_sequence.c
index a254ed3..509033f 100644
--- a/mh/mh_sequence.c
+++ b/mh/mh_sequence.c
@@ -16,6 +16,7 @@
    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <mh.h>
+#include <mailutils/sys/msgset.h>
 
 static char *
 private_sequence_name (const char *name)
@@ -62,118 +63,124 @@ delete_sequence (mu_mailbox_t mbox, const char *name, int 
private)
   write_sequence (mbox, name, NULL, private);
 }
 
-void
-mh_seq_add (mu_mailbox_t mbox, const char *name, mh_msgset_t *mset, int flags)
+struct format_closure
 {
-  const char *value = mh_seq_read (mbox, name, flags);
-  char *new_value, *p;
-  const char *buf;
-  size_t i, len;
+  mu_stream_t stream;
+  mu_mailbox_t mailbox;
+};
 
-  delete_sequence (mbox, name, !(flags & SEQ_PRIVATE));
+static int
+format_sequence (void *item, void *data)
+{
+  struct mu_msgrange *r = item;
+  struct format_closure *clos = data;
+  int rc;
+  size_t beg, end;
 
-  if (flags & SEQ_ZERO)
-    value = NULL;
-  
-  if (value)
-    len = strlen (value);
+  if (clos->mailbox)
+    {
+      rc = mu_mailbox_translate (clos->mailbox,
+                                MU_MAILBOX_MSGNO_TO_UID,
+                                r->msg_beg, &beg);
+      if (rc)
+       return rc;
+    }
+  else
+    beg = r->msg_beg;
+  if (r->msg_beg == r->msg_end)
+    rc = mu_stream_printf (clos->stream, " %lu", (unsigned long) beg);
   else
-    len = 0;
-  len++;
-  for (i = 0; i < mset->count; i++)
     {
-      buf = mu_umaxtostr (0, mset->list[i]);
-      len += strlen (buf) + 1;
+      if (clos->mailbox)
+       {
+         rc = mu_mailbox_translate (clos->mailbox,
+                                    MU_MAILBOX_MSGNO_TO_UID,
+                                    r->msg_end, &end);
+         if (rc)
+           return rc;
+       }
+      else
+       end = r->msg_end;
+      if (beg + 1 == end)
+       rc = mu_stream_printf (clos->stream, " %lu %lu",
+                              (unsigned long) beg,
+                              (unsigned long) end);
+      else
+       rc = mu_stream_printf (clos->stream, " %lu-%lu",
+                              (unsigned long) beg,
+                              (unsigned long) end);
     }
+  return rc;
+}
 
-  new_value = xmalloc (len + 1);
-  if (value)
-    strcpy (new_value, value);
+static void
+save_sequence (mu_mailbox_t mbox, const char *name, mu_msgset_t mset,
+              int flags)
+{
+  mu_list_t list;
+  
+  mu_msgset_get_list (mset, &list);
+  if (mu_list_is_empty (list))
+    write_sequence (mset->mbox, name, NULL, flags & SEQ_PRIVATE);
   else
-    new_value[0] = 0;
-  p = new_value + strlen (new_value);
-  *p++ = ' ';
-  for (i = 0; i < mset->count; i++)
     {
-      p += sprintf (p, "%s", mu_umaxtostr (0, mset->list[i]));
-      *p++ = ' ';
+      struct format_closure clos;
+      int rc;
+      mu_transport_t trans[2];
+      
+      rc = mu_memory_stream_create (&clos.stream, MU_STREAM_RDWR);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_memory_stream_create", NULL, rc);
+         exit (1);
+       }
+      
+      clos.mailbox = mset->mbox;
+      rc = mu_list_foreach (list, format_sequence, &clos);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_list_foreach", NULL, rc);
+         exit (1);
+       }
+      mu_stream_write (clos.stream, "", 1, NULL);
+      mu_stream_ioctl (clos.stream, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET,
+                      trans);
+      write_sequence (mbox, name, (char*)trans[0], flags & SEQ_PRIVATE);
+      mu_stream_unref (clos.stream);
     }
-  *p = 0;
-  write_sequence (mbox, name, new_value, flags & SEQ_PRIVATE);
-  /* FIXME
-  if (mu_c_strcasecmp (name, "cur") == 0)
-    current_message = strtoul (new_value, NULL, 0);
-  */
-  free (new_value);
 }
 
-static int
-cmp_msgnum (const void *a, const void *b)
+void
+mh_seq_add (mu_mailbox_t mbox, const char *name, mu_msgset_t mset, int flags)
 {
-  const size_t *as = a;
-  const size_t *bs = b;
-
-  if (*as < *bs)
-    return -1;
-  if (*as > *bs)
-    return 1;
-  return 0;
+  const char *value = mh_seq_read (mbox, name, flags);
+  
+  delete_sequence (mbox, name, !(flags & SEQ_PRIVATE));
+  if (value && !(flags & SEQ_ZERO))
+    {
+      mu_msgset_t oldset;
+      mh_msgset_parse_string (&oldset, mbox, value, "cur");
+      mu_msgset_add (oldset, mset);
+      save_sequence (mbox, name, oldset, flags);
+      mu_msgset_free (oldset);
+    }
+  else
+    save_sequence (mbox, name, mset, flags);
 }
 
 int
 mh_seq_delete (mu_mailbox_t mbox, const char *name,
-              mh_msgset_t *mset, int flags)
+              mu_msgset_t mset, int flags)
 {
   const char *value = mh_seq_read (mbox, name, flags);
-  char *new_val;
-  char *p;
-  size_t i, count;
-  struct mu_wordsplit ws;
-  
+  mu_msgset_t oldset;
+
   if (!value)
     return 0;
-
-  if (mu_wordsplit (value, &ws, MU_WRDSF_DEFFLAGS))
-    {
-      mu_error (_("cannot split line `%s': %s"), value,
-               mu_wordsplit_strerror (&ws));
-      return 0;
-    }
-
-  for (i = 0; i < ws.ws_wordc; i++)
-    {
-      char *p;
-      size_t num = strtoul (ws.ws_wordv[i], &p, 10);
-
-      if (*p)
-       continue;
-
-      if (bsearch (&num, mset->list, mset->count, sizeof (mset->list[0]),
-                  cmp_msgnum))
-       {
-         free (ws.ws_wordv[i]);
-         ws.ws_wordv[i] = NULL;
-       }
-    }
-
-  new_val = xstrdup (value);
-  p = new_val;
-  count = 0;
-  for (i = 0; i < ws.ws_wordc; i++)
-    {
-      if (ws.ws_wordv[i])
-       {
-         strcpy (p, ws.ws_wordv[i]);
-         p += strlen (p);
-         *p++ = ' ';
-         count++;
-       }
-    }
-  *p = 0;
-  write_sequence (mbox, name, count > 0 ? new_val : NULL, flags & SEQ_PRIVATE);
-  mu_wordsplit_free (&ws);
-  free (new_val);
-  
+  mh_msgset_parse_string (&oldset, mbox, value, "cur");
+  mu_msgset_sub (oldset, mset);
+  save_sequence (mbox, name, oldset, flags);
+  mu_msgset_free (oldset);
   return 0;
 }
 
diff --git a/mh/mhn.c b/mh/mhn.c
index 57d7418..1b1d902 100644
--- a/mh/mhn.c
+++ b/mh/mhn.c
@@ -158,7 +158,7 @@ static int width = 80;
 static char *charset;  /* Charset for output file names.  NULL means
                          no recoding is necessary. */
 
-static mh_msgset_t msgset;
+static mu_msgset_t msgset;
 static mu_mailbox_t mbox;
 static mu_message_t message;
 static msg_part_t req_part;
@@ -1369,7 +1369,7 @@ list_handler (mu_message_t msg, msg_part_t part, char 
*type, char *encoding,
 }
 
 int
-list_message (mu_message_t msg, size_t num)
+list_message (mu_message_t msg)
 {
   size_t uid;
   msg_part_t part;
@@ -1381,10 +1381,10 @@ list_message (mu_message_t msg, size_t num)
   return 0;
 }
 
-void
-list_iterator (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+int
+list_iterator (size_t num, mu_message_t msg, void *data)
 {
-  list_message (msg, num);
+  return list_message (msg);
 }
 
 int
@@ -1396,9 +1396,9 @@ mhn_list ()
     printf (_(" msg part type/subtype              size  description\n"));
 
   if (message)
-    rc = list_message (message, 0);
+    rc = list_message (message);
   else
-    rc = mh_iterate (mbox, &msgset, list_iterator, NULL);
+    rc = mu_msgset_foreach_message (msgset, list_iterator, NULL);
   return rc;
 }
 
@@ -1609,8 +1609,8 @@ show_message (mu_message_t msg, size_t num, void *data)
   return 0;
 }
 
-void
-show_iterator (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+int
+show_iterator (size_t num, mu_message_t msg, void *data)
 {
   msg_part_t part;
   
@@ -1618,6 +1618,7 @@ show_iterator (mu_mailbox_t mbox, mu_message_t msg, 
size_t num, void *data)
   part = msg_part_create (num);
   show_message (msg, num, data);
   msg_part_destroy (part);
+  return 0;
 }
 
 int
@@ -1630,7 +1631,7 @@ mhn_show ()
   if (message)
     rc = show_message (message, 0, mu_strout);
   else
-    rc = mh_iterate (mbox, &msgset, show_iterator, mu_strout);
+    rc = mu_msgset_foreach_message (msgset, show_iterator, mu_strout);
   mu_stream_flush (mu_strout);
   return rc;
 }
@@ -1855,10 +1856,11 @@ store_message (mu_message_t msg, void *data)
   msg_part_destroy (part);
 }
 
-void
-store_iterator (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+int
+store_iterator (size_t num, mu_message_t msg, void *data)
 {
   store_message (msg, data);
+  return 0;
 }
 
 int
@@ -1876,7 +1878,7 @@ mhn_store ()
       store_message (message, p);
     }
   else
-    rc = mh_iterate (mbox, &msgset, store_iterator, NULL);
+    rc = mu_msgset_foreach_message (msgset, store_iterator, NULL);
   return rc;
 }
 
@@ -2982,7 +2984,7 @@ main (int argc, char **argv)
   else
     {
       mbox = mh_open_folder (mh_current_folder (), MU_STREAM_READ);
-      mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
+      mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
     }
   
   switch (mode)
diff --git a/mh/mhpath.c b/mh/mhpath.c
index 089041f..63cf3f3 100644
--- a/mh/mhpath.c
+++ b/mh/mhpath.c
@@ -50,13 +50,14 @@ opt_handler (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
-void
-mhpath (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+static int
+mhpath (size_t num, mu_message_t msg, void *data)
 {
   size_t uid;
-      
+  
   mh_message_number (msg, &uid);
   printf ("%s/%s\n", (char*) data, mu_umaxtostr (0, uid));
+  return 0;
 }
 
 int
@@ -67,7 +68,7 @@ main (int argc, char **argv)
   mu_url_t url = NULL;
   char *mhdir;
   size_t total;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
   int status;
   const char *current_folder;
   
@@ -125,9 +126,9 @@ main (int argc, char **argv)
   /* Mhpath  expands  and  sorts  the  message  list `msgs' and
      writes the full pathnames of the messages to the  standard
      output separated by newlines. */
-  mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
-  status = mh_iterate (mbox, &msgset, mhpath, mhdir);
+  mh_msgset_parse (&msgset, mbox, argc - index, argv + index, "cur");
+  status = mu_msgset_foreach_message (msgset, mhpath, mhdir);
   mu_mailbox_close (mbox);
   mu_mailbox_destroy (&mbox);
-  return status;
+  return status != 0;
 }
diff --git a/mh/mhseq.c b/mh/mhseq.c
index 1059c4a..8685b2c 100644
--- a/mh/mhseq.c
+++ b/mh/mhseq.c
@@ -63,13 +63,19 @@ opt_handler (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
+static int
+_print_number (size_t n, void *data)
+{
+  printf ("%lu\n", (unsigned long) n);
+  return 0;
+}
+
 int
 main (int argc, char **argv)
 {
   int index;
   mu_mailbox_t mbox;
-  mh_msgset_t msgset;
-  size_t i;
+  mu_msgset_t msgset;
     
   /* Native Language Support */
   MU_APP_INIT_NLS ();
@@ -82,12 +88,11 @@ main (int argc, char **argv)
   argv += index;
   mbox = mh_open_folder (mh_current_folder (), MU_STREAM_READ);
 
-  mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
+  mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
   if (uid_option)
-    mh_msgset_uids (mbox, &msgset);
-
-  for (i = 0; i < msgset.count; i++)
-    printf ("%lu\n", (unsigned long) msgset.list[i]);
+    mu_msgset_foreach_msguid (msgset, _print_number, NULL);
+  else
+    mu_msgset_foreach_msgno (msgset, _print_number, NULL);
   return 0;
 }
 
diff --git a/mh/pick.c b/mh/pick.c
index c819a29..51e3c7d 100644
--- a/mh/pick.c
+++ b/mh/pick.c
@@ -21,9 +21,6 @@
 #include <regex.h>
 #include <pick.h>
 #include <pick-gram.h>
-#define obstack_chunk_alloc malloc
-#define obstack_chunk_free free
-#include <obstack.h>
 
 static char doc[] = N_("GNU MH pick")"\v"
 N_("Compatibility syntax for picking a matching component is:\n\
@@ -146,8 +143,7 @@ static mu_list_t seq_list;  /* List of sequence names to 
operate upon */
 
 static mu_list_t lexlist;   /* List of input tokens */
 
-static struct obstack msgno_stk; /* Stack of selected message numbers */
-static size_t msgno_count;       /* Number of items on the stack */
+static mu_msgset_t picked_message_uids;
 
 static void
 add_sequence (char *name)
@@ -282,34 +278,26 @@ opt_handler (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
-void
-pick_message (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+static int
+pick_message (size_t num, mu_message_t msg, void *data)
 {
   if (pick_eval (msg))
     {
       mh_message_number (msg, &num);
       if (list)
        printf ("%s\n", mu_umaxtostr (0, num));
-      if (seq_list)
-       {
-         obstack_grow (&msgno_stk, &num, sizeof (num));
-         msgno_count++;
-       }
+      if (picked_message_uids)
+       mu_msgset_add_range (picked_message_uids, num, num, MU_MSGSET_UID);
     }
+  return 0;
 }
 
 
-struct pick_closure
-{
-  mu_mailbox_t mbox;
-  mh_msgset_t *msgset;
-};
-
 static int
 action_add (void *item, void *data)
 {
-  struct pick_closure *clos = data;
-  mh_seq_add (clos->mbox, (char *)item, clos->msgset, seq_flags);
+  mu_mailbox_t mbox = data;
+  mh_seq_add (mbox, (char *)item, picked_message_uids, seq_flags);
   return 0;
 }
 
@@ -356,7 +344,7 @@ main (int argc, char **argv)
   int status;
   int index;
   mu_mailbox_t mbox;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
   int interactive = mh_interactive_mode_p ();
 
   MU_APP_INIT_NLS ();
@@ -397,21 +385,13 @@ main (int argc, char **argv)
   argv += index;
 
   if (seq_list)
-    obstack_init (&msgno_stk);
+    mu_msgset_create (&picked_message_uids, NULL, MU_MSGSET_UID);
   
-  mh_msgset_parse (mbox, &msgset, argc, argv, "all");
-  status = mh_iterate (mbox, &msgset, pick_message, NULL);
+  mh_msgset_parse (&msgset, mbox, argc, argv, "all");
+  status = mu_msgset_foreach_message (msgset, pick_message, NULL);
 
-  if (seq_list)
-    {
-      struct pick_closure clos;
-      mh_msgset_t msgset;
-      msgset.count = msgno_count;
-      msgset.list = obstack_finish (&msgno_stk);
-      clos.mbox = mbox;
-      clos.msgset = &msgset;
-      mu_list_foreach (seq_list, action_add, &clos);
-    }
+  if (picked_message_uids)
+    mu_list_foreach (seq_list, action_add, mbox);
 
   mh_global_save_state ();
   mu_mailbox_close (mbox);
diff --git a/mh/refile.c b/mh/refile.c
index ca929e8..343ec91 100644
--- a/mh/refile.c
+++ b/mh/refile.c
@@ -201,8 +201,8 @@ refile (mu_message_t msg)
   enumerate_folders (refile_folder, msg);
 }
 
-void
-refile_iterator (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+int
+refile_iterator (size_t num, mu_message_t msg, void *data)
 {
   enumerate_folders (refile_folder, msg);
   if (!link_flag)
@@ -211,13 +211,14 @@ refile_iterator (mu_mailbox_t mbox, mu_message_t msg, 
size_t num, void *data)
       mu_message_get_attribute (msg, &attr);
       mu_attribute_set_deleted (attr);
     }
+  return 0;
 }
 
 int
 main (int argc, char **argv)
 {
   int index;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
   mu_mailbox_t mbox;
   int status, i, j;
 
@@ -262,9 +263,9 @@ main (int argc, char **argv)
   else
     {
       mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
-      mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
+      mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
 
-      status = mh_iterate (mbox, &msgset, refile_iterator, NULL);
+      status = mu_msgset_foreach_message (msgset, refile_iterator, NULL);
  
       mu_mailbox_expunge (mbox);
       mu_mailbox_close (mbox);
diff --git a/mh/repl.c b/mh/repl.c
index c70081a..9b5157b 100644
--- a/mh/repl.c
+++ b/mh/repl.c
@@ -112,7 +112,7 @@ static int width = 80;
 struct mh_whatnow_env wh_env = { 0 };
 static int initial_edit = 1;
 static const char *whatnowproc;
-static mh_msgset_t msgset;
+static mu_msgset_t msgset;
 static mu_mailbox_t mbox;
 static int build_only = 0; /* --build flag */
 static int query_mode = 0; /* --query flag */
@@ -281,6 +281,7 @@ make_draft (mu_mailbox_t mbox, int disp, struct 
mh_whatnow_env *wh)
   int rc;
   mu_message_t msg;
   struct stat st;
+  size_t msgno;
   
   /* First check if the draft exists */
   if (!build_only && stat (wh->draftfile, &st) == 0)
@@ -309,12 +310,13 @@ make_draft (mu_mailbox_t mbox, int disp, struct 
mh_whatnow_env *wh)
       unlink (wh->draftfile);
       break;  
     }
-  
-  rc = mu_mailbox_get_message (mbox, msgset.list[0], &msg);
+
+  msgno = mh_msgset_first (msgset);
+  rc = mu_mailbox_get_message (mbox, msgno, &msg);
   if (rc)
     {
       mu_error (_("cannot read message %s: %s"),
-               mu_umaxtostr (0, msgset.list[0]),
+               mu_umaxtostr (0, msgno),
                mu_strerror (rc));
       exit (1);
     }
@@ -349,11 +351,11 @@ make_draft (mu_mailbox_t mbox, int disp, struct 
mh_whatnow_env *wh)
          mu_message_get_header (tmp_msg, &hdr);
          text = obstack_finish (&fcc_stack);
          mu_header_set_value (hdr, MU_HEADER_FCC, text, 0);
-         mh_format (&format, tmp_msg, msgset.list[0], width, &buf);
+         mh_format (&format, tmp_msg, msgno, width, &buf);
          mu_message_destroy (&tmp_msg, NULL);
        }
       else
-       mh_format (&format, msg, msgset.list[0], width, &buf);
+       mh_format (&format, msg, msgno, width, &buf);
       
       mu_stream_write (str, buf, strlen (buf), NULL);
 
@@ -409,8 +411,8 @@ main (int argc, char **argv)
     }
 
   mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
-  mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
-  if (msgset.count != 1)
+  mh_msgset_parse (&msgset, mbox, argc - index, argv + index, "cur");
+  if (!mh_msgset_single_message (msgset))
     {
       mu_error (_("only one message at a time!"));
       return 1;
diff --git a/mh/rmm.c b/mh/rmm.c
index 5bc2ab8..592e2a4 100644
--- a/mh/rmm.c
+++ b/mh/rmm.c
@@ -50,12 +50,13 @@ opt_handler (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
-void
-rmm (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+static int
+rmm (size_t num, mu_message_t msg, void *data)
 {
   mu_attribute_t attr;
   mu_message_get_attribute (msg, &attr);
   mu_attribute_set_deleted (attr);
+  return 0;
 }
 
 int
@@ -63,7 +64,7 @@ main (int argc, char **argv)
 {
   int index = 0;
   mu_mailbox_t mbox;
-  mh_msgset_t msgset;
+  mu_msgset_t msgset;
   int status;
 
   /* Native Language Support */
@@ -75,9 +76,9 @@ main (int argc, char **argv)
 
   mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
 
-  mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
+  mh_msgset_parse (&msgset, mbox, argc - index, argv + index, "cur");
 
-  status = mh_iterate (mbox, &msgset, rmm, NULL);
+  status = mu_msgset_foreach_message (msgset, rmm, NULL);
 
   mu_mailbox_expunge (mbox);
   mu_mailbox_close (mbox);
diff --git a/mh/scan.c b/mh/scan.c
index bee454d..c0b228e 100644
--- a/mh/scan.c
+++ b/mh/scan.c
@@ -75,9 +75,9 @@ static int header;
 
 static mh_format_t format;
 
-static mh_msgset_t msgset;
+static mu_msgset_t msgset;
 
-void list_message (mu_mailbox_t mbox, mu_message_t msg, size_t num, void 
*data);
+static int list_message (size_t num, mu_message_t msg, void *data);
 void print_header (mu_mailbox_t mbox);
 void clear_screen (void);
 
@@ -153,7 +153,7 @@ action (mu_observer_t o, size_t type, void *data, void 
*action_data)
       counter++;
       mu_mailbox_get_message (mbox, counter, &msg);
       mh_message_number (msg, &num);
-      list_message (mbox, msg, num, NULL);
+      list_message (num, msg, NULL);
     }
   return 0;
 }
@@ -201,13 +201,11 @@ main (int argc, char **argv)
   else
     {
       mu_mailbox_messages_count (mbox, &total);
-      mh_msgset_parse (mbox, &msgset, argc, argv, "all");
-
-      if (reverse)
-       mh_msgset_reverse (&msgset);
+      mh_msgset_parse (&msgset, mbox, argc, argv, "all");
 
       print_header (mbox);
-      status = mh_iterate (mbox, &msgset, list_message, NULL);
+      status = mu_msgset_foreach_dir_message (msgset, reverse,
+                                             list_message, NULL);
     }
 
   if (total == 0)
@@ -282,8 +280,8 @@ clear_screen ()
     }
 }
 
-void
-list_message (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+static int
+list_message (size_t num, mu_message_t msg, void *data)
 {
   char *buffer;
   int len;
@@ -294,4 +292,5 @@ list_message (mu_mailbox_t mbox, mu_message_t msg, size_t 
num, void *data)
   if (len > 0 && buffer[len-1] != '\n')
     printf("\n");
   free (buffer);
+  return 0;
 }
diff --git a/mh/send.c b/mh/send.c
index 479e9cc..4318520 100644
--- a/mh/send.c
+++ b/mh/send.c
@@ -737,6 +737,27 @@ _action_send (void *item, void *data)
   return 0;
 }
 
+static int
+_add_to_mesg_list (size_t num, mu_message_t msg, void *data)
+{
+  char const *path = data;
+  struct list_elt *elt;
+  size_t uid;
+  int rc;
+  
+  elt = xmalloc (sizeof *elt);
+  elt->msg = msg;
+  mu_message_get_uid (msg, &uid);
+  elt->file_name = mu_make_file_name (path, mu_umaxtostr (0, uid));
+  rc = mu_list_append (mesg_list, elt);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", NULL, rc);
+      exit (1);
+    }
+  return 0;
+}
+
 int
 main (int argc, char **argv)
 {
@@ -758,13 +779,12 @@ main (int argc, char **argv)
 
   if (draftfolder)
     {
-      mh_msgset_t msgset;
+      mu_msgset_t msgset;
       mu_url_t url;
       const char *path;
-      size_t i;
       
       mbox = mh_open_folder (draftfolder, MU_STREAM_RDWR|MU_STREAM_CREAT);
-      mh_msgset_parse (mbox, &msgset, argc, argv, draftmessage);
+      mh_msgset_parse (&msgset, mbox, argc, argv, draftmessage);
       mu_mailbox_get_url (mbox, &url);
       mu_url_sget_path (url, &path);
       if ((rc = mu_list_create (&mesg_list)))
@@ -772,25 +792,9 @@ main (int argc, char **argv)
          mu_error (_("cannot create message list: %s"), mu_strerror (rc));
          exit (1);
        }
-      for (i = 0; i < msgset.count; i++)
-       {
-         struct list_elt *elt;
-         size_t uid;
-         
-         elt = xmalloc (sizeof *elt);
-         mu_mailbox_get_message (mbox, msgset.list[i], &elt->msg);
-         mu_message_get_uid (elt->msg, &uid);
-         elt->file_name =
-           mu_make_file_name (path, mu_umaxtostr (0, uid));
-         rc = mu_list_append (mesg_list, elt);
-         if (rc)
-           {
-             mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", NULL, rc);
-             exit (1);
-           }
-       }
+      mu_msgset_foreach_message (msgset, _add_to_mesg_list, (void*)path);
       
-      mh_msgset_free (&msgset);
+      mu_msgset_free (msgset);
     }
   else
     {
diff --git a/mh/sortm.c b/mh/sortm.c
index 5778793..b0de66b 100644
--- a/mh/sortm.c
+++ b/mh/sortm.c
@@ -92,7 +92,10 @@ static int limit;
 static int verbose;
 static mu_mailbox_t mbox;
 static const char *mbox_path;
-static mh_msgset_t msgset;
+
+static size_t *msgarr;
+static size_t msgcount;
+
 static size_t current_num;
 
 #define ACTION_REORDER   0
@@ -416,17 +419,17 @@ shell_sort ()
     int h, s, i, j;
     size_t hold;
 
-    for (h = startdst (msgset.count, &s); s > 0; s--, h = prevdst (h))
+    for (h = startdst (msgcount, &s); s > 0; s--, h = prevdst (h))
       {
        if (verbose > 1)
          fprintf (stderr, _("distance %d\n"), h);
-        for (j = h; j < msgset.count; j++)
+        for (j = h; j < msgcount; j++)
          {
-            hold = msgset.list[j];
+            hold = msgarr[j];
             for (i = j - h;
-                i >= 0 && comp0 (hold, msgset.list[i]) < 0; i -= h)
-             msgset.list[i + h] = msgset.list[i];
-           msgset.list[i + h] = hold;
+                i >= 0 && comp0 (hold, msgarr[i]) < 0; i -= h)
+             msgarr[i + h] = msgarr[i];
+           msgarr[i + h] = hold;
          }
       }
 }
@@ -467,12 +470,12 @@ transpose(size_t i, size_t n)
 {
   size_t j;
 
-  for (j = i+1; j < msgset.count; j++)
-    if (msgset.list[j] == n)
+  for (j = i+1; j < msgcount; j++)
+    if (msgarr[j] == n)
       {
-       size_t t = msgset.list[i];
-       msgset.list[i] = msgset.list[j];
-       msgset.list[j] = t;
+       size_t t = msgarr[i];
+       msgarr[i] = msgarr[j];
+       msgarr[j] = t;
        break;
       }
 }
@@ -489,26 +492,25 @@ void
 sort ()
 {
   size_t *oldlist, i;
-  oldlist = xmalloc (msgset.count * sizeof (*oldlist));
-  memcpy (oldlist, msgset.list, msgset.count * sizeof (*oldlist));
+  oldlist = xmalloc (msgcount * sizeof (*oldlist));
+  memcpy (oldlist, msgarr, msgcount * sizeof (*oldlist));
 
   switch (algorithm)
     {
     case ARG_QUICKSORT:
-      qsort(msgset.list, msgset.count, sizeof (msgset.list[0]),
-           comp);
+      qsort (msgarr, msgcount, sizeof (msgarr[0]), comp);
       break;
 
     case ARG_SHELL:
-      shell_sort();
+      shell_sort ();
       break;
     }
 
   switch (action)
     {
     case ACTION_LIST:
-      for (i = 0; i < msgset.count; i++)
-       list_message (msgset.list[i]);
+      for (i = 0; i < msgcount; i++)
+       list_message (msgarr[i]);
       break;
 
     default:
@@ -519,16 +521,16 @@ sort ()
       
       if (verbose)
        fprintf (stderr, _("Transpositions:\n"));
-      for (i = 0, got_signal = 0; !got_signal && i < msgset.count; i++)
+      for (i = 0, got_signal = 0; !got_signal && i < msgcount; i++)
        {
-         if (msgset.list[i] != oldlist[i])
+         if (msgarr[i] != oldlist[i])
            {
              size_t old_num, new_num;
              mu_message_t msg;
 
              mu_mailbox_get_message (mbox, oldlist[i], &msg);
              mh_message_number (msg, &old_num);
-             mu_mailbox_get_message (mbox, msgset.list[i], &msg);
+             mu_mailbox_get_message (mbox, msgarr[i], &msg);
              mh_message_number (msg, &new_num);
              transpose (i, oldlist[i]);
              if (verbose)
@@ -563,6 +565,38 @@ sort ()
       mh_mailbox_set_cur (mbox, current_num);
     }
 }
+
+static int
+_add_msgno (size_t n, void *data)
+{
+  size_t *pidx = data;
+  msgarr[*pidx] = n;
+  ++*pidx;
+  return 0;
+}
+
+static void
+fill_msgarr (mu_msgset_t msgset)
+{
+  size_t i;
+  int rc;
+  
+  rc = mu_msgset_count (msgset, &msgcount);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_count", NULL, rc);
+      exit (1);
+    }
+      
+  msgarr = xcalloc (msgcount, sizeof (msgarr[0]));
+  i = 0;
+  rc = mu_msgset_foreach_msgno (msgset, _add_msgno, &i);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_foreach_msgno", NULL, rc);
+      exit (1);
+    }
+}
 
 
 /* Main */
@@ -572,6 +606,7 @@ main (int argc, char **argv)
 {
   int index;
   mu_url_t url;
+  mu_msgset_t msgset;
   
   MU_APP_INIT_NLS ();
   mh_argp_init ();
@@ -597,7 +632,9 @@ main (int argc, char **argv)
 
   mh_mailbox_get_cur (mbox, &current_num);
 
-  mh_msgset_parse (mbox, &msgset, argc, argv, "all");
+  mh_msgset_parse (&msgset, mbox, argc, argv, "all");
+  fill_msgarr (msgset);
+  mu_msgset_free (msgset);
   sort ();
   mh_global_save_state ();
   mu_mailbox_destroy (&mbox);
diff --git a/mh/tests/mark.at b/mh/tests/mark.at
index 8072dc7..363fafc 100644
--- a/mh/tests/mark.at
+++ b/mh/tests/mark.at
@@ -25,7 +25,7 @@ mark -sequence andro -add 3-5
 sed -n '/^andro:/{s/  */ /g;s/ $//;p;}' Mail/inbox/.mh_sequences
 ],
 [0],
-[andro: 2 3 4 5
+[andro: 2-5
 ])
 
 MH_CHECK([mark -add -zero],[mark01 mark-add-zero],[
@@ -48,7 +48,7 @@ mark -nopublic -sequence andro -add 1 2 3
 sed -n '/^atr-andro/{s/  */ /g;s/ $//;s/^[[^:]]*:/atr-andro:/;p;}' Mail/context
 ],
 [0],
-[atr-andro: 1 2 3
+[atr-andro: 1-3
 ])
 
 MH_CHECK([mark -del],[mark03 mark-del],[
@@ -67,7 +67,7 @@ MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
 echo 'Current-Folder: inbox' > Mail/context
 inbox=`pwd`/Mail/inbox
 cat > Mail/context <<EOT
-atr-andro-$inbox: 2 3 4 5
+atr-andro-$inbox: 2-5
 EOT
 mark -nopublic -sequence andro -del 3
 sed -n '/^atr-andro/{s/  */ /g;s/ $//;s/^[[^:]]*:/atr-andro:/;p;}' Mail/context
diff --git a/mh/whatnowenv.c b/mh/whatnowenv.c
index 8a69d58..78a6994 100644
--- a/mh/whatnowenv.c
+++ b/mh/whatnowenv.c
@@ -17,6 +17,13 @@
 
 #include <mh.h>
 
+static int
+_add_to_list (size_t num, mu_message_t msg, void *data)
+{
+  mu_list_t list = data;
+  return mu_list_append (list, msg);
+}
+
 void
 mh_whatnow_env_from_environ (struct mh_whatnow_env *wh)
 {
@@ -39,38 +46,15 @@ mh_whatnow_env_from_environ (struct mh_whatnow_env *wh)
            wh->anno_field = NULL;
          else
            {
-             size_t i;
-             struct mu_wordsplit ws;
-             mh_msgset_t msgset;
+             mu_msgset_t msgset;
              mu_mailbox_t mbox = mh_open_folder (folder, MU_STREAM_RDWR);
              
-             if (mu_wordsplit (p, &ws,
-                               MU_WRDSF_DEFFLAGS & ~MU_WRDSF_CESCAPES))
-               {
-                 mu_error (_("cannot parse mhmessages (%s): %s"), p,
-                           mu_wordsplit_strerror (&ws));
-                 exit (1);
-               }
-             mh_msgset_parse (mbox, &msgset, ws.ws_wordc, ws.ws_wordv, "cur");
-             mu_wordsplit_free (&ws);
+             mh_msgset_parse_string (&msgset, mbox, p, "cur");
 
              wh->mbox = mbox;
              mu_list_create (&wh->anno_list);
-             for (i = 0; i < msgset.count; i++)
-               {
-                 mu_message_t msg;
-                 int rc = mu_mailbox_get_message (mbox, msgset.list[i], &msg);
-                 if (rc)
-                   {
-                     mu_error (_("cannot get message %lu from %s: %s"),
-                               (unsigned long) msgset.list[i],
-                               folder,
-                               mu_strerror (rc));
-                     continue;
-                   }
-                 mu_list_append (wh->anno_list, msg);
-               }
-             mh_msgset_free (&msgset);
+             mu_msgset_foreach_message (msgset, _add_to_list, wh->anno_list);
+             mu_msgset_free (msgset);
              /* FIXME:
                 wh->anno_inplace = getenv ("mhinplace");
              */
diff --git a/mu/imap.c b/mu/imap.c
index 8e3e2bf..d8628c8 100644
--- a/mu/imap.c
+++ b/mu/imap.c
@@ -118,13 +118,13 @@ parse_msgset (const char *arg)
   mu_msgset_t msgset;
   char *p;
   
-  status = mu_msgset_create (&msgset, NULL, 0);
+  status = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
   if (status)
     {
       mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_create", NULL, status);
       return NULL;
     }
-  status = mu_msgset_parse_imap (msgset, arg, &p);
+  status = mu_msgset_parse_imap (msgset, MU_MSGSET_NUM, arg, &p);
   if (status)
     {
       mu_error (_("failed to parse message set near \"%s\": %s"),
diff --git a/testsuite/msgset.c b/testsuite/msgset.c
index ae2a099..8ddc2b1 100644
--- a/testsuite/msgset.c
+++ b/testsuite/msgset.c
@@ -19,7 +19,7 @@
 #include <mailutils/mailutils.h>
 
 static void
-parse_msgset (char *arg, struct mu_msgrange *range)
+parse_msgrange (char *arg, struct mu_msgrange *range)
 {
   size_t msgnum;
   char *p;
@@ -52,14 +52,36 @@ parse_msgset (char *arg, struct mu_msgrange *range)
   range->msg_end = msgnum;
 }
 
+mu_msgset_t
+parse_msgset (const char *arg, mu_mailbox_t mbox,
+             int create_mode, int parse_mode)
+{
+  int rc;
+  mu_msgset_t msgset;
+  char *end;
+  
+  MU_ASSERT (mu_msgset_create (&msgset, mbox, create_mode));
+  if (arg)
+    {
+      rc = mu_msgset_parse_imap (msgset, parse_mode, arg, &end);
+      if (rc)
+        {
+          mu_error ("mu_msgset_parse_imap: %s near %s",
+                   mu_strerror (rc), end);
+          exit (1);
+        }
+    }
+  return msgset;
+}
+
 int
 main (int argc, char **argv)
 {
   int i;
   char *msgset_string = NULL;
   mu_msgset_t msgset;
-  int rc;
-  int flags = 0;
+  int create_mode = MU_MSGSET_NUM;
+  int parse_mode = MU_MSGSET_NUM;
   mu_mailbox_t mbox = NULL;
   
   mu_set_program_name (argv[0]);
@@ -70,14 +92,23 @@ main (int argc, char **argv)
 
       if (strcmp (arg, "-h") == 0 || strcmp (arg, "-help") == 0)
        {
-         mu_printf ("usage: %s [-msgset=SET] [-add X[:Y]] [-del X:[Y]]...\n",
+         mu_printf ("usage: %s [-msgset[uid]=SET] [-uid] [-add[uid]=X[:Y]] 
[-del[uid]=X[:Y]] "
+                    "[-addset[uid]=SET] [-delset[uid]=SET] ...\n",
                     mu_program_name);
          return 0;
        }
       else if (strncmp (arg, "-msgset=", 8) == 0)
-       msgset_string = arg + 8;
+       {
+         parse_mode = MU_MSGSET_NUM;
+         msgset_string = arg + 8;
+       }
+      else if (strncmp (arg, "-msgsetuid=", 11) == 0)
+       {
+         parse_mode = MU_MSGSET_UID;
+         msgset_string = arg + 11;
+       }      
       else if (strcmp (arg, "-uid") == 0)
-       flags |= MU_MSGSET_UID;
+       create_mode = MU_MSGSET_UID;
       else if (strncmp (arg, "-mailbox=", 9) == 0)
        {
          MU_ASSERT (mu_mailbox_create (&mbox, arg + 9));
@@ -87,18 +118,7 @@ main (int argc, char **argv)
        break;
     }
 
-  MU_ASSERT (mu_msgset_create (&msgset, mbox, flags));
-  if (msgset_string)
-    {
-      char *end;
-      rc = mu_msgset_parse_imap (msgset, msgset_string, &end);
-      if (rc)
-       {
-         mu_error ("mu_msgset_parse_imap: %s near %s",
-                   mu_strerror (rc), end);
-         return 1;
-       }
-    }
+  msgset = parse_msgset (msgset_string, mbox, create_mode, parse_mode);
   
   for (; i < argc; i++)
     {
@@ -107,15 +127,102 @@ main (int argc, char **argv)
       
       if (strncmp (arg, "-add=", 5) == 0)
        {
-         parse_msgset (arg + 5, &range);
-         MU_ASSERT (mu_msgset_add_range (msgset, range.msg_beg,
-                                         range.msg_end));
+         parse_msgrange (arg + 5, &range);
+         MU_ASSERT (mu_msgset_add_range (msgset,
+                                         range.msg_beg, range.msg_end,
+                                         MU_MSGSET_NUM));
        }
       else if (strncmp (arg, "-sub=", 5) == 0)
        {
-         parse_msgset (arg + 5, &range);
-         MU_ASSERT (mu_msgset_sub_range (msgset, range.msg_beg,
-                                         range.msg_end));
+         parse_msgrange (arg + 5, &range);
+         MU_ASSERT (mu_msgset_sub_range (msgset,
+                                         range.msg_beg, range.msg_end,
+                                         MU_MSGSET_NUM));
+       }
+      else if (strncmp (arg, "-adduid=", 8) == 0)
+       {
+         parse_msgrange (arg + 8, &range);
+         MU_ASSERT (mu_msgset_add_range (msgset,
+                                         range.msg_beg, range.msg_end,
+                                         MU_MSGSET_UID));
+       }
+      else if (strncmp (arg, "-subuid=", 8) == 0)
+       {
+         parse_msgrange (arg + 8, &range);
+         MU_ASSERT (mu_msgset_sub_range (msgset,
+                                         range.msg_beg, range.msg_end,
+                                         MU_MSGSET_UID));
+       }
+      else if (strncmp (arg, "-addset", 7) == 0)
+       {
+         mu_msgset_t tset;
+         int m;
+
+         arg += 7;
+         if (strncmp (arg, "uid", 3) == 0)
+           {
+             m = MU_MSGSET_UID;
+             arg += 3;
+           }
+         else
+           m = MU_MSGSET_NUM;
+         if (*arg == '=')
+           arg++;
+         else
+           {
+             mu_error ("unknown option %s", argv[i]);
+             return 1;
+           }
+         
+         tset = parse_msgset (arg, mbox, m, m);
+         if (!msgset)
+           msgset = tset;
+         else
+           {
+             MU_ASSERT (mu_msgset_add (msgset, tset));
+             mu_msgset_free (tset);
+           }
+       }
+      else if (strncmp (arg, "-subset=", 8) == 0)
+       {
+         mu_msgset_t tset;
+         int m;
+
+         arg += 7;
+         if (strncmp (arg, "uid", 3) == 0)
+           {
+             m = MU_MSGSET_UID;
+             arg += 3;
+           }
+         else
+           m = MU_MSGSET_NUM;
+         if (*arg == '=')
+           arg++;
+         else
+           {
+             mu_error ("unknown option %s", argv[i]);
+             return 1;
+           }
+         
+         tset = parse_msgset (arg, mbox, m, m);
+         
+         if (!msgset)
+           {
+             mu_error ("no initial message set");
+             exit (1);
+           }
+         else
+           {
+             MU_ASSERT (mu_msgset_sub (msgset, tset));
+             mu_msgset_free (tset);
+           }
+       }
+      else if (strcmp (arg, "-neg") == 0)
+       {
+         mu_msgset_t negated_set;
+         MU_ASSERT (mu_msgset_negate (msgset, &negated_set));
+         mu_msgset_free (msgset);
+         msgset = negated_set;
        }
       else
        {


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]