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-544-ge218f1e


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-544-ge218f1e
Date: Thu, 22 Dec 2011 11:06:59 +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=e218f1ec00749701a00c074c4574a75a6f156d2b

The branch, master has been updated
       via  e218f1ec00749701a00c074c4574a75a6f156d2b (commit)
      from  690b1bf8506e50cb85d2634ba2db2fddbff99dfe (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 e218f1ec00749701a00c074c4574a75a6f156d2b
Author: Sergey Poznyakoff <address@hidden>
Date:   Thu Dec 22 12:31:25 2011 +0200

    Implement imap (client) bodystructure and envelope.
    
    * libmailutils/string/wordsplit.c (alloc_space): Fix reallocation
    calculations.
    
    * imap4d/fetch.c (bodystructure): Output number of lines for any
    TEXT part, not only TEXT/PLAIN.
    
    * include/mailutils/header.h (MU_HEADER_CONTENT_LOCATION): New define.
    * include/mailutils/imap.h (mu_imap_fetch_bodystructure): Implement.
    (mu_imap_fetch_envelope): Replace data fields with a single pointer
    to struct mu_imapenvelope.
    * include/mailutils/message.h: Include datetime.h
    (mu_imapenvelope, mu_bodystructure): New structs.
    (mu_message_type): New type.
    (mu_message_get_imapenvelope,mu_message_imapenvelope_free)
    (mu_message_set_imapenvelope)
    (mu_bodystructure_free,mu_list_free_bodystructure)
    (mu_message_get_bodystructure)
    (mu_message_set_bodystructure): New protos.
    * include/mailutils/mime.h (mu_mime_param_assoc_create)
    (mu_mime_param_assoc_add): New protos.
    * include/mailutils/sys/message.h (_mu_message)<_imapenvelope>
    <_bodystructure>: New methods.
    * libmailutils/mailbox/bodystruct.c: New file.
    * libmailutils/mailbox/imapenv.c: New file.
    * libmailutils/mailbox/Makefile.am (libmailbox_la_SOURCES): Add new
    sources.
    
    * libproto/imap/fetch.c: Implement bodystructure.
    * mu/imap.c: Likewise.
    
    * testsuite/bs.c: New file.
    * testsuite/Makefile.am (noinst_PROGRAMS): Add bs.

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

Summary of changes:
 imap4d/fetch.c                    |   14 +-
 include/mailutils/header.h        |    1 +
 include/mailutils/imap.h          |   14 +-
 include/mailutils/message.h       |   75 ++++++-
 include/mailutils/mime.h          |    3 +
 include/mailutils/sys/message.h   |    2 +
 libmailutils/mailbox/Makefile.am  |    2 +
 libmailutils/mailbox/bodystruct.c |  325 ++++++++++++++++++++++++
 libmailutils/mailbox/imapenv.c    |  138 ++++++++++
 libmailutils/string/wordsplit.c   |    2 +-
 libproto/imap/fetch.c             |  498 ++++++++++++++++++++++++++++++++++---
 libproto/imap/resplist.c          |    9 +
 mu/imap.c                         |  168 ++++++++++++-
 testsuite/Makefile.am             |    1 +
 testsuite/bs.c                    |  169 +++++++++++++
 15 files changed, 1353 insertions(+), 68 deletions(-)
 create mode 100644 libmailutils/mailbox/bodystruct.c
 create mode 100644 libmailutils/mailbox/imapenv.c
 create mode 100644 testsuite/bs.c

diff --git a/imap4d/fetch.c b/imap4d/fetch.c
index fed2e3f..ad42ff3 100644
--- a/imap4d/fetch.c
+++ b/imap4d/fetch.c
@@ -372,8 +372,9 @@ bodystructure (mu_message_t msg, int extension)
   if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
     {
       struct mu_wordsplit ws;
-      char *s, *p;
-         
+      char *p;
+      size_t len;
+      
       ws.ws_delim = " \t\r\n;=";
       ws.ws_alloc_die = imap4d_ws_alloc_die;
       if (mu_wordsplit (buffer, &ws, IMAP4D_WS_FLAGS))
@@ -383,18 +384,17 @@ bodystructure (mu_message_t msg, int extension)
          return RESP_BAD; /* FIXME: a better error handling, maybe? */
        }
 
+      len = strcspn (ws.ws_wordv[0], "/");
       if (mu_c_strcasecmp (ws.ws_wordv[0], "MESSAGE/RFC822") == 0)
         message_rfc822 = 1;
-      else if (mu_c_strcasecmp (ws.ws_wordv[0], "TEXT/PLAIN") == 0)
+      else if (mu_c_strncasecmp (ws.ws_wordv[0], "TEXT", len) == 0)
         text_plain = 1;
 
-      s = strchr (ws.ws_wordv[0], '/');
-      if (s)
-       *s++ = 0;
+      ws.ws_wordv[0][len++] = 0;
       p = ws.ws_wordv[0];
       io_send_qstring (p);
       io_sendf (" ");
-      io_send_qstring (s);
+      io_send_qstring (ws.ws_wordv[0] + len);
 
       /* body parameter parenthesized list: Content-type attributes */
       if (ws.ws_wordc > 1)
diff --git a/include/mailutils/header.h b/include/mailutils/header.h
index ed13ab3..4117a29 100644
--- a/include/mailutils/header.h
+++ b/include/mailutils/header.h
@@ -59,6 +59,7 @@ extern "C" {
 #define MU_HEADER_CONTENT_DESCRIPTION       "Content-Description"
 #define MU_HEADER_CONTENT_DISPOSITION       "Content-Disposition"
 #define MU_HEADER_CONTENT_MD5               "Content-MD5"
+#define MU_HEADER_CONTENT_LOCATION          "Content-Location"   
 #define MU_HEADER_MIME_VERSION              "MIME-Version"
 #define MU_HEADER_X_MAILER                  "X-Mailer"
 #define MU_HEADER_X_UIDL                    "X-UIDL"
diff --git a/include/mailutils/imap.h b/include/mailutils/imap.h
index 63a5eae..b6f9e57 100644
--- a/include/mailutils/imap.h
+++ b/include/mailutils/imap.h
@@ -236,23 +236,13 @@ struct mu_imap_fetch_body
 struct mu_imap_fetch_bodystructure
 {
   int type;
-  //FIXME?
+  struct mu_bodystructure *bs;
 };
   
 struct mu_imap_fetch_envelope
 {
   int type;
-  struct tm date;
-  struct mu_timezone tz;
-  char *subject;
-  mu_address_t from;
-  mu_address_t sender;
-  mu_address_t reply_to;
-  mu_address_t to;
-  mu_address_t cc;
-  mu_address_t bcc;
-  char *in_reply_to;
-  char *message_id;
+  struct mu_imapenvelope *imapenvelope;
 };
 
 struct mu_imap_fetch_flags
diff --git a/include/mailutils/message.h b/include/mailutils/message.h
index ced7901..d1a31ec 100644
--- a/include/mailutils/message.h
+++ b/include/mailutils/message.h
@@ -20,6 +20,7 @@
 #define _MAILUTILS_MESSAGE_H
 
 #include <mailutils/types.h>
+#include <mailutils/datetime.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -28,6 +29,64 @@ extern "C" {
 #define MU_SCAN_SEEK  0x01
 #define MU_SCAN_SIZE  0x02
 
+struct mu_imapenvelope
+{
+  struct tm date;
+  struct mu_timezone tz;
+  char *subject;
+  mu_address_t from;
+  mu_address_t sender;
+  mu_address_t reply_to;
+  mu_address_t to;
+  mu_address_t cc;
+  mu_address_t bcc;
+  char *in_reply_to;
+  char *message_id;
+};
+
+enum mu_message_type
+  {
+    mu_message_other,
+    mu_message_text,     /* text/plain */
+    mu_message_rfc822,   /* message/rfc822 */
+    mu_message_multipart /* multipart/mixed */
+  };
+  
+struct mu_bodystructure
+{
+  enum mu_message_type body_message_type;
+  char *body_type;
+  char *body_subtype;
+  mu_assoc_t body_param;
+  char *body_id;
+  char *body_descr;
+  char *body_encoding;
+  size_t body_size;
+  /* Optional */
+  char *body_md5;
+  char *body_disposition;
+  mu_assoc_t body_disp_param;
+  char *body_language;
+  char *body_location;
+  union
+  {
+    struct
+    {
+      size_t body_lines;
+    } text;
+    struct 
+    {
+      struct mu_imapenvelope *body_env;
+      struct mu_bodystructure *body_struct;
+      size_t body_lines;
+    } rfc822;
+    struct
+    {
+      mu_list_t body_parts;
+    } multipart;
+  } v;
+};
+
 struct mu_message_scan
 {
   int flags;
@@ -137,6 +196,21 @@ extern int mu_message_set_qid (mu_message_t,
                               int (*_get_qid) (mu_message_t,
                                                mu_message_qid_t *),
                               void *owner);
+
+extern int mu_message_get_imapenvelope (mu_message_t, struct mu_imapenvelope 
**);
+extern void mu_message_imapenvelope_free (struct mu_imapenvelope *);
+extern int mu_message_set_imapenvelope (mu_message_t,
+   int (*_imapenvelope) (mu_message_t, struct mu_imapenvelope **),
+   void *owner);
+
+extern void mu_bodystructure_free (struct mu_bodystructure *);
+extern void mu_list_free_bodystructure (void *item);
+
+extern int mu_message_get_bodystructure (mu_message_t,
+                                        struct mu_bodystructure **);
+extern int mu_message_set_bodystructure (mu_message_t msg,
+      int (*_bodystructure) (mu_message_t, struct mu_bodystructure **),
+      void *owner);
   
 /* misc functions */
 extern int mu_message_create_attachment (const char *content_type,
@@ -190,7 +264,6 @@ extern int mu_message_from_stream_with_envelope 
(mu_message_t *pmsg,
                                                 mu_envelope_t env);
 extern int mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg);
 
-  
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/mailutils/mime.h b/include/mailutils/mime.h
index 9c3d473..48989f1 100644
--- a/include/mailutils/mime.h
+++ b/include/mailutils/mime.h
@@ -66,6 +66,9 @@ int mu_base64_decode    (const unsigned char *input, size_t 
input_len,
                         unsigned char **output, size_t * output_len);
 
 
+int mu_mime_param_assoc_create (mu_assoc_t *passoc);
+int mu_mime_param_assoc_add (mu_assoc_t assoc, const char *name);
+  
 int mu_mime_header_parse (const char *text, char *charset, char **pvalue,
                          mu_assoc_t *paramtab);
 int mu_mime_header_parse_subset (const char *text, const char *charset,
diff --git a/include/mailutils/sys/message.h b/include/mailutils/sys/message.h
index f538fc9..6259dbe 100644
--- a/include/mailutils/sys/message.h
+++ b/include/mailutils/sys/message.h
@@ -61,6 +61,8 @@ struct _mu_message
   int (*_get_qid)        (mu_message_t,        mu_message_qid_t *);
   int (*_get_num_parts)  (mu_message_t, size_t *);
   int (*_get_part)       (mu_message_t, size_t, mu_message_t *);
+  int (*_imapenvelope)   (mu_message_t, struct mu_imapenvelope **);
+  int (*_bodystructure)  (mu_message_t, struct mu_bodystructure **);
   int (*_is_multipart)   (mu_message_t, int *);
   int (*_lines)          (mu_message_t, size_t *, int);
   int (*_size)           (mu_message_t, size_t *);
diff --git a/libmailutils/mailbox/Makefile.am b/libmailutils/mailbox/Makefile.am
index cb9e775..661a922 100644
--- a/libmailutils/mailbox/Makefile.am
+++ b/libmailutils/mailbox/Makefile.am
@@ -23,12 +23,14 @@ libmailbox_la_SOURCES =  \
  mbxitr.c\
  attribute.c\
  body.c\
+ bodystruct.c\
  envelope.c\
  folder.c\
  fsfolder.c\
  hdrfirst.c\
  hdritr.c\
  header.c\
+ imapenv.c\
  msgcpy.c\
  msgattr.c\
  msgbody.c\
diff --git a/libmailutils/mailbox/bodystruct.c 
b/libmailutils/mailbox/bodystruct.c
new file mode 100644
index 0000000..c99cbbe
--- /dev/null
+++ b/libmailutils/mailbox/bodystruct.c
@@ -0,0 +1,325 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/assoc.h>
+#include <mailutils/list.h>
+#include <mailutils/message.h>
+#include <mailutils/mime.h>
+#include <mailutils/header.h>
+#include <mailutils/sys/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/debug.h>
+#include <mailutils/nls.h>
+#include <mailutils/cstr.h>
+#include <mailutils/body.h>
+
+void
+mu_list_free_bodystructure (void *item)
+{
+  mu_bodystructure_free (item);
+}
+
+void
+mu_bodystructure_free (struct mu_bodystructure *bs)
+{
+  if (!bs)
+    return;
+  free (bs->body_type);
+  free (bs->body_subtype);
+  mu_assoc_destroy (&bs->body_param);
+  free (bs->body_id);
+  free (bs->body_descr);
+  free (bs->body_encoding);
+  free (bs->body_md5);
+  free (bs->body_disposition);
+  mu_assoc_destroy (&bs->body_disp_param);
+  free (bs->body_language);
+  free (bs->body_location);
+  switch (bs->body_message_type)
+    {
+    case mu_message_other:
+    case mu_message_text:
+      break;
+      
+    case mu_message_rfc822:
+      mu_message_imapenvelope_free (bs->v.rfc822.body_env);
+      mu_bodystructure_free (bs->v.rfc822.body_struct);
+      break;
+      
+    case mu_message_multipart:
+      mu_list_destroy (&bs->v.multipart.body_parts);
+    }
+
+  free (bs);
+}
+
+static int bodystructure_fill (mu_message_t msg,
+                              struct mu_bodystructure *bs);
+
+static int
+bodystructure_init (mu_message_t msg, struct mu_bodystructure **pbs)
+{
+  int rc;
+  struct mu_bodystructure *bs = calloc (1, sizeof (*bs));
+  if (!bs)
+    return ENOMEM;
+  rc = bodystructure_fill (msg, bs);
+  if (rc)
+    mu_bodystructure_free (bs);
+  else
+    *pbs = bs;
+  return rc;
+}
+
+static int
+bodystructure_fill (mu_message_t msg, struct mu_bodystructure *bs)
+{
+  mu_header_t header = NULL;
+  const char *buffer = NULL;
+  mu_body_t body = NULL;
+  int rc;
+  int is_multipart = 0;
+
+  rc = mu_message_get_header (msg, &header);
+  if (rc)
+    return rc;
+  
+  if (mu_header_sget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
+    {
+      char *value;
+      char *p;
+      size_t len;
+      
+      rc = mu_mime_header_parse (buffer, "UTF-8", &value, &bs->body_param);
+      if (rc)
+       return rc;
+
+      len = strcspn (value, "/");
+
+      if (mu_c_strcasecmp (value, "MESSAGE/RFC822") == 0)
+        bs->body_message_type = mu_message_rfc822;
+      else if (mu_c_strncasecmp (value, "TEXT", len) == 0)
+        bs->body_message_type = mu_message_text;
+
+      p = malloc (len + 1);
+      if (!p)
+       return ENOMEM;
+      memcpy (p, value, len);
+      p[len] = 0;
+      
+      bs->body_type = p;
+      mu_strupper (bs->body_type);
+      if (value[len])
+       {
+         bs->body_subtype = strdup (value + len + 1);
+         if (!bs->body_subtype)
+           return ENOMEM;
+         mu_strupper (bs->body_subtype);
+       }
+      
+      /* body parameter parenthesized list: Content-type attributes */
+
+      rc = mu_message_is_multipart (msg, &is_multipart);
+      if (rc)
+       return rc;
+      if (is_multipart)
+       bs->body_message_type = mu_message_multipart;
+    }
+  else
+    {
+      struct mu_mime_param param;
+      
+      /* Default? If Content-Type is not present consider as text/plain.  */
+      bs->body_type = strdup ("TEXT");
+      if (!bs->body_type)
+       return ENOMEM;
+      bs->body_subtype = strdup ("PLAIN");
+      if (!bs->body_subtype)
+       return ENOMEM;
+      rc = mu_mime_param_assoc_create (&bs->body_param);
+      if (rc)
+       return rc;
+      memset (&param, 0, sizeof (param));
+      param.value = strdup ("US-ASCII");
+      rc = mu_assoc_install (bs->body_param, "CHARSET", &param);
+      if (rc)
+       {
+         free (param.value);
+         return rc;
+       }
+      bs->body_message_type = mu_message_text;
+    }
+
+  if (is_multipart)
+    {
+      size_t i, nparts;
+
+      rc = mu_message_get_num_parts (msg, &nparts);
+      if (rc)
+       return rc;
+
+      rc = mu_list_create (&bs->v.multipart.body_parts);
+      if (rc)
+       return rc;
+
+      mu_list_set_destroy_item (bs->v.multipart.body_parts,
+                               mu_list_free_bodystructure);
+      
+      for (i = 1; i <= nparts; i++)
+        {
+          mu_message_t partmsg;
+         struct mu_bodystructure *partbs;
+
+         rc = mu_message_get_part (msg, i, &partmsg);
+         if (rc)
+           return rc;
+
+         rc = bodystructure_init (partmsg, &partbs);
+         if (rc)
+           return rc;
+
+         rc = mu_list_append (bs->v.multipart.body_parts, partbs);
+         if (rc)
+           {
+             mu_bodystructure_free (partbs);
+             return rc;
+           }
+       }
+    }
+  else
+    {
+      /* body id: Content-ID. */
+      rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_ID,
+                                       &bs->body_id);
+      if (rc && rc != MU_ERR_NOENT)
+       return rc;
+      /* body description: Content-Description. */
+      rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_DESCRIPTION,
+                                       &bs->body_descr);
+      if (rc && rc != MU_ERR_NOENT)
+       return rc;
+      
+      /* body encoding: Content-Transfer-Encoding. */
+      rc = mu_header_aget_value_unfold (header,
+                                       MU_HEADER_CONTENT_TRANSFER_ENCODING,
+                                       &bs->body_encoding);
+      if (rc == MU_ERR_NOENT)
+       {
+         bs->body_encoding = strdup ("7BIT");
+         if (!bs->body_encoding)
+           return ENOMEM;
+       }
+      else if (rc)
+       return rc;
+
+      /* body size RFC822 format.  */
+      rc = mu_message_get_body (msg, &body);
+      if (rc)
+       return rc;
+      rc = mu_body_size (body, &bs->body_size);
+      if (rc)
+       return rc;
+      
+      /* If the mime type was text.  */
+      if (bs->body_message_type == mu_message_text)
+       {
+         rc = mu_body_lines (body, &bs->v.text.body_lines);
+         if (rc)
+           return rc;
+       }
+      else if (bs->body_message_type == mu_message_rfc822)
+       {
+         mu_message_t emsg = NULL;
+
+         /* Add envelope structure of the encapsulated message.  */
+         rc = mu_message_unencapsulate  (msg, &emsg, NULL);
+         if (rc)
+           return rc;
+         rc = mu_message_get_imapenvelope (emsg, &bs->v.rfc822.body_env);
+         if (rc)
+           return rc;
+         /* Add body structure of the encapsulated message.  */
+         rc = bodystructure_init (emsg, &bs->v.rfc822.body_struct);
+         if (rc)
+           return rc;
+         /* Size in text lines of the encapsulated message.  */
+         rc = mu_message_lines (emsg, &bs->v.rfc822.body_lines);
+         mu_message_destroy (&emsg, NULL);
+       }
+    }
+  
+  /* body MD5: Content-MD5.  */
+  rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_MD5,
+                                   &bs->body_md5);
+  if (rc && rc != MU_ERR_NOENT)
+    return rc;
+  
+  /* body disposition: Content-Disposition.  */
+  rc = mu_header_sget_value (header, MU_HEADER_CONTENT_DISPOSITION,
+                            &buffer);
+  if (rc == 0)
+    {
+      rc = mu_mime_header_parse (buffer, "UTF-8", &bs->body_disposition,
+                                &bs->body_disp_param);
+      if (rc)
+       return rc;
+    }
+  else if (rc != MU_ERR_NOENT)
+    return rc;
+  /* body language: Content-Language.  */
+  rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_LANGUAGE,
+                                   &bs->body_language);
+  if (rc && rc != MU_ERR_NOENT)
+    return rc;
+  rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_LOCATION,
+                                   &bs->body_location);
+  if (rc && rc != MU_ERR_NOENT)
+    return rc;
+
+  return 0;
+}
+
+int
+mu_message_get_bodystructure (mu_message_t msg,
+                             struct mu_bodystructure **pbs)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (pbs == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+  if (msg->_bodystructure)
+    return msg->_bodystructure (msg, pbs);
+  return bodystructure_init (msg, pbs);
+}
+
+int
+mu_message_set_bodystructure (mu_message_t msg,
+      int (*_bodystructure) (mu_message_t, struct mu_bodystructure **),
+      void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_bodystructure = _bodystructure;
+  return 0;
+}
diff --git a/libmailutils/mailbox/imapenv.c b/libmailutils/mailbox/imapenv.c
new file mode 100644
index 0000000..efd49b9
--- /dev/null
+++ b/libmailutils/mailbox/imapenv.c
@@ -0,0 +1,138 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/header.h>
+#include <mailutils/envelope.h>
+#include <mailutils/address.h>
+#include <mailutils/message.h>
+#include <mailutils/sys/message.h>
+#include <mailutils/errno.h>
+
+void
+mu_message_imapenvelope_free (struct mu_imapenvelope *env)
+{
+  if (!env)
+    return;
+  free (env->subject);
+  mu_address_destroy (&env->from);
+  mu_address_destroy (&env->sender);
+  mu_address_destroy (&env->reply_to);
+  mu_address_destroy (&env->to);
+  mu_address_destroy (&env->cc);
+  mu_address_destroy (&env->bcc);
+  free (env->in_reply_to);
+  free (env->message_id);
+  free (env);
+}
+
+int
+mu_message_get_imapenvelope (mu_message_t msg, struct mu_imapenvelope 
**pimapenvelope)
+{
+  struct mu_imapenvelope *imapenvelope;
+  int rc;
+  
+  if (msg == NULL)
+    return EINVAL;
+  if (imapenvelope == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+  if (msg->_imapenvelope)
+    return msg->_imapenvelope (msg, pimapenvelope);
+
+  imapenvelope = calloc (1, sizeof (imapenvelope[0]));
+  if (!imapenvelope)
+    return ENOMEM;
+  do
+    {
+      mu_header_t hdr;
+      mu_envelope_t env;
+      const char *s;
+
+      if ((rc = mu_message_get_envelope (msg, &env)))
+       break;
+      if ((rc = mu_envelope_sget_date (env, &s)))
+       break;
+      if ((rc = mu_scan_datetime (s, MU_DATETIME_FROM,
+                                 &imapenvelope->date, &imapenvelope->tz,
+                                 NULL)))
+       break;
+
+      if ((rc = mu_message_get_header (msg, &hdr)))
+       break;
+
+      rc = mu_header_get_address (hdr, MU_HEADER_FROM, &imapenvelope->from);
+      if (rc && rc != MU_ERR_NOENT)
+       break;
+      
+      rc = mu_header_get_address (hdr, MU_HEADER_SENDER, 
&imapenvelope->sender);
+      if (rc && rc != MU_ERR_NOENT)
+       break;
+
+      rc = mu_header_get_address (hdr, MU_HEADER_REPLY_TO, 
&imapenvelope->reply_to);
+      if (rc && rc != MU_ERR_NOENT)
+       break;
+
+      rc = mu_header_get_address (hdr, MU_HEADER_TO, &imapenvelope->to);
+      if (rc && rc != MU_ERR_NOENT)
+       break;
+
+      rc = mu_header_get_address (hdr, MU_HEADER_CC, &imapenvelope->cc);
+      if (rc && rc != MU_ERR_NOENT)
+       break;
+
+      rc = mu_header_get_address (hdr, MU_HEADER_BCC, &imapenvelope->bcc);
+      if (rc && rc != MU_ERR_NOENT)
+       break;
+      
+      rc = mu_header_aget_value_unfold (hdr, MU_HEADER_SUBJECT,
+                                       &imapenvelope->subject);
+      if (rc && rc != MU_ERR_NOENT)
+       break;
+
+      rc = mu_header_aget_value_unfold (hdr, MU_HEADER_IN_REPLY_TO,
+                                       &imapenvelope->in_reply_to);
+      if (rc && rc != MU_ERR_NOENT)
+       break;
+
+      rc = mu_header_aget_value_unfold (hdr, MU_HEADER_MESSAGE_ID,
+                                       &imapenvelope->message_id);
+    }
+  while (0);
+  if (rc)
+    mu_message_imapenvelope_free (imapenvelope);
+  else
+    *pimapenvelope = imapenvelope;
+  return rc;
+}
+
+int
+mu_message_set_imapenvelope (mu_message_t msg,
+                       int (*_imapenvelope) (mu_message_t,
+                                        struct mu_imapenvelope **),
+                       void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_imapenvelope = _imapenvelope;
+  return 0;
+}
diff --git a/libmailutils/string/wordsplit.c b/libmailutils/string/wordsplit.c
index 12af725..0acf2a3 100644
--- a/libmailutils/string/wordsplit.c
+++ b/libmailutils/string/wordsplit.c
@@ -184,7 +184,7 @@ alloc_space (struct mu_wordsplit *wsp, size_t count)
   else if (wsp->ws_wordn < offs + wsp->ws_wordc + count)
     {
       newalloc = offs + wsp->ws_wordc +
-       count > ALLOC_INCR ? count : ALLOC_INCR;
+       (count > ALLOC_INCR ? count : ALLOC_INCR);
       ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0]));
     }
   else
diff --git a/libproto/imap/fetch.c b/libproto/imap/fetch.c
index b1994ae..e448041 100644
--- a/libproto/imap/fetch.c
+++ b/libproto/imap/fetch.c
@@ -25,6 +25,9 @@
 #include <mailutils/address.h>
 #include <mailutils/cstr.h>
 #include <mailutils/cctype.h>
+#include <mailutils/message.h>
+#include <mailutils/mime.h>
+#include <mailutils/assoc.h>
 #include <mailutils/imap.h>
 #include <mailutils/sys/imap.h>
 
@@ -67,19 +70,11 @@ _free_fetch_response (void *ptr)
       break;
       
     case MU_IMAP_FETCH_BODYSTRUCTURE:
-      /* FIXME */
+      mu_bodystructure_free (resp->bodystructure.bs);
       break;
       
     case MU_IMAP_FETCH_ENVELOPE:
-      free (resp->envelope.subject);
-      mu_address_destroy (&resp->envelope.from);
-      mu_address_destroy (&resp->envelope.sender);
-      mu_address_destroy (&resp->envelope.reply_to);
-      mu_address_destroy (&resp->envelope.to);
-      mu_address_destroy (&resp->envelope.cc);
-      mu_address_destroy (&resp->envelope.bcc);
-      free (resp->envelope.in_reply_to);
-      free (resp->envelope.message_id);
+      mu_message_imapenvelope_free (resp->envelope.imapenvelope);
       break;
       
     case MU_IMAP_FETCH_FLAGS:
@@ -228,8 +223,9 @@ _body_mapper (union mu_imap_fetch_response *resp,
       partv = calloc (partc, sizeof (partv[0]));
       for (i = 0, p = section; i < partc; i++)
        {
-         partv[i] = strtoul (p, &p, 10);
-         p++;
+         char *q;
+         partv[i] = strtoul (p, &q, 10);
+         p = q + 1;
        }
     }
 
@@ -327,12 +323,438 @@ _date_mapper (union mu_imap_fetch_response *resp,
   return 0;
 }
 
-/* FIXME */
-#define _bodystructure_mapper NULL
+static int parse_bodystructure (struct imap_list_element *elt,
+                               struct mu_bodystructure **pbs);
+
+struct body_field_map
+{
+  size_t offset; /* Offset of the target member of mu_bodystructure */
+  int (*mapper) (struct imap_list_element *, void *);
+};
+
+static int
+parse_bs_list (struct imap_list_element *elt,
+              struct mu_bodystructure *bs,
+              struct body_field_map *map)
+{
+  int rc;
+  mu_iterator_t itr;
+
+  rc = mu_list_get_iterator (elt->v.list, &itr);
+  if (rc)
+    return rc;
+  for (mu_iterator_first (itr);
+       map->mapper && !mu_iterator_is_done (itr);
+       mu_iterator_next (itr), map++)
+    {
+      struct imap_list_element *tok;
+      mu_iterator_current (itr, (void**)&tok);
+      rc = map->mapper (tok, (char*)bs + map->offset);
+      if (rc)
+       break;
+    }
+  mu_iterator_destroy (&itr);
+  return rc;
+}
+
+static int
+_map_body_param (void **itmv, size_t itmc, void *call_data)
+{
+  mu_assoc_t assoc = call_data;
+  struct mu_mime_param param;
+  struct imap_list_element *key, *val;
+  int rc;
+
+  if (itmc != 2)
+    return MU_ERR_PARSE;
+
+  key = itmv[0];
+  val = itmv[1];
+  if (key->type != imap_eltype_string || val->type != imap_eltype_string)
+    return MU_ERR_PARSE;
+  
+  rc = mu_rfc2047_decode_param ("UTF-8", val->v.string, &param);
+  if (rc)
+    {
+      param.lang = param.cset = NULL;
+      param.value = strdup (val->v.string);
+      if (!param.value)
+       return ENOMEM;
+    }
+  return mu_assoc_install (assoc, key->v.string, &param);
+}
+
+static int
+_body_field_text_mapper (struct imap_list_element *tok, void *ptr)
+{
+  char *s;
+  
+  if (_mu_imap_list_element_is_nil (tok))
+    s = NULL;
+  else if (tok->type != imap_eltype_string)
+    return MU_ERR_PARSE;
+  else if (!(s = strdup (tok->v.string)))
+    return ENOMEM;
+  *(char**) ptr = s;
+  return 0;
+}
+
+static int
+_body_field_size_mapper (struct imap_list_element *tok, void *ptr)
+{
+  unsigned long n;
+  
+  if (_mu_imap_list_element_is_nil (tok))
+    n = 0;
+  else if (tok->type != imap_eltype_string)
+    return MU_ERR_PARSE;
+  else
+    {
+      char *s;
+
+      errno = 0;
+      n = strtoul (tok->v.string, &s, 10);
+      if (*s || errno)
+       return MU_ERR_PARSE;
+    }
+  *(size_t*) ptr = n;
+  return 0;
+}
+
+static int
+_body_field_param_mapper (struct imap_list_element *tok, void *ptr)
+{
+  mu_assoc_t param;
+  int rc = mu_mime_param_assoc_create (&param);
+  if (rc)
+    return rc;
+  *(mu_assoc_t*) ptr = param;
+  if (_mu_imap_list_element_is_nil (tok))
+    return 0;
+  if (tok->type != imap_eltype_list)
+    return MU_ERR_PARSE;
+  return mu_list_gmap (tok->v.list, _map_body_param, 2, param);
+}  
+
+static int
+_body_field_disposition_mapper (struct imap_list_element *tok, void *ptr)
+{
+  int rc;
+  struct mu_bodystructure *bs = ptr;
+  struct imap_list_element *elt;
+  
+  if (_mu_imap_list_element_is_nil (tok))
+    return 0;
+  if (tok->type != imap_eltype_list)
+    return MU_ERR_PARSE;
+  elt = _mu_imap_list_at (tok->v.list, 0);
+  if (_mu_imap_list_element_is_nil (elt))
+    bs->body_disposition = NULL;
+  else if (elt->type != imap_eltype_string)
+    return MU_ERR_PARSE;
+  else if ((bs->body_disposition = strdup (elt->v.string)) == NULL)
+    return ENOMEM;
+
+  rc = mu_mime_param_assoc_create (&bs->body_disp_param);
+  if (rc)
+    return rc;
+  
+  elt = _mu_imap_list_at (tok->v.list, 1);
+  if (_mu_imap_list_element_is_nil (elt))
+    return 0;
+  else if (elt->type != imap_eltype_list)
+    return MU_ERR_PARSE;
+  return mu_list_gmap (elt->v.list, _map_body_param, 2, bs->body_disp_param);
+}
+
+static int parse_envelope (struct imap_list_element *elt,
+                          struct mu_imapenvelope **penv);
+
+static int
+_body_field_imapenvelope_mapper (struct imap_list_element *tok, void *ptr)
+{
+  return parse_envelope (tok, ptr);
+}
+
+static int
+_body_field_bodystructure_mapper (struct imap_list_element *tok, void *ptr)
+{
+  return parse_bodystructure (tok, ptr);
+}
+
+/* Simple text or message/rfc822 body.
+
+   Sample TEXT body structure:
+
+   ("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
+    "<address@hidden>" "Compiler diff"
+    "BASE64" 4554 73)
+
+    Elements:
+
+    0        "TEXT"            body_type
+    1        "PLAIN"           body_subtype
+    2        (...)             body_param
+    3        "<9607...>"       body_id
+    4        "Compiler diff"   body_descr
+    5        "BASE64"          body_encoding
+    6        4554              body_size
+    7        73                v.text.body_lines
+    [Optional]
+    8                          body_md5
+    9                          body_disposition;
+    10                         body_language;
+    11                         body_location;
+*/
+
+struct body_field_map base_field_map[] = {
+  { mu_offsetof (struct mu_bodystructure, body_type),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_subtype),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_param),
+    _body_field_param_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_id),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_descr),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_encoding),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_size),
+    _body_field_size_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_md5),
+    _body_field_text_mapper },
+  { 0, _body_field_disposition_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_language),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_location),
+    _body_field_text_mapper },
+  { 0, NULL }
+};
+
+struct body_field_map text_field_map[] = {
+  { mu_offsetof (struct mu_bodystructure, body_type),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_subtype),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_param),
+    _body_field_param_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_id),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_descr),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_encoding),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_size),
+    _body_field_size_mapper },
+  { mu_offsetof (struct mu_bodystructure, v.text.body_lines),
+    _body_field_size_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_md5),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_disposition),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_language),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_location),
+    _body_field_text_mapper },
+  { 0, NULL }
+};
+
+struct body_field_map message_field_map[] = {
+  { mu_offsetof (struct mu_bodystructure, body_type),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_subtype),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_param),
+    _body_field_param_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_id),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_descr),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_encoding),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_size),
+    _body_field_size_mapper },
+  { mu_offsetof (struct mu_bodystructure, v.rfc822.body_env),
+    _body_field_imapenvelope_mapper },
+  { mu_offsetof (struct mu_bodystructure, v.rfc822.body_struct),
+    _body_field_bodystructure_mapper },
+  { mu_offsetof (struct mu_bodystructure, v.rfc822.body_lines),
+    _body_field_size_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_md5),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_disposition),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_language),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_location),
+    _body_field_text_mapper },
+  { 0, NULL }
+};
+
+struct body_field_map multipart_field_map[] = {
+  /* Body type is processed separately */
+  { mu_offsetof (struct mu_bodystructure, body_subtype),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_param),
+    _body_field_param_mapper },
+  { 0, _body_field_disposition_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_language),
+    _body_field_text_mapper },
+  { mu_offsetof (struct mu_bodystructure, body_location),
+    _body_field_text_mapper },
+  { 0, NULL }
+};
+
+#define BSTOK_BODY_TYPE    0
+#define BSTOK_BODY_SUBTYPE 1
+
+static int
+_parse_bodystructure_simple (struct imap_list_element *elt,
+                            struct mu_bodystructure *bs)
+{
+  size_t n;
+  struct imap_list_element *tok, *subtype;
+  struct body_field_map *map;
+  
+  mu_list_count (elt->v.list, &n);
+  if (n < 8)
+    return MU_ERR_PARSE;
+
+  tok = _mu_imap_list_at (elt->v.list, BSTOK_BODY_TYPE);
+  if (!tok || tok->type != imap_eltype_string)
+    return MU_ERR_PARSE;
+  subtype = _mu_imap_list_at (elt->v.list, BSTOK_BODY_SUBTYPE);
+  if (!subtype || subtype->type != imap_eltype_string)
+    return MU_ERR_PARSE;
+  
+  if (mu_c_strcasecmp (tok->v.string, "TEXT") == 0)
+    {
+      bs->body_message_type = mu_message_text;
+      map = text_field_map;
+    }
+  else if (mu_c_strcasecmp (tok->v.string, "MESSAGE") == 0 &&
+          mu_c_strcasecmp (subtype->v.string, "RFC822") == 0)
+    {
+      bs->body_message_type = mu_message_rfc822;
+      map = message_field_map;
+    }
+  else
+    {
+      bs->body_message_type = mu_message_other;
+      map = base_field_map;
+    }
+  
+  return parse_bs_list (elt, bs, map);
+}
+
+/* Example multipart:
+        (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
+         23)
+        ("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
+         "<address@hidden>" "Compiler diff"
+         "BASE64" 4554 73)
+        "MIXED")
+
+*/
+static int
+_parse_bodystructure_mixed (struct imap_list_element *elt,
+                           struct mu_bodystructure *bs)
+{
+  int rc;
+  struct imap_list_element *tok;
+  mu_iterator_t itr;
+  struct body_field_map *map = multipart_field_map;
+  
+  bs->body_message_type = mu_message_multipart;
+  if (!(bs->body_type = strdup ("MULTIPART")))
+    return ENOMEM;
+
+  rc = mu_list_create (&bs->v.multipart.body_parts);
+  if (rc)
+    return rc;
+
+  mu_list_set_destroy_item (bs->v.multipart.body_parts,
+                           mu_list_free_bodystructure);
+
+  rc = mu_list_get_iterator (elt->v.list, &itr);
+  if (rc)
+    return rc;
+  for (mu_iterator_first (itr);
+       !mu_iterator_is_done (itr);
+       mu_iterator_next (itr))
+    {
+      struct mu_bodystructure *bspart;
+
+      mu_iterator_current (itr, (void**) &tok);
+      if (!tok)
+       return MU_ERR_PARSE;
+      if (tok->type != imap_eltype_list)
+       break;
+      rc = parse_bodystructure (tok, &bspart);
+      if (rc)
+       return rc;
+      rc = mu_list_append (bs->v.multipart.body_parts, bspart);
+      if (rc)
+       {
+         mu_bodystructure_free (bspart);
+         return rc;
+       }
+    }
+
+  if (mu_iterator_is_done (itr))
+    return MU_ERR_PARSE;
+  
+  for (; map->mapper && !mu_iterator_is_done (itr);
+       mu_iterator_next (itr), map++)
+    {
+      struct imap_list_element *tok;
+      mu_iterator_current (itr, (void**)&tok);
+      rc = map->mapper (tok, (char*)bs + map->offset);
+      if (rc)
+       return rc;
+    }
+  mu_iterator_destroy (&itr);
+  return 0;
+}
+
+static int
+parse_bodystructure (struct imap_list_element *elt,
+                    struct mu_bodystructure **pbs)
+{
+  int rc;
+  struct mu_bodystructure *bs;
+  struct imap_list_element *tok;
+  
+  if (elt->type != imap_eltype_list)
+    return MU_ERR_FAILURE;
+  bs = calloc (1, sizeof (*bs));
+  if (!bs)
+    return ENOMEM;
+  tok = _mu_imap_list_at (elt->v.list, 0);
+  if (tok->type == imap_eltype_string)
+    rc = _parse_bodystructure_simple (elt, bs);
+  else
+    rc = _parse_bodystructure_mixed (elt, bs);
+
+  if (rc)
+    mu_bodystructure_free (bs);
+  else
+    *pbs = bs;
+  return rc;
+}
+
+static int
+_bodystructure_mapper (union mu_imap_fetch_response *resp,
+                      struct imap_list_element *elt,
+                      struct parse_response_env *parse_env)
+{
+  return parse_bodystructure (elt, &resp->bodystructure.bs);
+}
 
 struct fill_env
 {
-  struct mu_imap_fetch_envelope *envelope;
+  struct mu_imapenvelope *imapenvelope;
   size_t n;
 };
 
@@ -435,7 +857,8 @@ _fill_response (void *item, void *data)
   int rc;
   struct imap_list_element *elt = item;
   struct fill_env *env = data;
-
+  struct mu_imapenvelope *imapenvelope = env->imapenvelope;
+  
   switch (env->n++)
     {
     case env_date:
@@ -445,8 +868,8 @@ _fill_response (void *item, void *data)
        {
          if (mu_scan_datetime (elt->v.string,
                                MU_DATETIME_SCAN_RFC822,
-                               &env->envelope->date,
-                               &env->envelope->tz, NULL))
+                               &imapenvelope->date,
+                               &imapenvelope->tz, NULL))
            rc = MU_ERR_FAILURE;
          else
            rc = 0;
@@ -454,58 +877,67 @@ _fill_response (void *item, void *data)
       break;
       
     case env_subject:
-      rc = elt_to_string (elt, &env->envelope->subject);
+      rc = elt_to_string (elt, &imapenvelope->subject);
       break;
 
     case env_from:
-      rc = elt_to_address (elt, &env->envelope->from);
+      rc = elt_to_address (elt, &imapenvelope->from);
       break;
        
     case env_sender:
-      rc = elt_to_address (elt, &env->envelope->sender);
+      rc = elt_to_address (elt, &imapenvelope->sender);
       break;
       
     case env_reply_to:
-      rc = elt_to_address (elt, &env->envelope->reply_to);
+      rc = elt_to_address (elt, &imapenvelope->reply_to);
       break;
       
     case env_to:
-      rc = elt_to_address (elt, &env->envelope->to);
+      rc = elt_to_address (elt, &imapenvelope->to);
       break;
       
     case env_cc:
-      rc = elt_to_address (elt, &env->envelope->cc);
+      rc = elt_to_address (elt, &imapenvelope->cc);
       break;
       
     case env_bcc:
-      rc = elt_to_address (elt, &env->envelope->bcc);
+      rc = elt_to_address (elt, &imapenvelope->bcc);
       break;
       
     case env_in_reply_to:
-      rc = elt_to_string (elt, &env->envelope->in_reply_to);
+      rc = elt_to_string (elt, &imapenvelope->in_reply_to);
       break;
       
     case env_message_id:
-      rc = elt_to_string (elt, &env->envelope->message_id);
+      rc = elt_to_string (elt, &imapenvelope->message_id);
       break;
     }
   return rc;
 }
-  
+
 static int
-_envelope_mapper (union mu_imap_fetch_response *resp,
-                 struct imap_list_element *elt,
-                 struct parse_response_env *parse_env)
+parse_envelope (struct imap_list_element *elt, struct mu_imapenvelope **penv)
 {
   struct fill_env env;
   
   if (elt->type != imap_eltype_list)
     return MU_ERR_FAILURE;
-  env.envelope = &resp->envelope;
+  env.imapenvelope = calloc (1, sizeof (*env.imapenvelope));
+  if (!env.imapenvelope)
+    return ENOMEM;
   env.n = 0;
   mu_list_foreach (elt->v.list, _fill_response, &env);
+  *penv = env.imapenvelope;
   return 0;
 }
+
+static int
+_envelope_mapper (union mu_imap_fetch_response *resp,
+                 struct imap_list_element *elt,
+                 struct parse_response_env *parse_env)
+{
+  return parse_envelope (elt, &resp->envelope.imapenvelope);
+}
 
 struct mapper_tab
 {
@@ -517,7 +949,7 @@ struct mapper_tab
   
 static struct mapper_tab mapper_tab[] = {
 #define S(s) s, (sizeof (s) - 1)
-  { S("BODYSTRUCTURE"), },
+  { S("BODYSTRUCTURE"), MU_IMAP_FETCH_BODYSTRUCTURE, _bodystructure_mapper },
   { S("BODY"),          MU_IMAP_FETCH_BODY,        _body_mapper },
   { S("ENVELOPE"),      MU_IMAP_FETCH_ENVELOPE,    _envelope_mapper },
   { S("FLAGS"),         MU_IMAP_FETCH_FLAGS,       _flags_mapper },
diff --git a/libproto/imap/resplist.c b/libproto/imap/resplist.c
index 65d78dc..2f9dc80 100644
--- a/libproto/imap/resplist.c
+++ b/libproto/imap/resplist.c
@@ -297,4 +297,13 @@ _mu_imap_list_nth_element_is_string (mu_list_t list, 
size_t n,
         strcmp (elt->v.string, str) == 0;
 }
 
+int
+_mu_imap_list_nth_element_is_string_ci (mu_list_t list, size_t n,
+                                       const char *str)
+{
+  struct imap_list_element *elt = _mu_imap_list_at (list, n);
+  return elt && elt->type == imap_eltype_string &&
+        mu_c_strcasecmp (elt->v.string, str) == 0;
+}
+
 
diff --git a/mu/imap.c b/mu/imap.c
index cf49b4b..9e6e387 100644
--- a/mu/imap.c
+++ b/mu/imap.c
@@ -225,7 +225,143 @@ format_date (mu_stream_t str, char *name,
     }
   mu_stream_printf (str, "\n");
 }
+
+#define S(str) ((str) ? (str) : "")
+
+static void
+print_param (mu_stream_t ostr, const char *prefix, mu_assoc_t assoc,
+            int indent)
+{
+  mu_iterator_t itr;
+  int i;
+
+  mu_stream_printf (ostr, "%*s%s:\n", indent, "", prefix);
+  indent += 4;
+  if (mu_assoc_get_iterator (assoc, &itr))
+    return;
+  for (i = 0, mu_iterator_first (itr);
+       !mu_iterator_is_done (itr);
+       i++, mu_iterator_next (itr))
+    {
+      const char *name;
+      struct mu_mime_param *p;
+      
+      mu_iterator_current_kv (itr, (const void **)&name, (void**)&p);
+      mu_stream_printf (ostr, "%*s%d: %s=%s\n", indent, "", i, name, p->value);
+    }
+  mu_iterator_destroy (&itr);
+}
+
+struct print_data
+{
+  mu_stream_t ostr;
+  int num;
+  int level;
+};
+
+static void print_bs (mu_stream_t ostr,
+                     struct mu_bodystructure *bs, int level);
+
+static int
+print_item (void *item, void *data)
+{
+  struct mu_bodystructure *bs = item;
+  struct print_data *pd = data;
+  mu_stream_printf (pd->ostr, "%*sPart #%d\n", (pd->level-1) << 2, "",
+                   pd->num);
+  print_bs (pd->ostr, bs, pd->level);
+  ++pd->num;
+  return 0;
+}
+
+static void
+print_address (mu_stream_t ostr, const char *title, mu_address_t addr,
+              int indent)
+{
+  mu_stream_printf (ostr, "%*s%s: ", indent, "", title);
+  mu_stream_format_address (mu_strout, addr);
+  mu_stream_printf (ostr, "\n");
+}
+
+static void
+print_imapenvelope (mu_stream_t ostr, struct mu_imapenvelope *env, int level)
+{
+  int indent = (level << 2);
+
+  mu_stream_printf (ostr, "%*sEnvelope:\n", indent, "");
+  indent += 4;
+  mu_stream_printf (ostr, "%*sTime: ", indent, "");
+  mu_c_streamftime (mu_strout, "%c%n", &env->date, &env->tz);
+  mu_stream_printf (ostr, "%*sSubject: %s\n", indent, "", S(env->subject));
+  print_address (ostr, "From", env->from, indent);
+  print_address (ostr, "Sender", env->sender, indent);
+  print_address (ostr, "Reply-to", env->reply_to, indent);
+  print_address (ostr, "To", env->to, indent);
+  print_address (ostr, "Cc", env->cc, indent);
+  print_address (ostr, "Bcc", env->bcc, indent);
+  mu_stream_printf (ostr, "%*sIn-Reply-To: %s\n", indent, "",
+                   S(env->in_reply_to));
+  mu_stream_printf (ostr, "%*sMessage-ID: %s\n", indent, "",
+                   S(env->message_id));
+}
 
+static void
+print_bs (mu_stream_t ostr, struct mu_bodystructure *bs, int level)
+{
+  int indent = level << 2;
+  mu_stream_printf (ostr, "%*sbody_type=%s\n", indent, "", S(bs->body_type));
+  mu_stream_printf (ostr, "%*sbody_subtype=%s\n", indent, "",
+                   S(bs->body_subtype));
+  print_param (ostr, "Parameters", bs->body_param, indent);
+  mu_stream_printf (ostr, "%*sbody_id=%s\n", indent, "", S(bs->body_id));
+  mu_stream_printf (ostr, "%*sbody_descr=%s\n", indent, "", S(bs->body_descr));
+  mu_stream_printf (ostr, "%*sbody_encoding=%s\n", indent, "",
+                   S(bs->body_encoding));
+  mu_stream_printf (ostr, "%*sbody_size=%lu\n", indent, "",
+                   (unsigned long) bs->body_size);
+  /* Optional */
+  mu_stream_printf (ostr, "%*sbody_md5=%s\n", indent, "", S(bs->body_md5));
+  mu_stream_printf (ostr, "%*sbody_disposition=%s\n", indent, "",
+                   S(bs->body_disposition));
+  print_param (ostr, "Disposition Parameters", bs->body_disp_param, indent);
+  mu_stream_printf (ostr, "%*sbody_language=%s\n", indent, "",
+                   S(bs->body_language));
+  mu_stream_printf (ostr, "%*sbody_location=%s\n", indent, "",
+                   S(bs->body_location));
+
+  mu_stream_printf (ostr, "%*sType ", indent, "");
+  switch (bs->body_message_type)
+    {
+    case mu_message_other:
+      mu_stream_printf (ostr, "mu_message_other\n");
+      break;
+      
+    case mu_message_text:
+      mu_stream_printf (ostr, "mu_message_text:\n%*sbody_lines=%lu\n",
+                       indent + 4, "",
+                       (unsigned long) bs->v.text.body_lines);
+      break;
+      
+    case mu_message_rfc822:
+      mu_stream_printf (ostr, "mu_message_rfc822:\n%*sbody_lines=%lu\n",
+                       indent + 4, "",
+                (unsigned long) bs->v.rfc822.body_lines);
+      print_imapenvelope (ostr, bs->v.rfc822.body_env, level + 1);
+      print_bs (ostr, bs->v.rfc822.body_struct, level + 1);
+      break;
+      
+    case mu_message_multipart:
+      {
+       struct print_data pd;
+       pd.ostr = ostr;
+       pd.num = 0;
+       pd.level = level + 1;
+       mu_stream_printf (ostr, "mu_message_multipart:\n");
+       mu_list_foreach (bs->v.multipart.body_parts, print_item, &pd);
+      }
+    }
+}
+
 static int
 fetch_response_printer (void *item, void *data)
 {
@@ -252,31 +388,35 @@ fetch_response_printer (void *item, void *data)
       
     case MU_IMAP_FETCH_BODYSTRUCTURE:
       /* FIXME */
-      mu_stream_printf (str, "BODYSTRUCTURE (not yet implemented)\n");
+      mu_stream_printf (str, "BODYSTRUCTURE:\nBEGIN\n");
+      print_bs (str, resp->bodystructure.bs, 0);
+      mu_stream_printf (str, "END\n");
       break;
       
     case MU_IMAP_FETCH_ENVELOPE:
       {
+       struct mu_imapenvelope *env = resp->envelope.imapenvelope;
+       
        mu_stream_printf (str, "ENVELOPE:\n");
        
-       format_date (str, "date", &resp->envelope.date, &resp->envelope.tz);
+       format_date (str, "date", &env->date, &env->tz);
        mu_stream_printf (str, "  subject = %s\n",
-                         resp->envelope.subject ?
-                          resp->envelope.subject : "NIL");
+                         env->subject ?
+                          env->subject : "NIL");
 
-       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);
+       format_email (str, "from", env->from);
+       format_email (str, "sender", env->sender);
+       format_email (str, "reply-to", env->reply_to);
+       format_email (str, "to", env->to);
+       format_email (str, "cc", env->cc);
+       format_email (str, "bcc", env->bcc);
 
        mu_stream_printf (str, "  in-reply-to = %s\n",
-                         resp->envelope.in_reply_to ?
-                          resp->envelope.in_reply_to : "NIL");
+                         env->in_reply_to ?
+                          env->in_reply_to : "NIL");
        mu_stream_printf (str, "  message-id = %s\n",
-                         resp->envelope.message_id ?
-                          resp->envelope.message_id : "NIL");
+                         env->message_id ?
+                          env->message_id : "NIL");
       }
       break;
       
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 219731d..2a9f4ea 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -50,6 +50,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
 
 INCLUDES = @MU_LIB_COMMON_INCLUDES@ 
 noinst_PROGRAMS = \
+ bs\
  fldel\
  lstuid\
  mbdel\
diff --git a/testsuite/bs.c b/testsuite/bs.c
new file mode 100644
index 0000000..8f74b2d
--- /dev/null
+++ b/testsuite/bs.c
@@ -0,0 +1,169 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <mailutils/mailutils.h>
+
+#define S(str) ((str) ? (str) : "")
+
+static void
+print_param (const char *prefix, mu_assoc_t assoc, int indent)
+{
+  mu_iterator_t itr;
+  int i;
+
+  mu_printf ("%*s%s:\n", indent, "", prefix);
+  if (!assoc)
+    return;
+  indent += 4;
+  MU_ASSERT (mu_assoc_get_iterator (assoc, &itr));
+      
+  for (i = 0, mu_iterator_first (itr);
+       !mu_iterator_is_done (itr);
+       i++, mu_iterator_next (itr))
+    {
+      const char *name;
+      struct mu_mime_param *p;
+      
+      mu_iterator_current_kv (itr, (const void **)&name, (void**)&p);
+      mu_printf ("%*s%d: %s=%s\n", indent, "", i, name, p->value);
+    }
+  mu_iterator_destroy (&itr);
+}
+
+struct print_data
+{
+  int num;
+  int level;
+};
+
+static void print_bs (struct mu_bodystructure *bs, int level);
+
+static int
+print_item (void *item, void *data)
+{
+  struct mu_bodystructure *bs = item;
+  struct print_data *pd = data;
+  mu_printf ("%*sPart #%d\n", (pd->level-1) << 2, "", pd->num);
+  print_bs (bs, pd->level);
+  ++pd->num;
+  return 0;
+}
+
+static void
+print_address (const char *title, mu_address_t addr, int indent)
+{
+  mu_printf ("%*s%s: ", indent, "", title);
+  mu_stream_format_address (mu_strout, addr);
+  mu_printf ("\n");
+}
+
+static void
+print_imapenvelope (struct mu_imapenvelope *env, int level)
+{
+  int indent = (level << 2);
+
+  mu_printf ("%*sEnvelope:\n", indent, "");
+  indent += 4;
+  mu_printf ("%*sTime: ", indent, "");
+  mu_c_streamftime (mu_strout, "%c%n", &env->date, &env->tz);
+  mu_printf ("%*sSubject: %s\n", indent, "", S(env->subject));
+  print_address ("From", env->from, indent);
+  print_address ("Sender", env->sender, indent);
+  print_address ("Reply-to", env->reply_to, indent);
+  print_address ("To", env->to, indent);
+  print_address ("Cc", env->cc, indent);
+  print_address ("Bcc", env->bcc, indent);
+  mu_printf ("%*sIn-Reply-To: %s\n", indent, "", S(env->in_reply_to));
+  mu_printf ("%*sMessage-ID: %s\n", indent, "", S(env->message_id));
+}
+
+static void
+print_bs (struct mu_bodystructure *bs, int level)
+{
+  int indent = level << 2;
+  mu_printf ("%*sbody_type=%s\n", indent, "", S(bs->body_type));
+  mu_printf ("%*sbody_subtype=%s\n", indent, "", S(bs->body_subtype));
+  print_param ("Parameters", bs->body_param, indent);
+  mu_printf ("%*sbody_id=%s\n", indent, "", S(bs->body_id));
+  mu_printf ("%*sbody_descr=%s\n", indent, "", S(bs->body_descr));
+  mu_printf ("%*sbody_encoding=%s\n", indent, "", S(bs->body_encoding));
+  mu_printf ("%*sbody_size=%lu\n", indent, "", (unsigned long) bs->body_size);
+  /* Optional */
+  mu_printf ("%*sbody_md5=%s\n", indent, "", S(bs->body_md5));
+  mu_printf ("%*sbody_disposition=%s\n", indent, "", S(bs->body_disposition));
+  print_param ("Disposition Parameters", bs->body_disp_param, indent);
+  mu_printf ("%*sbody_language=%s\n", indent, "", S(bs->body_language));
+  mu_printf ("%*sbody_location=%s\n", indent, "", S(bs->body_location));
+
+  mu_printf ("%*sType ", indent, "");
+  switch (bs->body_message_type)
+    {
+    case mu_message_other:
+      mu_printf ("mu_message_other\n");
+      break;
+      
+    case mu_message_text:
+      mu_printf ("mu_message_text:\n%*sbody_lines=%lu\n", indent + 4, "",
+                (unsigned long) bs->v.text.body_lines);
+      break;
+      
+    case mu_message_rfc822:
+      mu_printf ("mu_message_rfc822:\n%*sbody_lines=%lu\n", indent + 4, "",
+                (unsigned long) bs->v.rfc822.body_lines);
+      print_imapenvelope (bs->v.rfc822.body_env, level + 1);
+      print_bs (bs->v.rfc822.body_struct, level + 1);
+      break;
+      
+    case mu_message_multipart:
+      {
+       struct print_data pd;
+       pd.num = 0;
+       pd.level = level + 1;
+       mu_printf ("mu_message_multipart:\n");
+       mu_list_foreach (bs->v.multipart.body_parts, print_item, &pd);
+      }
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  mu_mailbox_t mbox;
+  mu_message_t mesg;
+  struct mu_bodystructure *bs;
+  
+  if (argc != 3)
+    {
+      fprintf (stderr, "usage: %s URL NUM\n", argv[0]);
+      return 1;
+    }
+
+  mu_register_all_mbox_formats ();
+  MU_ASSERT (mu_mailbox_create (&mbox, argv[1]));
+  MU_ASSERT (mu_mailbox_open (mbox, MU_STREAM_READ));
+  MU_ASSERT (mu_mailbox_get_message (mbox, atoi (argv[2]), &mesg));
+  MU_ASSERT (mu_message_get_bodystructure (mesg, &bs));
+  print_bs (bs, 0);
+  mu_bodystructure_free (bs);
+  
+  return 0;
+}


hooks/post-receive
-- 
GNU Mailutils



reply via email to

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