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-209-ge34d8c1


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-209-ge34d8c1
Date: Mon, 22 Nov 2010 15:15:31 +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=e34d8c168f9031dbfc2441006e0eb24182ef4389

The branch, master has been updated
       via  e34d8c168f9031dbfc2441006e0eb24182ef4389 (commit)
      from  e6927c46013d391242d76b63cdb7b044d9ba8065 (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 e34d8c168f9031dbfc2441006e0eb24182ef4389
Author: Sergey Poznyakoff <address@hidden>
Date:   Mon Nov 22 16:49:51 2010 +0200

    mh: fix msgset parser and some more comp compatibility issues; provide 
testsuite for comp.
    * mh/Makefile.am (bin_PROGRAMS): Add mhseq.
    * mh/comp.c (main): Rewrite to fix compatibility issues.
    * mh/mh.h (MH_MSGSET_UID): New define.
    (mh_msgset_t) <flags,size>: New members.
    * mh/mh_init.c (mh_draft_message): Bugfix: convert msgset to UIDs.
    * mh/mh_msgset.c: Rewrite from scratch.
    
    * mh/tests/comp.at: New file.
    * mh/tests/mhseq.at: New file.
    * mh/tests/Makefile.am (TESTSUITE_AT): Add comp.at, mhseq.at.
    * mh/tests/testsuite.at: Include comp.at and mhseq.at.
    
    * libmailutils/property/mhprop.c (_mh_prop_read_stream): Minor fix.
    Do remove empty lines.
    * mh/mh_whatnow.c (_whatnow): Detect EOF.
    (call_send): Quit after successful send.

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

Summary of changes:
 libmailutils/property/mhprop.c |    2 +-
 mh/.gitignore                  |    1 +
 mh/Makefile.am                 |    1 +
 mh/comp.c                      |   95 +++--
 mh/mh.h                        |   10 +-
 mh/mh_init.c                   |   12 +-
 mh/mh_msgset.c                 | 1001 ++++++++++++++++++++++------------------
 mh/mh_whatnow.c                |   12 +-
 mh/{rmm.c => mhseq.c}          |   60 ++--
 mh/tests/Makefile.am           |    2 +
 mh/tests/comp.at               |  148 ++++++
 mh/tests/mhed                  |    8 +
 mh/tests/mhseq.at              |  386 ++++++++++++++++
 mh/tests/testsuite.at          |    2 +
 14 files changed, 1204 insertions(+), 536 deletions(-)
 copy mh/{rmm.c => mhseq.c} (66%)
 create mode 100644 mh/tests/comp.at
 create mode 100755 mh/tests/mhed
 create mode 100644 mh/tests/mhseq.at

diff --git a/libmailutils/property/mhprop.c b/libmailutils/property/mhprop.c
index 9aedd22..f263d00 100644
--- a/libmailutils/property/mhprop.c
+++ b/libmailutils/property/mhprop.c
@@ -113,7 +113,7 @@ _mh_prop_read_stream (mu_header_t *phdr, mu_stream_t stream)
   argv[1] = "#";
   argv[2] = "-r";
   argv[3] = NULL;
-  rc = mu_filter_create_args (&flt, stream, argv[0], 2, argv,
+  rc = mu_filter_create_args (&flt, stream, argv[0], 3, argv,
                              MU_FILTER_DECODE, MU_STREAM_READ);
   if (rc)
     {
diff --git a/mh/.gitignore b/mh/.gitignore
index e1a9c51..fecc9d2 100644
--- a/mh/.gitignore
+++ b/mh/.gitignore
@@ -23,6 +23,7 @@ mh_alias_lex.c
 mh_fmtgram.c
 mhl
 mhn
+mhseq
 mhparam
 mhpath
 pick
diff --git a/mh/Makefile.am b/mh/Makefile.am
index 01dbdd0..a78eb65 100644
--- a/mh/Makefile.am
+++ b/mh/Makefile.am
@@ -33,6 +33,7 @@ bin_PROGRAMS = \
  mhn\
  mhparam\
  mhpath\
+ mhseq\
  pick\
  prompter\
  refile\
diff --git a/mh/comp.c b/mh/comp.c
index b882326..964baf4 100644
--- a/mh/comp.c
+++ b/mh/comp.c
@@ -80,6 +80,7 @@ static int build_only = 0; /* --build flag */
 static int use_draft = 0;  /* --use flag */
 static char *draftmessage = "new";
 static const char *draftfolder = NULL;
+static int folder_set; /* Folder is set on the command line */
 
 static error_t
 opt_handler (int key, char *arg, struct argp_state *state)
@@ -87,8 +88,7 @@ opt_handler (int key, char *arg, struct argp_state *state)
   switch (key)
     {
     case ARGP_KEY_INIT:
-      draftfolder = mh_global_profile_get ("Draft-Folder",
-                                          mu_folder_directory ());
+      draftfolder = mh_global_profile_get ("Draft-Folder", NULL);
       whatnowproc = mh_global_profile_get ("whatnowproc", NULL);
       break;
 
@@ -106,6 +106,7 @@ opt_handler (int key, char *arg, struct argp_state *state)
       
     case ARG_FOLDER: 
       mh_set_current_folder (arg);
+      folder_set = 1;
       break;
 
     case ARG_FORM:
@@ -126,7 +127,7 @@ opt_handler (int key, char *arg, struct argp_state *state)
       break;
       
     case ARG_FILE:
-      wh_env.draftfile = mh_expand_name (NULL, arg, 0);
+      wh_env.file = mh_expand_name (NULL, arg, 0);
       break;
        
     case ARG_NODRAFTFOLDER:
@@ -197,7 +198,7 @@ main (int argc, char **argv)
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
   
-  if (wh_env.draftfile)
+  if (wh_env.file)
     {
       if (build_only)
        {
@@ -205,68 +206,90 @@ main (int argc, char **argv)
          exit (1);
        }
     }
+  else if (folder_set)
+    {
+      wh_env.file = mh_expand_name (NULL, "draft", 0);
+    }
   else
     {
       if (build_only || !draftfolder)
-       wh_env.file = mh_expand_name (NULL, "draft", 0);
+       {
+         switch (argc - index)
+           {
+           case 0:
+             wh_env.file = mh_expand_name (NULL, "draft", 0);
+             break;
+
+           case 1:
+             wh_env.file = mh_expand_name (NULL, argv[index], 0);
+             break;
+             
+           default:
+             mu_error (_("only one message at a time!"));
+             return 1;
+           }
+       }
       else if (draftfolder)
        {
          /* Comp accepts a `file', and it will, if given
             `-draftfolder +folder'  treat this arguments  as `msg'. */
-         if (index < argc)
+         if (use_draft || index < argc)
            {
              mh_msgset_t msgset;
              mu_mailbox_t mbox;
              
              mbox = mh_open_folder (draftfolder, 1);
-             mh_msgset_parse (mbox, &msgset, argc - index, argv + index,
-                              "new");
+             mh_msgset_parse (mbox, &msgset, 
+                              argc - index, argv + index,
+                              use_draft ? "cur" : "new");
              mu_mailbox_destroy (&mbox);
              if (msgset.count != 1)
                {
                  mu_error (_("only one message at a time!"));
                  return 1;
                }
+              mh_msgset_uids (mbox, &msgset);  
              draftmessage = mu_umaxtostr (0, msgset.list[0]);
              mh_msgset_free (&msgset);
-             index = argc;
            }
          if (mh_draft_message (draftfolder, draftmessage,
                                &wh_env.file))
            return 1;
        }
-      wh_env.draftfile = wh_env.file;
     }
-  
-  switch (check_draft_disposition (&wh_env, use_draft))
-    {
-    case DISP_QUIT:
-      exit (0);
+  wh_env.draftfile = wh_env.file;
 
-    case DISP_USE:
-      break;
-         
-    case DISP_REPLACE:
-      unlink (wh_env.draftfile);
-  
-      if (index < argc)
+  if (folder_set && index < argc)
+    {
+      mh_msgset_t msgset;
+      mu_mailbox_t mbox;
+      
+      mbox = mh_open_folder (mh_current_folder (), 0);
+      mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
+      if (msgset.count != 1)
        {
-         mh_msgset_t msgset;
-         mu_mailbox_t mbox;
+         mu_error (_("only one message at a time!"));
+         return 1;
+       }
+      unlink (wh_env.file);
+      copy_message (mbox, msgset.list[0], wh_env.file);
+      mu_mailbox_destroy (&mbox);
+      mh_msgset_free (&msgset);
+    }
+  else
+    {
+      switch (check_draft_disposition (&wh_env, use_draft))
+       {
+       case DISP_QUIT:
+         exit (0);
+
+       case DISP_USE:
+         break;
          
-         mbox = mh_open_folder (mh_current_folder (), 0);
-         mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
-         if (msgset.count != 1)
-           {
-             mu_error (_("only one message at a time!"));
-             return 1;
-           }
-         copy_message (mbox, msgset.list[0], wh_env.file);
-         mu_mailbox_destroy (&mbox);
-         mh_msgset_free (&msgset);
+       case DISP_REPLACE:
+         unlink (wh_env.draftfile);
+         mh_comp_draft (formfile, "components", wh_env.file);
        }
-      else
-       mh_comp_draft (formfile, "components", wh_env.file);
     }
   
   /* Exit immediately if --build is given */
diff --git a/mh/mh.h b/mh/mh.h
index 8e658d7..a4c66cf 100644
--- a/mh/mh.h
+++ b/mh/mh.h
@@ -195,10 +195,14 @@ typedef struct
   mu_header_t header;
 } mh_context_t;
 
+#define MH_MSGSET_UID   0x01
+
 typedef struct
 {
-  size_t count;
+  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,
@@ -300,8 +304,8 @@ int mh_message_number (mu_message_t msg, size_t *pnum);
 
 mu_mailbox_t mh_open_folder (const char *folder, int create);
 
-int mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
-                    int argc, char **argv, char *def);
+void mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
+                     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);
diff --git a/mh/mh_init.c b/mh/mh_init.c
index 7adc649..bebfed9 100644
--- a/mh/mh_init.c
+++ b/mh/mh_init.c
@@ -998,14 +998,14 @@ mh_draft_message (const char *name, const char *msgspec, 
char **pname)
       
       argv[0] = (char*) msgspec;
       argv[1] = NULL;
-      rc = mh_msgset_parse (mbox, &msgset, 1, argv, "cur");
-      if (rc)
-       mu_error (_("invalid message number: %s"), msgspec);
-      else if (msgset.count > 1)
+      mh_msgset_parse (mbox, &msgset, 1, argv, "cur");
+      if (msgset.count > 1)
        mu_error (_("only one message at a time!"));
       else
-       uid = msgset.list[0];
-
+       {
+         mh_msgset_uids (mbox, &msgset);
+         uid = msgset.list[0];
+       }
       mh_msgset_free (&msgset);
     }
   
diff --git a/mh/mh_msgset.c b/mh/mh_msgset.c
index 6e058a2..fd0287f 100644
--- a/mh/mh_msgset.c
+++ b/mh/mh_msgset.c
@@ -19,473 +19,184 @@
 
 #include <mh.h>
 
-/* Expand a message set (msgcnt;msglist) to accomodate `inc' more
-   elements */
-static void
-_expand (size_t *msgcnt, size_t **msglist, size_t inc)
+int
+mh_uid_to_msgno (mu_mailbox_t mbox, size_t uid, size_t *msgno)
 {
-  if (!inc)
-    return;
-
-  *msgcnt += inc;
-  *msglist = realloc (*msglist, (*msgcnt)*sizeof(**msglist));
-  if (!*msglist)
-    mh_err_memory (1);
+  size_t num = mh_get_message (mbox, uid, NULL);
+  if (num == 0)
+    return MU_ERR_NOENT;
+  *msgno = num;
+  return 0;
 }
 
-/* Fatal error handler */ 
-static void
-msgset_abort (const char *arg)
+int
+mh_msgno_to_uid (mu_mailbox_t mbox, size_t msgno, size_t *uid)
 {
-  mu_error (_("bad message list `%s'"), arg);
-  exit (1);
+  mu_message_t msg;
+  int rc = mu_mailbox_get_message (mbox, msgno, &msg);
+  if (rc)
+    return rc;
+  return mu_message_get_uid (msg, uid);
 }
 
-/* Handlers for expansion of the reserved message names */
-
-static int
-msgset_first (mu_mailbox_t mbox, size_t *pnum)
+
+void
+mh_msgset_init (mh_msgset_t *msgset)
 {
-  *pnum = 1;
-  return 0;
+  memset (msgset, 0, sizeof (*msgset));
 }
 
-static int
-msgset_last (mu_mailbox_t mbox, size_t *pnum)
+void
+mh_msgset_expand (mh_msgset_t *msgset, size_t count)
 {
-  int rc;
-  size_t count = 0;
+  size_t rest = msgset->size - msgset->count;
 
-  rc = mu_mailbox_messages_count (mbox, &count);
-  if (rc)
+  if (rest < count)
     {
-      mu_error (_("cannot get last message: %s"), mu_strerror (rc));
-      exit (1);
+      msgset->size += count;
+      msgset->list = xrealloc (msgset->list,
+                              msgset->size * sizeof (msgset->list[0]));
     }
-  *pnum = count;
-  return 0;
 }
 
-static int
-msgset_cur (mu_mailbox_t mbox, size_t *pnum)
+void
+mh_msgset_add (mh_msgset_t *msgset, size_t n)
 {
-  size_t i, count = 0;
-  static int cached_n = 0;
-  size_t cur;
-
-  mh_mailbox_get_cur (mbox, &cur);
-  
-  if (cached_n)
-    {
-      *pnum = cached_n;
-      return 0;
-    }
-
-  mu_mailbox_messages_count (mbox, &count);
-  for (i = 1; i <= count; i++)
-    {
-      mu_message_t msg = NULL;
-      size_t uid = 0;
-      
-      mu_mailbox_get_message (mbox, i, &msg);
-      mh_message_number (msg, &uid);
-      if (uid == cur)
-       {
-         *pnum = cached_n = i;
-         return 0;
-       }
-    }
-  mu_error (_("no cur message"));
-  exit (1);
+  mh_msgset_expand (msgset, 1);
+  msgset->list[msgset->count++] = n;
 }
 
 static int
-msgset_prev (mu_mailbox_t mbox, size_t *pnum)
+comp_mesg (const void *a, const void *b)
 {
-  size_t cur_n = 0;
-  msgset_cur (mbox, &cur_n);
-  if (cur_n < 1)
-    {
-      mu_error (_("no prev message"));
-      exit (1);
-    }
-  *pnum = cur_n - 1;
+  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;
 }
 
-static int
-msgset_next (mu_mailbox_t mbox, size_t *pnum)
+void
+mh_msgset_optimize (mh_msgset_t *msgset)
 {
-  size_t cur_n = 0, total = 0;
-  msgset_cur (mbox, &cur_n);
-  mu_mailbox_messages_count (mbox, &total);
-  if (cur_n + 1 > total)
-    {
-      mu_error (_("no next message"));
-      exit (1);
-    }
-  *pnum = cur_n + 1;
-  return 0;
-}
+  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);
 
-static struct msgset_keyword {
-  char *name;
-  int (*handler) (mu_mailbox_t mbox, size_t *pnum);
-} keywords[] = {
-  { "first", msgset_first },
-  { "last", msgset_last },
-  { "prev", msgset_prev },
-  { "next", msgset_next },
-  { "cur", msgset_cur },
-  { NULL },
-};
+  /* Remove duplicates. */
+  for (i = 0, msgno = 1; i < msgset->count; i++)
+    if (msglist[msgno-1] != msglist[i])
+      msglist[msgno++] = msglist[i];
+  msgset->count = msgno;
+}
 
-/* Preprocess a part of a complex message designation. Returns
-   a pointer to the allocated memory containing expanded part of
-   the designation. Pointer to the beginning of the not expanded
-   part (in arg) is placed into *rest */
-static char *
-msgset_preproc_part (mu_mailbox_t mbox, char *arg, char **rest)
+/* Check if message with ordinal number `num' is contained in the
+   message set. */
+int
+mh_msgset_member (mh_msgset_t *msgset, size_t num)
 {
-  struct msgset_keyword *p;
-  char *cp;
-  
-  for (p = keywords; p->name; p++)
-    if (strncmp (arg, p->name, strlen (p->name)) == 0)
-      {
-       int rc;
-       size_t uid, num;
-       mu_message_t msg;
-       
-       if (p->handler (mbox, &num))
-         msgset_abort (arg);
-       rc = mu_mailbox_get_message (mbox, num, &msg);
-       if (rc)
-         {
-           mu_error (_("cannot get message %lu: %s"),
-                     (unsigned long) num, mu_strerror (rc));
-           exit (1);
-         }
-       *rest = arg + strlen (p->name);
-       mu_message_get_uid (msg, &uid);
-       return xstrdup (mu_umaxtostr (0, uid));
-      }
-  cp = strchr (arg, '-');
-  if (cp)
-    {
-      char *ret;
-
-      *rest = cp;
-      ret = xmalloc (cp - arg + 1);
-      memcpy (ret, arg, cp - arg);
-      ret[cp - arg] = 0;
-      return ret;
-    }
+  size_t i;
 
-  *rest = arg + strlen (arg);
-  return strdup (arg);
+  for (i = 0; i < msgset->count; i++)
+    if (msgset->list[i] == num)
+      return i + 1;
+  return 0;
 }
 
-/* Preprocess (expand) a single message designation */
-static char *
-msgset_preproc (mu_mailbox_t mbox, char *arg)
+/* Reverse the order of messages in the message set */
+void
+mh_msgset_reverse (mh_msgset_t *msgset)
 {
-  char *buf, *tail;
-  
-  if (strcmp (arg, "all") == 0 || strcmp (arg, ".") == 0)
-    {
-      /* Special case */
-      arg = "first-last";
-    }
+  int head, tail;
 
-  buf = msgset_preproc_part (mbox, arg, &tail);
-  if (tail[0] == '-')
-    {
-      char *rest = msgset_preproc_part (mbox, tail+1, &tail);
-      char *p = NULL;
-      mu_asprintf (&p, "%s-%s", buf, rest);
-      free (rest);
-      free (buf);
-      buf = p;
-    }
-  
-  if (tail[0])
+  for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
     {
-      char *p = NULL;
-      mu_asprintf (&p, "%s%s", buf, tail);
-      free (buf);
-      buf = p;
+      size_t val = msgset->list[head];
+      msgset->list[head] = msgset->list[tail];
+      msgset->list[tail] = val;
     }
-  return buf;
 }
 
-static int
-comp_mesg (const void *a, const void *b)
-{
-  if (*(size_t*)a > *(size_t*)b)
-    return 1;
-  else if (*(size_t*)a < *(size_t*)b)
-    return -1;
-  return 0;
-}
-
-static int _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
-                            int argc, char **argv);
-
-/* Treat arg as a name of user-defined sequence and attempt to
-   expand it. Return 0 if succeeded, non-zero otherwise. */
-int
-expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg)
+/* 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)
 {
-  struct mu_wordsplit ws;
-  char *p;
-  const char *listp;
-  int rc = 1;
-  int negate = 0;
-  
-  p = strchr (arg, ':');
-  if (p)
-    *p++ = 0;
-  listp = mh_global_sequences_get (mbox, arg, NULL);
-  if (!listp)
-    {
-      int len;
-      const char *neg = mh_global_profile_get ("Sequence-Negation", NULL);
-      if (!neg)
-       return 1;
-      len = strlen (neg);
-      if (strncmp (arg, neg, len))
-       return 1;
-      negate = 1;
-      listp = mh_global_sequences_get (mbox, arg + len, NULL);
-      if (!listp)
-       return 1;
-    }
-
-  if (mu_wordsplit (listp, &ws, MU_WRDSF_DEFFLAGS))
-    {
-      mu_error (_("cannot split line `%s': %s"), listp,
-               mu_wordsplit_strerror (&ws));
-    }
-  else
-    {
-      rc = _mh_msgset_parse (mbox, msgset, ws.ws_wordc, ws.ws_wordv);
-      mu_wordsplit_free (&ws);
-    }
+  mu_message_t msg = NULL;
+  int rc;
+  size_t cur;
   
+  rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
   if (rc)
-    return rc;
-
-  if (negate)
-    mh_msgset_negate (mbox, msgset);
-  
-  if (p)
     {
-      int first, num;
-      
-      num = strtoul (p, &p, 0);
-      if (*p)
-       {
-         mh_msgset_free (msgset);
-         return 1;
-       }
-      if (num < 0)
-       {
-         first = num + msgset->count;
-         num = - num;
-       }
-      else
-       first = 0;
-      if (num > msgset->count)
-       {
-         mh_msgset_free (msgset);
-         return 1;
-       }
-
-      if (first > 0)
-       memmove (msgset->list, &msgset->list[first],
-                sizeof (msgset->list[0]) * num);
-      msgset->count = num;
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
+      exit (1);
     }
-  
-  return rc;
+  mh_message_number (msg, &cur);
+  mh_mailbox_set_cur (mbox, cur);
 }
 
-/* Parse a message specification from (argc;argv). Returned msgset is
-   not sorted nor optimised */
-int
-_mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, int argc, char 
**argv)
+/* 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 */
+void
+mh_msgset_free (mh_msgset_t *msgset)
 {
-  size_t msgcnt;
-  size_t *msglist;
-  size_t i, msgno;
-  
-  if (argc == 0)
-    return 1;
-  
-  msgcnt = argc;
-  msglist = calloc (msgcnt, sizeof(*msglist));
-  for (i = 0, msgno = 0; i < argc; i++)
-    {
-      char *p = NULL, *q;
-      size_t start, end;
-      size_t msg_first, n;
-      long num;
-      char *arg = msgset_preproc (mbox, argv[i]);
-
-      if (!mu_isdigit (arg[0]))
-       {
-         int j;
-         mh_msgset_t m;
-         
-         if (expand_user_seq (mbox, &m, arg))
-           {
-             mu_error (_("message set %s does not exist"), arg);
-             exit (1);
-           }
-         _expand (&msgcnt, &msglist, m.count);
-         for (j = 0; j < m.count; j++)
-           msglist[msgno++] = m.list[j];
-         mh_msgset_free (&m);
-       }
-      else
-       {
-         start = strtoul (arg, &p, 0);
-         switch (*p)
-           {
-           case 0:
-             n = mh_get_message (mbox, start, NULL);
-             if (!n)
-               {
-                 mu_error (_("message %lu does not exist"),
-                           (unsigned long) start);
-                 exit (1);
-               }
-             msglist[msgno++] = n;
-             break;
-             
-           case '-':
-             end = strtoul (p+1, &p, 0);
-             if (*p)
-               msgset_abort (argv[i]);
-             if (end < start)
-               {
-                 size_t t = start;
-                 start = end;
-                 end = t;
-               }
-             _expand (&msgcnt, &msglist, end - start);
-             msg_first  = msgno;
-             for (; start <= end; start++)
-               {
-                 n = mh_get_message (mbox, start, NULL);
-                 if (n)
-                   msglist[msgno++] = n;
-               }
-             if (msgno == msg_first)
-               {
-                 mu_error (_("no messages in range %s"), argv[i]);
-                 exit (1);
-               }
-             break;
-             
-           case ':':
-             num = strtoul (p+1, &q, 0);
-             if (*q)
-               msgset_abort (argv[i]);
-             if (p[1] != '+' && p[1] != '-')
-               {
-                 if (strncmp (argv[i], "last:", 5) == 0
-                     || strncmp (argv[i], "prev:", 5) == 0)
-                   num = -num;
-               }
-             end = start + num;
-             if (end < start)
-               {
-                 size_t t = start;
-                 start = end + 1;
-                 end = t;
-               }
-             else
-               end--;
-             _expand (&msgcnt, &msglist, end - start);
-             msg_first  = msgno;
-             for (; start <= end; start++)
-               {
-                 n = mh_get_message (mbox, start, NULL);
-                 if (n)
-                   msglist[msgno++] = n;
-               }
-             if (msgno == msg_first)
-               {
-                 mu_error (_("no messages in range %s"), argv[i]);
-                 exit (1);
-               }
-             break;
-             
-           default:
-             msgset_abort (argv[i]);
-           }
-       }
-      free (arg);
-    }
-
-  msgset->count = msgno;
-  msgset->list = msglist;
-  return 0;
+  if (msgset->count)
+    free (msgset->list);
 }
 
-/* Parse a message specification from (argc;argv). Returned msgset is
-   sorted and optimised (i.e. it does not contain duplicate message
-   numbers) */
-int
-mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
-                int argc, char **argv, char *def)
+/* 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)
 {
-  char *xargv[2];
-  int rc;
-  
-  if (argc == 0)
+  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++)
     {
-      argc = 1;
-      argv = xargv;
-      argv[0] = def ? def : "cur";
-      argv[1] = NULL;
+      if (!mh_msgset_member (msgset, i))
+       list[msgno++] = i;
     }
-  
-  rc = _mh_msgset_parse (mbox, msgset, argc, argv);
 
-  if (rc == 0)
+  list = realloc (list, sizeof (list[0]) * msgno);
+  if (!list)
     {
-      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;
+      mu_error (_("not enough memory"));
+      abort ();
     }
-  return rc;
+  mh_msgset_free (msgset);
+  msgset->count = msgno;
+  msgset->list = list;
 }
 
-/* Check if message with ordinal number `num' is contained in the
-   message set. */
-int
-mh_msgset_member (mh_msgset_t *msgset, size_t num)
+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 (msgset->list[i] == num)
-      return i + 1;
-  return 0;
+    {
+      mu_message_t msg;
+      mu_mailbox_get_message (mbox, msgset->list[i], &msg);
+      mh_message_number (msg, &msgset->list[i]);
+    }
+  msgset->flags |= MH_MSGSET_UID;
 }
-
+
 /* Auxiliary function. Performs binary search for a message with the
    given sequence number */
 static size_t
@@ -555,87 +266,457 @@ mh_get_message (mu_mailbox_t mbox, size_t seqno, 
mu_message_t *mesg)
   return mh_search_message (mbox, 1, count, seqno, mesg);
 }
 
-/* Reverse the order of messages in the message set */
-void
-mh_msgset_reverse (mh_msgset_t *msgset)
+
+struct msgset_parser
 {
-  int head, tail;
+  mu_mailbox_t mbox;
+  mh_msgset_t *msgset;
+  char *curp;
+  int argc;
+  char **argv;
+
+  int sign;
+  size_t number;
+  int validuid;
+};
 
-  for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
+static void
+msgset_parser_init (struct msgset_parser *parser, mu_mailbox_t mbox,
+                   mh_msgset_t *msgset, int argc, char **argv)
+{
+  parser->mbox = mbox;
+  parser->msgset = msgset;
+  parser->argc = argc;
+  parser->argv = argv;
+  parser->curp = "";
+
+  parser->sign = 0;
+  parser->number = 0;
+}
+
+static void
+msgset_abort (const char *arg)
+{
+  mu_error (_("bad message list `%s'"), arg);
+  exit (1);
+}
+
+static void
+emptyrange_abort (const char *range)
+{
+  mu_error (_("no messages in range %s"), range);
+  exit (1);
+}
+
+/* Advance parser to the next argument */
+static int
+nextarg (struct msgset_parser *parser)
+{
+  if (parser->argc == 0)
+    return 0;
+  parser->argc--;
+  parser->curp = *parser->argv++;
+  return 1;
+}
+
+static void msgset_parser_run (struct msgset_parser *parser);
+
+static int
+_expand_sequence (struct msgset_parser *parser, char *term)
+{
+  struct mu_wordsplit ws;
+  const char *listp;
+  int negate = 0;
+
+  listp = mh_global_sequences_get (parser->mbox, term, NULL);
+  if (!listp)
     {
-      size_t val = msgset->list[head];
-      msgset->list[head] = msgset->list[tail];
-      msgset->list[tail] = val;
+      int len;
+      const char *neg = mh_global_profile_get ("Sequence-Negation", NULL);
+      if (!neg)
+       return 1;
+      len = strlen (neg);
+      if (strncmp (term, neg, len))
+       return 1;
+      negate = 1;
+      listp = mh_global_sequences_get (parser->mbox, term + len, NULL);
+      if (!listp)
+       return 1;
+    }
+
+  if (mu_wordsplit (listp, &ws, MU_WRDSF_DEFFLAGS))
+    {
+      mu_error (_("cannot split line `%s': %s"), listp,
+               mu_wordsplit_strerror (&ws));
+      exit (1);
+    }
+  else
+    {
+      struct msgset_parser clone;
+      
+      msgset_parser_init (&clone, parser->mbox,  parser->msgset,
+                         ws.ws_wordc, ws.ws_wordv);
+      msgset_parser_run (&clone);
+      mu_wordsplit_free (&ws);
     }
+  
+  if (negate)
+    mh_msgset_negate (parser->mbox, parser->msgset);
+  return 0;
 }
 
-/* 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)
+static int
+parse_count (struct msgset_parser *parser)
+{
+  char *endp;
+  if (!*parser->curp && nextarg (parser) == 0)
+    return 0;
+  if (*parser->curp == '-')
+    {
+      parser->sign = 1;
+      parser->curp++;
+    }
+  else if (*parser->curp == '+')
+    {
+      parser->sign = 0;
+      parser->curp++;
+    }
+  parser->number = strtoul (parser->curp, &endp, 10);
+  if (*endp)
+    msgset_abort (parser->curp);
+  parser->curp = endp;
+  return 1;
+}
+
+
+static int
+msgset_first (mu_mailbox_t mbox, size_t *pnum)
+{
+  *pnum = 1;
+  return 0;
+}
+
+static int
+msgset_last (mu_mailbox_t mbox, size_t *pnum)
 {
-  mu_message_t msg = NULL;
   int rc;
-  size_t cur;
-  
-  rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
+
+  rc = mu_mailbox_messages_count (mbox, pnum);
   if (rc)
     {
-      mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
+      mu_error (_("cannot get last message: %s"), mu_strerror (rc));
       exit (1);
     }
-  mh_message_number (msg, &cur);
-  mh_mailbox_set_cur (mbox, cur);
+  return 0;
 }
 
-/* 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 */
-void
-mh_msgset_free (mh_msgset_t *msgset)
+static int
+msgset_cur (mu_mailbox_t mbox, size_t *pnum)
 {
-  if (msgset->count)
-    free (msgset->list);
+  size_t num;
+  mh_mailbox_get_cur (mbox, &num);
+  return mh_uid_to_msgno (mbox, num, pnum);
 }
 
-/* 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)
+static int
+msgset_prev (mu_mailbox_t mbox, size_t *pnum)
 {
-  size_t i, total = 0, msgno;
-  size_t *list;
+  size_t cur_n = 0;
+  msgset_cur (mbox, &cur_n);
+  if (cur_n < 1)
+    {
+      mu_error (_("no prev message"));
+      exit (1);
+    }
+  *pnum = cur_n - 1;
+  return 0;
+}
 
+static int
+msgset_next (mu_mailbox_t mbox, size_t *pnum)
+{
+  size_t cur_n = 0, total = 0;
+  msgset_cur (mbox, &cur_n);
   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++)
+  if (cur_n + 1 > total)
     {
-      if (!mh_msgset_member (msgset, i))
-       list[msgno++] = i;
+      mu_error (_("no next message"));
+      exit (1);
     }
+  *pnum = cur_n + 1;
+  return 0;
+}
 
-  list = realloc (list, sizeof (list[0]) * msgno);
-  if (!list)
+struct msgset_keyword
+{
+  char *name;
+  size_t len;
+  int (*handler) (mu_mailbox_t mbox, size_t *pnum);
+  int sign;
+};
+
+static struct msgset_keyword keywords[] = {
+#define S(s) #s, sizeof (#s) - 1
+  { S(first), msgset_first, 0 },
+  { S(last), msgset_last, 1 },
+  { S(prev), msgset_prev, 1 },
+  { S(next), msgset_next, 0 },
+  { S(cur), msgset_cur, 0 },
+  { NULL }
+};
+
+#define PARSE_EOF  0
+#define PARSE_MORE 1
+#define PARSE_SUCCESS 2
+
+/* term : NUMBER
+        | "first"
+       | "last"
+       | "cur"
+       | "prev"
+       | "next"
+       ;
+*/
+static int
+parse_term (struct msgset_parser *parser, int seq)
+{
+  size_t tlen;
+  char *term;
+  
+  if (!*parser->curp && nextarg (parser) == 0)
+    return PARSE_EOF;
+
+  term = parser->curp;
+  parser->curp = mu_str_skip_class (term, MU_CTYPE_ALPHA|MU_CTYPE_DIGIT);
+  tlen = parser->curp - term;
+  if (mu_isalpha (*term))
     {
-      mu_error (_("not enough memory"));
-      abort ();
+      struct msgset_keyword *p;
+
+      for (p = keywords; p->name; p++)
+       if (tlen == p->len && memcmp (p->name, term, tlen) == 0)
+         {
+           if (p->handler (parser->mbox, &parser->number))
+             msgset_abort (term);
+           parser->sign = p->sign;
+           parser->validuid = 1;
+           return PARSE_MORE;
+         }
+
+      if (*parser->curp == 0 && seq)
+       {
+         /* See if it is a user-defined sequence */
+         if (_expand_sequence (parser, term) == 0)
+           return PARSE_SUCCESS;
+       }
+      msgset_abort (term);
     }
-  mh_msgset_free (msgset);
-  msgset->count = msgno;
-  msgset->list = list;
+  else if (mu_isdigit (*term))
+    {
+      char *endp;
+      size_t num = strtoul (term, &endp, 10);
+      if (endp != parser->curp)
+       msgset_abort (term);
+      
+      if (mh_uid_to_msgno (parser->mbox, num, &parser->number))
+       {
+         parser->validuid = 0;
+         parser->number = num;
+       }
+      else
+       parser->validuid = 1;
+      parser->sign = 0;
+    }
+  else
+    msgset_abort (term);
+  return PARSE_MORE;
 }
 
-void
-mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
+static void
+add_messages (struct msgset_parser *parser, size_t start, size_t count,
+             int sign)
 {
   size_t i;
-  for (i = 0; i < msgset->count; i++)
+
+  if (start == 0)
+    start = 1;
+  mh_msgset_expand (parser->msgset, count);
+  if (sign)
     {
-      mu_message_t msg;
-      mu_mailbox_get_message (mbox, msgset->list[i], &msg);
-      mh_message_number (msg, &msgset->list[i]);
+      if (count > start)
+       count = start;
+      for (i = 0; i < count; i++, start--)
+       parser->msgset->list[parser->msgset->count++] = start;
+    }
+  else
+    {
+      size_t total;
+  
+      mu_mailbox_messages_count (parser->mbox, &total);
+      if (start + count > total)
+       count = total - start + 1;
+      for (i = 0; i < count; i++, start++)
+       parser->msgset->list[parser->msgset->count++] = start;
+    }
+  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)
+    {
+      size_t t = start;
+      start = end;
+      end = t;
+    }
+  mh_msgset_expand (parser->msgset, end - start + 1);
+
+  for (; start <= end; start++)
+    parser->msgset->list[parser->msgset->count++] = start;
+}
+
+/* range: term '-' term
+        | term ':' count
+       ;
+   count: NUMBER
+        | '+' NUMBER
+       | '-' NUMBER
+       ;
+*/     
+static int
+parse_range (struct msgset_parser *parser)
+{
+  size_t start;
+
+  switch (parse_term (parser, 1))
+    {
+    case PARSE_EOF:
+      return 0;
+
+    case PARSE_SUCCESS:
+      return 1;
+
+    case PARSE_MORE:
+      break;
+    }
+      
+  start = parser->number;
+
+  if (*parser->curp == ':')
+    {
+      int validuid = parser->validuid;
+      parser->curp++;
+      if (parse_count (parser) == 0)
+       return 0;
+      if (!validuid)
+       {
+         size_t total, lastuid;
+         msgset_last (parser->mbox, &total);
+         mh_msgno_to_uid (parser->mbox, total, &lastuid);
+         if (start > lastuid)
+           {
+             if (!parser->sign)
+               emptyrange_abort (parser->argv[-1]);
+             start = total;
+           }
+         else
+           {
+             if (parser->sign)
+               emptyrange_abort (parser->argv[-1]);
+             start = 1;
+           }
+       }
+      add_messages (parser, start, parser->number, parser->sign);
+      return 1;
+    }
+  else if (*parser->curp == '-')
+    {
+      size_t lastuid = 0;
+      int validuid = parser->validuid;
+      
+      parser->curp++;
+      if (parse_term (parser, 0) == PARSE_EOF)
+       return 0;
+      if (!parser->validuid)
+       {
+         size_t total;
+
+         msgset_last (parser->mbox, &total);
+         mh_msgno_to_uid (parser->mbox, total, &lastuid);
+         if (parser->number > lastuid)
+           parser->number = total;
+         else if (!validuid)
+           emptyrange_abort (parser->argv[-1]);
+       }
+      if (!validuid)
+       {
+         if (!lastuid)
+           {
+             size_t total;
+             msgset_last (parser->mbox, &total);
+             mh_msgno_to_uid (parser->mbox, total, &lastuid);
+           }
+         if (start > lastuid && !parser->validuid)
+           emptyrange_abort (parser->argv[-1]);
+         start = 1;
+       }
+      add_message_range (parser, start, parser->number);
     }
+  else if (!parser->validuid)
+    {
+      mu_error (_("message %s does not exist"), parser->argv[-1]);
+      exit (1);
+    }
+  else
+    mh_msgset_add (parser->msgset, start);
+  return 1;
+}
+  
+  
+/* Parse a message specification. The composed msgset is
+   not sorted nor optimised */
+static void
+msgset_parser_run (struct msgset_parser *parser)
+{
+  while (parse_range (parser))
+    ;
+}
+
+/* Parse a message specification from (argc;argv). Returned msgset is
+   sorted and optimised (i.e. it does not contain duplicate message
+   numbers) */
+void
+mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, 
+                int argc, char **argv, char *def)
+{
+  struct msgset_parser parser;
+  char *xargv[2];
+  
+  if (argc == 0)
+    {
+      argc = 1;
+      argv = xargv;
+      argv[0] = def ? def : "cur";
+      argv[1] = NULL;
+    }
+
+  if (argc == 1 &&
+      (strcmp (argv[0], "all") == 0 || strcmp (argv[0], ".") == 0))
+    {
+      argc = 1;
+      argv = xargv;
+      argv[0] = "first-last";
+      argv[1] = NULL;
+    }
+  
+  mh_msgset_init (msgset);
+  msgset_parser_init (&parser, mbox, msgset, argc, argv);
+  msgset_parser_run (&parser);
+
+  mh_msgset_optimize (msgset);
 }
diff --git a/mh/mh_whatnow.c b/mh/mh_whatnow.c
index 0d8dd61..dee46b5 100644
--- a/mh/mh_whatnow.c
+++ b/mh/mh_whatnow.c
@@ -346,18 +346,21 @@ _whatnow (struct mh_whatnow_env *wh, struct action_tab 
*tab)
   
   do
     {
+      size_t n;
       handler_fp fun;
       
       printf ("%s ", wh->prompt);
       fflush (stdout);
-      rc = mu_stream_getline (in, &line, &size, NULL);
+      rc = mu_stream_getline (in, &line, &size, &n);
       if (rc)
        {
          mu_error (_("cannot read input stream: %s"), mu_strerror (rc));
          status = 1;
          break;
        }
-
+      if (n == 0)
+       break;
+      
       ws.ws_comment = "#";
       rc = mu_wordsplit (line, &ws, wsflags);
       if (rc)
@@ -462,7 +465,10 @@ static int
 call_send (struct mh_whatnow_env *wh, int argc, char **argv, int *status)
 {
   if (invoke ("sendproc", MHBINDIR "/send", argc, argv, wh->file, NULL) == 0)
-    annotate (wh);
+    {
+      annotate (wh);
+      return 1;
+    }
   return 0;
 }
 
diff --git a/mh/rmm.c b/mh/mhseq.c
similarity index 66%
copy from mh/rmm.c
copy to mh/mhseq.c
index 6e2f65e..48a7691 100644
--- a/mh/rmm.c
+++ b/mh/mhseq.c
@@ -1,6 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2002, 2005, 2007, 2008, 2009, 2010 Free Software
-   Foundation, Inc.
+   Copyright (C) 2010 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
@@ -15,26 +14,32 @@
    You should have received a copy of the GNU General Public License
    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
 
-/* MH rmm command */
+/* MH mhparam command */
 
 #include <mh.h>
 
-static char doc[] = N_("GNU MH rmm")"\v"
+static char doc[] = N_("GNU MH mhseq")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
-static char args_doc[] = N_("[+FOLDER] [MSGLIST]");
+static char args_doc[] = N_("[SEQUENCE]");
 
-/* GNU options */
 static struct argp_option options[] = {
   {"folder",  ARG_FOLDER, N_("FOLDER"), 0,
-   N_("specify folder to operate upon")},
-  { 0 }
+   N_("specify the folder to use")},
+  { "uids",  'u', NULL, 0,
+    N_("show message UIDs (default)")},
+  { "numbers", 'n', NULL, 0,
+    N_("show message numbers") },
+  { NULL }
 };
 
 /* Traditional MH options */
 struct mh_option mh_option[] = {
+  { "uid" },
   { NULL }
 };
 
+static int uid_option = 1;
+
 static error_t
 opt_handler (int key, char *arg, struct argp_state *state)
 {
@@ -43,29 +48,29 @@ opt_handler (int key, char *arg, struct argp_state *state)
     case ARG_FOLDER: 
       mh_set_current_folder (arg);
       break;
+
+    case 'n':
+      uid_option = 0;
+      break;
       
+    case 'u':
+      uid_option = 1;
+      break;
+
     default:
       return ARGP_ERR_UNKNOWN;
     }
   return 0;
 }
 
-void
-rmm (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
-{
-  mu_attribute_t attr;
-  mu_message_get_attribute (msg, &attr);
-  mu_attribute_set_deleted (attr);
-}
-
 int
 main (int argc, char **argv)
 {
-  int index = 0;
+  int index;
   mu_mailbox_t mbox;
   mh_msgset_t msgset;
-  int status;
-
+  size_t i;
+    
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
@@ -73,16 +78,17 @@ main (int argc, char **argv)
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
+  argc -= index;
+  argv += index;
   mbox = mh_open_folder (mh_current_folder (), 0);
 
-  mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
-
-  status = mh_iterate (mbox, &msgset, rmm, NULL);
+  mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
+  if (uid_option)
+    mh_msgset_uids (mbox, &msgset);
 
-  mu_mailbox_expunge (mbox);
-  mu_mailbox_close (mbox);
-  mu_mailbox_destroy (&mbox);
-  mh_global_save_state ();
-  return status;
+  for (i = 0; i < msgset.count; i++)
+    printf ("%lu\n", (unsigned long) msgset.list[i]);
+  return 0;
 }
 
+  
diff --git a/mh/tests/Makefile.am b/mh/tests/Makefile.am
index 3adf295..00c00ed 100644
--- a/mh/tests/Makefile.am
+++ b/mh/tests/Makefile.am
@@ -42,6 +42,7 @@ TESTSUITE_AT = \
  ali.at\
  anno.at\
  burst.at\
+ comp.at\
  folder.at\
  inc.at\
  install-mh.at\
@@ -49,6 +50,7 @@ TESTSUITE_AT = \
  mhl.at\
  mhparam.at\
  mhpath.at\
+ mhseq.at\
  pick.at\
  scan.at\
  refile.at\
diff --git a/mh/tests/comp.at b/mh/tests/comp.at
new file mode 100644
index 0000000..54a61b1
--- /dev/null
+++ b/mh/tests/comp.at
@@ -0,0 +1,148 @@
+# This file is part of GNU Mailutils. -*- Autotest -*-
+# Copyright (C) 2010 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/>.
+
+m4_pushdef([MH_KEYWORDS],[comp])
+m4_pushdef([compcmd],[comp dnl
+-form $abs_top_srcdir/mh/components dnl
+-editor $abs_top_srcdir/mh/tests/mhed])
+
+MH_CHECK([comp -file],[comp00 comp-file],[
+dir=`pwd`
+echo quit | compcmd -file ./infile | sed "s|$dir/*||;s|  *$||"
+cat infile
+],
+[0],
+[-- Editor invocation: ./infile
+-- Input file:
+To:
+cc:
+Subject:
+--------
+-- Input file end
+What now? draft left on "./infile".
+To:
+cc:
+Subject:
+--------
+Seen by mhed
+])
+
+MH_CHECK([comp -file (del)],[comp01 comp-file_del],[
+dir=`pwd`
+echo 'quit -delete' | compcmd -file ./infile | sed "s|$dir/*||;s|  *$||"
+],
+[0],
+[-- Editor invocation: ./infile
+-- Input file:
+To:
+cc:
+Subject:
+--------
+-- Input file end
+What now?])
+
+MH_CHECK([comp file],[comp02 comp_file],[
+echo 'quit' | compcmd file | sed "s|$dir/*||;s|  *$||"
+cat Mail/file 
+],
+[0], 
+[-- Editor invocation: Mail/file
+-- Input file:
+To:
+cc:
+Subject:
+--------
+-- Input file end
+What now? draft left on "Mail/file".
+To:
+cc:
+Subject:
+--------
+Seen by mhed
+])
+
+MH_CHECK([comp -use file],[comp03 comp-use_file],[
+AT_DATA([Mail/file],[From: gray
+To: root
+Subject: test input
+
+message body
+])
+
+echo 'quit' | compcmd -use file | sed "s|$dir/*||;s|  *$||"
+cat Mail/file 
+],
+[0], 
+[-- Editor invocation: Mail/file
+-- Input file:
+From: gray
+To: root
+Subject: test input
+
+message body
+-- Input file end
+What now? draft left on "Mail/file".
+From: gray
+To: root
+Subject: test input
+
+message body
+Seen by mhed
+])
+
+MH_CHECK([comp +folder msg],[comp04 comp+folder_msg],[
+mkdir Mail/inbox
+AT_DATA([Mail/inbox/1],[From: gray
+To: root
+Subject: test input
+
+message body
+])
+
+echo 'quit' | compcmd +inbox 1 | sed "s|$dir/*||;s|  *$||"
+echo Mail/draft
+cat Mail/draft
+echo Message
+cat Mail/inbox/1
+],
+[0], 
+[-- Editor invocation: Mail/draft
+-- Input file:
+From: gray
+To: root
+Subject: test input
+
+message body
+-- Input file end
+What now? draft left on "Mail/draft".
+Mail/draft
+From: gray
+To: root
+Subject: test input
+
+message body
+Seen by mhed
+Message
+From: gray
+To: root
+Subject: test input
+
+message body
+])
+
+m4_popdef([compcmd])
+m4_popdef([MH_KEYWORDS])
+
diff --git a/mh/tests/mhed b/mh/tests/mhed
new file mode 100755
index 0000000..986edce
--- /dev/null
+++ b/mh/tests/mhed
@@ -0,0 +1,8 @@
+#! /bin/sh
+
+echo "-- Editor invocation:" $*
+echo "-- Input file: "
+cat $1
+echo "-- Input file end"
+echo "Seen by mhed" >> $1
+exit 0
diff --git a/mh/tests/mhseq.at b/mh/tests/mhseq.at
new file mode 100644
index 0000000..225058a
--- /dev/null
+++ b/mh/tests/mhseq.at
@@ -0,0 +1,386 @@
+# This file is part of GNU Mailutils. -*- Autotest -*-
+# Copyright (C) 2010 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/>.
+
+m4_pushdef([MH_KEYWORDS],[mhseq mh-sequences])
+
+dnl ---------------------------------------------------------------
+
+MH_CHECK([mhseq: existing message number],[mhseq00],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+mhseq 1
+],
+[0],
+[1
+])
+
+MH_CHECK([mhseq: not existing message number],[mhseq01],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+mhseq 100
+],
+[1],
+[],
+dnl FIXME: See FIXME 3 in mhpath.at
+[mhseq: message 100 does not exist
+])
+
+MH_CHECK([mhseq: contiguous message range],[mhseq02],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+mhseq 2-5
+],
+[0],
+[2
+3
+4
+5
+])
+
+MH_CHECK([mhseq: reversed contiguous message range],[mhseq03],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+mhseq 5-2
+],
+[0],
+[2
+3
+4
+5
+])
+
+MH_CHECK([mhseq: reversed non-contiguous message range],[mhseq04],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/3 Mail/inbox/4
+mhseq 5-2
+],
+[0],
+[2
+5
+])
+
+MH_CHECK([mhseq: message range (left fixup)],[mhseq05],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1 Mail/inbox/2
+mhseq 1-5
+],
+[0],
+[3
+4
+5
+])
+
+MH_CHECK([mhseq: message range (right fixup)],[mhseq06],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/4 Mail/inbox/5
+mhseq 1-5
+],
+[0],
+[1
+2
+3
+])
+
+MH_CHECK([mhseq: message range (both fixups)],[mhseq07],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1 Mail/inbox/5
+mhseq 1-5
+],
+[0],
+[2
+3
+4
+])
+
+MH_CHECK([mhseq: non-existent message range (left)],[mhseq08],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1 Mail/inbox/2 Mail/inbox/3
+mhseq 1-2
+],
+[1],
+[],
+[mhseq: no messages in range 1-2
+])
+
+MH_CHECK([mhseq: non-existent message range (right)],[mhseq09],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+mhseq 6-10
+],
+[1],
+[],
+[mhseq: no messages in range 6-10
+])
+
+MH_CHECK([mhseq: message set addition],[mhseq10],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
+mhseq 5 8-10 15-20
+],
+[0],
+[5
+8
+9
+10
+15
+16
+17
+18
+19
+20
+])
+
+MH_CHECK([mhseq: message set optimization],[mhseq11],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
+rm Mail/inbox/17 Mail/inbox/19
+mhseq 5 1-10 15-20
+],
+[0],
+[1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+15
+16
+18
+20
+])
+
+MH_CHECK([mhseq: counted range (positive)],[mhseq12],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
+mhseq 10:4
+],
+[0],
+[10
+11
+12
+13
+])
+
+MH_CHECK([mhseq: non-contiguous counted range (positive)],[mhseq13],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
+rm Mail/inbox/12 Mail/inbox/14
+mhseq 10:4
+],
+[0],
+[10
+11
+13
+15
+])
+
+MH_CHECK([mhseq: counted range (positive, left fixup)],[mhseq14],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1 Mail/inbox/2
+mhseq 1:3
+],
+[0],
+[3
+4
+5
+])
+
+MH_CHECK([mhseq: counted range (positive, right fixup)],[mhseq15],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+mhseq 2:10
+],
+[0],
+[2
+3
+4
+5
+])
+
+MH_CHECK([mhseq: invalid counted range (negative)],[mhseq16],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1 Mail/inbox/2
+mhseq 10:2
+],
+[1],
+[],
+[mhseq: no messages in range 10:2
+])
+
+MH_CHECK([mhseq: counted range (negative)],[mhseq17],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
+mhseq 10:-4
+],
+[0],
+[7
+8
+9
+10
+])
+
+MH_CHECK([mhseq: non-contiguous counted range (negative)],[mhseq18],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox])
+rm Mail/inbox/8 Mail/inbox/6
+mhseq 10:-4
+],
+[0],
+[5
+7
+9
+10
+])
+
+MH_CHECK([mhseq: counted range (negative, left fixup)],[mhseq19],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1 Mail/inbox/2
+mhseq 4:-30
+],
+[0],
+[3
+4
+])
+
+MH_CHECK([mhseq: counted range (negative, right fixup)],[mhseq20],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1 Mail/inbox/2
+mhseq 4:30
+],
+[0],
+[4
+5
+])
+
+MH_CHECK([mhseq: invalid counted range (negative)],[mhseq21],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1 Mail/inbox/2
+mhseq 1:-30
+],
+[1],
+[],
+[mhseq: no messages in range 1:-30
+])
+
+MH_CHECK([mhseq: cur],[mhseq22 cur],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+echo "cur: 3" > Mail/inbox/.mh_sequences
+mhseq cur
+],
+[0],
+[3
+])
+
+MH_CHECK([mhseq: cur:n -- default direction],[mhseq23 cur:n],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+echo "cur: 3" > Mail/inbox/.mh_sequences
+mhseq cur:2
+],
+[0],
+[3
+4
+])
+
+MH_CHECK([mhseq: cur:n -- explicit dir (negative)],[mhseq24 cur:n cur:n-],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+echo "cur: 3" > Mail/inbox/.mh_sequences
+mhseq cur:-2
+],
+[0],
+[2
+3
+])
+
+MH_CHECK([mhseq: cur:n -- explicit dir (positive)],[mhseq25 cur:n cur:n+],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+echo "cur: 3" > Mail/inbox/.mh_sequences
+mhseq cur:+2
+],
+[0],
+[3
+4
+])
+
+MH_CHECK([mhseq: next],[mhseq26 next],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+echo "cur: 3" > Mail/inbox/.mh_sequences
+rm Mail/inbox/4
+mhseq next
+],
+[0],
+[5
+])
+
+MH_CHECK([mhseq: next:n -- default direction],[mhseq27 next:n],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+echo "cur: 3" > Mail/inbox/.mh_sequences
+mhseq next:2
+],
+[0],
+[4
+5
+])
+
+MH_CHECK([mhseq: prev],[mhseq28 prev],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+echo "cur: 3" > Mail/inbox/.mh_sequences
+rm Mail/inbox/2
+mhseq prev
+],
+[0],
+[1
+])
+
+MH_CHECK([mhseq: prev:n -- default direction],[mhseq29 prev:n],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+echo "cur: 3" > Mail/inbox/.mh_sequences
+mhseq prev:2
+],
+[0],
+[1
+2
+])
+
+MH_CHECK([mhseq: first],[mhseq30 first],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1
+mhseq first
+],
+[0],
+[2
+])
+
+MH_CHECK([mhseq: first:n -- default direction],[mhseq31 first:n],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+rm Mail/inbox/1
+mhseq first:2
+],
+[0],
+[2
+3
+])
+
+MH_CHECK([mhseq: last],[mhseq32 last],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+mhseq last
+],
+[0],
+[5
+])
+
+MH_CHECK([mhseq: last:n -- default direction],[mhseq33 last:n],[
+MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
+mhseq last:2
+],
+[0],
+[4
+5
+])
+
+m4_popdef([MH_KEYWORDS])
+# End of mhseq.at
\ No newline at end of file
diff --git a/mh/tests/testsuite.at b/mh/tests/testsuite.at
index 10b8d52..a18976d 100644
--- a/mh/tests/testsuite.at
+++ b/mh/tests/testsuite.at
@@ -42,6 +42,7 @@ AT_CLEANUP
 AT_INIT
 
 m4_include([install-mh.at])
+m4_include([mhseq.at])
 m4_include([ali.at])
 m4_include([folder.at])
 m4_include([inc.at])
@@ -56,3 +57,4 @@ m4_include([mhl.at])
 m4_include([anno.at])
 m4_include([pick.at])
 m4_include([burst.at])
+m4_include([comp.at])


hooks/post-receive
-- 
GNU Mailutils



reply via email to

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