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-491-g98ca43a


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-491-g98ca43a
Date: Wed, 30 Nov 2011 23:53:27 +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=98ca43a049365269e4052170eba3103a8d35e20b

The branch, master has been updated
       via  98ca43a049365269e4052170eba3103a8d35e20b (commit)
       via  827a4ba256a0d3cfc6b3caab546cea0c1ee96263 (commit)
       via  de2376862a1d3a9f00602eea7976751266287401 (commit)
      from  b848706b89934be5a4419ab2ec382157d2f30aba (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 98ca43a049365269e4052170eba3103a8d35e20b
Author: Sergey Poznyakoff <address@hidden>
Date:   Thu Dec 1 01:47:53 2011 +0200

    imap client: improve parsing of BODY[] items.
    
    * include/mailutils/imap.h (mu_imap_fetch_body) <key>: Rename to section.
    <fields>: New member.
    * libproto/imap/fetch.c: Rewrite response item parser.
    * mu/imap.c: Improve fetch_response_printer

commit 827a4ba256a0d3cfc6b3caab546cea0c1ee96263
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Nov 30 23:27:23 2011 +0200

    Implement list folding functions.
    
    * include/mailutils/list.h (mu_list_folder_t): New typedef.
    (mu_list_fold, mu_list_rfold): New functions.
    * libmailutils/list/fold.c: New file.
    * libmailutils/list/rfold.c: New file.
    * libmailutils/list/Makefile.am (liblist_la_SOURCES): Add fold.c and
    rfold.c
    * libmailutils/list/gmap.c (mu_list_gmap): Access list elements directly,
    instead of using iterators.
    * libmailutils/tests/list.at: Add test cases for list folding.
    * libmailutils/tests/listop.c: Add fold and rfold commands.

commit de2376862a1d3a9f00602eea7976751266287401
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Nov 30 20:13:09 2011 +0200

    Clean-up state changes in imap client.  Fix error handling in it and in 
pop3.
    
    * include/mailutils/imap.h (mu_imap_state): Rename to struct
    mu_imap_session_state, prefix all values with MU_IMAP_STATE_.
    All uses updated.
    * include/mailutils/sys/imap.h (mu_imap_client_state): Prefix all
    values with MU_IMAP_CLIENT. Rename MU_IMAP_NO_STATE to MU_IMAP_READY.
    All uses updated.
    (_mu_imap)<state>: Rename to client_state, fix data type.
    (imap_state): Rename to imap_state. All uses updated.
    (MU_IMAP_CHECK_EAGAIN): Reset state to MU_IMAP_CLIENT_READY if
    MU_ERR_REPLY or MU_ERR_BADREPLY is reported.
    * include/mailutils/sys/pop3.h (MU_POP3_CHECK_EAGAIN): Reset state
    to MU_POP3_NO_STATE, if MU_ERR_REPLY or MU_ERR_BADREPLY is reported.
    * libproto/imap/fetch.c (_date_mapper): Avoid overwriting resp->type.
    * libproto/imap/select.c (_mu_imap_collect_flags): Initialize *res
    prior to collecting flags into it.
    * mu/imap.c: Install a FETCH callback.

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

Summary of changes:
 include/mailutils/imap.h              |   15 +-
 include/mailutils/list.h              |   50 ++++-
 include/mailutils/sys/imap.h          |   87 ++++----
 include/mailutils/sys/pop3.h          |    2 +
 libmailutils/list/Makefile.am         |    2 +
 libmailutils/list/{head.c => fold.c}  |   26 ++-
 libmailutils/list/gmap.c              |   22 +--
 libmailutils/list/{head.c => rfold.c} |   26 ++-
 libmailutils/tests/list.at            |   56 +++++
 libmailutils/tests/listop.c           |   60 +++++
 libproto/imap/capability.c            |   15 +-
 libproto/imap/carrier.c               |    3 +-
 libproto/imap/connect.c               |   39 ++--
 libproto/imap/create.c                |    3 +-
 libproto/imap/disconnect.c            |    2 +-
 libproto/imap/fetch.c                 |  423 +++++++++++++++++++--------------
 libproto/imap/id.c                    |   14 +-
 libproto/imap/login.c                 |   16 +-
 libproto/imap/logout.c                |   15 +-
 libproto/imap/noop.c                  |   12 +-
 libproto/imap/resplist.c              |    4 +-
 libproto/imap/response.c              |    8 +-
 libproto/imap/resproc.c               |   22 +-
 libproto/imap/select.c                |   23 +-
 libproto/imap/state.c                 |    2 +-
 libproto/imap/status.c                |   18 +-
 mu/imap.c                             |  160 ++++++++++++-
 27 files changed, 756 insertions(+), 369 deletions(-)
 copy libmailutils/list/{head.c => fold.c} (68%)
 copy libmailutils/list/{head.c => rfold.c} (68%)

diff --git a/include/mailutils/imap.h b/include/mailutils/imap.h
index cfb879c..86e365c 100644
--- a/include/mailutils/imap.h
+++ b/include/mailutils/imap.h
@@ -33,13 +33,13 @@ extern "C" {
   
 typedef struct _mu_imap *mu_imap_t;
 
-enum mu_imap_state
+enum mu_imap_session_state
   {
-    MU_IMAP_STATE_INIT,     /* Initial state */
-    MU_IMAP_STATE_NONAUTH,  /* Non-Authenticated State */
-    MU_IMAP_STATE_AUTH,     /* Authenticated State */
-    MU_IMAP_STATE_SELECTED, /* Selected State */
-    MU_IMAP_STATE_LOGOUT,   /* Logout State */
+    MU_IMAP_SESSION_INIT,     /* Initial state (disconnected) */
+    MU_IMAP_SESSION_NONAUTH,  /* Non-Authenticated State */
+    MU_IMAP_SESSION_AUTH,     /* Authenticated State */
+    MU_IMAP_SESSION_SELECTED, /* Selected State */
+    MU_IMAP_SESSION_LOGOUT,   /* Logout State */
   };
   
 int mu_imap_create (mu_imap_t *pimap);
@@ -175,7 +175,8 @@ struct mu_imap_fetch_body
   int type;
   size_t *partv;
   size_t partc;
-  char *key;
+  char *section;
+  mu_list_t fields;
   char *text;
 };
 
diff --git a/include/mailutils/list.h b/include/mailutils/list.h
index 6d88819..2f860fb 100644
--- a/include/mailutils/list.h
+++ b/include/mailutils/list.h
@@ -238,7 +238,10 @@ typedef int (*mu_list_mapper_t) (void **_itmv, size_t 
_itmc, void *_call_data);
    and until all elements from the array have been visited.
 
    Mu_list_gmap returns 0 on success and a non-zero error code on failure.
-   If _map returns non-zero, its return value is propagated to the caller. */
+   If _map returns non-zero, its return value is propagated to the caller.
+
+   The _map function is not allowed to alter the _list.
+*/
    
 int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem,
                  void *_data);
@@ -263,11 +266,56 @@ int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, 
size_t _nelem,
    MU_LIST_MAP_SKIP bit set, the _itmv[0] element is appended to the new
    list.  If it has MU_LIST_MAP_STOP bit set, iteration is stopped
    immediately and any remaining elements in _list are ignored.
+
+   The mapper function (_map) is not allowed to alter the _list.
 */
 
 int mu_list_map (mu_list_t _list, mu_list_mapper_t _map,
                 void *_data, size_t _nelem,
                 mu_list_t *_res);
+
+  /* List fold */
+
+typedef int (*mu_list_folder_t) (void *_item, void *_data,
+                                void *_prev, void **_ret);
+
+  /* mu_list_fold iterates over list elements from first to last.
+     For each element it calls _fold with the following arguments:
+
+       _item     -  the current list element,
+       _data     -  call-specific data,
+       _prev     -  on the first call, _init; on subsequent calls,
+                    points to the value returned from the previous call
+                   to _fold in the _ret varialble,
+       _ret      -  memory location where to store the result of this
+                    call.
+
+     When all elements have been visited, mu_list_fold stores the result
+     of the last _fold invocation (as returned in *_ret) in the memory
+     location pointed to by _return_value.
+
+     If _fold returns a non-zero value, mu_list_fold stops iteration and
+     returns this value.  The *_return_value is filled in this case as
+     well.
+
+     Possible return codes:
+
+       0                   - success,
+       EINVAL              - _list or _fold is NULL,
+       MU_ERR_OUT_PTR_NULL - _return_code is NULL
+       other value         - non-zero value returned by _fold.
+
+     The _fold function is not allowed to alter the list it is being applied
+     to.
+       
+     The mu_list_rfold acts similarly, except that it iterates over list
+     elements from last to first.
+  */
+int mu_list_fold (mu_list_t _list, mu_list_folder_t _fold, void *_data,
+                 void *_init, void *_return_value);
+int mu_list_rfold (mu_list_t _list, mu_list_folder_t _fold, void *_data,
+                  void *_init, void *_return_value);
+  
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/mailutils/sys/imap.h b/include/mailutils/sys/imap.h
index ff23a91..02deead 100644
--- a/include/mailutils/sys/imap.h
+++ b/include/mailutils/sys/imap.h
@@ -45,20 +45,19 @@ extern "C" {
   
 enum mu_imap_client_state
   {
-    MU_IMAP_NO_STATE,
-    MU_IMAP_ERROR,
-    MU_IMAP_CONNECT,
-    MU_IMAP_GREETINGS,
-    MU_IMAP_CONNECTED,
-    MU_IMAP_CAPABILITY_RX,
-    MU_IMAP_LOGIN_RX,
-    MU_IMAP_LOGOUT_RX,
-    MU_IMAP_ID_RX,
-    MU_IMAP_SELECT_RX,
-    MU_IMAP_STATUS_RX,
-    MU_IMAP_NOOP_RX,
-    MU_IMAP_FETCH_RX,
-    MU_IMAP_CLOSING
+    MU_IMAP_CLIENT_READY,
+    MU_IMAP_CLIENT_ERROR,
+    MU_IMAP_CLIENT_CONNECT_RX,
+    MU_IMAP_CLIENT_GREETINGS,
+    MU_IMAP_CLIENT_CAPABILITY_RX,
+    MU_IMAP_CLIENT_LOGIN_RX,
+    MU_IMAP_CLIENT_LOGOUT_RX,
+    MU_IMAP_CLIENT_ID_RX,
+    MU_IMAP_CLIENT_SELECT_RX,
+    MU_IMAP_CLIENT_STATUS_RX,
+    MU_IMAP_CLIENT_NOOP_RX,
+    MU_IMAP_CLIENT_FETCH_RX,
+    MU_IMAP_CLIENT_CLOSING
   };
 
 enum mu_imap_response
@@ -79,8 +78,8 @@ struct _mu_imap
     char *errstr;
     size_t errsize;
     
-    enum mu_imap_state state;
-    enum mu_imap_state imap_state;
+    enum mu_imap_client_state client_state;
+    enum mu_imap_session_state session_state;
 
     /* Tag */
     size_t tag_len;  /* Length of the command tag */
@@ -129,39 +128,41 @@ int _mu_imap_xscript_level (mu_imap_t imap, int xlev);
 
 /* If status indicates an error, return.
   */
-#define MU_IMAP_CHECK_ERROR(imap, status)      \
-  do                                           \
-    {                                          \
-      if (status != 0)                         \
-       {                                       \
-          imap->state = MU_IMAP_ERROR;         \
-          return status;                       \
-       }                                       \
-    }                                          \
+#define MU_IMAP_CHECK_ERROR(imap, status)                      \
+  do                                                           \
+    {                                                          \
+      if (status != 0)                                         \
+       {                                                       \
+          imap->client_state = MU_IMAP_CLIENT_ERROR;           \
+          return status;                                       \
+       }                                                       \
+    }                                                          \
   while (0)
 
 /* Check if status indicates an error.
    If the error is recoverable just return the status.
    Otherwise, set the error state and return the status
  */
-#define MU_IMAP_CHECK_EAGAIN(imap, status)     \
-  do                                           \
-    {                                          \
-      switch (status)                          \
-       {                                       \
-        case 0:                                 \
-         break;                                \
-        case EAGAIN:                            \
-        case EINPROGRESS:                       \
-        case EINTR:                             \
-        case MU_ERR_REPLY:                      \
-        case MU_ERR_BADREPLY:                   \
-         return status;                        \
-        default:                                \
-          imap->state = MU_IMAP_ERROR;         \
-         return status;                        \
-       }                                       \
-    }                                          \
+#define MU_IMAP_CHECK_EAGAIN(imap, status)             \
+  do                                                   \
+    {                                                  \
+      switch (status)                                  \
+       {                                               \
+        case 0:                                                \
+         break;                                        \
+        case EAGAIN:                                   \
+        case EINPROGRESS:                              \
+        case EINTR:                                    \
+         return status;                                \
+        case MU_ERR_REPLY:                             \
+        case MU_ERR_BADREPLY:                          \
+         imap->client_state = MU_IMAP_CLIENT_READY;    \
+         return status;                                \
+        default:                                       \
+          imap->client_state = MU_IMAP_CLIENT_ERROR;   \
+         return status;                                \
+       }                                               \
+    }                                                  \
   while (0)
 
 int _mu_imap_seterrstr (mu_imap_t imap, const char *str, size_t len);
diff --git a/include/mailutils/sys/pop3.h b/include/mailutils/sys/pop3.h
index c727ca8..826dffb 100644
--- a/include/mailutils/sys/pop3.h
+++ b/include/mailutils/sys/pop3.h
@@ -107,8 +107,10 @@ int _mu_pop3_init (mu_pop3_t pop3);
         case EAGAIN:                            \
         case EINPROGRESS:                       \
         case EINTR:                             \
+         return status;                        \
         case MU_ERR_REPLY:                      \
         case MU_ERR_BADREPLY:                   \
+         pop3->state = MU_POP3_NO_STATE;       \
          return status;                        \
         default:                                \
           pop3->state = MU_POP3_ERROR;         \
diff --git a/libmailutils/list/Makefile.am b/libmailutils/list/Makefile.am
index ee6913c..cd17a9e 100644
--- a/libmailutils/list/Makefile.am
+++ b/libmailutils/list/Makefile.am
@@ -25,6 +25,7 @@ liblist_la_SOURCES = \
  create.c\
  destroy.c\
  empty.c\
+ fold.c\
  foreach.c\
  get.c\
  getcomp.c\
@@ -39,6 +40,7 @@ liblist_la_SOURCES = \
  prepend.c\
  remove.c\
  replace.c\
+ rfold.c\
  setcomp.c\
  setdestr.c\
  slice.c\
diff --git a/libmailutils/list/head.c b/libmailutils/list/fold.c
similarity index 68%
copy from libmailutils/list/head.c
copy to libmailutils/list/fold.c
index 7c52b89..1bae72c 100644
--- a/libmailutils/list/head.c
+++ b/libmailutils/list/fold.c
@@ -19,18 +19,28 @@
 # include <config.h>
 #endif
 #include <stdlib.h>
-#include <mailutils/sys/list.h>
 #include <mailutils/errno.h>
+#include <mailutils/sys/list.h>
 
 int
-mu_list_head (mu_list_t list, void **pitem)
+mu_list_fold (mu_list_t list, mu_list_folder_t fold, void *data, void *prev,
+             void *return_value)
 {
-  if (list == NULL)
+  struct list_data *current;
+  int status = 0;
+  
+  if (list == NULL || fold == NULL)
     return EINVAL;
-  if (pitem == NULL)
+  if (return_value == NULL)
     return MU_ERR_OUT_PTR_NULL;
-  if (!list->head.next)
-    return MU_ERR_NOENT;
-  *pitem = list->head.next->item;
-  return 0;
+
+  for (current = list->head.next; current != &list->head;
+       current = current->next)
+    {
+      status = fold (current->item, data, prev, &prev);
+      if (status)
+       break;
+    }
+  *(void **) return_value = prev;
+  return status;
 }
diff --git a/libmailutils/list/gmap.c b/libmailutils/list/gmap.c
index 4a20a44..4c91d10 100644
--- a/libmailutils/list/gmap.c
+++ b/libmailutils/list/gmap.c
@@ -27,28 +27,21 @@ int
 mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data)
 {
   int rc;
-  int status;
-  mu_iterator_t itr;
+  struct list_data *current;
   void **buf;
   size_t i;
   
   if (!list || !map || nelem == 0)
     return EINVAL;
-  rc = mu_list_get_iterator (list, &itr);
-  if (rc)
-    return status;
   buf = calloc (nelem, sizeof (buf[0]));
   if (!buf)
+    return ENOMEM;
+
+  i = 0;
+  for (current = list->head.next; current != &list->head;
+       current = current->next)
     {
-      mu_iterator_destroy (&itr);
-      return ENOMEM;
-    }
-  for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr);
-       mu_iterator_next (itr))
-    {
-      void *item;
-      mu_iterator_current (itr, &item);
-      buf[i++] = item;
+      buf[i++] = current->item;
       if (i == nelem)
        {
          i = 0;
@@ -59,7 +52,6 @@ mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t 
nelem, void *data)
     }
   if (rc == 0 && i > 0 && i < nelem)
     rc = map (buf, i, data);
-  mu_iterator_destroy (&itr);
   free (buf);
   return rc;
 }
diff --git a/libmailutils/list/head.c b/libmailutils/list/rfold.c
similarity index 68%
copy from libmailutils/list/head.c
copy to libmailutils/list/rfold.c
index 7c52b89..4628422 100644
--- a/libmailutils/list/head.c
+++ b/libmailutils/list/rfold.c
@@ -19,18 +19,28 @@
 # include <config.h>
 #endif
 #include <stdlib.h>
-#include <mailutils/sys/list.h>
 #include <mailutils/errno.h>
+#include <mailutils/sys/list.h>
 
 int
-mu_list_head (mu_list_t list, void **pitem)
+mu_list_rfold (mu_list_t list, mu_list_folder_t fold, void *data, void *prev,
+              void *return_value)
 {
-  if (list == NULL)
+  struct list_data *current;
+  int status = 0;
+  
+  if (list == NULL || fold == NULL)
     return EINVAL;
-  if (pitem == NULL)
+  if (return_value == NULL)
     return MU_ERR_OUT_PTR_NULL;
-  if (!list->head.next)
-    return MU_ERR_NOENT;
-  *pitem = list->head.next->item;
-  return 0;
+
+  for (current = list->head.prev; current != &list->head;
+       current = current->prev)
+    {
+      status = fold (current->item, data, prev, &prev);
+      if (status)
+       break;
+    }
+  *(void **) return_value = prev;
+  return status;
 }
diff --git a/libmailutils/tests/list.at b/libmailutils/tests/list.at
index 408e78e..fcc578e 100644
--- a/libmailutils/tests/list.at
+++ b/libmailutils/tests/list.at
@@ -388,6 +388,62 @@ ti
 ])
 
 m4_popdef([MU_TEST_KEYWORDS])
+# ------------------------------------------------------------
+# Fold
+# ------------------------------------------------------------
+
+m4_define([MU_TEST_GROUP],[Fold])
+m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ fold])
+
+TESTLIST([empty list],[],
+[fold
+],
+[NULL
+])
+
+TESTLIST([one element],[],
+[add en
+fold
+],
+[en
+])
+
+TESTLIST([many elements],[],
+[add en to tre fire fem
+fold
+],
+[entotrefirefem
+])
+
+m4_popdef([MU_TEST_KEYWORDS])
+# ------------------------------------------------------------
+# Reverse Fold
+# ------------------------------------------------------------
+
+m4_define([MU_TEST_GROUP],[Reverse Fold])
+m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ rfold])
+
+TESTLIST([empty list],[],
+[rfold
+],
+[NULL
+])
+
+TESTLIST([one element],[],
+[add en
+rfold
+],
+[en
+])
+
+TESTLIST([many elements],[],
+[add en to tre fire fem
+rfold
+],
+[femfiretretoen
+])
+
+m4_popdef([MU_TEST_KEYWORDS])
 
 dnl ------------------------------------------------------------
 dnl Cleanup
diff --git a/libmailutils/tests/listop.c b/libmailutils/tests/listop.c
index 68e59e4..93362ec 100644
--- a/libmailutils/tests/listop.c
+++ b/libmailutils/tests/listop.c
@@ -720,6 +720,60 @@ tail (size_t argc, mu_list_t list)
     printf ("%s\n", text);
 }
 
+static int
+fold_concat (void *item, void *data, void *prev, void **ret)
+{
+  char *s;
+  size_t len = strlen (item);
+  size_t prevlen = 0;
+  
+  if (prev)
+    prevlen = strlen (prev);
+
+  s = realloc (prev, len + prevlen + 1);
+  if (!s)
+    abort ();
+  strcpy (s + prevlen, item);
+  *ret = s;
+  return 0;
+}
+
+void
+fold (mu_list_t list)
+{
+  char *text = NULL;
+  int rc;
+
+  rc = mu_list_fold (list, fold_concat, NULL, NULL, &text);
+  if (rc)
+    mu_diag_funcall (MU_DIAG_ERROR, "mu_list_fold", NULL, rc);
+  else if (text)
+    {
+      printf ("%s\n", text);
+      free (text);
+    }
+  else
+    printf ("NULL\n");
+}
+
+void
+rfold (mu_list_t list)
+{
+  char *text = NULL;
+  int rc;
+
+  rc = mu_list_rfold (list, fold_concat, NULL, NULL, &text);
+  if (rc)
+    mu_diag_funcall (MU_DIAG_ERROR, "mu_list_fold", NULL, rc);
+  else if (text)
+    {
+      printf ("%s\n", text);
+      free (text);
+    }
+  else
+    printf ("NULL\n");
+}
+  
 void
 help ()
 {
@@ -739,6 +793,8 @@ help ()
   printf ("ictl ins item [item*]\n");
   printf ("ictl dir [backwards|forwards]\n");
   printf ("map [-replace] NAME [ARGS]\n");
+  printf ("fold\n");
+  printf ("rfold\n");
   printf ("print\n");
   printf ("slice [-replace] num [num...]\n");
   printf ("quit\n");
@@ -813,6 +869,10 @@ shell (mu_list_t list)
            print (list);
          else if (strcmp (ws.ws_wordv[0], "cur") == 0)
            cur (num, itr[num]);
+         else if (strcmp (ws.ws_wordv[0], "fold") == 0)
+           fold (list);
+         else if (strcmp (ws.ws_wordv[0], "rfold") == 0)
+           rfold (list);
          else if (strcmp (ws.ws_wordv[0], "map") == 0)
            {
              int i;
diff --git a/libproto/imap/capability.c b/libproto/imap/capability.c
index a90d5f9..e4bb4b7 100644
--- a/libproto/imap/capability.c
+++ b/libproto/imap/capability.c
@@ -82,7 +82,8 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t 
*piter)
     return EINVAL;
   if (!imap->io)
     return MU_ERR_NO_TRANSPORT;
-  if (imap->state != MU_IMAP_CONNECTED)
+  if (imap->session_state == MU_IMAP_SESSION_INIT ||
+      imap->client_state != MU_IMAP_CLIENT_READY)
     return MU_ERR_SEQ;
 
   if (imap->capa)
@@ -103,21 +104,21 @@ mu_imap_capability (mu_imap_t imap, int reread, 
mu_iterator_t *piter)
       mu_list_set_destroy_item (imap->capa, mu_list_free_item);
     }
 
-  switch (imap->state)
+  switch (imap->client_state)
     {
-    case MU_IMAP_CONNECTED:
+    case MU_IMAP_CLIENT_READY:
       status = _mu_imap_tag_next (imap);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       status = mu_imapio_printf (imap->io, "%s CAPABILITY\r\n",
                                 imap->tag_str); 
       MU_IMAP_CHECK_EAGAIN (imap, status);
       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
-      imap->state = MU_IMAP_CAPABILITY_RX;
+      imap->client_state = MU_IMAP_CLIENT_CAPABILITY_RX;
 
-    case MU_IMAP_CAPABILITY_RX:
+    case MU_IMAP_CLIENT_CAPABILITY_RX:
       status = _mu_imap_response (imap, _capability_response_action,
                                  NULL);
-      imap->state = MU_IMAP_CONNECTED;
+      imap->client_state = MU_IMAP_CLIENT_READY;
       MU_IMAP_CHECK_EAGAIN (imap, status);
       if (imap->resp_code != MU_IMAP_OK)
        return MU_ERR_REPLY;
@@ -130,7 +131,7 @@ mu_imap_capability (mu_imap_t imap, int reread, 
mu_iterator_t *piter)
        }  
       break;
       
-    case MU_IMAP_ERROR:
+    case MU_IMAP_CLIENT_ERROR:
       status = ECANCELED;
       break;
 
diff --git a/libproto/imap/carrier.c b/libproto/imap/carrier.c
index ecc170c..432f035 100644
--- a/libproto/imap/carrier.c
+++ b/libproto/imap/carrier.c
@@ -49,7 +49,8 @@ mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier)
   imap->io = io;
   if (MU_IMAP_FISSET (imap, MU_IMAP_TRACE))
     _mu_imap_trace_enable (imap);
-  imap->state = MU_IMAP_CONNECT;
+  imap->client_state = MU_IMAP_CLIENT_READY;
+  imap->session_state = MU_IMAP_SESSION_INIT;
   return 0;
 }
 
diff --git a/libproto/imap/connect.c b/libproto/imap/connect.c
index e9be515..7097f17 100644
--- a/libproto/imap/connect.c
+++ b/libproto/imap/connect.c
@@ -45,22 +45,25 @@ mu_imap_connect (mu_imap_t imap)
 
   _mu_imap_clrerrstr (imap);
   
-  switch (imap->state)
+  switch (imap->client_state)
     {
     default:
-    case MU_IMAP_NO_STATE:
-      status = mu_imap_disconnect (imap);
-      if (status != 0)
+    case MU_IMAP_CLIENT_READY:
+      if (imap->session_state != MU_IMAP_SESSION_INIT)
        {
-         /* Sleep for 2 seconds (FIXME: Must be configurable) */
-         struct timeval tval;
-         tval.tv_sec = 2;
-         tval.tv_usec = 0;
-         select (0, NULL, NULL, NULL, &tval);
+         status = mu_imap_disconnect (imap);
+         if (status != 0)
+           {
+             /* Sleep for 2 seconds (FIXME: Must be configurable) */
+             struct timeval tval;
+             tval.tv_sec = 2;
+             tval.tv_usec = 0;
+             select (0, NULL, NULL, NULL, &tval);
+           }
        }
-      imap->state = MU_IMAP_CONNECT;
+      imap->client_state = MU_IMAP_CLIENT_CONNECT_RX;
 
-    case MU_IMAP_CONNECT:
+    case MU_IMAP_CLIENT_CONNECT_RX:
       /* Establish the connection.  */
       if (!mu_stream_is_open (imap->io->_imap_stream))
         {
@@ -68,9 +71,9 @@ mu_imap_connect (mu_imap_t imap)
           MU_IMAP_CHECK_EAGAIN (imap, status);
           MU_IMAP_FCLR (imap, MU_IMAP_RESP);
         }
-      imap->state = MU_IMAP_GREETINGS;
+      imap->client_state = MU_IMAP_CLIENT_GREETINGS;
 
-    case MU_IMAP_GREETINGS:
+    case MU_IMAP_CLIENT_GREETINGS:
       status = mu_imapio_getline (imap->io);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       mu_imapio_get_words (imap->io, &wc, &wv);
@@ -79,7 +82,7 @@ mu_imap_connect (mu_imap_t imap)
          mu_imapio_getbuf (imap->io, &bufptr, &bufsize);
          mu_error ("mu_imap_connect: invalid server response: %s",
                    bufptr);
-         imap->state = MU_IMAP_ERROR;
+         imap->client_state = MU_IMAP_CLIENT_ERROR;
          return MU_ERR_BADREPLY;
        }
       else
@@ -92,18 +95,18 @@ mu_imap_connect (mu_imap_t imap)
          _mu_imap_process_untagged_response (imap, list, NULL, NULL);
          mu_list_destroy (&list);
 
-         switch (imap->state)
+         switch (imap->client_state)
            {
-           case MU_IMAP_CONNECTED:
+           case MU_IMAP_CLIENT_READY:
              status = 0;
              break;
 
-           case MU_IMAP_CLOSING:
+           case MU_IMAP_CLIENT_CLOSING:
              status = EACCES;
              break;
 
            default:
-             imap->state = MU_IMAP_ERROR;
+             imap->client_state = MU_IMAP_CLIENT_ERROR;
              status = MU_ERR_BADREPLY;
            }
        }
diff --git a/libproto/imap/create.c b/libproto/imap/create.c
index 9b2743e..9ae92eb 100644
--- a/libproto/imap/create.c
+++ b/libproto/imap/create.c
@@ -60,6 +60,7 @@ _mu_imap_init (mu_imap_t imap)
       if (rc)
        return rc;
     }
-  imap->state = MU_IMAP_NO_STATE; /* Init with no state.  */
+  imap->client_state = MU_IMAP_CLIENT_READY; 
+  imap->session_state = MU_IMAP_SESSION_INIT;
   return 0;
 }
diff --git a/libproto/imap/disconnect.c b/libproto/imap/disconnect.c
index 7683b26..3863142 100644
--- a/libproto/imap/disconnect.c
+++ b/libproto/imap/disconnect.c
@@ -32,7 +32,7 @@ mu_imap_disconnect (mu_imap_t imap)
   if (imap == NULL)
     return EINVAL;
 
-  imap->state = MU_IMAP_NO_STATE;
+  imap->client_state = MU_IMAP_CLIENT_READY;
   MU_IMAP_FCLR (imap, MU_IMAP_RESP);
 
   mu_list_clear (imap->capa);
diff --git a/libproto/imap/fetch.c b/libproto/imap/fetch.c
index 4b6e65d..1b6a70a 100644
--- a/libproto/imap/fetch.c
+++ b/libproto/imap/fetch.c
@@ -37,24 +37,22 @@ mu_imap_fetch (mu_imap_t imap, const char *msgset, const 
char *items)
     return EINVAL;
   if (!imap->io)
     return MU_ERR_NO_TRANSPORT;
-  if (imap->state != MU_IMAP_CONNECTED)
-    return MU_ERR_SEQ;
 
-  if (imap->imap_state != MU_IMAP_STATE_SELECTED)
+  if (imap->session_state != MU_IMAP_SESSION_SELECTED)
     return MU_ERR_SEQ;
   
-  switch (imap->state)
+  switch (imap->client_state)
     {
-    case MU_IMAP_CONNECTED:
+    case MU_IMAP_CLIENT_READY:
       status = _mu_imap_tag_next (imap);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       status = mu_imapio_printf (imap->io, "%s FETCH %s %s\r\n",
                                 imap->tag_str, msgset, items);
       MU_IMAP_CHECK_ERROR (imap, status);
       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
-      imap->state = MU_IMAP_FETCH_RX;
+      imap->client_state = MU_IMAP_CLIENT_FETCH_RX;
 
-    case MU_IMAP_FETCH_RX:
+    case MU_IMAP_CLIENT_FETCH_RX:
       status = _mu_imap_response (imap, NULL, NULL);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       switch (imap->resp_code)
@@ -71,7 +69,7 @@ mu_imap_fetch (mu_imap_t imap, const char *msgset, const char 
*items)
          status = MU_ERR_BADREPLY;
          break;
        }
-      imap->state = MU_IMAP_CONNECTED;
+      imap->client_state = MU_IMAP_CLIENT_READY;
       break;
 
     default:
@@ -88,7 +86,8 @@ _free_fetch_response (void *ptr)
     {
     case MU_IMAP_FETCH_BODY:
       free (resp->body.partv);
-      free (resp->body.key);
+      free (resp->body.section);
+      mu_list_destroy (&resp->body.fields);
       free (resp->body.text);
       break;
       
@@ -141,87 +140,112 @@ alloc_response (union mu_imap_fetch_response **resp, int 
type)
   return 0;
 }
 
-static int
-_uid_mapper (struct imap_list_element **elt,
-            union mu_imap_fetch_response **return_resp)
+enum parse_response_state
+  {
+    resp_kw,
+    resp_val,
+    resp_body,
+    resp_body_section,
+    resp_skip,
+    resp_body_hlist,
+    resp_body_end
+  };
+
+struct parse_response_env;
+
+typedef int (*mapper_fn) (union mu_imap_fetch_response *resp,
+                         struct imap_list_element *elt,
+                         struct parse_response_env *env);
+
+struct parse_response_env
 {
+  mu_list_t result;
+  struct imap_list_element *elt;
+  enum parse_response_state state;
   union mu_imap_fetch_response *resp;
-  int rc;
+  mapper_fn mapper;
+  const char *section;
+  mu_list_t hlist;
+  int status;
+};
+
+
+static int
+_uid_mapper (union mu_imap_fetch_response *resp,
+            struct imap_list_element *elt,
+            struct parse_response_env *parse_env)
+{
   char *p;
   size_t uid;
   
-  if (elt[1]->type != imap_eltype_string)
+  if (elt->type != imap_eltype_string)
     return MU_ERR_FAILURE;
-  uid = strtoul (elt[1]->v.string, &p, 0);
+  uid = strtoul (elt->v.string, &p, 0);
   if (*p)
     return MU_ERR_FAILURE;
-  rc = alloc_response (&resp, MU_IMAP_FETCH_UID);
-  if (rc)
-    return rc;
   resp->uid.uid = uid;
-  *return_resp = resp;
   return 0;
 }
                        
 static int
-_size_mapper (struct imap_list_element **elt,
-             union mu_imap_fetch_response **return_resp)
+_size_mapper (union mu_imap_fetch_response *resp,
+             struct imap_list_element *elt,
+             struct parse_response_env *parse_env)
 {
-  union mu_imap_fetch_response *resp;
-  int rc;
   char *p;
   size_t size;
   
-  if (elt[1]->type != imap_eltype_string)
+  if (elt->type != imap_eltype_string)
     return MU_ERR_FAILURE;
-  size = strtoul (elt[1]->v.string, &p, 0);
+  size = strtoul (elt->v.string, &p, 0);
   if (*p)
     return MU_ERR_FAILURE;
-  rc = alloc_response (&resp, MU_IMAP_FETCH_RFC822_SIZE);
-  if (rc)
-    return rc;
   resp->rfc822_size.size = size;
-  *return_resp = resp;
   return 0;
 }
 
 static int
-_body_mapper (struct imap_list_element **elt,
-             union mu_imap_fetch_response **return_resp)
+_body_mapper (union mu_imap_fetch_response *resp,
+             struct imap_list_element *elt,
+             struct parse_response_env *parse_env)
 {
-  union mu_imap_fetch_response *resp;
-  int rc;
-  char *section, *p;
+  const char *section, *p;
   size_t partc = 0;
   size_t *partv = NULL;
   
-  if (elt[1]->type != imap_eltype_string)
+  if (elt->type != imap_eltype_string)
     return MU_ERR_FAILURE;
-  rc = alloc_response (&resp, MU_IMAP_FETCH_BODY);
-  if (rc)
-    return rc;
 
-  section = strchr (elt[0]->v.string, '[');
+  section = parse_env->section;
   if (section)
     {
       p = section;
-      while (1)
+      while (mu_isdigit (*p))
        {
+         partc++;
          p = strchr (p, '.');
-         if (*p)
+         if (p)
            {
              p++;
-             if (mu_isdigit (p[1]))
-               {
-                 partc++;
-                 continue;
-               }
+             continue;
            }
          
          break;
        }
     }
-  
+  else
+    p = NULL;
+
+  if (p)
+    {
+      resp->body.section = strdup (p);
+      if (!resp->body.section)
+       {
+         free (resp);
+         return ENOMEM;
+       }
+    }
+
   if (partc)
     {
       size_t i;
@@ -237,51 +261,33 @@ _body_mapper (struct imap_list_element **elt,
   resp->body.partc = partc;
   resp->body.partv = partv;
 
-  if (p)
-    {
-      size_t len = strlen (p);
-      resp->body.key = malloc (len);
-      if (!resp->body.key)
-       {
-         free (resp->body.partv);
-         free (resp);
-         return ENOMEM;
-       }
-      len--;
-      memcpy (resp->body.key, p, len);
-      resp->body.key[len] = 0;
-    }
+  resp->body.fields = parse_env->hlist;
+  parse_env->hlist = NULL;
   
-  resp->body.text = strdup (elt[1]->v.string);
+  resp->body.text = strdup (elt->v.string);
   if (!resp->body.text)
     {
-      free (resp->body.key);
+      free (resp->body.section);
       free (resp->body.partv);
       free (resp);
       return ENOMEM;
     }
-  *return_resp = resp;
   return 0;
 }
 
 static int
-_rfc822_mapper (const char *key, struct imap_list_element *elt,
-               union mu_imap_fetch_response **return_resp)
+_rfc822_mapper (union mu_imap_fetch_response *resp,
+               struct imap_list_element *elt,
+               struct parse_response_env *parse_env)
 {
-  union mu_imap_fetch_response *resp;
-  int rc;
-  
   if (elt->type != imap_eltype_string)
     return MU_ERR_FAILURE;
-  rc = alloc_response (&resp, MU_IMAP_FETCH_BODY);
-  if (rc)
-    return rc;
 
   resp->body.partc = 0;
   resp->body.partv = NULL;
 
-  resp->body.key = strdup (key);
-  if (!resp->body.key)
+  resp->body.section = strdup (parse_env->section);
+  if (!resp->body.section)
     {
       free (resp);
       return ENOMEM;
@@ -290,72 +296,66 @@ _rfc822_mapper (const char *key, struct imap_list_element 
*elt,
   resp->body.text = strdup (elt->v.string);
   if (!resp->body.text)
     {
-      free (resp->body.key);
+      free (resp->body.section);
       free (resp->body.partv);
       free (resp);
       return ENOMEM;
     }
-  *return_resp = resp;
   return 0;
 }
 
 static int
-_rfc822_header_mapper (struct imap_list_element **elt,
-                      union mu_imap_fetch_response **return_resp)
+_rfc822_header_mapper (union mu_imap_fetch_response *resp,
+                      struct imap_list_element *elt,
+                      struct parse_response_env *parse_env)
 {
-  return _rfc822_mapper ("HEADER", elt[1], return_resp);
+  parse_env->section = "HEADER";
+  return _rfc822_mapper (resp, elt, parse_env);
 }
 
 static int
-_rfc822_text_mapper (struct imap_list_element **elt,
-                    union mu_imap_fetch_response **return_resp)
+_rfc822_text_mapper (union mu_imap_fetch_response *resp,
+                    struct imap_list_element *elt,
+                    struct parse_response_env *parse_env)
 {
-  return _rfc822_mapper ("TEXT", elt[1], return_resp);
+  parse_env->section = "TEXT";
+  return _rfc822_mapper (resp, elt, parse_env);
 }
 
 static int
-_flags_mapper (struct imap_list_element **elt,
-              union mu_imap_fetch_response **return_resp)
+_flags_mapper (union mu_imap_fetch_response *resp,
+              struct imap_list_element *elt,
+              struct parse_response_env *parse_env)
 {
-  union mu_imap_fetch_response *resp;
-  int rc;
-  int flags;
-  
-  if (elt[1]->type != imap_eltype_list)
+  if (elt->type != imap_eltype_list)
     return MU_ERR_FAILURE;
-  if (_mu_imap_collect_flags (elt[1], &flags))
+  if (_mu_imap_collect_flags (elt, &resp->flags.flags))
     return MU_ERR_FAILURE;
-
-  rc = alloc_response (&resp, MU_IMAP_FETCH_FLAGS);
-  if (rc)
-    return rc;
-  resp->flags.flags = flags;
-  *return_resp = resp;
   return 0;
 }
 
 static int
-_date_mapper (struct imap_list_element **elt,
-             union mu_imap_fetch_response **return_resp)
+_date_mapper (union mu_imap_fetch_response *resp,
+             struct imap_list_element *elt,
+             struct parse_response_env *parse_env)
 {
-  struct mu_imap_fetch_internaldate idate;
-  union mu_imap_fetch_response *resp;
-  int rc;
   const char *p;
+  struct tm tm;
+  struct mu_timezone tz;
   
-  if (elt[1]->type != imap_eltype_string)
+  if (elt->type != imap_eltype_string)
     return MU_ERR_FAILURE;
-  p = elt[1]->v.string;
-  if (mu_parse_imap_date_time (&p, &idate.tm, &idate.tz))
+  p = elt->v.string;
+  if (mu_parse_imap_date_time (&p, &tm, &tz))
     return MU_ERR_FAILURE;
-  rc = alloc_response (&resp, MU_IMAP_FETCH_INTERNALDATE);
-  if (rc)
-    return rc;
-  resp->internaldate = idate;
-  *return_resp = resp;
+  resp->internaldate.tm = tm;
+  resp->internaldate.tz = tz;
   return 0;
 }
 
+/* FIXME */
+#define _bodystructure_mapper NULL
+
 struct fill_env
 {
   struct mu_imap_fetch_envelope *envelope;
@@ -522,23 +522,17 @@ _fill_response (void *item, void *data)
 }
   
 static int
-_envelope_mapper (struct imap_list_element **elt,
-                 union mu_imap_fetch_response **return_resp)
+_envelope_mapper (union mu_imap_fetch_response *resp,
+                 struct imap_list_element *elt,
+                 struct parse_response_env *parse_env)
 {
-  union mu_imap_fetch_response *resp;
-  int rc;
   struct fill_env env;
   
-  if (elt[1]->type != imap_eltype_list)
+  if (elt->type != imap_eltype_list)
     return MU_ERR_FAILURE;
-  rc = alloc_response (&resp, MU_IMAP_FETCH_ENVELOPE);
-  if (rc)
-    return rc;
   env.envelope = &resp->envelope;
   env.n = 0;
-  mu_list_foreach (elt[1]->v.list, _fill_response, &env);
-  
-  *return_resp = resp;
+  mu_list_foreach (elt->v.list, _fill_response, &env);
   return 0;
 }
 
@@ -546,81 +540,146 @@ struct mapper_tab
 {
   char *name;
   size_t size;
-  int prefix;
-  int (*mapper) (struct imap_list_element **, union mu_imap_fetch_response **);
+  int type;
+  mapper_fn mapper;
 };
   
 static struct mapper_tab mapper_tab[] = {
 #define S(s) s, (sizeof (s) - 1)
-  { S("BODYSTRUCTURE"), 0, },
-  { S("BODY["),         1, _body_mapper },
-  { S("BODY"),          0, _body_mapper },
-  { S("ENVELOPE"),      0, _envelope_mapper },
-  { S("FLAGS"),         0, _flags_mapper },
-  { S("INTERNALDATE"),  0, _date_mapper },
-  { S("RFC822"),        0, _body_mapper},
-  { S("RFC822.HEADER"), 0, _rfc822_header_mapper }, 
-  { S("RFC822.SIZE"),   0, _size_mapper },
-  { S("RFC822.TEXT"),   0, _rfc822_text_mapper },
-  { S("UID"),           0, _uid_mapper },
+  { S("BODYSTRUCTURE"), },
+  { S("BODY"),          MU_IMAP_FETCH_BODY,        _body_mapper },
+  { S("ENVELOPE"),      MU_IMAP_FETCH_ENVELOPE,    _envelope_mapper },
+  { S("FLAGS"),         MU_IMAP_FETCH_FLAGS,       _flags_mapper },
+  { S("INTERNALDATE"),  MU_IMAP_FETCH_INTERNALDATE, _date_mapper },
+  { S("RFC822"),        MU_IMAP_FETCH_BODY,        _body_mapper},
+  { S("RFC822.HEADER"), MU_IMAP_FETCH_BODY,        _rfc822_header_mapper }, 
+  { S("RFC822.SIZE"),   MU_IMAP_FETCH_RFC822_SIZE, _size_mapper },
+  { S("RFC822.TEXT"),   MU_IMAP_FETCH_BODY,        _rfc822_text_mapper },
+  { S("UID"),           MU_IMAP_FETCH_UID,         _uid_mapper },
 #undef S
   { NULL }
 };
-  
+
 static int
-_fetch_mapper (void **itmv, size_t itmc, void *call_data)
+_extract_string (void **itmv, size_t itmc, void *call_data)
 {
-  int *status = call_data;
-  struct mapper_tab *mt;
-  struct imap_list_element *elt[2];
-  char *kw;
-  size_t kwlen;
-  union mu_imap_fetch_response *resp;
+  struct imap_list_element *elt = itmv[0];
+  if (elt->type != imap_eltype_string)
+    return MU_LIST_MAP_SKIP;
+  itmv[0] = elt->v.string;
+  return 0;
+}
 
-  elt[0] = itmv[0];
-  elt[1] = itmv[1];
-  
-  if (elt[0]->type != imap_eltype_string)
-    {
-      *status = MU_ERR_FAILURE;
-      return MU_LIST_MAP_STOP|MU_LIST_MAP_SKIP;
-    }
-  kw = elt[0]->v.string;
-  kwlen = strlen (kw);
-  for (mt = mapper_tab; mt->name; mt++)
+static int
+_fetch_fold (void *item, void *data)
+{
+  struct imap_list_element *elt = item;
+  struct parse_response_env *env = data;
+
+  switch (env->state)
     {
-      if (mt->prefix)
+    case resp_kw:
+      {
+       int rc;
+       char *kw;
+       size_t kwlen;
+       struct mapper_tab *mt;
+
+       if (elt->type != imap_eltype_string)
+         {
+           env->status = MU_ERR_FAILURE;
+           return MU_ERR_FAILURE;
+         }
+       kw = elt->v.string;
+       kwlen = strlen (kw);
+       for (mt = mapper_tab; mt->name; mt++)
+         {
+           if (mt->size == kwlen && memcmp (mt->name, kw, kwlen) == 0)
+             break;
+         }
+
+       if (!mt->name)
+         {
+           mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE9,
+                     ("ignoring unknown FETCH item '%s'", kw));
+           env->state = resp_skip;
+           return 0;
+         }
+
+       env->mapper = mt->mapper;
+       rc = alloc_response (&env->resp, mt->type);
+       if (rc)
+         {
+           env->status = rc;
+           return MU_ERR_FAILURE;
+         }
+       env->state = mt->type == MU_IMAP_FETCH_BODY ? resp_body : resp_val;
+       break;
+      }
+      
+    case resp_val:
+      if (env->mapper)
        {
-         if (mt->size >= kwlen && memcmp (mt->name, kw, kwlen) == 0)
-           break;
+         int rc = env->mapper (env->resp, elt, env);
+         if (rc)
+           _free_fetch_response (env->resp);
+         else
+           mu_list_append (env->result, env->resp);
        }
-      else if (mt->size == kwlen && memcmp (mt->name, kw, kwlen) == 0)
-       break;
-    }
-
-  if (!mt->name)
-    {
-      mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE9,
-               ("ignoring unknown FETCH item '%s'", kw));
-      return MU_LIST_MAP_SKIP;
-    }
-
-  if (mt->mapper)
-    {
-      int rc = mt->mapper (elt, &resp);
-      if (rc == 0)
+      env->resp = NULL;
+      mu_list_destroy (&env->hlist);
+      env->state = resp_kw;
+      break;
+      
+    case resp_body:
+      if (_mu_imap_list_element_is_string (elt, "["))
+       env->state = resp_body_section;
+      else
+       {
+         env->mapper = _bodystructure_mapper;
+         env->state = resp_val;
+       }
+      break;
+      
+    case resp_body_section:
+      if (elt->type != imap_eltype_string)
+       {
+         env->status = MU_ERR_PARSE;
+         return MU_ERR_FAILURE;
+       }
+      else if (strncmp (elt->v.string, "HEADER.FIELDS", 13) == 0)
+       env->state = resp_body_hlist;
+      else
+       env->state = resp_body_end;
+      env->section = elt->v.string;
+      break;
+      
+    case resp_skip:
+      mu_list_destroy (&env->hlist);
+      env->state = resp_kw;
+      break;
+      
+    case resp_body_hlist:
+      if (elt->type != imap_eltype_list)
        {
-         itmv[0] = resp;
-         return MU_LIST_MAP_OK;
+         env->status = MU_ERR_PARSE;
+         return MU_ERR_FAILURE;
        }
+      mu_list_map (elt->v.list, _extract_string, NULL, 1, &env->hlist);
+      env->state = resp_body_end;
+      break;
+      
+    case resp_body_end:
+      if (_mu_imap_list_element_is_string (elt, "]"))
+       env->state = resp_val;
       else
        {
-         *status = rc;
-         return MU_LIST_MAP_STOP|MU_LIST_MAP_SKIP;
+         env->status = MU_ERR_PARSE;
+         return MU_ERR_FAILURE;
        }
     }
-      
-  return MU_LIST_MAP_SKIP;
+  
+  return 0;
 }
 
 int
@@ -628,7 +687,8 @@ _mu_imap_parse_fetch_response (mu_list_t input, mu_list_t 
*result_list)
 {
   mu_list_t result;
   int status;
-
+  struct parse_response_env env;
+  
   status = mu_list_create (&result);
   if (status)
     {
@@ -637,11 +697,14 @@ _mu_imap_parse_fetch_response (mu_list_t input, mu_list_t 
*result_list)
       return 1;
     }
   mu_list_set_destroy_item (result, _free_fetch_response);
-  mu_list_map (input, _fetch_mapper, &status, 2, &result);
-  if (status)
+  memset (&env, 0, sizeof (env));
+
+  env.result = result;
+  mu_list_foreach (input, _fetch_fold, &env);
+  if (env.status)
     mu_list_destroy (&result);
   else
     *result_list = result;
-  
+  mu_list_destroy (&env.hlist);
   return status;
 }
diff --git a/libproto/imap/id.c b/libproto/imap/id.c
index 05938ab..487ecf3 100644
--- a/libproto/imap/id.c
+++ b/libproto/imap/id.c
@@ -84,12 +84,12 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t 
*passoc)
     return EINVAL;
   if (!imap->io)
     return MU_ERR_NO_TRANSPORT;
-  if (imap->state != MU_IMAP_CONNECTED)
+  if (imap->session_state == MU_IMAP_SESSION_INIT)
     return MU_ERR_SEQ;
-
-  switch (imap->state)
+  
+  switch (imap->client_state)
     {
-    case MU_IMAP_CONNECTED:
+    case MU_IMAP_CLIENT_READY:
       status = _mu_imap_tag_next (imap);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       status = mu_imapio_printf (imap->io, "%s ID ", imap->tag_str);
@@ -121,9 +121,9 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t 
*passoc)
       status = mu_imapio_printf (imap->io, "\r\n");
       MU_IMAP_CHECK_ERROR (imap, status);
       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
-      imap->state = MU_IMAP_ID_RX;
+      imap->client_state = MU_IMAP_CLIENT_ID_RX;
 
-    case MU_IMAP_ID_RX:
+    case MU_IMAP_CLIENT_ID_RX:
       status = _mu_imap_response (imap, parse_id_reply, passoc);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       switch (imap->resp_code)
@@ -140,7 +140,7 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t 
*passoc)
          status = MU_ERR_BADREPLY;
          break;
        }
-      imap->state = MU_IMAP_CONNECTED;
+      imap->client_state = MU_IMAP_CLIENT_READY;
       break;
 
     default:
diff --git a/libproto/imap/login.c b/libproto/imap/login.c
index b0d3597..2a8f363 100644
--- a/libproto/imap/login.c
+++ b/libproto/imap/login.c
@@ -33,14 +33,12 @@ mu_imap_login (mu_imap_t imap, const char *user, const char 
*pass)
     return EINVAL;
   if (!imap->io)
     return MU_ERR_NO_TRANSPORT;
-  if (imap->state != MU_IMAP_CONNECTED)
-    return MU_ERR_SEQ;
-  if (imap->imap_state != MU_IMAP_STATE_NONAUTH)
+  if (imap->session_state != MU_IMAP_SESSION_NONAUTH)
     return MU_ERR_SEQ;
   
-  switch (imap->state)
+  switch (imap->client_state)
     {
-    case MU_IMAP_CONNECTED:
+    case MU_IMAP_CLIENT_READY:
       if (mu_imap_trace_mask (imap, MU_IMAP_TRACE_QRY, MU_XSCRIPT_SECURE))
        _mu_imap_xscript_level (imap, MU_XSCRIPT_SECURE);
       status = _mu_imap_tag_next (imap);
@@ -51,16 +49,16 @@ mu_imap_login (mu_imap_t imap, const char *user, const char 
*pass)
       /* FIXME: how to obscure the passwd in the stream buffer? */
       MU_IMAP_CHECK_EAGAIN (imap, status);
       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
-      imap->state = MU_IMAP_LOGIN_RX;
+      imap->client_state = MU_IMAP_CLIENT_LOGIN_RX;
 
-    case MU_IMAP_LOGIN_RX:
+    case MU_IMAP_CLIENT_LOGIN_RX:
       status = _mu_imap_response (imap, NULL, NULL);
-      imap->state = MU_IMAP_CONNECTED;
+      imap->client_state = MU_IMAP_CLIENT_READY;
       MU_IMAP_CHECK_EAGAIN (imap, status);
       switch (imap->resp_code)
        {
        case MU_IMAP_OK:
-         imap->imap_state = MU_IMAP_STATE_AUTH;
+         imap->session_state = MU_IMAP_SESSION_AUTH;
          break;
 
        case MU_IMAP_NO:
diff --git a/libproto/imap/logout.c b/libproto/imap/logout.c
index 11bef62..e91e1ce 100644
--- a/libproto/imap/logout.c
+++ b/libproto/imap/logout.c
@@ -32,25 +32,26 @@ mu_imap_logout (mu_imap_t imap)
     return EINVAL;
   if (!imap->io)
     return MU_ERR_NO_TRANSPORT;
-  if (imap->state != MU_IMAP_CONNECTED)
+  if (!(imap->session_state == MU_IMAP_SESSION_AUTH ||
+       imap->session_state == MU_IMAP_SESSION_SELECTED))
     return MU_ERR_SEQ;
 
-  switch (imap->state)
+  switch (imap->client_state)
     {
-    case MU_IMAP_CONNECTED:
+    case MU_IMAP_CLIENT_READY:
       status = _mu_imap_tag_next (imap);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       status = mu_imapio_printf (imap->io, "%s LOGOUT\r\n",
                                 imap->tag_str); 
       MU_IMAP_CHECK_EAGAIN (imap, status);
       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
-      imap->state = MU_IMAP_LOGOUT_RX;
+      imap->client_state = MU_IMAP_CLIENT_LOGOUT_RX;
 
-    case MU_IMAP_LOGOUT_RX:
+    case MU_IMAP_CLIENT_LOGOUT_RX:
       status = _mu_imap_response (imap, NULL, NULL);
       MU_IMAP_CHECK_EAGAIN (imap, status);
-      imap->state = MU_IMAP_NO_STATE;
-      imap->imap_state = MU_IMAP_STATE_LOGOUT;
+      imap->client_state = MU_IMAP_CLIENT_READY;
+      imap->session_state = MU_IMAP_SESSION_LOGOUT;
       break;
 
     default:
diff --git a/libproto/imap/noop.c b/libproto/imap/noop.c
index 6d7accc..a4b22e7 100644
--- a/libproto/imap/noop.c
+++ b/libproto/imap/noop.c
@@ -33,20 +33,20 @@ mu_imap_noop (mu_imap_t imap)
     return EINVAL;
   if (!imap->io)
     return MU_ERR_NO_TRANSPORT;
-  if (imap->state != MU_IMAP_CONNECTED)
+  if (imap->session_state == MU_IMAP_SESSION_INIT)
     return MU_ERR_SEQ;
 
-  switch (imap->state)
+  switch (imap->client_state)
     {
-    case MU_IMAP_CONNECTED:
+    case MU_IMAP_CLIENT_READY:
       status = _mu_imap_tag_next (imap);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       status = mu_imapio_printf (imap->io, "%s NOOP\r\n", imap->tag_str);
       MU_IMAP_CHECK_ERROR (imap, status);
       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
-      imap->state = MU_IMAP_NOOP_RX;
+      imap->client_state = MU_IMAP_CLIENT_NOOP_RX;
 
-    case MU_IMAP_NOOP_RX:
+    case MU_IMAP_CLIENT_NOOP_RX:
       status = _mu_imap_response (imap, NULL, NULL);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       switch (imap->resp_code)
@@ -63,7 +63,7 @@ mu_imap_noop (mu_imap_t imap)
          status = MU_ERR_BADREPLY;
          break;
        }
-      imap->state = MU_IMAP_CONNECTED;
+      imap->client_state = MU_IMAP_CLIENT_READY;
       break;
 
     default:
diff --git a/libproto/imap/resplist.c b/libproto/imap/resplist.c
index 98b8a22..cca7f33 100644
--- a/libproto/imap/resplist.c
+++ b/libproto/imap/resplist.c
@@ -64,7 +64,7 @@ _new_imap_list_element (mu_imap_t imap, enum imap_eltype type)
   struct imap_list_element *elt = calloc (1, sizeof (*elt));
   if (!elt)
     {
-      imap->state = MU_IMAP_ERROR;
+      imap->client_state = MU_IMAP_CLIENT_ERROR;
     }
   else
     elt->type = type;
@@ -238,7 +238,7 @@ _mu_imap_untagged_response_to_list (mu_imap_t imap, 
mu_list_t *plist)
     {
       if (elt)
        _imap_list_free (elt);
-      imap->state = MU_IMAP_ERROR;
+      imap->client_state = MU_IMAP_CLIENT_ERROR;
       return pb.pb_err;
     }
   *plist = elt->v.list;
diff --git a/libproto/imap/response.c b/libproto/imap/response.c
index 653b074..c74f656 100644
--- a/libproto/imap/response.c
+++ b/libproto/imap/response.c
@@ -59,7 +59,7 @@ _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t 
fun,
          mu_imapio_get_words (imap->io, &wc, &wv);
          if (wc == 0)
            {
-             imap->state = MU_IMAP_ERROR;
+             imap->client_state = MU_IMAP_CLIENT_ERROR;
              status = MU_ERR_BADREPLY;/* FIXME: ECONNRESET ? */
              break;
            }
@@ -80,7 +80,7 @@ _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t 
fun,
              /* Handle the tagged response */
              if (wc < 2)
                {
-                 /*imap->state = MU_IMAP_ERROR;*/
+                 /*imap->client_state = MU_IMAP_CLIENT_ERROR;*/
                  status = MU_ERR_BADREPLY;
                }
              else if (strcmp (wv[1], "OK") == 0)
@@ -104,12 +104,12 @@ _mu_imap_response (mu_imap_t imap, 
mu_imap_response_action_t fun,
            }
          else
            {
-             imap->state = MU_IMAP_ERROR;
+             imap->client_state = MU_IMAP_CLIENT_ERROR;
              status = MU_ERR_BADREPLY;
            }
        }
       else
-       imap->state = MU_IMAP_ERROR;
+       imap->client_state = MU_IMAP_CLIENT_ERROR;
       break;
     }
   return status;
diff --git a/libproto/imap/resproc.c b/libproto/imap/resproc.c
index 373e258..2aac6a4 100644
--- a/libproto/imap/resproc.c
+++ b/libproto/imap/resproc.c
@@ -143,10 +143,10 @@ ok_response (mu_imap_t imap, mu_list_t resp, void *data)
   if (mu_list_tail (resp, (void*) &arg) || arg->type != imap_eltype_string)
     arg = NULL;
   mu_imap_callback (imap, MU_IMAP_CB_OK, rcode, arg ? arg->v.string : NULL);
-  if (imap->state == MU_IMAP_GREETINGS)
+  if (imap->client_state == MU_IMAP_CLIENT_GREETINGS)
     {
-      imap->state = MU_IMAP_CONNECTED;
-      imap->imap_state = MU_IMAP_STATE_NONAUTH;
+      imap->client_state = MU_IMAP_CLIENT_READY;
+      imap->session_state = MU_IMAP_SESSION_NONAUTH;
     }
 }
 
@@ -165,29 +165,29 @@ static void
 no_response (mu_imap_t imap, mu_list_t resp, void *data)
 {
   default_response (imap, MU_IMAP_CB_NO, resp, data);
-  if (imap->state == MU_IMAP_GREETINGS)
-    imap->state = MU_IMAP_ERROR;
+  if (imap->client_state == MU_IMAP_CLIENT_GREETINGS)
+    imap->client_state = MU_IMAP_CLIENT_ERROR;
 }
 
 static void
 bad_response (mu_imap_t imap, mu_list_t resp, void *data)
 {
   default_response (imap, MU_IMAP_CB_BAD, resp, data);
-  if (imap->state == MU_IMAP_GREETINGS)
-    imap->state = MU_IMAP_ERROR;
+  if (imap->client_state == MU_IMAP_CLIENT_GREETINGS)
+    imap->client_state = MU_IMAP_CLIENT_ERROR;
 }
 
 static void
 bye_response (mu_imap_t imap, mu_list_t resp, void *data)
 {
   default_response (imap, MU_IMAP_CB_BYE, resp, data);
-  imap->state = MU_IMAP_CLOSING;
+  imap->client_state = MU_IMAP_CLIENT_CLOSING;
 }
 
 static void
 preauth_response (mu_imap_t imap, mu_list_t resp, void *data)
 {
-  if (imap->state == MU_IMAP_GREETINGS)
+  if (imap->client_state == MU_IMAP_CLIENT_GREETINGS)
     {
       struct imap_list_element *arg;
 
@@ -196,8 +196,8 @@ preauth_response (mu_imap_t imap, mu_list_t resp, void 
*data)
       mu_imap_callback (imap, MU_IMAP_CB_PREAUTH,
                        parse_response_code (imap, resp),
                        arg ? arg->v.string : NULL);
-      imap->state = MU_IMAP_CONNECTED;
-      imap->imap_state = MU_IMAP_STATE_AUTH;
+      imap->client_state = MU_IMAP_CLIENT_READY;
+      imap->session_state = MU_IMAP_SESSION_AUTH;
     }
   else
     mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
diff --git a/libproto/imap/select.c b/libproto/imap/select.c
index 5d30db3..be19668 100644
--- a/libproto/imap/select.c
+++ b/libproto/imap/select.c
@@ -43,6 +43,7 @@ _mu_imap_collect_flags (struct imap_list_element *arg, int 
*res)
 {
   if (arg->type != imap_eltype_list)
     return EINVAL;
+  *res = 0;
   mu_list_foreach (arg->v.list, _collect_flags, res);
   return 0;
 }
@@ -72,15 +73,13 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int 
writable,
     return EINVAL;
   if (!imap->io)
     return MU_ERR_NO_TRANSPORT;
-  if (imap->state != MU_IMAP_CONNECTED)
-    return MU_ERR_SEQ;
-  if (imap->imap_state != MU_IMAP_STATE_AUTH &&
-      imap->imap_state != MU_IMAP_STATE_SELECTED)
+  if (imap->session_state != MU_IMAP_SESSION_AUTH &&
+      imap->session_state != MU_IMAP_SESSION_SELECTED)
     return MU_ERR_SEQ;
 
   if (!mbox)
     {
-      if (imap->imap_state == MU_IMAP_STATE_SELECTED)
+      if (imap->session_state == MU_IMAP_SESSION_SELECTED)
        {
          if (ps)
            *ps = imap->mbox_stat;
@@ -97,9 +96,9 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int 
writable,
       return 0;
     }
   
-  switch (imap->state)
+  switch (imap->client_state)
     {
-    case MU_IMAP_CONNECTED:
+    case MU_IMAP_CLIENT_READY:
       status = _mu_imap_tag_next (imap);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       status = mu_imapio_printf (imap->io, "%s %s %s\r\n",
@@ -108,21 +107,21 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int 
writable,
                                 mbox);
       MU_IMAP_CHECK_ERROR (imap, status);
       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
-      imap->state = MU_IMAP_SELECT_RX;
+      imap->client_state = MU_IMAP_CLIENT_SELECT_RX;
 
-    case MU_IMAP_SELECT_RX:
+    case MU_IMAP_CLIENT_SELECT_RX:
       memset (&imap->mbox_stat, 0, sizeof (imap->mbox_stat));
       status = _mu_imap_response (imap, _select_response_action, NULL);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       switch (imap->resp_code)
        {
        case MU_IMAP_OK:
-         imap->imap_state = MU_IMAP_STATE_SELECTED;
+         imap->session_state = MU_IMAP_SESSION_SELECTED;
          free (imap->mbox_name);
          imap->mbox_name = strdup (mbox);
          if (!imap->mbox_name)
            {
-             imap->state = MU_IMAP_ERROR;
+             imap->client_state = MU_IMAP_CLIENT_ERROR;
              return errno;
            }
          imap->mbox_writable = writable;
@@ -138,7 +137,7 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int 
writable,
          status = MU_ERR_BADREPLY;
          break;
        }
-      imap->state = MU_IMAP_CONNECTED;
+      imap->client_state = MU_IMAP_CLIENT_READY;
       break;
 
     default:
diff --git a/libproto/imap/state.c b/libproto/imap/state.c
index b77f0c2..a957aa1 100644
--- a/libproto/imap/state.c
+++ b/libproto/imap/state.c
@@ -36,7 +36,7 @@ mu_imap_state (mu_imap_t imap, int *pstate)
 {
   if (imap == NULL || pstate == NULL)
     return EINVAL;
-  *pstate = imap->imap_state;
+  *pstate = imap->session_state;
   return 0;
 }
 
diff --git a/libproto/imap/status.c b/libproto/imap/status.c
index b8969ce..7a3a287 100644
--- a/libproto/imap/status.c
+++ b/libproto/imap/status.c
@@ -126,10 +126,8 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, 
struct mu_imap_stat *ps)
     return EINVAL;
   if (!imap->io)
     return MU_ERR_NO_TRANSPORT;
-  if (imap->state != MU_IMAP_CONNECTED)
-    return MU_ERR_SEQ;
-  if (imap->imap_state != MU_IMAP_STATE_AUTH &&
-      imap->imap_state != MU_IMAP_STATE_SELECTED)
+  if (imap->session_state != MU_IMAP_SESSION_AUTH &&
+      imap->session_state != MU_IMAP_SESSION_SELECTED)
     return MU_ERR_SEQ;
   if (!ps)
     return MU_ERR_OUT_PTR_NULL;
@@ -138,7 +136,7 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, 
struct mu_imap_stat *ps)
       
   if (!mboxname)
     {
-      if (imap->imap_state == MU_IMAP_STATE_SELECTED)
+      if (imap->session_state == MU_IMAP_SESSION_SELECTED)
        {
          if (ps)
            *ps = imap->mbox_stat;
@@ -154,9 +152,9 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, 
struct mu_imap_stat *ps)
       return 0;
     }
   
-  switch (imap->state)
+  switch (imap->client_state)
     {
-    case MU_IMAP_CONNECTED:
+    case MU_IMAP_CLIENT_READY:
       status = _mu_imap_tag_next (imap);
       MU_IMAP_CHECK_EAGAIN (imap, status);
       status = mu_imapio_printf (imap->io, "%s STATUS %s (",
@@ -179,9 +177,9 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, 
struct mu_imap_stat *ps)
        status = mu_imapio_send (imap->io, ")\r\n", 3);
       MU_IMAP_CHECK_ERROR (imap, status);
       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
-      imap->state = MU_IMAP_STATUS_RX;
+      imap->client_state = MU_IMAP_CLIENT_STATUS_RX;
 
-    case MU_IMAP_STATUS_RX:
+    case MU_IMAP_CLIENT_STATUS_RX:
       {
        struct status_data sd = { mboxname, ps };
 
@@ -200,7 +198,7 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, 
struct mu_imap_stat *ps)
            status = MU_ERR_BADREPLY;
            break;
          }
-       imap->state = MU_IMAP_CONNECTED;
+       imap->client_state = MU_IMAP_CLIENT_READY;
       }
       break;
 
diff --git a/mu/imap.c b/mu/imap.c
index 44a6cdb..54ebca7 100644
--- a/mu/imap.c
+++ b/mu/imap.c
@@ -62,17 +62,17 @@ static struct argp imap_argp = {
 
 static mu_imap_t imap;
 
-static enum mu_imap_state
+static enum mu_imap_session_state
 current_imap_state ()
 {
   int state;
   if (imap == NULL)
-    state = MU_IMAP_STATE_INIT;
+    state = MU_IMAP_SESSION_INIT;
   else
     {
       mu_imap_state (imap, &state);
-      if (state == MU_IMAP_STATE_LOGOUT)
-       state = MU_IMAP_STATE_INIT;
+      if (state == MU_IMAP_SESSION_LOGOUT)
+       state = MU_IMAP_SESSION_INIT;
     }
   return state;
 }
@@ -131,12 +131,12 @@ static char *username;
 static void
 imap_prompt_env ()
 {
-  enum mu_imap_state state = current_imap_state ();
+  enum mu_imap_session_state state = current_imap_state ();
   if (!mutool_prompt_env)
     mutool_prompt_env = xcalloc (2*7 + 1, sizeof(mutool_prompt_env[0]));
 
   mutool_prompt_env[0] = "user";
-  mutool_prompt_env[1] = (state >= MU_IMAP_STATE_AUTH && username) ?
+  mutool_prompt_env[1] = (state >= MU_IMAP_SESSION_AUTH && username) ?
                            username : "[nouser]";
 
   mutool_prompt_env[2] = "host"; 
@@ -188,7 +188,135 @@ imap_bad_callback (void *data, int code, size_t sdat, 
void *pdat)
   const char *text = pdat;
   mu_diag_output (MU_DIAG_CRIT, "SERVER ALERT: %s", text);
 }
+
+/* Fetch callback */
+static void
+format_email (mu_stream_t str, const char *name, mu_address_t addr)
+{
+  mu_stream_printf (str, "  %s = ", name);
+  if (!addr)
+    mu_stream_printf (str, "NIL");
+  else
+    {
+      size_t sz = mu_address_format_string (addr, NULL, 0);
+      char *buf = xmalloc (sz + 1);
+      mu_address_format_string (addr, buf, sz);
+      mu_stream_write (str, buf, strlen (buf), NULL);
+    }
+  mu_stream_printf (str, "\n");
+}
+
+static void
+format_date (mu_stream_t str, char *name,
+            struct tm *tm, struct mu_timezone *tz)
+{
+  char date[128];
+  
+  strftime (date, sizeof (date), "%a %b %e %H:%M:%S", tm);
+  mu_stream_printf (str, "  %s = %s", name, date);
+  if (tz->tz_name)
+    mu_stream_printf (str, " %s", tz->tz_name);
+  else
+    {
+      int off = tz->utc_offset;
+      if (off < 0)
+       {
+         mu_stream_printf (str, " -");
+         off = - off;
+       }
+      else
+       mu_stream_printf (str, " +");
+      off /= 60;
+      mu_stream_printf (str, "%02d%02d", off / 60, off % 60);
+    }
+  mu_stream_printf (str, "\n");
+}
 
+static int
+fetch_response_printer (void *item, void *data)
+{
+  union mu_imap_fetch_response *resp = item;
+  mu_stream_t str = data;
+
+  switch (resp->type)
+    {
+    case MU_IMAP_FETCH_BODY:
+      mu_stream_printf (str, "BODY [");
+      if (resp->body.partv)
+       {
+         size_t i;
+         
+         for (i = 0; i < resp->body.partc; i++)
+           mu_stream_printf (str, "%lu.",
+                             (unsigned long) resp->body.partv[i]);
+       }
+      if (resp->body.section)
+       mu_stream_printf (str, "%s", resp->body.section);
+      mu_stream_printf (str, "]");
+      mu_stream_printf (str, "\nBEGIN\n%s\nEND\n", resp->body.text);
+      break;
+      
+    case MU_IMAP_FETCH_BODYSTRUCTURE:
+      /* FIXME */
+      mu_stream_printf (str, "BODYSTRUCTURE (not yet implemented)\n");
+      break;
+      
+    case MU_IMAP_FETCH_ENVELOPE:
+      {
+       mu_stream_printf (str, "ENVELOPE:\n");
+       
+       format_date (str, "date", &resp->envelope.date, &resp->envelope.tz);
+
+       format_email (str, "from", resp->envelope.from);
+       format_email (str, "sender", resp->envelope.sender);
+       format_email (str, "reply-to", resp->envelope.reply_to);
+       format_email (str, "to", resp->envelope.to);
+       format_email (str, "cc", resp->envelope.cc);
+       format_email (str, "bcc", resp->envelope.bcc);
+
+       mu_stream_printf (str, "  in-reply-to = %s\n",
+                         resp->envelope.in_reply_to ?
+                          resp->envelope.in_reply_to : "NIL");
+       mu_stream_printf (str, "  message-id = %s\n",
+                         resp->envelope.message_id ?
+                          resp->envelope.message_id : "NIL");
+      }
+      break;
+      
+    case MU_IMAP_FETCH_FLAGS:
+      mu_stream_printf (str, "  flags = ");
+      mu_imap_format_flags (str, resp->flags.flags);
+      mu_stream_printf (str, "\n");
+      break;
+      
+    case MU_IMAP_FETCH_INTERNALDATE:
+      format_date (str, "internaldate", &resp->internaldate.tm,
+                  &resp->internaldate.tz);
+      break;
+      
+    case MU_IMAP_FETCH_RFC822_SIZE:
+      mu_stream_printf (str, "  size = %lu\n",
+                       (unsigned long) resp->rfc822_size.size);
+      break;
+      
+    case MU_IMAP_FETCH_UID:
+      mu_stream_printf (str, "  UID = %lu\n",
+                       (unsigned long) resp->uid.uid);
+    }
+  return 0;
+}
+
+static void
+imap_fetch_callback (void *data, int code, size_t sdat, void *pdat)
+{
+  mu_stream_t str = data;
+  mu_list_t list = pdat;
+
+  mu_stream_printf (str, "Message #%lu:\n", (unsigned long) sdat);
+  mu_list_foreach (list, fetch_response_printer, str);
+  mu_stream_printf (str, "\n\n");
+}
+  
 
 static int
 com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
@@ -212,7 +340,7 @@ com_connect (int argc, char **argv)
   int status;
   int tls = 0;
   int i = 1;
-  enum mu_imap_state state;
+  enum mu_imap_session_state state;
   
   for (i = 1; i < argc; i++)
     {
@@ -234,7 +362,7 @@ com_connect (int argc, char **argv)
   
   state = current_imap_state ();
   
-  if (state != MU_IMAP_STATE_INIT)
+  if (state != MU_IMAP_SESSION_INIT)
     com_disconnect (0, NULL);
   
   status = mu_imap_create (&imap);
@@ -292,7 +420,9 @@ com_connect (int argc, char **argv)
          mu_imap_register_callback_function (imap, MU_IMAP_CB_BAD,
                                              imap_bad_callback,
                                              NULL);
-
+         mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH,
+                                             imap_fetch_callback,
+                                             mu_strout);
          
          status = mu_imap_connect (imap);
          if (status)
@@ -600,7 +730,17 @@ com_noop (int argc MU_ARG_UNUSED, char **argv 
MU_ARG_UNUSED)
 static int
 com_fetch (int argc, char **argv)
 {
-  int status = mu_imap_fetch (imap, argv[1], argv[2]);
+  int status;
+  mu_stream_t out = mutool_open_pager ();
+  
+  mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH,
+                                     imap_fetch_callback,
+                                     out);
+  status = mu_imap_fetch (imap, argv[1], argv[2]);
+  mu_stream_destroy (&out);
+  mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH,
+                                     imap_fetch_callback,
+                                     mu_strout);
   if (status)
     report_failure ("fetch", status);
   return 0;  


hooks/post-receive
-- 
GNU Mailutils



reply via email to

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