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-495-g217ae7a


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-495-g217ae7a
Date: Fri, 02 Dec 2011 12:33:04 +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=217ae7a2228c6f7054b4e8e1731ec5e17f0a86a4

The branch, master has been updated
       via  217ae7a2228c6f7054b4e8e1731ec5e17f0a86a4 (commit)
      from  1ae9bae29836a20784c836b630264b9e15e5af13 (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 217ae7a2228c6f7054b4e8e1731ec5e17f0a86a4
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Dec 2 00:06:31 2011 +0200

    Split ibmailutils/mailbox/message.c into logically separated and
    easily manageable parts.

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

Summary of changes:
 libmailutils/mailbox/Makefile.am                   |   24 +-
 libmailutils/mailbox/message.c                     | 1363 --------------------
 libmailutils/mailbox/msgattr.c                     |   59 +
 libmailutils/mailbox/msgbody.c                     |   85 ++
 libmailutils/mailbox/msgcpy.c                      |   86 ++
 libmailutils/{list/create.c => mailbox/msgcreat.c} |   42 +-
 libmailutils/mailbox/msgenv.c                      |  161 +++
 libmailutils/mailbox/msgheader.c                   |  163 +++
 libmailutils/mailbox/msglines.c                    |   65 +
 libmu_dbm/name.c => libmailutils/mailbox/msgmbx.c  |   35 +-
 libmailutils/mailbox/msgmod.c                      |   62 +
 .../create.c => libmailutils/mailbox/msgmulti.c    |   66 +-
 .../create.c => libmailutils/mailbox/msgnumparts.c |   60 +-
 libmu_dbm/name.c => libmailutils/mailbox/msgobs.c  |   31 +-
 .../create.c => libmailutils/mailbox/msgpart.c     |   60 +-
 libmu_dbm/name.c => libmailutils/mailbox/msgqid.c  |   38 +-
 libmailutils/mailbox/msgqlines.c                   |   62 +
 libmailutils/mailbox/msgref.c                      |  136 ++
 libmailutils/mailbox/msgsave.c                     |   76 ++
 libmailutils/mailbox/msgsize.c                     |   66 +
 libmailutils/mailbox/msgstream.c                   |  365 ++++++
 libmu_dbm/name.c => libmailutils/mailbox/msguid.c  |   38 +-
 libmailutils/mailbox/msguidl.c                     |  102 ++
 23 files changed, 1696 insertions(+), 1549 deletions(-)
 delete mode 100644 libmailutils/mailbox/message.c
 create mode 100644 libmailutils/mailbox/msgattr.c
 create mode 100644 libmailutils/mailbox/msgbody.c
 create mode 100644 libmailutils/mailbox/msgcpy.c
 copy libmailutils/{list/create.c => mailbox/msgcreat.c} (54%)
 create mode 100644 libmailutils/mailbox/msgenv.c
 create mode 100644 libmailutils/mailbox/msgheader.c
 create mode 100644 libmailutils/mailbox/msglines.c
 copy libmu_dbm/name.c => libmailutils/mailbox/msgmbx.c (61%)
 create mode 100644 libmailutils/mailbox/msgmod.c
 copy libproto/imap/create.c => libmailutils/mailbox/msgmulti.c (50%)
 copy libproto/imap/create.c => libmailutils/mailbox/msgnumparts.c (51%)
 copy libmu_dbm/name.c => libmailutils/mailbox/msgobs.c (61%)
 copy libproto/imap/create.c => libmailutils/mailbox/msgpart.c (51%)
 copy libmu_dbm/name.c => libmailutils/mailbox/msgqid.c (58%)
 create mode 100644 libmailutils/mailbox/msgqlines.c
 create mode 100644 libmailutils/mailbox/msgref.c
 create mode 100644 libmailutils/mailbox/msgsave.c
 create mode 100644 libmailutils/mailbox/msgsize.c
 create mode 100644 libmailutils/mailbox/msgstream.c
 copy libmu_dbm/name.c => libmailutils/mailbox/msguid.c (59%)
 create mode 100644 libmailutils/mailbox/msguidl.c

diff --git a/libmailutils/mailbox/Makefile.am b/libmailutils/mailbox/Makefile.am
index 7f2fe01..27e6c04 100644
--- a/libmailutils/mailbox/Makefile.am
+++ b/libmailutils/mailbox/Makefile.am
@@ -28,7 +28,27 @@ libmailbox_la_SOURCES =  \
  hdrfirst.c\
  hdritr.c\
  header.c\
- message.c\
- msgscan.c
+ msgcpy.c\
+ msgattr.c\
+ msgbody.c\
+ msgcreat.c\
+ msgheader.c\
+ msgenv.c\
+ msglines.c\
+ msgmbx.c\
+ msgmod.c\
+ msgmulti.c\
+ msgnumparts.c\
+ msgobs.c\
+ msgpart.c\
+ msgqid.c\
+ msgqlines.c\
+ msgref.c\
+ msgsave.c\
+ msgscan.c\
+ msgsize.c\
+ msgstream.c\
+ msguid.c\
+ msguidl.c
 
 INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/mailbox/message.c b/libmailutils/mailbox/message.c
deleted file mode 100644
index 8cf233a..0000000
--- a/libmailutils/mailbox/message.c
+++ /dev/null
@@ -1,1363 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
-   2010, 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <unistd.h>
-#include <string.h>
-#include <pwd.h>
-
-#include <mailutils/cctype.h>
-#include <mailutils/address.h>
-#include <mailutils/attribute.h>
-#include <mailutils/auth.h>
-#include <mailutils/body.h>
-#include <mailutils/debug.h>
-#include <mailutils/envelope.h>
-#include <mailutils/errno.h>
-#include <mailutils/folder.h>
-#include <mailutils/header.h>
-#include <mailutils/mailbox.h>
-#include <mailutils/util.h>
-#include <mailutils/observer.h>
-#include <mailutils/stream.h>
-#include <mailutils/mu_auth.h>
-#include <mailutils/nls.h>
-#include <mailutils/md5.h>
-#include <mailutils/io.h>
-
-#include <mailutils/sys/message.h>
-#include <mailutils/sys/stream.h>
-
-
-/* Message stream */
-
-enum _message_stream_state
-  {
-    _mss_init,
-    _mss_header,
-    _mss_body,
-    _mss_eof
-  };
-
-struct _mu_message_stream
-{
-  struct _mu_stream stream;
-  mu_message_t msg;
-  enum _message_stream_state state;
-  mu_stream_t transport;
-  mu_off_t limit;
-};
-
-static int
-_check_stream_state (struct _mu_message_stream *str)
-{
-  int rc = 0;
-  
-  if (str->transport && mu_stream_eof (str->transport))
-    mu_stream_destroy (&str->transport);
-  
-  switch (str->state)
-    {
-    case _mss_init:
-      if (!str->transport)
-       {
-         rc = mu_header_get_streamref (str->msg->header, &str->transport);
-         if (rc == 0)
-           {
-             str->state = _mss_header;
-             rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
-           }
-       }
-      break;
-      
-    case _mss_header:
-      if (!str->transport)
-       {
-         rc = mu_body_get_streamref (str->msg->body, &str->transport);
-         if (rc == 0)
-           {
-             str->state = _mss_body;
-             rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
-           }
-       }
-      break;
-      
-    case _mss_body:
-      if (!str->transport)
-       str->state = _mss_eof;
-    case _mss_eof:
-      break;
-    }
-  return rc;
-}
-
-static void
-_message_stream_done (struct _mu_stream *str)
-{
-  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
-  mu_stream_destroy (&sp->transport);
-}
-
-static int
-_message_stream_flush (struct _mu_stream *str)
-{
-  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
-  int rc = _check_stream_state (sp);
-  if (rc)
-    return rc;
-  return mu_stream_flush (sp->transport);
-}
-  
-static int
-_message_stream_size (struct _mu_stream *str, mu_off_t *psize)
-{
-  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
-  size_t hsize, bsize;
-  mu_header_size (sp->msg->header, &hsize);
-  mu_body_size (sp->msg->body, &bsize);
-  if (psize)
-    *psize = hsize + bsize;
-  return 0;
-}
-
-static int
-_message_stream_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
-{
-  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
-  size_t hsize, size;
-  int rc;
-  
-  rc = _check_stream_state (sp);
-  if (rc)
-    return rc;
-  mu_header_size (sp->msg->header, &hsize);
-  mu_body_size (sp->msg->body, &size);
-  
-  if (off < 0 || off >= size + hsize)
-    return ESPIPE;
-
-  switch (sp->state)
-    {
-    case _mss_eof:
-      sp->state = _mss_init;
-      rc = _check_stream_state (sp);
-      if (rc)
-       return rc;
-      /* fall through */
-    case _mss_header:
-      if (off < hsize)
-       break;
-      mu_stream_destroy (&sp->transport);
-      rc = _check_stream_state (sp);
-      if (rc)
-       return rc;
-      /* fall through */
-    case _mss_body:
-      if (off > hsize)
-       off -= hsize;   
-      else
-       {
-         mu_stream_destroy (&sp->transport);
-         sp->state = _mss_init;
-         rc = _check_stream_state (sp);
-         if (rc)
-           return rc;
-       }
-
-      break;
-
-    default:
-      break;
-    }
-  rc = mu_stream_seek (sp->transport, off, MU_SEEK_SET, &off);
-  if (rc == 0)
-    {
-      if (sp->state == _mss_body)
-       off += hsize;
-      *ppos = off;
-    }
-  return rc;
-}
-
-static int
-_message_stream_read (struct _mu_stream *str, char *buf, size_t bufsize,
-                     size_t *pnread)
-{
-  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
-  size_t nread = 0;
-  int rc;
-  
-  while (bufsize)
-    {
-      size_t n;
-      rc = _check_stream_state (sp);
-      if (rc)
-       break;
-      if (sp->state == _mss_eof)
-       break;
-      rc = mu_stream_read (sp->transport, buf, bufsize, &n);
-      if (rc)
-       break;
-      if (n == 0)
-       continue;
-      nread += n;
-      buf += n;
-      bufsize -= n;
-    }
-  *pnread = nread;
-  return rc;
-}
-
-static int
-_message_stream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
-                          int delim, size_t *pnread)
-{
-  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
-  size_t nread = 0;
-  int rc;
-  
-  while (bufsize)
-    {
-      size_t n;
-      rc = _check_stream_state (sp);
-      if (rc)
-       break;
-      if (sp->state == _mss_eof)
-       break;
-      rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &n);
-      if (rc)
-       break;
-      if (n == 0)
-       continue;
-      nread += n;
-      if (buf[n-1] == delim)
-       break;
-      buf += n;
-      bufsize -= n;
-    }
-  *pnread = nread;
-  return rc;
-}  
-
-#if 0
-static int
-_message_stream_write (struct _mu_stream *str,
-                      const char *buf, size_t bufsize,
-                      size_t *pnwritten)
-{
-  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
-  
-  /* FIXME */
-}
-#endif
-
-static int
-_message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags)
-{
-  struct _mu_message_stream *sp;
-
-  sp = (struct _mu_message_stream *) _mu_stream_create (sizeof (*sp),
-                                                       flags |
-                                                       MU_STREAM_SEEK |
-                                                       _MU_STR_OPEN);
-  if (!sp)
-    return ENOMEM;
-
-  sp->stream.read = _message_stream_read;
-  sp->stream.readdelim = _message_stream_readdelim;
-  /* FIXME: Write is not defined */
-  /*  sp->stream.write = _message_stream_write;*/
-  sp->stream.done = _message_stream_done;
-  sp->stream.flush = _message_stream_flush;
-  sp->stream.seek = _message_stream_seek; 
-  sp->stream.size = _message_stream_size;
-  sp->state = _mss_init;
-  sp->msg = msg;
-  *pmsg = (mu_stream_t) sp;
-  return 0;
-}
-
-
-enum eoh_state
-  {
-    eoh_no,
-    eoh_maybe,
-    eoh_yes
-  };
-
-/* Message header stuff */
-static enum eoh_state
-string_find_eoh (enum eoh_state eoh, const char *str, size_t len,
-                size_t *ppos)
-{
-  size_t pos;
-
-  if (eoh == eoh_maybe && *str == '\n')
-    {
-      *ppos = 0;
-      return eoh_yes;
-    }
-  
-  for (pos = 0; pos < len - 1; pos++)
-    if (str[pos] == '\n' && str[pos + 1] == '\n')
-      {
-       *ppos = pos + 1;
-       return eoh_yes;
-      }
-  
-  *ppos = pos + 1;
-  return str[pos] == '\n' ? eoh_maybe : eoh_no;
-}
-
-#define MIN_HEADER_BUF_SIZE 2048
-
-static int
-_header_fill (mu_stream_t stream, char **pbuf, size_t *plen)
-{
-  int status = 0;
-  char *buffer = NULL;
-  size_t bufsize = 0;
-  char inbuf[MIN_HEADER_BUF_SIZE];
-  size_t nread;
-  enum eoh_state eoh = eoh_no;
-  
-  status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
-  if (status)
-    return status;
-      
-  while (eoh != eoh_yes
-        && (status = mu_stream_read (stream, inbuf, sizeof (inbuf), &nread))
-           == 0
-        && nread)
-    {
-      char *nbuf;
-      size_t len;
-
-      eoh = string_find_eoh (eoh, inbuf, nread, &len);
-      
-      nbuf = realloc (buffer, bufsize + len);
-      if (!nbuf)
-       {
-         status = ENOMEM;
-         break;
-       }
-      memcpy (nbuf + bufsize, inbuf, len);
-      buffer = nbuf;
-      bufsize += len;
-    }
-
-  if (status)
-    free (buffer);
-  else
-    {
-      *pbuf = buffer;
-      *plen = bufsize;
-    }
-  return status;
-}
-    
-static int
-message_header_fill (void *data, char **pbuf, size_t *plen)
-{
-  int status = 0;
-  mu_message_t msg = data;
-  mu_stream_t stream;
-
-  status = mu_message_get_streamref (msg, &stream);
-  if (status == 0)
-    {
-      status = _header_fill (stream, pbuf, plen);
-      mu_stream_destroy (&stream);
-    }
-  return status;
-}
-
-
-/* Message envelope */
-static int
-message_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
-                      size_t *pnwrite)
-{
-  mu_message_t msg = mu_envelope_get_owner (envelope);
-  time_t t;
-  size_t n;
-
-  if (msg == NULL)
-    return EINVAL;
-
-  /* FIXME: extract the time from "Date:".  */
-
-  if (buf == NULL || len == 0)
-    {
-      n = MU_ENVELOPE_DATE_LENGTH;
-    }
-  else
-    {
-      char tmpbuf[MU_ENVELOPE_DATE_LENGTH+1];
-      t = time (NULL);
-      n = mu_strftime (tmpbuf, sizeof tmpbuf, 
-                       MU_ENVELOPE_DATE_FORMAT, localtime (&t));
-      n = mu_cpystr (buf, tmpbuf, len);
-    }
-  if (pnwrite)
-    *pnwrite = n;
-  return 0;
-}
-
-static int
-message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
-                        size_t *pnwrite)
-{
-  mu_message_t msg = mu_envelope_get_owner (envelope);
-  mu_header_t header;
-  int status;
-  const char *sender;
-  struct mu_auth_data *auth = NULL;
-  static char *hdrnames[] = {
-    "X-Envelope-Sender",
-    "X-Envelope-From",
-    "X-Original-Sender",
-    "From",
-    NULL
-  };
-  mu_address_t address = NULL;
-
-  if (msg == NULL)
-    return EINVAL;
-
-  /* First, try the header  */
-  status = mu_message_get_header (msg, &header);
-  if (status)
-    return status;
-  status = mu_header_sget_firstof (header, hdrnames, &sender, NULL);
-  if (status)
-    {
-      auth = mu_get_auth_by_uid (getuid ());
-      if (!auth)
-       return MU_ERR_NOENT;
-      sender = auth->name;
-    }
-
-  status = mu_address_create (&address, sender);
-  if (status == 0)
-    {
-      status = mu_address_sget_email (address, 1, &sender);
-      if (status == 0)
-       {
-         size_t n = strlen (sender);
-         if (buf && len > 0)
-           {
-             len--; /* One for the null.  */
-             n = (n < len) ? n : len;
-             memcpy (buf, sender, n);
-             buf[n] = '\0';
-           }
-         if (pnwrite)
-           *pnwrite = n;
-       }
-      mu_address_destroy (&address);
-    }
-  
-  if (auth)
-    mu_auth_data_free (auth);
-
-  return status;
-}
-
-
-
-/*  Allocate ressources for the mu_message_t.  */
-int
-mu_message_create (mu_message_t *pmsg, void *owner)
-{
-  mu_message_t msg;
-  int status;
-
-  if (pmsg == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-  msg = calloc (1, sizeof (*msg));
-  if (msg == NULL)
-    return ENOMEM;
-  status = mu_monitor_create (&msg->monitor, 0, msg);
-  if (status != 0)
-    {
-      free (msg);
-      return status;
-    }
-  msg->owner = owner;
-  msg->ref_count = 1;
-  *pmsg = msg;
-  return 0;
-}
-
-/* Free the message and all associated stuff */
-static void
-_mu_message_free (mu_message_t msg)
-{
-  /* Notify the listeners.  */
-  /* FIXME: to be removed since we do not support this event.  */
-  if (msg->observable)
-    {
-      mu_observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY, msg);
-      mu_observable_destroy (&msg->observable, msg);
-    }
-      
-  /* Envelope.  */
-  if (msg->envelope)
-    mu_envelope_destroy (&msg->envelope, msg);
-      
-  /* Header.  */
-  if (msg->header)
-    mu_header_destroy (&msg->header);
-      
-  /* Body.  */
-  if (msg->body)
-    mu_body_destroy (&msg->body, msg);
-      
-  /* Attribute.  */
-  if (msg->attribute)
-    mu_attribute_destroy (&msg->attribute, msg);
-      
-  /* Stream.  */
-  if (msg->stream)
-    mu_stream_destroy (&msg->stream);
-      
-  /*  Mime.  */
-  if (msg->flags & MESSAGE_MIME_OWNER)
-    mu_mime_destroy (&msg->mime);
-      
-  /* Loose the owner.  */
-  msg->owner = NULL;
-      
-  free (msg);
-}
-
-void
-mu_message_unref (mu_message_t msg)
-{
-  if (msg)
-    {
-      mu_monitor_t monitor = msg->monitor;
-      mu_monitor_wrlock (monitor);
-      /* Note: msg->ref may be incremented by mu_message_ref without
-        additional checking for its owner, therefore decrementing
-        it must also occur independently of the owner checking. Due
-        to this inconsistency ref may reach negative values, which
-        is very unfortunate.
-        
-        The `owner' stuff is a leftover from older mailutils versions.
-        We are heading to removing it altogether. */
-      if (msg->ref_count > 0)
-       msg->ref_count--;
-      if (msg->ref_count == 0)
-       {
-         _mu_message_free (msg);
-         mu_monitor_unlock (monitor);
-         mu_monitor_destroy (&monitor, msg);
-       }
-      else
-       mu_monitor_unlock (monitor);
-    }
-}
-
-void
-mu_message_destroy (mu_message_t *pmsg, void *owner)
-{
-  if (pmsg && *pmsg)
-    {
-      mu_message_t msg = *pmsg;
-      
-      mu_monitor_t monitor = msg->monitor;
-      mu_monitor_wrlock (monitor);
-
-      if (msg->owner && msg->owner == owner)
-       {
-         _mu_message_free (msg);
-         mu_monitor_unlock (monitor);
-         mu_monitor_destroy (&monitor, msg);
-         *pmsg = NULL;
-         return;
-       }
-      mu_monitor_unlock (monitor);
-    }
-}
-
-int
-mu_message_create_copy (mu_message_t *to, mu_message_t from)
-{
-  int status = 0;
-  mu_stream_t fromstr = NULL;
-  mu_stream_t tmp = NULL;
-
-  if (!to)
-    return MU_ERR_OUT_PTR_NULL;
-  if (!from)
-    return EINVAL;
-
-  status = mu_memory_stream_create (&tmp, MU_STREAM_RDWR|MU_STREAM_SEEK);
-  if (status)
-    return status;
-
-  status = mu_message_get_streamref (from, &fromstr);
-  if (status)
-    {
-      mu_stream_destroy (&tmp);
-      return status;
-    }
-
-  status = mu_stream_copy (tmp, fromstr, 0, NULL);
-  if (status == 0)
-    {
-      status = mu_message_create (to, NULL);
-      if (status == 0)
-       mu_message_set_stream (*to, tmp, NULL);
-    }
-
-  if (status)
-    mu_stream_destroy (&tmp);
-  mu_stream_destroy (&fromstr);
-
-  return status;
-}
-
-void
-mu_message_ref (mu_message_t msg)
-{
-  if (msg)
-    {
-      mu_monitor_wrlock (msg->monitor);
-      msg->ref_count++;
-      mu_monitor_unlock (msg->monitor);
-    }
-}
-
-void *
-mu_message_get_owner (mu_message_t msg)
-{
-  return (msg == NULL) ? NULL : msg->owner;
-}
-
-int
-mu_message_is_modified (mu_message_t msg)
-{
-  int mod = 0;
-  if (msg)
-    {
-      if (mu_header_is_modified (msg->header))
-       mod |= MU_MSG_HEADER_MODIFIED;
-      if (mu_attribute_is_modified (msg->attribute))
-       mod |= MU_MSG_ATTRIBUTE_MODIFIED;
-      if (mu_body_is_modified (msg->body))
-       mod |= MU_MSG_BODY_MODIFIED;
-      if (msg->flags & MESSAGE_MODIFIED)
-       mod |= MU_MSG_BODY_MODIFIED | MU_MSG_HEADER_MODIFIED;
-    }
-  return mod;
-}
-
-int
-mu_message_clear_modified (mu_message_t msg)
-{
-  if (msg)
-    {
-      if (msg->header)
-       mu_header_clear_modified (msg->header);
-      if (msg->attribute)
-       mu_attribute_clear_modified (msg->attribute);
-      if (msg->body)
-       mu_body_clear_modified (msg->body);
-      msg->flags &= ~MESSAGE_MODIFIED;
-    }
-  return 0;
-}
-
-int
-mu_message_get_mailbox (mu_message_t msg, mu_mailbox_t *pmailbox)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (pmailbox == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-  *pmailbox = msg->mailbox;
-  return 0;
-}
-
-int
-mu_message_set_mailbox (mu_message_t msg, mu_mailbox_t mailbox, void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->mailbox = mailbox;
-  return 0;
-}
-
-int
-mu_message_get_header (mu_message_t msg, mu_header_t *phdr)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (phdr == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  if (msg->header == NULL)
-    {
-      mu_header_t header;
-      int status = mu_header_create (&header, NULL, 0);
-      if (status != 0)
-       return status;
-      if (msg->stream)
-       mu_header_set_fill (header, message_header_fill, msg);
-      status = mu_header_size (header, &msg->orig_header_size);
-      if (status)
-       return status;
-      msg->header = header;
-    }
-  *phdr = msg->header;
-  return 0;
-}
-
-/* Note: mu_message_set_header steals the reference to hdr */
-int
-mu_message_set_header (mu_message_t msg, mu_header_t hdr, void *owner)
-{
-  if (msg == NULL )
-    return EINVAL;
-  if (msg->owner != owner)
-     return EACCES;
-  if (msg->header)
-    mu_header_destroy (&msg->header);
-  msg->header = hdr;
-  msg->flags |= MESSAGE_MODIFIED;
-  return 0;
-}
-
-int
-mu_message_get_body (mu_message_t msg, mu_body_t *pbody)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (pbody == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  /* Is it a floating mesg.  */
-  if (msg->body == NULL)
-    {
-      mu_body_t body;
-      int status = mu_body_create (&body, msg);
-      if (status != 0)
-       return status;
-      /* If a stream is already set, use it to create the body stream.  */
-      /* FIXME: I'm not sure if the second condition is really needed */
-      if (msg->stream/* && (msg->flags & MESSAGE_INTERNAL_STREAM)*/)
-       {
-         mu_stream_t stream;
-         int flags = 0;
-
-         /* FIXME: The actual mu_header_size cannot be used as offset,
-            because the headers might have been modified in between. */
-         
-         mu_stream_get_flags (msg->stream, &flags);
-         status = mu_streamref_create_abridged (&stream, msg->stream,
-                                                msg->orig_header_size, 0);
-         if (status)
-           {
-             mu_body_destroy (&body, msg);
-             return status;
-           }
-         mu_body_set_stream (body, stream, msg);
-       }
-      msg->body = body;
-    }
-  *pbody = msg->body;
-  return 0;
-}
-
-int
-mu_message_set_body (mu_message_t msg, mu_body_t body, void *owner)
-{
-  if (msg == NULL )
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  /* Make sure we destroy the old if it was owned by the mesg.  */
-  /* FIXME:  I do not know if somebody has already a ref on this ? */
-  if (msg->body)
-    mu_body_destroy (&msg->body, msg);
-  msg->body = body;
-  msg->flags |= MESSAGE_MODIFIED;
-  return 0;
-}
-
-int
-mu_message_set_stream (mu_message_t msg, mu_stream_t stream, void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  if (msg->stream)
-    mu_stream_destroy (&msg->stream);
-  msg->stream = stream;
-  msg->flags |= MESSAGE_MODIFIED;
-  msg->flags &= ~MESSAGE_INTERNAL_STREAM;
-  return 0;
-}
-
-static int
-_message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref)
-{
-  int status;
-
-  if (msg == NULL)
-    return EINVAL;
-  if (pstream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  if (msg->stream == NULL)
-    {
-      if (msg->_get_stream)
-       {
-         status = msg->_get_stream (msg, &msg->stream);
-         if (status)
-           return status;
-       }
-      else
-       {
-         mu_header_t hdr;
-         mu_body_t body;
-
-         /* FIXME: Kind of a kludge: make sure the message has header
-            and body initialized. */
-         status = mu_message_get_header (msg, &hdr);
-         if (status)
-           return status;
-         status = mu_message_get_body (msg, &body);
-         if (status)
-           return status;
-         
-         status = _message_stream_create (&msg->stream, msg, MU_STREAM_RDWR);
-         if (status)
-           return status;
-         msg->flags |= MESSAGE_INTERNAL_STREAM;
-       }
-    }
-  
-  if (!ref)
-    {
-      *pstream = msg->stream;
-      return 0;
-    }
-  return mu_streamref_create (pstream, msg->stream);
-}
-
-int
-mu_message_get_stream (mu_message_t msg, mu_stream_t *pstream)
-{
-  /* FIXME: Deprecation warning */
-  return _message_get_stream (msg, pstream, 0);
-}
-
-int
-mu_message_get_streamref (mu_message_t msg, mu_stream_t *pstream)
-{
-  return _message_get_stream (msg, pstream, 1);
-}
-
-int
-mu_message_set_get_stream (mu_message_t msg,
-                          int (*_getstr) (mu_message_t, mu_stream_t *),
-                          void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_get_stream = _getstr;
-  return 0;
-}
-
-int
-mu_message_set_lines (mu_message_t msg, int (*_lines)
-                     (mu_message_t, size_t *, int), void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_lines = _lines;
-  return 0;
-}
-
-int
-mu_message_lines (mu_message_t msg, size_t *plines)
-{
-  size_t hlines, blines;
-  int ret = 0;
-
-  if (msg == NULL)
-    return EINVAL;
-  /* Overload.  */
-  if (msg->_lines)
-    return msg->_lines (msg, plines, 0);
-  if (plines)
-    {
-      mu_header_t hdr = NULL;
-      mu_body_t body = NULL;
-
-      hlines = blines = 0;
-      mu_message_get_header (msg, &hdr);
-      mu_message_get_body (msg, &body);
-      if ( ( ret = mu_header_lines (hdr, &hlines) ) == 0 )
-             ret = mu_body_lines (body, &blines);
-      *plines = hlines + blines;
-    }
-  return ret;
-}
-
-/* Return the number of lines in the message, without going into
-   excess trouble for calculating it.  If obtaining the result
-   means downloading the entire message (as is the case for POP3,
-   for example), return MU_ERR_INFO_UNAVAILABLE. */
-int
-mu_message_quick_lines (mu_message_t msg, size_t *plines)
-{
-  size_t hlines, blines;
-  int rc;
-  
-  if (msg == NULL)
-    return EINVAL;
-  /* Overload.  */
-  if (msg->_lines)
-    {
-      int rc = msg->_lines (msg, plines, 1);
-      if (rc != ENOSYS)
-       return rc;
-    }
-  if (plines)
-    {
-      mu_header_t hdr = NULL;
-      mu_body_t body = NULL;
-
-      hlines = blines = 0;
-      mu_message_get_header (msg, &hdr);
-      mu_message_get_body (msg, &body);
-      if ((rc = mu_header_lines (hdr, &hlines)) == 0)
-       rc = mu_body_lines (body, &blines);
-      if (rc == 0)
-       *plines = hlines + blines;
-    }
-  return rc;
-}
-
-int
-mu_message_set_size (mu_message_t msg, int (*_size)
-                    (mu_message_t, size_t *), void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_size = _size;
-  return 0;
-}
-
-int
-mu_message_size (mu_message_t msg, size_t *psize)
-{
-  size_t hsize, bsize;
-  int ret = 0;
-
-  if (msg == NULL)
-    return EINVAL;
-  /* Overload ? */
-  if (msg->_size)
-    return msg->_size (msg, psize);
-  if (psize)
-    {
-      mu_header_t hdr = NULL;
-      mu_body_t body = NULL;
-      
-      hsize = bsize = 0;
-      mu_message_get_header (msg, &hdr);
-      mu_message_get_body (msg, &body);
-      if ( ( ret = mu_header_size (hdr, &hsize) ) == 0 )
-       ret = mu_body_size (body, &bsize);
-      *psize = hsize + bsize;
-    }
-  return ret;
-}
-
-int
-mu_message_get_envelope (mu_message_t msg, mu_envelope_t *penvelope)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (penvelope == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  if (msg->envelope == NULL)
-    {
-      mu_envelope_t envelope;
-      int status = mu_envelope_create (&envelope, msg);
-      if (status != 0)
-       return status;
-      mu_envelope_set_sender (envelope, message_envelope_sender, msg);
-      mu_envelope_set_date (envelope, message_envelope_date, msg);
-      msg->envelope = envelope;
-    }
-  *penvelope = msg->envelope;
-  return 0;
-}
-
-int
-mu_message_set_envelope (mu_message_t msg, mu_envelope_t envelope, void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  if (msg->envelope)
-    mu_envelope_destroy (&msg->envelope, msg);
-  msg->envelope = envelope;
-  msg->flags |= MESSAGE_MODIFIED;
-  return 0;
-}
-
-int
-mu_message_get_attribute (mu_message_t msg, mu_attribute_t *pattribute)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (pattribute == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-  if (msg->attribute == NULL)
-    {
-      mu_attribute_t attribute;
-      int status = mu_attribute_create (&attribute, msg);
-      if (status != 0)
-       return status;
-      msg->attribute = attribute;
-    }
-  *pattribute = msg->attribute;
-  return 0;
-}
-
-int
-mu_message_set_attribute (mu_message_t msg, mu_attribute_t attribute, void 
*owner)
-{
-  if (msg == NULL)
-   return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  if (msg->attribute)
-    mu_attribute_destroy (&msg->attribute, owner);
-  msg->attribute = attribute;
-  msg->flags |= MESSAGE_MODIFIED;
-  return 0;
-}
-
-int
-mu_message_get_uid (mu_message_t msg, size_t *puid)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->_get_uid)
-    return msg->_get_uid (msg, puid);
-  *puid = 0;
-  return 0;
-}
-
-int
-mu_message_get_uidl (mu_message_t msg, char *buffer, size_t buflen,
-                    size_t *pwriten)
-{
-  mu_header_t header = NULL;
-  size_t n = 0;
-  int status;
-
-  if (msg == NULL || buffer == NULL || buflen == 0)
-    return EINVAL;
-
-  buffer[0] = '\0';
-  /* Try the function overload if error fallback.  */
-  if (msg->_get_uidl)
-    {
-      status = msg->_get_uidl (msg, buffer, buflen, pwriten);
-      if (status == 0)
-       return status;
-    }
-
-  /* Be compatible with Qpopper ? qppoper saves the UIDL in "X-UIDL".
-     We generate a chksum and save it in the header.  */
-  mu_message_get_header (msg, &header);
-  status = mu_header_get_value_unfold (header, "X-UIDL", buffer, buflen, &n);
-  if (status != 0 || n == 0)
-    {
-      size_t uid = 0;
-      struct mu_md5_ctx md5context;
-      mu_stream_t stream = NULL;
-      char buf[1024];
-      unsigned char md5digest[16];
-      char *tmp;
-      n = 0;
-      mu_message_get_uid (msg, &uid);
-      mu_message_get_streamref (msg, &stream);
-      mu_md5_init_ctx (&md5context);
-      status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
-      if (status == 0)
-       {
-         while (mu_stream_read (stream, buf, sizeof (buf), &n) == 0
-                && n > 0)
-           mu_md5_process_bytes (buf, n, &md5context);
-         mu_md5_finish_ctx (&md5context, md5digest);
-         tmp = buf;
-         for (n = 0; n < 16; n++, tmp += 2)
-           sprintf (tmp, "%02x", md5digest[n]);
-         *tmp = '\0';
-         /* POP3 rfc says that an UID should not be longer than 70.  */
-         snprintf (buf + 32, 70, ".%lu.%lu", (unsigned long)time (NULL), 
-                   (unsigned long) uid);
-
-         mu_header_set_value (header, "X-UIDL", buf, 1);
-         buflen--; /* leave space for the NULL.  */
-         strncpy (buffer, buf, buflen)[buflen] = '\0';
-       }
-      mu_stream_destroy (&stream);
-    }
-  return status;
-}
-
-int
-mu_message_get_qid (mu_message_t msg, mu_message_qid_t *pqid)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (!msg->_get_qid)
-    return ENOSYS;
-  return msg->_get_qid (msg, pqid);
-}
-    
-int
-mu_message_set_qid (mu_message_t msg,
-                   int (*_get_qid) (mu_message_t, mu_message_qid_t *),
-                   void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_get_qid = _get_qid;
-  return 0;
-}
-
-int
-mu_message_set_uid (mu_message_t msg, int (*_get_uid) (mu_message_t, size_t *),
-                   void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_get_uid = _get_uid;
-  return 0;
-}
-
-int
-mu_message_set_uidl (mu_message_t msg,
-                 int (* _get_uidl) (mu_message_t, char *, size_t, size_t *),
-                 void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_get_uidl = _get_uidl;
-  return 0;
-}
-
-int
-mu_message_set_is_multipart (mu_message_t msg,
-                         int (*_is_multipart) (mu_message_t, int *),
-                         void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_is_multipart = _is_multipart;
-  return 0;
-}
-
-int
-mu_message_is_multipart (mu_message_t msg, int *pmulti)
-{
-  if (msg && pmulti)
-    {
-      if (msg->_is_multipart)
-       return msg->_is_multipart (msg, pmulti);
-      if (msg->mime == NULL)
-       {
-         int status = mu_mime_create (&msg->mime, msg, 0);
-         if (status != 0)
-           return 0;
-         msg->flags |= MESSAGE_MIME_OWNER;
-       }
-      *pmulti = mu_mime_is_multipart(msg->mime);
-    }
-  return 0;
-}
-
-int
-mu_message_get_num_parts (mu_message_t msg, size_t *pparts)
-{
-  if (msg == NULL || pparts == NULL)
-    return EINVAL;
-
-  if (msg->_get_num_parts)
-    return msg->_get_num_parts (msg, pparts);
-
-  if (msg->mime == NULL)
-    {
-      int status = mu_mime_create (&msg->mime, msg, 0);
-      if (status != 0)
-       return status;
-    }
-  return mu_mime_get_num_parts (msg->mime, pparts);
-}
-
-int
-mu_message_set_get_num_parts (mu_message_t msg,
-                          int (*_get_num_parts) (mu_message_t, size_t *),
-                          void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_get_num_parts = _get_num_parts;
-  return 0;
-}
-
-int
-mu_message_get_part (mu_message_t msg, size_t part, mu_message_t *pmsg)
-{
-  if (msg == NULL || pmsg == NULL)
-    return EINVAL;
-
-  /* Overload.  */
-  if (msg->_get_part)
-    return msg->_get_part (msg, part, pmsg);
-
-  if (msg->mime == NULL)
-    {
-      int status = mu_mime_create (&msg->mime, msg, 0);
-      if (status != 0)
-       return status;
-    }
-  return mu_mime_get_part (msg->mime, part, pmsg);
-}
-
-int
-mu_message_set_get_part (mu_message_t msg, int (*_get_part)
-                     (mu_message_t, size_t, mu_message_t *),
-                     void *owner)
-{
-  if (msg == NULL)
-    return EINVAL;
-  if (msg->owner != owner)
-    return EACCES;
-  msg->_get_part = _get_part;
-  return 0;
-}
-
-int
-mu_message_get_observable (mu_message_t msg, mu_observable_t *pobservable)
-{
-  if (msg == NULL || pobservable == NULL)
-    return EINVAL;
-
-  if (msg->observable == NULL)
-    {
-      int status = mu_observable_create (&msg->observable, msg);
-      if (status != 0)
-       return status;
-    }
-  *pobservable = msg->observable;
-  return 0;
-}
-
-int
-mu_message_save_to_mailbox (mu_message_t msg, const char *toname, int perms)
-{
-  int rc = 0;
-  mu_mailbox_t to = 0;
-
-  if ((rc = mu_mailbox_create_default (&to, toname)))
-    {
-      mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,              
-               ("mu_mailbox_create_default (%s) failed: %s\n", toname,
-                mu_strerror (rc)));
-      goto end;
-    }
-
-  if ((rc = mu_mailbox_open (to,
-                            MU_STREAM_WRITE | MU_STREAM_CREAT
-                            | (perms & MU_STREAM_IMASK))))
-    {
-      mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,              
-               ("mu_mailbox_open (%s) failed: %s", toname,
-                mu_strerror (rc)));
-      goto end;
-    }
-
-  if ((rc = mu_mailbox_append_message (to, msg)))
-    {
-      mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,              
-               ("mu_mailbox_append_message (%s) failed: %s", toname,
-                mu_strerror (rc)));
-      goto end;
-    }
-
-end:
-
-  if (!rc)
-    {
-      if ((rc = mu_mailbox_close (to)))
-        mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,            
-                 ("mu_mailbox_close (%s) failed: %s", toname,
-                  mu_strerror (rc)));
-    }
-  else
-    mu_mailbox_close (to);
-
-  mu_mailbox_destroy (&to);
-
-  return rc;
-}
-
diff --git a/libmailutils/mailbox/msgattr.c b/libmailutils/mailbox/msgattr.c
new file mode 100644
index 0000000..6703c5a
--- /dev/null
+++ b/libmailutils/mailbox/msgattr.c
@@ -0,0 +1,59 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/attribute.h>
+#include <mailutils/sys/message.h>
+
+int
+mu_message_get_attribute (mu_message_t msg, mu_attribute_t *pattribute)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (pattribute == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+  if (msg->attribute == NULL)
+    {
+      mu_attribute_t attribute;
+      int status = mu_attribute_create (&attribute, msg);
+      if (status != 0)
+       return status;
+      msg->attribute = attribute;
+    }
+  *pattribute = msg->attribute;
+  return 0;
+}
+
+int
+mu_message_set_attribute (mu_message_t msg, mu_attribute_t attribute, void 
*owner)
+{
+  if (msg == NULL)
+   return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  if (msg->attribute)
+    mu_attribute_destroy (&msg->attribute, owner);
+  msg->attribute = attribute;
+  msg->flags |= MESSAGE_MODIFIED;
+  return 0;
+}
diff --git a/libmailutils/mailbox/msgbody.c b/libmailutils/mailbox/msgbody.c
new file mode 100644
index 0000000..beb5a27
--- /dev/null
+++ b/libmailutils/mailbox/msgbody.c
@@ -0,0 +1,85 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/header.h>
+#include <mailutils/body.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/message.h>
+
+int
+mu_message_get_body (mu_message_t msg, mu_body_t *pbody)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (pbody == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+
+  /* Is it a floating mesg.  */
+  if (msg->body == NULL)
+    {
+      mu_body_t body;
+      int status = mu_body_create (&body, msg);
+      if (status != 0)
+       return status;
+      /* If a stream is already set, use it to create the body stream.  */
+      /* FIXME: I'm not sure if the second condition is really needed */
+      if (msg->stream/* && (msg->flags & MESSAGE_INTERNAL_STREAM)*/)
+       {
+         mu_stream_t stream;
+         int flags = 0;
+
+         /* FIXME: The actual mu_header_size cannot be used as offset,
+            because the headers might have been modified in between. */
+         
+         mu_stream_get_flags (msg->stream, &flags);
+         status = mu_streamref_create_abridged (&stream, msg->stream,
+                                                msg->orig_header_size, 0);
+         if (status)
+           {
+             mu_body_destroy (&body, msg);
+             return status;
+           }
+         mu_body_set_stream (body, stream, msg);
+       }
+      msg->body = body;
+    }
+  *pbody = msg->body;
+  return 0;
+}
+
+int
+mu_message_set_body (mu_message_t msg, mu_body_t body, void *owner)
+{
+  if (msg == NULL )
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  /* Make sure we destroy the old if it was owned by the mesg.  */
+  /* FIXME:  I do not know if somebody has already a ref on this ? */
+  if (msg->body)
+    mu_body_destroy (&msg->body, msg);
+  msg->body = body;
+  msg->flags |= MESSAGE_MODIFIED;
+  return 0;
+}
diff --git a/libmailutils/mailbox/msgcpy.c b/libmailutils/mailbox/msgcpy.c
new file mode 100644
index 0000000..29f1f28
--- /dev/null
+++ b/libmailutils/mailbox/msgcpy.c
@@ -0,0 +1,86 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/message.h>
+
+int
+mu_message_create_copy (mu_message_t *to, mu_message_t from)
+{
+  int status = 0;
+  mu_stream_t fromstr = NULL;
+  mu_stream_t tmp = NULL;
+
+  if (!to)
+    return MU_ERR_OUT_PTR_NULL;
+  if (!from)
+    return EINVAL;
+
+  status = mu_memory_stream_create (&tmp, MU_STREAM_RDWR|MU_STREAM_SEEK);
+  if (status)
+    return status;
+
+  status = mu_message_get_streamref (from, &fromstr);
+  if (status)
+    {
+      mu_stream_destroy (&tmp);
+      return status;
+    }
+
+  status = mu_stream_copy (tmp, fromstr, 0, NULL);
+  if (status == 0)
+    {
+      status = mu_message_create (to, NULL);
+      if (status == 0)
+       mu_message_set_stream (*to, tmp, NULL);
+    }
+
+  if (status)
+    mu_stream_destroy (&tmp);
+  mu_stream_destroy (&fromstr);
+
+  return status;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libmailutils/list/create.c b/libmailutils/mailbox/msgcreat.c
similarity index 54%
copy from libmailutils/list/create.c
copy to libmailutils/mailbox/msgcreat.c
index c5d59e1..244bf1f 100644
--- a/libmailutils/list/create.c
+++ b/libmailutils/mailbox/msgcreat.c
@@ -1,6 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 2008, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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
@@ -13,37 +13,43 @@
    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 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
+#include <config.h>
 #include <stdlib.h>
 
-#include <mailutils/sys/list.h>
+#include <mailutils/types.h>
+#include <mailutils/message.h>
 #include <mailutils/errno.h>
+#include <mailutils/sys/message.h>
 
+/*  Allocate ressources for the mu_message_t.  */
 int
-mu_list_create (mu_list_t *plist)
+mu_message_create (mu_message_t *pmsg, void *owner)
 {
-  mu_list_t list;
+  mu_message_t msg;
   int status;
 
-  if (plist == NULL)
+  if (pmsg == NULL)
     return MU_ERR_OUT_PTR_NULL;
-  list = calloc (sizeof (*list), 1);
-  if (list == NULL)
+  msg = calloc (1, sizeof (*msg));
+  if (msg == NULL)
     return ENOMEM;
-  status = mu_monitor_create (&list->monitor, 0,  list);
+  status = mu_monitor_create (&msg->monitor, 0, msg);
   if (status != 0)
     {
-      free (list);
+      free (msg);
       return status;
     }
-  list->head.next = &list->head;
-  list->head.prev = &list->head;
-  *plist = list;
+  msg->owner = owner;
+  msg->ref_count = 1;
+  *pmsg = msg;
   return 0;
 }
+
+void *
+mu_message_get_owner (mu_message_t msg)
+{
+  return (msg == NULL) ? NULL : msg->owner;
+}
diff --git a/libmailutils/mailbox/msgenv.c b/libmailutils/mailbox/msgenv.c
new file mode 100644
index 0000000..a478891
--- /dev/null
+++ b/libmailutils/mailbox/msgenv.c
@@ -0,0 +1,161 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/envelope.h>
+#include <mailutils/util.h>
+#include <mailutils/header.h>
+#include <mailutils/mu_auth.h>
+#include <mailutils/address.h>
+#include <mailutils/sys/message.h>
+
+/* Message envelope */
+static int
+message_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
+                      size_t *pnwrite)
+{
+  mu_message_t msg = mu_envelope_get_owner (envelope);
+  time_t t;
+  size_t n;
+
+  if (msg == NULL)
+    return EINVAL;
+
+  /* FIXME: extract the time from "Date:".  */
+
+  if (buf == NULL || len == 0)
+    {
+      n = MU_ENVELOPE_DATE_LENGTH;
+    }
+  else
+    {
+      char tmpbuf[MU_ENVELOPE_DATE_LENGTH+1];
+      t = time (NULL);
+      n = mu_strftime (tmpbuf, sizeof tmpbuf, 
+                       MU_ENVELOPE_DATE_FORMAT, localtime (&t));
+      n = mu_cpystr (buf, tmpbuf, len);
+    }
+  if (pnwrite)
+    *pnwrite = n;
+  return 0;
+}
+
+static int
+message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
+                        size_t *pnwrite)
+{
+  mu_message_t msg = mu_envelope_get_owner (envelope);
+  mu_header_t header;
+  int status;
+  const char *sender;
+  struct mu_auth_data *auth = NULL;
+  static char *hdrnames[] = {
+    "X-Envelope-Sender",
+    "X-Envelope-From",
+    "X-Original-Sender",
+    "From",
+    NULL
+  };
+  mu_address_t address = NULL;
+
+  if (msg == NULL)
+    return EINVAL;
+
+  /* First, try the header  */
+  status = mu_message_get_header (msg, &header);
+  if (status)
+    return status;
+  status = mu_header_sget_firstof (header, hdrnames, &sender, NULL);
+  if (status)
+    {
+      auth = mu_get_auth_by_uid (getuid ());
+      if (!auth)
+       return MU_ERR_NOENT;
+      sender = auth->name;
+    }
+
+  status = mu_address_create (&address, sender);
+  if (status == 0)
+    {
+      status = mu_address_sget_email (address, 1, &sender);
+      if (status == 0)
+       {
+         size_t n = strlen (sender);
+         if (buf && len > 0)
+           {
+             len--; /* One for the null.  */
+             n = (n < len) ? n : len;
+             memcpy (buf, sender, n);
+             buf[n] = '\0';
+           }
+         if (pnwrite)
+           *pnwrite = n;
+       }
+      mu_address_destroy (&address);
+    }
+  
+  if (auth)
+    mu_auth_data_free (auth);
+
+  return status;
+}
+
+int
+mu_message_get_envelope (mu_message_t msg, mu_envelope_t *penvelope)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (penvelope == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+
+  if (msg->envelope == NULL)
+    {
+      mu_envelope_t envelope;
+      int status = mu_envelope_create (&envelope, msg);
+      if (status != 0)
+       return status;
+      mu_envelope_set_sender (envelope, message_envelope_sender, msg);
+      mu_envelope_set_date (envelope, message_envelope_date, msg);
+      msg->envelope = envelope;
+    }
+  *penvelope = msg->envelope;
+  return 0;
+}
+
+int
+mu_message_set_envelope (mu_message_t msg, mu_envelope_t envelope, void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  if (msg->envelope)
+    mu_envelope_destroy (&msg->envelope, msg);
+  msg->envelope = envelope;
+  msg->flags |= MESSAGE_MODIFIED;
+  return 0;
+}
diff --git a/libmailutils/mailbox/msgheader.c b/libmailutils/mailbox/msgheader.c
new file mode 100644
index 0000000..09052d8
--- /dev/null
+++ b/libmailutils/mailbox/msgheader.c
@@ -0,0 +1,163 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/header.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/message.h>
+
+
+enum eoh_state
+  {
+    eoh_no,
+    eoh_maybe,
+    eoh_yes
+  };
+
+/* Message header stuff */
+static enum eoh_state
+string_find_eoh (enum eoh_state eoh, const char *str, size_t len,
+                size_t *ppos)
+{
+  size_t pos;
+
+  if (eoh == eoh_maybe && *str == '\n')
+    {
+      *ppos = 0;
+      return eoh_yes;
+    }
+  
+  for (pos = 0; pos < len - 1; pos++)
+    if (str[pos] == '\n' && str[pos + 1] == '\n')
+      {
+       *ppos = pos + 1;
+       return eoh_yes;
+      }
+  
+  *ppos = pos + 1;
+  return str[pos] == '\n' ? eoh_maybe : eoh_no;
+}
+
+#define MIN_HEADER_BUF_SIZE 2048
+
+static int
+_header_fill (mu_stream_t stream, char **pbuf, size_t *plen)
+{
+  int status = 0;
+  char *buffer = NULL;
+  size_t bufsize = 0;
+  char inbuf[MIN_HEADER_BUF_SIZE];
+  size_t nread;
+  enum eoh_state eoh = eoh_no;
+  
+  status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+  if (status)
+    return status;
+      
+  while (eoh != eoh_yes
+        && (status = mu_stream_read (stream, inbuf, sizeof (inbuf), &nread))
+           == 0
+        && nread)
+    {
+      char *nbuf;
+      size_t len;
+
+      eoh = string_find_eoh (eoh, inbuf, nread, &len);
+      
+      nbuf = realloc (buffer, bufsize + len);
+      if (!nbuf)
+       {
+         status = ENOMEM;
+         break;
+       }
+      memcpy (nbuf + bufsize, inbuf, len);
+      buffer = nbuf;
+      bufsize += len;
+    }
+
+  if (status)
+    free (buffer);
+  else
+    {
+      *pbuf = buffer;
+      *plen = bufsize;
+    }
+  return status;
+}
+
+static int
+message_header_fill (void *data, char **pbuf, size_t *plen)
+{
+  int status = 0;
+  mu_message_t msg = data;
+  mu_stream_t stream;
+
+  status = mu_message_get_streamref (msg, &stream);
+  if (status == 0)
+    {
+      status = _header_fill (stream, pbuf, plen);
+      mu_stream_destroy (&stream);
+    }
+  return status;
+}
+
+int
+mu_message_get_header (mu_message_t msg, mu_header_t *phdr)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (phdr == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+
+  if (msg->header == NULL)
+    {
+      mu_header_t header;
+      int status = mu_header_create (&header, NULL, 0);
+      if (status != 0)
+       return status;
+      if (msg->stream)
+       mu_header_set_fill (header, message_header_fill, msg);
+      status = mu_header_size (header, &msg->orig_header_size);
+      if (status)
+       return status;
+      msg->header = header;
+    }
+  *phdr = msg->header;
+  return 0;
+}
+
+/* Note: mu_message_set_header steals the reference to hdr */
+int
+mu_message_set_header (mu_message_t msg, mu_header_t hdr, void *owner)
+{
+  if (msg == NULL )
+    return EINVAL;
+  if (msg->owner != owner)
+     return EACCES;
+  if (msg->header)
+    mu_header_destroy (&msg->header);
+  msg->header = hdr;
+  msg->flags |= MESSAGE_MODIFIED;
+  return 0;
+}
diff --git a/libmailutils/mailbox/msglines.c b/libmailutils/mailbox/msglines.c
new file mode 100644
index 0000000..194cee8
--- /dev/null
+++ b/libmailutils/mailbox/msglines.c
@@ -0,0 +1,65 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/header.h>
+#include <mailutils/body.h>
+#include <mailutils/sys/message.h>
+
+int
+mu_message_lines (mu_message_t msg, size_t *plines)
+{
+  size_t hlines, blines;
+  int ret = 0;
+
+  if (msg == NULL)
+    return EINVAL;
+  /* Overload.  */
+  if (msg->_lines)
+    return msg->_lines (msg, plines, 0);
+  if (plines)
+    {
+      mu_header_t hdr = NULL;
+      mu_body_t body = NULL;
+
+      hlines = blines = 0;
+      mu_message_get_header (msg, &hdr);
+      mu_message_get_body (msg, &body);
+      if ( ( ret = mu_header_lines (hdr, &hlines) ) == 0 )
+             ret = mu_body_lines (body, &blines);
+      *plines = hlines + blines;
+    }
+  return ret;
+}
+
+int
+mu_message_set_lines (mu_message_t msg, int (*_lines)
+                     (mu_message_t, size_t *, int), void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_lines = _lines;
+  return 0;
+}
diff --git a/libmu_dbm/name.c b/libmailutils/mailbox/msgmbx.c
similarity index 61%
copy from libmu_dbm/name.c
copy to libmailutils/mailbox/msgmbx.c
index 94aabae..ed421f0 100644
--- a/libmu_dbm/name.c
+++ b/libmailutils/mailbox/msgmbx.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2011 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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
@@ -15,26 +16,32 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <unistd.h>
+#include <config.h>
 #include <stdlib.h>
+
 #include <mailutils/types.h>
-#include <mailutils/list.h>
-#include <mailutils/url.h>
-#include <mailutils/dbm.h>
+#include <mailutils/message.h>
 #include <mailutils/errno.h>
-#include <mailutils/util.h>
-#include "mudbm.h"
+#include <mailutils/sys/message.h>
 
 int
-mu_dbm_get_name (mu_dbm_file_t db, const char **pname)
+mu_message_get_mailbox (mu_message_t msg, mu_mailbox_t *pmailbox)
 {
-  if (!db)
+  if (msg == NULL)
     return EINVAL;
-  if (!pname)
+  if (pmailbox == NULL)
     return MU_ERR_OUT_PTR_NULL;
-  *pname = db->db_name;
+  *pmailbox = msg->mailbox;
+  return 0;
+}
+
+int
+mu_message_set_mailbox (mu_message_t msg, mu_mailbox_t mailbox, void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->mailbox = mailbox;
   return 0;
 }
diff --git a/libmailutils/mailbox/msgmod.c b/libmailutils/mailbox/msgmod.c
new file mode 100644
index 0000000..5582a42
--- /dev/null
+++ b/libmailutils/mailbox/msgmod.c
@@ -0,0 +1,62 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/header.h>
+#include <mailutils/attribute.h>
+#include <mailutils/body.h>
+#include <mailutils/sys/message.h>
+
+int
+mu_message_is_modified (mu_message_t msg)
+{
+  int mod = 0;
+  if (msg)
+    {
+      if (mu_header_is_modified (msg->header))
+       mod |= MU_MSG_HEADER_MODIFIED;
+      if (mu_attribute_is_modified (msg->attribute))
+       mod |= MU_MSG_ATTRIBUTE_MODIFIED;
+      if (mu_body_is_modified (msg->body))
+       mod |= MU_MSG_BODY_MODIFIED;
+      if (msg->flags & MESSAGE_MODIFIED)
+       mod |= MU_MSG_BODY_MODIFIED | MU_MSG_HEADER_MODIFIED;
+    }
+  return mod;
+}
+
+int
+mu_message_clear_modified (mu_message_t msg)
+{
+  if (msg)
+    {
+      if (msg->header)
+       mu_header_clear_modified (msg->header);
+      if (msg->attribute)
+       mu_attribute_clear_modified (msg->attribute);
+      if (msg->body)
+       mu_body_clear_modified (msg->body);
+      msg->flags &= ~MESSAGE_MODIFIED;
+    }
+  return 0;
+}
diff --git a/libproto/imap/create.c b/libmailutils/mailbox/msgmulti.c
similarity index 50%
copy from libproto/imap/create.c
copy to libmailutils/mailbox/msgmulti.c
index 9ae92eb..9dffb94 100644
--- a/libproto/imap/create.c
+++ b/libmailutils/mailbox/msgmulti.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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
@@ -15,52 +16,43 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
+#include <config.h>
 #include <stdlib.h>
-#include <errno.h>
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/mime.h>
 #include <mailutils/errno.h>
-#include <mailutils/sys/imap.h>
-#include <mailutils/list.h>
+#include <mailutils/sys/message.h>
 
 int
-mu_imap_create (mu_imap_t *pimap)
+mu_message_is_multipart (mu_message_t msg, int *pmulti)
 {
-  mu_imap_t imap;
-
-  /* Sanity check.  */
-  if (pimap == NULL)
-    return EINVAL;
-
-  imap = calloc (1, sizeof *imap);
-  if (imap == NULL)
-    return ENOMEM;
-
-  _mu_imap_init (imap);
-
-  *pimap = imap;
+  if (msg && pmulti)
+    {
+      if (msg->_is_multipart)
+       return msg->_is_multipart (msg, pmulti);
+      if (msg->mime == NULL)
+       {
+         int status = mu_mime_create (&msg->mime, msg, 0);
+         if (status != 0)
+           return 0;
+         msg->flags |= MESSAGE_MIME_OWNER;
+       }
+      *pmulti = mu_mime_is_multipart(msg->mime);
+    }
   return 0;
 }
 
 int
-_mu_imap_init (mu_imap_t imap)
+mu_message_set_is_multipart (mu_message_t msg,
+                            int (*_is_multipart) (mu_message_t, int *),
+                            void *owner)
 {
-  if (imap == NULL)
+  if (msg == NULL)
     return EINVAL;
-  if (!imap->io)
-    {
-      int rc;
-      
-      mu_list_destroy (&imap->capa);
-      _mu_imap_clrerrstr (imap);
-      rc = _mu_imap_tag_clr (imap);
-      imap->flags = 0;
-      if (rc)
-       return rc;
-    }
-  imap->client_state = MU_IMAP_CLIENT_READY; 
-  imap->session_state = MU_IMAP_SESSION_INIT;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_is_multipart = _is_multipart;
   return 0;
 }
+
diff --git a/libproto/imap/create.c b/libmailutils/mailbox/msgnumparts.c
similarity index 51%
copy from libproto/imap/create.c
copy to libmailutils/mailbox/msgnumparts.c
index 9ae92eb..fb51872 100644
--- a/libproto/imap/create.c
+++ b/libmailutils/mailbox/msgnumparts.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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
@@ -15,52 +16,41 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
+#include <config.h>
 #include <stdlib.h>
-#include <errno.h>
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/mime.h>
 #include <mailutils/errno.h>
-#include <mailutils/sys/imap.h>
-#include <mailutils/list.h>
+#include <mailutils/sys/message.h>
 
 int
-mu_imap_create (mu_imap_t *pimap)
+mu_message_get_num_parts (mu_message_t msg, size_t *pparts)
 {
-  mu_imap_t imap;
-
-  /* Sanity check.  */
-  if (pimap == NULL)
+  if (msg == NULL || pparts == NULL)
     return EINVAL;
 
-  imap = calloc (1, sizeof *imap);
-  if (imap == NULL)
-    return ENOMEM;
+  if (msg->_get_num_parts)
+    return msg->_get_num_parts (msg, pparts);
 
-  _mu_imap_init (imap);
-
-  *pimap = imap;
-  return 0;
+  if (msg->mime == NULL)
+    {
+      int status = mu_mime_create (&msg->mime, msg, 0);
+      if (status != 0)
+       return status;
+    }
+  return mu_mime_get_num_parts (msg->mime, pparts);
 }
 
 int
-_mu_imap_init (mu_imap_t imap)
+mu_message_set_get_num_parts (mu_message_t msg,
+                          int (*_get_num_parts) (mu_message_t, size_t *),
+                          void *owner)
 {
-  if (imap == NULL)
+  if (msg == NULL)
     return EINVAL;
-  if (!imap->io)
-    {
-      int rc;
-      
-      mu_list_destroy (&imap->capa);
-      _mu_imap_clrerrstr (imap);
-      rc = _mu_imap_tag_clr (imap);
-      imap->flags = 0;
-      if (rc)
-       return rc;
-    }
-  imap->client_state = MU_IMAP_CLIENT_READY; 
-  imap->session_state = MU_IMAP_SESSION_INIT;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_get_num_parts = _get_num_parts;
   return 0;
 }
diff --git a/libmu_dbm/name.c b/libmailutils/mailbox/msgobs.c
similarity index 61%
copy from libmu_dbm/name.c
copy to libmailutils/mailbox/msgobs.c
index 94aabae..aa8065e 100644
--- a/libmu_dbm/name.c
+++ b/libmailutils/mailbox/msgobs.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2011 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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
@@ -15,26 +16,26 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <unistd.h>
+#include <config.h>
 #include <stdlib.h>
 #include <mailutils/types.h>
-#include <mailutils/list.h>
-#include <mailutils/url.h>
-#include <mailutils/dbm.h>
+#include <mailutils/message.h>
 #include <mailutils/errno.h>
-#include <mailutils/util.h>
-#include "mudbm.h"
+#include <mailutils/observer.h>
+#include <mailutils/sys/message.h>
 
 int
-mu_dbm_get_name (mu_dbm_file_t db, const char **pname)
+mu_message_get_observable (mu_message_t msg, mu_observable_t *pobservable)
 {
-  if (!db)
+  if (msg == NULL || pobservable == NULL)
     return EINVAL;
-  if (!pname)
-    return MU_ERR_OUT_PTR_NULL;
-  *pname = db->db_name;
+
+  if (msg->observable == NULL)
+    {
+      int status = mu_observable_create (&msg->observable, msg);
+      if (status != 0)
+       return status;
+    }
+  *pobservable = msg->observable;
   return 0;
 }
diff --git a/libproto/imap/create.c b/libmailutils/mailbox/msgpart.c
similarity index 51%
copy from libproto/imap/create.c
copy to libmailutils/mailbox/msgpart.c
index 9ae92eb..4be2478 100644
--- a/libproto/imap/create.c
+++ b/libmailutils/mailbox/msgpart.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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
@@ -15,52 +16,41 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
+#include <config.h>
 #include <stdlib.h>
-#include <errno.h>
+#include <mailutils/types.h>
+#include <mailutils/message.h>
 #include <mailutils/errno.h>
-#include <mailutils/sys/imap.h>
-#include <mailutils/list.h>
+#include <mailutils/sys/message.h>
 
 int
-mu_imap_create (mu_imap_t *pimap)
+mu_message_get_part (mu_message_t msg, size_t part, mu_message_t *pmsg)
 {
-  mu_imap_t imap;
-
-  /* Sanity check.  */
-  if (pimap == NULL)
+  if (msg == NULL || pmsg == NULL)
     return EINVAL;
 
-  imap = calloc (1, sizeof *imap);
-  if (imap == NULL)
-    return ENOMEM;
+  /* Overload.  */
+  if (msg->_get_part)
+    return msg->_get_part (msg, part, pmsg);
 
-  _mu_imap_init (imap);
-
-  *pimap = imap;
-  return 0;
+  if (msg->mime == NULL)
+    {
+      int status = mu_mime_create (&msg->mime, msg, 0);
+      if (status != 0)
+       return status;
+    }
+  return mu_mime_get_part (msg->mime, part, pmsg);
 }
 
 int
-_mu_imap_init (mu_imap_t imap)
+mu_message_set_get_part (mu_message_t msg, int (*_get_part)
+                     (mu_message_t, size_t, mu_message_t *),
+                     void *owner)
 {
-  if (imap == NULL)
+  if (msg == NULL)
     return EINVAL;
-  if (!imap->io)
-    {
-      int rc;
-      
-      mu_list_destroy (&imap->capa);
-      _mu_imap_clrerrstr (imap);
-      rc = _mu_imap_tag_clr (imap);
-      imap->flags = 0;
-      if (rc)
-       return rc;
-    }
-  imap->client_state = MU_IMAP_CLIENT_READY; 
-  imap->session_state = MU_IMAP_SESSION_INIT;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_get_part = _get_part;
   return 0;
 }
diff --git a/libmu_dbm/name.c b/libmailutils/mailbox/msgqid.c
similarity index 58%
copy from libmu_dbm/name.c
copy to libmailutils/mailbox/msgqid.c
index 94aabae..04e3ab9 100644
--- a/libmu_dbm/name.c
+++ b/libmailutils/mailbox/msgqid.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2011 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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
@@ -15,26 +16,33 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <unistd.h>
+#include <config.h>
 #include <stdlib.h>
+
 #include <mailutils/types.h>
-#include <mailutils/list.h>
-#include <mailutils/url.h>
-#include <mailutils/dbm.h>
+#include <mailutils/message.h>
 #include <mailutils/errno.h>
-#include <mailutils/util.h>
-#include "mudbm.h"
+#include <mailutils/sys/message.h>
 
 int
-mu_dbm_get_name (mu_dbm_file_t db, const char **pname)
+mu_message_get_qid (mu_message_t msg, mu_message_qid_t *pqid)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (!msg->_get_qid)
+    return ENOSYS;
+  return msg->_get_qid (msg, pqid);
+}
+    
+int
+mu_message_set_qid (mu_message_t msg,
+                   int (*_get_qid) (mu_message_t, mu_message_qid_t *),
+                   void *owner)
 {
-  if (!db)
+  if (msg == NULL)
     return EINVAL;
-  if (!pname)
-    return MU_ERR_OUT_PTR_NULL;
-  *pname = db->db_name;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_get_qid = _get_qid;
   return 0;
 }
diff --git a/libmailutils/mailbox/msgqlines.c b/libmailutils/mailbox/msgqlines.c
new file mode 100644
index 0000000..a52249a
--- /dev/null
+++ b/libmailutils/mailbox/msgqlines.c
@@ -0,0 +1,62 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/header.h>
+#include <mailutils/body.h>
+#include <mailutils/sys/message.h>
+
+/* Return the number of lines in the message, without going into
+   excess trouble for calculating it.  If obtaining the result
+   means downloading the entire message (as is the case for POP3,
+   for example), return MU_ERR_INFO_UNAVAILABLE. */
+int
+mu_message_quick_lines (mu_message_t msg, size_t *plines)
+{
+  size_t hlines, blines;
+  int rc;
+  
+  if (msg == NULL)
+    return EINVAL;
+  /* Overload.  */
+  if (msg->_lines)
+    {
+      int rc = msg->_lines (msg, plines, 1);
+      if (rc != ENOSYS)
+       return rc;
+    }
+  if (plines)
+    {
+      mu_header_t hdr = NULL;
+      mu_body_t body = NULL;
+
+      hlines = blines = 0;
+      mu_message_get_header (msg, &hdr);
+      mu_message_get_body (msg, &body);
+      if ((rc = mu_header_lines (hdr, &hlines)) == 0)
+       rc = mu_body_lines (body, &blines);
+      if (rc == 0)
+       *plines = hlines + blines;
+    }
+  return rc;
+}
diff --git a/libmailutils/mailbox/msgref.c b/libmailutils/mailbox/msgref.c
new file mode 100644
index 0000000..1419dbb
--- /dev/null
+++ b/libmailutils/mailbox/msgref.c
@@ -0,0 +1,136 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/monitor.h>
+#include <mailutils/observer.h>
+#include <mailutils/envelope.h>
+#include <mailutils/header.h>
+#include <mailutils/body.h>
+#include <mailutils/attribute.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/message.h>
+
+void
+mu_message_ref (mu_message_t msg)
+{
+  if (msg)
+    {
+      mu_monitor_wrlock (msg->monitor);
+      msg->ref_count++;
+      mu_monitor_unlock (msg->monitor);
+    }
+}
+
+/* Free the message and all associated stuff */
+static void
+_mu_message_free (mu_message_t msg)
+{
+  /* Notify the listeners.  */
+  /* FIXME: to be removed since we do not support this event.  */
+  if (msg->observable)
+    {
+      mu_observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY, msg);
+      mu_observable_destroy (&msg->observable, msg);
+    }
+      
+  /* Envelope.  */
+  if (msg->envelope)
+    mu_envelope_destroy (&msg->envelope, msg);
+      
+  /* Header.  */
+  if (msg->header)
+    mu_header_destroy (&msg->header);
+      
+  /* Body.  */
+  if (msg->body)
+    mu_body_destroy (&msg->body, msg);
+      
+  /* Attribute.  */
+  if (msg->attribute)
+    mu_attribute_destroy (&msg->attribute, msg);
+      
+  /* Stream.  */
+  if (msg->stream)
+    mu_stream_destroy (&msg->stream);
+      
+  /*  Mime.  */
+  if (msg->flags & MESSAGE_MIME_OWNER)
+    mu_mime_destroy (&msg->mime);
+      
+  /* Loose the owner.  */
+  msg->owner = NULL;
+      
+  free (msg);
+}
+
+void
+mu_message_unref (mu_message_t msg)
+{
+  if (msg)
+    {
+      mu_monitor_t monitor = msg->monitor;
+      mu_monitor_wrlock (monitor);
+      /* Note: msg->ref may be incremented by mu_message_ref without
+        additional checking for its owner, therefore decrementing
+        it must also occur independently of the owner checking. Due
+        to this inconsistency ref may reach negative values, which
+        is very unfortunate.
+        
+        The `owner' stuff is a leftover from older mailutils versions.
+        We are heading to removing it altogether. */
+      if (msg->ref_count > 0)
+       msg->ref_count--;
+      if (msg->ref_count == 0)
+       {
+         _mu_message_free (msg);
+         mu_monitor_unlock (monitor);
+         mu_monitor_destroy (&monitor, msg);
+       }
+      else
+       mu_monitor_unlock (monitor);
+    }
+}
+
+void
+mu_message_destroy (mu_message_t *pmsg, void *owner)
+{
+  if (pmsg && *pmsg)
+    {
+      mu_message_t msg = *pmsg;
+      
+      mu_monitor_t monitor = msg->monitor;
+      mu_monitor_wrlock (monitor);
+
+      if (msg->owner && msg->owner == owner)
+       {
+         _mu_message_free (msg);
+         mu_monitor_unlock (monitor);
+         mu_monitor_destroy (&monitor, msg);
+         *pmsg = NULL;
+         return;
+       }
+      mu_monitor_unlock (monitor);
+    }
+}
+
diff --git a/libmailutils/mailbox/msgsave.c b/libmailutils/mailbox/msgsave.c
new file mode 100644
index 0000000..89f0e8e
--- /dev/null
+++ b/libmailutils/mailbox/msgsave.c
@@ -0,0 +1,76 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+
+#include <mailutils/types.h>
+#include <mailutils/diag.h>
+#include <mailutils/error.h>
+#include <mailutils/errno.h>
+#include <mailutils/mailbox.h>
+#include <mailutils/message.h>
+#include <mailutils/stream.h>
+
+int
+mu_message_save_to_mailbox (mu_message_t msg, const char *toname, int perms)
+{
+  int rc = 0;
+  mu_mailbox_t to = 0;
+
+  if ((rc = mu_mailbox_create_default (&to, toname)))
+    {
+      mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,              
+               ("mu_mailbox_create_default (%s) failed: %s\n", toname,
+                mu_strerror (rc)));
+      goto end;
+    }
+
+  if ((rc = mu_mailbox_open (to,
+                            MU_STREAM_WRITE | MU_STREAM_CREAT
+                            | (perms & MU_STREAM_IMASK))))
+    {
+      mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,              
+               ("mu_mailbox_open (%s) failed: %s", toname,
+                mu_strerror (rc)));
+      goto end;
+    }
+
+  if ((rc = mu_mailbox_append_message (to, msg)))
+    {
+      mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,              
+               ("mu_mailbox_append_message (%s) failed: %s", toname,
+                mu_strerror (rc)));
+      goto end;
+    }
+
+end:
+
+  if (!rc)
+    {
+      if ((rc = mu_mailbox_close (to)))
+        mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,            
+                 ("mu_mailbox_close (%s) failed: %s", toname,
+                  mu_strerror (rc)));
+    }
+  else
+    mu_mailbox_close (to);
+
+  mu_mailbox_destroy (&to);
+
+  return rc;
+}
diff --git a/libmailutils/mailbox/msgsize.c b/libmailutils/mailbox/msgsize.c
new file mode 100644
index 0000000..874a45d
--- /dev/null
+++ b/libmailutils/mailbox/msgsize.c
@@ -0,0 +1,66 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/header.h>
+#include <mailutils/body.h>
+#include <mailutils/sys/message.h>
+
+int
+mu_message_size (mu_message_t msg, size_t *psize)
+{
+  size_t hsize, bsize;
+  int ret = 0;
+
+  if (msg == NULL)
+    return EINVAL;
+  /* Overload ? */
+  if (msg->_size)
+    return msg->_size (msg, psize);
+  if (psize)
+    {
+      mu_header_t hdr = NULL;
+      mu_body_t body = NULL;
+      
+      hsize = bsize = 0;
+      mu_message_get_header (msg, &hdr);
+      mu_message_get_body (msg, &body);
+      if ( ( ret = mu_header_size (hdr, &hsize) ) == 0 )
+       ret = mu_body_size (body, &bsize);
+      *psize = hsize + bsize;
+    }
+  return ret;
+}
+
+int
+mu_message_set_size (mu_message_t msg, int (*_size)
+                    (mu_message_t, size_t *), void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_size = _size;
+  return 0;
+}
+
diff --git a/libmailutils/mailbox/msgstream.c b/libmailutils/mailbox/msgstream.c
new file mode 100644
index 0000000..a65135c
--- /dev/null
+++ b/libmailutils/mailbox/msgstream.c
@@ -0,0 +1,365 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/header.h>
+#include <mailutils/body.h>
+#include <mailutils/sys/message.h>
+#include <mailutils/sys/stream.h>
+
+/* Message stream */
+
+enum _message_stream_state
+  {
+    _mss_init,
+    _mss_header,
+    _mss_body,
+    _mss_eof
+  };
+
+struct _mu_message_stream
+{
+  struct _mu_stream stream;
+  mu_message_t msg;
+  enum _message_stream_state state;
+  mu_stream_t transport;
+  mu_off_t limit;
+};
+
+static int
+_check_stream_state (struct _mu_message_stream *str)
+{
+  int rc = 0;
+  
+  if (str->transport && mu_stream_eof (str->transport))
+    mu_stream_destroy (&str->transport);
+  
+  switch (str->state)
+    {
+    case _mss_init:
+      if (!str->transport)
+       {
+         rc = mu_header_get_streamref (str->msg->header, &str->transport);
+         if (rc == 0)
+           {
+             str->state = _mss_header;
+             rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
+           }
+       }
+      break;
+      
+    case _mss_header:
+      if (!str->transport)
+       {
+         rc = mu_body_get_streamref (str->msg->body, &str->transport);
+         if (rc == 0)
+           {
+             str->state = _mss_body;
+             rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
+           }
+       }
+      break;
+      
+    case _mss_body:
+      if (!str->transport)
+       str->state = _mss_eof;
+    case _mss_eof:
+      break;
+    }
+  return rc;
+}
+
+static void
+_message_stream_done (struct _mu_stream *str)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  mu_stream_destroy (&sp->transport);
+}
+
+static int
+_message_stream_flush (struct _mu_stream *str)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  int rc = _check_stream_state (sp);
+  if (rc)
+    return rc;
+  return mu_stream_flush (sp->transport);
+}
+  
+static int
+_message_stream_size (struct _mu_stream *str, mu_off_t *psize)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  size_t hsize, bsize;
+  mu_header_size (sp->msg->header, &hsize);
+  mu_body_size (sp->msg->body, &bsize);
+  if (psize)
+    *psize = hsize + bsize;
+  return 0;
+}
+
+static int
+_message_stream_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  size_t hsize, size;
+  int rc;
+  
+  rc = _check_stream_state (sp);
+  if (rc)
+    return rc;
+  mu_header_size (sp->msg->header, &hsize);
+  mu_body_size (sp->msg->body, &size);
+  
+  if (off < 0 || off >= size + hsize)
+    return ESPIPE;
+
+  switch (sp->state)
+    {
+    case _mss_eof:
+      sp->state = _mss_init;
+      rc = _check_stream_state (sp);
+      if (rc)
+       return rc;
+      /* fall through */
+    case _mss_header:
+      if (off < hsize)
+       break;
+      mu_stream_destroy (&sp->transport);
+      rc = _check_stream_state (sp);
+      if (rc)
+       return rc;
+      /* fall through */
+    case _mss_body:
+      if (off > hsize)
+       off -= hsize;   
+      else
+       {
+         mu_stream_destroy (&sp->transport);
+         sp->state = _mss_init;
+         rc = _check_stream_state (sp);
+         if (rc)
+           return rc;
+       }
+
+      break;
+
+    default:
+      break;
+    }
+  rc = mu_stream_seek (sp->transport, off, MU_SEEK_SET, &off);
+  if (rc == 0)
+    {
+      if (sp->state == _mss_body)
+       off += hsize;
+      *ppos = off;
+    }
+  return rc;
+}
+
+static int
+_message_stream_read (struct _mu_stream *str, char *buf, size_t bufsize,
+                     size_t *pnread)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  size_t nread = 0;
+  int rc;
+  
+  while (bufsize)
+    {
+      size_t n;
+      rc = _check_stream_state (sp);
+      if (rc)
+       break;
+      if (sp->state == _mss_eof)
+       break;
+      rc = mu_stream_read (sp->transport, buf, bufsize, &n);
+      if (rc)
+       break;
+      if (n == 0)
+       continue;
+      nread += n;
+      buf += n;
+      bufsize -= n;
+    }
+  *pnread = nread;
+  return rc;
+}
+
+static int
+_message_stream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
+                          int delim, size_t *pnread)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  size_t nread = 0;
+  int rc;
+  
+  while (bufsize)
+    {
+      size_t n;
+      rc = _check_stream_state (sp);
+      if (rc)
+       break;
+      if (sp->state == _mss_eof)
+       break;
+      rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &n);
+      if (rc)
+       break;
+      if (n == 0)
+       continue;
+      nread += n;
+      if (buf[n-1] == delim)
+       break;
+      buf += n;
+      bufsize -= n;
+    }
+  *pnread = nread;
+  return rc;
+}  
+
+#if 0
+static int
+_message_stream_write (struct _mu_stream *str,
+                      const char *buf, size_t bufsize,
+                      size_t *pnwritten)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  
+  /* FIXME */
+}
+#endif
+
+static int
+_message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags)
+{
+  struct _mu_message_stream *sp;
+
+  sp = (struct _mu_message_stream *) _mu_stream_create (sizeof (*sp),
+                                                       flags |
+                                                       MU_STREAM_SEEK |
+                                                       _MU_STR_OPEN);
+  if (!sp)
+    return ENOMEM;
+
+  sp->stream.read = _message_stream_read;
+  sp->stream.readdelim = _message_stream_readdelim;
+  /* FIXME: Write is not defined */
+  /*  sp->stream.write = _message_stream_write;*/
+  sp->stream.done = _message_stream_done;
+  sp->stream.flush = _message_stream_flush;
+  sp->stream.seek = _message_stream_seek; 
+  sp->stream.size = _message_stream_size;
+  sp->state = _mss_init;
+  sp->msg = msg;
+  *pmsg = (mu_stream_t) sp;
+  return 0;
+}
+
+int
+mu_message_set_stream (mu_message_t msg, mu_stream_t stream, void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  if (msg->stream)
+    mu_stream_destroy (&msg->stream);
+  msg->stream = stream;
+  msg->flags |= MESSAGE_MODIFIED;
+  msg->flags &= ~MESSAGE_INTERNAL_STREAM;
+  return 0;
+}
+
+static int
+_message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref)
+{
+  int status;
+
+  if (msg == NULL)
+    return EINVAL;
+  if (pstream == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+
+  if (msg->stream == NULL)
+    {
+      if (msg->_get_stream)
+       {
+         status = msg->_get_stream (msg, &msg->stream);
+         if (status)
+           return status;
+       }
+      else
+       {
+         mu_header_t hdr;
+         mu_body_t body;
+
+         /* FIXME: Kind of a kludge: make sure the message has header
+            and body initialized. */
+         status = mu_message_get_header (msg, &hdr);
+         if (status)
+           return status;
+         status = mu_message_get_body (msg, &body);
+         if (status)
+           return status;
+         
+         status = _message_stream_create (&msg->stream, msg, MU_STREAM_RDWR);
+         if (status)
+           return status;
+         msg->flags |= MESSAGE_INTERNAL_STREAM;
+       }
+    }
+  
+  if (!ref)
+    {
+      *pstream = msg->stream;
+      return 0;
+    }
+  return mu_streamref_create (pstream, msg->stream);
+}
+
+int
+mu_message_get_stream (mu_message_t msg, mu_stream_t *pstream)
+{
+  /* FIXME: Deprecation warning */
+  return _message_get_stream (msg, pstream, 0);
+}
+
+int
+mu_message_get_streamref (mu_message_t msg, mu_stream_t *pstream)
+{
+  return _message_get_stream (msg, pstream, 1);
+}
+
+int
+mu_message_set_get_stream (mu_message_t msg,
+                          int (*_getstr) (mu_message_t, mu_stream_t *),
+                          void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_get_stream = _getstr;
+  return 0;
+}
diff --git a/libmu_dbm/name.c b/libmailutils/mailbox/msguid.c
similarity index 59%
copy from libmu_dbm/name.c
copy to libmailutils/mailbox/msguid.c
index 94aabae..8402e0e 100644
--- a/libmu_dbm/name.c
+++ b/libmailutils/mailbox/msguid.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2011 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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
@@ -15,26 +16,33 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <unistd.h>
+#include <config.h>
 #include <stdlib.h>
+
 #include <mailutils/types.h>
-#include <mailutils/list.h>
-#include <mailutils/url.h>
-#include <mailutils/dbm.h>
+#include <mailutils/message.h>
 #include <mailutils/errno.h>
-#include <mailutils/util.h>
-#include "mudbm.h"
+#include <mailutils/sys/message.h>
+
+int
+mu_message_get_uid (mu_message_t msg, size_t *puid)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->_get_uid)
+    return msg->_get_uid (msg, puid);
+  *puid = 0;
+  return 0;
+}
 
 int
-mu_dbm_get_name (mu_dbm_file_t db, const char **pname)
+mu_message_set_uid (mu_message_t msg, int (*_get_uid) (mu_message_t, size_t *),
+                   void *owner)
 {
-  if (!db)
+  if (msg == NULL)
     return EINVAL;
-  if (!pname)
-    return MU_ERR_OUT_PTR_NULL;
-  *pname = db->db_name;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_get_uid = _get_uid;
   return 0;
 }
diff --git a/libmailutils/mailbox/msguidl.c b/libmailutils/mailbox/msguidl.c
new file mode 100644
index 0000000..2d5a2f2
--- /dev/null
+++ b/libmailutils/mailbox/msguidl.c
@@ -0,0 +1,102 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
+   2010, 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <mailutils/types.h>
+#include <mailutils/message.h>
+#include <mailutils/errno.h>
+#include <mailutils/header.h>
+#include <mailutils/stream.h>
+#include <mailutils/md5.h>
+#include <mailutils/sys/message.h>
+
+int
+mu_message_get_uidl (mu_message_t msg, char *buffer, size_t buflen,
+                    size_t *pwriten)
+{
+  mu_header_t header = NULL;
+  size_t n = 0;
+  int status;
+
+  if (msg == NULL || buffer == NULL || buflen == 0)
+    return EINVAL;
+
+  buffer[0] = '\0';
+  /* Try the function overload if error fallback.  */
+  if (msg->_get_uidl)
+    {
+      status = msg->_get_uidl (msg, buffer, buflen, pwriten);
+      if (status == 0)
+       return status;
+    }
+
+  /* Be compatible with Qpopper ? qppoper saves the UIDL in "X-UIDL".
+     We generate a chksum and save it in the header.  */
+  mu_message_get_header (msg, &header);
+  status = mu_header_get_value_unfold (header, "X-UIDL", buffer, buflen, &n);
+  if (status != 0 || n == 0)
+    {
+      size_t uid = 0;
+      struct mu_md5_ctx md5context;
+      mu_stream_t stream = NULL;
+      char buf[1024];
+      unsigned char md5digest[16];
+      char *tmp;
+      n = 0;
+      mu_message_get_uid (msg, &uid);
+      mu_message_get_streamref (msg, &stream);
+      mu_md5_init_ctx (&md5context);
+      status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+      if (status == 0)
+       {
+         while (mu_stream_read (stream, buf, sizeof (buf), &n) == 0
+                && n > 0)
+           mu_md5_process_bytes (buf, n, &md5context);
+         mu_md5_finish_ctx (&md5context, md5digest);
+         tmp = buf;
+         for (n = 0; n < 16; n++, tmp += 2)
+           sprintf (tmp, "%02x", md5digest[n]);
+         *tmp = '\0';
+         /* POP3 rfc says that an UID should not be longer than 70.  */
+         snprintf (buf + 32, 70, ".%lu.%lu", (unsigned long)time (NULL), 
+                   (unsigned long) uid);
+
+         mu_header_set_value (header, "X-UIDL", buf, 1);
+         buflen--; /* leave space for the NULL.  */
+         strncpy (buffer, buf, buflen)[buflen] = '\0';
+       }
+      mu_stream_destroy (&stream);
+    }
+  return status;
+}
+
+int
+mu_message_set_uidl (mu_message_t msg,
+                 int (* _get_uidl) (mu_message_t, char *, size_t, size_t *),
+                 void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_get_uidl = _get_uidl;
+  return 0;
+}


hooks/post-receive
-- 
GNU Mailutils



reply via email to

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