[evolution-data-server] Bug 764065 - [Camel] Port more classes to GObject



commit 9af0c834ea6094c651f7e82fc2f02afa0c6fd697
Author: Corentin Noël <corentin elementary io>
Date:   Tue Nov 8 15:49:25 2016 +0100

    Bug 764065 - [Camel] Port more classes to GObject
    
    Some parts had been done by Milan Crha.

 CMakeLists.txt                                     |    2 +-
 src/camel/CMakeLists.txt                           |   12 +
 src/camel/camel-address.c                          |   42 +-
 src/camel/camel-address.h                          |    6 +-
 src/camel/camel-async-closure.c                    |    8 +-
 src/camel/camel-block-file.c                       |  434 ++--
 src/camel/camel-block-file.h                       |   32 +-
 src/camel/camel-certdb.h                           |    3 +
 src/camel/camel-charset-map.c                      |   12 +-
 src/camel/camel-cipher-context.c                   |   23 +-
 src/camel/camel-cipher-context.h                   |    4 +-
 src/camel/camel-data-cache.h                       |    3 +
 src/camel/camel-data-wrapper.c                     |  205 ++-
 src/camel/camel-data-wrapper.h                     |   27 +-
 src/camel/camel-db.c                               |  375 +--
 src/camel/camel-db.h                               |  323 ++-
 src/camel/camel-enums.h                            |   14 +
 src/camel/camel-filter-driver.c                    |   31 +-
 src/camel/camel-filter-driver.h                    |    5 +-
 src/camel/camel-filter-input-stream.h              |    3 +
 src/camel/camel-filter-output-stream.h             |    3 +
 src/camel/camel-filter-search.c                    |  123 +-
 src/camel/camel-folder-search.c                    |  485 ++--
 src/camel/camel-folder-search.h                    |   33 +-
 src/camel/camel-folder-summary.c                   | 2955 +++----------------
 src/camel/camel-folder-summary.h                   |  438 +---
 src/camel/camel-folder-thread.c                    |   68 +-
 src/camel/camel-folder.c                           |  404 ++-
 src/camel/camel-folder.h                           |   60 +-
 src/camel/camel-gpg-context.c                      |    2 +-
 src/camel/camel-gpg-context.h                      |    3 +
 src/camel/camel-html-parser.h                      |    3 +
 src/camel/camel-iconv.c                            |   28 +-
 src/camel/camel-index.h                            |    5 +-
 src/camel/camel-internet-address.c                 |  113 +-
 src/camel/camel-internet-address.h                 |    3 +
 src/camel/camel-junk-filter.h                      |    3 +
 src/camel/camel-local-settings.h                   |    3 +
 src/camel/camel-medium.c                           |   56 +-
 src/camel/camel-medium.h                           |   35 +-
 src/camel/camel-memchunk.c                         |   14 +-
 src/camel/camel-mempool.c                          |   10 +-
 src/camel/camel-message-info-base.c                |  877 ++++++
 src/camel/camel-message-info-base.h                |   70 +
 src/camel/camel-message-info.c                     | 2979 ++++++++++++++++++++
 src/camel/camel-message-info.h                     |  328 +++
 src/camel/camel-mime-filter-basic.h                |    3 +
 src/camel/camel-mime-filter-bestenc.h              |    3 +
 src/camel/camel-mime-filter-canon.h                |    3 +
 src/camel/camel-mime-filter-charset.h              |    3 +
 src/camel/camel-mime-filter-crlf.h                 |    3 +
 src/camel/camel-mime-filter-enriched.h             |    3 +
 src/camel/camel-mime-filter-from.h                 |    3 +
 src/camel/camel-mime-filter-gzip.h                 |    3 +
 src/camel/camel-mime-filter-html.h                 |    3 +
 src/camel/camel-mime-filter-index.h                |    3 +
 src/camel/camel-mime-filter-linewrap.h             |    3 +
 src/camel/camel-mime-filter-pgp.h                  |    3 +
 src/camel/camel-mime-filter-progress.h             |    3 +
 src/camel/camel-mime-filter-tohtml.h               |    3 +
 src/camel/camel-mime-filter-windows.h              |    3 +
 src/camel/camel-mime-filter-yenc.c                 |   30 +-
 src/camel/camel-mime-filter-yenc.h                 |    3 +
 src/camel/camel-mime-filter.h                      |    3 +
 src/camel/camel-mime-message.c                     |  194 +-
 src/camel/camel-mime-message.h                     |   22 +-
 src/camel/camel-mime-parser.c                      |  102 +-
 src/camel/camel-mime-parser.h                      |    8 +-
 src/camel/camel-mime-part-utils.c                  |  248 ++-
 src/camel/camel-mime-part-utils.h                  |   39 +-
 src/camel/camel-mime-part.c                        |  219 +-
 src/camel/camel-mime-part.h                        |    7 +-
 src/camel/camel-mime-utils.c                       |  358 +--
 src/camel/camel-mime-utils.h                       |   30 +-
 src/camel/camel-movemail.c                         |   24 +-
 src/camel/camel-msgport.c                          |   20 +-
 src/camel/camel-multipart-encrypted.h              |    2 +
 src/camel/camel-multipart-signed.h                 |    3 +
 src/camel/camel-multipart.c                        |    8 +-
 src/camel/camel-multipart.h                        |    3 +
 src/camel/camel-name-value-array.c                 |  636 +++++
 src/camel/camel-name-value-array.h                 |   97 +
 src/camel/camel-named-flags.c                      |  319 +++
 src/camel/camel-named-flags.h                      |   62 +
 src/camel/camel-network-service.h                  |    3 +-
 src/camel/camel-network-settings.h                 |    3 +
 src/camel/camel-nntp-address.c                     |   92 +-
 src/camel/camel-nntp-address.h                     |    7 +-
 src/camel/camel-null-output-stream.h               |    3 +
 src/camel/camel-object-bag.c                       |    4 +-
 src/camel/camel-object.h                           |    3 +
 src/camel/camel-offline-folder.h                   |    4 +-
 src/camel/camel-offline-settings.h                 |    3 +
 src/camel/camel-offline-store.c                    |    9 +-
 src/camel/camel-offline-store.h                    |    3 +
 src/camel/camel-operation.h                        |    3 +
 src/camel/camel-partition-table.c                  |  191 +-
 src/camel/camel-partition-table.h                  |   22 +-
 src/camel/camel-provider.c                         |   40 +-
 src/camel/camel-provider.h                         |    3 +
 src/camel/camel-sasl-anonymous.c                   |   30 +-
 src/camel/camel-sasl-anonymous.h                   |    8 +-
 src/camel/camel-sasl-cram-md5.h                    |    3 +
 src/camel/camel-sasl-digest-md5.h                  |    3 +
 src/camel/camel-sasl-gssapi.c                      |    4 +-
 src/camel/camel-sasl-gssapi.h                      |    3 +
 src/camel/camel-sasl-login.h                       |    3 +
 src/camel/camel-sasl-ntlm.h                        |    3 +
 src/camel/camel-sasl-plain.h                       |    3 +
 src/camel/camel-sasl-popb4smtp.h                   |    3 +
 src/camel/camel-sasl.c                             |    2 +-
 src/camel/camel-sasl.h                             |    4 +-
 src/camel/camel-search-private.c                   |   34 +-
 src/camel/camel-service.c                          |   43 +-
 src/camel/camel-service.h                          |   11 +-
 src/camel/camel-session.c                          |    2 +-
 src/camel/camel-session.h                          |    7 +-
 src/camel/camel-settings.h                         |    3 +
 src/camel/camel-sexp.c                             |  135 +-
 src/camel/camel-sexp.h                             |   23 +-
 src/camel/camel-smime-context.c                    |    6 +-
 src/camel/camel-smime-context.h                    |    3 +
 src/camel/camel-store-settings.h                   |    3 +
 src/camel/camel-store-summary.c                    |   84 +-
 src/camel/camel-store-summary.h                    |   13 +-
 src/camel/camel-store.c                            |  317 ++-
 src/camel/camel-store.h                            |   48 +-
 src/camel/camel-stream-buffer.c                    |    2 +-
 src/camel/camel-stream-buffer.h                    |    3 +
 src/camel/camel-stream-filter.h                    |    3 +
 src/camel/camel-stream-fs.c                        |   17 +-
 src/camel/camel-stream-fs.h                        |    3 +
 src/camel/camel-stream-mem.h                       |    3 +
 src/camel/camel-stream-null.c                      |   30 +-
 src/camel/camel-stream-null.h                      |   11 +-
 src/camel/camel-stream-process.c                   |   54 +-
 src/camel/camel-stream-process.h                   |    8 +-
 src/camel/camel-stream.c                           |   15 +-
 src/camel/camel-stream.h                           |    5 +-
 src/camel/camel-subscribable.c                     |   47 +-
 src/camel/camel-subscribable.h                     |    7 +-
 src/camel/camel-text-index.c                       |   46 +-
 src/camel/camel-text-index.h                       |   12 +
 src/camel/camel-transport.h                        |    4 +-
 src/camel/camel-trie.c                             |   14 +-
 src/camel/camel-uid-cache.c                        |    2 +-
 src/camel/camel-url-scanner.c                      |   29 +
 src/camel/camel-url.c                              |   42 +-
 src/camel/camel-url.h                              |    6 +-
 src/camel/camel-utf8.c                             |   21 +-
 src/camel/camel-utf8.h                             |    3 -
 src/camel/camel-utils.c                            |  173 ++
 src/camel/camel-utils.h                            |   40 +
 src/camel/camel-vee-data-cache.h                   |   13 +-
 src/camel/camel-vee-folder.c                       |  104 +-
 src/camel/camel-vee-folder.h                       |    9 +-
 src/camel/camel-vee-message-info.c                 |  532 ++++
 src/camel/camel-vee-message-info.h                 |   80 +
 src/camel/camel-vee-store.c                        |   38 +-
 src/camel/camel-vee-store.h                        |    3 +
 src/camel/camel-vee-summary.c                      |  335 +--
 src/camel/camel-vee-summary.h                      |   17 +-
 src/camel/camel-vtrash-folder.c                    |   50 +-
 src/camel/camel-vtrash-folder.h                    |   11 +-
 src/camel/camel.h                                  |    6 +
 src/camel/providers/imapx/CMakeLists.txt           |    2 +
 src/camel/providers/imapx/camel-imapx-command.c    |    4 +-
 .../providers/imapx/camel-imapx-conn-manager.c     |    2 +-
 .../providers/imapx/camel-imapx-conn-manager.h     |    3 +
 src/camel/providers/imapx/camel-imapx-folder.c     |   92 +-
 src/camel/providers/imapx/camel-imapx-folder.h     |    3 +
 .../providers/imapx/camel-imapx-input-stream.h     |    3 +
 src/camel/providers/imapx/camel-imapx-job.h        |    1 -
 .../providers/imapx/camel-imapx-list-response.h    |    3 +
 src/camel/providers/imapx/camel-imapx-logger.h     |    3 +
 src/camel/providers/imapx/camel-imapx-mailbox.h    |    3 +
 .../providers/imapx/camel-imapx-message-info.c     |  435 +++
 .../providers/imapx/camel-imapx-message-info.h     |   90 +
 .../imapx/camel-imapx-namespace-response.h         |    3 +
 src/camel/providers/imapx/camel-imapx-namespace.h  |    3 +
 src/camel/providers/imapx/camel-imapx-search.c     |   49 +-
 src/camel/providers/imapx/camel-imapx-search.h     |    3 +
 src/camel/providers/imapx/camel-imapx-server.c     |  534 ++--
 src/camel/providers/imapx/camel-imapx-server.h     |    3 +
 src/camel/providers/imapx/camel-imapx-settings.h   |    3 +
 .../providers/imapx/camel-imapx-status-response.h  |    3 +
 .../providers/imapx/camel-imapx-store-summary.h    |    3 +
 src/camel/providers/imapx/camel-imapx-store.c      |   50 +-
 src/camel/providers/imapx/camel-imapx-store.h      |    3 +
 src/camel/providers/imapx/camel-imapx-summary.c    |  291 +--
 src/camel/providers/imapx/camel-imapx-summary.h    |   17 +-
 src/camel/providers/imapx/camel-imapx-utils.c      |  181 +-
 src/camel/providers/imapx/camel-imapx-utils.h      |   17 +-
 src/camel/providers/local/CMakeLists.txt           |    4 +
 src/camel/providers/local/camel-local-folder.c     |   42 +-
 src/camel/providers/local/camel-local-folder.h     |    3 +
 src/camel/providers/local/camel-local-store.c      |    2 +-
 src/camel/providers/local/camel-local-store.h      |    3 +
 src/camel/providers/local/camel-local-summary.c    |  207 +-
 src/camel/providers/local/camel-local-summary.h    |   19 +-
 src/camel/providers/local/camel-maildir-folder.c   |   70 +-
 src/camel/providers/local/camel-maildir-folder.h   |    3 +
 .../providers/local/camel-maildir-message-info.c   |  251 ++
 .../providers/local/camel-maildir-message-info.h   |   74 +
 src/camel/providers/local/camel-maildir-store.c    |    4 +-
 src/camel/providers/local/camel-maildir-store.h    |    3 +
 src/camel/providers/local/camel-maildir-summary.c  |  191 +-
 src/camel/providers/local/camel-maildir-summary.h  |   18 +-
 src/camel/providers/local/camel-mbox-folder.c      |   91 +-
 src/camel/providers/local/camel-mbox-folder.h      |    3 +
 .../providers/local/camel-mbox-message-info.c      |  255 ++
 .../providers/local/camel-mbox-message-info.h      |   70 +
 src/camel/providers/local/camel-mbox-store.c       |    6 +-
 src/camel/providers/local/camel-mbox-store.h       |    3 +
 src/camel/providers/local/camel-mbox-summary.c     |  415 +--
 src/camel/providers/local/camel-mbox-summary.h     |    9 +-
 src/camel/providers/local/camel-mh-folder.c        |   10 +-
 src/camel/providers/local/camel-mh-folder.h        |    3 +
 src/camel/providers/local/camel-mh-settings.h      |    3 +
 src/camel/providers/local/camel-mh-store.c         |    8 +-
 src/camel/providers/local/camel-mh-store.h         |    3 +
 src/camel/providers/local/camel-mh-summary.c       |   40 +-
 src/camel/providers/local/camel-mh-summary.h       |    3 +
 src/camel/providers/local/camel-spool-folder.c     |    5 +-
 src/camel/providers/local/camel-spool-folder.h     |    3 +
 src/camel/providers/local/camel-spool-settings.h   |    3 +
 src/camel/providers/local/camel-spool-store.c      |    5 +-
 src/camel/providers/local/camel-spool-store.h      |    3 +
 src/camel/providers/local/camel-spool-summary.c    |   24 +-
 src/camel/providers/local/camel-spool-summary.h    |    7 +-
 src/camel/providers/nntp/camel-nntp-folder.c       |   75 +-
 src/camel/providers/nntp/camel-nntp-folder.h       |    3 +
 src/camel/providers/nntp/camel-nntp-settings.h     |    3 +
 .../providers/nntp/camel-nntp-store-summary.h      |    3 +
 src/camel/providers/nntp/camel-nntp-store.c        |   12 +-
 src/camel/providers/nntp/camel-nntp-store.h        |    3 +
 src/camel/providers/nntp/camel-nntp-stream.h       |    3 +
 src/camel/providers/nntp/camel-nntp-summary.c      |   82 +-
 src/camel/providers/nntp/camel-nntp-summary.h      |    3 +
 src/camel/providers/pop3/camel-pop3-engine.h       |    3 +
 src/camel/providers/pop3/camel-pop3-folder.c       |   30 +-
 src/camel/providers/pop3/camel-pop3-folder.h       |    3 +
 src/camel/providers/pop3/camel-pop3-settings.h     |    3 +
 src/camel/providers/pop3/camel-pop3-store.h        |    3 +
 src/camel/providers/pop3/camel-pop3-stream.h       |    3 +
 .../providers/sendmail/camel-sendmail-provider.c   |    4 +-
 .../providers/sendmail/camel-sendmail-settings.h   |    3 +
 .../providers/sendmail/camel-sendmail-transport.c  |   55 +-
 .../providers/sendmail/camel-sendmail-transport.h  |    3 +
 src/camel/providers/smtp/camel-smtp-settings.h     |    3 +
 src/camel/providers/smtp/camel-smtp-transport.c    |   45 +-
 src/camel/providers/smtp/camel-smtp-transport.h    |    3 +
 src/camel/tests/CMakeLists.txt                     |    3 +-
 src/camel/tests/folder/test10.c                    |    3 +-
 src/camel/tests/folder/test11.c                    |   27 +-
 src/camel/tests/folder/test2.c                     |    2 +-
 src/camel/tests/folder/test8.c                     |    3 +-
 src/camel/tests/lib/folders.c                      |   12 +-
 src/camel/tests/lib/messages.c                     |    8 +-
 src/camel/tests/message/test2.c                    |    4 +-
 src/camel/tests/mime-filter/test-charset.c         |    3 +-
 src/camel/tests/misc/split.c                       |    4 +-
 src/camel/tests/misc/utf7.c                        |    2 +-
 src/camel/tests/smime/pgp.c                        |    1 -
 src/vala/Camel-1.2.metadata                        |   12 +
 265 files changed, 13074 insertions(+), 7170 deletions(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5588f3a..06be584 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,7 +44,7 @@ set(USER_PROMPTER_DBUS_SERVICE_NAME   "org.gnome.evolution.dataserver.UserPrompter
 # ******************************
 # Library versioning
 # ******************************
-set(LIBCAMEL_CURRENT 59)
+set(LIBCAMEL_CURRENT 60)
 set(LIBCAMEL_REVISION 0)
 set(LIBCAMEL_AGE 0)
 
diff --git a/src/camel/CMakeLists.txt b/src/camel/CMakeLists.txt
index 923e674..481f102 100644
--- a/src/camel/CMakeLists.txt
+++ b/src/camel/CMakeLists.txt
@@ -38,6 +38,8 @@ set(SOURCES
        camel-medium.c
        camel-memchunk.c
        camel-mempool.c
+       camel-message-info.c
+       camel-message-info-base.c
        camel-mime-filter-basic.c
        camel-mime-filter-bestenc.c
        camel-mime-filter-canon.c
@@ -64,6 +66,8 @@ set(SOURCES
        camel-multipart-encrypted.c
        camel-multipart-signed.c
        camel-multipart.c
+       camel-named-flags.c
+       camel-name-value-array.c
        camel-net-utils.c
        camel-network-service.c
        camel-network-settings.c
@@ -111,8 +115,10 @@ set(SOURCES
        camel-url-scanner.c
        camel-url.c
        camel-utf8.c
+       camel-utils.c
        camel-vee-data-cache.c
        camel-vee-folder.c
+       camel-vee-message-info.c
        camel-vee-store.c
        camel-vee-summary.c
        camel-vtrash-folder.c
@@ -167,6 +173,8 @@ set(HEADERS
        camel-medium.h
        camel-memchunk.h
        camel-mempool.h
+       camel-message-info.h
+       camel-message-info-base.h
        camel-mime-filter-basic.h
        camel-mime-filter-bestenc.h
        camel-mime-filter-canon.h
@@ -194,6 +202,8 @@ set(HEADERS
        camel-multipart-encrypted.h
        camel-multipart-signed.h
        camel-multipart.h
+       camel-named-flags.h
+       camel-name-value-array.h
        camel-net-utils.h
        camel-network-service.h
        camel-network-settings.h
@@ -242,8 +252,10 @@ set(HEADERS
        camel-url-scanner.h
        camel-url.h
        camel-utf8.h
+       camel-utils.h
        camel-vee-data-cache.h
        camel-vee-folder.h
+       camel-vee-message-info.h
        camel-vee-store.h
        camel-vee-summary.h
        camel-vtrash-folder.h
diff --git a/src/camel/camel-address.c b/src/camel/camel-address.c
index 9b6e6d3..8897cd1 100644
--- a/src/camel/camel-address.c
+++ b/src/camel/camel-address.c
@@ -18,33 +18,22 @@
 
 #include "camel-address.h"
 
-G_DEFINE_TYPE (CamelAddress, camel_address, G_TYPE_OBJECT)
-
-static void
-address_finalize (GObject *object)
-{
-       CamelAddress *address = CAMEL_ADDRESS (object);
+struct _CamelAddressPrivate {
+       guint dummy;
+};
 
-       camel_address_remove (address, -1);
-       g_ptr_array_free (address->addresses, TRUE);
-
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (camel_address_parent_class)->finalize (object);
-}
+G_DEFINE_TYPE (CamelAddress, camel_address, G_TYPE_OBJECT)
 
 static void
 camel_address_class_init (CamelAddressClass *class)
 {
-       GObjectClass *object_class;
-
-       object_class = G_OBJECT_CLASS (class);
-       object_class->finalize = address_finalize;
+       g_type_class_add_private (class, sizeof (CamelAddressPrivate));
 }
 
 static void
 camel_address_init (CamelAddress *address)
 {
-       address->addresses = g_ptr_array_new ();
+       address->priv = G_TYPE_INSTANCE_GET_PRIVATE (address, CAMEL_TYPE_ADDRESS, CamelAddressPrivate);
 }
 
 /**
@@ -90,7 +79,14 @@ camel_address_new_clone (CamelAddress *addr)
 gint
 camel_address_length (CamelAddress *addr)
 {
-       return addr->addresses->len;
+       CamelAddressClass *class;
+
+       g_return_val_if_fail (CAMEL_IS_ADDRESS (addr), -1);
+
+       class = CAMEL_ADDRESS_GET_CLASS (addr);
+       g_return_val_if_fail (class->length != NULL, -1);
+
+       return class->length (addr);
 }
 
 /**
@@ -236,7 +232,7 @@ camel_address_copy (CamelAddress *dest,
  **/
 void
 camel_address_remove (CamelAddress *addr,
-                      gint index)
+                     gint index)
 {
        CamelAddressClass *class;
 
@@ -246,8 +242,12 @@ camel_address_remove (CamelAddress *addr,
        g_return_if_fail (class->remove != NULL);
 
        if (index == -1) {
-               for (index = addr->addresses->len; index>-1; index--)
+               gint len = camel_address_length (addr);
+
+               for (index = len - 1; index >= 0; index--) {
                        class->remove (addr, index);
-       } else
+               }
+       } else {
                class->remove (addr, index);
+       }
 }
diff --git a/src/camel/camel-address.h b/src/camel/camel-address.h
index 186d6cd..6965eb2 100644
--- a/src/camel/camel-address.h
+++ b/src/camel/camel-address.h
@@ -54,14 +54,13 @@ typedef struct _CamelAddressPrivate CamelAddressPrivate;
 struct _CamelAddress {
        GObject parent;
 
-       GPtrArray *addresses;
-
        CamelAddressPrivate *priv;
 };
 
 struct _CamelAddressClass {
        GObjectClass parent_class;
 
+       gint            (*length)               (CamelAddress *addr);
        gint            (*decode)               (CamelAddress *addr,
                                                 const gchar *raw);
        gchar *         (*encode)               (CamelAddress *addr);
@@ -72,6 +71,9 @@ struct _CamelAddressClass {
                                                 CamelAddress *source);
        void            (*remove)               (CamelAddress *addr,
                                                 gint index);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_address_get_type          (void);
diff --git a/src/camel/camel-async-closure.c b/src/camel/camel-async-closure.c
index f765571..970c363 100644
--- a/src/camel/camel-async-closure.c
+++ b/src/camel/camel-async-closure.c
@@ -59,7 +59,7 @@ struct _CamelAsyncClosure {
 };
 
 /**
- * camel_async_closure_new:
+ * camel_async_closure_new: (skip)
  *
  * Creates a new #CamelAsyncClosure for use with asynchronous functions.
  *
@@ -96,7 +96,7 @@ camel_async_closure_unlock_mutex_cb (gpointer user_data)
 }
 
 /**
- * camel_async_closure_wait:
+ * camel_async_closure_wait: (skip)
  * @closure: a #CamelAsyncClosure
  *
  * Call this function immediately after starting an asynchronous operation.
@@ -136,7 +136,7 @@ camel_async_closure_wait (CamelAsyncClosure *closure)
 }
 
 /**
- * camel_async_closure_free:
+ * camel_async_closure_free: (skip)
  * @closure: a #CamelAsyncClosure
  *
  * Frees the @closure and the resources it holds.
@@ -162,7 +162,7 @@ camel_async_closure_free (CamelAsyncClosure *closure)
 }
 
 /**
- * camel_async_closure_callback:
+ * camel_async_closure_callback: (skip)
  * @source_object: a #GObject or %NULL
  * @result: a #GAsyncResult
  * @closure: a #CamelAsyncClosure
diff --git a/src/camel/camel-block-file.c b/src/camel/camel-block-file.c
index 92ec24b..c0b333f 100644
--- a/src/camel/camel-block-file.c
+++ b/src/camel/camel-block-file.c
@@ -44,6 +44,22 @@ struct _CamelBlockFilePrivate {
        GMutex io_lock; /* for all io ops */
 
        guint deleted : 1;
+
+       gchar version[8];
+       gchar *path;
+       CamelBlockFileFlags flags;
+
+       gint fd;
+       gsize block_size;
+
+       CamelBlockRoot *root;
+       CamelBlock *root_block;
+
+       /* make private? */
+       gint block_cache_limit;
+       gint block_cache_count;
+       GQueue block_cache;
+       GHashTable *blocks;
 };
 
 #define CAMEL_BLOCK_FILE_LOCK(kf, lock) (g_mutex_lock(&(kf)->priv->lock))
@@ -74,39 +90,39 @@ block_file_validate_root (CamelBlockFile *bs)
        struct stat st;
        gint retval;
 
-       br = bs->root;
+       br = bs->priv->root;
 
-       retval = fstat (bs->fd, &st);
+       retval = fstat (bs->priv->fd, &st);
 
-       d (printf ("Validate root: '%s'\n", bs->path));
-       d (printf ("version: %.8s (%.8s)\n", bs->root->version, bs->version));
+       d (printf ("Validate root: '%s'\n", bs->priv->path));
+       d (printf ("version: %.8s (%.8s)\n", bs->priv->root->version, bs->priv->version));
        d (printf (
                "block size: %d (%d)%s\n",
-               br->block_size, bs->block_size,
-               br->block_size != bs->block_size ? " BAD":" OK"));
+               br->block_size, bs->priv->block_size,
+               br->block_size != bs->priv->block_size ? " BAD":" OK"));
        d (printf (
                "free: %ld (%d add size < %ld)%s\n",
                (glong) br->free,
-               br->free / bs->block_size * bs->block_size,
+               br->free / bs->priv->block_size * bs->priv->block_size,
                (glong) st.st_size,
                (br->free > st.st_size) ||
-               (br->free % bs->block_size) != 0 ? " BAD":" OK"));
+               (br->free % bs->priv->block_size) != 0 ? " BAD":" OK"));
        d (printf (
                "last: %ld (%d and size: %ld)%s\n",
                (glong) br->last,
-               br->last / bs->block_size * bs->block_size,
+               br->last / bs->priv->block_size * bs->priv->block_size,
                (glong) st.st_size,
                (br->last != st.st_size) ||
-               ((br->last % bs->block_size) != 0) ? " BAD": " OK"));
+               ((br->last % bs->priv->block_size) != 0) ? " BAD": " OK"));
        d (printf (
                "flags: %s\n",
-               (br->flags & CAMEL_BLOCK_FILE_SYNC) ? "SYNC" : "unSYNC"));
+               (br->priv->flags & CAMEL_BLOCK_FILE_SYNC) ? "SYNC" : "unSYNC"));
 
        if (br->last == 0
-           || memcmp (bs->root->version, bs->version, 8) != 0
-           || br->block_size != bs->block_size
-           || (br->free % bs->block_size) != 0
-           || (br->last % bs->block_size) != 0
+           || memcmp (bs->priv->root->version, bs->priv->version, 8) != 0
+           || br->block_size != bs->priv->block_size
+           || (br->free % bs->priv->block_size) != 0
+           || (br->last % bs->priv->block_size) != 0
            || retval == -1
            || st.st_size != br->last
            || br->free > st.st_size
@@ -120,14 +136,14 @@ block_file_validate_root (CamelBlockFile *bs)
 static gint
 block_file_init_root (CamelBlockFile *bs)
 {
-       CamelBlockRoot *br = bs->root;
+       CamelBlockRoot *br = bs->priv->root;
 
-       memset (br, 0, bs->block_size);
-       memcpy (br->version, bs->version, 8);
-       br->last = bs->block_size;
+       memset (br, 0, bs->priv->block_size);
+       memcpy (br->version, bs->priv->version, 8);
+       br->last = bs->priv->block_size;
        br->flags = CAMEL_BLOCK_FILE_SYNC;
        br->free = 0;
-       br->block_size = bs->block_size;
+       br->block_size = bs->priv->block_size;
 
        return 0;
 }
@@ -138,13 +154,13 @@ block_file_finalize (GObject *object)
        CamelBlockFile *bs = CAMEL_BLOCK_FILE (object);
        CamelBlock *bl;
 
-       if (bs->root_block)
+       if (bs->priv->root_block)
                camel_block_file_sync (bs);
 
        /* remove from lru list */
        LOCK (block_file_lock);
 
-       if (bs->fd != -1)
+       if (bs->priv->fd != -1)
                block_file_count--;
 
        /* XXX This is only supposed to be in one block file list
@@ -155,26 +171,24 @@ block_file_finalize (GObject *object)
 
        UNLOCK (block_file_lock);
 
-       while ((bl = g_queue_pop_head (&bs->block_cache)) != NULL) {
+       while ((bl = g_queue_pop_head (&bs->priv->block_cache)) != NULL) {
                if (bl->refcount != 0)
                        g_warning ("Block '%u' still referenced", bl->id);
                g_free (bl);
        }
 
-       g_hash_table_destroy (bs->blocks);
+       g_hash_table_destroy (bs->priv->blocks);
 
-       if (bs->root_block)
-               camel_block_file_unref_block (bs, bs->root_block);
-       g_free (bs->path);
-       if (bs->fd != -1)
-               close (bs->fd);
+       if (bs->priv->root_block)
+               camel_block_file_unref_block (bs, bs->priv->root_block);
+       g_free (bs->priv->path);
+       if (bs->priv->fd != -1)
+               close (bs->priv->fd);
 
        g_mutex_clear (&bs->priv->io_lock);
        g_mutex_clear (&bs->priv->cache_lock);
        g_mutex_clear (&bs->priv->root_lock);
 
-       g_free (bs->priv);
-
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_block_file_parent_class)->finalize (object);
 }
@@ -184,6 +198,8 @@ camel_block_file_class_init (CamelBlockFileClass *class)
 {
        GObjectClass *object_class;
 
+       g_type_class_add_private (class, sizeof (CamelBlockFilePrivate));
+
        object_class = G_OBJECT_CLASS (class);
        object_class->finalize = block_file_finalize;
 
@@ -200,15 +216,16 @@ block_hash_func (gconstpointer v)
 static void
 camel_block_file_init (CamelBlockFile *bs)
 {
-       bs->fd = -1;
-       bs->block_size = CAMEL_BLOCK_SIZE;
-       g_queue_init (&bs->block_cache);
-       bs->blocks = g_hash_table_new ((GHashFunc) block_hash_func, NULL);
+       bs->priv = G_TYPE_INSTANCE_GET_PRIVATE (bs, CAMEL_TYPE_BLOCK_FILE, CamelBlockFilePrivate);
+
+       bs->priv->fd = -1;
+       bs->priv->block_size = CAMEL_BLOCK_SIZE;
+       g_queue_init (&bs->priv->block_cache);
+       bs->priv->blocks = g_hash_table_new ((GHashFunc) block_hash_func, NULL);
        /* this cache size and the text index size have been tuned for about the best
         * with moderate memory usage.  Doubling the memory usage barely affects performance. */
-       bs->block_cache_limit = 256;
+       bs->priv->block_cache_limit = 256;
 
-       bs->priv = g_malloc0 (sizeof (*bs->priv));
        bs->priv->base = bs;
 
        g_mutex_init (&bs->priv->root_lock);
@@ -240,17 +257,17 @@ block_file_use (CamelBlockFile *bs)
 
        CAMEL_BLOCK_FILE_LOCK (bs, io_lock);
 
-       if (bs->fd != -1)
+       if (bs->priv->fd != -1)
                return 0;
        else if (bs->priv->deleted) {
                CAMEL_BLOCK_FILE_UNLOCK (bs, io_lock);
                errno = ENOENT;
                return -1;
        } else {
-               d (printf ("Turning block file online: %s\n", bs->path));
+               d (printf ("Turning block file online: %s\n", bs->priv->path));
        }
 
-       if ((bs->fd = g_open (bs->path, bs->flags | O_BINARY, 0600)) == -1) {
+       if ((bs->priv->fd = g_open (bs->priv->path, bs->priv->flags | O_BINARY, 0600)) == -1) {
                err = errno;
                CAMEL_BLOCK_FILE_UNLOCK (bs, io_lock);
                errno = err;
@@ -274,16 +291,16 @@ block_file_use (CamelBlockFile *bs)
 
                /* We never hit the current blockfile here, as its removed from the list first */
                bf = nw->base;
-               if (bf->fd != -1) {
+               if (bf->priv->fd != -1) {
                        /* Need to trylock, as any of these lock levels might be trying
                         * to lock the block_file_lock, so we need to check and abort if so */
                        if (CAMEL_BLOCK_FILE_TRYLOCK (bf, root_lock)) {
                                if (CAMEL_BLOCK_FILE_TRYLOCK (bf, cache_lock)) {
                                        if (CAMEL_BLOCK_FILE_TRYLOCK (bf, io_lock)) {
-                                               d (printf ("[%d] Turning block file offline: %s\n", 
block_file_count - 1, bf->path));
+                                               d (printf ("[%d] Turning block file offline: %s\n", 
block_file_count - 1, bf->priv->path));
                                                sync_nolock (bf);
-                                               close (bf->fd);
-                                               bf->fd = -1;
+                                               close (bf->priv->fd);
+                                               bf->priv->fd = -1;
                                                block_file_count--;
                                                CAMEL_BLOCK_FILE_UNLOCK (bf, io_lock);
                                        }
@@ -348,20 +365,20 @@ camel_block_file_new (const gchar *path,
        CamelBlockFile *bs;
 
        bs = g_object_new (CAMEL_TYPE_BLOCK_FILE, NULL);
-       memcpy (bs->version, version, 8);
-       bs->path = g_strdup (path);
-       bs->flags = flags;
+       memcpy (bs->priv->version, version, 8);
+       bs->priv->path = g_strdup (path);
+       bs->priv->flags = flags;
 
-       bs->root_block = camel_block_file_get_block (bs, 0);
-       if (bs->root_block == NULL) {
+       bs->priv->root_block = camel_block_file_get_block (bs, 0);
+       if (bs->priv->root_block == NULL) {
                g_object_unref (bs);
                return NULL;
        }
-       camel_block_file_detach_block (bs, bs->root_block);
-       bs->root = (CamelBlockRoot *) &bs->root_block->data;
+       camel_block_file_detach_block (bs, bs->priv->root_block);
+       bs->priv->root = (CamelBlockRoot *) &bs->priv->root_block->data;
 
        /* we only need these flags on first open */
-       bs->flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
+       bs->priv->flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
 
        class = CAMEL_BLOCK_FILE_GET_CLASS (bs);
 
@@ -370,13 +387,13 @@ camel_block_file_new (const gchar *path,
                d (printf ("Initialise root block: %.8s\n", version));
 
                class->init_root (bs);
-               camel_block_file_touch_block (bs, bs->root_block);
+               camel_block_file_touch_block (bs, bs->priv->root_block);
                if (block_file_use (bs) == -1) {
                        g_object_unref (bs);
                        return NULL;
                }
-               if (sync_block_nolock (bs, bs->root_block) == -1
-                   || ftruncate (bs->fd, bs->root->last) == -1) {
+               if (sync_block_nolock (bs, bs->priv->root_block) == -1
+                   || ftruncate (bs->priv->fd, bs->priv->root->last) == -1) {
                        block_file_unuse (bs);
                        g_object_unref (bs);
                        return NULL;
@@ -387,6 +404,72 @@ camel_block_file_new (const gchar *path,
        return bs;
 }
 
+/**
+ * camel_block_file_get_root:
+ * @bs: a #CamelBlockFile
+ *
+ * Returns: (transfer none): A #CamelBlockRoot of @bs.
+ *
+ * Since: 3.24
+ **/
+CamelBlockRoot *
+camel_block_file_get_root (CamelBlockFile *bs)
+{
+       g_return_val_if_fail (CAMEL_IS_BLOCK_FILE (bs), NULL);
+
+       return bs->priv->root;
+}
+
+/**
+ * camel_block_file_get_root_block:
+ * @bs: a #CamelBlockFile
+ *
+ * Returns: (transfer none): A root #CamelBlock of @bs.
+ *
+ * Since: 3.24
+ **/
+CamelBlock *
+camel_block_file_get_root_block (CamelBlockFile *bs)
+{
+       g_return_val_if_fail (CAMEL_IS_BLOCK_FILE (bs), NULL);
+
+       return bs->priv->root_block;
+}
+
+/**
+ * camel_block_file_get_cache_limit:
+ * @bs: a #CamelBlockFile
+ *
+ * Returns: Current block cache limit of @bs.
+ *
+ * Since: 3.24
+ **/
+gint
+camel_block_file_get_cache_limit (CamelBlockFile *bs)
+{
+       g_return_val_if_fail (CAMEL_IS_BLOCK_FILE (bs), -1);
+
+       return bs->priv->block_cache_limit;
+}
+
+/**
+ * camel_block_file_set_cache_limit:
+ * @bs: a #CamelBlockFile
+ * @block_cache_limit: a new block cache limit to set
+ *
+ * Sets a new block cache limit for @bs.
+ *
+ * Since: 3.24
+ **/
+void
+camel_block_file_set_cache_limit (CamelBlockFile *bs,
+                                 gint block_cache_limit)
+{
+       g_return_if_fail (CAMEL_IS_BLOCK_FILE (bs));
+
+       bs->priv->block_cache_limit = block_cache_limit;
+}
+
 gint
 camel_block_file_rename (CamelBlockFile *bs,
                          const gchar *path)
@@ -400,20 +483,20 @@ camel_block_file_rename (CamelBlockFile *bs,
 
        CAMEL_BLOCK_FILE_LOCK (bs, io_lock);
 
-       ret = g_rename (bs->path, path);
+       ret = g_rename (bs->priv->path, path);
        if (ret == -1) {
                /* Maybe the rename actually worked */
                err = errno;
                if (g_stat (path, &st) == 0
-                   && g_stat (bs->path, &st) == -1
+                   && g_stat (bs->priv->path, &st) == -1
                    && errno == ENOENT)
                        ret = 0;
                errno = err;
        }
 
        if (ret != -1) {
-               g_free (bs->path);
-               bs->path = g_strdup (path);
+               g_free (bs->priv->path);
+               bs->priv->path = g_strdup (path);
        }
 
        CAMEL_BLOCK_FILE_UNLOCK (bs, io_lock);
@@ -430,16 +513,16 @@ camel_block_file_delete (CamelBlockFile *bs)
 
        CAMEL_BLOCK_FILE_LOCK (bs, io_lock);
 
-       if (bs->fd != -1) {
+       if (bs->priv->fd != -1) {
                LOCK (block_file_lock);
                block_file_count--;
                UNLOCK (block_file_lock);
-               close (bs->fd);
-               bs->fd = -1;
+               close (bs->priv->fd);
+               bs->priv->fd = -1;
        }
 
        bs->priv->deleted = TRUE;
-       ret = g_unlink (bs->path);
+       ret = g_unlink (bs->priv->path);
 
        CAMEL_BLOCK_FILE_UNLOCK (bs, io_lock);
 
@@ -448,7 +531,7 @@ camel_block_file_delete (CamelBlockFile *bs)
 }
 
 /**
- * camel_block_file_new_block:
+ * camel_block_file_new_block: (skip)
  * @bs:
  *
  * Allocate a new block, return a pointer to it.  Old blocks
@@ -465,19 +548,19 @@ camel_block_file_new_block (CamelBlockFile *bs)
 
        CAMEL_BLOCK_FILE_LOCK (bs, root_lock);
 
-       if (bs->root->free) {
-               bl = camel_block_file_get_block (bs, bs->root->free);
+       if (bs->priv->root->free) {
+               bl = camel_block_file_get_block (bs, bs->priv->root->free);
                if (bl == NULL)
                        goto fail;
-               bs->root->free = ((camel_block_t *) bl->data)[0];
+               bs->priv->root->free = ((camel_block_t *) bl->data)[0];
        } else {
-               bl = camel_block_file_get_block (bs, bs->root->last);
+               bl = camel_block_file_get_block (bs, bs->priv->root->last);
                if (bl == NULL)
                        goto fail;
-               bs->root->last += CAMEL_BLOCK_SIZE;
+               bs->priv->root->last += CAMEL_BLOCK_SIZE;
        }
 
-       bs->root_block->flags |= CAMEL_BLOCK_DIRTY;
+       bs->priv->root_block->flags |= CAMEL_BLOCK_DIRTY;
 
        bl->flags |= CAMEL_BLOCK_DIRTY;
        memset (bl->data, 0, CAMEL_BLOCK_SIZE);
@@ -508,9 +591,9 @@ camel_block_file_free_block (CamelBlockFile *bs,
 
        CAMEL_BLOCK_FILE_LOCK (bs, root_lock);
 
-       ((camel_block_t *) bl->data)[0] = bs->root->free;
-       bs->root->free = bl->id;
-       bs->root_block->flags |= CAMEL_BLOCK_DIRTY;
+       ((camel_block_t *) bl->data)[0] = bs->priv->root->free;
+       bs->priv->root->free = bl->id;
+       bs->priv->root_block->flags |= CAMEL_BLOCK_DIRTY;
        bl->flags |= CAMEL_BLOCK_DIRTY;
        camel_block_file_unref_block (bs, bl);
 
@@ -520,7 +603,7 @@ camel_block_file_free_block (CamelBlockFile *bs,
 }
 
 /**
- * camel_block_file_get_block:
+ * camel_block_file_get_block: (skip)
  * @bs:
  * @id:
  *
@@ -539,16 +622,16 @@ camel_block_file_get_block (CamelBlockFile *bs,
 
        /* Sanity check: Dont allow reading of root block (except before its been read)
         * or blocks with invalid block id's */
-       if ((bs->root == NULL && id != 0)
-           || (bs->root != NULL && (id > bs->root->last || id == 0))
-           || (id % bs->block_size) != 0) {
+       if ((bs->priv->root == NULL && id != 0)
+           || (bs->priv->root != NULL && (id > bs->priv->root->last || id == 0))
+           || (id % bs->priv->block_size) != 0) {
                errno = EINVAL;
                return NULL;
        }
 
        CAMEL_BLOCK_FILE_LOCK (bs, cache_lock);
 
-       bl = g_hash_table_lookup (bs->blocks, GUINT_TO_POINTER (id));
+       bl = g_hash_table_lookup (bs->priv->blocks, GUINT_TO_POINTER (id));
 
        d (printf ("Get  block %08x: %s\n", id, bl?"cached":"must read"));
 
@@ -564,30 +647,30 @@ camel_block_file_get_block (CamelBlockFile *bs,
 
                bl = g_malloc0 (sizeof (*bl));
                bl->id = id;
-               if (lseek (bs->fd, id, SEEK_SET) == -1 ||
-                   camel_read (bs->fd, (gchar *) bl->data, CAMEL_BLOCK_SIZE, NULL, NULL) == -1) {
+               if (lseek (bs->priv->fd, id, SEEK_SET) == -1 ||
+                   camel_read (bs->priv->fd, (gchar *) bl->data, CAMEL_BLOCK_SIZE, NULL, NULL) == -1) {
                        block_file_unuse (bs);
                        CAMEL_BLOCK_FILE_UNLOCK (bs, cache_lock);
                        g_free (bl);
                        return NULL;
                }
 
-               bs->block_cache_count++;
-               g_hash_table_insert (bs->blocks, GUINT_TO_POINTER (bl->id), bl);
+               bs->priv->block_cache_count++;
+               g_hash_table_insert (bs->priv->blocks, GUINT_TO_POINTER (bl->id), bl);
 
                /* flush old blocks */
-               link = g_queue_peek_tail_link (&bs->block_cache);
+               link = g_queue_peek_tail_link (&bs->priv->block_cache);
 
-               while (link != NULL && bs->block_cache_count > bs->block_cache_limit) {
+               while (link != NULL && bs->priv->block_cache_count > bs->priv->block_cache_limit) {
                        CamelBlock *flush = link->data;
 
                        if (flush->refcount == 0) {
                                if (sync_block_nolock (bs, flush) != -1) {
-                                       g_hash_table_remove (bs->blocks, GUINT_TO_POINTER (flush->id));
+                                       g_hash_table_remove (bs->priv->blocks, GUINT_TO_POINTER (flush->id));
                                        g_queue_push_tail (&trash, link);
                                        link->data = NULL;
                                        g_free (flush);
-                                       bs->block_cache_count--;
+                                       bs->priv->block_cache_count--;
                                }
                        }
 
@@ -596,15 +679,15 @@ camel_block_file_get_block (CamelBlockFile *bs,
 
                /* Remove deleted blocks from the cache. */
                while ((link = g_queue_pop_head (&trash)) != NULL)
-                       g_queue_delete_link (&bs->block_cache, link);
+                       g_queue_delete_link (&bs->priv->block_cache, link);
 
                /* UNLOCK io_lock */
                block_file_unuse (bs);
        } else {
-               g_queue_remove (&bs->block_cache, bl);
+               g_queue_remove (&bs->priv->block_cache, bl);
        }
 
-       g_queue_push_head (&bs->block_cache, bl);
+       g_queue_push_head (&bs->priv->block_cache, bl);
        bl->refcount++;
 
        CAMEL_BLOCK_FILE_UNLOCK (bs, cache_lock);
@@ -633,8 +716,8 @@ camel_block_file_detach_block (CamelBlockFile *bs,
 
        CAMEL_BLOCK_FILE_LOCK (bs, cache_lock);
 
-       g_hash_table_remove (bs->blocks, GUINT_TO_POINTER (bl->id));
-       g_queue_remove (&bs->block_cache, bl);
+       g_hash_table_remove (bs->priv->blocks, GUINT_TO_POINTER (bl->id));
+       g_queue_remove (&bs->priv->block_cache, bl);
        bl->flags |= CAMEL_BLOCK_DETACHED;
 
        CAMEL_BLOCK_FILE_UNLOCK (bs, cache_lock);
@@ -656,8 +739,8 @@ camel_block_file_attach_block (CamelBlockFile *bs,
 
        CAMEL_BLOCK_FILE_LOCK (bs, cache_lock);
 
-       g_hash_table_insert (bs->blocks, GUINT_TO_POINTER (bl->id), bl);
-       g_queue_push_tail (&bs->block_cache, bl);
+       g_hash_table_insert (bs->priv->blocks, GUINT_TO_POINTER (bl->id), bl);
+       g_queue_push_tail (&bs->priv->block_cache, bl);
        bl->flags &= ~CAMEL_BLOCK_DETACHED;
 
        CAMEL_BLOCK_FILE_UNLOCK (bs, cache_lock);
@@ -683,11 +766,11 @@ camel_block_file_touch_block (CamelBlockFile *bs,
 
        bl->flags |= CAMEL_BLOCK_DIRTY;
 
-       if ((bs->root->flags & CAMEL_BLOCK_FILE_SYNC) && bl != bs->root_block) {
+       if ((bs->priv->root->flags & CAMEL_BLOCK_FILE_SYNC) && bl != bs->priv->root_block) {
                d (printf ("turning off sync flag\n"));
-               bs->root->flags &= ~CAMEL_BLOCK_FILE_SYNC;
-               bs->root_block->flags |= CAMEL_BLOCK_DIRTY;
-               camel_block_file_sync_block (bs, bs->root_block);
+               bs->priv->root->flags &= ~CAMEL_BLOCK_FILE_SYNC;
+               bs->priv->root_block->flags |= CAMEL_BLOCK_DIRTY;
+               camel_block_file_sync_block (bs, bs->priv->root_block);
        }
 
        CAMEL_BLOCK_FILE_UNLOCK (bs, cache_lock);
@@ -726,11 +809,11 @@ static gint
 sync_block_nolock (CamelBlockFile *bs,
                    CamelBlock *bl)
 {
-       d (printf ("Sync block %08x: %s\n", bl->id, (bl->flags & CAMEL_BLOCK_DIRTY)?"dirty":"clean"));
+       d (printf ("Sync block %08x: %s\n", bl->id, (bl->priv->flags & CAMEL_BLOCK_DIRTY)?"dirty":"clean"));
 
        if (bl->flags & CAMEL_BLOCK_DIRTY) {
-               if (lseek (bs->fd, bl->id, SEEK_SET) == -1
-                   || write (bs->fd, bl->data, CAMEL_BLOCK_SIZE) != CAMEL_BLOCK_SIZE) {
+               if (lseek (bs->priv->fd, bl->id, SEEK_SET) == -1
+                   || write (bs->priv->fd, bl->data, CAMEL_BLOCK_SIZE) != CAMEL_BLOCK_SIZE) {
                        return -1;
                }
                bl->flags &= ~CAMEL_BLOCK_DIRTY;
@@ -745,7 +828,7 @@ sync_nolock (CamelBlockFile *bs)
        GList *head, *link;
        gint work = FALSE;
 
-       head = g_queue_peek_head_link (&bs->block_cache);
+       head = g_queue_peek_head_link (&bs->priv->block_cache);
 
        for (link = head; link != NULL; link = g_list_next (link)) {
                CamelBlock *bl = link->data;
@@ -758,16 +841,16 @@ sync_nolock (CamelBlockFile *bs)
        }
 
        if (!work
-           && (bs->root_block->flags & CAMEL_BLOCK_DIRTY) == 0
-           && (bs->root->flags & CAMEL_BLOCK_FILE_SYNC) != 0)
+           && (bs->priv->root_block->flags & CAMEL_BLOCK_DIRTY) == 0
+           && (bs->priv->root->flags & CAMEL_BLOCK_FILE_SYNC) != 0)
                return 0;
 
        d (printf ("turning on sync flag\n"));
 
-       bs->root->flags |= CAMEL_BLOCK_FILE_SYNC;
-       bs->root_block->flags |= CAMEL_BLOCK_DIRTY;
+       bs->priv->root->flags |= CAMEL_BLOCK_FILE_SYNC;
+       bs->priv->root_block->flags |= CAMEL_BLOCK_DIRTY;
 
-       return sync_block_nolock (bs, bs->root_block);
+       return sync_block_nolock (bs, bs->priv->root_block);
 }
 
 /**
@@ -838,6 +921,11 @@ struct _CamelKeyFilePrivate {
        struct _CamelKeyFile *base;
        GMutex lock;
        guint deleted : 1;
+
+       FILE *fp;
+       gchar *path;
+       gint flags;
+       goffset last;
 };
 
 #define CAMEL_KEY_FILE_LOCK(kf, lock) (g_mutex_lock(&(kf)->priv->lock))
@@ -857,28 +945,26 @@ G_DEFINE_TYPE (CamelKeyFile, camel_key_file, G_TYPE_OBJECT)
 static void
 key_file_finalize (GObject *object)
 {
-       CamelKeyFile *bs = CAMEL_KEY_FILE (object);
+       CamelKeyFile *kf = CAMEL_KEY_FILE (object);
 
        LOCK (key_file_lock);
 
        /* XXX This is only supposed to be in one key file list
         *     at a time, but not sure if we can guarantee which,
         *     so try removing from both lists. */
-       g_queue_remove (&key_file_list, bs->priv);
-       g_queue_remove (&key_file_active_list, bs->priv);
+       g_queue_remove (&key_file_list, kf->priv);
+       g_queue_remove (&key_file_active_list, kf->priv);
 
-       if (bs-> fp) {
+       if (kf->priv->fp) {
                key_file_count--;
-               fclose (bs->fp);
+               fclose (kf->priv->fp);
        }
 
        UNLOCK (key_file_lock);
 
-       g_free (bs->path);
-
-       g_mutex_clear (&bs->priv->lock);
+       g_free (kf->priv->path);
 
-       g_free (bs->priv);
+       g_mutex_clear (&kf->priv->lock);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_key_file_parent_class)->finalize (object);
@@ -889,28 +975,30 @@ camel_key_file_class_init (CamelKeyFileClass *class)
 {
        GObjectClass *object_class;
 
+       g_type_class_add_private (class, sizeof (CamelKeyFilePrivate));
+
        object_class = G_OBJECT_CLASS (class);
        object_class->finalize = key_file_finalize;
 }
 
 static void
-camel_key_file_init (CamelKeyFile *bs)
+camel_key_file_init (CamelKeyFile *kf)
 {
-       bs->priv = g_malloc0 (sizeof (*bs->priv));
-       bs->priv->base = bs;
+       kf->priv = G_TYPE_INSTANCE_GET_PRIVATE (kf, CAMEL_TYPE_KEY_FILE, CamelKeyFilePrivate);
+       kf->priv->base = kf;
 
-       g_mutex_init (&bs->priv->lock);
+       g_mutex_init (&kf->priv->lock);
 
        LOCK (key_file_lock);
-       g_queue_push_head (&key_file_list, bs->priv);
+       g_queue_push_head (&key_file_list, kf->priv);
        UNLOCK (key_file_lock);
 }
 
 /* 'use' a key file for io */
 static gint
-key_file_use (CamelKeyFile *bs)
+key_file_use (CamelKeyFile *ks)
 {
-       CamelKeyFile *bf;
+       CamelKeyFile *kf;
        gint err, fd;
        const gchar *flag;
        GList *link;
@@ -926,36 +1014,36 @@ key_file_use (CamelKeyFile *bs)
 
        /* TODO: Check header on reset? */
 
-       CAMEL_KEY_FILE_LOCK (bs, lock);
+       CAMEL_KEY_FILE_LOCK (ks, lock);
 
-       if (bs->fp != NULL)
+       if (ks->priv->fp != NULL)
                return 0;
-       else if (bs->priv->deleted) {
-               CAMEL_KEY_FILE_UNLOCK (bs, lock);
+       else if (ks->priv->deleted) {
+               CAMEL_KEY_FILE_UNLOCK (ks, lock);
                errno = ENOENT;
                return -1;
        } else {
-               d (printf ("Turning key file online: '%s'\n", bs->path));
+               d (printf ("Turning key file online: '%s'\n", bs->priv->path));
        }
 
-       if ((bs->flags & O_ACCMODE) == O_RDONLY)
+       if ((ks->priv->flags & O_ACCMODE) == O_RDONLY)
                flag = "rb";
        else
                flag = "a+b";
 
-       if ((fd = g_open (bs->path, bs->flags | O_BINARY, 0600)) == -1
-           || (bs->fp = fdopen (fd, flag)) == NULL) {
+       if ((fd = g_open (ks->priv->path, ks->priv->flags | O_BINARY, 0600)) == -1
+           || (ks->priv->fp = fdopen (fd, flag)) == NULL) {
                err = errno;
                if (fd != -1)
                        close (fd);
-               CAMEL_KEY_FILE_UNLOCK (bs, lock);
+               CAMEL_KEY_FILE_UNLOCK (ks, lock);
                errno = err;
                return -1;
        }
 
        LOCK (key_file_lock);
 
-       link = g_queue_find (&key_file_list, bs->priv);
+       link = g_queue_find (&key_file_list, ks->priv);
        if (link != NULL) {
                g_queue_unlink (&key_file_list, link);
                g_queue_push_tail_link (&key_file_active_list, link);
@@ -968,16 +1056,16 @@ key_file_use (CamelKeyFile *bs)
                struct _CamelKeyFilePrivate *nw = link->data;
 
                /* We never hit the current keyfile here, as its removed from the list first */
-               bf = nw->base;
-               if (bf->fp != NULL) {
+               kf = nw->base;
+               if (kf->priv->fp != NULL) {
                        /* Need to trylock, as any of these lock levels might be trying
                         * to lock the key_file_lock, so we need to check and abort if so */
-                       if (CAMEL_BLOCK_FILE_TRYLOCK (bf, lock)) {
-                               d (printf ("Turning key file offline: %s\n", bf->path));
-                               fclose (bf->fp);
-                               bf->fp = NULL;
+                       if (CAMEL_BLOCK_FILE_TRYLOCK (kf, lock)) {
+                               d (printf ("Turning key file offline: %s\n", kf->priv->path));
+                               fclose (kf->priv->fp);
+                               kf->priv->fp = NULL;
                                key_file_count--;
-                               CAMEL_BLOCK_FILE_UNLOCK (bf, lock);
+                               CAMEL_BLOCK_FILE_UNLOCK (kf, lock);
                        }
                }
 
@@ -990,19 +1078,19 @@ key_file_use (CamelKeyFile *bs)
 }
 
 static void
-key_file_unuse (CamelKeyFile *bs)
+key_file_unuse (CamelKeyFile *kf)
 {
        GList *link;
 
        LOCK (key_file_lock);
-       link = g_queue_find (&key_file_active_list, bs->priv);
+       link = g_queue_find (&key_file_active_list, kf->priv);
        if (link != NULL) {
                g_queue_unlink (&key_file_active_list, link);
                g_queue_push_tail_link (&key_file_list, link);
        }
        UNLOCK (key_file_lock);
 
-       CAMEL_KEY_FILE_UNLOCK (bs, lock);
+       CAMEL_KEY_FILE_UNLOCK (kf, lock);
 }
 
 /**
@@ -1029,28 +1117,28 @@ camel_key_file_new (const gchar *path,
        d (printf ("New key file '%s'\n", path));
 
        kf = g_object_new (CAMEL_TYPE_KEY_FILE, NULL);
-       kf->path = g_strdup (path);
-       kf->fp = NULL;
-       kf->flags = flags;
-       kf->last = 8;
+       kf->priv->path = g_strdup (path);
+       kf->priv->fp = NULL;
+       kf->priv->flags = flags;
+       kf->priv->last = 8;
 
        if (key_file_use (kf) == -1) {
                g_object_unref (kf);
                kf = NULL;
        } else {
-               fseek (kf->fp, 0, SEEK_END);
-               last = ftell (kf->fp);
+               fseek (kf->priv->fp, 0, SEEK_END);
+               last = ftell (kf->priv->fp);
                if (last == 0) {
-                       fwrite (version, sizeof (gchar), 8, kf->fp);
+                       fwrite (version, sizeof (gchar), 8, kf->priv->fp);
                        last += 8;
                }
-               kf->last = last;
+               kf->priv->last = last;
 
-               err = ferror (kf->fp);
+               err = ferror (kf->priv->fp);
                key_file_unuse (kf);
 
                /* we only need these flags on first open */
-               kf->flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
+               kf->priv->flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
 
                if (err) {
                        g_object_unref (kf);
@@ -1074,20 +1162,20 @@ camel_key_file_rename (CamelKeyFile *kf,
 
        CAMEL_KEY_FILE_LOCK (kf, lock);
 
-       ret = g_rename (kf->path, path);
+       ret = g_rename (kf->priv->path, path);
        if (ret == -1) {
                /* Maybe the rename actually worked */
                err = errno;
                if (g_stat (path, &st) == 0
-                   && g_stat (kf->path, &st) == -1
+                   && g_stat (kf->priv->path, &st) == -1
                    && errno == ENOENT)
                        ret = 0;
                errno = err;
        }
 
        if (ret != -1) {
-               g_free (kf->path);
-               kf->path = g_strdup (path);
+               g_free (kf->priv->path);
+               kf->priv->path = g_strdup (path);
        }
 
        CAMEL_KEY_FILE_UNLOCK (kf, lock);
@@ -1104,16 +1192,16 @@ camel_key_file_delete (CamelKeyFile *kf)
 
        CAMEL_KEY_FILE_LOCK (kf, lock);
 
-       if (kf->fp) {
+       if (kf->priv->fp) {
                LOCK (key_file_lock);
                key_file_count--;
                UNLOCK (key_file_lock);
-               fclose (kf->fp);
-               kf->fp = NULL;
+               fclose (kf->priv->fp);
+               kf->priv->fp = NULL;
        }
 
        kf->priv->deleted = TRUE;
-       ret = g_unlink (kf->path);
+       ret = g_unlink (kf->priv->path);
 
        CAMEL_KEY_FILE_UNLOCK (kf, lock);
 
@@ -1160,18 +1248,18 @@ camel_key_file_write (CamelKeyFile *kf,
        size = len;
 
        /* FIXME: Use io util functions? */
-       next = kf->last;
-       if (fseek (kf->fp, kf->last, SEEK_SET) == -1)
+       next = kf->priv->last;
+       if (fseek (kf->priv->fp, kf->priv->last, SEEK_SET) == -1)
                return -1;
 
-       fwrite (parent, sizeof (*parent), 1, kf->fp);
-       fwrite (&size, sizeof (size), 1, kf->fp);
-       fwrite (records, sizeof (records[0]), len, kf->fp);
+       fwrite (parent, sizeof (*parent), 1, kf->priv->fp);
+       fwrite (&size, sizeof (size), 1, kf->priv->fp);
+       fwrite (records, sizeof (records[0]), len, kf->priv->fp);
 
-       if (ferror (kf->fp)) {
-               clearerr (kf->fp);
+       if (ferror (kf->priv->fp)) {
+               clearerr (kf->priv->fp);
        } else {
-               kf->last = ftell (kf->fp);
+               kf->priv->last = ftell (kf->priv->fp);
                *parent = next;
                ret = len;
        }
@@ -1218,11 +1306,11 @@ camel_key_file_read (CamelKeyFile *kf,
        if (key_file_use (kf) == -1)
                return -1;
 
-       if (fseek (kf->fp, pos, SEEK_SET) == -1
-           || fread (&next, sizeof (next), 1, kf->fp) != 1
-           || fread (&size, sizeof (size), 1, kf->fp) != 1
+       if (fseek (kf->priv->fp, pos, SEEK_SET) == -1
+           || fread (&next, sizeof (next), 1, kf->priv->fp) != 1
+           || fread (&size, sizeof (size), 1, kf->priv->fp) != 1
            || size > 1024) {
-               clearerr (kf->fp);
+               clearerr (kf->priv->fp);
                goto fail;
        }
 
@@ -1232,7 +1320,7 @@ camel_key_file_read (CamelKeyFile *kf,
        if (records) {
                camel_key_t *keys = g_malloc (size * sizeof (camel_key_t));
 
-               if (fread (keys, sizeof (camel_key_t), size, kf->fp) != size) {
+               if (fread (keys, sizeof (camel_key_t), size, kf->priv->fp) != size) {
                        g_free (keys);
                        goto fail;
                }
diff --git a/src/camel/camel-block-file.h b/src/camel/camel-block-file.h
index 9c02075..3a3e8da 100644
--- a/src/camel/camel-block-file.h
+++ b/src/camel/camel-block-file.h
@@ -112,22 +112,6 @@ struct _CamelBlock {
 struct _CamelBlockFile {
        GObject parent;
        CamelBlockFilePrivate *priv;
-
-       gchar version[8];
-       gchar *path;
-       CamelBlockFileFlags flags;
-
-       gint fd;
-       gsize block_size;
-
-       CamelBlockRoot *root;
-       CamelBlock *root_block;
-
-       /* make private? */
-       gint block_cache_limit;
-       gint block_cache_count;
-       GQueue block_cache;
-       GHashTable *blocks;
 };
 
 struct _CamelBlockFileClass {
@@ -135,6 +119,9 @@ struct _CamelBlockFileClass {
 
        gint (*validate_root)(CamelBlockFile *bs);
        gint (*init_root)(CamelBlockFile *bs);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_block_file_get_type       (void);
@@ -142,6 +129,11 @@ CamelBlockFile *camel_block_file_new               (const gchar *path,
                                                 gint flags,
                                                 const gchar version[8],
                                                 gsize block_size);
+CamelBlockRoot *camel_block_file_get_root      (CamelBlockFile *bs);
+CamelBlock *   camel_block_file_get_root_block (CamelBlockFile *bs);
+gint           camel_block_file_get_cache_limit(CamelBlockFile *bs);
+void           camel_block_file_set_cache_limit(CamelBlockFile *bs,
+                                                gint block_cache_limit);
 gint           camel_block_file_rename         (CamelBlockFile *bs,
                                                 const gchar *path);
 gint           camel_block_file_delete         (CamelBlockFile *kf);
@@ -171,15 +163,13 @@ typedef struct _CamelKeyFilePrivate CamelKeyFilePrivate;
 struct _CamelKeyFile {
        GObject parent;
        CamelKeyFilePrivate *priv;
-
-       FILE *fp;
-       gchar *path;
-       gint flags;
-       goffset last;
 };
 
 struct _CamelKeyFileClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType      camel_key_file_get_type (void);
diff --git a/src/camel/camel-certdb.h b/src/camel/camel-certdb.h
index 6f0b092..cf289f7 100644
--- a/src/camel/camel-certdb.h
+++ b/src/camel/camel-certdb.h
@@ -91,6 +91,9 @@ struct _CamelCertDBClass {
        gint            (*cert_save)            (CamelCertDB *certdb,
                                                 CamelCert *cert,
                                                 FILE *ostream);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_cert_get_type             (void) G_GNUC_CONST;
diff --git a/src/camel/camel-charset-map.c b/src/camel/camel-charset-map.c
index 38f4167..1e765c3 100644
--- a/src/camel/camel-charset-map.c
+++ b/src/camel/camel-charset-map.c
@@ -316,6 +316,10 @@ camel_charset_init (CamelCharset *c)
        c->level = 0;
 }
 
+/**
+ * camel_charset_step:
+ * @in: (array length=len) (type gchar):
+ **/
 void
 camel_charset_step (CamelCharset *cc,
                     const gchar *in,
@@ -381,7 +385,13 @@ camel_charset_best_name (CamelCharset *charset)
                return NULL;
 }
 
-/* finds the minimum charset for this string NULL means US-ASCII */
+/**
+ * camel_charset_best:
+ * @in: (array length=len) (type gchar):
+ *
+ * finds the minimum charset for this string NULL means US-ASCII
+ * Returns: (nullable): the minimum charset or NULL for US_ASCII.
+ **/
 const gchar *
 camel_charset_best (const gchar *in,
                     gint len)
diff --git a/src/camel/camel-cipher-context.c b/src/camel/camel-cipher-context.c
index 80bcc6c..d05a866 100644
--- a/src/camel/camel-cipher-context.c
+++ b/src/camel/camel-cipher-context.c
@@ -1179,6 +1179,13 @@ camel_cipher_validity_add_certinfo (CamelCipherValidity *vin,
 
 /**
  * camel_cipher_validity_add_certinfo_ex:
+ * @vin: a #CamelCipherValidity
+ * @mode: a #CamelCipherValidityMode, where to add the additional certificate information
+ * @name: a name to add
+ * @email: an e-mail address to add
+ * @cert_data: (nullable) (destroy cert_data_free): a certificate data, or %NULL
+ * @cert_data_free: (nullable): a destroy function for @cert_data; required, when @cert_data is not %NULL
+ * @cert_data_clone: (nullable) (scope call): a copy function for @cert_data, to copy the data; required, 
when @cert_data is not %NULL
  *
  * Add a cert info to the signer or encrypter info, with extended data set.
  *
@@ -1232,7 +1239,7 @@ camel_cipher_validity_add_certinfo_ex (CamelCipherValidity *vin,
  *
  * Gets a named property @name value for the given @info_index of the @mode validity part.
  *
- * Returns: Value of a named property of a #CamelCipherCertInfo, or %NULL when no such
+ * Returns: (transfer none) (nullable): Value of a named property of a #CamelCipherCertInfo, or %NULL when 
no such
  *    property exists. The returned value is owned by the associated #CamelCipherCertInfo
  *    and is valid until the cert info is freed.
  *
@@ -1270,9 +1277,9 @@ camel_cipher_validity_get_certinfo_property (CamelCipherValidity *vin,
  * @mode: which cipher validity part to use
  * @info_index: a 0-based index of the requested #CamelCipherCertInfo
  * @name: a property name
- * @value: (nullable): a property value, or %NULL
+ * @value: (nullable) (destroy value_free): a property value, or %NULL
  * @value_free: (nullable): a free function for the @value
- * @value_clone: (nullable): a clone function for the @value
+ * @value_clone: (nullable) (scope call): a clone function for the @value
  *
  * Sets a named property @name value @value for the given @info_index
  * of the @mode validity part. If the @value is %NULL, then the property
@@ -1399,9 +1406,9 @@ camel_cipher_validity_free (CamelCipherValidity *validity)
  *
  * Gets a named property @name value for the given @cert_info.
  *
- * Returns: Value of a named property of the @cert_info, or %NULL when no such
- *    property exists. The returned value is owned by the @cert_info
- *    and is valid until the @cert_info is freed.
+ * Returns: (transfer none) (nullable): Value of a named property of the @cert_info,
+ *    or %NULL when no such property exists. The returned value is owned by
+ *    the @cert_info and is valid until the @cert_info is freed.
  *
  * Since: 3.22
  **/
@@ -1428,9 +1435,9 @@ camel_cipher_certinfo_get_property (CamelCipherCertInfo *cert_info,
  * camel_cipher_certinfo_set_property:
  * @cert_info: a #CamelCipherCertInfo
  * @name: a property name
- * @value: (nullable): a property value, or %NULL
+ * @value: (nullable) (destroy value_free): a property value, or %NULL
  * @value_free: (nullable): a free function for the @value
- * @value_clone: (nullable): a clone function for the @value
+ * @value_clone: (nullable) (scope call): a clone function for the @value
  *
  * Sets a named property @name value @value for the given @cert_info.
  * If the @value is %NULL, then the property is removed. With a non-%NULL
diff --git a/src/camel/camel-cipher-context.h b/src/camel/camel-cipher-context.h
index 191a24d..6ad74b6 100644
--- a/src/camel/camel-cipher-context.h
+++ b/src/camel/camel-cipher-context.h
@@ -182,8 +182,8 @@ struct _CamelCipherContextClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots. */
-       gpointer reserved[8];
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_cipher_context_get_type   (void);
diff --git a/src/camel/camel-data-cache.h b/src/camel/camel-data-cache.h
index 97a468e..3d616ee 100644
--- a/src/camel/camel-data-cache.h
+++ b/src/camel/camel-data-cache.h
@@ -59,6 +59,9 @@ struct _CamelDataCache {
 
 struct _CamelDataCacheClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_data_cache_get_type       (void);
diff --git a/src/camel/camel-data-wrapper.c b/src/camel/camel-data-wrapper.c
index 1da5026..68c6093 100644
--- a/src/camel/camel-data-wrapper.c
+++ b/src/camel/camel-data-wrapper.c
@@ -29,6 +29,7 @@
 #include "camel-mime-filter-crlf.h"
 #include "camel-stream-filter.h"
 #include "camel-stream-mem.h"
+#include "camel-stream-null.h"
 
 #define d(x)
 
@@ -41,6 +42,12 @@ typedef struct _AsyncContext AsyncContext;
 struct _CamelDataWrapperPrivate {
        GMutex stream_lock;
        GByteArray *byte_array;
+
+       CamelTransferEncoding encoding;
+
+       CamelContentType *mime_type;
+
+       guint offline : 1;
 };
 
 struct _AsyncContext {
@@ -66,9 +73,9 @@ data_wrapper_dispose (GObject *object)
 {
        CamelDataWrapper *data_wrapper = CAMEL_DATA_WRAPPER (object);
 
-       if (data_wrapper->mime_type != NULL) {
-               camel_content_type_unref (data_wrapper->mime_type);
-               data_wrapper->mime_type = NULL;
+       if (data_wrapper->priv->mime_type != NULL) {
+               camel_content_type_unref (data_wrapper->priv->mime_type);
+               data_wrapper->priv->mime_type = NULL;
        }
 
        /* Chain up to parent's dispose() method. */
@@ -93,21 +100,21 @@ static void
 data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
                             const gchar *mime_type)
 {
-       if (data_wrapper->mime_type)
-               camel_content_type_unref (data_wrapper->mime_type);
-       data_wrapper->mime_type = camel_content_type_decode (mime_type);
+       if (data_wrapper->priv->mime_type)
+               camel_content_type_unref (data_wrapper->priv->mime_type);
+       data_wrapper->priv->mime_type = camel_content_type_decode (mime_type);
 }
 
 static gchar *
 data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
 {
-       return camel_content_type_simple (data_wrapper->mime_type);
+       return camel_content_type_simple (data_wrapper->priv->mime_type);
 }
 
 static CamelContentType *
 data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
 {
-       return data_wrapper->mime_type;
+       return data_wrapper->priv->mime_type;
 }
 
 static void
@@ -116,15 +123,15 @@ data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
 {
        if (mime_type)
                camel_content_type_ref (mime_type);
-       if (data_wrapper->mime_type)
-               camel_content_type_unref (data_wrapper->mime_type);
-       data_wrapper->mime_type = mime_type;
+       if (data_wrapper->priv->mime_type)
+               camel_content_type_unref (data_wrapper->priv->mime_type);
+       data_wrapper->priv->mime_type = mime_type;
 }
 
 static gboolean
 data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
 {
-       return data_wrapper->offline;
+       return data_wrapper->priv->offline;
 }
 
 static gssize
@@ -173,7 +180,7 @@ data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper,
 
        fstream = camel_stream_filter_new (stream);
 
-       switch (data_wrapper->encoding) {
+       switch (data_wrapper->priv->encoding) {
        case CAMEL_TRANSFER_ENCODING_BASE64:
                filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
                camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter);
@@ -290,7 +297,7 @@ data_wrapper_decode_to_output_stream_sync (CamelDataWrapper *data_wrapper,
        gboolean content_type_is_text;
        gssize bytes_written;
 
-       switch (data_wrapper->encoding) {
+       switch (data_wrapper->priv->encoding) {
                case CAMEL_TRANSFER_ENCODING_BASE64:
                        filter = camel_mime_filter_basic_new (
                                CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
@@ -325,10 +332,8 @@ data_wrapper_decode_to_output_stream_sync (CamelDataWrapper *data_wrapper,
        }
 
        content_type_is_text =
-               camel_content_type_is (
-               data_wrapper->mime_type, "text", "*") &&
-               !camel_content_type_is (
-               data_wrapper->mime_type, "text", "pdf");
+               camel_content_type_is (data_wrapper->priv->mime_type, "text", "*") &&
+               !camel_content_type_is (data_wrapper->priv->mime_type, "text", "pdf");
 
        if (content_type_is_text) {
                GOutputStream *temp_stream;
@@ -444,10 +449,9 @@ camel_data_wrapper_init (CamelDataWrapper *data_wrapper)
        g_mutex_init (&data_wrapper->priv->stream_lock);
        data_wrapper->priv->byte_array = g_byte_array_new ();
 
-       data_wrapper->mime_type = camel_content_type_new (
-               "application", "octet-stream");
-       data_wrapper->encoding = CAMEL_TRANSFER_ENCODING_DEFAULT;
-       data_wrapper->offline = FALSE;
+       data_wrapper->priv->mime_type = camel_content_type_new ("application", "octet-stream");
+       data_wrapper->priv->encoding = CAMEL_TRANSFER_ENCODING_DEFAULT;
+       data_wrapper->priv->offline = FALSE;
 }
 
 /**
@@ -484,6 +488,41 @@ camel_data_wrapper_get_byte_array (CamelDataWrapper *data_wrapper)
 }
 
 /**
+ * camel_data_wrapper_get_encoding:
+ * @data_wrapper: a #CamelDataWrapper
+ *
+ * Returns: An encoding (#CamelTransferEncoding) of the @data_wrapper
+ *
+ * Since: 3.24
+ **/
+CamelTransferEncoding
+camel_data_wrapper_get_encoding (CamelDataWrapper *data_wrapper)
+{
+       g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), CAMEL_TRANSFER_ENCODING_DEFAULT);
+
+       return data_wrapper->priv->encoding;
+}
+
+/**
+ * camel_data_wrapper_set_encoding:
+ * @data_wrapper: a #CamelDataWrapper
+ * @encoding: an encoding to set
+ *
+ * Sets encoding (#CamelTransferEncoding) for the @data_wrapper.
+ * It doesn't re-encode the content, if the encoding changes.
+ *
+ * Since: 3.24
+ **/
+void
+camel_data_wrapper_set_encoding (CamelDataWrapper *data_wrapper,
+                                CamelTransferEncoding encoding)
+{
+       g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+
+       data_wrapper->priv->encoding = encoding;
+}
+
+/**
  * camel_data_wrapper_set_mime_type:
  * @data_wrapper: a #CamelDataWrapper
  * @mime_type: a MIME type
@@ -552,10 +591,12 @@ camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
 /**
  * camel_data_wrapper_set_mime_type_field:
  * @data_wrapper: a #CamelDataWrapper
- * @mime_type: a #CamelContentType
+ * @mime_type: (nullable): a #CamelContentType
+ *
+ * This sets the data wrapper's MIME type. It adds its own reference
+ * to @mime_type, if not %NULL.
  *
- * This sets the data wrapper's MIME type. It suffers from the same
- * flaws as camel_data_wrapper_set_mime_type().
+ * It suffers from the same flaws as camel_data_wrapper_set_mime_type().
  **/
 void
 camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
@@ -573,6 +614,32 @@ camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
 }
 
 /**
+ * camel_data_wrapper_take_mime_type_field:
+ * @data_wrapper: a #CamelDataWrapper
+ * @mime_type: (nullable) (transfer full): a #CamelContentType
+ *
+ * Sets mime-type filed to be @mime_type and consumes it, aka unlike
+ * camel_data_wrapper_set_mime_type_field(), this doesn't add its own
+ * reference to @mime_type.
+ *
+ * It suffers from the same flaws as camel_data_wrapper_set_mime_type().
+ *
+ * Since: 3.24
+ **/
+void
+camel_data_wrapper_take_mime_type_field (CamelDataWrapper *data_wrapper,
+                                        CamelContentType *mime_type)
+{
+       g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+       g_return_if_fail (mime_type != NULL);
+
+       camel_data_wrapper_set_mime_type_field (data_wrapper, mime_type);
+
+       if (mime_type)
+               camel_content_type_unref (mime_type);
+}
+
+/**
  * camel_data_wrapper_is_offline:
  * @data_wrapper: a #CamelDataWrapper
  *
@@ -594,6 +661,25 @@ camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
 }
 
 /**
+ * camel_data_wrapper_set_offline:
+ * @data_wrapper: a #CamelDataWrapper
+ * @offline: whether the @data_wrapper is "offline"
+ *
+ * Sets whether the @data_wrapper is "offline". It applies only to this
+ * concrete instance. See camel_data_wrapper_is_offline().
+ *
+ * Since: 3.24
+ **/
+void
+camel_data_wrapper_set_offline (CamelDataWrapper *data_wrapper,
+                               gboolean offline)
+{
+       g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+
+       data_wrapper->priv->offline = offline;
+}
+
+/**
  * camel_data_wrapper_write_to_stream_sync:
  * @data_wrapper: a #CamelDataWrapper
  * @stream: a #CamelStream for output
@@ -1459,3 +1545,72 @@ camel_data_wrapper_construct_from_input_stream_finish (CamelDataWrapper *data_wr
        return g_task_propagate_boolean (G_TASK (result), error);
 }
 
+/**
+ * camel_data_wrapper_calculate_size_sync:
+ * @data_wrapper: a #CamelDataWrapper
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Calculates size of the @data_wrapper by saving it to a null-stream
+ * and returns how many bytes had been written. It's using
+ * camel_data_wrapper_write_to_stream_sync() internally.
+ *
+ * Returns: how many bytes the @data_wrapper would use when saved,
+ *   or -1 on error.
+ *
+ * Since: 3.24
+ **/
+gsize
+camel_data_wrapper_calculate_size_sync (CamelDataWrapper *data_wrapper,
+                                       GCancellable *cancellable,
+                                       GError **error)
+{
+       CamelStream *stream;
+       gsize bytes_written = -1;
+
+       g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
+
+       stream = camel_stream_null_new ();
+
+       if (camel_data_wrapper_write_to_stream_sync (data_wrapper, stream, cancellable, error))
+               bytes_written = camel_stream_null_get_bytes_written (CAMEL_STREAM_NULL (stream));
+
+       g_object_unref (stream);
+
+       return bytes_written;
+}
+
+/**
+ * camel_data_wrapper_calculate_decoded_size_sync:
+ * @data_wrapper: a #CamelDataWrapper
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Calculates decoded size of the @data_wrapper by saving it to a null-stream
+ * and returns how many bytes had been written. It's using
+ * camel_data_wrapper_decode_to_stream_sync() internally.
+ *
+ * Returns: how many bytes the @data_wrapper would use when saved,
+ *   or -1 on error.
+ *
+ * Since: 3.24
+ **/
+gsize
+camel_data_wrapper_calculate_decoded_size_sync (CamelDataWrapper *data_wrapper,
+                                               GCancellable *cancellable,
+                                               GError **error)
+{
+       CamelStream *stream;
+       gsize bytes_written = -1;
+
+       g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
+
+       stream = camel_stream_null_new ();
+
+       if (camel_data_wrapper_decode_to_stream_sync (data_wrapper, stream, cancellable, error))
+               bytes_written = camel_stream_null_get_bytes_written (CAMEL_STREAM_NULL (stream));
+
+       g_object_unref (stream);
+
+       return bytes_written;
+}
diff --git a/src/camel/camel-data-wrapper.h b/src/camel/camel-data-wrapper.h
index 0e70224..34376d9 100644
--- a/src/camel/camel-data-wrapper.h
+++ b/src/camel/camel-data-wrapper.h
@@ -59,12 +59,6 @@ typedef struct _CamelDataWrapperPrivate CamelDataWrapperPrivate;
 struct _CamelDataWrapper {
        GObject parent;
        CamelDataWrapperPrivate *priv;
-
-       CamelTransferEncoding encoding;
-
-       CamelContentType *mime_type;
-
-       guint offline : 1;
 };
 
 struct _CamelDataWrapperClass {
@@ -110,8 +104,8 @@ struct _CamelDataWrapperClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots. */
-       gpointer reserved[3];
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_data_wrapper_get_type     (void);
@@ -119,6 +113,10 @@ CamelDataWrapper *
                camel_data_wrapper_new          (void);
 GByteArray *   camel_data_wrapper_get_byte_array
                                                (CamelDataWrapper *data_wrapper);
+CamelTransferEncoding
+               camel_data_wrapper_get_encoding (CamelDataWrapper *data_wrapper);
+void           camel_data_wrapper_set_encoding (CamelDataWrapper *data_wrapper,
+                                                CamelTransferEncoding encoding);
 void           camel_data_wrapper_set_mime_type
                                                (CamelDataWrapper *data_wrapper,
                                                 const gchar *mime_type);
@@ -130,7 +128,12 @@ CamelContentType *
 void           camel_data_wrapper_set_mime_type_field
                                                (CamelDataWrapper *data_wrapper,
                                                 CamelContentType *mime_type);
+void           camel_data_wrapper_take_mime_type_field
+                                               (CamelDataWrapper *data_wrapper,
+                                                CamelContentType *mime_type);
 gboolean       camel_data_wrapper_is_offline   (CamelDataWrapper *data_wrapper);
+void           camel_data_wrapper_set_offline  (CamelDataWrapper *data_wrapper,
+                                                gboolean offline);
 
 gssize         camel_data_wrapper_write_to_stream_sync
                                                (CamelDataWrapper *data_wrapper,
@@ -228,6 +231,14 @@ gboolean   camel_data_wrapper_construct_from_input_stream_finish
                                                (CamelDataWrapper *data_wrapper,
                                                 GAsyncResult *result,
                                                 GError **error);
+gsize          camel_data_wrapper_calculate_size_sync
+                                               (CamelDataWrapper *data_wrapper,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gsize          camel_data_wrapper_calculate_decoded_size_sync
+                                               (CamelDataWrapper *data_wrapper,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-db.c b/src/camel/camel-db.c
index dffad32..4e585ef 100644
--- a/src/camel/camel-db.c
+++ b/src/camel/camel-db.c
@@ -29,6 +29,8 @@
 #include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
 
+#include <sqlite3.h>
+
 #include "camel-debug.h"
 #include "camel-object.h"
 #include "camel-string-utils.h"
@@ -437,6 +439,9 @@ init_sqlite_vfs (void)
 
        sqlite3_vfs_register (&vfs, 1);
 
+       if (g_getenv ("CAMEL_SQLITE_SHARED_CACHE"))
+               sqlite3_enable_shared_cache (TRUE);
+
        return NULL;
 }
 
@@ -481,14 +486,56 @@ init_sqlite_vfs (void)
        }
 
 struct _CamelDBPrivate {
+       sqlite3 *db;
        GTimer *timer;
        GRWLock rwlock;
-       gchar *file_name;
+       gchar *filename;
        GMutex transaction_lock;
        GThread *transaction_thread;
        guint32 transaction_level;
 };
 
+G_DEFINE_TYPE (CamelDB, camel_db, G_TYPE_OBJECT)
+
+static void
+camel_db_finalize (GObject *object)
+{
+       CamelDB *cdb = CAMEL_DB (object);
+
+       sqlite3_close (cdb->priv->db);
+       g_rw_lock_clear (&cdb->priv->rwlock);
+       g_mutex_clear (&cdb->priv->transaction_lock);
+       g_free (cdb->priv->filename);
+
+       d (g_print ("\nDatabase succesfully closed \n"));
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (camel_db_parent_class)->finalize (object);
+}
+
+static void
+camel_db_class_init (CamelDBClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelDBPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->finalize = camel_db_finalize;
+}
+
+static void
+camel_db_init (CamelDB *cdb)
+{
+       cdb->priv = G_TYPE_INSTANCE_GET_PRIVATE (cdb, CAMEL_TYPE_DB, CamelDBPrivate);
+
+       g_rw_lock_init (&cdb->priv->rwlock);
+       g_mutex_init (&cdb->priv->transaction_lock);
+       cdb->priv->transaction_thread = NULL;
+       cdb->priv->transaction_level = 0;
+       cdb->priv->timer = NULL;
+}
+
 /**
  * cdb_sql_exec 
  * @db: 
@@ -713,7 +760,7 @@ camel_db_command_internal (CamelDB *cdb,
        cdb_writer_lock (cdb);
 
        START (stmt);
-       ret = cdb_sql_exec (cdb->db, stmt, NULL, NULL, out_sqlite_error_code, error);
+       ret = cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, out_sqlite_error_code, error);
        END;
 
        cdb_writer_unlock (cdb);
@@ -722,13 +769,18 @@ camel_db_command_internal (CamelDB *cdb,
 }
 
 /**
- * camel_db_open:
+ * camel_db_new:
+ * @filename: A filename with the database to open/create
+ * @error: (out): a #GError for error messages
  *
- * Since: 2.24
+ * Returns: (transfer full): A new #CamelDB with @filename as its database file.
+ *   Free it with g_object_unref() when no longer needed.
+ *
+ * Since: 3.24
  **/
 CamelDB *
-camel_db_open (const gchar *path,
-               GError **error)
+camel_db_new (const gchar *filename,
+              GError **error)
 {
        static GOnce vfs_once = G_ONCE_INIT;
        CamelDB *cdb;
@@ -739,10 +791,8 @@ camel_db_open (const gchar *path,
 
        g_once (&vfs_once, (GThreadFunc) init_sqlite_vfs, NULL);
 
-       CAMEL_DB_USE_SHARED_CACHE;
-
  reopen:
-       ret = sqlite3_open (path, &db);
+       ret = sqlite3_open (filename, &db);
        if (ret) {
                if (!db) {
                        g_set_error (
@@ -752,7 +802,7 @@ camel_db_open (const gchar *path,
                } else {
                        const gchar *errmsg;
                        errmsg = sqlite3_errmsg (db);
-                       d (g_print ("Can't open database %s: %s\n", path, errmsg));
+                       d (g_print ("Can't open database %s: %s\n", filename, errmsg));
                        g_set_error (
                                error, CAMEL_ERROR,
                                CAMEL_ERROR_GENERIC, "%s", errmsg);
@@ -761,15 +811,9 @@ camel_db_open (const gchar *path,
                return NULL;
        }
 
-       cdb = g_new (CamelDB, 1);
-       cdb->db = db;
-       cdb->priv = g_new0 (CamelDBPrivate, 1);
-       cdb->priv->file_name = g_strdup (path);
-       g_rw_lock_init (&cdb->priv->rwlock);
-       g_mutex_init (&cdb->priv->transaction_lock);
-       cdb->priv->transaction_thread = NULL;
-       cdb->priv->transaction_level = 0;
-       cdb->priv->timer = NULL;
+       cdb = g_object_new (CAMEL_TYPE_DB, NULL);
+       cdb->priv->db = db;
+       cdb->priv->filename = g_strdup (filename);
        d (g_print ("\nDatabase succesfully opened  \n"));
 
        sqlite3_create_function (db, "MATCH", 2, SQLITE_UTF8, NULL, cdb_match_func, NULL, NULL);
@@ -799,16 +843,16 @@ camel_db_open (const gchar *path,
            cdb_sqlite_error_code == SQLITE_NOTADB)) {
                gchar *second_filename;
 
-               camel_db_close (cdb);
+               g_clear_object (&cdb);
 
                reopening = TRUE;
 
-               second_filename = g_strconcat (path, ".corrupt", NULL);
-               if (g_rename (path, second_filename) == -1) {
+               second_filename = g_strconcat (filename, ".corrupt", NULL);
+               if (g_rename (filename, second_filename) == -1) {
                        if (!local_error) {
                                g_set_error (&local_error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                                        _("Could not rename '%s' to %s: %s"),
-                                       path, second_filename, g_strerror (errno));
+                                       filename, second_filename, g_strerror (errno));
                        }
 
                        g_propagate_error (error, local_error);
@@ -820,7 +864,7 @@ camel_db_open (const gchar *path,
 
                g_free (second_filename);
 
-               g_warning ("%s: Failed to open '%s', renamed old file to .corrupt; code:%s (%d) error:%s", 
G_STRFUNC, path,
+               g_warning ("%s: Failed to open '%s', renamed old file to .corrupt; code:%s (%d) error:%s", 
G_STRFUNC, filename,
                        cdb_sqlite_error_code == SQLITE_CANTOPEN ? "SQLITE_CANTOPEN" :
                        cdb_sqlite_error_code == SQLITE_CORRUPT ? "SQLITE_CORRUPT" :
                        cdb_sqlite_error_code == SQLITE_NOTADB ? "SQLITE_NOTADB" : "???",
@@ -833,44 +877,29 @@ camel_db_open (const gchar *path,
 
        if (local_error) {
                g_propagate_error (error, local_error);
-               camel_db_close (cdb);
+               g_clear_object (&cdb);
                return NULL;
        }
 
-       sqlite3_busy_timeout (cdb->db, CAMEL_DB_SLEEP_INTERVAL);
+       sqlite3_busy_timeout (cdb->priv->db, CAMEL_DB_SLEEP_INTERVAL);
 
        return cdb;
 }
 
 /**
- * camel_db_clone:
+ * camel_db_get_filename:
+ * @cdb: a #CamelDB
  *
- * Since: 2.26
+ * Returns: (transfer none): A filename associated with @cdb.
+ *
+ * Since: 3.24
  **/
-CamelDB *
-camel_db_clone (CamelDB *cdb,
-                GError **error)
+const gchar *
+camel_db_get_filename (CamelDB *cdb)
 {
-       return camel_db_open (cdb->priv->file_name, error);
-}
+       g_return_val_if_fail (CAMEL_IS_DB (cdb), NULL);
 
-/**
- * camel_db_close:
- *
- * Since: 2.24
- **/
-void
-camel_db_close (CamelDB *cdb)
-{
-       if (cdb) {
-               sqlite3_close (cdb->db);
-               g_rw_lock_clear (&cdb->priv->rwlock);
-               g_mutex_clear (&cdb->priv->transaction_lock);
-               g_free (cdb->priv->file_name);
-               g_free (cdb->priv);
-               g_free (cdb);
-               d (g_print ("\nDatabase succesfully closed \n"));
-       }
+       return cdb->priv->filename;
 }
 
 /**
@@ -885,18 +914,18 @@ camel_db_set_collate (CamelDB *cdb,
                       const gchar *collate,
                       CamelDBCollate func)
 {
-               gint ret = 0;
+       gint ret = 0;
 
-               if (!cdb)
-                       return 0;
+       if (!cdb)
+               return 0;
 
-               cdb_writer_lock (cdb);
-               d (g_print ("Creating Collation %s on %s with %p\n", collate, col, (gpointer) func));
-               if (collate && func)
-                       ret = sqlite3_create_collation (cdb->db, collate, SQLITE_UTF8,  NULL, func);
-               cdb_writer_unlock (cdb);
+       cdb_writer_lock (cdb);
+       d (g_print ("Creating Collation %s on %s with %p\n", collate, col, (gpointer) func));
+       if (collate && func)
+               ret = sqlite3_create_collation (cdb->priv->db, collate, SQLITE_UTF8,  NULL, func);
+       cdb_writer_unlock (cdb);
 
-               return ret;
+       return ret;
 }
 
 /**
@@ -932,7 +961,7 @@ camel_db_begin_transaction (CamelDB *cdb,
        stmt = cdb_construct_transaction_stmt (cdb, "SAVEPOINT ");
 
        STARTTS (stmt);
-       res = cdb_sql_exec (cdb->db, stmt, NULL, NULL, NULL, error);
+       res = cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, NULL, error);
        g_free (stmt);
 
        return res;
@@ -954,12 +983,12 @@ camel_db_end_transaction (CamelDB *cdb,
                return -1;
 
        stmt = cdb_construct_transaction_stmt (cdb, "RELEASE SAVEPOINT ");
-       ret = cdb_sql_exec (cdb->db, stmt, NULL, NULL, NULL, error);
+       ret = cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, NULL, error);
        g_free (stmt);
 
        ENDTS;
        cdb_writer_unlock (cdb);
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
 
        return ret;
 }
@@ -977,11 +1006,11 @@ camel_db_abort_transaction (CamelDB *cdb,
        gint ret;
 
        stmt = cdb_construct_transaction_stmt (cdb, "ROLLBACK TO SAVEPOINT ");
-       ret = cdb_sql_exec (cdb->db, stmt, NULL, NULL, NULL, error);
+       ret = cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, NULL, error);
        g_free (stmt);
 
        cdb_writer_unlock (cdb);
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
 
        return ret;
 }
@@ -1001,7 +1030,7 @@ camel_db_add_to_transaction (CamelDB *cdb,
 
        g_return_val_if_fail (cdb_is_in_transaction (cdb), -1);
 
-       return (cdb_sql_exec (cdb->db, stmt, NULL, NULL, NULL, error));
+       return (cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, NULL, error));
 }
 
 /**
@@ -1031,7 +1060,7 @@ camel_db_transaction_command (CamelDB *cdb,
 
        while (qry_list) {
                query = qry_list->data;
-               ret = cdb_sql_exec (cdb->db, query, NULL, NULL, NULL, error);
+               ret = cdb_sql_exec (cdb->priv->db, query, NULL, NULL, NULL, error);
                if (ret)
                        goto end;
                qry_list = g_list_next (qry_list);
@@ -1079,12 +1108,12 @@ camel_db_count_message_info (CamelDB *cdb,
        cdb_reader_lock (cdb);
 
        START (query);
-       ret = cdb_sql_exec (cdb->db, query, count_cb, count, NULL, error);
+       ret = cdb_sql_exec (cdb->priv->db, query, count_cb, count, NULL, error);
        END;
 
        cdb_reader_unlock (cdb);
 
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
 
        return ret;
 }
@@ -1287,11 +1316,11 @@ camel_db_select (CamelDB *cdb,
        cdb_reader_lock (cdb);
 
        START (stmt);
-       ret = cdb_sql_exec (cdb->db, stmt, callback, user_data, NULL, error);
+       ret = cdb_sql_exec (cdb->priv->db, stmt, callback, user_data, NULL, error);
        END;
 
        cdb_reader_unlock (cdb);
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
 
        return ret;
 }
@@ -1369,7 +1398,7 @@ camel_db_get_folder_uids (CamelDB *db,
  **/
 GPtrArray *
 camel_db_get_folder_junk_uids (CamelDB *db,
-                               gchar *folder_name,
+                               const gchar *folder_name,
                                GError **error)
 {
         gchar *sel_query;
@@ -1418,104 +1447,6 @@ camel_db_get_folder_deleted_uids (CamelDB *db,
         return array;
 }
 
-struct ReadPreviewData
-{
-       GHashTable *columns_hash;
-       GHashTable *hash;
-};
-
-static gint
-read_preview_callback (gpointer ref,
-                       gint ncol,
-                       gchar **cols,
-                       gchar **name)
-{
-       struct ReadPreviewData *rpd = ref;
-       const gchar *uid = NULL;
-       gchar *msg = NULL;
-       gint i;
-
-       for (i = 0; i < ncol; ++i) {
-               if (!name[i] || !cols[i])
-                       continue;
-
-               switch (camel_db_get_column_ident (&rpd->columns_hash, i, ncol, name)) {
-                       case CAMEL_DB_COLUMN_UID:
-                               uid = camel_pstring_strdup (cols[i]);
-                               break;
-                       case CAMEL_DB_COLUMN_PREVIEW:
-                               msg = g_strdup (cols[i]);
-                               break;
-                       default:
-                               g_warn_if_reached ();
-                               break;
-               }
-       }
-
-       g_hash_table_insert (rpd->hash, (gchar *) uid, msg);
-
-       return 0;
-}
-
-/**
- * camel_db_get_folder_preview:
- *
- * Returns: (element-type utf8 utf8) (transfer full):
- *
- * Since: 2.28
- **/
-GHashTable *
-camel_db_get_folder_preview (CamelDB *db,
-                             const gchar *folder_name,
-                             GError **error)
-{
-       gchar *sel_query;
-       gint ret;
-       struct ReadPreviewData rpd;
-       GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
-
-       sel_query = sqlite3_mprintf ("SELECT uid, preview FROM '%q_preview'", folder_name);
-
-       rpd.columns_hash = NULL;
-       rpd.hash = hash;
-
-       ret = camel_db_select (db, sel_query, read_preview_callback, &rpd, error);
-       sqlite3_free (sel_query);
-
-       if (rpd.columns_hash)
-               g_hash_table_destroy (rpd.columns_hash);
-
-       if (!g_hash_table_size (hash) || ret != 0) {
-               g_hash_table_destroy (hash);
-               hash = NULL;
-       }
-
-       return hash;
-}
-
-/**
- * camel_db_write_preview_record:
- *
- * Since: 2.28
- **/
-gint
-camel_db_write_preview_record (CamelDB *db,
-                               const gchar *folder_name,
-                               const gchar *uid,
-                               const gchar *msg,
-                               GError **error)
-{
-       gchar *query;
-       gint ret;
-
-       query = sqlite3_mprintf ("INSERT OR REPLACE INTO '%q_preview' VALUES(%Q,%Q)", folder_name, uid, msg);
-
-       ret = camel_db_add_to_transaction (db, query, error);
-       sqlite3_free (query);
-
-       return ret;
-}
-
 /**
  * camel_db_create_folders_table:
  *
@@ -1539,7 +1470,7 @@ camel_db_create_folders_table (CamelDB *cdb,
                "visible_count INTEGER, "
                "jnd_count INTEGER, "
                "bdata TEXT )";
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
 
        ret = camel_db_command (cdb, query, error);
 
@@ -1598,19 +1529,6 @@ camel_db_create_message_info_table (CamelDB *cdb,
        ret = camel_db_add_to_transaction (cdb, table_creation_query, error);
        sqlite3_free (table_creation_query);
 
-       table_creation_query = sqlite3_mprintf (
-               "CREATE TABLE IF NOT EXISTS '%q_bodystructure' ( "
-                       "uid TEXT PRIMARY KEY , "
-                       "bodystructure TEXT )",
-                       folder_name);
-       ret = camel_db_add_to_transaction (cdb, table_creation_query, error);
-       sqlite3_free (table_creation_query);
-
-       /* Create message preview table. */
-       table_creation_query = sqlite3_mprintf ("CREATE TABLE IF NOT EXISTS '%q_preview' (  uid TEXT PRIMARY 
KEY , preview TEXT)", folder_name);
-       ret = camel_db_add_to_transaction (cdb, table_creation_query, error);
-       sqlite3_free (table_creation_query);
-
        /* FIXME: sqlize folder_name before you create the index */
        safe_index = g_strdup_printf ("SINDEX-%s", folder_name);
        table_creation_query = sqlite3_mprintf ("DROP INDEX IF EXISTS %Q", safe_index);
@@ -1618,13 +1536,6 @@ camel_db_create_message_info_table (CamelDB *cdb,
        g_free (safe_index);
        sqlite3_free (table_creation_query);
 
-       /* INDEX on preview */
-       safe_index = g_strdup_printf ("SINDEX-%s-preview", folder_name);
-       table_creation_query = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON '%q_preview' (uid, 
preview)", safe_index, folder_name);
-       ret = camel_db_add_to_transaction (cdb, table_creation_query, error);
-       g_free (safe_index);
-       sqlite3_free (table_creation_query);
-
        /* Index on deleted*/
        safe_index = g_strdup_printf ("DELINDEX-%s", folder_name);
        table_creation_query = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (deleted)", safe_index, 
folder_name);
@@ -1974,8 +1885,8 @@ write_mir (CamelDB *cdb,
                record->attachment,
                record->dirty,
                record->size,
-               (gint64) record->dsent,
-               (gint64) record->dreceived,
+               record->dsent,
+               record->dreceived,
                record->subject,
                record->from,
                record->to,
@@ -1994,15 +1905,6 @@ write_mir (CamelDB *cdb,
 
        sqlite3_free (ins_query);
 
-       if (ret == 0) {
-               ins_query = sqlite3_mprintf (
-                       "INSERT OR REPLACE INTO "
-                       "'%q_bodystructure' VALUES (%Q, %Q )",
-                       folder_name, record->uid, record->bodystructure);
-               ret = camel_db_add_to_transaction (cdb, ins_query, error);
-               sqlite3_free (ins_query);
-       }
-
        return ret;
 }
 
@@ -2051,12 +1953,12 @@ camel_db_write_folder_info_record (CamelDB *cdb,
 
        ins_query = sqlite3_mprintf (
                "INSERT INTO folders VALUES ("
-               "%Q, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %Q ) ",
+               "%Q, %d, %d, %d, %lld, %d, %d, %d, %d, %d, %d, %Q ) ",
                record->folder_name,
                record->version,
                record->flags,
                record->nextuid,
-               record->time,
+               record->timestamp,
                record->saved_count,
                record->unread_count,
                record->deleted_count,
@@ -2112,7 +2014,7 @@ read_fir_callback (gpointer ref,
                                rfd->record->nextuid = cols[i] ? strtoul (cols[i], NULL, 10) : 0;
                                break;
                        case CAMEL_DB_COLUMN_TIME:
-                               rfd->record->time = cols[i] ? strtoul (cols[i], NULL, 10) : 0;
+                               rfd->record->timestamp = cols[i] ? g_ascii_strtoll (cols[i], NULL, 10) : 0;
                                break;
                        case CAMEL_DB_COLUMN_SAVED_COUNT:
                                rfd->record->saved_count = cols[i] ? strtoul (cols[i], NULL, 10) : 0;
@@ -2242,17 +2144,13 @@ camel_db_delete_uid (CamelDB *cdb,
 
        camel_db_begin_transaction (cdb, error);
 
-       tab = sqlite3_mprintf ("DELETE FROM '%q_bodystructure' WHERE uid = %Q", folder, uid);
-       ret = camel_db_add_to_transaction (cdb, tab, error);
-       sqlite3_free (tab);
-
        tab = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", folder, uid);
        ret = camel_db_add_to_transaction (cdb, tab, error);
        sqlite3_free (tab);
 
        ret = camel_db_end_transaction (cdb, error);
 
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
        return ret;
 }
 
@@ -2303,7 +2201,7 @@ cdb_delete_ids (CamelDB *cdb,
        else
                ret = camel_db_end_transaction (cdb, error);
 
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
 
        g_string_free (str, TRUE);
 
@@ -2342,23 +2240,19 @@ camel_db_clear_folder_summary (CamelDB *cdb,
        gint ret;
        gchar *folders_del;
        gchar *msginfo_del;
-       gchar *bstruct_del;
 
        folders_del = sqlite3_mprintf ("DELETE FROM folders WHERE folder_name = %Q", folder);
        msginfo_del = sqlite3_mprintf ("DELETE FROM %Q ", folder);
-       bstruct_del = sqlite3_mprintf ("DELETE FROM '%q_bodystructure' ", folder);
 
        camel_db_begin_transaction (cdb, error);
 
        camel_db_add_to_transaction (cdb, msginfo_del, error);
        camel_db_add_to_transaction (cdb, folders_del, error);
-       camel_db_add_to_transaction (cdb, bstruct_del, error);
 
        ret = camel_db_end_transaction (cdb, error);
 
        sqlite3_free (folders_del);
        sqlite3_free (msginfo_del);
-       sqlite3_free (bstruct_del);
 
        return ret;
 }
@@ -2386,13 +2280,9 @@ camel_db_delete_folder (CamelDB *cdb,
        ret = camel_db_add_to_transaction (cdb, del, error);
        sqlite3_free (del);
 
-       del = sqlite3_mprintf ("DROP TABLE '%q_bodystructure' ", folder);
-       ret = camel_db_add_to_transaction (cdb, del, error);
-       sqlite3_free (del);
-
        ret = camel_db_end_transaction (cdb, error);
 
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
        return ret;
 }
 
@@ -2430,7 +2320,7 @@ camel_db_rename_folder (CamelDB *cdb,
 
        ret = camel_db_end_transaction (cdb, error);
 
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
        return ret;
 }
 
@@ -2444,20 +2334,19 @@ camel_db_camel_mir_free (CamelMIRecord *record)
 {
        if (record) {
                camel_pstring_free (record->uid);
-               camel_pstring_free (record->subject);
-               camel_pstring_free (record->from);
-               camel_pstring_free (record->to);
-               camel_pstring_free (record->cc);
-               camel_pstring_free (record->mlist);
-               camel_pstring_free (record->followup_flag);
-               camel_pstring_free (record->followup_completed_on);
-               camel_pstring_free (record->followup_due_by);
+               g_free (record->subject);
+               g_free (record->from);
+               g_free (record->to);
+               g_free (record->cc);
+               g_free (record->mlist);
+               g_free (record->followup_flag);
+               g_free (record->followup_completed_on);
+               g_free (record->followup_due_by);
                g_free (record->part);
                g_free (record->labels);
                g_free (record->usertags);
                g_free (record->cinfo);
                g_free (record->bdata);
-               g_free (record->bodystructure);
 
                g_free (record);
        }
@@ -2624,7 +2513,6 @@ static struct _known_column_names {
 } known_column_names[] = {
        { "attachment",                 CAMEL_DB_COLUMN_ATTACHMENT },
        { "bdata",                      CAMEL_DB_COLUMN_BDATA },
-       { "bodystructure",              CAMEL_DB_COLUMN_BODYSTRUCTURE },
        { "cinfo",                      CAMEL_DB_COLUMN_CINFO },
        { "deleted",                    CAMEL_DB_COLUMN_DELETED },
        { "deleted_count",              CAMEL_DB_COLUMN_DELETED_COUNT },
@@ -2646,7 +2534,6 @@ static struct _known_column_names {
        { "mlist",                      CAMEL_DB_COLUMN_MLIST },
        { "nextuid",                    CAMEL_DB_COLUMN_NEXTUID },
        { "part",                       CAMEL_DB_COLUMN_PART },
-       { "preview",                    CAMEL_DB_COLUMN_PREVIEW },
        { "read",                       CAMEL_DB_COLUMN_READ },
        { "replied",                    CAMEL_DB_COLUMN_REPLIED },
        { "saved_count",                CAMEL_DB_COLUMN_SAVED_COUNT },
@@ -2760,11 +2647,11 @@ camel_db_maybe_run_maintenance (CamelDB *cdb,
 
        cdb_writer_lock (cdb);
 
-       if (cdb_sql_exec (cdb->db, "PRAGMA page_count;", get_number_cb, &page_count, NULL, &local_error) == 
SQLITE_OK &&
-           cdb_sql_exec (cdb->db, "PRAGMA freelist_count;", get_number_cb, &freelist_count, NULL, 
&local_error) == SQLITE_OK) {
+       if (cdb_sql_exec (cdb->priv->db, "PRAGMA page_count;", get_number_cb, &page_count, NULL, 
&local_error) == SQLITE_OK &&
+           cdb_sql_exec (cdb->priv->db, "PRAGMA freelist_count;", get_number_cb, &freelist_count, NULL, 
&local_error) == SQLITE_OK) {
                /* Vacuum, if there's more than 5% of the free pages */
                success = !page_count || !freelist_count || freelist_count * 1000 / page_count <= 50 ||
-                   cdb_sql_exec (cdb->db, "vacuum;", NULL, NULL, NULL, &local_error) == SQLITE_OK;
+                   cdb_sql_exec (cdb->priv->db, "vacuum;", NULL, NULL, NULL, &local_error) == SQLITE_OK;
        }
 
        cdb_writer_unlock (cdb);
@@ -2776,3 +2663,23 @@ camel_db_maybe_run_maintenance (CamelDB *cdb,
 
        return success;
 }
+
+/**
+ * camel_db_release_cache_memory:
+ *
+ * Instructs sqlite to release its memory, if possible. This can be avoided
+ * when CAMEL_SQLITE_FREE_CACHE environment variable is set.
+ *
+ * Since: 3.24
+ **/
+void
+camel_db_release_cache_memory (void)
+{
+       static gint env_set = -1;
+
+       if (env_set == -1)
+               env_set = g_getenv("CAMEL_SQLITE_FREE_CACHE") ? 1 : 0;
+
+       if (!env_set)
+               sqlite3_release_memory (CAMEL_DB_FREE_CACHE_SIZE);
+}
diff --git a/src/camel/camel-db.h b/src/camel/camel-db.h
index b454af9..77a88b9 100644
--- a/src/camel/camel-db.h
+++ b/src/camel/camel-db.h
@@ -24,11 +24,58 @@
 #ifndef CAMEL_DB_H
 #define CAMEL_DB_H
 
-#include <sqlite3.h>
 #include <glib.h>
+#include <glib-object.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_DB \
+       (camel_db_get_type ())
+#define CAMEL_DB(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_DB, CamelDB))
+#define CAMEL_DB_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_DB, CamelDBClass))
+#define CAMEL_IS_DB(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_DB))
+#define CAMEL_IS_DB_CLASS(obj) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_DB))
+#define CAMEL_DB_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_DB, CamelDBClass))
 
 G_BEGIN_DECLS
 
+typedef struct _CamelDB CamelDB;
+typedef struct _CamelDBClass CamelDBClass;
+typedef struct _CamelDBPrivate CamelDBPrivate;
+
+/**
+ * CamelDB:
+ *
+ * Since: 2.24
+ **/
+struct _CamelDB {
+       GObject parent;
+       CamelDBPrivate *priv;
+};
+
+struct _CamelDBClass {
+       GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
+};
+
+/**
+ * CamelDBCollate:
+ *
+ * Since: 2.24
+ **/
+typedef gint (*CamelDBCollate)(gpointer enc, gint length1, gconstpointer data1, gint length2, gconstpointer 
data2);
+
 /**
  * CAMEL_DB_FILE:
  *
@@ -59,27 +106,6 @@ G_BEGIN_DECLS
  **/
 #define CAMEL_DB_IN_MEMORY_TABLE_LIMIT 100000
 
-typedef struct _CamelDBPrivate CamelDBPrivate;
-
-/**
- * CamelDBCollate:
- *
- * Since: 2.24
- **/
-typedef gint (*CamelDBCollate)(gpointer enc, gint length1, gconstpointer data1, gint length2, gconstpointer 
data2);
-
-/**
- * CamelDB:
- *
- * Since: 2.24
- **/
-struct _CamelDB {
-       sqlite3 *db;
-       /* this lock has been replaced with a rw lock which sits inside priv. 
-        * This is currently unused. Keeping it, not to break the ABI */
-       GMutex *lock;
-       CamelDBPrivate *priv;
-};
 
 /**
  * CAMEL_DB_FREE_CACHE_SIZE:
@@ -96,20 +122,6 @@ struct _CamelDB {
 #define CAMEL_DB_SLEEP_INTERVAL 1*10*10
 
 /**
- * CAMEL_DB_RELEASE_SQLITE_MEMORY:
- *
- * Since: 2.24
- **/
-#define CAMEL_DB_RELEASE_SQLITE_MEMORY if(!g_getenv("CAMEL_SQLITE_FREE_CACHE")) 
sqlite3_release_memory(CAMEL_DB_FREE_CACHE_SIZE);
-
-/**
- * CAMEL_DB_USE_SHARED_CACHE:
- *
- * Since: 2.24
- **/
-#define CAMEL_DB_USE_SHARED_CACHE if(g_getenv("CAMEL_SQLITE_SHARED_CACHE")) 
sqlite3_enable_shared_cache(TRUE);
-
-/**
  * CamelMIRecord:
  * @uid:
  *     Message UID
@@ -161,7 +173,6 @@ struct _CamelDB {
  *     content info string - composite string
  * @bdata:
  *     provider specific data
- * @bodystructure:
  *
  * The extensive DB format, supporting basic searching and sorting.
  *
@@ -179,8 +190,8 @@ typedef struct _CamelMIRecord {
        gboolean junk;
        gboolean attachment;
        guint32 size;
-       time_t dsent;
-       time_t dreceived;
+       gint64 dsent; /* time_t */
+       gint64 dreceived; /* time_t */
        gchar *subject;
        gchar *from;
        gchar *to;
@@ -194,7 +205,6 @@ typedef struct _CamelMIRecord {
        gchar *usertags;
        gchar *cinfo;
        gchar *bdata;
-       gchar *bodystructure;
 } CamelMIRecord;
 
 /**
@@ -207,7 +217,7 @@ typedef struct _CamelFIRecord {
        guint32 version;
        guint32 flags;
        guint32 nextuid;
-       time_t time;
+       gint64 timestamp;
        guint32 saved_count;
        guint32 unread_count;
        guint32 deleted_count;
@@ -217,8 +227,6 @@ typedef struct _CamelFIRecord {
        gchar *bdata;
 } CamelFIRecord;
 
-typedef struct _CamelDB CamelDB;
-
 /**
  * CamelDBKnownColumnNames:
  *
@@ -228,7 +236,6 @@ typedef enum {
        CAMEL_DB_COLUMN_UNKNOWN = -1,
        CAMEL_DB_COLUMN_ATTACHMENT,
        CAMEL_DB_COLUMN_BDATA,
-       CAMEL_DB_COLUMN_BODYSTRUCTURE,
        CAMEL_DB_COLUMN_CINFO,
        CAMEL_DB_COLUMN_DELETED,
        CAMEL_DB_COLUMN_DELETED_COUNT,
@@ -250,7 +257,6 @@ typedef enum {
        CAMEL_DB_COLUMN_MLIST,
        CAMEL_DB_COLUMN_NEXTUID,
        CAMEL_DB_COLUMN_PART,
-       CAMEL_DB_COLUMN_PREVIEW,
        CAMEL_DB_COLUMN_READ,
        CAMEL_DB_COLUMN_REPLIED,
        CAMEL_DB_COLUMN_SAVED_COUNT,
@@ -272,74 +278,165 @@ CamelDBKnownColumnNames camel_db_get_column_ident (GHashTable **hash, gint index
  *
  * Since: 2.24
  **/
-typedef gint (*CamelDBSelectCB) (gpointer data, gint ncol, gchar **colvalues, gchar **colnames);
-
-CamelDB * camel_db_open (const gchar *path, GError **error);
-CamelDB * camel_db_clone (CamelDB *cdb, GError **error);
-void camel_db_close (CamelDB *cdb);
-gint camel_db_command (CamelDB *cdb, const gchar *stmt, GError **error);
-
-gint camel_db_transaction_command (CamelDB *cdb, GList *qry_list, GError **error);
-
-gint camel_db_begin_transaction (CamelDB *cdb, GError **error);
-gint camel_db_add_to_transaction (CamelDB *cdb, const gchar *query, GError **error);
-gint camel_db_end_transaction (CamelDB *cdb, GError **error);
-gint camel_db_abort_transaction (CamelDB *cdb, GError **error);
-gint camel_db_clear_folder_summary (CamelDB *cdb, const gchar *folder, GError **error);
-gint camel_db_rename_folder (CamelDB *cdb, const gchar *old_folder, const gchar *new_folder, GError **error);
-
-gint camel_db_delete_folder (CamelDB *cdb, const gchar *folder, GError **error);
-gint camel_db_delete_uid (CamelDB *cdb, const gchar *folder, const gchar *uid, GError **error);
-/*int camel_db_delete_uids (CamelDB *cdb, GError **error, gint nargs, ... );*/
-gint camel_db_delete_uids (CamelDB *cdb, const gchar * folder_name, GList *uids, GError **error);
-
-gint camel_db_create_folders_table (CamelDB *cdb, GError **error);
-gint camel_db_select (CamelDB *cdb, const gchar * stmt, CamelDBSelectCB callback, gpointer user_data, GError 
**error);
-
-gint camel_db_write_folder_info_record (CamelDB *cdb, CamelFIRecord *record, GError **error);
-gint camel_db_read_folder_info_record (CamelDB *cdb, const gchar *folder_name, CamelFIRecord *record, GError 
**error);
-
-gint camel_db_prepare_message_info_table (CamelDB *cdb, const gchar *folder_name, GError **error);
-
-gint camel_db_write_message_info_record (CamelDB *cdb, const gchar *folder_name, CamelMIRecord *record, 
GError **error);
-gint camel_db_write_fresh_message_info_record (CamelDB *cdb, const gchar *folder_name, CamelMIRecord 
*record, GError **error);
-gint camel_db_read_message_info_records (CamelDB *cdb, const gchar *folder_name, gpointer user_data, 
CamelDBSelectCB read_mir_callback, GError **error);
-gint camel_db_read_message_info_record_with_uid (CamelDB *cdb, const gchar *folder_name, const gchar *uid, 
gpointer user_data, CamelDBSelectCB read_mir_callback, GError **error);
-
-gint camel_db_count_junk_message_info (CamelDB *cdb, const gchar *table_name, guint32 *count, GError 
**error);
-gint camel_db_count_unread_message_info (CamelDB *cdb, const gchar *table_name, guint32 *count, GError 
**error);
-gint camel_db_count_deleted_message_info (CamelDB *cdb, const gchar *table_name, guint32 *count, GError 
**error);
-gint camel_db_count_total_message_info (CamelDB *cdb, const gchar *table_name, guint32 *count, GError 
**error);
-
-gint camel_db_count_visible_message_info (CamelDB *cdb, const gchar *table_name, guint32 *count, GError 
**error);
-gint camel_db_count_visible_unread_message_info (CamelDB *cdb, const gchar *table_name, guint32 *count, 
GError **error);
-
-gint camel_db_count_junk_not_deleted_message_info (CamelDB *cdb, const gchar *table_name, guint32 *count, 
GError **error);
-gint camel_db_count_message_info (CamelDB *cdb, const gchar *query, guint32 *count, GError **error);
-void camel_db_camel_mir_free (CamelMIRecord *record);
-
-gint camel_db_get_folder_uids (CamelDB *db, const gchar *folder_name, const gchar *sort_by, const gchar 
*collate, GHashTable *hash, GError **error);
-
-GPtrArray * camel_db_get_folder_junk_uids (CamelDB *db, gchar *folder_name, GError **error);
-GPtrArray * camel_db_get_folder_deleted_uids (CamelDB *db, const gchar *folder_name, GError **error);
-
-gchar * camel_db_sqlize_string (const gchar *string);
-void camel_db_free_sqlized_string (gchar *string);
-
-gchar * camel_db_get_column_name (const gchar *raw_name);
-gint camel_db_set_collate (CamelDB *cdb, const gchar *col, const gchar *collate, CamelDBCollate func);
-
-gint camel_db_start_in_memory_transactions (CamelDB *cdb, GError **error);
-gint camel_db_flush_in_memory_transactions (CamelDB *cdb, const gchar * folder_name, GError **error);
-
-GHashTable *
-camel_db_get_folder_preview (CamelDB *db, const gchar *folder_name, GError **error);
-gint camel_db_write_preview_record (CamelDB *db, const gchar *folder_name, const gchar *uid, const gchar 
*msg, GError **error);
-
-gint
-camel_db_reset_folder_version (CamelDB *cdb, const gchar *folder_name, gint reset_version, GError **error);
-
-gboolean camel_db_maybe_run_maintenance (CamelDB *cdb, GError **error);
+typedef gint (*CamelDBSelectCB) (gpointer user_data, gint ncol, gchar **colvalues, gchar **colnames);
+
+GType          camel_db_get_type               (void) G_GNUC_CONST;
+
+CamelDB *      camel_db_new                    (const gchar *filename,
+                                                GError **error);
+const gchar *  camel_db_get_filename           (CamelDB *cdb);
+gint           camel_db_command                (CamelDB *cdb,
+                                                const gchar *stmt,
+                                                GError **error);
+gint           camel_db_transaction_command    (CamelDB *cdb,
+                                                GList *qry_list,
+                                                GError **error);
+gint           camel_db_begin_transaction      (CamelDB *cdb,
+                                                GError **error);
+gint           camel_db_add_to_transaction     (CamelDB *cdb,
+                                                const gchar *query,
+                                                GError **error);
+gint           camel_db_end_transaction        (CamelDB *cdb,
+                                                GError **error);
+gint           camel_db_abort_transaction      (CamelDB *cdb,
+                                                GError **error);
+gint           camel_db_clear_folder_summary   (CamelDB *cdb,
+                                                const gchar *folder,
+                                                GError **error);
+gint           camel_db_rename_folder          (CamelDB *cdb,
+                                                const gchar *old_folder,
+                                                const gchar *new_folder,
+                                                GError **error);
+gint           camel_db_delete_folder          (CamelDB *cdb,
+                                                const gchar *folder,
+                                                GError **error);
+gint           camel_db_delete_uid             (CamelDB *cdb,
+                                                const gchar *folder,
+                                                const gchar *uid,
+                                                GError **error);
+gint           camel_db_delete_uids            (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                GList *uids,
+                                                GError **error);
+gint           camel_db_create_folders_table   (CamelDB *cdb,
+                                                GError **error);
+gint           camel_db_select                 (CamelDB *cdb,
+                                                const gchar *stmt,
+                                                CamelDBSelectCB callback,
+                                                gpointer user_data,
+                                                GError **error);
+gint           camel_db_write_folder_info_record
+                                               (CamelDB *cdb,
+                                                CamelFIRecord *record,
+                                                GError **error);
+gint           camel_db_read_folder_info_record
+                                               (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                CamelFIRecord *record,
+                                                GError **error);
+gint           camel_db_prepare_message_info_table
+                                               (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                GError **error);
+gint           camel_db_write_message_info_record
+                                               (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                CamelMIRecord *record,
+                                                GError **error);
+gint           camel_db_write_fresh_message_info_record
+                                               (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                CamelMIRecord *record,
+                                                GError **error);
+gint           camel_db_read_message_info_records
+                                               (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                gpointer user_data,
+                                                CamelDBSelectCB read_mir_callback,
+                                                GError **error);
+gint           camel_db_read_message_info_record_with_uid
+                                               (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                const gchar *uid,
+                                                gpointer user_data,
+                                                CamelDBSelectCB read_mir_callback,
+                                                GError **error);
+gint           camel_db_count_junk_message_info
+                                               (CamelDB *cdb,
+                                                const gchar *table_name,
+                                                guint32 *count,
+                                                GError **error);
+gint           camel_db_count_unread_message_info
+                                               (CamelDB *cdb,
+                                                const gchar *table_name,
+                                                guint32 *count,
+                                                GError **error);
+gint           camel_db_count_deleted_message_info
+                                               (CamelDB *cdb,
+                                                const gchar *table_name,
+                                                guint32 *count,
+                                                GError **error);
+gint           camel_db_count_total_message_info
+                                               (CamelDB *cdb,
+                                                const gchar *table_name,
+                                                guint32 *count,
+                                                GError **error);
+gint           camel_db_count_visible_message_info
+                                               (CamelDB *cdb,
+                                                const gchar *table_name,
+                                                guint32 *count,
+                                                GError **error);
+gint           camel_db_count_visible_unread_message_info
+                                               (CamelDB *cdb,
+                                                const gchar *table_name,
+                                                guint32 *count,
+                                                GError **error);
+gint           camel_db_count_junk_not_deleted_message_info
+                                               (CamelDB *cdb,
+                                                const gchar *table_name,
+                                                guint32 *count,
+                                                GError **error);
+gint           camel_db_count_message_info     (CamelDB *cdb,
+                                                const gchar *query,
+                                                guint32 *count,
+                                                GError **error);
+gint           camel_db_get_folder_uids        (CamelDB *db,
+                                                const gchar *folder_name,
+                                                const gchar *sort_by,
+                                                const gchar *collate,
+                                                GHashTable *hash,
+                                                GError **error);
+GPtrArray *    camel_db_get_folder_junk_uids   (CamelDB *db,
+                                                const gchar *folder_name,
+                                                GError **error);
+GPtrArray *    camel_db_get_folder_deleted_uids
+                                               (CamelDB *db,
+                                                const gchar *folder_name,
+                                                GError **error);
+gint           camel_db_set_collate            (CamelDB *cdb,
+                                                const gchar *col,
+                                                const gchar *collate,
+                                                CamelDBCollate func);
+gint           camel_db_start_in_memory_transactions
+                                               (CamelDB *cdb,
+                                                GError **error);
+gint           camel_db_flush_in_memory_transactions
+                                               (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                GError **error);
+gint           camel_db_reset_folder_version   (CamelDB *cdb,
+                                                const gchar *folder_name,
+                                                gint reset_version,
+                                                GError **error);
+gboolean       camel_db_maybe_run_maintenance  (CamelDB *cdb,
+                                                GError **error);
+
+void           camel_db_release_cache_memory   (void);
+
+gchar *                camel_db_sqlize_string          (const gchar *string);
+void           camel_db_free_sqlized_string    (gchar *string);
+gchar *                camel_db_get_column_name        (const gchar *raw_name);
+void           camel_db_camel_mir_free         (CamelMIRecord *record);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-enums.h b/src/camel/camel-enums.h
index 13577db..e20578e 100644
--- a/src/camel/camel-enums.h
+++ b/src/camel/camel-enums.h
@@ -474,4 +474,18 @@ typedef enum {
        CAMEL_THREE_STATE_INCONSISTENT
 } CamelThreeState;
 
+/**
+ * CamelCompareType:
+ * @CAMEL_COMPARE_CASE_INSENSITIVE: compare case insensitively
+ * @CAMEL_COMPARE_CASE_SENSITIVE: compare case sensitively
+ *
+ * Declares the compare type to use.
+ *
+ * Since: 3.24
+ **/
+typedef enum {
+       CAMEL_COMPARE_CASE_INSENSITIVE,
+       CAMEL_COMPARE_CASE_SENSITIVE
+} CamelCompareType;
+
 #endif /* CAMEL_ENUMS_H */
diff --git a/src/camel/camel-filter-driver.c b/src/camel/camel-filter-driver.c
index b0e73b4..eacab5d 100644
--- a/src/camel/camel-filter-driver.c
+++ b/src/camel/camel-filter-driver.c
@@ -1345,7 +1345,7 @@ camel_filter_driver_flush (CamelFilterDriver *driver,
 
 static gint
 decode_flags_from_xev (const gchar *xev,
-                       CamelMessageInfoBase *mi)
+                       CamelMessageInfo *mi)
 {
        guint32 uid, flags = 0;
        gchar *header;
@@ -1359,7 +1359,8 @@ decode_flags_from_xev (const gchar *xev,
        }
        g_free (header);
 
-       mi->flags = flags;
+       camel_message_info_set_flags (mi, ~0, flags);
+
        return 0;
 }
 
@@ -1421,6 +1422,7 @@ camel_filter_driver_filter_mbox (CamelFilterDriver *driver,
        while (camel_mime_parser_step (mp, NULL, NULL) == CAMEL_MIME_PARSER_STATE_FROM) {
                CamelMessageInfo *info;
                CamelMimeMessage *message;
+               const CamelNameValueArray *headers;
                CamelMimePart *mime_part;
                gint pc = 0;
                const gchar *xev;
@@ -1448,13 +1450,14 @@ camel_filter_driver_filter_mbox (CamelFilterDriver *driver,
                        goto fail;
                }
 
-               info = camel_message_info_new_from_header (NULL, mime_part->headers);
+               headers = camel_medium_get_headers (CAMEL_MEDIUM (mime_part));
+               info = camel_message_info_new_from_headers (NULL, headers);
                /* Try and see if it has X-Evolution headers */
-               xev = camel_header_raw_find (&mime_part->headers, "X-Evolution", NULL);
+               xev = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
"X-Evolution");
                if (xev)
-                       decode_flags_from_xev (xev, (CamelMessageInfoBase *) info);
+                       decode_flags_from_xev (xev, info);
 
-               ((CamelMessageInfoBase *) info)->size = camel_mime_parser_tell (mp) - last;
+               camel_message_info_set_size (info, camel_mime_parser_tell (mp) - last);
 
                last = camel_mime_parser_tell (mp);
                status = camel_filter_driver_filter_message (
@@ -1466,7 +1469,7 @@ camel_filter_driver_filter_mbox (CamelFilterDriver *driver,
                        report_status (
                                driver, CAMEL_FILTER_STATUS_END,
                                100, _("Failed on message %d"), i);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                        g_propagate_error (error, local_error);
                        goto fail;
                }
@@ -1476,7 +1479,7 @@ camel_filter_driver_filter_mbox (CamelFilterDriver *driver,
                /* skip over the FROM_END state */
                camel_mime_parser_step (mp, NULL, NULL);
 
-               camel_message_info_unref (info);
+               g_clear_object (&info);
        }
 
        camel_operation_progress (cancellable, 100);
@@ -1565,7 +1568,7 @@ camel_filter_driver_filter_folder (CamelFilterDriver *driver,
                        store_uid, store_uid, cancellable, &local_error);
 
                if (camel_folder_has_summary_capability (folder))
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
 
                if (local_error != NULL || status == -1) {
                        report_status (
@@ -1690,7 +1693,7 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver,
        g_return_val_if_fail (message != NULL || (source != NULL && uid != NULL), -1);
 
        if (info == NULL) {
-               struct _camel_header_raw *h;
+               const CamelNameValueArray *headers;
 
                if (message) {
                        g_object_ref (message);
@@ -1701,8 +1704,8 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver,
                                return -1;
                }
 
-               h = CAMEL_MIME_PART (message)->headers;
-               info = camel_message_info_new_from_header (NULL, h);
+               headers = camel_medium_get_headers (CAMEL_MEDIUM (message));
+               info = camel_message_info_new_from_headers (NULL, headers);
                freeinfo = TRUE;
        } else {
                if (camel_message_info_get_flags (info) & CAMEL_MESSAGE_DELETED)
@@ -1865,7 +1868,7 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver,
                g_object_unref (driver->priv->message);
 
        if (freeinfo)
-               camel_message_info_unref (info);
+               g_clear_object (&info);
 
        return 0;
 
@@ -1877,7 +1880,7 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver,
                g_object_unref (driver->priv->message);
 
        if (freeinfo)
-               camel_message_info_unref (info);
+               g_clear_object (&info);
 
        g_propagate_error (error, driver->priv->error);
        driver->priv->error = NULL;
diff --git a/src/camel/camel-filter-driver.h b/src/camel/camel-filter-driver.h
index d0b7eda..8425863 100644
--- a/src/camel/camel-filter-driver.h
+++ b/src/camel/camel-filter-driver.h
@@ -61,6 +61,9 @@ struct _CamelFilterDriver {
 
 struct _CamelFilterDriverClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 /* FIXME: this maybe should change... */
@@ -74,7 +77,7 @@ enum camel_filter_status_t {
 };
 
 typedef CamelFolder * (*CamelFilterGetFolderFunc) (CamelFilterDriver *driver, const gchar *uri,
-                                                  gpointer data, GError **error);
+                                                  gpointer user_data, GError **error);
 /* report status */
 typedef void (*CamelFilterStatusFunc) (CamelFilterDriver *driver, enum camel_filter_status_t status,
                                      gint pc, const gchar *desc, gpointer user_data);
diff --git a/src/camel/camel-filter-input-stream.h b/src/camel/camel-filter-input-stream.h
index abc8f3d..1740a4d 100644
--- a/src/camel/camel-filter-input-stream.h
+++ b/src/camel/camel-filter-input-stream.h
@@ -57,6 +57,9 @@ struct _CamelFilterInputStream {
 
 struct _CamelFilterInputStreamClass {
        GFilterInputStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_filter_input_stream_get_type
diff --git a/src/camel/camel-filter-output-stream.h b/src/camel/camel-filter-output-stream.h
index 064f851..b089f80 100644
--- a/src/camel/camel-filter-output-stream.h
+++ b/src/camel/camel-filter-output-stream.h
@@ -57,6 +57,9 @@ struct _CamelFilterOutputStream {
 
 struct _CamelFilterOutputStreamClass {
        GFilterOutputStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_filter_output_stream_get_type
diff --git a/src/camel/camel-filter-search.c b/src/camel/camel-filter-search.c
index 68f0b63..1d85d59 100644
--- a/src/camel/camel-filter-search.c
+++ b/src/camel/camel-filter-search.c
@@ -148,16 +148,18 @@ check_header_in_message_info (CamelMessageInfo *info,
 {
        struct _KnownHeaders {
                const gchar *header_name;
-               guint info_key;
+               const gchar *info_name;
+               camel_search_t type;
        } known_headers[] = {
-               { "Subject", CAMEL_MESSAGE_INFO_SUBJECT },
-               { "From", CAMEL_MESSAGE_INFO_FROM },
-               { "To", CAMEL_MESSAGE_INFO_TO },
-               { "Cc", CAMEL_MESSAGE_INFO_CC }
+               { "Subject", "subject", CAMEL_SEARCH_TYPE_ENCODED },
+               { "From", "from", CAMEL_SEARCH_TYPE_ADDRESS_ENCODED },
+               { "To", "to", CAMEL_SEARCH_TYPE_ADDRESS_ENCODED },
+               { "Cc", "cc", CAMEL_SEARCH_TYPE_ADDRESS_ENCODED }
        };
-       camel_search_t type = CAMEL_SEARCH_TYPE_ENCODED;
-       const gchar *name, *value;
+       const gchar *name;
+       gchar *value;
        gboolean found = FALSE;
+       camel_search_t use_type;
        gint ii;
 
        g_return_val_if_fail (argc > 1, FALSE);
@@ -175,20 +177,20 @@ check_header_in_message_info (CamelMessageInfo *info,
                gint jj;
 
                for (jj = 0; jj < G_N_ELEMENTS (known_headers); jj++) {
-                       value = camel_message_info_get_ptr (info, known_headers[jj].info_key);
+                       value = NULL;
+
+                       g_object_get (G_OBJECT (info), known_headers[jj].info_name, &value, NULL);
+
                        if (!value)
                                continue;
 
-                       if (known_headers[jj].info_key == CAMEL_MESSAGE_INFO_SUBJECT)
-                               type = CAMEL_SEARCH_TYPE_ENCODED;
-                       else
-                               type = CAMEL_SEARCH_TYPE_ADDRESS_ENCODED;
-
                        for (ii = 1; ii < argc && !*matched; ii++) {
                                if (argv[ii]->type == CAMEL_SEXP_RES_STRING)
-                                       *matched = camel_search_header_match (value, argv[ii]->value.string, 
how, type, NULL);
+                                       *matched = camel_search_header_match (value, argv[ii]->value.string, 
how, known_headers[jj].type, NULL);
                        }
 
+                       g_free (value);
+
                        if (*matched)
                                return TRUE;
                }
@@ -201,21 +203,24 @@ check_header_in_message_info (CamelMessageInfo *info,
        for (ii = 0; ii < G_N_ELEMENTS (known_headers); ii++) {
                found = g_ascii_strcasecmp (name, known_headers[ii].header_name) == 0;
                if (found) {
-                       value = camel_message_info_get_ptr (info, known_headers[ii].info_key);
-                       if (known_headers[ii].info_key != CAMEL_MESSAGE_INFO_SUBJECT)
-                               type = CAMEL_SEARCH_TYPE_ADDRESS_ENCODED;
+                       g_object_get (G_OBJECT (info), known_headers[ii].info_name, &value, NULL);
+                       use_type = known_headers[ii].type;
                        break;
                }
        }
 
-       if (!found || !value)
+       if (!found || !value) {
+               g_free (value);
                return FALSE;
+       }
 
        for (ii = 1; ii < argc && !*matched; ii++) {
                if (argv[ii]->type == CAMEL_SEXP_RES_STRING)
-                       *matched = camel_search_header_match (value, argv[ii]->value.string, how, type, NULL);
+                       *matched = camel_search_header_match (value, argv[ii]->value.string, how, use_type, 
NULL);
        }
 
+       g_free (value);
+
        return TRUE;
 }
 
@@ -249,10 +254,12 @@ check_header (struct _CamelSExp *f,
                } else if (fms->message || !check_header_in_message_info (fms->info, argc, argv, how, 
&matched)) {
                        CamelMimeMessage *message;
                        CamelMimePart *mime_part;
-                       struct _camel_header_raw *header;
+                       const CamelNameValueArray *headers;
                        const gchar *charset = NULL;
                        camel_search_t type = CAMEL_SEARCH_TYPE_ENCODED;
                        CamelContentType *ct;
+                       guint ii;
+                       const gchar *header_name = NULL, *header_value = NULL;
 
                        message = camel_filter_search_get_message (fms, f);
                        mime_part = CAMEL_MIME_PART (message);
@@ -267,12 +274,13 @@ check_header (struct _CamelSExp *f,
                                }
                        }
 
-                       for (header = mime_part->headers; header && !matched; header = header->next) {
+                       headers = camel_medium_get_headers (CAMEL_MEDIUM (mime_part));
+                       for (ii = 0; camel_name_value_array_get (headers, ii, &header_name, &header_value); 
ii++) {
                                /* empty name means any header */
-                               if (!name || !*name || !g_ascii_strcasecmp (header->name, name)) {
+                               if (!name || !*name || !g_ascii_strcasecmp (header_name, name)) {
                                        for (i = 1; i < argc && !matched; i++) {
                                                if (argv[i]->type == CAMEL_SEXP_RES_STRING)
-                                                       matched = camel_search_header_match (header->value, 
argv[i]->value.string, how, type, charset);
+                                                       matched = camel_search_header_match (header_value, 
argv[i]->value.string, how, type, charset);
                                        }
                                }
                        }
@@ -845,7 +853,7 @@ junk_test (struct _CamelSExp *f,
        CamelMimeMessage *message;
        CamelJunkStatus status;
        const GHashTable *ht;
-       const CamelHeaderParam *node;
+       const CamelNameValueArray *info_headers;
        gboolean sender_is_known;
        gboolean message_is_junk = FALSE;
        GError *error = NULL;
@@ -887,52 +895,69 @@ junk_test (struct _CamelSExp *f,
        /* Check the headers for a junk designation. */
 
        ht = camel_session_get_junk_headers (fms->session);
-       node = camel_message_info_get_headers (info);
 
-       while (node != NULL) {
-               const gchar *value = NULL;
+       camel_message_info_property_lock (info);
 
-               if (node->name != NULL)
-                       value = g_hash_table_lookup (
-                               (GHashTable *) ht, node->name);
+       info_headers = camel_message_info_get_headers (info);
+       if (info_headers) {
+               guint len, ii;
 
-               message_is_junk =
-                       (value != NULL) &&
-                       (camel_strstrcase (node->value, value) != NULL);
+               len = camel_name_value_array_get_length (info_headers);
+               for (ii = 0; ii < len; ii++) {
+                       const gchar *hdr_name = NULL;
+                       const gchar *hdr_value = NULL;
+                       const gchar *junk_value = NULL;
 
-               if (message_is_junk) {
-                       if (camel_debug ("junk"))
-                               printf (
-                                       "Message contains \"%s: %s\"",
-                                       node->name, value);
-                       goto done;
-               }
+                       if (!camel_name_value_array_get (info_headers, ii, &hdr_name, &hdr_value))
+                               continue;
+
+                       if (!hdr_name || !hdr_value)
+                               continue;
 
-               node = node->next;
+                       junk_value = g_hash_table_lookup ((GHashTable *) ht, hdr_name);
+
+                       message_is_junk =
+                               (junk_value != NULL) &&
+                               (camel_strstrcase (hdr_value, junk_value) != NULL);
+
+                       if (message_is_junk) {
+                               if (camel_debug ("junk"))
+                                       printf (
+                                               "Message contains \"%s: %s\"",
+                                               hdr_name, junk_value);
+                               camel_message_info_property_unlock (info);
+                               goto done;
+                       }
+               }
        }
 
+       camel_message_info_property_unlock (info);
+
        /* Not every message info has headers available, thus try headers of the message itself */
        message = camel_filter_search_get_message (fms, f);
        if (message) {
-               struct _camel_header_raw *h;
+               const CamelNameValueArray *headers;
+               const gchar *raw_name = NULL, *raw_value = NULL;
+               guint ii;
 
-               for (h = CAMEL_MIME_PART (message)->headers; h; h = h->next) {
+               headers = camel_medium_get_headers (CAMEL_MEDIUM (message));
+               for (ii = 0; camel_name_value_array_get (headers, ii, &raw_name, &raw_value); ii++) {
                        const gchar *value;
-
-                       if (!h->name)
+                       if (!raw_name)
                                continue;
 
-                       value = g_hash_table_lookup ((GHashTable *) ht, h->name);
+                       value = g_hash_table_lookup ((GHashTable *) ht, raw_name);
                        if (!value)
                                continue;
 
-                       message_is_junk = camel_strstrcase (h->value, value) != NULL;
+                       message_is_junk = camel_strstrcase (raw_value, value) != NULL;
 
                        if (message_is_junk) {
-                               if (camel_debug ("junk"))
+                               if (camel_debug ("junk")) {
                                        printf (
                                                "Message contains \"%s: %s\"",
-                                               h->name, value);
+                                               raw_name, value);
+                               }
                                goto done;
                        }
                }
diff --git a/src/camel/camel-folder-search.c b/src/camel/camel-folder-search.c
index ffb4add..850d27d 100644
--- a/src/camel/camel-folder-search.c
+++ b/src/camel/camel-folder-search.c
@@ -57,6 +57,17 @@
        ((obj), CAMEL_TYPE_FOLDER_SEARCH, CamelFolderSearchPrivate))
 
 struct _CamelFolderSearchPrivate {
+       CamelSExp *sexp;                /* s-exp evaluator */
+       gchar *last_search;     /* last searched expression */
+
+       /* these are only valid during the search, and are reset afterwards */
+       CamelFolder *folder;    /* folder for current search */
+       GPtrArray *summary;     /* summary array for current search */
+       GPtrArray *summary_set; /* subset of summary to actually include in search */
+       CamelMessageInfo *current; /* current message info, when searching one by one */
+       CamelMimeMessage *current_message; /* cache of current message, if required */
+       CamelIndex *body_index;
+
        GCancellable *cancellable;
        GError **error;
 
@@ -269,11 +280,10 @@ fill_thread_table (CamelFolderThreadNode *root,
 static CamelMimeMessage *
 get_current_message (CamelFolderSearch *search)
 {
-       if (!search || !search->folder || !search->current)
+       if (!search || !search->priv->folder || !search->priv->current)
                return NULL;
 
-       return camel_folder_get_message_sync (
-               search->folder, search->current->uid, search->priv->cancellable, NULL);
+       return camel_folder_get_message_sync (search->priv->folder, camel_message_info_get_uid 
(search->priv->current), search->priv->cancellable, NULL);
 }
 
 static CamelSExpResult *
@@ -289,7 +299,7 @@ check_header (CamelSExp *sexp,
        r (printf ("executing check-header %d\n", how));
 
        /* are we inside a match-all? */
-       if (search->current && argc > 1
+       if (search->priv->current && argc > 1
            && argv[0]->type == CAMEL_SEXP_RES_STRING
            && !g_cancellable_is_cancelled (search->priv->cancellable)) {
                gchar *headername;
@@ -299,29 +309,28 @@ check_header (CamelSExp *sexp,
                camel_search_t type = CAMEL_SEARCH_TYPE_ASIS;
                struct _camel_search_words *words;
                CamelMimeMessage *message = NULL;
-               struct _camel_header_raw *raw_header;
 
                /* only a subset of headers are supported .. */
                headername = argv[0]->value.string;
                if (!g_ascii_strcasecmp (headername, "subject")) {
-                       header = camel_message_info_get_subject (search->current);
+                       header = camel_message_info_get_subject (search->priv->current);
                } else if (!g_ascii_strcasecmp (headername, "date")) {
                        /* FIXME: not a very useful form of the date */
                        g_snprintf (
                                strbuf, sizeof (strbuf), "%d",
-                               (gint) camel_message_info_get_date_sent (search->current));
+                               (gint) camel_message_info_get_date_sent (search->priv->current));
                        header = strbuf;
                } else if (!g_ascii_strcasecmp (headername, "from")) {
-                       header = camel_message_info_get_from (search->current);
+                       header = camel_message_info_get_from (search->priv->current);
                        type = CAMEL_SEARCH_TYPE_ADDRESS;
                } else if (!g_ascii_strcasecmp (headername, "to")) {
-                       header = camel_message_info_get_to (search->current);
+                       header = camel_message_info_get_to (search->priv->current);
                        type = CAMEL_SEARCH_TYPE_ADDRESS;
                } else if (!g_ascii_strcasecmp (headername, "cc")) {
-                       header = camel_message_info_get_cc (search->current);
+                       header = camel_message_info_get_cc (search->priv->current);
                        type = CAMEL_SEARCH_TYPE_ADDRESS;
                } else if (!g_ascii_strcasecmp (headername, "x-camel-mlist")) {
-                       header = camel_message_info_get_mlist (search->current);
+                       header = camel_message_info_get_mlist (search->priv->current);
                        type = CAMEL_SEARCH_TYPE_MLIST;
                } else {
                        message = get_current_message (search);
@@ -351,15 +360,20 @@ check_header (CamelSExp *sexp,
                                        truth = TRUE;
                                        for (j = 0; j < words->len && truth; j++) {
                                                if (message) {
-                                                       for (raw_header = ((CamelMimePart *) 
message)->headers; raw_header; raw_header = raw_header->next) {
+                                                       const CamelNameValueArray *headers = NULL;
+                                                       const gchar *raw_name = NULL, *raw_value = NULL;
+                                                       guint ii;
+
+                                                       headers = camel_medium_get_headers (CAMEL_MEDIUM 
(message));
+                                                       for (ii = 0; camel_name_value_array_get (headers, ii, 
&raw_name, &raw_value); ii++) {
                                                                /* empty name means any header */
-                                                               if (!headername || !*headername || 
!g_ascii_strcasecmp (raw_header->name, headername)) {
-                                                                       if (camel_search_header_match 
(raw_header->value, words->words[j]->word, how, type, charset))
+                                                               if (!headername || !*headername || 
!g_ascii_strcasecmp (raw_name, headername)) {
+                                                                       if (camel_search_header_match 
(raw_value, words->words[j]->word, how, type, charset))
                                                                                break;
                                                                }
                                                        }
 
-                                                       truth = raw_header != NULL;
+                                                       truth = ii < camel_name_value_array_get_length 
(headers);
                                                } else
                                                        truth = camel_search_header_match (
                                                                header,
@@ -369,11 +383,16 @@ check_header (CamelSExp *sexp,
                                        camel_search_words_free (words);
                                } else {
                                        if (message) {
-                                               for (raw_header = ((CamelMimePart *) message)->headers; 
raw_header && !truth; raw_header = raw_header->next) {
+                                               const CamelNameValueArray *headers = NULL;
+                                               const gchar *raw_name = NULL, *raw_value = NULL;
+                                               guint ii;
+
+                                               headers = camel_medium_get_headers (CAMEL_MEDIUM (message));
+                                               for (ii = 0; camel_name_value_array_get (headers, ii, 
&raw_name, &raw_value); ii++) {
                                                        /* empty name means any header */
-                                                       if (!headername || !*headername || 
!g_ascii_strcasecmp (raw_header->name, headername)) {
+                                                       if (!headername || !*headername || 
!g_ascii_strcasecmp (raw_name, headername)) {
                                                                truth = camel_search_header_match (
-                                                                       raw_header->value,
+                                                                       raw_value,
                                                                        argv[i]->value.string,
                                                                        how, type, charset);
                                                        }
@@ -460,7 +479,7 @@ match_words_index (CamelFolderSearch *search,
 
        /* we can have a maximum of 32 words, as we use it as the AND mask */
 
-       wc = camel_index_words (search->body_index);
+       wc = camel_index_words (search->priv->body_index);
        if (wc) {
                GHashTable *ht = g_hash_table_new (g_str_hash, g_str_equal);
 
@@ -468,7 +487,7 @@ match_words_index (CamelFolderSearch *search,
                        for (i = 0; i < words->len; i++) {
                                if (camel_ustrstrcase (word, words->words[i]->word) != NULL) {
                                        /* perf: could have the wc cursor return the name cursor */
-                                       nc = camel_index_find (search->body_index, word);
+                                       nc = camel_index_find (search->priv->body_index, word);
                                        if (nc) {
                                                while ((name = camel_index_cursor_next (nc))) {
                                                                gchar *name_owned;
@@ -528,7 +547,7 @@ match_words_1message (CamelDataWrapper *object,
        } else if (CAMEL_IS_MIME_MESSAGE (containee)) {
                /* for messages we only look at its contents */
                truth = match_words_1message ((CamelDataWrapper *) containee, words, mask, cancellable);
-       } else if (camel_content_type_is (CAMEL_DATA_WRAPPER (containee)->mime_type, "text", "*")) {
+       } else if (camel_content_type_is (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER 
(containee)), "text", "*")) {
                /* for all other text parts, we look inside, otherwise we dont care */
                CamelStream *stream;
                GByteArray *byte_array;
@@ -537,7 +556,7 @@ match_words_1message (CamelDataWrapper *object,
                byte_array = g_byte_array_new ();
                stream = camel_stream_mem_new_with_byte_array (byte_array);
 
-               charset = camel_content_type_param (CAMEL_DATA_WRAPPER (containee)->mime_type, "charset");
+               charset = camel_content_type_param (camel_data_wrapper_get_mime_type_field 
(CAMEL_DATA_WRAPPER (containee)), "charset");
                if (charset && *charset) {
                        CamelMimeFilter *filter = camel_mime_filter_charset_new (charset, "UTF-8");
                        if (filter) {
@@ -609,7 +628,7 @@ match_words_messages (CamelFolderSearch *search,
        if (g_cancellable_set_error_if_cancelled (cancellable, error))
                return matches;
 
-       if (search->body_index) {
+       if (search->priv->body_index) {
                GPtrArray *indexed;
                struct _camel_search_words *simple;
 
@@ -621,20 +640,20 @@ match_words_messages (CamelFolderSearch *search,
                        const gchar *uid = g_ptr_array_index (indexed, i);
 
                        if (match_words_message (
-                                       search->folder, uid, words,
+                                       search->priv->folder, uid, words,
                                        cancellable, error))
                                g_ptr_array_add (matches, (gchar *) uid);
                }
 
                g_ptr_array_free (indexed, TRUE);
        } else {
-               GPtrArray *v = search->summary_set ? search->summary_set : search->summary;
+               GPtrArray *v = camel_folder_search_get_current_summary (search);
 
                for (i = 0; i < v->len && !g_cancellable_is_cancelled (cancellable); i++) {
                        gchar *uid = g_ptr_array_index (v, i);
 
                        if (match_words_message (
-                               search->folder, uid, words,
+                               search->priv->folder, uid, words,
                                cancellable, error))
                                g_ptr_array_add (matches, (gchar *) uid);
                }
@@ -666,7 +685,7 @@ folder_search_dummy (CamelSExp *sexp,
 {
        CamelSExpResult *r;
 
-       if (search->current == NULL) {
+       if (search->priv->current == NULL) {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
                r->value.boolean = FALSE;
        } else {
@@ -691,10 +710,7 @@ folder_search_dispose (GObject *object)
 {
        CamelFolderSearch *search = CAMEL_FOLDER_SEARCH (object);
 
-       if (search->sexp != NULL) {
-               g_object_unref (search->sexp);
-               search->sexp = NULL;
-       }
+       g_clear_object (&search->priv->sexp);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (camel_folder_search_parent_class)->dispose (object);
@@ -705,7 +721,7 @@ folder_search_finalize (GObject *object)
 {
        CamelFolderSearch *search = CAMEL_FOLDER_SEARCH (object);
 
-       g_free (search->last_search);
+       g_free (search->priv->last_search);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_folder_search_parent_class)->finalize (object);
@@ -747,18 +763,18 @@ folder_search_constructed (GObject *object)
                if (func != NULL) {
                        if (flags & CAMEL_FOLDER_SEARCH_IMMEDIATE) {
                                camel_sexp_add_ifunction (
-                                       search->sexp, 0, name,
+                                       search->priv->sexp, 0, name,
                                        (CamelSExpIFunc) func, search);
                        } else {
                                camel_sexp_add_function (
-                                       search->sexp, 0, name,
+                                       search->priv->sexp, 0, name,
                                        (CamelSExpFunc) func, search);
                        }
                }
        }
 
        camel_sexp_add_function (
-               search->sexp, 0, "header-has-words",
+               search->priv->sexp, 0, "header-has-words",
                (CamelSExpFunc) folder_search_header_has_words, search);
 }
 
@@ -781,10 +797,10 @@ folder_search_not (CamelSExp *sexp,
                        r->value.ptrarray = g_ptr_array_new ();
 
                        /* not against a single message?*/
-                       if (search->current) {
+                       if (search->priv->current) {
                                gint found = FALSE;
 
-                               uid = camel_message_info_get_uid (search->current);
+                               uid = camel_message_info_get_uid (search->priv->current);
                                for (i = 0; !found && i < v->len; i++) {
                                        if (strcmp (uid, v->pdata[i]) == 0)
                                                found = TRUE;
@@ -792,7 +808,7 @@ folder_search_not (CamelSExp *sexp,
 
                                if (!found)
                                        g_ptr_array_add (r->value.ptrarray, (gchar *) uid);
-                       } else if (search->summary == NULL) {
+                       } else if (search->priv->summary == NULL) {
                                g_warning ("No summary set, 'not' against an array requires a summary");
                        } else {
                                /* 'not' against the whole summary */
@@ -804,7 +820,7 @@ folder_search_not (CamelSExp *sexp,
                                for (i = 0; i < v->len; i++)
                                        g_hash_table_insert (have, s[i], s[i]);
 
-                               v = search->summary_set ? search->summary_set : search->summary;
+                               v = camel_folder_search_get_current_summary (search);
                                m = (gchar **) v->pdata;
                                for (i = 0; i < v->len; i++) {
                                        gchar *uid = m[i];
@@ -847,8 +863,8 @@ folder_search_match_all (CamelSExp *sexp,
        }
 
        /* we are only matching a single message?  or already inside a match-all? */
-       if (search->current) {
-               d (printf ("matching against 1 message: %s\n", camel_message_info_get_subject 
(search->current)));
+       if (search->priv->current) {
+               d (printf ("matching against 1 message: %s\n", camel_message_info_get_subject 
(search->priv->current)));
 
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
                r->value.boolean = FALSE;
@@ -874,25 +890,25 @@ folder_search_match_all (CamelSExp *sexp,
        r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_ARRAY_PTR);
        r->value.ptrarray = g_ptr_array_new ();
 
-       if (search->summary == NULL) {
+       if (search->priv->summary == NULL) {
                /* TODO: make it work - e.g. use the folder and so forth for a slower search */
                g_warning ("No summary supplied, match-all doesn't work with no summary");
                return r;
        }
 
-       v = search->summary_set ? search->summary_set : search->summary;
+       v = camel_folder_search_get_current_summary (search);
 
-       if (!CAMEL_IS_VEE_FOLDER (search->folder)) {
-               camel_folder_summary_prepare_fetch_all (search->folder->summary, search->priv->error);
+       if (!CAMEL_IS_VEE_FOLDER (search->priv->folder)) {
+               camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary 
(search->priv->folder), search->priv->error);
        }
 
        for (i = 0; i < v->len && !g_cancellable_is_cancelled (search->priv->cancellable); i++) {
                const gchar *uid;
 
-               search->current = camel_folder_summary_get (search->folder->summary, v->pdata[i]);
-               if (!search->current)
+               search->priv->current = camel_folder_summary_get (camel_folder_get_folder_summary 
(search->priv->folder), v->pdata[i]);
+               if (!search->priv->current)
                        continue;
-               uid = camel_message_info_get_uid (search->current);
+               uid = camel_message_info_get_uid (search->priv->current);
 
                if (argc > 0) {
                        r1 = camel_sexp_term_eval (sexp, argv[0]);
@@ -910,9 +926,9 @@ folder_search_match_all (CamelSExp *sexp,
                } else {
                        g_ptr_array_add (r->value.ptrarray, (gchar *) uid);
                }
-               camel_message_info_unref (search->current);
+               g_clear_object (&search->priv->current);
        }
-       search->current = NULL;
+       search->priv->current = NULL;
        return r;
 }
 
@@ -935,7 +951,7 @@ folder_search_match_threads (CamelSExp *sexp,
        }
 
        /* not supported in match-all */
-       if (search->current) {
+       if (search->priv->current) {
                /* Translators: Each '%s' is an element type name, part of an expressing language */
                error_msg = g_strdup_printf (_("(%s) not allowed inside %s"), "match-threads", "match-all");
                camel_sexp_fatal_error (sexp, error_msg);
@@ -988,7 +1004,7 @@ folder_search_match_threads (CamelSExp *sexp,
        if (type == 0)
                return r;
 
-       if (search->folder == NULL) {
+       if (search->priv->folder == NULL) {
                /* Translators: The '%s' is an element type name, part of an expressing language */
                error_msg = g_strdup_printf (_("(%s) requires the folder set"), "match-threads");
                camel_sexp_fatal_error (sexp, error_msg);
@@ -997,7 +1013,7 @@ folder_search_match_threads (CamelSExp *sexp,
 
        /* cache this, so we only have to re-calculate once per search at most */
        if (p->threads == NULL) {
-               p->threads = camel_folder_thread_messages_new (search->folder, NULL, TRUE);
+               p->threads = camel_folder_thread_messages_new (search->priv->folder, NULL, TRUE);
                p->threads_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
                fill_thread_table (p->threads->tree, p->threads_hash);
@@ -1058,7 +1074,7 @@ folder_search_body_contains (CamelSExp *sexp,
        CamelSExpResult *r;
        struct IterData lambdafoo;
 
-       if (search->current) {
+       if (search->priv->current) {
                gint truth = FALSE;
 
                if (argc == 1 && argv[0]->value.string[0] == 0) {
@@ -1068,18 +1084,18 @@ folder_search_body_contains (CamelSExp *sexp,
                                if (argv[i]->type == CAMEL_SEXP_RES_STRING) {
                                        words = camel_search_words_split ((const guchar *) 
argv[i]->value.string);
                                        truth = TRUE;
-                                       if ((words->type & CAMEL_SEARCH_WORD_COMPLEX) == 0 && 
search->body_index) {
+                                       if ((words->type & CAMEL_SEARCH_WORD_COMPLEX) == 0 && 
search->priv->body_index) {
                                                for (j = 0; j < words->len && truth; j++)
                                                        truth = match_message_index (
-                                                               search->body_index,
-                                                               camel_message_info_get_uid (search->current),
+                                                               search->priv->body_index,
+                                                               camel_message_info_get_uid 
(search->priv->current),
                                                                words->words[j]->word,
                                                                error);
                                        } else {
                                                /* TODO: cache current message incase of multiple body search 
terms */
                                                truth = match_words_message (
-                                                       search->folder,
-                                                       camel_message_info_get_uid (search->current),
+                                                       search->priv->folder,
+                                                       camel_message_info_get_uid (search->priv->current),
                                                        words,
                                                        search->priv->cancellable,
                                                        error);
@@ -1095,7 +1111,7 @@ folder_search_body_contains (CamelSExp *sexp,
                r->value.ptrarray = g_ptr_array_new ();
 
                if (argc == 1 && argv[0]->value.string[0] == 0) {
-                       GPtrArray *v = search->summary_set ? search->summary_set : search->summary;
+                       GPtrArray *v = camel_folder_search_get_current_summary (search);
 
                        for (i = 0; i < v->len && !g_cancellable_is_cancelled (search->priv->cancellable); 
i++) {
                                gchar *uid = g_ptr_array_index (v, i);
@@ -1109,7 +1125,7 @@ folder_search_body_contains (CamelSExp *sexp,
                        for (i = 0; i < argc && !g_cancellable_is_cancelled (search->priv->cancellable); i++) 
{
                                if (argv[i]->type == CAMEL_SEXP_RES_STRING) {
                                        words = camel_search_words_split ((const guchar *) 
argv[i]->value.string);
-                                       if ((words->type & CAMEL_SEARCH_WORD_COMPLEX) == 0 && 
search->body_index) {
+                                       if ((words->type & CAMEL_SEARCH_WORD_COMPLEX) == 0 && 
search->priv->body_index) {
                                                matches = match_words_index (search, words, 
search->priv->cancellable, error);
                                        } else {
                                                matches = match_words_messages (search, words, 
search->priv->cancellable, error);
@@ -1173,14 +1189,14 @@ folder_search_body_regex (CamelSExp *sexp,
                                argc, argv,
                                search->priv->error) == 0) {
                        gint i;
-                       GPtrArray *v = search->summary_set ? search->summary_set : search->summary;
+                       GPtrArray *v = camel_folder_search_get_current_summary (search);
                        CamelMimeMessage *message;
 
                        for (i = 0; i < v->len && !g_cancellable_is_cancelled (search->priv->cancellable); 
i++) {
                                gchar *uid = g_ptr_array_index (v, i);
 
                                message = camel_folder_get_message_sync (
-                                       search->folder, uid, search->priv->cancellable, NULL);
+                                       search->priv->folder, uid, search->priv->cancellable, NULL);
                                if (message) {
                                        if (camel_search_message_body_contains ((CamelDataWrapper *) message, 
&pattern)) {
                                                g_ptr_array_add (r->value.ptrarray, uid);
@@ -1243,10 +1259,10 @@ folder_search_header_exists (CamelSExp *sexp,
 
        r (printf ("executing header-exists\n"));
 
-       if (search->current) {
+       if (search->priv->current) {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
                if (argc == 1 && argv[0]->type == CAMEL_SEXP_RES_STRING)
-                       r->value.boolean = camel_medium_get_header (CAMEL_MEDIUM (search->current), 
argv[0]->value.string) != NULL;
+                       r->value.boolean = camel_medium_get_header (CAMEL_MEDIUM (search->priv->current), 
argv[0]->value.string) != NULL;
 
        } else {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_ARRAY_PTR);
@@ -1366,8 +1382,8 @@ folder_search_user_tag (CamelSExp *sexp,
 
        r (printf ("executing user-tag\n"));
 
-       if (search->current && argc == 1)
-               value = camel_message_info_get_user_tag (search->current, argv[0]->value.string);
+       if (search->priv->current && argc == 1)
+               value = camel_message_info_get_user_tag (search->priv->current, argv[0]->value.string);
 
        r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_STRING);
        r->value.string = g_strdup (value ? value : "");
@@ -1387,12 +1403,12 @@ folder_search_user_flag (CamelSExp *sexp,
        r (printf ("executing user-flag\n"));
 
        /* are we inside a match-all? */
-       if (search->current) {
+       if (search->priv->current) {
                gint truth = FALSE;
                /* performs an OR of all words */
                for (i = 0; i < argc && !truth; i++) {
                        if (argv[i]->type == CAMEL_SEXP_RES_STRING
-                           && camel_message_info_get_user_flag (search->current, argv[i]->value.string)) {
+                           && camel_message_info_get_user_flag (search->priv->current, 
argv[i]->value.string)) {
                                truth = TRUE;
                                break;
                        }
@@ -1417,11 +1433,11 @@ folder_search_system_flag (CamelSExp *sexp,
 
        r (printf ("executing system-flag\n"));
 
-       if (search->current) {
+       if (search->priv->current) {
                gboolean truth = FALSE;
 
                if (argc == 1)
-                       truth = camel_system_flag_get (camel_message_info_get_flags (search->current), 
argv[0]->value.string);
+                       truth = camel_system_flag_get (camel_message_info_get_flags (search->priv->current), 
argv[0]->value.string);
 
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
                r->value.boolean = truth;
@@ -1444,10 +1460,10 @@ folder_search_get_sent_date (CamelSExp *sexp,
        r (printf ("executing get-sent-date\n"));
 
        /* are we inside a match-all? */
-       if (search->current) {
+       if (search->priv->current) {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
 
-               r->value.number = camel_message_info_get_date_sent (search->current);
+               r->value.number = camel_message_info_get_date_sent (search->priv->current);
        } else {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_ARRAY_PTR);
                r->value.ptrarray = g_ptr_array_new ();
@@ -1467,10 +1483,10 @@ folder_search_get_received_date (CamelSExp *sexp,
        r (printf ("executing get-received-date\n"));
 
        /* are we inside a match-all? */
-       if (search->current) {
+       if (search->priv->current) {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
 
-               r->value.number = camel_message_info_get_date_received (search->current);
+               r->value.number = camel_message_info_get_date_received (search->priv->current);
        } else {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_ARRAY_PTR);
                r->value.ptrarray = g_ptr_array_new ();
@@ -1528,9 +1544,9 @@ folder_search_get_size (CamelSExp *sexp,
        r (printf ("executing get-size\n"));
 
        /* are we inside a match-all? */
-       if (search->current) {
+       if (search->priv->current) {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
-               r->value.number = camel_message_info_get_size (search->current) / 1024;
+               r->value.number = camel_message_info_get_size (search->priv->current) / 1024;
        } else {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_ARRAY_PTR);
                r->value.ptrarray = g_ptr_array_new ();
@@ -1551,9 +1567,9 @@ folder_search_uid (CamelSExp *sexp,
        r (printf ("executing uid\n"));
 
        /* are we inside a match-all? */
-       if (search->current) {
+       if (search->priv->current) {
                gint truth = FALSE;
-               const gchar *uid = camel_message_info_get_uid (search->current);
+               const gchar *uid = camel_message_info_get_uid (search->priv->current);
 
                /* performs an OR of all words */
                for (i = 0; i < argc && !truth; i++) {
@@ -1617,13 +1633,13 @@ folder_search_message_location (CamelSExp *sexp,
        gboolean same = FALSE;
 
        if (argc == 1 && argv[0]->type == CAMEL_SEXP_RES_STRING) {
-               if (argv[0]->value.string && search->folder) {
+               if (argv[0]->value.string && search->priv->folder) {
                        CamelStore *store;
                        const gchar *name;
                        gchar *uri;
 
-                       store = camel_folder_get_parent_store (search->folder);
-                       name = camel_folder_get_full_name (search->folder);
+                       store = camel_folder_get_parent_store (search->priv->folder);
+                       name = camel_folder_get_full_name (search->priv->folder);
                        uri = mail_folder_uri_build (store, name);
 
                        same = g_str_equal (uri, argv[0]->value.string);
@@ -1632,7 +1648,7 @@ folder_search_message_location (CamelSExp *sexp,
                }
        }
 
-       if (search->current) {
+       if (search->priv->current) {
                r = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
                r->value.boolean = same ? TRUE : FALSE;
        } else {
@@ -1642,7 +1658,7 @@ folder_search_message_location (CamelSExp *sexp,
                if (same) {
                        /* all matches */
                        gint i;
-                       GPtrArray *v = search->summary_set ? search->summary_set : search->summary;
+                       GPtrArray *v = camel_folder_search_get_current_summary (search);
 
                        for (i = 0; i < v->len; i++) {
                                gchar *uid = g_ptr_array_index (v, i);
@@ -1696,22 +1712,7 @@ static void
 camel_folder_search_init (CamelFolderSearch *search)
 {
        search->priv = CAMEL_FOLDER_SEARCH_GET_PRIVATE (search);
-       search->sexp = camel_sexp_new ();
-}
-
-/**
- * camel_folder_search_construct:
- * @search: a #CamelFolderSearch
- *
- * This function used to register callbacks with @search's internal
- * #CamelSExp, but this now happens during instance initialization.
- *
- * Deprecated: 3.8: The function no longer does anything.
- **/
-void
-camel_folder_search_construct (CamelFolderSearch *search)
-{
-       /* XXX constructed() method handles what used to be here. */
+       search->priv->sexp = camel_sexp_new ();
 }
 
 /**
@@ -1733,13 +1734,97 @@ camel_folder_search_new (void)
 }
 
 /**
+ * camel_folder_search_set_current_message_info:
+ * @search: a #CamelFolderSearch
+ * @info: (nullable): a #CamelMessageInfo
+ *
+ * Sets, or unsets, the @info as the currently processing #CamelMessageInfo.
+ * The function adds its own reference to @info, if not %NULL.
+ *
+ * Since: 3.24
+ **/
+void
+camel_folder_search_set_current_message_info (CamelFolderSearch *search,
+                                             CamelMessageInfo *info)
+{
+       g_return_if_fail (CAMEL_IS_FOLDER_SEARCH (search));
+       if (info)
+               g_return_if_fail (CAMEL_IS_MESSAGE_INFO (info));
+
+       if (info != search->priv->current) {
+               if (info)
+                       g_object_ref (info);
+
+               g_clear_object (&search->priv->current);
+               search->priv->current = info;
+       }
+}
+
+/**
+ * camel_folder_search_take_current_message_info:
+ * @search: a #CamelFolderSearch
+ * @info: (nullable): a #CamelMessageInfo
+ *
+ * Sets, or unsets, the @info as the currently processing #CamelMessageInfo.
+ * Unlike camel_folder_search_set_current_message_info(), this function
+ * assumes ownership of the @info, if not %NULL.
+ *
+ * Since: 3.24
+ **/
+void
+camel_folder_search_take_current_message_info (CamelFolderSearch *search,
+                                              CamelMessageInfo *info)
+{
+       g_return_if_fail (CAMEL_IS_FOLDER_SEARCH (search));
+       if (info)
+               g_return_if_fail (CAMEL_IS_MESSAGE_INFO (info));
+
+       camel_folder_search_set_current_message_info (search, info);
+
+       /* Remove the reference added by camel_folder_search_set_current_message_info() */
+       g_clear_object (&info);
+}
+
+/**
+ * camel_folder_search_get_current_message_info:
+ * @search: a #CamelFolderSearch
+ *
+ * Returns: (nullable) (transfer none): the currently processing #CamelMessageInfo
+ *
+ * Since: 3.24
+ **/
+CamelMessageInfo *
+camel_folder_search_get_current_message_info (CamelFolderSearch *search)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SEARCH (search), NULL);
+
+       return search->priv->current;
+}
+
+/**
+ * camel_folder_search_get_current_summary:
+ * @search: a #CamelFolderSearch
+ *
+ * Returns: (transfer none) (element-type utf8): the current summary, and array
+ *   of message info UID-s to use.
+ *
+ * Since: 3.24
+ **/
+GPtrArray *
+camel_folder_search_get_current_summary (CamelFolderSearch *search)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SEARCH (search), NULL);
+
+       return search->priv->summary_set ? search->priv->summary_set : search->priv->summary;
+}
+
+/**
  * camel_folder_search_set_folder:
- * @search:
- * @folder: A folder.
+ * @search: a #CamelFolderSearch
+ * @folder: a #CamelFolder
  *
- * Set the folder attribute of the search.  This is currently unused, but
- * could be used to perform a slow-search when indexes and so forth are not
- * available.  Or for use by subclasses.
+ * Set the folder attribute of the search. This can be used to perform a slow-search
+ * when indexes and so forth are not available. Or for use by subclasses.
  **/
 void
 camel_folder_search_set_folder (CamelFolderSearch *search,
@@ -1748,13 +1833,29 @@ camel_folder_search_set_folder (CamelFolderSearch *search,
        g_return_if_fail (CAMEL_IS_FOLDER_SEARCH (search));
        g_return_if_fail (CAMEL_IS_FOLDER (folder));
 
-       search->folder = folder;
+       search->priv->folder = folder;
+}
+
+/**
+ * camel_folder_search_get_folder:
+ * @search: a #CamelFolderSearch
+ *
+ * Returns: (transfer none): a #CamelFolder for which the @search is currently running.
+ *
+ * Since: 3.24
+ **/
+CamelFolder *
+camel_folder_search_get_folder (CamelFolderSearch *search)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SEARCH (search), NULL);
+
+       return search->priv->folder;
 }
 
 /**
  * camel_folder_search_set_summary:
- * @search:
- * @summary: (element-type CamelMessageInfo): An array of CamelMessageInfo pointers.
+ * @search: a #CamelFolderSearch
+ * @summary: (element-type utf8): An array of UID-s of #CamelMessageInfo.
  *
  * Set the array of summary objects representing the span of the search.
  *
@@ -1767,7 +1868,39 @@ camel_folder_search_set_summary (CamelFolderSearch *search,
 {
        g_return_if_fail (CAMEL_IS_FOLDER_SEARCH (search));
 
-       search->summary = summary;
+       search->priv->summary = summary;
+}
+
+/**
+ * camel_folder_search_get_summary:
+ * @search: a #CamelFolderSearch
+ *
+ * Returns: (element-type utf8) (transfer none): A summary of UID-s of #CamelMessageInfo
+ *   previously set by camel_folder_search_set_summary().
+ *
+ * Since: 3.24
+ **/
+GPtrArray *
+camel_folder_search_get_summary (CamelFolderSearch *search)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SEARCH (search), NULL);
+
+       return search->priv->summary;
+}
+
+/**
+ * camel_folder_search_get_summary_empty:
+ * @search: a #CamelFolderSearch
+ *
+ * Returns: Whether the summary (as returned by camel_folder_search_get_summary()) is empty.
+ *   It returns %FALSE when the summary is set and contains at least one item.
+ **/
+gboolean
+camel_folder_search_get_summary_empty (CamelFolderSearch *search)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SEARCH (search), TRUE);
+
+       return !search->priv->summary || !search->priv->summary->len;
 }
 
 /**
@@ -1791,10 +1924,10 @@ camel_folder_search_set_body_index (CamelFolderSearch *search,
                g_object_ref (body_index);
        }
 
-       if (search->body_index != NULL)
-               g_object_unref (search->body_index);
+       if (search->priv->body_index != NULL)
+               g_object_unref (search->priv->body_index);
 
-       search->body_index = body_index;
+       search->priv->body_index = body_index;
 }
 
 static gboolean
@@ -1818,8 +1951,8 @@ do_search_in_memory (CamelFolder *search_in_folder,
        gint i;
 
        if (search_in_folder &&
-           search_in_folder->summary &&
-           (search_in_folder->summary->flags & CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY) != 0)
+           camel_folder_get_folder_summary (search_in_folder) &&
+           (camel_folder_summary_get_flags (camel_folder_get_folder_summary (search_in_folder)) & 
CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY) != 0)
                return TRUE;
 
        if (!expr)
@@ -1888,7 +2021,7 @@ camel_folder_search_count (CamelFolderSearch *search,
        if (!expr || !*expr)
                expr = "(match-all)";
 
-       if (!search->folder) {
+       if (!search->priv->folder) {
                g_warn_if_reached ();
                goto fail;
        }
@@ -1898,35 +2031,35 @@ camel_folder_search_count (CamelFolderSearch *search,
        p->error = error;
 
        /* We route body-contains search and thread based search through memory and not via db. */
-       if (do_search_in_memory (search->folder, expr, &sql_query)) {
+       if (do_search_in_memory (search->priv->folder, expr, &sql_query)) {
                /* setup our search list only contains those we're interested in */
-               search->summary = camel_folder_get_summary (search->folder);
-               if (search->folder->summary)
-                       camel_folder_summary_prepare_fetch_all (search->folder->summary, NULL);
+               search->priv->summary = camel_folder_get_summary (search->priv->folder);
+               if (camel_folder_get_folder_summary (search->priv->folder))
+                       camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary 
(search->priv->folder), NULL);
 
-               summary_set = search->summary;
+               summary_set = search->priv->summary;
 
                /* only re-parse if the search has changed */
-               if (search->last_search == NULL
-                   || strcmp (search->last_search, expr)) {
-                       camel_sexp_input_text (search->sexp, expr, strlen (expr));
-                       if (camel_sexp_parse (search->sexp) == -1) {
+               if (search->priv->last_search == NULL
+                   || strcmp (search->priv->last_search, expr)) {
+                       camel_sexp_input_text (search->priv->sexp, expr, strlen (expr));
+                       if (camel_sexp_parse (search->priv->sexp) == -1) {
                                g_set_error (
                                        error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                                        _("Cannot parse search expression: %s:\n%s"),
-                                       camel_sexp_error (search->sexp), expr);
+                                       camel_sexp_error (search->priv->sexp), expr);
                                goto fail;
                        }
 
-                       g_free (search->last_search);
-                       search->last_search = g_strdup (expr);
+                       g_free (search->priv->last_search);
+                       search->priv->last_search = g_strdup (expr);
                }
-               r = camel_sexp_eval (search->sexp);
+               r = camel_sexp_eval (search->priv->sexp);
                if (r == NULL) {
                        g_set_error (
                                error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                                _("Error executing search expression: %s:\n%s"),
-                               camel_sexp_error (search->sexp), expr);
+                               camel_sexp_error (search->priv->sexp), expr);
                        goto fail;
                }
 
@@ -1949,18 +2082,18 @@ camel_folder_search_count (CamelFolderSearch *search,
                        g_hash_table_destroy (results);
                }
 
-               camel_sexp_result_free (search->sexp, r);
+               camel_sexp_result_free (search->priv->sexp, r);
 
        } else {
                CamelStore *parent_store;
                const gchar *full_name;
                GError *local_error = NULL;
 
-               full_name = camel_folder_get_full_name (search->folder);
-               parent_store = camel_folder_get_parent_store (search->folder);
+               full_name = camel_folder_get_full_name (search->priv->folder);
+               parent_store = camel_folder_get_parent_store (search->priv->folder);
 
                /* Sync the db, so that we search the db for changes */
-               camel_folder_summary_save_to_db (search->folder->summary, error);
+               camel_folder_summary_save (camel_folder_get_folder_summary (search->priv->folder), error);
 
                dd (printf ("sexp is : [%s]\n", expr));
                tmp1 = camel_db_sqlize_string (full_name);
@@ -1969,7 +2102,7 @@ camel_folder_search_count (CamelFolderSearch *search,
                g_free (sql_query);
                dd (printf ("Equivalent sql %s\n", tmp));
 
-               cdb = (CamelDB *) (parent_store->cdb_r);
+               cdb = camel_store_get_db (parent_store);
                camel_db_count_message_info  (cdb, tmp, &count, &local_error);
                if (local_error != NULL) {
                        const gchar *message = local_error->message;
@@ -1989,10 +2122,10 @@ fail:
                camel_folder_thread_messages_unref (p->threads);
        if (p->threads_hash)
                g_hash_table_destroy (p->threads_hash);
-       if (search->summary_set)
-               g_ptr_array_free (search->summary_set, TRUE);
-       if (search->summary)
-               camel_folder_free_summary (search->folder, search->summary);
+       if (search->priv->summary_set)
+               g_ptr_array_free (search->priv->summary_set, TRUE);
+       if (search->priv->summary)
+               camel_folder_free_summary (search->priv->folder, search->priv->summary);
 
        free_pstring_array (p->owned_pstrings);
        p->owned_pstrings = NULL;
@@ -2000,11 +2133,11 @@ fail:
        p->error = NULL;
        p->threads = NULL;
        p->threads_hash = NULL;
-       search->folder = NULL;
-       search->summary = NULL;
-       search->summary_set = NULL;
-       search->current = NULL;
-       search->body_index = NULL;
+       search->priv->folder = NULL;
+       search->priv->summary = NULL;
+       search->priv->summary_set = NULL;
+       search->priv->current = NULL;
+       search->priv->body_index = NULL;
 
        return count;
 }
@@ -2048,7 +2181,7 @@ camel_folder_search_search (CamelFolderSearch *search,
        if (!expr || !*expr)
                expr = "(match-all)";
 
-       if (!search->folder) {
+       if (!search->priv->folder) {
                g_warn_if_reached ();
                goto fail;
        }
@@ -2058,47 +2191,47 @@ camel_folder_search_search (CamelFolderSearch *search,
        p->error = error;
 
        /* We route body-contains / thread based search and uid search through memory and not via db. */
-       if (uids || do_search_in_memory (search->folder, expr, &sql_query)) {
+       if (uids || do_search_in_memory (search->priv->folder, expr, &sql_query)) {
                /* setup our search list only contains those we're interested in */
-               search->summary = camel_folder_get_summary (search->folder);
+               search->priv->summary = camel_folder_get_summary (search->priv->folder);
 
                if (uids) {
                        GHashTable *uids_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
-                       summary_set = search->summary_set = g_ptr_array_new ();
+                       summary_set = search->priv->summary_set = g_ptr_array_new ();
                        for (i = 0; i < uids->len; i++)
                                g_hash_table_insert (uids_hash, uids->pdata[i], uids->pdata[i]);
-                       for (i = 0; i < search->summary->len; i++)
-                               if (g_hash_table_lookup (uids_hash, search->summary->pdata[i]))
-                                       g_ptr_array_add (search->summary_set, search->summary->pdata[i]);
+                       for (i = 0; i < search->priv->summary->len; i++)
+                               if (g_hash_table_lookup (uids_hash, search->priv->summary->pdata[i]))
+                                       g_ptr_array_add (search->priv->summary_set, 
search->priv->summary->pdata[i]);
                        g_hash_table_destroy (uids_hash);
                } else {
-                       if (search->folder->summary)
-                               camel_folder_summary_prepare_fetch_all (search->folder->summary, NULL);
-                       summary_set = search->summary;
+                       if (camel_folder_get_folder_summary (search->priv->folder))
+                               camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary 
(search->priv->folder), NULL);
+                       summary_set = search->priv->summary;
                }
 
                /* only re-parse if the search has changed */
-               if (search->last_search == NULL
-                   || strcmp (search->last_search, expr)) {
-                       camel_sexp_input_text (search->sexp, expr, strlen (expr));
-                       if (camel_sexp_parse (search->sexp) == -1) {
+               if (search->priv->last_search == NULL
+                   || strcmp (search->priv->last_search, expr)) {
+                       camel_sexp_input_text (search->priv->sexp, expr, strlen (expr));
+                       if (camel_sexp_parse (search->priv->sexp) == -1) {
                                g_set_error (
                                        error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                                        _("Cannot parse search expression: %s:\n%s"),
-                                       camel_sexp_error (search->sexp), expr);
+                                       camel_sexp_error (search->priv->sexp), expr);
                                goto fail;
                        }
 
-                       g_free (search->last_search);
-                       search->last_search = g_strdup (expr);
+                       g_free (search->priv->last_search);
+                       search->priv->last_search = g_strdup (expr);
                }
-               r = camel_sexp_eval (search->sexp);
+               r = camel_sexp_eval (search->priv->sexp);
                if (r == NULL) {
                        g_set_error (
                                error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                                _("Error executing search expression: %s:\n%s"),
-                               camel_sexp_error (search->sexp), expr);
+                               camel_sexp_error (search->priv->sexp), expr);
                        goto fail;
                }
 
@@ -2123,18 +2256,18 @@ camel_folder_search_search (CamelFolderSearch *search,
                        g_hash_table_destroy (results);
                }
 
-               camel_sexp_result_free (search->sexp, r);
+               camel_sexp_result_free (search->priv->sexp, r);
 
        } else {
                CamelStore *parent_store;
                const gchar *full_name;
                GError *local_error = NULL;
 
-               full_name = camel_folder_get_full_name (search->folder);
-               parent_store = camel_folder_get_parent_store (search->folder);
+               full_name = camel_folder_get_full_name (search->priv->folder);
+               parent_store = camel_folder_get_parent_store (search->priv->folder);
 
                /* Sync the db, so that we search the db for changes */
-               camel_folder_summary_save_to_db (search->folder->summary, error);
+               camel_folder_summary_save (camel_folder_get_folder_summary (search->priv->folder), error);
 
                dd (printf ("sexp is : [%s]\n", expr));
                tmp1 = camel_db_sqlize_string (full_name);
@@ -2144,7 +2277,7 @@ camel_folder_search_search (CamelFolderSearch *search,
                dd (printf ("Equivalent sql %s\n", tmp));
 
                matches = g_ptr_array_new ();
-               cdb = (CamelDB *) (parent_store->cdb_r);
+               cdb = camel_store_get_db (parent_store);
                camel_db_select (
                        cdb, tmp, (CamelDBSelectCB)
                        read_uid_callback, matches, &local_error);
@@ -2167,10 +2300,10 @@ fail:
                camel_folder_thread_messages_unref (p->threads);
        if (p->threads_hash)
                g_hash_table_destroy (p->threads_hash);
-       if (search->summary_set)
-               g_ptr_array_free (search->summary_set, TRUE);
-       if (search->summary)
-               camel_folder_free_summary (search->folder, search->summary);
+       if (search->priv->summary_set)
+               g_ptr_array_free (search->priv->summary_set, TRUE);
+       if (search->priv->summary)
+               camel_folder_free_summary (search->priv->folder, search->priv->summary);
 
        free_pstring_array (p->owned_pstrings);
        p->owned_pstrings = NULL;
@@ -2178,11 +2311,11 @@ fail:
        p->error = NULL;
        p->threads = NULL;
        p->threads_hash = NULL;
-       search->folder = NULL;
-       search->summary = NULL;
-       search->summary_set = NULL;
-       search->current = NULL;
-       search->body_index = NULL;
+       search->priv->folder = NULL;
+       search->priv->summary = NULL;
+       search->priv->summary_set = NULL;
+       search->priv->current = NULL;
+       search->priv->body_index = NULL;
 
        if (error && *error) {
                camel_folder_search_free_result (search, matches);
diff --git a/src/camel/camel-folder-search.h b/src/camel/camel-folder-search.h
index 7c88f68..fe86b8b 100644
--- a/src/camel/camel-folder-search.h
+++ b/src/camel/camel-folder-search.h
@@ -56,17 +56,6 @@ typedef struct _CamelFolderSearchPrivate CamelFolderSearchPrivate;
 struct _CamelFolderSearch {
        GObject parent;
        CamelFolderSearchPrivate *priv;
-
-       CamelSExp *sexp;                /* s-exp evaluator */
-       gchar *last_search;     /* last searched expression */
-
-       /* these are only valid during the search, and are reset afterwards */
-       CamelFolder *folder;    /* folder for current search */
-       GPtrArray *summary;     /* summary array for current search */
-       GPtrArray *summary_set; /* subset of summary to actually include in search */
-       CamelMessageInfo *current; /* current message info, when searching one by one */
-       CamelMimeMessage *current_message; /* cache of current message, if required */
-       CamelIndex *body_index;
 };
 
 struct _CamelFolderSearchClass {
@@ -263,18 +252,36 @@ struct _CamelFolderSearchClass {
                                                 gint argc,
                                                 CamelSExpResult **argv,
                                                 CamelFolderSearch *search);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_folder_search_get_type    (void) G_GNUC_CONST;
 CamelFolderSearch *
                camel_folder_search_new         (void);
+void           camel_folder_search_set_current_message_info
+                                               (CamelFolderSearch *search,
+                                                CamelMessageInfo *info);
+void           camel_folder_search_take_current_message_info
+                                               (CamelFolderSearch *search,
+                                                CamelMessageInfo *info);
+CamelMessageInfo *
+               camel_folder_search_get_current_message_info
+                                               (CamelFolderSearch *search);
+GPtrArray *    camel_folder_search_get_current_summary
+                                               (CamelFolderSearch *search);
 
 /* XXX This stuff currently gets cleared when you run a search.
  *     What on earth was i thinking ... */
 void           camel_folder_search_set_folder  (CamelFolderSearch *search,
                                                 CamelFolder *folder);
+CamelFolder *  camel_folder_search_get_folder  (CamelFolderSearch *search);
 void           camel_folder_search_set_summary (CamelFolderSearch *search,
                                                 GPtrArray *summary);
+GPtrArray *    camel_folder_search_get_summary (CamelFolderSearch *search);
+gboolean       camel_folder_search_get_summary_empty
+                                               (CamelFolderSearch *search);
 void           camel_folder_search_set_body_index
                                                (CamelFolderSearch *search,
                                                 CamelIndex *body_index);
@@ -296,10 +303,6 @@ time_t             camel_folder_search_util_add_months
                                                (time_t t,
                                                 gint months);
 
-#ifndef CAMEL_DISABLE_DEPRECATED
-void           camel_folder_search_construct   (CamelFolderSearch *search);
-#endif /* CAMEL_DISABLE_DEPRECATED */
-
 G_END_DECLS
 
 #endif /* CAMEL_FOLDER_SEARCH_H */
diff --git a/src/camel/camel-folder-summary.c b/src/camel/camel-folder-summary.c
index aec35e3..e7f0234 100644
--- a/src/camel/camel-folder-summary.c
+++ b/src/camel/camel-folder-summary.c
@@ -37,6 +37,8 @@
 #include "camel-folder-summary.h"
 #include "camel-folder.h"
 #include "camel-iconv.h"
+#include "camel-message-info.h"
+#include "camel-message-info-base.h"
 #include "camel-mime-filter-basic.h"
 #include "camel-mime-filter-charset.h"
 #include "camel-mime-filter-html.h"
@@ -63,6 +65,11 @@
 #define dd(x) if (camel_debug("sync")) x
 
 struct _CamelFolderSummaryPrivate {
+       /* header info */
+       guint32 version;        /* version of file loaded/loading */
+       gint64 timestamp;       /* timestamp for this summary (for implementors to use) */
+       CamelFolderSummaryFlags flags;
+
        GHashTable *filter_charset;     /* CamelMimeFilterCharset's indexed by source charset */
 
        struct _CamelMimeFilter *filter_index;
@@ -79,9 +86,6 @@ struct _CamelFolderSummaryPrivate {
        GRecMutex summary_lock; /* for the summary hashtable/array */
        GRecMutex filter_lock;  /* for accessing any of the filtering/indexing stuff, since we share them */
 
-       gboolean need_preview;
-       GHashTable *preview_updates;
-
        guint32 nextuid;        /* next uid? */
        guint32 saved_count;    /* how many were saved/loaded */
        guint32 unread_count;   /* handy totals */
@@ -90,8 +94,6 @@ struct _CamelFolderSummaryPrivate {
        guint32 junk_not_deleted_count;
        guint32 visible_count;
 
-       gboolean build_content; /* do we try and parse/index the content, or not? */
-
        GHashTable *uids; /* uids of all known message infos; the 'value' are used flags for the message info 
*/
        GHashTable *loaded_infos; /* uid->CamelMessageInfo *, those currently in memory */
 
@@ -116,27 +118,18 @@ struct _node {
 
 static void cfs_schedule_info_release_timer (CamelFolderSummary *summary);
 
-static struct _node *my_list_append (struct _node **list, struct _node *n);
-static gint my_list_size (struct _node **list);
+static void summary_traverse_content_with_parser (CamelFolderSummary *summary, CamelMessageInfo *msginfo, 
CamelMimeParser *mp);
+static void summary_traverse_content_with_part (CamelFolderSummary *summary, CamelMessageInfo *msginfo, 
CamelMimePart *object);
 
-static CamelMessageInfo * message_info_new_from_header (CamelFolderSummary *, struct _camel_header_raw *);
+static CamelMessageInfo * message_info_new_from_headers (CamelFolderSummary *, const CamelNameValueArray *);
 static CamelMessageInfo * message_info_new_from_parser (CamelFolderSummary *, CamelMimeParser *);
-static CamelMessageInfo * message_info_new_from_message (CamelFolderSummary *summary, CamelMimeMessage *msg, 
const gchar *bodystructure);
-static void              message_info_free (CamelFolderSummary *, CamelMessageInfo *);
-
-static CamelMessageContentInfo * content_info_new_from_header (CamelFolderSummary *, struct 
_camel_header_raw *);
-static CamelMessageContentInfo * content_info_new_from_parser (CamelFolderSummary *, CamelMimeParser *);
-static CamelMessageContentInfo * content_info_new_from_message (CamelFolderSummary *summary, CamelMimePart 
*mp);
-static void                     content_info_free (CamelFolderSummary *, CamelMessageContentInfo *);
+static CamelMessageInfo * message_info_new_from_message (CamelFolderSummary *summary, CamelMimeMessage *msg);
 
 static gint save_message_infos_to_db (CamelFolderSummary *summary, GError **error);
 static gint camel_read_mir_callback (gpointer  ref, gint ncol, gchar ** cols, gchar ** name);
 
 static gchar *next_uid_string (CamelFolderSummary *summary);
 
-static CamelMessageContentInfo * summary_build_content_info (CamelFolderSummary *summary, CamelMessageInfo 
*msginfo, CamelMimeParser *mp);
-static CamelMessageContentInfo * summary_build_content_info_message (CamelFolderSummary *summary, 
CamelMessageInfo *msginfo, CamelMimePart *object);
-
 static CamelMessageInfo * message_info_from_uid (CamelFolderSummary *summary, const gchar *uid);
 
 enum {
@@ -147,18 +140,11 @@ enum {
        PROP_DELETED_COUNT,
        PROP_JUNK_COUNT,
        PROP_JUNK_NOT_DELETED_COUNT,
-       PROP_VISIBLE_COUNT,
-       PROP_BUILD_CONTENT,
-       PROP_NEED_PREVIEW
+       PROP_VISIBLE_COUNT
 };
 
 G_DEFINE_TYPE (CamelFolderSummary, camel_folder_summary, G_TYPE_OBJECT)
 
-G_DEFINE_BOXED_TYPE (CamelMessageInfo,
-               camel_message_info,
-               camel_message_info_ref,
-               camel_message_info_unref)
-
 static gboolean
 remove_each_item (gpointer uid,
                   gpointer mi,
@@ -182,8 +168,7 @@ remove_all_loaded (CamelFolderSummary *summary)
 
        g_hash_table_foreach_remove (summary->priv->loaded_infos, remove_each_item, &to_remove_infos);
 
-       g_slist_foreach (to_remove_infos, (GFunc) camel_message_info_unref, NULL);
-       g_slist_free (to_remove_infos);
+       g_slist_free_full (to_remove_infos, g_object_unref);
 
        camel_folder_summary_unlock (summary);
 }
@@ -242,8 +227,6 @@ folder_summary_finalize (GObject *object)
        g_hash_table_foreach (priv->filter_charset, free_o_name, NULL);
        g_hash_table_destroy (priv->filter_charset);
 
-       g_hash_table_destroy (priv->preview_updates);
-
        g_rec_mutex_clear (&priv->summary_lock);
        g_rec_mutex_clear (&priv->filter_lock);
 
@@ -275,18 +258,6 @@ folder_summary_set_property (GObject *object,
                                CAMEL_FOLDER_SUMMARY (object),
                                CAMEL_FOLDER (g_value_get_object (value)));
                        return;
-
-               case PROP_BUILD_CONTENT:
-                       camel_folder_summary_set_build_content (
-                               CAMEL_FOLDER_SUMMARY (object),
-                               g_value_get_boolean (value));
-                       return;
-
-               case PROP_NEED_PREVIEW:
-                       camel_folder_summary_set_need_preview (
-                               CAMEL_FOLDER_SUMMARY (object),
-                               g_value_get_boolean (value));
-                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -347,20 +318,6 @@ folder_summary_get_property (GObject *object,
                                camel_folder_summary_get_visible_count (
                                CAMEL_FOLDER_SUMMARY (object)));
                        return;
-
-               case PROP_BUILD_CONTENT:
-                       g_value_set_boolean (
-                               value,
-                               camel_folder_summary_get_build_content (
-                               CAMEL_FOLDER_SUMMARY (object)));
-                       return;
-
-               case PROP_NEED_PREVIEW:
-                       g_value_set_boolean (
-                               value,
-                               camel_folder_summary_get_need_preview (
-                               CAMEL_FOLDER_SUMMARY (object)));
-                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -371,7 +328,7 @@ is_in_memory_summary (CamelFolderSummary *summary)
 {
        g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
 
-       return (summary->flags & CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY) != 0;
+       return (summary->priv->flags & CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY) != 0;
 }
 
 #define UPDATE_COUNTS_ADD              (1)
@@ -398,8 +355,8 @@ folder_summary_update_counts_by_flags (CamelFolderSummary *summary,
        if (summary->priv->folder && CAMEL_IS_VTRASH_FOLDER (summary->priv->folder)) {
                CamelVTrashFolder *vtrash = CAMEL_VTRASH_FOLDER (summary->priv->folder);
 
-               is_junk_folder = vtrash && vtrash->type == CAMEL_VTRASH_FOLDER_JUNK;
-               is_trash_folder = vtrash && vtrash->type == CAMEL_VTRASH_FOLDER_TRASH;
+               is_junk_folder = vtrash && camel_vtrash_folder_get_folder_type (vtrash) == 
CAMEL_VTRASH_FOLDER_JUNK;
+               is_trash_folder = vtrash && camel_vtrash_folder_get_folder_type (vtrash) == 
CAMEL_VTRASH_FOLDER_TRASH;
        }
 
        if (!(flags & CAMEL_MESSAGE_SEEN))
@@ -467,31 +424,31 @@ folder_summary_update_counts_by_flags (CamelFolderSummary *summary,
 }
 
 static gboolean
-summary_header_from_db (CamelFolderSummary *summary,
-                        CamelFIRecord *record)
+summary_header_load (CamelFolderSummary *summary,
+                    CamelFIRecord *record)
 {
        io (printf ("Loading header from db \n"));
 
-       summary->version = record->version;
+       summary->priv->version = record->version;
 
        /* We may not worry, as we are setting a new standard here */
 #if 0
        /* Legacy version check, before version 12 we have no upgrade knowledge */
-       if ((summary->version > 0xff) && (summary->version & 0xff) < 12) {
+       if ((summary->priv->version > 0xff) && (summary->priv->version & 0xff) < 12) {
                io (printf ("Summary header version mismatch"));
                errno = EINVAL;
                return FALSE;
        }
 
-       if (!(summary->version < 0x100 && summary->version >= 13))
+       if (!(summary->priv->version < 0x100 && summary->priv->version >= 13))
                io (printf ("Loading legacy summary\n"));
        else
                io (printf ("loading new-format summary\n"));
 #endif
 
-       summary->flags = record->flags;
+       summary->priv->flags = record->flags;
        summary->priv->nextuid = record->nextuid;
-       summary->time = record->time;
+       summary->priv->timestamp = record->timestamp;
        summary->priv->saved_count = record->saved_count;
 
        summary->priv->unread_count = record->unread_count;
@@ -504,19 +461,19 @@ summary_header_from_db (CamelFolderSummary *summary,
 }
 
 static CamelFIRecord *
-summary_header_to_db (CamelFolderSummary *summary,
-                      GError **error)
+summary_header_save (CamelFolderSummary *summary,
+                    GError **error)
 {
        CamelFIRecord *record = g_new0 (CamelFIRecord, 1);
        CamelStore *parent_store;
-       CamelDB *db;
+       CamelDB *cdb;
        const gchar *table_name;
 
        /* Though we are going to read, we do this during write,
         * so lets use it that way. */
        table_name = camel_folder_get_full_name (summary->priv->folder);
        parent_store = camel_folder_get_parent_store (summary->priv->folder);
-       db = parent_store ? parent_store->cdb_w : NULL;
+       cdb = parent_store ? camel_store_get_db (parent_store) : NULL;
 
        io (printf ("Savining header to db\n"));
 
@@ -524,23 +481,23 @@ summary_header_to_db (CamelFolderSummary *summary,
 
        /* we always write out the current version */
        record->version = CAMEL_FOLDER_SUMMARY_VERSION;
-       record->flags = summary->flags;
+       record->flags = summary->priv->flags;
        record->nextuid = summary->priv->nextuid;
-       record->time = summary->time;
+       record->timestamp = summary->priv->timestamp;
 
-       if (db && !is_in_memory_summary (summary)) {
+       if (cdb && !is_in_memory_summary (summary)) {
                /* FIXME: Ever heard of Constructors and initializing ? */
-               if (camel_db_count_total_message_info (db, table_name, &(record->saved_count), NULL))
+               if (camel_db_count_total_message_info (cdb, table_name, &(record->saved_count), NULL))
                        record->saved_count = 0;
-               if (camel_db_count_junk_message_info (db, table_name, &(record->junk_count), NULL))
+               if (camel_db_count_junk_message_info (cdb, table_name, &(record->junk_count), NULL))
                        record->junk_count = 0;
-               if (camel_db_count_deleted_message_info (db, table_name, &(record->deleted_count), NULL))
+               if (camel_db_count_deleted_message_info (cdb, table_name, &(record->deleted_count), NULL))
                        record->deleted_count = 0;
-               if (camel_db_count_unread_message_info (db, table_name, &(record->unread_count), NULL))
+               if (camel_db_count_unread_message_info (cdb, table_name, &(record->unread_count), NULL))
                        record->unread_count = 0;
-               if (camel_db_count_visible_message_info (db, table_name, &(record->visible_count), NULL))
+               if (camel_db_count_visible_message_info (cdb, table_name, &(record->visible_count), NULL))
                        record->visible_count = 0;
-               if (camel_db_count_junk_not_deleted_message_info (db, table_name, &(record->jnd_count), NULL))
+               if (camel_db_count_junk_not_deleted_message_info (cdb, table_name, &(record->jnd_count), 
NULL))
                        record->jnd_count = 0;
        }
 
@@ -553,282 +510,6 @@ summary_header_to_db (CamelFolderSummary *summary,
        return record;
 }
 
-static CamelMessageInfo *
-message_info_from_db (CamelFolderSummary *summary,
-                      CamelMIRecord *record)
-{
-       CamelMessageInfoBase *mi;
-       gint i;
-       gint count;
-       gchar *part, *label;
-
-       mi = (CamelMessageInfoBase *) camel_message_info_new (summary);
-
-       io (printf ("Loading message info from db\n"));
-
-       mi->flags = record->flags;
-       mi->size = record->size;
-       mi->date_sent = record->dsent;
-       mi->date_received = record->dreceived;
-
-       mi->uid = (gchar *) camel_pstring_strdup (record->uid);
-       mi->subject = (gchar *) camel_pstring_add (record->subject, FALSE);
-       mi->from = (gchar *) camel_pstring_add (record->from, FALSE);
-       mi->to = (gchar *) camel_pstring_add (record->to, FALSE);
-       mi->cc = (gchar *) camel_pstring_add (record->cc, FALSE);
-       mi->mlist = (gchar *) camel_pstring_add (record->mlist, FALSE);
-
-       /* Evolution itself doesn't yet use this, so we ignore it (saving some memory) */
-       mi->bodystructure = NULL;
-
-       /* Extract Message id & References */
-       mi->content = NULL;
-       part = record->part;
-       if (part) {
-               mi->message_id.id.part.hi = bdata_extract_digit (&part);
-               mi->message_id.id.part.lo = bdata_extract_digit (&part);
-               count = bdata_extract_digit (&part);
-
-               if (count > 0) {
-                       mi->references = g_malloc (sizeof (*mi->references) + ((count - 1) * sizeof 
(mi->references->references[0])));
-                       mi->references->size = count;
-                       for (i = 0; i < count; i++) {
-                               mi->references->references[i].id.part.hi = bdata_extract_digit (&part);
-                               mi->references->references[i].id.part.lo = bdata_extract_digit (&part);
-                       }
-               } else
-                       mi->references = NULL;
-
-       }
-
-       /* Extract User flags/labels */
-       part = record->labels;
-       if (part) {
-               label = part;
-               for (i = 0; part[i]; i++) {
-
-                       if (part[i] == ' ') {
-                               part[i] = 0;
-                               camel_flag_set (&mi->user_flags, label, TRUE);
-                               label = &(part[i + 1]);
-                       }
-               }
-               camel_flag_set (&mi->user_flags, label, TRUE);
-       }
-
-       /* Extract User tags */
-       part = record->usertags;
-       count = bdata_extract_digit (&part);
-       for (i = 0; i < count; i++) {
-               gchar *name, *value;
-
-               name = bdata_extract_string (&part);
-               value = bdata_extract_string (&part);
-               camel_tag_set (&mi->user_tags, name, value);
-
-               g_free (name);
-               g_free (value);
-       }
-
-       return (CamelMessageInfo *) mi;
-}
-
-static CamelMIRecord *
-message_info_to_db (CamelFolderSummary *summary,
-                    CamelMessageInfo *info)
-{
-       CamelMIRecord *record = g_new0 (CamelMIRecord, 1);
-       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
-       GString *tmp;
-       CamelFlag *flag;
-       CamelTag *tag;
-       gint count, i;
-
-       /* Assume that we dont have to take care of DB Safeness. It will be done while doing the DB 
transaction */
-       record->uid = (gchar *) camel_pstring_strdup (camel_message_info_get_uid (info));
-       record->flags = mi->flags;
-
-       record->read = ((mi->flags & (CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_JUNK))) ? 1 
: 0;
-       record->deleted = mi->flags & CAMEL_MESSAGE_DELETED ? 1 : 0;
-       record->replied = mi->flags & CAMEL_MESSAGE_ANSWERED ? 1 : 0;
-       record->important = mi->flags & CAMEL_MESSAGE_FLAGGED ? 1 : 0;
-       record->junk = mi->flags & CAMEL_MESSAGE_JUNK ? 1 : 0;
-       record->dirty = mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED ? 1 : 0;
-       record->attachment = mi->flags & CAMEL_MESSAGE_ATTACHMENTS ? 1 : 0;
-
-       record->size = mi->size;
-       record->dsent = mi->date_sent;
-       record->dreceived = mi->date_received;
-
-       record->subject = (gchar *) camel_pstring_strdup (camel_message_info_get_subject (info));
-       record->from = (gchar *) camel_pstring_strdup (camel_message_info_get_from (info));
-       record->to = (gchar *) camel_pstring_strdup (camel_message_info_get_to (info));
-       record->cc = (gchar *) camel_pstring_strdup (camel_message_info_get_cc (info));
-       record->mlist = (gchar *) camel_pstring_strdup (camel_message_info_get_mlist (info));
-
-       record->followup_flag = (gchar *) camel_pstring_strdup (camel_message_info_get_user_tag (info, 
"follow-up"));
-       record->followup_completed_on = (gchar *) camel_pstring_strdup (camel_message_info_get_user_tag 
(info, "completed-on"));
-       record->followup_due_by = (gchar *) camel_pstring_strdup (camel_message_info_get_user_tag (info, 
"due-by"));
-
-       record->bodystructure = mi->bodystructure ? g_strdup (mi->bodystructure) : NULL;
-
-       tmp = g_string_new (NULL);
-       if (mi->references) {
-               g_string_append_printf (tmp, "%lu %lu %lu", (gulong) mi->message_id.id.part.hi, (gulong) 
mi->message_id.id.part.lo, (gulong) mi->references->size);
-               for (i = 0; i < mi->references->size; i++)
-                       g_string_append_printf (tmp, " %lu %lu", (gulong) 
mi->references->references[i].id.part.hi, (gulong) mi->references->references[i].id.part.lo);
-       } else {
-               g_string_append_printf (tmp, "%lu %lu %lu", (gulong) mi->message_id.id.part.hi, (gulong) 
mi->message_id.id.part.lo, (gulong) 0);
-       }
-       record->part = tmp->str;
-       g_string_free (tmp, FALSE);
-
-       tmp = g_string_new (NULL);
-       flag = mi->user_flags;
-       while (flag) {
-               g_string_append_printf (tmp, "%s ", flag->name);
-               flag = flag->next;
-       }
-
-       /* Strip off the last space */
-       if (tmp->len)
-               tmp->len--;
-
-       record->labels = tmp->str;
-       g_string_free (tmp, FALSE);
-
-       tmp = g_string_new (NULL);
-       count = camel_tag_list_size (&mi->user_tags);
-       g_string_append_printf (tmp, "%lu", (gulong) count);
-       tag = mi->user_tags;
-       while (tag) {
-               /* FIXME: Should we handle empty tags? Can it be empty? If it potential crasher ahead*/
-               g_string_append_printf (tmp, " %lu-%s %lu-%s", (gulong) strlen (tag->name), tag->name, 
(gulong) strlen (tag->value), tag->value);
-               tag = tag->next;
-       }
-       record->usertags = tmp->str;
-       g_string_free (tmp, FALSE);
-
-       return record;
-}
-
-static CamelMessageContentInfo *
-content_info_from_db (CamelFolderSummary *summary,
-                      CamelMIRecord *record)
-{
-       CamelMessageContentInfo *ci;
-       gchar *type, *subtype;
-       guint32 count, i;
-       CamelContentType *ct;
-       gchar *part = record->cinfo;
-
-       io (printf ("Loading content info from db\n"));
-
-       if (!part)
-               return NULL;
-
-       ci = camel_folder_summary_content_info_new (summary);
-       if (*part == ' ') part++; /* Move off the space in the record */
-
-       type = bdata_extract_string (&part);
-       subtype = bdata_extract_string (&part);
-       ct = camel_content_type_new (type, subtype);
-       g_free (type);          /* can this be removed? */
-       g_free (subtype);
-       count = bdata_extract_digit (&part);
-
-       for (i = 0; i < count; i++) {
-               gchar *name, *value;
-               name = bdata_extract_string (&part);
-               value = bdata_extract_string (&part);
-
-               camel_content_type_set_param (ct, name, value);
-               /* TODO: do this so we dont have to double alloc/free */
-               g_free (name);
-               g_free (value);
-       }
-       ci->type = ct;
-
-       /* FIXME[disk-summary] move all these to camel pstring */
-       ci->id = bdata_extract_string (&part);
-       ci->description = bdata_extract_string (&part);
-       ci->encoding = bdata_extract_string (&part);
-       ci->size = bdata_extract_digit (&part);
-
-       record->cinfo = part; /* Keep moving the cursor in the record */
-
-       ci->childs = NULL;
-
-       return ci;
-}
-
-static gboolean
-content_info_to_db (CamelFolderSummary *summary,
-                    CamelMessageContentInfo *ci,
-                    CamelMIRecord *record)
-{
-       CamelContentType *ct;
-       struct _camel_header_param *hp;
-       GString *str = g_string_new (NULL);
-       gchar *oldr;
-
-       io (printf ("Saving content info to db\n"));
-
-       ct = ci->type;
-       if (ct) {
-               if (ct->type)
-                       g_string_append_printf (str, " %d-%s", (gint) strlen (ct->type), ct->type);
-               else
-                       g_string_append_printf (str, " 0-");
-               if (ct->subtype)
-                       g_string_append_printf (str, " %d-%s", (gint) strlen (ct->subtype), ct->subtype);
-               else
-                       g_string_append_printf (str, " 0-");
-               g_string_append_printf (str, " %d", my_list_size ((struct _node **) &ct->params));
-               hp = ct->params;
-               while (hp) {
-                       if (hp->name)
-                               g_string_append_printf (str, " %d-%s", (gint) strlen (hp->name), hp->name);
-                       else
-                               g_string_append_printf (str, " 0-");
-                       if (hp->value)
-                               g_string_append_printf (str, " %d-%s", (gint) strlen (hp->value), hp->value);
-                       else
-                               g_string_append_printf (str, " 0-");
-                       hp = hp->next;
-               }
-       } else {
-               g_string_append_printf (str, " %d-", 0);
-               g_string_append_printf (str, " %d-", 0);
-               g_string_append_printf (str, " %d", 0);
-       }
-
-       if (ci->id)
-               g_string_append_printf (str, " %d-%s", (gint) strlen (ci->id), ci->id);
-       else
-               g_string_append_printf (str, " 0-");
-       if (ci->description)
-               g_string_append_printf (str, " %d-%s", (gint) strlen (ci->description), ci->description);
-       else
-               g_string_append_printf (str, " 0-");
-       if (ci->encoding)
-               g_string_append_printf (str, " %d-%s", (gint) strlen (ci->encoding), ci->encoding);
-       else
-               g_string_append_printf (str, " 0-");
-       g_string_append_printf (str, " %u", ci->size);
-
-       if (record->cinfo) {
-               oldr = record->cinfo;
-               record->cinfo = g_strconcat (oldr, str->str, NULL);
-               g_free (oldr); g_string_free (str, TRUE);
-       } else {
-               record->cinfo = str->str;
-               g_string_free (str, FALSE);
-       }
-
-       return TRUE;
-}
-
 /**
  * camel_folder_summary_replace_flags:
  * @summary: a #CamelFolderSummary
@@ -873,8 +554,8 @@ camel_folder_summary_replace_flags (CamelFolderSummary *summary,
        if (summary->priv->folder && CAMEL_IS_VTRASH_FOLDER (summary->priv->folder)) {
                CamelVTrashFolder *vtrash = CAMEL_VTRASH_FOLDER (summary->priv->folder);
 
-               is_junk_folder = vtrash && vtrash->type == CAMEL_VTRASH_FOLDER_JUNK;
-               is_trash_folder = vtrash && vtrash->type == CAMEL_VTRASH_FOLDER_TRASH;
+               is_junk_folder = vtrash && camel_vtrash_folder_get_folder_type (vtrash) == 
CAMEL_VTRASH_FOLDER_JUNK;
+               is_trash_folder = vtrash && camel_vtrash_folder_get_folder_type (vtrash) == 
CAMEL_VTRASH_FOLDER_TRASH;
        }
 
        added_flags = new_flags & (~(old_flags & new_flags));
@@ -915,231 +596,6 @@ camel_folder_summary_replace_flags (CamelFolderSummary *summary,
        return changed;
 }
 
-static CamelMessageInfo *
-message_info_clone (CamelFolderSummary *summary,
-                    const CamelMessageInfo *mi)
-{
-       CamelMessageInfoBase *to, *from = (CamelMessageInfoBase *) mi;
-       CamelFlag *flag;
-       CamelTag *tag;
-
-       to = (CamelMessageInfoBase *) camel_message_info_new (summary);
-
-       to->flags = from->flags;
-       to->size = from->size;
-       to->date_sent = from->date_sent;
-       to->date_received = from->date_received;
-       to->refcount = 1;
-
-       /* NB: We don't clone the uid */
-
-       to->subject = camel_pstring_strdup (from->subject);
-       to->from = camel_pstring_strdup (from->from);
-       to->to = camel_pstring_strdup (from->to);
-       to->cc = camel_pstring_strdup (from->cc);
-       to->mlist = camel_pstring_strdup (from->mlist);
-       memcpy (&to->message_id, &from->message_id, sizeof (to->message_id));
-       to->preview = g_strdup (from->preview);
-       if (from->references) {
-               gint len = sizeof (*from->references) + ((from->references->size - 1) * sizeof 
(from->references->references[0]));
-
-               to->references = g_malloc (len);
-               memcpy (to->references, from->references, len);
-       }
-
-       flag = from->user_flags;
-       while (flag) {
-               camel_flag_set (&to->user_flags, flag->name, TRUE);
-               flag = flag->next;
-       }
-
-       tag = from->user_tags;
-       while (tag) {
-               camel_tag_set (&to->user_tags, tag->name, tag->value);
-               tag = tag->next;
-       }
-
-       if (from->content) {
-               /* FIXME: copy content-infos */
-       }
-
-       return (CamelMessageInfo *) to;
-}
-
-static gconstpointer
-info_ptr (const CamelMessageInfo *mi,
-          gint id)
-{
-       switch (id) {
-               case CAMEL_MESSAGE_INFO_SUBJECT:
-                       return ((const CamelMessageInfoBase *) mi)->subject;
-               case CAMEL_MESSAGE_INFO_FROM:
-                       return ((const CamelMessageInfoBase *) mi)->from;
-               case CAMEL_MESSAGE_INFO_TO:
-                       return ((const CamelMessageInfoBase *) mi)->to;
-               case CAMEL_MESSAGE_INFO_CC:
-                       return ((const CamelMessageInfoBase *) mi)->cc;
-               case CAMEL_MESSAGE_INFO_MLIST:
-                       return ((const CamelMessageInfoBase *) mi)->mlist;
-               case CAMEL_MESSAGE_INFO_MESSAGE_ID:
-                       return &((const CamelMessageInfoBase *) mi)->message_id;
-               case CAMEL_MESSAGE_INFO_REFERENCES:
-                       return ((const CamelMessageInfoBase *) mi)->references;
-               case CAMEL_MESSAGE_INFO_USER_FLAGS:
-                       return ((const CamelMessageInfoBase *) mi)->user_flags;
-               case CAMEL_MESSAGE_INFO_USER_TAGS:
-                       return ((const CamelMessageInfoBase *) mi)->user_tags;
-               case CAMEL_MESSAGE_INFO_HEADERS:
-                       return ((const CamelMessageInfoBase *) mi)->headers;
-               case CAMEL_MESSAGE_INFO_CONTENT:
-                       return ((const CamelMessageInfoBase *) mi)->content;
-               case CAMEL_MESSAGE_INFO_PREVIEW:
-                       return ((const CamelMessageInfoBase *) mi)->preview;
-               default:
-                       g_return_val_if_reached (NULL);
-       }
-}
-
-static guint32
-info_uint32 (const CamelMessageInfo *mi,
-             gint id)
-{
-       switch (id) {
-               case CAMEL_MESSAGE_INFO_FLAGS:
-                       return ((const CamelMessageInfoBase *) mi)->flags;
-               case CAMEL_MESSAGE_INFO_SIZE:
-                       return ((const CamelMessageInfoBase *) mi)->size;
-               default:
-                       g_return_val_if_reached (0);
-       }
-}
-
-static time_t
-info_time (const CamelMessageInfo *mi,
-           gint id)
-{
-       switch (id) {
-               case CAMEL_MESSAGE_INFO_DATE_SENT:
-                       return ((const CamelMessageInfoBase *) mi)->date_sent;
-               case CAMEL_MESSAGE_INFO_DATE_RECEIVED:
-                       return ((const CamelMessageInfoBase *) mi)->date_received;
-               default:
-                       g_return_val_if_reached (0);
-       }
-}
-
-static gboolean
-info_user_flag (const CamelMessageInfo *mi,
-                const gchar *id)
-{
-       return camel_flag_get (&((CamelMessageInfoBase *) mi)->user_flags, id);
-}
-
-static const gchar *
-info_user_tag (const CamelMessageInfo *mi,
-               const gchar *id)
-{
-       return camel_tag_get (&((CamelMessageInfoBase *) mi)->user_tags, id);
-}
-
-static gboolean
-info_set_user_flag (CamelMessageInfo *info,
-                    const gchar *name,
-                    gboolean value)
-{
-       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
-       gint res;
-
-       res = camel_flag_set (&mi->user_flags, name, value);
-
-       if (mi->summary && res && mi->summary->priv->folder && mi->uid
-           && camel_folder_summary_check_uid (mi->summary, mi->uid)) {
-               CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
-
-               mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
-               mi->dirty = TRUE;
-               camel_folder_summary_touch (mi->summary);
-               camel_folder_change_info_change_uid (changes, camel_message_info_get_uid (info));
-               camel_folder_changed (mi->summary->priv->folder, changes);
-               camel_folder_change_info_free (changes);
-       }
-
-       return res;
-}
-
-static gboolean
-info_set_user_tag (CamelMessageInfo *info,
-                   const gchar *name,
-                   const gchar *value)
-{
-       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
-       gint res;
-
-       res = camel_tag_set (&mi->user_tags, name, value);
-
-       if (mi->summary && res && mi->summary->priv->folder && mi->uid
-           && camel_folder_summary_check_uid (mi->summary, mi->uid)) {
-               CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
-
-               mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
-               mi->dirty = TRUE;
-               camel_folder_summary_touch (mi->summary);
-               camel_folder_change_info_change_uid (changes, camel_message_info_get_uid (info));
-               camel_folder_changed (mi->summary->priv->folder, changes);
-               camel_folder_change_info_free (changes);
-       }
-
-       return res;
-}
-
-static gboolean
-info_set_flags (CamelMessageInfo *info,
-                guint32 flags,
-                guint32 set)
-{
-       guint32 old;
-       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
-       gboolean counts_changed = FALSE;
-
-       old = camel_message_info_get_flags (info);
-       mi->flags = (old & ~flags) | (set & flags);
-       if (old != mi->flags) {
-               mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
-               mi->dirty = TRUE;
-               if (mi->summary)
-                       camel_folder_summary_touch (mi->summary);
-       }
-
-       if (mi->summary) {
-               camel_folder_summary_lock (mi->summary);
-               g_object_freeze_notify (G_OBJECT (mi->summary));
-               counts_changed = camel_folder_summary_replace_flags (mi->summary, info);
-       }
-
-       if (!counts_changed && ((old & ~CAMEL_MESSAGE_SYSTEM_MASK) == (mi->flags & 
~CAMEL_MESSAGE_SYSTEM_MASK)) && !((set & CAMEL_MESSAGE_JUNK_LEARN) && !(set & CAMEL_MESSAGE_JUNK))) {
-               if (mi->summary) {
-                       g_object_thaw_notify (G_OBJECT (mi->summary));
-                       camel_folder_summary_unlock (mi->summary);
-               }
-               return FALSE;
-       }
-
-       if (mi->summary) {
-               g_object_thaw_notify (G_OBJECT (mi->summary));
-               camel_folder_summary_unlock (mi->summary);
-       }
-
-       if (mi->summary && mi->summary->priv->folder && mi->uid) {
-               CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
-
-               camel_folder_change_info_change_uid (changes, camel_message_info_get_uid (info));
-               camel_folder_changed (mi->summary->priv->folder, changes);
-               camel_folder_change_info_free (changes);
-       }
-
-       return TRUE;
-}
-
 static void
 camel_folder_summary_class_init (CamelFolderSummaryClass *class)
 {
@@ -1153,41 +609,18 @@ camel_folder_summary_class_init (CamelFolderSummaryClass *class)
        object_class->dispose = folder_summary_dispose;
        object_class->finalize = folder_summary_finalize;
 
-       class->message_info_size = sizeof (CamelMessageInfoBase);
-       class->content_info_size = sizeof (CamelMessageContentInfo);
+       class->message_info_type = CAMEL_TYPE_MESSAGE_INFO_BASE;
 
-       class->summary_header_from_db = summary_header_from_db;
-       class->summary_header_to_db = summary_header_to_db;
-       class->message_info_from_db = message_info_from_db;
-       class->message_info_to_db = message_info_to_db;
-       class->content_info_from_db = content_info_from_db;
-       class->content_info_to_db = content_info_to_db;
+       class->summary_header_load = summary_header_load;
+       class->summary_header_save = summary_header_save;
 
-       class->message_info_new_from_header = message_info_new_from_header;
+       class->message_info_new_from_headers = message_info_new_from_headers;
        class->message_info_new_from_parser = message_info_new_from_parser;
        class->message_info_new_from_message = message_info_new_from_message;
-       class->message_info_free = message_info_free;
-       class->message_info_clone = message_info_clone;
        class->message_info_from_uid = message_info_from_uid;
 
-       class->content_info_new_from_header = content_info_new_from_header;
-       class->content_info_new_from_parser = content_info_new_from_parser;
-       class->content_info_new_from_message = content_info_new_from_message;
-       class->content_info_free = content_info_free;
-
        class->next_uid_string = next_uid_string;
 
-       class->info_ptr = info_ptr;
-       class->info_uint32 = info_uint32;
-       class->info_time = info_time;
-       class->info_user_flag = info_user_flag;
-       class->info_user_tag = info_user_tag;
-
-       class->info_set_user_flag = info_set_user_flag;
-       class->info_set_user_tag = info_set_user_tag;
-
-       class->info_set_flags = info_set_flags;
-
        /**
         * CamelFolderSummary:folder
         *
@@ -1293,35 +726,6 @@ camel_folder_summary_class_init (CamelFolderSummaryClass *class)
                        "How many visible (not deleted and not junk) infos is saved in a summary",
                        0,  G_MAXUINT32,
                        0, G_PARAM_READABLE));
-
-       /**
-        * CamelFolderSummary:build-content
-        *
-        * Whether to build CamelMessageInfo.content.
-        **/
-       g_object_class_install_property (
-               object_class,
-               PROP_BUILD_CONTENT,
-               g_param_spec_boolean (
-                       "build-content",
-                       "Build content",
-                       "Whether to build CamelMessageInfo.content",
-                       FALSE,
-                       G_PARAM_READWRITE));
-
-       /**
-        * CamelFolderSummary:need-preview
-        *
-        **/
-       g_object_class_install_property (
-               object_class,
-               PROP_NEED_PREVIEW,
-               g_param_spec_boolean (
-                       "need-preview",
-                       "Need preview",
-                       "",
-                       FALSE,
-                       G_PARAM_READWRITE));
 }
 
 static void
@@ -1329,16 +733,13 @@ camel_folder_summary_init (CamelFolderSummary *summary)
 {
        summary->priv = CAMEL_FOLDER_SUMMARY_GET_PRIVATE (summary);
 
-       summary->version = CAMEL_FOLDER_SUMMARY_VERSION;
-       summary->flags = 0;
-       summary->time = 0;
+       summary->priv->version = CAMEL_FOLDER_SUMMARY_VERSION;
+       summary->priv->flags = 0;
+       summary->priv->timestamp = 0;
 
        summary->priv->filter_charset = g_hash_table_new (
                camel_strcase_hash, camel_strcase_equal);
 
-       summary->priv->need_preview = FALSE;
-       summary->priv->preview_updates = g_hash_table_new (g_str_hash, g_str_equal);
-
        summary->priv->nextuid = 1;
        summary->priv->uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) 
camel_pstring_free, NULL);
        summary->priv->loaded_infos = g_hash_table_new (g_str_hash, g_str_equal);
@@ -1352,7 +753,7 @@ camel_folder_summary_init (CamelFolderSummary *summary)
 
 /**
  * camel_folder_summary_new:
- * @folder: parent #CamelFolder object
+ * @folder: (type CamelFolder): parent #CamelFolder object
  *
  * Create a new #CamelFolderSummary object.
  *
@@ -1381,6 +782,109 @@ camel_folder_summary_get_folder (CamelFolderSummary *summary)
 }
 
 /**
+ * camel_folder_summary_get_flags:
+ * @summary: a #CamelFolderSummary
+ *
+ * Returns: flags of the @summary, a bit-or of #CamelFolderSummaryFlags
+ *
+ * Since: 3.24
+ **/
+guint32
+camel_folder_summary_get_flags (CamelFolderSummary *summary)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), 0);
+
+       return summary->priv->flags;
+}
+
+/**
+ * camel_folder_summary_set_flags:
+ * @summary: a #CamelFolderSummary
+ * @flags: flags to set
+ *
+ * Sets flags of the @summary, a bit-or of #CamelFolderSummaryFlags.
+ *
+ * Since: 3.24
+ **/
+void
+camel_folder_summary_set_flags (CamelFolderSummary *summary,
+                               guint32 flags)
+{
+       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
+
+       summary->priv->flags = flags;
+}
+
+/**
+ * camel_folder_summary_get_timestamp:
+ * @summary: a #CamelFolderSummary
+ *
+ * Returns: timestamp of the @summary, as set by the descendants
+ *
+ * Since: 3.24
+ **/
+gint64
+camel_folder_summary_get_timestamp (CamelFolderSummary *summary)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), 0);
+
+       return summary->priv->timestamp;
+}
+
+/**
+ * camel_folder_summary_set_timestamp:
+ * @summary: a #CamelFolderSummary
+ * @timestamp: a timestamp to set
+ *
+ * Sets timestamp of the @summary, provided by the descendants. This doesn't
+ * change the 'dirty' flag of the @summary.
+ *
+ * Since: 3.24
+ **/
+void
+camel_folder_summary_set_timestamp (CamelFolderSummary *summary,
+                                   gint64 timestamp)
+{
+       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
+
+       summary->priv->timestamp = timestamp;
+}
+
+/**
+ * camel_folder_summary_get_version:
+ * @summary: a #CamelFolderSummary
+ *
+ * Returns: version of the @summary
+ *
+ * Since: 3.24
+ **/
+guint32
+camel_folder_summary_get_version (CamelFolderSummary *summary)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), 0);
+
+       return summary->priv->version;
+}
+
+/**
+ * camel_folder_summary_set_version:
+ * @summary: a #CamelFolderSummary
+ * @version: version to set
+ *
+ * Sets version of the @summary.
+ *
+ * Since: 3.24
+ **/
+void
+camel_folder_summary_set_version (CamelFolderSummary *summary,
+                                 guint32 version)
+{
+       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
+
+       summary->priv->version = version;
+}
+
+/**
  * camel_folder_summary_get_saved_count:
  * @summary: a #CamelFolderSummary object
  *
@@ -1483,8 +987,6 @@ camel_folder_summary_get_visible_count (CamelFolderSummary *summary)
  *
  * Set the index used to index body content.  If the index is %NULL, or
  * not set (the default), no indexing of body content will take place.
- *
- * Unlike earlier behaviour, build_content need not be set to perform indexing.
  **/
 void
 camel_folder_summary_set_index (CamelFolderSummary *summary,
@@ -1518,72 +1020,6 @@ camel_folder_summary_get_index (CamelFolderSummary *summary)
 }
 
 /**
- * camel_folder_summary_set_build_content:
- * @summary: a #CamelFolderSummary object
- * @state: to build or not to build the content
- *
- * Set a flag to tell the summary to build the content info summary
- * (#CamelMessageInfo.content).  The default is not to build content
- * info summaries.
- **/
-void
-camel_folder_summary_set_build_content (CamelFolderSummary *summary,
-                                        gboolean state)
-{
-       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
-
-       if (summary->priv->build_content == state)
-               return;
-
-       summary->priv->build_content = state;
-
-       g_object_notify (G_OBJECT (summary), "build-content");
-}
-
-/**
- * camel_folder_summary_get_build_content:
- * @summary: a #CamelFolderSummary object
- *
- * Returns: Whether to build #CamelMessageInfo.content.
- *
- * Since: 3.4
- **/
-gboolean
-camel_folder_summary_get_build_content (CamelFolderSummary *summary)
-{
-       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
-
-       return summary->priv->build_content;
-}
-
-/**
- * camel_folder_summary_set_need_preview:
- *
- * Since: 2.28
- **/
-void
-camel_folder_summary_set_need_preview (CamelFolderSummary *summary,
-                                       gboolean preview)
-{
-       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
-
-       summary->priv->need_preview = preview;
-}
-
-/**
- * camel_folder_summary_get_need_preview:
- *
- * Since: 2.28
- **/
-gboolean
-camel_folder_summary_get_need_preview (CamelFolderSummary *summary)
-{
-       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
-
-       return summary->priv->need_preview;
-}
-
-/**
  * camel_folder_summary_next_uid:
  * @summary: a #CamelFolderSummary object
  *
@@ -1824,6 +1260,7 @@ camel_folder_summary_get_hash (CamelFolderSummary *summary)
 /**
  * camel_folder_summary_peek_loaded:
  *
+ * Returns: (nullable) (transfer full):
  * Since: 2.26
  **/
 CamelMessageInfo *
@@ -1837,7 +1274,7 @@ camel_folder_summary_peek_loaded (CamelFolderSummary *summary,
        info = g_hash_table_lookup (summary->priv->loaded_infos, uid);
 
        if (info)
-               camel_message_info_ref (info);
+               g_object_ref (info);
 
        return info;
 }
@@ -1882,7 +1319,7 @@ message_info_from_uid (CamelFolderSummary *summary,
                        return NULL;
                }
 
-               cdb = parent_store->cdb_r;
+               cdb = camel_store_get_db (parent_store);
 
                data.columns_hash = NULL;
                data.summary = summary;
@@ -1906,7 +1343,7 @@ message_info_from_uid (CamelFolderSummary *summary,
        }
 
        if (info)
-               camel_message_info_ref (info);
+               g_object_ref (info);
 
        camel_folder_summary_unlock (summary);
 
@@ -1923,7 +1360,7 @@ message_info_from_uid (CamelFolderSummary *summary,
  * A referenced to the summary item is returned, which may be
  * ref'd or free'd as appropriate.
  *
- * Returns: the summary item, or %NULL if the uid @uid is not available
+ * Returns: (nullable) (transfer full): the summary item, or %NULL if the uid @uid is not available
  *
  * See camel_folder_summary_get_info_flags().
  *
@@ -1978,49 +1415,16 @@ camel_folder_summary_get_info_flags (CamelFolderSummary *summary,
        return GPOINTER_TO_UINT (ptr_flags);
 }
 
-static CamelMessageContentInfo *
-perform_content_info_load_from_db (CamelFolderSummary *summary,
-                                   CamelMIRecord *mir)
-{
-       gint i;
-       guint32 count;
-       CamelMessageContentInfo *ci, *pci;
-       gchar *part;
-
-       ci = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->content_info_from_db (summary, mir);
-       if (ci == NULL)
-               return NULL;
-       part = mir->cinfo;
-       if (!part)
-               return ci;
-       if (*part == ' ') part++;
-       count = bdata_extract_digit (&part);
-
-       mir->cinfo = part;
-       for (i = 0; i < count; i++) {
-               pci = perform_content_info_load_from_db (summary, mir);
-               if (pci ) {
-                       my_list_append ((struct _node **) &ci->childs, (struct _node *) pci);
-                       pci->parent = ci;
-               } else {
-                       d (fprintf (stderr, "Summary file format messed up?"));
-                       camel_folder_summary_content_info_free (summary, ci);
-                       return NULL;
-               }
-       }
-       return ci;
-}
-
 static void
 gather_dirty_or_flagged_uids (gpointer key,
                              gpointer value,
                              gpointer user_data)
 {
        const gchar *uid = key;
-       CamelMessageInfoBase *info = value;
+       CamelMessageInfo *info = value;
        GHashTable *hash = user_data;
 
-       if (info->dirty || (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0)
+       if (camel_message_info_get_dirty (info) || (camel_message_info_get_flags (info) & 
CAMEL_MESSAGE_FOLDER_FLAGGED) != 0)
                g_hash_table_insert (hash, (gpointer) camel_pstring_strdup (uid), GINT_TO_POINTER (1));
 }
 
@@ -2067,10 +1471,10 @@ camel_folder_summary_get_changed (CamelFolderSummary *summary)
 
 static void
 count_changed_uids (gchar *key,
-                    CamelMessageInfoBase *info,
+                    CamelMessageInfo *info,
                     gint *count)
 {
-       if (info->dirty)
+       if (camel_message_info_get_dirty (info))
                (*count)++;
 }
 
@@ -2088,10 +1492,10 @@ cfs_count_dirty (CamelFolderSummary *summary)
 
 static gboolean
 remove_item (gchar *uid,
-             CamelMessageInfoBase *info,
+             CamelMessageInfo *info,
              GSList **to_remove_infos)
 {
-       if (info->refcount == 1 && !info->dirty && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) == 0) {
+       if (G_OBJECT (info)->ref_count == 1 && !camel_message_info_get_dirty (info) && 
(camel_message_info_get_flags (info) & CAMEL_MESSAGE_FOLDER_FLAGGED) == 0) {
                *to_remove_infos = g_slist_prepend (*to_remove_infos, info);
                return TRUE;
        }
@@ -2107,7 +1511,7 @@ remove_cache (CamelSession *session,
 {
        GSList *to_remove_infos = NULL;
 
-       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       camel_db_release_cache_memory ();
 
        if (time (NULL) - summary->priv->cache_load_time < SUMMARY_CACHE_DROP)
                return;
@@ -2116,8 +1520,7 @@ remove_cache (CamelSession *session,
 
        g_hash_table_foreach_remove (summary->priv->loaded_infos, (GHRFunc) remove_item, &to_remove_infos);
 
-       g_slist_foreach (to_remove_infos, (GFunc) camel_message_info_unref, NULL);
-       g_slist_free (to_remove_infos);
+       g_slist_free_full (to_remove_infos, g_object_unref);
 
        camel_folder_summary_unlock (summary);
 
@@ -2254,115 +1657,6 @@ cfs_cache_size (CamelFolderSummary *summary)
                return g_hash_table_size (summary->priv->uids);
 }
 
-/* Update preview of cached messages */
-
-static void
-msg_update_preview (const gchar *uid,
-                    gpointer value,
-                    CamelFolder *folder)
-{
-       CamelMessageInfoBase *info = (CamelMessageInfoBase *) camel_folder_summary_get (folder->summary, uid);
-       CamelMimeMessage *msg;
-       CamelStore *parent_store;
-       const gchar *full_name;
-
-       full_name = camel_folder_get_full_name (folder);
-       parent_store = camel_folder_get_parent_store (folder);
-
-       /* FIXME Pass a GCancellable */
-       msg = camel_folder_get_message_sync (folder, uid, NULL, NULL);
-       if (msg != NULL) {
-               if (camel_mime_message_build_preview ((CamelMimePart *) msg, (CamelMessageInfo *) info) && 
info->preview) {
-                       if (parent_store && !is_in_memory_summary (folder->summary))
-                               camel_db_write_preview_record (parent_store->cdb_w, full_name, info->uid, 
info->preview, NULL);
-               }
-       }
-       camel_message_info_unref (info);
-}
-
-static void
-pick_uids (const gchar *uid,
-           CamelMessageInfoBase *mi,
-           GPtrArray *array)
-{
-       if (mi->preview)
-               g_ptr_array_add (array, (gchar *) camel_pstring_strdup (uid));
-}
-
-static void
-copy_all_uids_to_hash (gpointer uid,
-                       gpointer hash)
-{
-       g_return_if_fail (uid != NULL);
-
-       g_hash_table_insert (hash, (gchar *) camel_pstring_strdup (uid), GINT_TO_POINTER (1));
-}
-
-static gboolean
-fill_mi (const gchar *uid,
-         const gchar *msg,
-         CamelFolder *folder)
-{
-       CamelMessageInfoBase *info;
-
-       info = g_hash_table_lookup (folder->summary->priv->loaded_infos, uid);
-       if (info) /* We re assign the memory of msg */
-               info->preview = (gchar *) msg;
-       camel_pstring_free (uid); /* unref the uid */
-
-       return TRUE;
-}
-
-static void
-preview_update (CamelSession *session,
-                GCancellable *cancellable,
-                CamelFolder *folder,
-                GError **error)
-{
-       /* FIXME: Either lock & use or copy & use.*/
-       GPtrArray *uids_uncached, *uids_array;
-       GHashTable *preview_data, *uids_hash;
-       CamelStore *parent_store;
-       const gchar *full_name;
-       gboolean is_in_memory = is_in_memory_summary (folder->summary);
-       gint i;
-
-       uids_array = camel_folder_summary_get_array (folder->summary);
-       uids_hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, 
NULL);
-       g_ptr_array_foreach (uids_array, copy_all_uids_to_hash, uids_hash);
-       uids_uncached = camel_folder_get_uncached_uids (folder, uids_array, NULL);
-       camel_folder_summary_free_array (uids_array);
-       uids_array = NULL;
-
-       full_name = camel_folder_get_full_name (folder);
-       parent_store = camel_folder_get_parent_store (folder);
-       preview_data = (!parent_store || is_in_memory) ? NULL : camel_db_get_folder_preview 
(parent_store->cdb_r, full_name, NULL);
-       if (preview_data) {
-               g_hash_table_foreach_remove (preview_data, (GHRFunc) fill_mi, folder);
-               g_hash_table_destroy (preview_data);
-       }
-
-       camel_folder_summary_lock (folder->summary);
-       g_hash_table_foreach (folder->summary->priv->loaded_infos, (GHFunc) pick_uids, uids_uncached);
-       camel_folder_summary_unlock (folder->summary);
-
-       for (i = 0; i < uids_uncached->len; i++) {
-               g_hash_table_remove (uids_hash, uids_uncached->pdata[i]);
-       }
-
-       camel_folder_lock (folder);
-       if (parent_store && !is_in_memory)
-               camel_db_begin_transaction (parent_store->cdb_w, NULL);
-       g_hash_table_foreach (uids_hash, (GHFunc) msg_update_preview, folder);
-       if (parent_store && !is_in_memory)
-               camel_db_end_transaction (parent_store->cdb_w, NULL);
-       camel_folder_unlock (folder);
-       camel_folder_free_uids (folder, uids_uncached);
-       g_hash_table_destroy (uids_hash);
-}
-
-/* end */
-
 static void
 cfs_reload_from_db (CamelFolderSummary *summary,
                     GError **error)
@@ -2384,7 +1678,7 @@ cfs_reload_from_db (CamelFolderSummary *summary,
                return;
 
        folder_name = camel_folder_get_full_name (summary->priv->folder);
-       cdb = parent_store->cdb_r;
+       cdb = camel_store_get_db (parent_store);
 
        data.columns_hash = NULL;
        data.summary = summary;
@@ -2398,54 +1692,6 @@ cfs_reload_from_db (CamelFolderSummary *summary,
                g_hash_table_destroy (data.columns_hash);
 
        cfs_schedule_info_release_timer (summary);
-
-       /* FIXME Convert this to a GTask, submitted through
-        *       camel_service_queue_task().  Then it won't
-        *       have to call camel_folder_lock/unlock(). */
-       if (summary->priv->need_preview) {
-               CamelSession *session;
-
-               /* This may not be available in a case of this being called as part
-                  of CamelSession's dispose, because the CamelService uses GWeakRef
-                  object which is invalidates its content when it reaches the dispose. */
-               session = camel_service_ref_session (CAMEL_SERVICE (parent_store));
-               if (session) {
-                       gchar *description;
-
-                       /* Translators: The first '%s' is replaced with an account name and the second '%s'
-                          is replaced with a full path name. The spaces around ':' are intentional, as
-                          the whole '%s : %s' is meant as an absolute identification of the folder. */
-                       description = g_strdup_printf (_("Update preview data for folder '%s : %s'"),
-                               camel_service_get_display_name (CAMEL_SERVICE (parent_store)),
-                               camel_folder_get_full_name (summary->priv->folder));
-
-                       camel_session_submit_job (
-                               session, description,
-                               (CamelSessionCallback) preview_update,
-                               g_object_ref (summary->priv->folder),
-                               (GDestroyNotify) g_object_unref);
-
-                       g_object_unref (session);
-                       g_free (description);
-               }
-       }
-
-       return;
-}
-
-/**
- * camel_folder_summary_add_preview:
- *
- * Since: 2.28
- **/
-void
-camel_folder_summary_add_preview (CamelFolderSummary *summary,
-                                  CamelMessageInfo *info)
-{
-       camel_folder_summary_lock (summary);
-       g_hash_table_insert (summary->priv->preview_updates, (gchar *) info->uid, ((CamelMessageInfoBase *) 
info)->preview);
-       camel_folder_summary_touch (summary);
-       camel_folder_summary_unlock (summary);
 }
 
 /**
@@ -2482,14 +1728,15 @@ camel_folder_summary_prepare_fetch_all (CamelFolderSummary *summary,
 }
 
 /**
- * camel_folder_summary_load_from_db:
+ * camel_folder_summary_load:
  *
- * Since: 2.24
+ * Since: 3.24
  **/
 gboolean
-camel_folder_summary_load_from_db (CamelFolderSummary *summary,
-                                   GError **error)
+camel_folder_summary_load (CamelFolderSummary *summary,
+                          GError **error)
 {
+       CamelFolderSummaryClass *klass;
        CamelDB *cdb;
        CamelStore *parent_store;
        const gchar *full_name;
@@ -2498,18 +1745,21 @@ camel_folder_summary_load_from_db (CamelFolderSummary *summary,
 
        g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
 
+       klass = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
+       g_return_val_if_fail (klass != NULL, FALSE);
+
        if (is_in_memory_summary (summary))
                return TRUE;
 
        camel_folder_summary_lock (summary);
-       camel_folder_summary_save_to_db (summary, NULL);
+       camel_folder_summary_save (summary, NULL);
 
        /* struct _db_pass_data data; */
-       d (printf ("\ncamel_folder_summary_load_from_db called \n"));
+       d (printf ("\ncamel_folder_summary_load called \n"));
 
        full_name = camel_folder_get_full_name (summary->priv->folder);
        parent_store = camel_folder_get_parent_store (summary->priv->folder);
-       if (!camel_folder_summary_header_load_from_db (summary, parent_store, full_name, error)) {
+       if (!camel_folder_summary_header_load (summary, parent_store, full_name, error)) {
                camel_folder_summary_unlock (summary);
                return FALSE;
        }
@@ -2519,10 +1769,10 @@ camel_folder_summary_load_from_db (CamelFolderSummary *summary,
                return FALSE;
        }
 
-       cdb = parent_store->cdb_r;
+       cdb = camel_store_get_db (parent_store);
 
        ret = camel_db_get_folder_uids (
-               cdb, full_name, summary->sort_by, summary->collate,
+               cdb, full_name, klass->sort_by, klass->collate,
                summary->priv->uids, &local_error);
 
        if (local_error != NULL && local_error->message != NULL &&
@@ -2539,6 +1789,7 @@ camel_folder_summary_load_from_db (CamelFolderSummary *summary,
        return ret == 0;
 }
 
+/* Beware, it only borrows pointers from 'cols' here */
 static void
 mir_from_cols (CamelMIRecord *mir,
                CamelFolderSummary *summary,
@@ -2555,80 +1806,76 @@ mir_from_cols (CamelMIRecord *mir,
 
                switch (camel_db_get_column_ident (columns_hash, i, ncol, name)) {
                        case CAMEL_DB_COLUMN_UID:
-                               mir->uid = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->uid = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_FLAGS:
-                               mir->flags = cols[i] ? strtoul (cols[i], NULL, 10) : 0;
+                               mir->flags = cols[i] ? g_ascii_strtoull (cols[i], NULL, 10) : 0;
                                break;
                        case CAMEL_DB_COLUMN_READ:
-                               mir->read = (cols[i]) ? ( ((strtoul (cols[i], NULL, 10)) ? TRUE : FALSE)) : 
FALSE;
+                               mir->read = (cols[i]) ? ( ((g_ascii_strtoull (cols[i], NULL, 10)) ? TRUE : 
FALSE)) : FALSE;
                                break;
                        case CAMEL_DB_COLUMN_DELETED:
-                               mir->deleted = (cols[i]) ? ( ((strtoul (cols[i], NULL, 10)) ? TRUE : FALSE)) 
: FALSE;
+                               mir->deleted = (cols[i]) ? ( ((g_ascii_strtoull (cols[i], NULL, 10)) ? TRUE : 
FALSE)) : FALSE;
                                break;
                        case CAMEL_DB_COLUMN_REPLIED:
-                               mir->replied = (cols[i]) ? ( ((strtoul (cols[i], NULL, 10)) ? TRUE : FALSE)) 
: FALSE;
+                               mir->replied = (cols[i]) ? ( ((g_ascii_strtoull (cols[i], NULL, 10)) ? TRUE : 
FALSE)) : FALSE;
                                break;
                        case CAMEL_DB_COLUMN_IMPORTANT:
-                               mir->important = (cols[i]) ? ( ((strtoul (cols[i], NULL, 10)) ? TRUE : 
FALSE)) : FALSE;
+                               mir->important = (cols[i]) ? ( ((g_ascii_strtoull (cols[i], NULL, 10)) ? TRUE 
: FALSE)) : FALSE;
                                break;
                        case CAMEL_DB_COLUMN_JUNK:
-                               mir->junk = (cols[i]) ? ( ((strtoul (cols[i], NULL, 10)) ? TRUE : FALSE)) : 
FALSE;
+                               mir->junk = (cols[i]) ? ( ((g_ascii_strtoull (cols[i], NULL, 10)) ? TRUE : 
FALSE)) : FALSE;
                                break;
                        case CAMEL_DB_COLUMN_ATTACHMENT:
-                               mir->attachment = (cols[i]) ? ( ((strtoul (cols[i], NULL, 10)) ? TRUE : 
FALSE)) : FALSE;
+                               mir->attachment = (cols[i]) ? ( ((g_ascii_strtoull (cols[i], NULL, 10)) ? 
TRUE : FALSE)) : FALSE;
                                break;
                        case CAMEL_DB_COLUMN_SIZE:
-                               mir->size = cols[i] ? strtoul (cols[i], NULL, 10) : 0;
+                               mir->size = cols[i] ? g_ascii_strtoull (cols[i], NULL, 10) : 0;
                                break;
                        case CAMEL_DB_COLUMN_DSENT:
-                               mir->dsent = cols[i] ? strtol (cols[i], NULL, 10) : 0;
+                               mir->dsent = cols[i] ? g_ascii_strtoll (cols[i], NULL, 10) : 0;
                                break;
                        case CAMEL_DB_COLUMN_DRECEIVED:
-                               mir->dreceived = cols[i] ? strtol (cols[i], NULL, 10) : 0;
+                               mir->dreceived = cols[i] ? g_ascii_strtoll (cols[i], NULL, 10) : 0;
                                break;
                        case CAMEL_DB_COLUMN_SUBJECT:
-                               mir->subject = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->subject = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_MAIL_FROM:
-                               mir->from = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->from = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_MAIL_TO:
-                               mir->to = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->to = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_MAIL_CC:
-                               mir->cc = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->cc = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_MLIST:
-                               mir->mlist = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->mlist = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_FOLLOWUP_FLAG:
-                               mir->followup_flag = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->followup_flag = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_FOLLOWUP_COMPLETED_ON:
-                               mir->followup_completed_on = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->followup_completed_on = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_FOLLOWUP_DUE_BY:
-                               mir->followup_due_by = (gchar *) camel_pstring_strdup (cols[i]);
+                               mir->followup_due_by = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_PART:
-                               mir->part = g_strdup (cols[i]);
+                               mir->part = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_LABELS:
-                               mir->labels = g_strdup (cols[i]);
+                               mir->labels = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_USERTAGS:
-                               mir->usertags = g_strdup (cols[i]);
+                               mir->usertags = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_CINFO:
-                               mir->cinfo = g_strdup (cols[i]);
+                               mir->cinfo = cols[i];
                                break;
                        case CAMEL_DB_COLUMN_BDATA:
-                               mir->bdata = g_strdup (cols[i]);
-                               break;
-                       case CAMEL_DB_COLUMN_BODYSTRUCTURE:
-                               /* Evolution itself doesn't yet use this, ignoring */
-                               /* mir->bodystructure = g_strdup (cols[i]); */
+                               mir->bdata = cols[i];
                                break;
                        default:
                                g_warn_if_reached ();
@@ -2645,133 +1892,105 @@ camel_read_mir_callback (gpointer ref,
 {
        struct _db_pass_data *data = (struct _db_pass_data *) ref;
        CamelFolderSummary *summary = data->summary;
-       CamelMIRecord *mir;
+       CamelMIRecord mir;
        CamelMessageInfo *info;
+       gchar *bdata_ptr;
        gint ret = 0;
 
-       mir = g_new0 (CamelMIRecord , 1);
-       mir_from_cols (mir, summary, &data->columns_hash, ncol, cols, name);
+       memset (&mir, 0, sizeof (CamelMIRecord));
+
+       /* As mir_from_cols() only borrows data from cols, no need to free mir */
+       mir_from_cols (&mir, summary, &data->columns_hash, ncol, cols, name);
 
        camel_folder_summary_lock (summary);
-       if (!mir->uid || g_hash_table_lookup (summary->priv->loaded_infos, mir->uid)) {
+       if (!mir.uid || g_hash_table_lookup (summary->priv->loaded_infos, mir.uid)) {
                /* Unlock and better return */
                camel_folder_summary_unlock (summary);
-               camel_db_camel_mir_free (mir);
                return ret;
        }
        camel_folder_summary_unlock (summary);
 
-       info = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_from_db (summary, mir);
-
-       if (info) {
-
-               if (summary->priv->build_content) {
-                       gchar *tmp;
-                       tmp = mir->cinfo;
-                       /* FIXME: this should be done differently, how i don't know */
-                       ((CamelMessageInfoBase *) info)->content = perform_content_info_load_from_db 
(summary, mir);
-                       if (((CamelMessageInfoBase *) info)->content == NULL) {
-                               camel_message_info_unref (info);
-                               info = NULL;
-                       }
-                       mir->cinfo = tmp;
-
-                       if (!info) {
-                               camel_db_camel_mir_free (mir);
-                               return -1;
-                       }
-               }
-
+       info = camel_message_info_new (summary);
+       bdata_ptr = mir.bdata;
+       if (camel_message_info_load (info, &mir, &bdata_ptr)) {
                /* Just now we are reading from the DB, it can't be dirty. */
-               ((CamelMessageInfoBase *) info)->dirty = FALSE;
-               if (data->add)
-                       camel_folder_summary_add (summary, info);
-               else
-                       camel_folder_summary_insert (summary, info, TRUE);
-
+               camel_message_info_set_dirty (info, FALSE);
+               if (data->add) {
+                       camel_folder_summary_add (summary, info, FALSE);
+                       g_clear_object (&info);
+               } else {
+                       camel_folder_summary_lock (summary);
+                       /* Summary always holds a ref for the loaded infos; this consumes it */
+                       g_hash_table_insert (summary->priv->loaded_infos, (gchar *) 
camel_message_info_get_uid (info), info);
+                       camel_folder_summary_unlock (summary);
+               }
        } else {
+               g_clear_object (&info);
                g_warning ("Loading messageinfo from db failed");
                ret = -1;
        }
 
-       camel_db_camel_mir_free (mir);
-
        return ret;
 }
 
-/* saves the content descriptions, recursively */
-static gboolean
-perform_content_info_save_to_db (CamelFolderSummary *summary,
-                                 CamelMessageContentInfo *ci,
-                                 CamelMIRecord *record)
-{
-       CamelMessageContentInfo *part;
-       gchar *oldr;
-
-       if (!CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->content_info_to_db (summary, ci, record))
-               return FALSE;
-
-       oldr = record->cinfo;
-       record->cinfo = g_strdup_printf ("%s %d", oldr, my_list_size ((struct _node **) &ci->childs));
-       g_free (oldr);
-
-       part = ci->childs;
-       while (part) {
-               if (perform_content_info_save_to_db (summary, part, record) == -1)
-                       return FALSE;
-               part = part->next;
-       }
-
-       return TRUE;
-}
-
 static void
 save_to_db_cb (gpointer key,
                gpointer value,
                gpointer data)
 {
-       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) value;
-       CamelFolderSummary *summary = (CamelFolderSummary *) mi->summary;
+       CamelMessageInfo *mi = value;
+       CamelFolderSummary *summary;
        CamelStore *parent_store;
        const gchar *full_name;
        CamelDB *cdb;
        CamelMIRecord *mir;
+       GString *bdata_str;
        GError **error = data;
 
-       full_name = camel_folder_get_full_name (summary->priv->folder);
-       parent_store = camel_folder_get_parent_store (summary->priv->folder);
-       if (!parent_store)
+       if (!camel_message_info_get_dirty (mi))
                return;
 
-       cdb = parent_store->cdb_w;
+       summary = camel_message_info_ref_summary (mi);
+       if (!summary)
+               return;
 
-       if (!mi->dirty)
+       full_name = camel_folder_get_full_name (summary->priv->folder);
+       parent_store = camel_folder_get_parent_store (summary->priv->folder);
+       if (!parent_store) {
+               g_clear_object (&summary);
                return;
+       }
 
-       mir = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_to_db (summary, (CamelMessageInfo *) mi);
+       cdb = camel_store_get_db (parent_store);
 
-       if (mir && summary->priv->build_content) {
-               if (!perform_content_info_save_to_db (summary, ((CamelMessageInfoBase *) mi)->content, mir)) {
-                       g_warning ("unable to save mir+cinfo for uid: %s\n", mir->uid);
-                       camel_db_camel_mir_free (mir);
-                       /* FIXME: Add exception here */
-                       return;
-               }
+       mir = g_new0 (CamelMIRecord, 1);
+       bdata_str = g_string_new (NULL);
+
+       if (!camel_message_info_save (mi, mir, bdata_str)) {
+               g_warning ("Failed to save message info: %s\n", camel_message_info_get_uid (mi));
+               g_string_free (bdata_str, TRUE);
+               camel_db_camel_mir_free (mir);
+               g_clear_object (&summary);
+               return;
        }
 
-       g_return_if_fail (mir != NULL);
+       g_warn_if_fail (mir->bdata == NULL);
+       mir->bdata = g_string_free (bdata_str, FALSE);
+       bdata_str = NULL;
 
        if (camel_db_write_message_info_record (cdb, full_name, mir, error) != 0) {
                camel_db_camel_mir_free (mir);
+               g_clear_object (&summary);
                return;
        }
 
        /* Reset the dirty flag which decides if the changes are synced to the DB or not.
        The FOLDER_FLAGGED should be used to check if the changes are synced to the server.
        So, dont unset the FOLDER_FLAGGED flag */
-       mi->dirty = FALSE;
+       camel_message_info_set_dirty (mi, FALSE);
 
        camel_db_camel_mir_free (mir);
+       g_clear_object (&summary);
 }
 
 static gint
@@ -2790,7 +2009,7 @@ save_message_infos_to_db (CamelFolderSummary *summary,
        if (!parent_store)
                return 0;
 
-       cdb = parent_store->cdb_w;
+       cdb = camel_store_get_db (parent_store);
 
        if (camel_db_prepare_message_info_table (cdb, full_name, error) != 0)
                return -1;
@@ -2808,31 +2027,14 @@ save_message_infos_to_db (CamelFolderSummary *summary,
        return 0;
 }
 
-static void
-msg_save_preview (const gchar *uid,
-                  gpointer value,
-                  CamelFolder *folder)
-{
-       CamelStore *parent_store;
-       const gchar *full_name;
-
-       full_name = camel_folder_get_full_name (folder);
-       parent_store = camel_folder_get_parent_store (folder);
-
-       if (parent_store) {
-               camel_db_write_preview_record (
-                       parent_store->cdb_w, full_name, uid, (gchar *) value, NULL);
-       }
-}
-
 /**
- * camel_folder_summary_save_to_db:
+ * camel_folder_summary_save:
  *
- * Since: 2.24
+ * Since: 3.24
  **/
 gboolean
-camel_folder_summary_save_to_db (CamelFolderSummary *summary,
-                                 GError **error)
+camel_folder_summary_save (CamelFolderSummary *summary,
+                          GError **error)
 {
        CamelStore *parent_store;
        CamelDB *cdb;
@@ -2841,7 +2043,7 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
 
        g_return_val_if_fail (summary != NULL, FALSE);
 
-       if (!(summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) ||
+       if (!(summary->priv->flags & CAMEL_FOLDER_SUMMARY_DIRTY) ||
            is_in_memory_summary (summary))
                return TRUE;
 
@@ -2849,23 +2051,17 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
        if (!parent_store)
                return FALSE;
 
-       cdb = parent_store->cdb_w;
+       cdb = camel_store_get_db (parent_store);
 
        camel_folder_summary_lock (summary);
 
-       d (printf ("\ncamel_folder_summary_save_to_db called \n"));
-       if (summary->priv->need_preview && g_hash_table_size (summary->priv->preview_updates)) {
-               camel_db_begin_transaction (parent_store->cdb_w, NULL);
-               g_hash_table_foreach (summary->priv->preview_updates, (GHFunc) msg_save_preview, 
summary->priv->folder);
-               g_hash_table_remove_all (summary->priv->preview_updates);
-               camel_db_end_transaction (parent_store->cdb_w, NULL);
-       }
+       d (printf ("\ncamel_folder_summary_save called \n"));
 
-       summary->flags &= ~CAMEL_FOLDER_SUMMARY_DIRTY;
+       summary->priv->flags &= ~CAMEL_FOLDER_SUMMARY_DIRTY;
 
        count = cfs_count_dirty (summary);
        if (!count) {
-               gboolean res = camel_folder_summary_header_save_to_db (summary, error);
+               gboolean res = camel_folder_summary_header_save (summary, error);
                camel_folder_summary_unlock (summary);
                return res;
        }
@@ -2873,7 +2069,7 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
        ret = save_message_infos_to_db (summary, error);
        if (ret != 0) {
                /* Failed, so lets reset the flag */
-               summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
+               summary->priv->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
                camel_folder_summary_unlock (summary);
                return FALSE;
        }
@@ -2895,15 +2091,15 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
 
                ret = save_message_infos_to_db (summary, error);
                if (ret != 0) {
-                       summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
+                       summary->priv->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
                        camel_folder_summary_unlock (summary);
                        return FALSE;
                }
        }
 
-       record = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->summary_header_to_db (summary, error);
+       record = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->summary_header_save (summary, error);
        if (!record) {
-               summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
+               summary->priv->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
                camel_folder_summary_unlock (summary);
                return FALSE;
        }
@@ -2916,7 +2112,7 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
 
        if (ret != 0) {
                camel_db_abort_transaction (cdb, NULL);
-               summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
+               summary->priv->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
                camel_folder_summary_unlock (summary);
                return FALSE;
        }
@@ -2928,13 +2124,13 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
 }
 
 /**
- * camel_folder_summary_header_save_to_db:
+ * camel_folder_summary_header_save:
  *
- * Since: 2.24
+ * Since: 3.24
  **/
 gboolean
-camel_folder_summary_header_save_to_db (CamelFolderSummary *summary,
-                                        GError **error)
+camel_folder_summary_header_save (CamelFolderSummary *summary,
+                                 GError **error)
 {
        CamelStore *parent_store;
        CamelFIRecord *record;
@@ -2948,12 +2144,12 @@ camel_folder_summary_header_save_to_db (CamelFolderSummary *summary,
        if (!parent_store)
                return FALSE;
 
-       cdb = parent_store->cdb_w;
+       cdb = camel_store_get_db (parent_store);
        camel_folder_summary_lock (summary);
 
-       d (printf ("\ncamel_folder_summary_header_save_to_db called \n"));
+       d (printf ("\ncamel_folder_summary_header_save called \n"));
 
-       record = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->summary_header_to_db (summary, error);
+       record = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->summary_header_save (summary, error);
        if (!record) {
                camel_folder_summary_unlock (summary);
                return FALSE;
@@ -2978,34 +2174,34 @@ camel_folder_summary_header_save_to_db (CamelFolderSummary *summary,
 }
 
 /**
- * camel_folder_summary_header_load_from_db:
+ * camel_folder_summary_header_load:
  *
- * Since: 2.24
+ * Since: 3.24
  **/
 gboolean
-camel_folder_summary_header_load_from_db (CamelFolderSummary *summary,
-                                          CamelStore *store,
-                                          const gchar *folder_name,
-                                          GError **error)
+camel_folder_summary_header_load (CamelFolderSummary *summary,
+                                 CamelStore *store,
+                                 const gchar *folder_name,
+                                 GError **error)
 {
        CamelDB *cdb;
        CamelFIRecord *record;
        gboolean ret = FALSE;
 
-       d (printf ("\ncamel_folder_summary_header_load_from_db called \n"));
+       d (printf ("\ncamel_folder_summary_header_load called \n"));
 
        if (is_in_memory_summary (summary))
                return TRUE;
 
        camel_folder_summary_lock (summary);
-       camel_folder_summary_save_to_db (summary, NULL);
+       camel_folder_summary_save (summary, NULL);
 
-       cdb = store->cdb_r;
+       cdb = camel_store_get_db (store);
 
        record = g_new0 (CamelFIRecord, 1);
        camel_db_read_folder_info_record (cdb, folder_name, record, error);
 
-       ret = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->summary_header_from_db (summary, record);
+       ret = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->summary_header_load (summary, record);
 
        camel_folder_summary_unlock (summary);
 
@@ -3020,35 +2216,51 @@ static gboolean
 summary_assign_uid (CamelFolderSummary *summary,
                     CamelMessageInfo *info)
 {
-       const gchar *uid;
+       const gchar *info_uid;
+       gchar *new_uid;
        CamelMessageInfo *mi;
 
-       uid = camel_message_info_get_uid (info);
+       camel_message_info_set_abort_notifications (info, TRUE);
+       camel_message_info_property_lock (info);
 
-       if (uid == NULL || uid[0] == 0) {
-               camel_pstring_free (info->uid);
-               uid = info->uid = (gchar *) camel_pstring_add (camel_folder_summary_next_uid_string 
(summary), TRUE);
+       info_uid = camel_message_info_get_uid (info);
+
+       if (!info_uid || !*info_uid) {
+               new_uid = camel_folder_summary_next_uid_string (summary);
+
+               camel_message_info_set_uid (info, new_uid);
+       } else {
+               new_uid = g_strdup (info_uid);
        }
 
        camel_folder_summary_lock (summary);
 
-       while ((mi = g_hash_table_lookup (summary->priv->loaded_infos, uid))) {
+       while ((mi = g_hash_table_lookup (summary->priv->loaded_infos, new_uid))) {
                camel_folder_summary_unlock (summary);
 
-               if (mi == info)
+               g_free (new_uid);
+
+               if (mi == info) {
+                       camel_message_info_property_unlock (info);
                        return FALSE;
+               }
 
                d (printf ("Trying to insert message with clashing uid (%s).  new uid re-assigned", 
camel_message_info_get_uid (info)));
 
-               camel_pstring_free (info->uid);
-               uid = info->uid = camel_pstring_add (camel_folder_summary_next_uid_string (summary), TRUE);
-               camel_message_info_set_flags (info, CAMEL_MESSAGE_FOLDER_FLAGGED, 
CAMEL_MESSAGE_FOLDER_FLAGGED);
+               new_uid = camel_folder_summary_next_uid_string (summary);
+               camel_message_info_set_uid (info, new_uid);
+               camel_message_info_set_folder_flagged (info, TRUE);
 
                camel_folder_summary_lock (summary);
        }
 
+       g_free (new_uid);
+
        camel_folder_summary_unlock (summary);
 
+       camel_message_info_property_unlock (info);
+       camel_message_info_set_abort_notifications (info, FALSE);
+
        return TRUE;
 }
 
@@ -3056,36 +2268,47 @@ summary_assign_uid (CamelFolderSummary *summary,
  * camel_folder_summary_add:
  * @summary: a #CamelFolderSummary object
  * @info: a #CamelMessageInfo
+ * @force_keep_uid: whether to keep set UID of the @info
  *
- * Adds a new @info record to the summary.  If @info->uid is %NULL,
+ * Adds a new @info record to the summary. If the @force_keep_uid is %FALSE,
  * then a new uid is automatically re-assigned by calling
- * camel_folder_summary_next_uid_string().
+ * camel_folder_summary_next_uid_string(). It's an error to to use
+ * @force_keep_uid whe nthe @info has none set.
  *
- * The @info record should have been generated by calling one of the
- * info_new_*() functions, as it will be free'd based on the summary
- * class.  And MUST NOT be allocated directly using malloc.
+ * The @summary adds its own reference to @info, if needed.
  **/
 void
 camel_folder_summary_add (CamelFolderSummary *summary,
-                          CamelMessageInfo *info)
+                          CamelMessageInfo *info,
+                         gboolean force_keep_uid)
 {
-       CamelMessageInfoBase *base_info;
-
        g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
 
-       if (info == NULL)
+       if (!info)
                return;
 
+       g_return_if_fail (CAMEL_IS_MESSAGE_INFO (info));
+
        camel_folder_summary_lock (summary);
-       if (!summary_assign_uid (summary, info)) {
+       if (!force_keep_uid && !summary_assign_uid (summary, info)) {
                camel_folder_summary_unlock (summary);
                return;
        }
 
-       base_info = (CamelMessageInfoBase *) info;
+       if (force_keep_uid) {
+               const gchar *uid;
+
+               uid = camel_message_info_get_uid (info);
+               if (!uid || !*uid) {
+                       g_warning ("%s: Cannot add message info without UID, when disabled to assign new UID; 
skipping it", G_STRFUNC);
+                       camel_folder_summary_unlock (summary);
+                       return;
+               }
+       }
+
        folder_summary_update_counts_by_flags (summary, camel_message_info_get_flags (info), 
UPDATE_COUNTS_ADD);
-       base_info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
-       base_info->dirty = TRUE;
+       camel_message_info_set_folder_flagged (info, TRUE);
+       camel_message_info_set_dirty (info, TRUE);
 
        g_hash_table_insert (
                summary->priv->uids,
@@ -3093,7 +2316,7 @@ camel_folder_summary_add (CamelFolderSummary *summary,
                GUINT_TO_POINTER (camel_message_info_get_flags (info)));
 
        /* Summary always holds a ref for the loaded infos */
-       g_hash_table_insert (summary->priv->loaded_infos, (gpointer) camel_message_info_get_uid (info), info);
+       g_hash_table_insert (summary->priv->loaded_infos, (gpointer) camel_message_info_get_uid (info), 
g_object_ref (info));
 
        camel_folder_summary_touch (summary);
 
@@ -3101,65 +2324,29 @@ camel_folder_summary_add (CamelFolderSummary *summary,
 }
 
 /**
- * camel_folder_summary_insert:
- *
- * Since: 2.24
- **/
-void
-camel_folder_summary_insert (CamelFolderSummary *summary,
-                             CamelMessageInfo *info,
-                             gboolean load)
-{
-       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
-
-       if (info == NULL)
-               return;
-
-       camel_folder_summary_lock (summary);
-
-       if (!load) {
-               CamelMessageInfoBase *base_info = (CamelMessageInfoBase *) info;
-
-               folder_summary_update_counts_by_flags (summary, camel_message_info_get_flags (info), 
UPDATE_COUNTS_ADD);
-               base_info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
-               base_info->dirty = TRUE;
-
-               g_hash_table_insert (
-                       summary->priv->uids,
-                       (gpointer) camel_pstring_strdup (camel_message_info_get_uid (info)),
-                       GUINT_TO_POINTER (camel_message_info_get_flags (info)));
-
-               camel_folder_summary_touch (summary);
-       }
-
-       /* Summary always holds a ref for the loaded infos */
-       g_hash_table_insert (summary->priv->loaded_infos, (gchar *) camel_message_info_get_uid (info), info);
-
-       camel_folder_summary_unlock (summary);
-}
-
-/**
- * camel_folder_summary_info_new_from_header:
+ * camel_folder_summary_info_new_from_headers:
  * @summary: a #CamelFolderSummary object
- * @headers: rfc822 headers
+ * @headers: rfc822 headers as #CamelNameValueArray
  *
  * Create a new info record from a header.
  *
- * Returns: the newly allocated record which must be unreferenced with
- *          camel_message_info_unref()
+ * Returns: (transfer full): a newly created #CamelMessageInfo. Unref it
+ *   with g_object_unref(), when done with it.
+ *
+ * Since: 3.24
  **/
 CamelMessageInfo *
-camel_folder_summary_info_new_from_header (CamelFolderSummary *summary,
-                                           struct _camel_header_raw *h)
+camel_folder_summary_info_new_from_headers (CamelFolderSummary *summary,
+                                           const CamelNameValueArray *headers)
 {
        CamelFolderSummaryClass *class;
 
        g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
 
        class = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
-       g_return_val_if_fail (class->message_info_new_from_header != NULL, NULL);
+       g_return_val_if_fail (class->message_info_new_from_headers != NULL, NULL);
 
-       return class->message_info_new_from_header (summary, h);
+       return class->message_info_new_from_headers (summary, headers);
 }
 
 /**
@@ -3180,8 +2367,8 @@ camel_folder_summary_info_new_from_header (CamelFolderSummary *summary,
  * Once complete, the parser will be positioned at the end of
  * the message.
  *
- * Returns: the newly allocated record which must be unreferenced with
- *          camel_message_info_unref()
+ * Returns: (transfer full): a newly created #CamelMessageInfo. Unref it
+ *   with g_object_unref(), when done with it.
  **/
 CamelMessageInfo *
 camel_folder_summary_info_new_from_parser (CamelFolderSummary *summary,
@@ -3218,7 +2405,7 @@ camel_folder_summary_info_new_from_parser (CamelFolderSummary *summary,
                }
 
                /* always scan the content info, even if we dont save it */
-               ((CamelMessageInfoBase *) info)->content = summary_build_content_info (summary, info, mp);
+               summary_traverse_content_with_parser (summary, info, mp);
 
                if (name && p->index) {
                        camel_index_write_name (p->index, name);
@@ -3229,7 +2416,7 @@ camel_folder_summary_info_new_from_parser (CamelFolderSummary *summary,
 
                g_rec_mutex_unlock (&summary->priv->filter_lock);
 
-               ((CamelMessageInfoBase *) info)->size = camel_mime_parser_tell (mp) - start;
+               camel_message_info_set_size (info, camel_mime_parser_tell (mp) - start);
        }
        return info;
 }
@@ -3238,23 +2425,21 @@ camel_folder_summary_info_new_from_parser (CamelFolderSummary *summary,
  * camel_folder_summary_info_new_from_message:
  * @summary: a #CamelFolderSummary object
  * @message: a #CamelMimeMessage object
- * @bodystructure: a bodystructure or NULL
  *
  * Create a summary item from a message.
  *
- * Returns: the newly allocated record which must be unreferenced with
- *          camel_message_info_unref()
+ * Returns: (transfer full): a newly created #CamelMessageInfo. Unref it
+ *   with g_object_unref(), when done with it.
  **/
 CamelMessageInfo *
 camel_folder_summary_info_new_from_message (CamelFolderSummary *summary,
-                                            CamelMimeMessage *msg,
-                                            const gchar *bodystructure)
+                                            CamelMimeMessage *msg)
 {
        CamelMessageInfo *info;
        CamelFolderSummaryPrivate *p = summary->priv;
        CamelIndexName *name = NULL;
 
-       info = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_new_from_message (summary, msg, 
bodystructure);
+       info = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_new_from_message (summary, msg);
 
        /* assign a unique uid, this is slightly 'wrong' as we do not really
         * know if we are going to store this in the summary, but we need it set for indexing */
@@ -3279,7 +2464,7 @@ camel_folder_summary_info_new_from_message (CamelFolderSummary *summary,
                }
        }
 
-       ((CamelMessageInfoBase *) info)->content = summary_build_content_info_message (summary, info, 
(CamelMimePart *) msg);
+       summary_traverse_content_with_part (summary, info, (CamelMimePart *) msg);
 
        if (name) {
                camel_index_write_name (p->index, name);
@@ -3294,28 +2479,6 @@ camel_folder_summary_info_new_from_message (CamelFolderSummary *summary,
 }
 
 /**
- * camel_folder_summary_content_info_free:
- * @summary: a #CamelFolderSummary object
- * @ci: a #CamelMessageContentInfo
- *
- * Free the content info @ci, and all associated memory.
- **/
-void
-camel_folder_summary_content_info_free (CamelFolderSummary *summary,
-                                        CamelMessageContentInfo *ci)
-{
-       CamelMessageContentInfo *pw, *pn;
-
-       pw = ci->childs;
-       CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->content_info_free (summary, ci);
-       while (pw) {
-               pn = pw->next;
-               camel_folder_summary_content_info_free (summary, pw);
-               pw = pn;
-       }
-}
-
-/**
  * camel_folder_summary_touch:
  * @summary: a #CamelFolderSummary object
  *
@@ -3326,7 +2489,7 @@ void
 camel_folder_summary_touch (CamelFolderSummary *summary)
 {
        camel_folder_summary_lock (summary);
-       summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
+       summary->priv->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
        camel_folder_summary_unlock (summary);
 }
 
@@ -3374,7 +2537,7 @@ camel_folder_summary_clear (CamelFolderSummary *summary,
                return FALSE;
        }
 
-       cdb = parent_store->cdb_w;
+       cdb = camel_store_get_db (parent_store);
 
        if (!is_in_memory_summary (summary))
                res = camel_db_clear_folder_summary (cdb, folder_name, error) == 0;
@@ -3413,7 +2576,7 @@ camel_folder_summary_remove (CamelFolderSummary *summary,
        g_return_val_if_fail (info != NULL, FALSE);
 
        if (camel_folder_summary_remove_uid (summary, camel_message_info_get_uid (info))) {
-               camel_message_info_unref (info);
+               g_clear_object (&info);
                return TRUE;
        }
 
@@ -3457,7 +2620,7 @@ camel_folder_summary_remove_uid (CamelFolderSummary *summary,
        if (!is_in_memory_summary (summary)) {
                full_name = camel_folder_get_full_name (summary->priv->folder);
                parent_store = camel_folder_get_parent_store (summary->priv->folder);
-               if (!parent_store || camel_db_delete_uid (parent_store->cdb_w, full_name, uid_copy, NULL) != 
0)
+               if (!parent_store || camel_db_delete_uid (camel_store_get_db (parent_store), full_name, 
uid_copy, NULL) != 0)
                        res = FALSE;
        }
 
@@ -3508,7 +2671,7 @@ camel_folder_summary_remove_uids (CamelFolderSummary *summary,
                        g_hash_table_remove (summary->priv->loaded_infos, uid_copy);
 
                        if (mi)
-                               camel_message_info_unref (mi);
+                               g_clear_object (&mi);
                        camel_pstring_free (uid_copy);
                }
        }
@@ -3516,7 +2679,7 @@ camel_folder_summary_remove_uids (CamelFolderSummary *summary,
        if (!is_in_memory_summary (summary)) {
                full_name = camel_folder_get_full_name (summary->priv->folder);
                parent_store = camel_folder_get_parent_store (summary->priv->folder);
-               if (!parent_store || camel_db_delete_uids (parent_store->cdb_w, full_name, uids, NULL) != 0)
+               if (!parent_store || camel_db_delete_uids (camel_store_get_db (parent_store), full_name, 
uids, NULL) != 0)
                        res = FALSE;
        }
 
@@ -3527,42 +2690,13 @@ camel_folder_summary_remove_uids (CamelFolderSummary *summary,
        return res;
 }
 
-static struct _node *
-my_list_append (struct _node **list,
-                struct _node *n)
-{
-       struct _node *ln = *list;
-       n->next = NULL;
-
-       if (!ln) {
-               *list = n;
-               return n;
-       }
-
-       while (ln->next)
-               ln = ln->next;
-       ln->next = n;
-       return n;
-}
-
-static gint
-my_list_size (struct _node **list)
-{
-       gint len = 0;
-       struct _node *ln = (struct _node *) list;
-       while (ln->next) {
-               ln = ln->next;
-               len++;
-       }
-       return len;
-}
-
 /* are these even useful for anything??? */
 static CamelMessageInfo *
 message_info_new_from_parser (CamelFolderSummary *summary,
                               CamelMimeParser *mp)
 {
        CamelMessageInfo *mi = NULL;
+       CamelNameValueArray *headers;
        gint state;
 
        state = camel_mime_parser_state (mp);
@@ -3570,7 +2704,9 @@ message_info_new_from_parser (CamelFolderSummary *summary,
        case CAMEL_MIME_PARSER_STATE_HEADER:
        case CAMEL_MIME_PARSER_STATE_MESSAGE:
        case CAMEL_MIME_PARSER_STATE_MULTIPART:
-               mi = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_new_from_header (summary, 
camel_mime_parser_headers_raw (mp));
+               headers = camel_mime_parser_dup_headers (mp);
+               mi = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_new_from_headers (summary, 
headers);
+               camel_name_value_array_free (headers);
                break;
        default:
                g_error ("Invalid parser state");
@@ -3579,70 +2715,30 @@ message_info_new_from_parser (CamelFolderSummary *summary,
        return mi;
 }
 
-static CamelMessageContentInfo *
-content_info_new_from_parser (CamelFolderSummary *summary,
-                              CamelMimeParser *mp)
-{
-       CamelMessageContentInfo *ci = NULL;
-
-       switch (camel_mime_parser_state (mp)) {
-       case CAMEL_MIME_PARSER_STATE_HEADER:
-       case CAMEL_MIME_PARSER_STATE_MESSAGE:
-       case CAMEL_MIME_PARSER_STATE_MULTIPART:
-               ci = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->content_info_new_from_header (summary, 
camel_mime_parser_headers_raw (mp));
-               if (ci) {
-                       if (ci->type)
-                               camel_content_type_unref (ci->type);
-                       ci->type = camel_mime_parser_content_type (mp);
-                       camel_content_type_ref (ci->type);
-               }
-               break;
-       default:
-               g_error ("Invalid parser state");
-       }
-
-       return ci;
-}
-
 static CamelMessageInfo *
 message_info_new_from_message (CamelFolderSummary *summary,
-                               CamelMimeMessage *msg,
-                               const gchar *bodystructure)
-{
-       CamelMessageInfo *mi;
-
-       mi = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (summary)))->message_info_new_from_header 
(summary, ((CamelMimePart *) msg)->headers);
-       ((CamelMessageInfoBase *) mi)->bodystructure = g_strdup (bodystructure);
-
-       return mi;
-}
-
-static CamelMessageContentInfo *
-content_info_new_from_message (CamelFolderSummary *summary,
-                               CamelMimePart *mp)
+                               CamelMimeMessage *msg)
 {
-       CamelMessageContentInfo *ci;
-
-       ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (summary)))->content_info_new_from_header 
(summary, mp->headers);
-
-       return ci;
+       return CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_new_from_headers (summary, 
camel_medium_get_headers (CAMEL_MEDIUM (msg)));
 }
 
 static gchar *
-summary_format_address (struct _camel_header_raw *h,
+summary_format_address (const CamelNameValueArray *headers,
                         const gchar *name,
                         const gchar *charset)
 {
-       CamelHeaderAddress *addr;
-       gchar *text, *str;
+       CamelHeaderAddress *addr = NULL;
+       gchar *text = NULL, *str = NULL;
+       const gchar *value;
 
-       if (!(text = (gchar *) camel_header_raw_find (&h, name, NULL)))
+       value = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, name);
+       if (!value)
                return NULL;
 
-       while (isspace ((unsigned) *text))
-               text++;
+       while (*value && g_ascii_isspace (*value))
+               value++;
 
-       text = camel_header_unfold (text);
+       text = camel_header_unfold (value);
 
        if ((addr = camel_header_address_decode (text, charset))) {
                str = camel_header_address_list_format (addr);
@@ -3656,54 +2752,36 @@ summary_format_address (struct _camel_header_raw *h,
 }
 
 static gchar *
-summary_format_string (struct _camel_header_raw *h,
+summary_format_string (const CamelNameValueArray *headers,
                        const gchar *name,
                        const gchar *charset)
 {
        gchar *text, *str;
+       const gchar *value;
 
-       if (!(text = (gchar *) camel_header_raw_find (&h, name, NULL)))
+       value = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, name);
+       if (!value)
                return NULL;
 
-       while (isspace ((unsigned) *text))
-               text++;
+       while (*value && g_ascii_isspace (*value))
+               value++;
 
-       text = camel_header_unfold (text);
+       text = camel_header_unfold (value);
        str = camel_header_decode_string (text, charset);
        g_free (text);
 
        return str;
 }
 
-/**
- * camel_folder_summary_content_info_new:
- * @summary: a #CamelFolderSummary object
- *
- * Allocate a new #CamelMessageContentInfo, suitable for adding
- * to this summary.
- *
- * Returns: a newly allocated #CamelMessageContentInfo
- **/
-CamelMessageContentInfo *
-camel_folder_summary_content_info_new (CamelFolderSummary *summary)
-{
-       CamelFolderSummaryClass *class;
-
-       class = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
-       g_return_val_if_fail (class->content_info_size > 0, NULL);
-
-       return g_slice_alloc0 (class->content_info_size);
-}
-
 static CamelMessageInfo *
-message_info_new_from_header (CamelFolderSummary *summary,
-                              struct _camel_header_raw *h)
+message_info_new_from_headers (CamelFolderSummary *summary,
+                              const CamelNameValueArray *headers)
 {
        const gchar *received, *date, *content, *charset = NULL;
        GSList *refs, *irt, *scan;
        gchar *subject, *from, *to, *cc, *mlist;
        CamelContentType *ct = NULL;
-       CamelMessageInfoBase *mi;
+       CamelMessageInfo *mi;
        guint8 *digest;
        gsize length;
        gchar *msgid;
@@ -3712,9 +2790,11 @@ message_info_new_from_header (CamelFolderSummary *summary,
        length = g_checksum_type_get_length (G_CHECKSUM_MD5);
        digest = g_alloca (length);
 
-       mi = (CamelMessageInfoBase *) camel_message_info_new (summary);
+       mi = camel_message_info_new (summary);
+
+       camel_message_info_set_abort_notifications (mi, TRUE);
 
-       if ((content = camel_header_raw_find (&h, "Content-Type", NULL))
+       if ((content = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
"Content-Type"))
             && (ct = camel_content_type_decode (content))
             && (charset = camel_content_type_param (ct, "charset"))
             && (g_ascii_strcasecmp (charset, "us-ascii") == 0))
@@ -3722,62 +2802,71 @@ message_info_new_from_header (CamelFolderSummary *summary,
 
        charset = charset ? camel_iconv_charset_name (charset) : NULL;
 
-       subject = summary_format_string (h, "subject", charset);
-       from = summary_format_address (h, "from", charset);
-       to = summary_format_address (h, "to", charset);
-       cc = summary_format_address (h, "cc", charset);
-       mlist = camel_header_raw_check_mailing_list (&h);
+       subject = summary_format_string (headers, "subject", charset);
+       from = summary_format_address (headers, "from", charset);
+       to = summary_format_address (headers, "to", charset);
+       cc = summary_format_address (headers, "cc", charset);
+       mlist = camel_headers_dup_mailing_list (headers);
 
        if (ct)
                camel_content_type_unref (ct);
 
-       mi->subject = camel_pstring_add (subject, TRUE);
-       mi->from = camel_pstring_add (from, TRUE);
-       mi->to = camel_pstring_add (to, TRUE);
-       mi->cc = camel_pstring_add (cc, TRUE);
-       mi->mlist = camel_pstring_add (mlist, TRUE);
+       camel_message_info_set_subject (mi, subject);
+       camel_message_info_set_from (mi, from);
+       camel_message_info_set_to (mi, to);
+       camel_message_info_set_cc (mi, cc);
+       camel_message_info_set_mlist (mi, mlist);
 
-       mi->user_flags = NULL;
-       mi->user_tags = NULL;
+       g_free (subject);
+       g_free (from);
+       g_free (to);
+       g_free (cc);
+       g_free (mlist);
 
-       if ((date = camel_header_raw_find (&h, "date", NULL)))
-               mi->date_sent = camel_header_decode_date (date, NULL);
+       if ((date = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, "Date")))
+               camel_message_info_set_date_sent (mi, camel_header_decode_date (date, NULL));
        else
-               mi->date_sent = 0;
+               camel_message_info_set_date_sent (mi, 0);
 
-       received = camel_header_raw_find (&h, "received", NULL);
+       received = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, "Received");
        if (received)
                received = strrchr (received, ';');
        if (received)
-               mi->date_received = camel_header_decode_date (received + 1, NULL);
+               camel_message_info_set_date_received (mi, camel_header_decode_date (received + 1, NULL));
        else
-               mi->date_received = 0;
+               camel_message_info_set_date_received (mi, 0);
 
        /* Fallback to Received date, when the Date header is missing */
-       if (!mi->date_sent)
-               mi->date_sent = mi->date_received;
+       if (!camel_message_info_get_date_sent (mi))
+               camel_message_info_set_date_sent (mi, camel_message_info_get_date_received (mi));
 
        /* If neither Received is available, then use the current time. */
-       if (!mi->date_sent)
-               mi->date_sent = time (NULL);
+       if (!camel_message_info_get_date_sent (mi))
+               camel_message_info_set_date_sent (mi, (gint64) time (NULL));
 
-       msgid = camel_header_msgid_decode (camel_header_raw_find (&h, "message-id", NULL));
+       msgid = camel_header_msgid_decode (camel_name_value_array_get_named (headers, 
CAMEL_COMPARE_CASE_INSENSITIVE, "Message-ID"));
        if (msgid) {
                GChecksum *checksum;
+               CamelSummaryMessageID message_id;
 
                checksum = g_checksum_new (G_CHECKSUM_MD5);
                g_checksum_update (checksum, (guchar *) msgid, -1);
                g_checksum_get_digest (checksum, digest, &length);
                g_checksum_free (checksum);
 
-               memcpy (mi->message_id.id.hash, digest, sizeof (mi->message_id.id.hash));
+               memcpy (message_id.id.hash, digest, sizeof (message_id.id.hash));
                g_free (msgid);
+
+               camel_message_info_set_message_id (mi, message_id.id.id);
        }
 
        /* decode our references and in-reply-to headers */
-       refs = camel_header_references_decode (camel_header_raw_find (&h, "references", NULL));
-       irt = camel_header_references_decode (camel_header_raw_find (&h, "in-reply-to", NULL));
+       refs = camel_header_references_decode (camel_name_value_array_get_named (headers, 
CAMEL_COMPARE_CASE_INSENSITIVE, "References"));
+       irt = camel_header_references_decode (camel_name_value_array_get_named (headers, 
CAMEL_COMPARE_CASE_INSENSITIVE, "In-Reply-To"));
        if (refs || irt) {
+               GArray *references;
+               CamelSummaryMessageID message_id;
+
                if (irt) {
                        /* The References field is populated from the "References" and/or "In-Reply-To"
                         * headers. If both headers exist, take the first thing in the In-Reply-To header
@@ -3790,8 +2879,8 @@ message_info_new_from_header (CamelFolderSummary *summary,
                }
 
                count = g_slist_length (refs);
-               mi->references = g_malloc (sizeof (*mi->references) + ((count - 1) * sizeof 
(mi->references->references[0])));
-               count = 0;
+               references = g_array_sized_new (FALSE, FALSE, sizeof (guint64), count);
+
                for (scan = refs; scan != NULL; scan = g_slist_next (scan)) {
                        GChecksum *checksum;
 
@@ -3800,84 +2889,18 @@ message_info_new_from_header (CamelFolderSummary *summary,
                        g_checksum_get_digest (checksum, digest, &length);
                        g_checksum_free (checksum);
 
-                       memcpy (mi->references->references[count].id.hash, digest, sizeof 
(mi->message_id.id.hash));
-                       count++;
+                       memcpy (message_id.id.hash, digest, sizeof (message_id.id.hash));
+
+                       g_array_append_val (references, message_id.id.id);
                }
-               mi->references->size = count;
                g_slist_free_full (refs, g_free);
-       }
-
-       return (CamelMessageInfo *) mi;
-}
-
-static void
-message_info_free (CamelFolderSummary *summary,
-                   CamelMessageInfo *info)
-{
-       CamelFolderSummaryClass *class;
-       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
 
-       if (mi->uid) {
-               if (summary) {
-                       camel_folder_summary_lock (summary);
-                       if (g_hash_table_lookup (summary->priv->loaded_infos, mi->uid) == mi) {
-                               g_hash_table_remove (summary->priv->loaded_infos, mi->uid);
-                       }
-                       camel_folder_summary_unlock (summary);
-               }
-               camel_pstring_free (mi->uid);
+               camel_message_info_take_references (mi, references);
        }
-       camel_pstring_free (mi->subject);
-       camel_pstring_free (mi->from);
-       camel_pstring_free (mi->to);
-       camel_pstring_free (mi->cc);
-       camel_pstring_free (mi->mlist);
-       g_free (mi->bodystructure);
-       g_free (mi->references);
-       g_free (mi->preview);
-       camel_flag_list_free (&mi->user_flags);
-       camel_tag_list_free (&mi->user_tags);
-       if (mi->headers)
-               camel_header_param_list_free (mi->headers);
-
-       if (summary) {
-               class = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
-               g_slice_free1 (class->message_info_size, mi);
-       } else
-               g_slice_free (CamelMessageInfoBase, mi);
-}
 
-static CamelMessageContentInfo *
-content_info_new_from_header (CamelFolderSummary *summary,
-                              struct _camel_header_raw *h)
-{
-       CamelMessageContentInfo *ci;
-       const gchar *charset;
-
-       ci = camel_folder_summary_content_info_new (summary);
-
-       charset = camel_iconv_locale_charset ();
-       ci->id = camel_header_msgid_decode (camel_header_raw_find (&h, "content-id", NULL));
-       ci->description = camel_header_decode_string (camel_header_raw_find (&h, "content-description", 
NULL), charset);
-       ci->encoding = camel_content_transfer_encoding_decode (camel_header_raw_find (&h, 
"content-transfer-encoding", NULL));
-       ci->type = camel_content_type_decode (camel_header_raw_find (&h, "content-type", NULL));
-
-       return ci;
-}
-
-static void
-content_info_free (CamelFolderSummary *summary,
-                   CamelMessageContentInfo *ci)
-{
-       CamelFolderSummaryClass *class;
-
-       class = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
+       camel_message_info_set_abort_notifications (mi, FALSE);
 
-       camel_content_type_unref (ci->type);
-       g_free (ci->id);
-       g_free (ci->description);
-       g_free (ci->encoding);
-       g_slice_free1 (class->content_info_size, ci);
+       return mi;
 }
 
 static gchar *
@@ -3893,30 +2916,25 @@ next_uid_string (CamelFolderSummary *summary)
 */
 
 /* must have filter_lock before calling this function */
-static CamelMessageContentInfo *
-summary_build_content_info (CamelFolderSummary *summary,
-                            CamelMessageInfo *msginfo,
-                            CamelMimeParser *mp)
+static void
+summary_traverse_content_with_parser (CamelFolderSummary *summary,
+                                     CamelMessageInfo *msginfo,
+                                     CamelMimeParser *mp)
 {
        gint state;
        gsize len;
        gchar *buffer;
-       CamelMessageContentInfo *info = NULL;
        CamelContentType *ct;
        gint enc_id = -1, chr_id = -1, html_id = -1, idx_id = -1;
        CamelFolderSummaryPrivate *p = summary->priv;
        CamelMimeFilter *mfc;
-       CamelMessageContentInfo *part;
        const gchar *calendar_header;
 
-       d (printf ("building content info\n"));
+       d (printf ("traversing content\n"));
 
        /* start of this part */
        state = camel_mime_parser_step (mp, &buffer, &len);
 
-       if (summary->priv->build_content)
-               info = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->content_info_new_from_parser (summary, mp);
-
        switch (state) {
        case CAMEL_MIME_PARSER_STATE_HEADER:
                /* check content type for indexing, then read body */
@@ -4032,11 +3050,7 @@ summary_build_content_info (CamelFolderSummary *summary,
 
                while (camel_mime_parser_step (mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) {
                        camel_mime_parser_unstep (mp);
-                       part = summary_build_content_info (summary, msginfo, mp);
-                       if (part) {
-                               part->parent = info;
-                               my_list_append ((struct _node **) &info->childs, (struct _node *) part);
-                       }
+                       summary_traverse_content_with_parser (summary, msginfo, mp);
                }
                break;
        case CAMEL_MIME_PARSER_STATE_MESSAGE:
@@ -4044,11 +3058,7 @@ summary_build_content_info (CamelFolderSummary *summary,
                /* update attachments flag as we go */
                camel_message_info_set_flags (msginfo, CAMEL_MESSAGE_ATTACHMENTS, CAMEL_MESSAGE_ATTACHMENTS);
 
-               part = summary_build_content_info (summary, msginfo, mp);
-               if (part) {
-                       part->parent = info;
-                       my_list_append ((struct _node **) &info->childs, (struct _node *) part);
-               }
+               summary_traverse_content_with_parser (summary, msginfo, mp);
                state = camel_mime_parser_step (mp, &buffer, &len);
                if (state != CAMEL_MIME_PARSER_STATE_MESSAGE_END) {
                        g_error ("Bad parser state: Expecing MESSAGE_END or MESSAGE_EOF, got: %d", state);
@@ -4057,39 +3067,34 @@ summary_build_content_info (CamelFolderSummary *summary,
                break;
        }
 
-       d (printf ("finished building content info\n"));
-
-       return info;
+       d (printf ("finished traversion content info\n"));
 }
 
 /* build the content-info, from a message */
 /* this needs the filter lock since it uses filters to perform indexing */
-static CamelMessageContentInfo *
-summary_build_content_info_message (CamelFolderSummary *summary,
+static void
+summary_traverse_content_with_part (CamelFolderSummary *summary,
                                     CamelMessageInfo *msginfo,
                                     CamelMimePart *object)
 {
        CamelDataWrapper *containee;
        gint parts, i;
        CamelFolderSummaryPrivate *p = summary->priv;
-       CamelMessageContentInfo *info = NULL, *child;
        CamelContentType *ct;
-       const struct _camel_header_raw *header;
+       const CamelNameValueArray *headers;
        gboolean is_calendar = FALSE, is_note = FALSE;
-
-       if (summary->priv->build_content)
-               info = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->content_info_new_from_message (summary, 
object);
+       const gchar *header_name, *header_value;
 
        containee = camel_medium_get_content (CAMEL_MEDIUM (object));
 
        if (containee == NULL)
-               return info;
+               return;
 
        /* TODO: I find it odd that get_part and get_content do not
         * add a reference, probably need fixing for multithreading */
 
        /* check for attachments */
-       ct = ((CamelDataWrapper *) containee)->mime_type;
+       ct = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (containee));
        if (camel_content_type_is (ct, "multipart", "*")) {
                if (camel_content_type_is (ct, "multipart", "mixed"))
                        camel_message_info_set_flags (msginfo, CAMEL_MESSAGE_ATTACHMENTS, 
CAMEL_MESSAGE_ATTACHMENTS);
@@ -4105,22 +3110,22 @@ summary_build_content_info_message (CamelFolderSummary *summary,
                camel_message_info_set_flags (msginfo, CAMEL_MESSAGE_SECURE, CAMEL_MESSAGE_SECURE);
        }
 
-       for (header = object->headers; header; header = header->next) {
-               const gchar *value = header->value;
+       headers = camel_medium_get_headers (CAMEL_MEDIUM (object));
+       for (i = 0; camel_name_value_array_get (headers, i, &header_name, &header_value); i++) {
+               const gchar *value = header_value;
 
-               /* skip preceding spaces in the value */
-               while (value && *value && isspace (*value))
+               while (value && *value && g_ascii_isspace (*value))
                        value++;
 
-               if (header->name && value && (
-                   (g_ascii_strcasecmp (header->name, "Content-class") == 0 && g_ascii_strcasecmp (value, 
"urn:content-classes:calendarmessage") == 0) ||
-                   (g_ascii_strcasecmp (header->name, "X-Calendar-Attachment") == 0))) {
+               if (header_name && value && (
+                   (g_ascii_strcasecmp (header_name, "Content-class") == 0 && g_ascii_strcasecmp (value, 
"urn:content-classes:calendarmessage") == 0) ||
+                   (g_ascii_strcasecmp (header_name, "X-Calendar-Attachment") == 0))) {
                        is_calendar = TRUE;
                        if (is_note)
                                break;
                }
 
-               if (header->name && value && g_ascii_strcasecmp (header->name, "X-Evolution-Note") == 0) {
+               if (header_name && value && g_ascii_strcasecmp (header_name, "X-Evolution-Note") == 0) {
                        is_note = TRUE;
                        if (is_calendar)
                                break;
@@ -4139,20 +3144,12 @@ summary_build_content_info_message (CamelFolderSummary *summary,
 
                for (i = 0; i < parts; i++) {
                        CamelMimePart *part = camel_multipart_get_part (CAMEL_MULTIPART (containee), i);
-                       g_return_val_if_fail (part, info);
-                       child = summary_build_content_info_message (summary, msginfo, part);
-                       if (child) {
-                               child->parent = info;
-                               my_list_append ((struct _node **) &info->childs, (struct _node *) child);
-                       }
+                       g_return_if_fail (part);
+                       summary_traverse_content_with_part (summary, msginfo, part);
                }
        } else if (CAMEL_IS_MIME_MESSAGE (containee)) {
                /* for messages we only look at its contents */
-               child = summary_build_content_info_message (summary, msginfo, (CamelMimePart *) containee);
-               if (child) {
-                       child->parent = info;
-                       my_list_append ((struct _node **) &info->childs, (struct _node *) child);
-               }
+               summary_traverse_content_with_part (summary, msginfo, (CamelMimePart *) containee);
        } else if (p->filter_stream
                   && camel_content_type_is (ct, "text", "*")) {
                gint html_id = -1, idx_id = -1;
@@ -4181,327 +3178,6 @@ summary_build_content_info_message (CamelFolderSummary *summary,
                camel_stream_filter_remove (
                        CAMEL_STREAM_FILTER (p->filter_stream), html_id);
        }
-
-       return info;
-}
-
-/**
- * camel_flag_get:
- * @list: the address of a #CamelFlag list
- * @name: name of the flag to get
- *
- * Find the state of the flag @name in @list.
- *
- * Returns: the state of the flag (%TRUE or %FALSE)
- **/
-gboolean
-camel_flag_get (CamelFlag **list,
-                const gchar *name)
-{
-       CamelFlag *flag;
-       flag = *list;
-       while (flag) {
-               if (!strcmp (flag->name, name))
-                       return TRUE;
-               flag = flag->next;
-       }
-       return FALSE;
-}
-
-/**
- * camel_flag_set:
- * @list: the address of a #CamelFlag list
- * @name: name of the flag to set or change
- * @value: the value to set on the flag
- *
- * Set the state of a flag @name in the list @list to @value.
- *
- * Returns: %TRUE if the value of the flag has been changed or %FALSE
- * otherwise
- **/
-gboolean
-camel_flag_set (CamelFlag **list,
-                const gchar *name,
-                gboolean value)
-{
-       CamelFlag *flag, *tmp;
-       gsize tmp_len = 0;
-
-       if (!name)
-               return TRUE;
-
-       /* this 'trick' works because flag->next is the first element */
-       flag = (CamelFlag *) list;
-       while (flag->next) {
-               tmp = flag->next;
-               if (!strcmp (flag->next->name, name)) {
-                       if (!value) {
-                               flag->next = tmp->next;
-                               g_free (tmp);
-                       }
-                       return !value;
-               }
-               flag = tmp;
-       }
-
-       if (value) {
-               tmp_len = sizeof (*tmp) + strlen (name);
-               tmp = g_malloc (tmp_len);
-               g_strlcpy (tmp->name, name, strlen (name) + 1);
-               tmp->next = NULL;
-               flag->next = tmp;
-       }
-       return value;
-}
-
-/**
- * camel_flag_list_size:
- * @list: the address of a #CamelFlag list
- *
- * Get the length of the flag list.
- *
- * Returns: the number of flags in the list
- **/
-gint
-camel_flag_list_size (CamelFlag **list)
-{
-       gint count = 0;
-       CamelFlag *flag;
-
-       flag = *list;
-       while (flag) {
-               count++;
-               flag = flag->next;
-       }
-       return count;
-}
-
-/**
- * camel_flag_list_free:
- * @list: the address of a #CamelFlag list
- *
- * Free the memory associated with the flag list @list.
- **/
-void
-camel_flag_list_free (CamelFlag **list)
-{
-       CamelFlag *flag, *tmp;
-       flag = *list;
-       while (flag) {
-               tmp = flag->next;
-               g_free (flag);
-               flag = tmp;
-       }
-       *list = NULL;
-}
-
-/**
- * camel_flag_list_copy:
- * @to: the address of the #CamelFlag list to copy to
- * @from: the address of the #CamelFlag list to copy from
- *
- * Copy a flag list.
- *
- * Returns: %TRUE if @to is changed or %FALSE otherwise
- **/
-gboolean
-camel_flag_list_copy (CamelFlag **to,
-                      CamelFlag **from)
-{
-       CamelFlag *flag, *tmp;
-       gboolean changed = FALSE;
-
-       if (*to == NULL && from == NULL)
-               return FALSE;
-
-       /* Remove any now-missing flags */
-       flag = (CamelFlag *) to;
-       while (flag->next) {
-               tmp = flag->next;
-               if (!camel_flag_get (from, tmp->name)) {
-                       if (*tmp->name)
-                               changed = TRUE;
-                       flag->next = tmp->next;
-                       g_free (tmp);
-               } else {
-                       flag = tmp;
-               }
-       }
-
-       /* Add any new non-empty flags */
-       flag = *from;
-       while (flag) {
-               if (*flag->name)
-                       changed |= camel_flag_set (to, flag->name, TRUE);
-               flag = flag->next;
-       }
-
-       return changed;
-}
-
-/**
- * camel_tag_get:
- * @list: the address of a #CamelTag list
- * @name: name of the tag to get
- *
- * Find the flag @name in @list and get the value.
- *
- * Returns: the value of the flag  or %NULL if unset
- **/
-const gchar *
-camel_tag_get (CamelTag **list,
-               const gchar *name)
-{
-       CamelTag *tag;
-
-       tag = *list;
-       while (tag) {
-               if (!strcmp (tag->name, name))
-                       return (const gchar *) tag->value;
-               tag = tag->next;
-       }
-       return NULL;
-}
-
-/**
- * camel_tag_set:
- * @list: the address of a #CamelTag list
- * @name: name of the tag to set
- * @value: value to set on the tag
- *
- * Set the tag @name in the tag list @list to @value.
- *
- * Returns: %TRUE if the value on the tag changed or %FALSE otherwise
- **/
-gboolean
-camel_tag_set (CamelTag **list,
-               const gchar *name,
-               const gchar *value)
-{
-       CamelTag *tag, *tmp;
-
-       /* this 'trick' works because tag->next is the first element */
-       tag = (CamelTag *) list;
-       while (tag->next) {
-               tmp = tag->next;
-               if (!strcmp (tmp->name, name)) {
-                       if (value == NULL) { /* clear it? */
-                               tag->next = tmp->next;
-                               g_free (tmp->value);
-                               g_free (tmp);
-                               return TRUE;
-                       } else if (strcmp (tmp->value, value)) { /* has it changed? */
-                               g_free (tmp->value);
-                               tmp->value = g_strdup (value);
-                               return TRUE;
-                       }
-                       return FALSE;
-               }
-               tag = tmp;
-       }
-
-       if (value) {
-               tmp = g_malloc (sizeof (*tmp) + strlen (name));
-               g_strlcpy (tmp->name, name, strlen (name) + 1);
-               tmp->value = g_strdup (value);
-               tmp->next = NULL;
-               tag->next = tmp;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-/**
- * camel_tag_list_size:
- * @list: the address of a #CamelTag list
- *
- * Get the number of tags present in the tag list @list.
- *
- * Returns: the number of tags
- **/
-gint
-camel_tag_list_size (CamelTag **list)
-{
-       gint count = 0;
-       CamelTag *tag;
-
-       tag = *list;
-       while (tag) {
-               count++;
-               tag = tag->next;
-       }
-       return count;
-}
-
-static void
-rem_tag (gchar *key,
-         gchar *value,
-         CamelTag **to)
-{
-       camel_tag_set (to, key, NULL);
-}
-
-/**
- * camel_tag_list_copy:
- * @to: the address of the #CamelTag list to copy to
- * @from: the address of the #CamelTag list to copy from
- *
- * Copy a tag list.
- *
- * Returns: %TRUE if @to is changed or %FALSE otherwise
- **/
-gboolean
-camel_tag_list_copy (CamelTag **to,
-                     CamelTag **from)
-{
-       gint changed = FALSE;
-       CamelTag *tag;
-       GHashTable *left;
-
-       if (*to == NULL && from == NULL)
-               return FALSE;
-
-       left = g_hash_table_new (g_str_hash, g_str_equal);
-       tag = *to;
-       while (tag) {
-               g_hash_table_insert (left, tag->name, tag);
-               tag = tag->next;
-       }
-
-       tag = *from;
-       while (tag) {
-               changed |= camel_tag_set (to, tag->name, tag->value);
-               g_hash_table_remove (left, tag->name);
-               tag = tag->next;
-       }
-
-       if (g_hash_table_size (left) > 0) {
-               g_hash_table_foreach (left, (GHFunc) rem_tag, to);
-               changed = TRUE;
-       }
-       g_hash_table_destroy (left);
-
-       return changed;
-}
-
-/**
- * camel_tag_list_free:
- * @list: the address of a #CamelTag list
- *
- * Free the tag list @list.
- **/
-void
-camel_tag_list_free (CamelTag **list)
-{
-       CamelTag *tag, *tmp;
-       tag = *list;
-       while (tag) {
-               tmp = tag->next;
-               g_free (tag->value);
-               g_free (tag);
-               tag = tmp;
-       }
-       *list = NULL;
 }
 
 static struct flag_names_t {
@@ -4559,684 +3235,25 @@ camel_system_flag_get (CamelMessageFlags flags,
 }
 
 /**
- * camel_message_info_new:
- * @summary: (nullable): a #CamelFolderSummary object or %NULL
- *
- * Create a new #CamelMessageInfo.
- *
- * Returns: (transfer full) (type CamelMessageInfo): a new #CamelMessageInfo
- **/
-gpointer
-camel_message_info_new (CamelFolderSummary *summary)
-{
-       CamelFolderSummaryClass *class;
-       CamelMessageInfo *info;
-       gsize message_info_size;
-
-       if (summary != NULL) {
-               class = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
-               g_return_val_if_fail (class->message_info_size > 0, NULL);
-               message_info_size = class->message_info_size;
-       } else {
-               message_info_size = sizeof (CamelMessageInfoBase);
-       }
-
-       info = g_slice_alloc0 (message_info_size);
-       info->refcount = 1;
-       info->summary = summary;
-
-       /* We assume that mi is always dirty unless freshly read or just saved*/
-       ((CamelMessageInfoBase *) info)->dirty = TRUE;
-
-       return info;
-}
-
-/**
- * camel_message_info_ref:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Reference an info.
- * Returns: (transfer full) (type CamelMessageInfo):
- **/
-gpointer
-camel_message_info_ref (gpointer o)
-{
-       CamelMessageInfo *mi = o;
-
-       g_return_val_if_fail (mi != NULL, NULL);
-       g_return_val_if_fail (mi->refcount > 0, NULL);
-
-       g_atomic_int_inc (&mi->refcount);
-
-       return o;
-}
-
-/**
- * camel_message_info_new_from_header:
+ * camel_message_info_new_from_headers:
  * @summary: a #CamelFolderSummary object or %NULL
- * @header: raw header
+ * @headers: a #CamelNameValueArray
  *
  * Create a new #CamelMessageInfo pre-populated with info from
- * @header.
+ * @headers.
  *
  * Returns: (transfer full): a new #CamelMessageInfo
+ *
+ * Since: 3.24
  **/
 CamelMessageInfo *
-camel_message_info_new_from_header (CamelFolderSummary *summary,
-                                    struct _camel_header_raw *header)
+camel_message_info_new_from_headers (CamelFolderSummary *summary,
+                                    const CamelNameValueArray *headers)
 {
        if (summary != NULL)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->
-                       message_info_new_from_header (summary, header);
-       else
-               return message_info_new_from_header (NULL, header);
-}
-
-/**
- * camel_message_info_unref:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Unref's and potentially frees a #CamelMessageInfo and its contents.
- **/
-void
-camel_message_info_unref (gpointer o)
-{
-       CamelMessageInfo *mi = o;
-
-       g_return_if_fail (mi != NULL);
-       g_return_if_fail (mi->refcount > 0);
-
-       if (g_atomic_int_dec_and_test (&mi->refcount)) {
-               if (mi->summary != NULL) {
-                       CamelFolderSummaryClass *class;
-
-                       /* FIXME This is kinda busted, should really
-                        *       be handled by message_info_free(). */
-                       if (mi->summary->priv->build_content
-                           && ((CamelMessageInfoBase *) mi)->content) {
-                               camel_folder_summary_content_info_free (
-                                       mi->summary,
-                                       ((CamelMessageInfoBase *) mi)->content);
-                               ((CamelMessageInfoBase *) mi)->content = NULL;
-                       }
-
-                       class = CAMEL_FOLDER_SUMMARY_GET_CLASS (mi->summary);
-                       g_return_if_fail (class->message_info_free != NULL);
-
-                       class->message_info_free (mi->summary, mi);
-               } else {
-                       message_info_free (NULL, mi);
-               }
-       }
-}
-
-/**
- * camel_message_info_clone:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Duplicate a #CamelMessageInfo.
- *
- * Returns: (transfer full) (type CamelMessageInfo): the duplicated #CamelMessageInfo
- **/
-gpointer
-camel_message_info_clone (gconstpointer o)
-{
-       const CamelMessageInfo *mi = o;
-
-       if (mi->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (mi->summary)->message_info_clone (mi->summary, mi);
+               return CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_new_from_headers (summary, 
headers);
        else
-               return message_info_clone (NULL, mi);
-}
-
-/**
- * camel_message_info_get_ptr:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- * @id: info to get
- *
- * Generic accessor method for getting pointer data.
- *
- * Returns: (transfer none): the pointer data
- *
- * Since: 3.22
- **/
-gconstpointer
-camel_message_info_get_ptr (gconstpointer info,
-                           gint id)
-{
-       const CamelMessageInfo *nfo = info;
-
-       g_return_val_if_fail (info != NULL, NULL);
-
-       if (nfo->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (nfo->summary)->info_ptr (nfo, id);
-       else
-               return info_ptr (nfo, id);
-}
-
-/**
- * camel_message_info_get_uint32:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- * @id: info to get
- *
- * Generic accessor method for getting 32bit unsigned integer data.
- *
- * Returns: the guint32 data
- *
- * Since: 3.22
- **/
-guint32
-camel_message_info_get_uint32 (gconstpointer info,
-                              gint id)
-{
-       const CamelMessageInfo *nfo = info;
-
-       g_return_val_if_fail (info != NULL, 0);
-
-       if (nfo->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (nfo->summary)->info_uint32 (nfo, id);
-       else
-               return info_uint32 (nfo, id);
-}
-
-/**
- * camel_message_info_get_time:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- * @id: info to get
- *
- * Generic accessor method for getting time_t data.
- *
- * Returns: the time_t data
- *
- * Since: 3.22
- **/
-time_t
-camel_message_info_get_time (gconstpointer info,
-                            gint id)
-{
-       const CamelMessageInfo *nfo = info;
-
-       g_return_val_if_fail (info != NULL, (time_t) 0);
-
-       if (nfo->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (nfo->summary)->info_time (nfo, id);
-       else
-               return info_time (nfo, id);
-}
-
-/**
- * camel_message_info_get_uid:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the uid of the #CamelMessageInfo
- *
- * Returns: the uid
- *
- * Since: 3.22
- **/
-const gchar *
-camel_message_info_get_uid (gconstpointer info)
-{
-       const CamelMessageInfo *nfo = info;
-
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return nfo->uid;
-}
-
-/**
- * camel_message_info_get_subject:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the subject of the #CamelMessageInfo
- *
- * Returns: the subject
- *
- * Since: 3.22
- **/
-const gchar *
-camel_message_info_get_subject (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_SUBJECT);
-}
-
-/**
- * camel_message_info_get_preview:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the preview of the #CamelMessageInfo
- *
- * Returns: the preview
- *
- * Since: 3.22
- **/
-const gchar *
-camel_message_info_get_preview (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_PREVIEW);
-}
-
-/**
- * camel_message_info_get_from:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the from field of the #CamelMessageInfo
- *
- * Returns: the from field
- *
- * Since: 3.22
- **/
-const gchar *
-camel_message_info_get_from (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_FROM);
-}
-
-/**
- * camel_message_info_get_to:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the to field of the #CamelMessageInfo
- *
- * Returns: the to field
- *
- * Since: 3.22
- **/
-const gchar *
-camel_message_info_get_to (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_TO);
-}
-
-/**
- * camel_message_info_get_cc:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the cc field of the #CamelMessageInfo
- *
- * Returns: the cc field
- *
- * Since: 3.22
- **/
-const gchar *
-camel_message_info_get_cc (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_CC);
-}
-
-/**
- * camel_message_info_get_mlist:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the mlist of the #CamelMessageInfo
- *
- * Returns: the mlist
- *
- * Since: 3.22
- **/
-const gchar *
-camel_message_info_get_mlist (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_MLIST);
-}
-
-/**
- * camel_message_info_get_flags:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the flags of the #CamelMessageInfo
- *
- * Returns: the flags
- *
- * Since: 3.22
- **/
-guint32
-camel_message_info_get_flags (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, 0);
-
-       return camel_message_info_get_uint32 (info, CAMEL_MESSAGE_INFO_FLAGS);
-}
-
-/**
- * camel_message_info_get_size:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the size of the #CamelMessageInfo
- *
- * Returns: the size
- *
- * Since: 3.22
- **/
-guint32
-camel_message_info_get_size (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, 0);
-
-       return camel_message_info_get_uint32 (info, CAMEL_MESSAGE_INFO_SIZE);
-}
-
-/**
- * camel_message_info_get_date_sent:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the sent date of the #CamelMessageInfo
- *
- * Returns: the sent date
- *
- * Since: 3.22
- **/
-time_t
-camel_message_info_get_date_sent (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, (time_t) 0);
-
-       return camel_message_info_get_time (info, CAMEL_MESSAGE_INFO_DATE_SENT);
-}
-
-/**
- * camel_message_info_get_date_received:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the received date of the #CamelMessageInfo
- *
- * Returns: the received date
- *
- * Since: 3.22
- **/
-time_t
-camel_message_info_get_date_received (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, (time_t) 0);
-
-       return camel_message_info_get_time (info, CAMEL_MESSAGE_INFO_DATE_RECEIVED);
-}
-
-/**
- * camel_message_info_get_user_flag:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- * @id: user flag to get
- *
- * Get the state of a user flag named @id.
- *
- * Returns: the state of the user flag
- *
- * Since: 3.22
- **/
-gboolean
-camel_message_info_get_user_flag (gconstpointer info,
-                                 const gchar *id)
-{
-       const CamelMessageInfo *nfo = info;
-
-       g_return_val_if_fail (info != NULL, FALSE);
-
-       if (nfo->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (nfo->summary)->info_user_flag (nfo, id);
-       else
-               return info_user_flag (nfo, id);
-}
-
-/**
- * camel_message_info_get_user_tag:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- * @id: user tag to get
- *
- * Get the value of a user tag named @id.
- *
- * Returns: the value of the user tag
- *
- * Since: 3.22
- **/
-const gchar *
-camel_message_info_get_user_tag (gconstpointer info,
-                                const gchar *id)
-{
-       const CamelMessageInfo *nfo = info;
-
-       g_return_val_if_fail (info != NULL, NULL);
-
-       if (nfo->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (nfo->summary)->info_user_tag (nfo, id);
-       else
-               return info_user_tag (nfo, id);
-}
-
-/**
- * camel_message_info_get_message_id:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the #CamelSummaryMessageID of the #CamelMessageInfo
- *
- * Returns: the id of the message
- *
- * Since: 3.22
- **/
-const CamelSummaryMessageID *
-camel_message_info_get_message_id (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_MESSAGE_ID);
-}
-
-/**
- * camel_message_info_get_references:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the #CamelSummaryReferences of the #CamelMessageInfo
- *
- * Returns: the references of the message
- *
- * Since: 3.22
- **/
-const CamelSummaryReferences *
-camel_message_info_get_references (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_REFERENCES);
-}
-
-/**
- * camel_message_info_get_user_flags:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the #CamelFlag of the #CamelMessageInfo
- *
- * Returns: the flags of the message
- *
- * Since: 3.22
- **/
-const CamelFlag *
-camel_message_info_get_user_flags (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_USER_FLAGS);
-}
-
-/**
- * camel_message_info_get_user_tags:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the #CamelTag of the #CamelMessageInfo
- *
- * Returns: the tags of the message
- *
- * Since: 3.22
- **/
-const CamelTag *
-camel_message_info_get_user_tags (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_USER_TAGS);
-}
-
-/**
- * camel_message_info_get_headers:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the #CamelHeaderParam of the #CamelMessageInfo
- *
- * Returns: the headers of the message
- *
- * Since: 3.22
- **/
-const CamelHeaderParam *
-camel_message_info_get_headers (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_HEADERS);
-}
-
-/**
- * camel_message_info_get_content:
- * @info: (type CamelMessageInfo): a #CamelMessageInfo
- *
- * Get the #CamelMessageContentInfo of the #CamelMessageInfo
- *
- * Returns: the content of the message
- *
- * Since: 3.22
- **/
-const CamelMessageContentInfo *
-camel_message_info_get_content (gconstpointer info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return camel_message_info_get_ptr (info, CAMEL_MESSAGE_INFO_CONTENT);
-}
-
-/**
- * camel_message_info_set_flags:
- * @info: a #CamelMessageInfo
- * @flags: mask of flags to change
- * @set: state the flags should be changed to
- *
- * Change the state of the system flags on the #CamelMessageInfo
- *
- * Returns: %TRUE if any of the flags changed or %FALSE otherwise
- **/
-gboolean
-camel_message_info_set_flags (CamelMessageInfo *info,
-                              CamelMessageFlags flags,
-                              guint32 set)
-{
-       if (info->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (info->summary)->info_set_flags (info, flags, set);
-       else
-               return info_set_flags (info, flags, set);
-}
-
-/**
- * camel_message_info_set_user_flag:
- * @info: a #CamelMessageInfo
- * @id: name of the user flag to set
- * @state: state to set the flag to
- *
- * Set the state of a user flag on a #CamelMessageInfo.
- *
- * Returns: %TRUE if the state changed or %FALSE otherwise
- **/
-gboolean
-camel_message_info_set_user_flag (CamelMessageInfo *info,
-                                  const gchar *id,
-                                  gboolean state)
-{
-       if (info->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (info->summary)->info_set_user_flag (info, id, state);
-       else
-               return info_set_user_flag (info, id, state);
-}
-
-/**
- * camel_message_info_set_user_tag:
- * @info: a #CamelMessageInfo
- * @id: name of the user tag to set
- * @val: value to set
- *
- * Set the value of a user tag on a #CamelMessageInfo.
- *
- * Returns: %TRUE if the value changed or %FALSE otherwise
- **/
-gboolean
-camel_message_info_set_user_tag (CamelMessageInfo *info,
-                                 const gchar *id,
-                                 const gchar *val)
-{
-       if (info->summary)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (info->summary)->info_set_user_tag (info, id, val);
-       else
-               return info_set_user_tag (info, id, val);
-}
-
-void
-camel_content_info_dump (CamelMessageContentInfo *ci,
-                         gint depth)
-{
-       gchar *p;
-
-       p = alloca (depth * 4 + 1);
-       memset (p, ' ', depth * 4);
-       p[depth * 4] = 0;
-
-       if (ci == NULL) {
-               printf ("%s<empty>\n", p);
-               return;
-       }
-
-       if (ci->type)
-               printf (
-                       "%scontent-type: %s/%s\n",
-                       p, ci->type->type ? ci->type->type : "(null)",
-                       ci->type->subtype ? ci->type->subtype : "(null)");
-       else
-               printf ("%scontent-type: <unset>\n", p);
-       printf (
-               "%scontent-transfer-encoding: %s\n",
-               p, ci->encoding ? ci->encoding : "(null)");
-       printf (
-               "%scontent-description: %s\n",
-               p, ci->description ? ci->description : "(null)");
-       printf ("%ssize: %lu\n", p, (gulong) ci->size);
-       ci = ci->childs;
-       while (ci) {
-               camel_content_info_dump (ci, depth + 1);
-               ci = ci->next;
-       }
-}
-
-void
-camel_message_info_dump (CamelMessageInfo *info)
-{
-       if (info == NULL) {
-               printf ("No message?\n");
-               return;
-       }
-
-       printf ("Subject: %s\n", camel_message_info_get_subject (info));
-       printf ("To: %s\n", camel_message_info_get_to (info));
-       printf ("Cc: %s\n", camel_message_info_get_cc (info));
-       printf ("mailing list: %s\n", camel_message_info_get_mlist (info));
-       printf ("From: %s\n", camel_message_info_get_from (info));
-       printf ("UID: %s\n", camel_message_info_get_uid (info));
-       printf ("Flags: %04x\n", camel_message_info_get_flags (info));
-       camel_content_info_dump (((CamelMessageInfoBase *) info)->content, 0);
+               return message_info_new_from_headers (NULL, headers);
 }
 
 /**
@@ -5270,47 +3287,3 @@ camel_folder_summary_unlock (CamelFolderSummary *summary)
 
        g_rec_mutex_unlock (&summary->priv->summary_lock);
 }
-
-gint
-bdata_extract_digit (/* const */ gchar **part)
-{
-       if (!part || !*part || !**part)
-               return 0;
-
-       if (**part == ' ')
-               *part += 1;
-
-       if (!**part)
-               return 0;
-
-       return strtoul (*part, part, 10);
-}
-
-/* expecting "digit-value", where digit is length of the value */
-gchar *
-bdata_extract_string (/* const */ gchar **part)
-{
-       gint len, has_len;
-       gchar *val;
-
-       len = bdata_extract_digit (part);
-
-       /* might be a '-' sign */
-       if (part && *part && **part)
-               *part += 1;
-
-       if (len <= 0 || !part || !*part || !**part)
-               return g_strdup ("");
-
-       if (!**part)
-               return g_strdup ("");
-
-       has_len = strlen (*part);
-       if (has_len < len)
-               len = has_len;
-
-       val = g_strndup (*part, len);
-       *part += len;
-
-       return val;
-}
diff --git a/src/camel/camel-folder-summary.h b/src/camel/camel-folder-summary.h
index d6dfff0..8fb53bb 100644
--- a/src/camel/camel-folder-summary.h
+++ b/src/camel/camel-folder-summary.h
@@ -28,7 +28,7 @@
 #include <time.h>
 
 #include <camel/camel-index.h>
-#include <camel/camel-memchunk.h>
+#include <camel/camel-message-info.h>
 #include <camel/camel-mime-message.h>
 #include <camel/camel-mime-parser.h>
 
@@ -60,156 +60,6 @@ typedef struct _CamelFolderSummary CamelFolderSummary;
 typedef struct _CamelFolderSummaryClass CamelFolderSummaryClass;
 typedef struct _CamelFolderSummaryPrivate CamelFolderSummaryPrivate;
 
-typedef struct _CamelMessageInfo CamelMessageInfo;
-typedef struct _CamelMessageInfoBase CamelMessageInfoBase;
-
-typedef struct _CamelMessageContentInfo CamelMessageContentInfo;
-
-/* A tree of message content info structures
- * describe the content structure of the message (if it has any) */
-struct _CamelMessageContentInfo {
-       CamelMessageContentInfo *next;
-
-       CamelMessageContentInfo *childs;
-       CamelMessageContentInfo *parent;
-
-       CamelContentType *type;
-       gchar *id;
-       gchar *description;
-       gchar *encoding;                /* this should be an enum?? */
-       guint32 size;
-};
-
-/* system flag bits */
-typedef enum _CamelMessageFlags {
-       CAMEL_MESSAGE_ANSWERED = 1 << 0,
-       CAMEL_MESSAGE_DELETED = 1 << 1,
-       CAMEL_MESSAGE_DRAFT = 1 << 2,
-       CAMEL_MESSAGE_FLAGGED = 1 << 3,
-       CAMEL_MESSAGE_SEEN = 1 << 4,
-
-       /* these aren't really system flag bits, but are convenience flags */
-       CAMEL_MESSAGE_ATTACHMENTS = 1 << 5,
-       CAMEL_MESSAGE_ANSWERED_ALL = 1 << 6,
-       CAMEL_MESSAGE_JUNK = 1 << 7,
-       CAMEL_MESSAGE_SECURE = 1 << 8,
-       CAMEL_MESSAGE_NOTJUNK = 1 << 9,
-       CAMEL_MESSAGE_FORWARDED = 1 << 10,
-
-       /* following flags are for the folder, and are not really permanent flags */
-       CAMEL_MESSAGE_FOLDER_FLAGGED = 1 << 16, /* for use by the folder implementation */
-       /* flags after 1 << 16 are used by camel providers,
- *         if adding non permanent flags, add them to the end  */
-
-       CAMEL_MESSAGE_JUNK_LEARN = 1 << 30, /* used when setting CAMEL_MESSAGE_JUNK flag
-                                            * to say that we request junk plugin
-                                            * to learn that message as junk/non junk */
-       CAMEL_MESSAGE_USER = 1 << 31 /* supports user flags */
-} CamelMessageFlags;
-
-/* Changes to system flags will NOT trigger a folder changed event */
-#define CAMEL_MESSAGE_SYSTEM_MASK (0xffff << 16)
-
-typedef struct _CamelFlag {
-       struct _CamelFlag *next;
-       gchar name[1];          /* name allocated as part of the structure */
-} CamelFlag;
-
-typedef struct _CamelTag {
-       struct _CamelTag *next;
-       gchar *value;
-       gchar name[1];          /* name allocated as part of the structure */
-} CamelTag;
-
-/* a summary messageid is a 64 bit identifier (partial md5 hash) */
-typedef struct _CamelSummaryMessageID {
-       union {
-               guint64 id;
-               guchar hash[8];
-               struct {
-                       guint32 hi;
-                       guint32 lo;
-               } part;
-       } id;
-} CamelSummaryMessageID;
-
-/* summary references is a fixed size array of references */
-typedef struct _CamelSummaryReferences {
-       gint size;
-       CamelSummaryMessageID references[1];
-} CamelSummaryReferences;
-
-/* accessor id's */
-enum {
-       CAMEL_MESSAGE_INFO_SUBJECT,
-       CAMEL_MESSAGE_INFO_FROM,
-       CAMEL_MESSAGE_INFO_TO,
-       CAMEL_MESSAGE_INFO_CC,
-       CAMEL_MESSAGE_INFO_MLIST,
-
-       CAMEL_MESSAGE_INFO_FLAGS,
-       CAMEL_MESSAGE_INFO_SIZE,
-
-       CAMEL_MESSAGE_INFO_DATE_SENT,
-       CAMEL_MESSAGE_INFO_DATE_RECEIVED,
-
-       CAMEL_MESSAGE_INFO_MESSAGE_ID,
-       CAMEL_MESSAGE_INFO_REFERENCES,
-       CAMEL_MESSAGE_INFO_USER_FLAGS,
-       CAMEL_MESSAGE_INFO_USER_TAGS,
-
-       CAMEL_MESSAGE_INFO_HEADERS,
-       CAMEL_MESSAGE_INFO_PREVIEW,
-       CAMEL_MESSAGE_INFO_CONTENT,
-       CAMEL_MESSAGE_INFO_LAST
-};
-
-/* information about a given message, use accessors */
-struct _CamelMessageInfo {
-       CamelFolderSummary *summary;
-
-       volatile gint refcount;
-       const gchar *uid;
-       /*FIXME: Make it work with the CAMEL_MESSADE_DB_DIRTY flag instead of another 4 bytes*/
-       guint dirty : 1;
-};
-
-/* For classes wishing to do the provided i/o, or for anonymous users,
- * they must subclass or use this messageinfo structure */
-/* Otherwise they can do their own thing entirely */
-struct _CamelMessageInfoBase {
-       CamelFolderSummary *summary;
-
-       volatile gint refcount;
-       const gchar *uid;
-       /*FIXME: Make it work with the CAMEL_MESSADE_DB_DIRTY flag instead of another 4 bytes*/
-       guint dirty : 1;
-
-       const gchar *subject;
-       const gchar *from;
-       const gchar *to;
-       const gchar *cc;
-       const gchar *mlist;
-
-       CamelMessageFlags flags;
-       guint32 size;
-
-       time_t date_sent;
-       time_t date_received;
-
-       CamelSummaryMessageID message_id;
-       CamelSummaryReferences *references;/* from parent to root */
-
-       struct _CamelFlag *user_flags;
-       struct _CamelTag *user_tags;
-
-       /* tree of content description - NULL if it is not available */
-       CamelMessageContentInfo *content;
-       struct _camel_header_param *headers;
-       gchar *preview;
-       gchar *bodystructure;
-};
-
 /**
  * CamelFolderSummaryFlags:
  * @CAMEL_FOLDER_SUMMARY_DIRTY:
@@ -226,17 +76,6 @@ typedef enum {
 struct _CamelFolderSummary {
        GObject parent;
        CamelFolderSummaryPrivate *priv;
-
-       /* header info */
-       guint32 version;        /* version of file loaded/loading */
-       time_t time;            /* timestamp for this summary (for implementors to use) */
-       CamelFolderSummaryFlags flags;
-
-       const gchar *collate;
-       const gchar *sort_by;
-
-       /* Future ABI expansion */
-       gpointer later[4];
 };
 
 struct _CamelMIRecord;
@@ -245,40 +84,24 @@ struct _CamelFIRecord;
 struct _CamelFolderSummaryClass {
        GObjectClass parent_class;
 
-       /* sizes of memory objects */
-       gsize message_info_size;
-       gsize content_info_size;
+       GType message_info_type;
+       const gchar *collate;
+       const gchar *sort_by;
 
-       /* Load/Save folder summary from DB*/
-       gboolean        (*summary_header_from_db)
+       /* Load/Save folder summary*/
+       gboolean        (*summary_header_load)
                                        (CamelFolderSummary *summary,
                                         struct _CamelFIRecord *fir);
        struct _CamelFIRecord *
-                       (*summary_header_to_db)
+                       (*summary_header_save)
                                        (CamelFolderSummary *summary,
                                         GError **error);
-       CamelMessageInfo *
-                       (*message_info_from_db)
-                                       (CamelFolderSummary *summary,
-                                        struct _CamelMIRecord *mir);
-       struct _CamelMIRecord *
-                       (*message_info_to_db)
-                                       (CamelFolderSummary *summary,
-                                        CamelMessageInfo *info);
-       CamelMessageContentInfo *
-                       (*content_info_from_db)
-                                       (CamelFolderSummary *summary,
-                                        struct _CamelMIRecord *mir);
-       gboolean        (*content_info_to_db)
-                                       (CamelFolderSummary *summary,
-                                        CamelMessageContentInfo *info,
-                                        struct _CamelMIRecord *mir);
 
-       /* create/save/load an individual message info */
+       /* create an individual message info */
        CamelMessageInfo *
-                       (*message_info_new_from_header)
+                       (*message_info_new_from_headers)
                                        (CamelFolderSummary *summary,
-                                        struct _camel_header_raw *header);
+                                        const CamelNameValueArray *headers);
        CamelMessageInfo *
                        (*message_info_new_from_parser)
                                        (CamelFolderSummary *summary,
@@ -286,32 +109,8 @@ struct _CamelFolderSummaryClass {
        CamelMessageInfo *
                        (*message_info_new_from_message)
                                        (CamelFolderSummary *summary,
-                                        CamelMimeMessage *message,
-                                        const gchar *bodystructure);
-       void            (*message_info_free)
-                                       (CamelFolderSummary *summary,
-                                        CamelMessageInfo *ci);
-       CamelMessageInfo *
-                       (*message_info_clone)
-                                       (CamelFolderSummary *summary,
-                                        const CamelMessageInfo *info);
+                                        CamelMimeMessage *message);
 
-       /* save/load individual content info's */
-       CamelMessageContentInfo *
-                       (*content_info_new_from_header)
-                                       (CamelFolderSummary *summary,
-                                        struct _camel_header_raw *header);
-       CamelMessageContentInfo *
-                       (*content_info_new_from_parser)
-                                       (CamelFolderSummary *summary,
-                                        CamelMimeParser *parser);
-       CamelMessageContentInfo *
-                       (*content_info_new_from_message)
-                                       (CamelFolderSummary *summary,
-                                        CamelMimePart *mime_part);
-       void            (*content_info_free)
-                                       (CamelFolderSummary *summary,
-                                        CamelMessageContentInfo *ci);
        CamelMessageInfo *
                        (*message_info_from_uid)
                                        (CamelFolderSummary *summary,
@@ -321,34 +120,8 @@ struct _CamelFolderSummaryClass {
        gchar *         (*next_uid_string)
                                        (CamelFolderSummary *summary);
 
-       /* virtual accessors on messageinfo's */
-       gconstpointer   (*info_ptr)     (const CamelMessageInfo *info,
-                                        gint id);
-       guint32         (*info_uint32)  (const CamelMessageInfo *info,
-                                        gint id);
-       time_t          (*info_time)    (const CamelMessageInfo *info,
-                                        gint id);
-
-       gboolean        (*info_user_flag)
-                                       (const CamelMessageInfo *info,
-                                        const gchar *id);
-       const gchar *   (*info_user_tag)
-                                       (const CamelMessageInfo *info,
-                                        const gchar *id);
-
-       /* set accessors for the modifyable bits */
-       gboolean        (*info_set_user_flag)
-                                       (CamelMessageInfo *info,
-                                        const gchar *id,
-                                        gboolean state);
-       gboolean        (*info_set_user_tag)
-                                       (CamelMessageInfo *info,
-                                        const gchar *id,
-                                        const gchar *val);
-       gboolean        (*info_set_flags)
-                                       (CamelMessageInfo *info,
-                                        guint32 mask,
-                                        guint32 set);
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_folder_summary_get_type   (void);
@@ -357,7 +130,19 @@ CamelFolderSummary *
 
 struct _CamelFolder *
                camel_folder_summary_get_folder (CamelFolderSummary *summary);
-
+guint32                camel_folder_summary_get_flags  (CamelFolderSummary *summary);
+void           camel_folder_summary_set_flags  (CamelFolderSummary *summary,
+                                                guint32 flags);
+gint64         camel_folder_summary_get_timestamp
+                                               (CamelFolderSummary *summary);
+void           camel_folder_summary_set_timestamp
+                                               (CamelFolderSummary *summary,
+                                                gint64 timestamp);
+guint32                camel_folder_summary_get_version
+                                               (CamelFolderSummary *summary);
+void           camel_folder_summary_set_version
+                                               (CamelFolderSummary *summary,
+                                                guint32 version);
 guint32                camel_folder_summary_get_saved_count
                                                (CamelFolderSummary *summary);
 guint32                camel_folder_summary_get_unread_count
@@ -374,16 +159,6 @@ guint32            camel_folder_summary_get_visible_count
 void           camel_folder_summary_set_index  (CamelFolderSummary *summary,
                                                 CamelIndex *index);
 CamelIndex *   camel_folder_summary_get_index  (CamelFolderSummary *summary);
-void           camel_folder_summary_set_build_content
-                                               (CamelFolderSummary *summary,
-                                                gboolean state);
-gboolean       camel_folder_summary_get_build_content
-                                               (CamelFolderSummary *summary);
-void           camel_folder_summary_set_need_preview
-                                               (CamelFolderSummary *summary,
-                                                gboolean preview);
-gboolean       camel_folder_summary_get_need_preview
-                                               (CamelFolderSummary *summary);
 guint32                camel_folder_summary_next_uid   (CamelFolderSummary *summary);
 void           camel_folder_summary_set_next_uid
                                                (CamelFolderSummary *summary,
@@ -393,20 +168,19 @@ guint32           camel_folder_summary_get_next_uid
 gchar *                camel_folder_summary_next_uid_string
                                                (CamelFolderSummary *summary);
 
-/* load/save the full summary from/to the db */
-gboolean       camel_folder_summary_save_to_db (CamelFolderSummary *summary,
+/* load/save the full summary */
+gboolean       camel_folder_summary_save       (CamelFolderSummary *summary,
                                                 GError **error);
-gboolean       camel_folder_summary_load_from_db
-                                               (CamelFolderSummary *summary,
+gboolean       camel_folder_summary_load       (CamelFolderSummary *summary,
                                                 GError **error);
 
 /* only load the header */
-gboolean       camel_folder_summary_header_load_from_db
+gboolean       camel_folder_summary_header_load
                                                (CamelFolderSummary *summary,
                                                 struct _CamelStore *store,
                                                 const gchar *folder_name,
                                                 GError **error);
-gboolean       camel_folder_summary_header_save_to_db
+gboolean       camel_folder_summary_header_save
                                                (CamelFolderSummary *summary,
                                                 GError **error);
 
@@ -415,9 +189,9 @@ void                camel_folder_summary_touch      (CamelFolderSummary *summary);
 
 /* Just build raw summary items */
 CamelMessageInfo *
-               camel_folder_summary_info_new_from_header
+               camel_folder_summary_info_new_from_headers
                                                (CamelFolderSummary *summary,
-                                                struct _camel_header_raw *headers);
+                                                const CamelNameValueArray *headers);
 CamelMessageInfo *
                camel_folder_summary_info_new_from_parser
                                                (CamelFolderSummary *summary,
@@ -425,35 +199,20 @@ CamelMessageInfo *
 CamelMessageInfo *
                camel_folder_summary_info_new_from_message
                                                (CamelFolderSummary *summary,
-                                                CamelMimeMessage *message,
-                                                const gchar *bodystructure);
-
-CamelMessageContentInfo *
-               camel_folder_summary_content_info_new
-                                               (CamelFolderSummary *summary);
-void           camel_folder_summary_content_info_free
-                                               (CamelFolderSummary *summary,
-                                                CamelMessageContentInfo *ci);
-
-void           camel_folder_summary_add_preview
-                                               (CamelFolderSummary *summary,
-                                                CamelMessageInfo *info);
+                                                CamelMimeMessage *message);
 
 /* add a new raw summary item */
 void           camel_folder_summary_add        (CamelFolderSummary *summary,
-                                                CamelMessageInfo *info);
-
-/* insert mi to summary */
-void           camel_folder_summary_insert     (CamelFolderSummary *summary,
                                                 CamelMessageInfo *info,
-                                                gboolean load);
+                                                gboolean force_keep_uid);
 
 gboolean       camel_folder_summary_remove     (CamelFolderSummary *summary,
                                                 CamelMessageInfo *info);
 
 gboolean       camel_folder_summary_remove_uid (CamelFolderSummary *summary,
                                                 const gchar *uid);
-gboolean       camel_folder_summary_remove_uids (CamelFolderSummary *summary,
+gboolean       camel_folder_summary_remove_uids
+                                               (CamelFolderSummary *summary,
                                                 GList *uids);
 
 /* remove all items */
@@ -499,134 +258,15 @@ void             camel_folder_summary_prepare_fetch_all
 void           camel_folder_summary_lock       (CamelFolderSummary *summary);
 void           camel_folder_summary_unlock     (CamelFolderSummary *summary);
 
-/* message flag operations */
-gboolean       camel_flag_get                  (CamelFlag **list,
-                                                const gchar *name);
-gboolean       camel_flag_set                  (CamelFlag **list,
-                                                const gchar *name,
-                                                gboolean value);
-gboolean       camel_flag_list_copy            (CamelFlag **to,
-                                                CamelFlag **from);
-gint           camel_flag_list_size            (CamelFlag **list);
-void           camel_flag_list_free            (CamelFlag **list);
-
 CamelMessageFlags
                camel_system_flag               (const gchar *name);
 gboolean       camel_system_flag_get           (CamelMessageFlags flags,
                                                 const gchar *name);
 
-/* message tag operations */
-const gchar *  camel_tag_get                   (CamelTag **list,
-                                                const gchar *name);
-gboolean       camel_tag_set                   (CamelTag **list,
-                                                const gchar *name,
-                                                const gchar *value);
-gboolean       camel_tag_list_copy             (CamelTag **to,
-                                                CamelTag **from);
-gint           camel_tag_list_size             (CamelTag **list);
-void           camel_tag_list_free             (CamelTag **list);
-
-/* Summary may be null */
-/* Use anonymous pointers to avoid tons of cast crap */
-GType          camel_message_info_get_type     (void) G_GNUC_CONST;
-gpointer       camel_message_info_new          (CamelFolderSummary *summary);
-gpointer       camel_message_info_ref          (gpointer info);
 CamelMessageInfo *
-               camel_message_info_new_from_header
+               camel_message_info_new_from_headers
                                                (CamelFolderSummary *summary,
-                                                struct _camel_header_raw *header);
-void           camel_message_info_unref        (gpointer info);
-gpointer       camel_message_info_clone        (gconstpointer info);
-
-/* These will be fully removed soon, left only for a backward compatibility */
-#define camel_message_info_ptr                 camel_message_info_get_ptr
-#define camel_message_info_uint32              camel_message_info_get_uint32
-#define camel_message_info_time                        camel_message_info_get_time
-#define camel_message_info_uid                 camel_message_info_get_uid
-#define camel_message_info_subject             camel_message_info_get_subject
-#define camel_message_info_preview             camel_message_info_get_preview
-#define camel_message_info_from                        camel_message_info_get_from
-#define camel_message_info_to                  camel_message_info_get_to
-#define camel_message_info_cc                  camel_message_info_get_cc
-#define camel_message_info_mlist               camel_message_info_get_mlist
-#define camel_message_info_flags               camel_message_info_get_flags
-#define camel_message_info_size                        camel_message_info_get_size
-#define camel_message_info_date_sent           camel_message_info_get_date_sent
-#define camel_message_info_date_received       camel_message_info_get_date_received
-#define camel_message_info_message_id          camel_message_info_get_message_id
-#define camel_message_info_references          camel_message_info_get_references
-#define camel_message_info_user_flags          camel_message_info_get_user_flags
-#define camel_message_info_user_tags           camel_message_info_get_user_tags
-#define camel_message_info_headers             camel_message_info_get_headers
-#define camel_message_info_content             camel_message_info_get_content
-#define camel_message_info_user_flag           camel_message_info_get_user_flag
-#define camel_message_info_user_tag            camel_message_info_get_user_tag
-
-/* accessors */
-gconstpointer  camel_message_info_get_ptr      (gconstpointer info,
-                                                gint id);
-guint32                camel_message_info_get_uint32   (gconstpointer info,
-                                                gint id);
-time_t         camel_message_info_get_time     (gconstpointer info,
-                                                gint id);
-
-const gchar *  camel_message_info_get_uid      (gconstpointer info);
-const gchar *  camel_message_info_get_subject  (gconstpointer info);
-const gchar *  camel_message_info_get_preview  (gconstpointer info);
-const gchar *  camel_message_info_get_from     (gconstpointer info);
-const gchar *  camel_message_info_get_to       (gconstpointer info);
-
-const gchar *  camel_message_info_get_cc       (gconstpointer info);
-const gchar *  camel_message_info_get_mlist    (gconstpointer info);
-guint32                camel_message_info_get_flags    (gconstpointer info);
-guint32                camel_message_info_get_size     (gconstpointer info);
-
-time_t         camel_message_info_get_date_sent
-                                               (gconstpointer info);
-time_t         camel_message_info_get_date_received
-                                               (gconstpointer info);
-
-const CamelSummaryMessageID *
-               camel_message_info_get_message_id
-                                               (gconstpointer info);
-const CamelSummaryReferences *
-               camel_message_info_get_references
-                                               (gconstpointer info);
-const CamelFlag *
-               camel_message_info_get_user_flags
-                                               (gconstpointer info);
-const CamelTag *
-               camel_message_info_get_user_tags
-                                               (gconstpointer info);
-const CamelHeaderParam *
-               camel_message_info_get_headers  (gconstpointer info);
-const CamelMessageContentInfo *
-               camel_message_info_get_content  (gconstpointer info);
-gboolean       camel_message_info_get_user_flag(gconstpointer info,
-                                                const gchar *id);
-const gchar *  camel_message_info_get_user_tag (gconstpointer info,
-                                                const gchar *id);
-
-gboolean       camel_message_info_set_flags    (CamelMessageInfo *info,
-                                                CamelMessageFlags flags,
-                                                guint32 set);
-gboolean       camel_message_info_set_user_flag
-                                               (CamelMessageInfo *info,
-                                                const gchar *id,
-                                                gboolean state);
-gboolean       camel_message_info_set_user_tag (CamelMessageInfo *info,
-                                                const gchar *id,
-                                                const gchar *val);
-
-/* debugging functions */
-void           camel_content_info_dump         (CamelMessageContentInfo *ci,
-                                                gint depth);
-void           camel_message_info_dump         (CamelMessageInfo *info);
-
-/* utility functions for bdata string decomposition */
-gint           bdata_extract_digit             (gchar **part);
-gchar *                bdata_extract_string            (gchar **part);
-
+                                                const CamelNameValueArray *headers);
 G_END_DECLS
 
 #endif /* CAMEL_FOLDER_SUMMARY_H */
diff --git a/src/camel/camel-folder-thread.c b/src/camel/camel-folder-thread.c
index 9ff205d..1d6c53d 100644
--- a/src/camel/camel-folder-thread.c
+++ b/src/camel/camel-folder-thread.c
@@ -367,12 +367,16 @@ dump_tree_rec (struct _tree_info *info,
                        g_hash_table_insert (info->visited, c, c);
                }
                if (c->message) {
+                       CamelSummaryMessageID message_id;
+
+                       message_id.id.id = camel_message_info_get_message_id (c->message);
+
                        printf (
                                "%*s %p Subject: %s <%08x%08x>\n",
                                indent, "", (gpointer) c,
                                camel_message_info_get_subject (c->message),
-                               camel_message_info_get_message_id (c->message)->id.part.hi,
-                               camel_message_info_get_message_id (c->message)->id.part.lo);
+                               message_id.id.part.hi,
+                               message_id.id.part.lo);
                        count += 1;
                } else {
                        printf ("%*s %p <empty>\n", indent, "", (gpointer) c);
@@ -461,18 +465,18 @@ sort_thread (CamelFolderThreadNode **cp)
 }
 
 static guint
-id_hash (gpointer key)
+id_hash (gconstpointer key)
 {
-       CamelSummaryMessageID *id = (CamelSummaryMessageID *) key;
+       const CamelSummaryMessageID *id = key;
 
        return id->id.part.lo;
 }
 
-static gint
-id_equal (gpointer a,
-          gpointer b)
+static gboolean
+id_equal (gconstpointer a,
+          gconstpointer b)
 {
-       return ((CamelSummaryMessageID *) a)->id.id == ((CamelSummaryMessageID *) b)->id.id;
+       return ((const CamelSummaryMessageID *) a)->id.id == ((const CamelSummaryMessageID *) b)->id.id;
 }
 
 /* perform actual threading */
@@ -490,15 +494,20 @@ thread_summary (CamelFolderThread *thread,
        gettimeofday (&start, NULL);
 #endif
 
-       id_table = g_hash_table_new ((GHashFunc) id_hash, (GCompareFunc) id_equal);
+       id_table = g_hash_table_new_full (id_hash, id_equal, g_free, NULL);
        no_id_table = g_hash_table_new (NULL, NULL);
        for (i = 0; i < summary->len; i++) {
                CamelMessageInfo *mi = summary->pdata[i];
-               const CamelSummaryMessageID *mid = camel_message_info_get_message_id (mi);
-               const CamelSummaryReferences *references = camel_message_info_get_references (mi);
+               CamelSummaryMessageID *message_id_copy, message_id;
+               const GArray *references;
+
+               camel_message_info_property_lock (mi);
 
-               if (mid != NULL && mid->id.id) {
-                       c = g_hash_table_lookup (id_table, mid);
+               message_id.id.id = camel_message_info_get_message_id (mi);
+               references = camel_message_info_get_references (mi);
+
+               if (message_id.id.id) {
+                       c = g_hash_table_lookup (id_table, &message_id);
                        /* check for duplicate messages */
                        if (c && c->order) {
                                /* if duplicate, just make out it is a no-id message,  but try and insert it
@@ -507,9 +516,11 @@ thread_summary (CamelFolderThread *thread,
                                c = camel_memchunk_alloc0 (thread->node_chunks);
                                g_hash_table_insert (no_id_table, (gpointer) mi, c);
                        } else if (!c) {
-                               d (printf ("doing : %08x%08x (%s)\n", mid->id.part.hi, mid->id.part.lo, 
camel_message_info_get_subject (mi)));
+                               d (printf ("doing : %08x%08x (%s)\n", message_id.id.part.hi, 
message_id.id.part.lo, camel_message_info_get_subject (mi)));
                                c = camel_memchunk_alloc0 (thread->node_chunks);
-                               g_hash_table_insert (id_table, (gpointer) mid, c);
+                               message_id_copy = g_new0 (CamelSummaryMessageID, 1);
+                               message_id_copy->id.id = message_id.id.id;
+                               g_hash_table_insert (id_table, message_id_copy, c);
                        }
                } else {
                        d (printf ("doing : (no message id)\n"));
@@ -521,21 +532,26 @@ thread_summary (CamelFolderThread *thread,
                c->order = i + 1;
                child = c;
                if (references) {
-                       gint j;
+                       guint jj;
 
                        d (printf ("%s (%s) references:\n", G_STRLOC, G_STRFUNC); )
-                       for (j = 0; j < references->size; j++) {
+
+                       for (jj = 0; jj < references->len; jj++) {
                                gboolean found = FALSE;
 
+                               message_id.id.id = g_array_index (references, guint64, jj);
+
                                /* should never be empty, but just incase */
-                               if (references->references[j].id.id == 0)
+                               if (!message_id.id.id)
                                        continue;
 
-                               c = g_hash_table_lookup (id_table, &references->references[j]);
+                               c = g_hash_table_lookup (id_table, &message_id);
                                if (c == NULL) {
                                        d (printf ("%s (%s) not found\n", G_STRLOC, G_STRFUNC));
                                        c = camel_memchunk_alloc0 (thread->node_chunks);
-                                       g_hash_table_insert (id_table, (gpointer) &references->references[j], 
c);
+                                       message_id_copy = g_new0 (CamelSummaryMessageID, 1);
+                                       message_id_copy->id.id = message_id.id.id;
+                                       g_hash_table_insert (id_table, message_id_copy, c);
                                } else
                                        found = TRUE;
                                if (c != child) {
@@ -549,6 +565,8 @@ thread_summary (CamelFolderThread *thread,
                                child = c;
                        }
                }
+
+               camel_message_info_property_unlock (mi);
        }
 
        d (printf ("\n\n"));
@@ -631,7 +649,7 @@ thread_summary (CamelFolderThread *thread,
 }
 
 /**
- * camel_folder_thread_messages_new:
+ * camel_folder_thread_messages_new: (skip)
  * @folder:
  * @uids: (element-type utf8): The subset of uid's to thread.  If NULL. then thread all
  * uid's in @folder.
@@ -666,12 +684,12 @@ camel_folder_thread_messages_new (CamelFolder *folder,
        thread->node_chunks = camel_memchunk_new (32, sizeof (CamelFolderThreadNode));
        thread->folder = g_object_ref (folder);
 
-       camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
+       camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary (folder), NULL);
        thread->summary = summary = g_ptr_array_new ();
 
        /* prefer given order from the summary order */
        if (!uids) {
-               fsummary = camel_folder_summary_get_array (folder->summary);
+               fsummary = camel_folder_summary_get_array (camel_folder_get_folder_summary (folder));
                uids = fsummary;
        }
 
@@ -712,7 +730,7 @@ add_present_rec (CamelFolderThread *thread,
                        g_hash_table_remove (have, uid);
                        g_ptr_array_add (summary, info);
                } else {
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
 
                if (node->child)
@@ -781,7 +799,7 @@ camel_folder_thread_messages_unref (CamelFolderThread *thread)
                gint i;
 
                for (i = 0; i < thread->summary->len; i++)
-                       camel_message_info_unref (thread->summary->pdata[i]);
+                       g_clear_object (&thread->summary->pdata[i]);
                g_ptr_array_free (thread->summary, TRUE);
                g_object_unref (thread->folder);
        }
diff --git a/src/camel/camel-folder.c b/src/camel/camel-folder.c
index 2b08478..460da61 100644
--- a/src/camel/camel-folder.c
+++ b/src/camel/camel-folder.c
@@ -50,6 +50,9 @@ typedef struct _SignalClosure SignalClosure;
 typedef struct _FolderFilterData FolderFilterData;
 
 struct _CamelFolderPrivate {
+       CamelFolderSummary *summary;
+       CamelFolderFlags folder_flags;
+
        GRecMutex lock;
        GMutex change_lock;
        /* must require the 'change_lock' to access this */
@@ -135,7 +138,7 @@ async_context_free (AsyncContext *async_context)
                g_object_unref (async_context->message);
 
        if (async_context->info != NULL)
-               camel_message_info_unref (async_context->info);
+               g_clear_object (&async_context->info);
 
        if (async_context->destination != NULL)
                g_object_unref (async_context->destination);
@@ -247,7 +250,7 @@ folder_filter_data_free_thread (gpointer user_data)
                camel_folder_free_deep (data->folder, data->notjunk);
 
        /* XXX Too late to pass a GError here. */
-       camel_folder_summary_save_to_db (data->folder->summary, NULL);
+       camel_folder_summary_save (camel_folder_get_folder_summary (data->folder), NULL);
 
        camel_folder_thaw (data->folder);
        g_object_unref (data->folder);
@@ -294,23 +297,23 @@ folder_filter (CamelSession *session,
        /* Reset junk learn flag so that we don't process it again */
        if (data->junk) {
                for (i = 0; i < data->junk->len; i++) {
-                       info = camel_folder_summary_get (data->folder->summary, data->junk->pdata[i]);
+                       info = camel_folder_summary_get (camel_folder_get_folder_summary (data->folder), 
data->junk->pdata[i]);
                        if (!info)
                                continue;
 
                        camel_message_info_set_flags (info, CAMEL_MESSAGE_JUNK_LEARN, 0);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
        }
 
        if (data->notjunk) {
                for (i = 0; i < data->notjunk->len; i++) {
-                       info = camel_folder_summary_get (data->folder->summary, data->notjunk->pdata[i]);
+                       info = camel_folder_summary_get (camel_folder_get_folder_summary (data->folder), 
data->notjunk->pdata[i]);
                        if (!info)
                                continue;
 
                        camel_message_info_set_flags (info, CAMEL_MESSAGE_JUNK_LEARN, 0);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
        }
 
@@ -444,7 +447,7 @@ folder_filter (CamelSession *session,
                                data->driver, NULL, info, uid, data->folder,
                                store_uid, store_uid, cancellable, error);
 
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
 
                camel_operation_pop_message (cancellable);
@@ -482,6 +485,7 @@ folder_transfer_message_to (CamelFolder *source,
 {
        CamelMimeMessage *msg;
        CamelMessageInfo *minfo, *info;
+       guint32 source_folder_flags;
        GError *local_error = NULL;
 
        /* Default implementation. */
@@ -490,19 +494,24 @@ folder_transfer_message_to (CamelFolder *source,
        if (!msg)
                return;
 
+       source_folder_flags = camel_folder_get_flags (source);
+
        /* if its deleted we poke the flags, so we need to copy the messageinfo */
-       if ((source->folder_flags & CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY)
-                       && (minfo = camel_folder_get_message_info (source, uid))) {
-               info = camel_message_info_clone (minfo);
-               camel_message_info_unref (minfo);
-       } else
-               info = camel_message_info_new_from_header (NULL, ((CamelMimePart *) msg)->headers);
+       if ((source_folder_flags & CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY)
+           && (minfo = camel_folder_get_message_info (source, uid))) {
+               info = camel_message_info_clone (minfo, NULL);
+               g_clear_object (&minfo);
+       } else {
+               const CamelNameValueArray *headers = camel_medium_get_headers (CAMEL_MEDIUM (msg));
+
+               info = camel_message_info_new_from_headers (NULL, headers);
+       }
 
        /* unset deleted flag when transferring from trash folder */
-       if ((source->folder_flags & CAMEL_FOLDER_IS_TRASH) != 0)
+       if ((source_folder_flags & CAMEL_FOLDER_IS_TRASH) != 0)
                camel_message_info_set_flags (info, CAMEL_MESSAGE_DELETED, 0);
        /* unset junk flag when transferring from junk folder */
-       if ((source->folder_flags & CAMEL_FOLDER_IS_JUNK) != 0)
+       if ((source_folder_flags & CAMEL_FOLDER_IS_JUNK) != 0)
                camel_message_info_set_flags (info, CAMEL_MESSAGE_JUNK, 0);
 
        camel_folder_append_message_sync (
@@ -517,7 +526,7 @@ folder_transfer_message_to (CamelFolder *source,
                        source, uid, CAMEL_MESSAGE_DELETED |
                        CAMEL_MESSAGE_SEEN, ~0);
 
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 }
 
 static gboolean
@@ -664,10 +673,7 @@ folder_dispose (GObject *object)
                folder->priv->parent_store = NULL;
        }
 
-       if (folder->summary) {
-               g_object_unref (folder->summary);
-               folder->summary = NULL;
-       }
+       g_clear_object (&folder->priv->summary);
 
        /* Chain up to parent's dispose () method. */
        G_OBJECT_CLASS (camel_folder_parent_class)->dispose (object);
@@ -701,32 +707,32 @@ folder_finalize (GObject *object)
 static gint
 folder_get_message_count (CamelFolder *folder)
 {
-       g_return_val_if_fail (folder->summary != NULL, -1);
+       g_return_val_if_fail (folder->priv->summary != NULL, -1);
 
-       return camel_folder_summary_count (folder->summary);
+       return camel_folder_summary_count (folder->priv->summary);
 }
 
-static CamelMessageFlags
+static guint32
 folder_get_permanent_flags (CamelFolder *folder)
 {
-       return folder->permanent_flags;
+       return 0;
 }
 
-static CamelMessageFlags
+static guint32
 folder_get_message_flags (CamelFolder *folder,
                           const gchar *uid)
 {
        CamelMessageInfo *info;
-       CamelMessageFlags flags;
+       guint32 flags;
 
-       g_return_val_if_fail (folder->summary != NULL, 0);
+       g_return_val_if_fail (folder->priv->summary != NULL, 0);
 
-       info = camel_folder_summary_get (folder->summary, uid);
+       info = camel_folder_summary_get (folder->priv->summary, uid);
        if (info == NULL)
                return 0;
 
        flags = camel_message_info_get_flags (info);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        return flags;
 }
@@ -734,20 +740,20 @@ folder_get_message_flags (CamelFolder *folder,
 static gboolean
 folder_set_message_flags (CamelFolder *folder,
                           const gchar *uid,
-                          CamelMessageFlags flags,
-                          CamelMessageFlags set)
+                          guint32 mask,
+                          guint32 set)
 {
        CamelMessageInfo *info;
        gint res;
 
-       g_return_val_if_fail (folder->summary != NULL, FALSE);
+       g_return_val_if_fail (folder->priv->summary != NULL, FALSE);
 
-       info = camel_folder_summary_get (folder->summary, uid);
+       info = camel_folder_summary_get (folder->priv->summary, uid);
        if (info == NULL)
                return FALSE;
 
-       res = camel_message_info_set_flags (info, flags, set);
-       camel_message_info_unref (info);
+       res = camel_message_info_set_flags (info, mask, set);
+       g_clear_object (&info);
 
        return res;
 }
@@ -760,14 +766,14 @@ folder_get_message_user_flag (CamelFolder *folder,
        CamelMessageInfo *info;
        gboolean ret;
 
-       g_return_val_if_fail (folder->summary != NULL, FALSE);
+       g_return_val_if_fail (folder->priv->summary != NULL, FALSE);
 
-       info = camel_folder_summary_get (folder->summary, uid);
+       info = camel_folder_summary_get (folder->priv->summary, uid);
        if (info == NULL)
                return FALSE;
 
        ret = camel_message_info_get_user_flag (info, name);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        return ret;
 }
@@ -780,14 +786,14 @@ folder_set_message_user_flag (CamelFolder *folder,
 {
        CamelMessageInfo *info;
 
-       g_return_if_fail (folder->summary != NULL);
+       g_return_if_fail (folder->priv->summary != NULL);
 
-       info = camel_folder_summary_get (folder->summary, uid);
+       info = camel_folder_summary_get (folder->priv->summary, uid);
        if (info == NULL)
                return;
 
        camel_message_info_set_user_flag (info, name, value);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 }
 
 static const gchar *
@@ -798,14 +804,14 @@ folder_get_message_user_tag (CamelFolder *folder,
        CamelMessageInfo *info;
        const gchar *ret;
 
-       g_return_val_if_fail (folder->summary != NULL, NULL);
+       g_return_val_if_fail (folder->priv->summary != NULL, NULL);
 
-       info = camel_folder_summary_get (folder->summary, uid);
+       info = camel_folder_summary_get (folder->priv->summary, uid);
        if (info == NULL)
                return NULL;
 
        ret = camel_message_info_get_user_tag (info, name);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        return ret;
 }
@@ -818,22 +824,22 @@ folder_set_message_user_tag (CamelFolder *folder,
 {
        CamelMessageInfo *info;
 
-       g_return_if_fail (folder->summary != NULL);
+       g_return_if_fail (folder->priv->summary != NULL);
 
-       info = camel_folder_summary_get (folder->summary, uid);
+       info = camel_folder_summary_get (folder->priv->summary, uid);
        if (info == NULL)
                return;
 
        camel_message_info_set_user_tag (info, name, value);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 }
 
 static GPtrArray *
 folder_get_uids (CamelFolder *folder)
 {
-       g_return_val_if_fail (folder->summary != NULL, NULL);
+       g_return_val_if_fail (folder->priv->summary != NULL, NULL);
 
-       return camel_folder_summary_get_array (folder->summary);
+       return camel_folder_summary_get_array (folder->priv->summary);
 }
 
 static GPtrArray *
@@ -884,9 +890,9 @@ folder_sort_uids (CamelFolder *folder,
 static GPtrArray *
 folder_get_summary (CamelFolder *folder)
 {
-       g_return_val_if_fail (folder->summary != NULL, NULL);
+       g_return_val_if_fail (folder->priv->summary != NULL, NULL);
 
-       return camel_folder_summary_get_array (folder->summary);
+       return camel_folder_summary_get_array (folder->priv->summary);
 }
 
 static void
@@ -911,16 +917,16 @@ static CamelMessageInfo *
 folder_get_message_info (CamelFolder *folder,
                          const gchar *uid)
 {
-       g_return_val_if_fail (folder->summary != NULL, NULL);
+       g_return_val_if_fail (folder->priv->summary != NULL, NULL);
 
-       return camel_folder_summary_get (folder->summary, uid);
+       return camel_folder_summary_get (folder->priv->summary, uid);
 }
 
 static void
 folder_delete (CamelFolder *folder)
 {
-       if (folder->summary)
-               camel_folder_summary_clear (folder->summary, NULL);
+       if (folder->priv->summary)
+               camel_folder_summary_clear (folder->priv->summary, NULL);
 }
 
 static void
@@ -945,8 +951,8 @@ folder_freeze (CamelFolder *folder)
        g_mutex_lock (&folder->priv->change_lock);
 
        folder->priv->frozen++;
-       if (folder->summary)
-               g_object_freeze_notify (G_OBJECT (folder->summary));
+       if (folder->priv->summary)
+               g_object_freeze_notify (G_OBJECT (folder->priv->summary));
 
        d (printf ("freeze (%p '%s') = %d\n", folder, folder->full_name, folder->priv->frozen));
        g_mutex_unlock (&folder->priv->change_lock);
@@ -962,8 +968,8 @@ folder_thaw (CamelFolder *folder)
        g_mutex_lock (&folder->priv->change_lock);
 
        folder->priv->frozen--;
-       if (folder->summary)
-               g_object_thaw_notify (G_OBJECT (folder->summary));
+       if (folder->priv->summary)
+               g_object_thaw_notify (G_OBJECT (folder->priv->summary));
 
        d (printf ("thaw (%p '%s') = %d\n", folder, folder->full_name, folder->priv->frozen));
 
@@ -979,8 +985,8 @@ folder_thaw (CamelFolder *folder)
                camel_folder_changed (folder, info);
                camel_folder_change_info_free (info);
 
-               if (folder->summary)
-                       camel_folder_summary_save_to_db (folder->summary, NULL);
+               if (folder->priv->summary)
+                       camel_folder_summary_save (folder->priv->summary, NULL);
        }
 }
 
@@ -1113,10 +1119,10 @@ folder_changed (CamelFolder *folder,
        junk_filter = camel_session_get_junk_filter (session);
 
        if (junk_filter != NULL && info->uid_changed->len) {
-               CamelMessageFlags flags;
+               guint32 flags;
 
                for (i = 0; i < info->uid_changed->len; i++) {
-                       flags = camel_folder_summary_get_info_flags (folder->summary, 
info->uid_changed->pdata[i]);
+                       flags = camel_folder_summary_get_info_flags (folder->priv->summary, 
info->uid_changed->pdata[i]);
                        if (flags != (~0) && (flags & CAMEL_MESSAGE_JUNK_LEARN) != 0) {
                                if (flags & CAMEL_MESSAGE_JUNK) {
                                        if (!junk)
@@ -1133,11 +1139,11 @@ folder_changed (CamelFolder *folder,
                }
        }
 
-       if ((folder->folder_flags & (CAMEL_FOLDER_FILTER_RECENT | CAMEL_FOLDER_FILTER_JUNK))
+       if ((camel_folder_get_flags (folder) & (CAMEL_FOLDER_FILTER_RECENT | CAMEL_FOLDER_FILTER_JUNK))
            && p->uid_filter->len > 0)
                driver = camel_session_get_filter_driver (
                        session,
-                       (folder->folder_flags & CAMEL_FOLDER_FILTER_RECENT)
+                       (camel_folder_get_flags (folder) & CAMEL_FOLDER_FILTER_RECENT)
                        ? "incoming" : "junktest", NULL);
 
        if (driver) {
@@ -1294,6 +1300,7 @@ camel_folder_class_init (CamelFolderClass *class)
        /**
         * CamelFolder::changed
         * @folder: the #CamelFolder which emitted the signal
+        * @changes: the #CamelFolderChangeInfo with the list of changes
         **/
        signals[CHANGED] = g_signal_new (
                "changed",
@@ -1302,7 +1309,7 @@ camel_folder_class_init (CamelFolderClass *class)
                G_STRUCT_OFFSET (CamelFolderClass, changed),
                NULL, NULL, NULL,
                G_TYPE_NONE, 1,
-               G_TYPE_POINTER);
+               CAMEL_TYPE_FOLDER_CHANGE_INFO);
 
        /**
         * CamelFolder::deleted
@@ -1644,6 +1651,46 @@ camel_folder_get_parent_store (CamelFolder *folder)
 }
 
 /**
+ * camel_folder_get_folder_summary:
+ * @folder: a #CamelFolder
+ *
+ * Returns: (transfer none): a #CamelFolderSummary of the folder
+ *
+ * Since: 3.24
+ **/
+CamelFolderSummary *
+camel_folder_get_folder_summary (CamelFolder *folder)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+
+       return folder->priv->summary;
+}
+
+/**
+ * camel_folder_take_folder_summary:
+ * @folder: a #CamelFolder
+ * @summary: (transfer full): a #CamelFolderSummary
+ *
+ * Sets a #CamelFolderSummary of the folder. It consumes the @summary.
+ *
+ * This is supposed to be called only by the descendants of
+ * the #CamelFolder and only at the construction time. Calling
+ * this function twice yeilds to an error.
+ *
+ * Since: 3.24
+ **/
+void
+camel_folder_take_folder_summary (CamelFolder *folder,
+                                 CamelFolderSummary *summary)
+{
+       g_return_if_fail (CAMEL_IS_FOLDER (folder));
+       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
+       g_return_if_fail (folder->priv->summary == NULL);
+
+       folder->priv->summary = summary;
+}
+
+/**
  * camel_folder_get_message_count:
  * @folder: a #CamelFolder
  *
@@ -1675,9 +1722,9 @@ gint
 camel_folder_get_unread_message_count (CamelFolder *folder)
 {
        g_return_val_if_fail (CAMEL_IS_FOLDER (folder), -1);
-       g_return_val_if_fail (folder->summary != NULL, -1);
+       g_return_val_if_fail (folder->priv->summary != NULL, -1);
 
-       return camel_folder_summary_get_unread_count (folder->summary);
+       return camel_folder_summary_get_unread_count (folder->priv->summary);
 }
 
 /**
@@ -1691,9 +1738,43 @@ gint
 camel_folder_get_deleted_message_count (CamelFolder *folder)
 {
        g_return_val_if_fail (CAMEL_IS_FOLDER (folder), -1);
-       g_return_val_if_fail (folder->summary != NULL, -1);
+       g_return_val_if_fail (folder->priv->summary != NULL, -1);
+
+       return camel_folder_summary_get_deleted_count (folder->priv->summary);
+}
 
-       return camel_folder_summary_get_deleted_count (folder->summary);
+/**
+ * camel_folder_get_flags:
+ * @folder: a #CamelFolder
+ *
+ * Returns: Folder flags (bit-or of #CamelFolderFlags) of the @folder
+ *
+ * Since: 3.24
+ **/
+guint32
+camel_folder_get_flags (CamelFolder *folder)
+{
+       g_return_val_if_fail (CAMEL_IS_FOLDER (folder), 0);
+
+       return folder->priv->folder_flags;
+}
+
+/**
+ * camel_folder_set_flags:
+ * @folder: a #CamelFolder
+ * @folder_flags: flags (bit-or of #CamelFolderFlags) to set
+ *
+ * Sets folder flags (bit-or of #CamelFolderFlags) for the @folder.
+ *
+ * Since: 3.24
+ **/
+void
+camel_folder_set_flags (CamelFolder *folder,
+                       guint32 folder_flags)
+{
+       g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+       folder->priv->folder_flags = folder_flags;
 }
 
 /**
@@ -1704,7 +1785,7 @@ camel_folder_get_deleted_message_count (CamelFolder *folder)
  * stored on a message between sessions. If it includes
  * #CAMEL_FLAG_USER, then user-defined flags will be remembered.
  **/
-CamelMessageFlags
+guint32
 camel_folder_get_permanent_flags (CamelFolder *folder)
 {
        CamelFolderClass *class;
@@ -1727,7 +1808,7 @@ camel_folder_get_permanent_flags (CamelFolder *folder)
  * Returns: the #CamelMessageFlags that are set on the indicated
  * message.
  **/
-CamelMessageFlags
+guint32
 camel_folder_get_message_flags (CamelFolder *folder,
                                 const gchar *uid)
 {
@@ -1746,10 +1827,10 @@ camel_folder_get_message_flags (CamelFolder *folder,
  * camel_folder_set_message_flags:
  * @folder: a #CamelFolder
  * @uid: the UID of a message in @folder
- * @flags: a set of #CamelMessageFlag values to set
- * @set: the mask of values in @flags to use.
+ * @mask: a mask of #CamelMessageFlag bit-or values to use
+ * @set: the flags to ser, also bit-or of #CamelMessageFlag
  *
- * Sets those flags specified by @flags to the values specified by @set
+ * Sets those flags specified by @mask to the values specified by @set
  * on the indicated message. (This may or may not persist after the
  * folder or store is closed. See camel_folder_get_permanent_flags())
  *
@@ -1764,8 +1845,8 @@ camel_folder_get_message_flags (CamelFolder *folder,
 gboolean
 camel_folder_set_message_flags (CamelFolder *folder,
                                 const gchar *uid,
-                                CamelMessageFlags flags,
-                                CamelMessageFlags set)
+                                guint32 mask,
+                                guint32 set)
 {
        CamelFolderClass *class;
 
@@ -1775,12 +1856,7 @@ camel_folder_set_message_flags (CamelFolder *folder,
        class = CAMEL_FOLDER_GET_CLASS (folder);
        g_return_val_if_fail (class->set_message_flags != NULL, FALSE);
 
-       if ((flags & (CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_JUNK_LEARN)) == CAMEL_MESSAGE_JUNK) {
-               flags |= CAMEL_MESSAGE_JUNK_LEARN;
-               set &= ~CAMEL_MESSAGE_JUNK_LEARN;
-       }
-
-       return class->set_message_flags (folder, uid, flags, set);
+       return class->set_message_flags (folder, uid, mask, set);
 }
 
 /**
@@ -1910,11 +1986,11 @@ camel_folder_set_message_user_tag (CamelFolder *folder,
  * @folder: a #CamelFolder
  * @uid: the uid of a message
  *
- * Retrieve the #CamelMessageInfo for the specified @uid.  This return
- * must be freed using camel_message_info_unref().
+ * Retrieve the #CamelMessageInfo for the specified @uid.
  *
- * Returns: the summary information for the indicated message, or %NULL
- * if the uid does not exist
+ * Returns: (transfer full): The summary information for the indicated message, or %NULL
+ *   if the uid does not exist. Free the returned object with g_object_unref(),
+ *   when done with it.
  **/
 CamelMessageInfo *
 camel_folder_get_message_info (CamelFolder *folder,
@@ -1945,7 +2021,7 @@ camel_folder_has_summary_capability (CamelFolder *folder)
 {
        g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
 
-       return folder->folder_flags & CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
+       return (camel_folder_get_flags (folder) & CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY) != 0;
 }
 
 /* UIDs stuff */
@@ -2093,7 +2169,7 @@ camel_folder_sort_uids (CamelFolder *folder,
  * should not be modified, and must be freed with
  * camel_folder_free_summary().
  *
- * Returns: (element-type CamelMessageInfo) (transfer none): an array of #CamelMessageInfo
+ * Returns: (element-type utf8) (transfer none): an array of UID-s of #CamelMessageInfo
  **/
 GPtrArray *
 camel_folder_get_summary (CamelFolder *folder)
@@ -2283,12 +2359,12 @@ camel_folder_delete (CamelFolder *folder)
        g_return_if_fail (class->delete_ != NULL);
 
        camel_folder_lock (folder);
-       if (folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED) {
+       if (camel_folder_get_flags (folder) & CAMEL_FOLDER_HAS_BEEN_DELETED) {
                camel_folder_unlock (folder);
                return;
        }
 
-       folder->folder_flags |= CAMEL_FOLDER_HAS_BEEN_DELETED;
+       camel_folder_set_flags (folder, camel_folder_get_flags (folder) | CAMEL_FOLDER_HAS_BEEN_DELETED);
 
        class->delete_ (folder);
 
@@ -2297,7 +2373,7 @@ camel_folder_delete (CamelFolder *folder)
        /* Delete the references of the folder from the DB.*/
        full_name = camel_folder_get_full_name (folder);
        parent_store = camel_folder_get_parent_store (folder);
-       camel_db_delete_folder (parent_store->cdb_w, full_name, NULL);
+       camel_db_delete_folder (camel_store_get_db (parent_store), full_name, NULL);
 
        service = CAMEL_SERVICE (parent_store);
        session = camel_service_ref_session (service);
@@ -2352,7 +2428,7 @@ camel_folder_rename (CamelFolder *folder,
        class->rename (folder, new_name);
 
        parent_store = camel_folder_get_parent_store (folder);
-       camel_db_rename_folder (parent_store->cdb_w, old_name, new_name, NULL);
+       camel_db_rename_folder (camel_store_get_db (parent_store), old_name, new_name, NULL);
 
        service = CAMEL_SERVICE (parent_store);
        session = camel_service_ref_session (service);
@@ -2598,22 +2674,6 @@ camel_folder_quota_info_free (CamelFolderQuotaInfo *info)
 }
 
 /**
- * camel_folder_free_nop:
- * @folder: a #CamelFolder
- * @array: an array of uids or #CamelMessageInfo
- *
- * "Frees" the provided array by doing nothing. Used by #CamelFolder
- * subclasses as an implementation for free_uids, or free_summary when
- * the returned array is "static" information and should not be freed.
- **/
-void
-camel_folder_free_nop (CamelFolder *folder,
-                       GPtrArray *array)
-{
-       ;
-}
-
-/**
  * camel_folder_free_shallow:
  * @folder: a #CamelFolder
  * @array: (element-type utf8): an array of uids or #CamelMessageInfo
@@ -2807,7 +2867,7 @@ camel_folder_append_message (CamelFolder *folder,
 
        async_context = g_slice_new0 (AsyncContext);
        async_context->message = g_object_ref (message);
-       async_context->info = camel_message_info_ref (info);
+       async_context->info = g_object_ref (info);
 
        task = g_task_new (folder, cancellable, callback, user_data);
        g_task_set_source_tag (task, camel_folder_append_message);
@@ -2915,7 +2975,7 @@ camel_folder_expunge_sync (CamelFolder *folder,
                camel_service_get_display_name (CAMEL_SERVICE (camel_folder_get_parent_store (folder))),
                camel_folder_get_full_name (folder));
 
-       if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) {
+       if (!(camel_folder_get_flags (folder) & CAMEL_FOLDER_HAS_BEEN_DELETED)) {
                success = class->expunge_sync (folder, cancellable, error);
                CAMEL_CHECK_GERROR (folder, expunge_sync, success, error);
 
@@ -3674,7 +3734,7 @@ camel_folder_synchronize_sync (CamelFolder *folder,
                return FALSE;
        }
 
-       if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) {
+       if (!(camel_folder_get_flags (folder) & CAMEL_FOLDER_HAS_BEEN_DELETED)) {
                success = class->synchronize_sync (
                        folder, expunge, cancellable, error);
                CAMEL_CHECK_GERROR (folder, synchronize_sync, success, error);
@@ -4175,6 +4235,8 @@ camel_folder_prepare_content_refresh (CamelFolder *folder)
                klass->prepare_content_refresh (folder);
 }
 
+G_DEFINE_BOXED_TYPE (CamelFolderChangeInfo, camel_folder_change_info, camel_folder_change_info_copy, 
camel_folder_change_info_free)
+
 /**
  * camel_folder_change_info_new:
  *
@@ -4183,7 +4245,7 @@ camel_folder_prepare_content_refresh (CamelFolder *folder)
  * Change info structures are not MT-SAFE and must be
  * locked for exclusive access externally.
  *
- * Returns: a new #CamelFolderChangeInfo
+ * Returns: (transfer full): a new #CamelFolderChangeInfo
  **/
 CamelFolderChangeInfo *
 camel_folder_change_info_new (void)
@@ -4205,6 +4267,30 @@ camel_folder_change_info_new (void)
 }
 
 /**
+ * camel_folder_change_info_copy:
+ * @src: a #CamelFolderChangeInfo to make copy of
+ *
+ * Creates a copy of the @src.
+ *
+ * Returns: (transfer full): Copy of the @src.
+ *
+ * Since: 3.24
+ **/
+CamelFolderChangeInfo *
+camel_folder_change_info_copy (CamelFolderChangeInfo *src)
+{
+       CamelFolderChangeInfo *copy;
+
+       if (!src)
+               return NULL;
+
+       copy = camel_folder_change_info_new ();
+       camel_folder_change_info_cat (copy, src);
+
+       return copy;
+}
+
+/**
  * camel_folder_change_info_add_source:
  * @info: a #CamelFolderChangeInfo
  * @uid: a uid
@@ -4409,21 +4495,21 @@ change_info_cat (CamelFolderChangeInfo *info,
  * @info: a #CamelFolderChangeInfo to append to
  * @src: a #CamelFolderChangeInfo to append from
  *
- * Concatenate one change info onto antoher.  Can be used to copy them
+ * Concatenate one change info onto antoher. Can be used to copy them
  * too.
  **/
 void
 camel_folder_change_info_cat (CamelFolderChangeInfo *info,
-                              CamelFolderChangeInfo *source)
+                              CamelFolderChangeInfo *src)
 {
        g_return_if_fail (info != NULL);
-       g_return_if_fail (source != NULL);
+       g_return_if_fail (src != NULL);
 
-       change_info_cat (info, source->uid_added, camel_folder_change_info_add_uid);
-       change_info_cat (info, source->uid_removed, camel_folder_change_info_remove_uid);
-       change_info_cat (info, source->uid_changed, camel_folder_change_info_change_uid);
-       change_info_cat (info, source->uid_recent, change_info_recent_uid);
-       change_info_cat (info, source->priv->uid_filter, change_info_filter_uid);
+       change_info_cat (info, src->uid_added, camel_folder_change_info_add_uid);
+       change_info_cat (info, src->uid_removed, camel_folder_change_info_remove_uid);
+       change_info_cat (info, src->uid_changed, camel_folder_change_info_change_uid);
+       change_info_cat (info, src->uid_recent, change_info_recent_uid);
+       change_info_cat (info, src->priv->uid_filter, change_info_filter_uid);
 }
 
 /**
@@ -4565,6 +4651,82 @@ camel_folder_change_info_changed (CamelFolderChangeInfo *info)
 }
 
 /**
+ * camel_folder_change_info_get_added_uids:
+ * @info: a #CamelFolderChangeInfo
+ *
+ * Returns an array of added messages UIDs. The returned array, the same as its content,
+ * is owned by the @info.
+ *
+ * Returns: (element-type utf8) (transfer none): An array of added UIDs.
+ *
+ * Since: 3.24
+ **/
+GPtrArray *
+camel_folder_change_info_get_added_uids (CamelFolderChangeInfo *info)
+{
+       g_return_val_if_fail (info != NULL, NULL);
+
+       return info->uid_added;
+}
+
+/**
+ * camel_folder_change_info_get_removed_uids:
+ * @info: a #CamelFolderChangeInfo
+ *
+ * Returns an array of removed messages UIDs. The returned array, the same as its content,
+ * is owned by the @info.
+ *
+ * Returns: (element-type utf8) (transfer none): An array of removed UIDs.
+ *
+ * Since: 3.24
+ **/
+GPtrArray *
+camel_folder_change_info_get_removed_uids (CamelFolderChangeInfo *info)
+{
+       g_return_val_if_fail (info != NULL, NULL);
+
+       return info->uid_removed;
+}
+
+/**
+ * camel_folder_change_info_get_changed_uids:
+ * @info: a #CamelFolderChangeInfo
+ *
+ * Returns an array of changed messages UIDs. The returned array, the same as its content,
+ * is owned by the @info.
+ *
+ * Returns: (element-type utf8) (transfer none): An array of changed UIDs.
+ *
+ * Since: 3.24
+ **/
+GPtrArray *
+camel_folder_change_info_get_changed_uids (CamelFolderChangeInfo *info)
+{
+       g_return_val_if_fail (info != NULL, NULL);
+
+       return info->uid_changed;
+}
+
+/**
+ * camel_folder_change_info_get_recent_uids:
+ * @info: a #CamelFolderChangeInfo
+ *
+ * Returns an array of recent messages UIDs. The returned array, the same as its content,
+ * is owned by the @info.
+ *
+ * Returns: (element-type utf8) (transfer none): An array of recent UIDs.
+ *
+ * Since: 3.24
+ **/
+GPtrArray *
+camel_folder_change_info_get_recent_uids (CamelFolderChangeInfo *info)
+{
+       g_return_val_if_fail (info != NULL, NULL);
+
+       return info->uid_recent;
+}
+
+/**
  * camel_folder_change_info_clear:
  * @info: a #CamelFolderChangeInfo
  *
diff --git a/src/camel/camel-folder.h b/src/camel/camel-folder.h
index df2cdbb..f68a192 100644
--- a/src/camel/camel-folder.h
+++ b/src/camel/camel-folder.h
@@ -49,6 +49,8 @@
        (G_TYPE_INSTANCE_GET_CLASS \
        ((obj), CAMEL_TYPE_FOLDER, CamelFolderClass))
 
+#define CAMEL_TYPE_FOLDER_CHANGE_INFO (camel_folder_change_info_get_type ())
+
 /**
  * CAMEL_FOLDER_ERROR:
  *
@@ -100,6 +102,7 @@ struct _CamelFolderChangeInfo {
        GPtrArray *uid_changed;
        GPtrArray *uid_recent;
 
+       /*< private >*/
        CamelFolderChangeInfoPrivate *priv;
 };
 
@@ -121,14 +124,6 @@ struct _CamelFolderQuotaInfo {
 struct _CamelFolder {
        CamelObject parent;
        CamelFolderPrivate *priv;
-
-       CamelFolderSummary *summary;
-
-       CamelFolderFlags folder_flags;
-       CamelMessageFlags permanent_flags;
-
-       /* Future ABI expansion */
-       gpointer later[4];
 };
 
 struct _CamelFolderClass {
@@ -136,15 +131,13 @@ struct _CamelFolderClass {
 
        /* Non-Blocking Methods */
        gint            (*get_message_count)    (CamelFolder *folder);
-       CamelMessageFlags
-                       (*get_permanent_flags)  (CamelFolder *folder);
-       CamelMessageFlags
-                       (*get_message_flags)    (CamelFolder *folder,
+       guint32         (*get_permanent_flags)  (CamelFolder *folder);
+       guint32         (*get_message_flags)    (CamelFolder *folder,
                                                 const gchar *uid);
        gboolean        (*set_message_flags)    (CamelFolder *folder,
                                                 const gchar *uid,
-                                                CamelMessageFlags flags,
-                                                CamelMessageFlags set);
+                                                guint32 mask,
+                                                guint32 set);
        gboolean        (*get_message_user_flag)(CamelFolder *folder,
                                                 const gchar *uid,
                                                 const gchar *name);
@@ -254,8 +247,8 @@ struct _CamelFolderClass {
        void            (*prepare_content_refresh)
                                                (CamelFolder *folder);
 
-       /* Reserved slots for methods. */
-       gpointer reserved_for_methods[19];
+       /* Padding for future expansion */
+       gpointer reserved_methods[20];
 
        /* Signals */
        void            (*changed)              (CamelFolder *folder,
@@ -263,6 +256,9 @@ struct _CamelFolderClass {
        void            (*deleted)              (CamelFolder *folder);
        void            (*renamed)              (CamelFolder *folder,
                                                 const gchar *old_name);
+
+       /* Padding for future expansion */
+       gpointer reserved_signals[20];
 };
 
 GType          camel_folder_get_type           (void);
@@ -271,6 +267,11 @@ void               camel_folder_set_lock_async     (CamelFolder *folder,
                                                 gboolean skip_folder_lock);
 struct _CamelStore *
                camel_folder_get_parent_store   (CamelFolder *folder);
+CamelFolderSummary *
+               camel_folder_get_folder_summary (CamelFolder *folder);
+void           camel_folder_take_folder_summary
+                                               (CamelFolder *folder,
+                                                CamelFolderSummary *summary);
 const gchar *  camel_folder_get_full_name      (CamelFolder *folder);
 gchar *                camel_folder_dup_full_name      (CamelFolder *folder);
 void           camel_folder_set_full_name      (CamelFolder *folder,
@@ -283,17 +284,18 @@ const gchar *     camel_folder_get_description    (CamelFolder *folder);
 gchar *                camel_folder_dup_description    (CamelFolder *folder);
 void           camel_folder_set_description    (CamelFolder *folder,
                                                 const gchar *description);
-CamelMessageFlags
-               camel_folder_get_permanent_flags
+guint32                camel_folder_get_flags          (CamelFolder *folder);
+void           camel_folder_set_flags          (CamelFolder *folder,
+                                                guint32 folder_flags);
+guint32                camel_folder_get_permanent_flags
                                                (CamelFolder *folder);
 #ifndef CAMEL_DISABLE_DEPRECATED
-CamelMessageFlags
-               camel_folder_get_message_flags  (CamelFolder *folder,
+guint32                camel_folder_get_message_flags  (CamelFolder *folder,
                                                 const gchar *uid);
 gboolean       camel_folder_set_message_flags  (CamelFolder *folder,
                                                 const gchar *uid,
-                                                CamelMessageFlags flags,
-                                                CamelMessageFlags set);
+                                                guint32 mask,
+                                                guint32 set);
 gboolean       camel_folder_get_message_user_flag
                                                (CamelFolder *folder,
                                                 const gchar *uid,
@@ -380,8 +382,6 @@ CamelFolderQuotaInfo *
 CamelFolderQuotaInfo *
                camel_folder_quota_info_clone   (const CamelFolderQuotaInfo *info);
 void           camel_folder_quota_info_free    (CamelFolderQuotaInfo *info);
-void           camel_folder_free_nop           (CamelFolder *folder,
-                                                GPtrArray *array);
 void           camel_folder_free_shallow       (CamelFolder *folder,
                                                 GPtrArray *array);
 void           camel_folder_free_deep          (CamelFolder *folder,
@@ -537,11 +537,23 @@ void              camel_folder_prepare_content_refresh
                                                (CamelFolder *folder);
 
 /* update functions for change info */
+GType          camel_folder_change_info_get_type
+                                               (void) G_GNUC_CONST;
 CamelFolderChangeInfo *
                camel_folder_change_info_new    (void);
+CamelFolderChangeInfo *
+               camel_folder_change_info_copy   (CamelFolderChangeInfo *src);
 void           camel_folder_change_info_clear  (CamelFolderChangeInfo *info);
 void           camel_folder_change_info_free   (CamelFolderChangeInfo *info);
 gboolean       camel_folder_change_info_changed (CamelFolderChangeInfo *info);
+GPtrArray *    camel_folder_change_info_get_added_uids
+                                               (CamelFolderChangeInfo *info);
+GPtrArray *    camel_folder_change_info_get_removed_uids
+                                               (CamelFolderChangeInfo *info);
+GPtrArray *    camel_folder_change_info_get_changed_uids
+                                               (CamelFolderChangeInfo *info);
+GPtrArray *    camel_folder_change_info_get_recent_uids
+                                               (CamelFolderChangeInfo *info);
 
 /* for building diff's automatically */
 void           camel_folder_change_info_add_source
diff --git a/src/camel/camel-gpg-context.c b/src/camel/camel-gpg-context.c
index b539272..4194637 100644
--- a/src/camel/camel-gpg-context.c
+++ b/src/camel/camel-gpg-context.c
@@ -2082,7 +2082,7 @@ gpg_verify_sync (CamelCipherContext *context,
        class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
 
        mps = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) ipart);
-       ct = ((CamelDataWrapper *) mps)->mime_type;
+       ct = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (mps));
 
        /* Inline signature (using our fake mime type) or PGP/Mime signature */
        if (camel_content_type_is (ct, "multipart", "signed")) {
diff --git a/src/camel/camel-gpg-context.h b/src/camel/camel-gpg-context.h
index 763bc23..667f74e 100644
--- a/src/camel/camel-gpg-context.h
+++ b/src/camel/camel-gpg-context.h
@@ -59,6 +59,9 @@ struct _CamelGpgContext {
 
 struct _CamelGpgContextClass {
        CamelCipherContextClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_gpg_context_get_type      (void);
diff --git a/src/camel/camel-html-parser.h b/src/camel/camel-html-parser.h
index b299a4d..06d8d82 100644
--- a/src/camel/camel-html-parser.h
+++ b/src/camel/camel-html-parser.h
@@ -82,6 +82,9 @@ struct _CamelHTMLParser {
 
 struct _CamelHTMLParserClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_html_parser_get_type      (void);
diff --git a/src/camel/camel-iconv.c b/src/camel/camel-iconv.c
index ed5b2fe..723707f 100644
--- a/src/camel/camel-iconv.c
+++ b/src/camel/camel-iconv.c
@@ -369,12 +369,18 @@ flush_entry (struct _iconv_cache *ic)
        g_free (ic);
 }
 
-/* This should run pretty quick, its called a lot */
+/**
+ * camel_iconv_open: (skip)
+ * @to: charset to convert to
+ * @from: charset to covert from
+ *
+ * Returns: a #GIConv for the conversion from charset @from to charset @to, or (GIConv) -1 on error.
+ **/
 GIConv
-camel_iconv_open (const gchar *oto,
-                  const gchar *ofrom)
+camel_iconv_open (const gchar *to,
+                  const gchar *from)
 {
-       const gchar *to, *from;
+       const gchar *nto, *nfrom;
        gchar *tofrom;
        gsize tofrom_len;
        struct _iconv_cache *ic;
@@ -382,16 +388,16 @@ camel_iconv_open (const gchar *oto,
        gint errnosav;
        GIConv ip;
 
-       if (oto == NULL || ofrom == NULL) {
+       if (to == NULL || from == NULL) {
                errno = EINVAL;
                return (GIConv) -1;
        }
 
-       to = camel_iconv_charset_name (oto);
-       from = camel_iconv_charset_name (ofrom);
-       tofrom_len = strlen (to) + strlen (from) + 2;
+       nto = camel_iconv_charset_name (to);
+       nfrom = camel_iconv_charset_name (from);
+       tofrom_len = strlen (nto) + strlen (nfrom) + 2;
        tofrom = g_alloca (tofrom_len);
-       g_snprintf (tofrom, tofrom_len, "%s%%%s", to, from);
+       g_snprintf (tofrom, tofrom_len, "%s%%%s", nto, nfrom);
 
        G_LOCK (iconv);
 
@@ -449,7 +455,7 @@ camel_iconv_open (const gchar *oto,
                }
        } else {
                cd (printf ("creating new iconv converter '%s'\n", ic->conv));
-               ip = g_iconv_open (to, from);
+               ip = g_iconv_open (nto, nfrom);
                in = g_malloc (sizeof (*in));
                in->ip = ip;
                in->parent = ic;
@@ -459,7 +465,7 @@ camel_iconv_open (const gchar *oto,
                        in->busy = TRUE;
                } else {
                        errnosav = errno;
-                       g_warning ("Could not open converter for '%s' to '%s' charset", from, to);
+                       g_warning ("Could not open converter for '%s' to '%s' charset", nfrom, nto);
                        in->busy = FALSE;
                        errno = errnosav;
                }
diff --git a/src/camel/camel-index.h b/src/camel/camel-index.h
index 5bec6cf..fa49ddc 100644
--- a/src/camel/camel-index.h
+++ b/src/camel/camel-index.h
@@ -94,7 +94,7 @@ typedef struct _CamelIndexCursor CamelIndexCursor;
 typedef struct _CamelIndexCursorClass CamelIndexCursorClass;
 typedef struct _CamelIndexCursorPrivate CamelIndexCursorPrivate;
 
-typedef gchar * (*CamelIndexNorm)(CamelIndex *index, const gchar *word, gpointer data);
+typedef gchar * (*CamelIndexNorm)(CamelIndex *index, const gchar *word, gpointer user_data);
 
 /* ********************************************************************** */
 
@@ -109,6 +109,9 @@ struct _CamelIndexCursorClass {
        GObjectClass parent;
 
        const gchar * (*next) (CamelIndexCursor *idc);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType           camel_index_cursor_get_type (void);
diff --git a/src/camel/camel-internet-address.c b/src/camel/camel-internet-address.c
index 42f87ca..ef7ee51 100644
--- a/src/camel/camel-internet-address.c
+++ b/src/camel/camel-internet-address.c
@@ -25,6 +25,10 @@
 
 #define d(x)
 
+struct _CamelInternetAddressPrivate {
+       GPtrArray *addresses;
+};
+
 struct _address {
        gchar *name;
        gchar *address;
@@ -33,11 +37,21 @@ struct _address {
 G_DEFINE_TYPE (CamelInternetAddress, camel_internet_address, CAMEL_TYPE_ADDRESS)
 
 static gint
-internet_address_decode (CamelAddress *a,
+internet_address_length (CamelAddress *paddr)
+{
+       CamelInternetAddress *inet_addr = CAMEL_INTERNET_ADDRESS (paddr);
+
+       g_return_val_if_fail (inet_addr != NULL, -1);
+
+       return inet_addr->priv->addresses->len;
+}
+
+static gint
+internet_address_decode (CamelAddress *addr,
                          const gchar *raw)
 {
        CamelHeaderAddress *ha, *n;
-       gint count = a->addresses->len;
+       gint count = camel_address_length (addr);
 
        /* Should probably use its own decoder or something */
        ha = camel_header_address_decode (raw, NULL);
@@ -45,12 +59,12 @@ internet_address_decode (CamelAddress *a,
                n = ha;
                while (n) {
                        if (n->type == CAMEL_HEADER_ADDRESS_NAME) {
-                               camel_internet_address_add ((CamelInternetAddress *) a, n->name, n->v.addr);
+                               camel_internet_address_add ((CamelInternetAddress *) addr, n->name, 
n->v.addr);
                        } else if (n->type == CAMEL_HEADER_ADDRESS_GROUP) {
                                CamelHeaderAddress *g = n->v.members;
                                while (g) {
                                        if (g->type == CAMEL_HEADER_ADDRESS_NAME)
-                                               camel_internet_address_add ((CamelInternetAddress *) a, 
g->name, g->v.addr);
+                                               camel_internet_address_add ((CamelInternetAddress *) addr, 
g->name, g->v.addr);
                                        /* otherwise, it's an error, infact */
                                        g = g->next;
                                }
@@ -60,24 +74,25 @@ internet_address_decode (CamelAddress *a,
                camel_header_address_list_clear (&ha);
        }
 
-       return a->addresses->len - count;
+       return camel_address_length (addr) - count;
 }
 
 static gchar *
-internet_address_encode (CamelAddress *a)
+internet_address_encode (CamelAddress *paddr)
 {
+       CamelInternetAddress *inet_addr = CAMEL_INTERNET_ADDRESS (paddr);
        gint i;
        GString *out;
        gchar *ret;
        gint len = 6;           /* "From: ", assume longer of the address headers */
 
-       if (a->addresses->len == 0)
+       if (inet_addr->priv->addresses->len == 0)
                return NULL;
 
        out = g_string_new ("");
 
-       for (i = 0; i < a->addresses->len; i++) {
-               struct _address *addr = g_ptr_array_index (a->addresses, i);
+       for (i = 0; i < inet_addr->priv->addresses->len; i++) {
+               struct _address *addr = g_ptr_array_index (inet_addr->priv->addresses, i);
                gchar *enc;
 
                if (i != 0)
@@ -95,12 +110,13 @@ internet_address_encode (CamelAddress *a)
 }
 
 static gint
-internet_address_unformat (CamelAddress *a,
+internet_address_unformat (CamelAddress *paddr,
                            const gchar *raw)
 {
+       CamelInternetAddress *inet_addr = CAMEL_INTERNET_ADDRESS (paddr);
        gchar *buffer, *p, *name, *addr;
        gint c;
-       gint count = a->addresses->len;
+       gint count = inet_addr->priv->addresses->len;
 
        if (raw == NULL)
                return 0;
@@ -148,7 +164,7 @@ internet_address_unformat (CamelAddress *a,
                        addr = g_strstrip (addr);
                        if (addr[0]) {
                                d (printf ("found address: '%s' <%s>\n", name, addr));
-                               camel_internet_address_add ((CamelInternetAddress *) a, name, addr);
+                               camel_internet_address_add (inet_addr, name, addr);
                        }
                        name = NULL;
                        addr = p;
@@ -158,23 +174,24 @@ internet_address_unformat (CamelAddress *a,
 
        g_free (buffer);
 
-       return a->addresses->len - count;
+       return inet_addr->priv->addresses->len - count;
 }
 
 static gchar *
-internet_address_format (CamelAddress *a)
+internet_address_format (CamelAddress *paddr)
 {
+       CamelInternetAddress *inet_addr = CAMEL_INTERNET_ADDRESS (paddr);
        gint i;
        GString *out;
        gchar *ret;
 
-       if (a->addresses->len == 0)
+       if (inet_addr->priv->addresses->len == 0)
                return NULL;
 
        out = g_string_new ("");
 
-       for (i = 0; i < a->addresses->len; i++) {
-               struct _address *addr = g_ptr_array_index (a->addresses, i);
+       for (i = 0; i < inet_addr->priv->addresses->len; i++) {
+               struct _address *addr = g_ptr_array_index (inet_addr->priv->addresses, i);
                gchar *enc;
 
                if (i != 0)
@@ -192,43 +209,69 @@ internet_address_format (CamelAddress *a)
 }
 
 static void
-internet_address_remove (CamelAddress *a,
+internet_address_remove (CamelAddress *paddr,
                          gint index)
 {
+       CamelInternetAddress *inet_addr = CAMEL_INTERNET_ADDRESS (paddr);
        struct _address *addr;
 
-       if (index < 0 || index >= a->addresses->len)
+       if (index < 0 || index >= inet_addr->priv->addresses->len)
                return;
 
-       addr = g_ptr_array_index (a->addresses, index);
+       addr = g_ptr_array_index (inet_addr->priv->addresses, index);
        g_free (addr->name);
        g_free (addr->address);
        g_free (addr);
-       g_ptr_array_remove_index (a->addresses, index);
+       g_ptr_array_remove_index (inet_addr->priv->addresses, index);
 }
 
 static gint
 internet_address_cat (CamelAddress *dest,
                       CamelAddress *source)
 {
+       CamelInternetAddress *dest_inet_addr;
+       CamelInternetAddress *source_inet_addr;
        gint i;
 
+       g_return_val_if_fail (CAMEL_IS_INTERNET_ADDRESS (dest), -1);
        g_return_val_if_fail (CAMEL_IS_INTERNET_ADDRESS (source), -1);
 
-       for (i = 0; i < source->addresses->len; i++) {
-               struct _address *addr = g_ptr_array_index (source->addresses, i);
-               camel_internet_address_add ((CamelInternetAddress *) dest, addr->name, addr->address);
+       dest_inet_addr = CAMEL_INTERNET_ADDRESS (dest);
+       source_inet_addr = CAMEL_INTERNET_ADDRESS (source);
+
+       for (i = 0; i < source_inet_addr->priv->addresses->len; i++) {
+               struct _address *addr = g_ptr_array_index (source_inet_addr->priv->addresses, i);
+               camel_internet_address_add (dest_inet_addr, addr->name, addr->address);
        }
 
        return i;
 }
 
 static void
+internet_address_finalize (GObject *object)
+{
+       CamelInternetAddress *inet_addr = CAMEL_INTERNET_ADDRESS (object);
+
+       camel_address_remove (CAMEL_ADDRESS (inet_addr), -1);
+       g_ptr_array_free (inet_addr->priv->addresses, TRUE);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (camel_internet_address_parent_class)->finalize (object);
+}
+
+static void
 camel_internet_address_class_init (CamelInternetAddressClass *class)
 {
        CamelAddressClass *address_class;
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelInternetAddressPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->finalize = internet_address_finalize;
 
        address_class = CAMEL_ADDRESS_CLASS (class);
+       address_class->length = internet_address_length;
        address_class->decode = internet_address_decode;
        address_class->encode = internet_address_encode;
        address_class->unformat = internet_address_unformat;
@@ -240,6 +283,8 @@ camel_internet_address_class_init (CamelInternetAddressClass *class)
 static void
 camel_internet_address_init (CamelInternetAddress *internet_address)
 {
+       internet_address->priv = G_TYPE_INSTANCE_GET_PRIVATE (internet_address, CAMEL_TYPE_INTERNET_ADDRESS, 
CamelInternetAddressPrivate);
+       internet_address->priv->addresses = g_ptr_array_new ();
 }
 
 /**
@@ -278,8 +323,8 @@ camel_internet_address_add (CamelInternetAddress *addr,
        new = g_malloc (sizeof (*new));
        new->name = g_strdup (name);
        new->address = g_strdup (address);
-       index = ((CamelAddress *) addr)->addresses->len;
-       g_ptr_array_add (((CamelAddress *) addr)->addresses, new);
+       index = addr->priv->addresses->len;
+       g_ptr_array_add (addr->priv->addresses, new);
 
        return index;
 }
@@ -305,10 +350,10 @@ camel_internet_address_get (CamelInternetAddress *addr,
 
        g_return_val_if_fail (CAMEL_IS_INTERNET_ADDRESS (addr), FALSE);
 
-       if (index < 0 || index >= ((CamelAddress *) addr)->addresses->len)
+       if (index < 0 || index >= addr->priv->addresses->len)
                return FALSE;
 
-       a = g_ptr_array_index (((CamelAddress *) addr)->addresses, index);
+       a = g_ptr_array_index (addr->priv->addresses, index);
        if (namep)
                *namep = a->name;
        if (addressp)
@@ -337,9 +382,9 @@ camel_internet_address_find_name (CamelInternetAddress *addr,
 
        g_return_val_if_fail (CAMEL_IS_INTERNET_ADDRESS (addr), -1);
 
-       len = ((CamelAddress *) addr)->addresses->len;
+       len = addr->priv->addresses->len;
        for (i = 0; i < len; i++) {
-               a = g_ptr_array_index (((CamelAddress *) addr)->addresses, i);
+               a = g_ptr_array_index (addr->priv->addresses, i);
                if (a->name && !strcmp (a->name, name)) {
                        if (addressp)
                                *addressp = a->address;
@@ -391,10 +436,10 @@ camel_internet_address_ensure_ascii_domains (CamelInternetAddress *addr)
 
        g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (addr));
 
-       len = ((CamelAddress *) addr)->addresses->len;
+       len = addr->priv->addresses->len;
        for (i = 0; i < len; i++) {
                gint at_pos = -1;
-               a = g_ptr_array_index (((CamelAddress *) addr)->addresses, i);
+               a = g_ptr_array_index (addr->priv->addresses, i);
                if (a->address && !domain_contains_only_ascii (a->address, &at_pos)) {
                        gchar *address, *domain;
 
@@ -434,9 +479,9 @@ camel_internet_address_find_address (CamelInternetAddress *addr,
 
        g_return_val_if_fail (CAMEL_IS_INTERNET_ADDRESS (addr), -1);
 
-       len = ((CamelAddress *) addr)->addresses->len;
+       len = addr->priv->addresses->len;
        for (i = 0; i < len; i++) {
-               a = g_ptr_array_index (((CamelAddress *) addr)->addresses, i);
+               a = g_ptr_array_index (addr->priv->addresses, i);
                if (!strcmp (a->address, address)) {
                        if (namep)
                                *namep = a->name;
diff --git a/src/camel/camel-internet-address.h b/src/camel/camel-internet-address.h
index 4253abb..9562460 100644
--- a/src/camel/camel-internet-address.h
+++ b/src/camel/camel-internet-address.h
@@ -58,6 +58,9 @@ struct _CamelInternetAddress {
 
 struct _CamelInternetAddressClass {
        CamelAddressClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_internet_address_get_type (void);
diff --git a/src/camel/camel-junk-filter.h b/src/camel/camel-junk-filter.h
index b27064f..b36abe7 100644
--- a/src/camel/camel-junk-filter.h
+++ b/src/camel/camel-junk-filter.h
@@ -75,6 +75,9 @@ struct _CamelJunkFilterInterface {
        gboolean        (*synchronize)          (CamelJunkFilter *junk_filter,
                                                 GCancellable *cancellable,
                                                 GError **error);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_junk_filter_get_type      (void) G_GNUC_CONST;
diff --git a/src/camel/camel-local-settings.h b/src/camel/camel-local-settings.h
index 6ae5d1d..eedb42b 100644
--- a/src/camel/camel-local-settings.h
+++ b/src/camel/camel-local-settings.h
@@ -64,6 +64,9 @@ struct _CamelLocalSettings {
 
 struct _CamelLocalSettingsClass {
        CamelStoreSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_local_settings_get_type   (void) G_GNUC_CONST;
diff --git a/src/camel/camel-medium.c b/src/camel/camel-medium.c
index dc0d5d0..2165881 100644
--- a/src/camel/camel-medium.c
+++ b/src/camel/camel-medium.c
@@ -178,7 +178,7 @@ camel_medium_init (CamelMedium *medium)
 void
 camel_medium_add_header (CamelMedium *medium,
                          const gchar *name,
-                         gconstpointer value)
+                         const gchar *value)
 {
        CamelMediumClass *class;
 
@@ -205,7 +205,7 @@ camel_medium_add_header (CamelMedium *medium,
 void
 camel_medium_set_header (CamelMedium *medium,
                          const gchar *name,
-                         gconstpointer value)
+                         const gchar *value)
 {
        CamelMediumClass *class;
 
@@ -256,11 +256,11 @@ camel_medium_remove_header (CamelMedium *medium,
  *
  * If the header occurs more than once, only retrieve the first
  * instance of the header.  For multi-occuring headers, use
- * :get_headers().
+ * camel_medium_dup_headers() or camel_medium_get_headers().
  *
- * Returns: (transfer none) (nullable): the value of the named header, or %NULL
+ * Returns: (nullable): the value of the named header, or %NULL
  **/
-gconstpointer
+const gchar *
 camel_medium_get_header (CamelMedium *medium,
                          const gchar *name)
 {
@@ -276,51 +276,53 @@ camel_medium_get_header (CamelMedium *medium,
 }
 
 /**
- * camel_medium_get_headers:
+ * camel_medium_dup_headers:
  * @medium: a #CamelMedium object
  *
- * Gets an array of all header name/value pairs (as
- * CamelMediumHeader structures). The values will be decoded
- * to UTF-8 for any headers that are recognized by Camel. The
- * caller should not modify the returned data.
+ * Gets an array of all header name/value pairs. The values will be
+ * decoded to UTF-8 for any headers that are recognized by Camel.
+ * See also camel_medium_get_headers().
+ *
+ * Returns: (transfer full): the array of headers, which must be freed with camel_name_value_array_free().
  *
- * Returns: (element-type CamelMediumHeader) (transfer full): the array of
- * headers, which must be freed with camel_medium_free_headers().
+ * Since: 3.24
  **/
-GArray *
-camel_medium_get_headers (CamelMedium *medium)
+CamelNameValueArray *
+camel_medium_dup_headers (CamelMedium *medium)
 {
        CamelMediumClass *class;
 
        g_return_val_if_fail (CAMEL_IS_MEDIUM (medium), NULL);
 
        class = CAMEL_MEDIUM_GET_CLASS (medium);
-       g_return_val_if_fail (class->get_headers != NULL, NULL);
+       g_return_val_if_fail (class->dup_headers != NULL, NULL);
 
-       return class->get_headers (medium);
+       return class->dup_headers (medium);
 }
 
 /**
- * camel_medium_free_headers:
+ * camel_medium_get_headers:
  * @medium: a #CamelMedium object
- * @headers: (element-type CamelMediumHeader): an array of headers returned
- * from camel_medium_get_headers()
  *
- * Frees @headers.
+ * Gets an array of all header name/value pairs. The values will be
+ * decoded to UTF-8 for any headers that are recognized by Camel.
+ * See also camel_medium_dup_headers().
+ *
+ * Returns: (transfer none): the array of headers, owned by @medium.
+ *
+ * Since: 3.24
  **/
-void
-camel_medium_free_headers (CamelMedium *medium,
-                           GArray *headers)
+const CamelNameValueArray *
+camel_medium_get_headers (CamelMedium *medium)
 {
        CamelMediumClass *class;
 
-       g_return_if_fail (CAMEL_IS_MEDIUM (medium));
-       g_return_if_fail (headers != NULL);
+       g_return_val_if_fail (CAMEL_IS_MEDIUM (medium), NULL);
 
        class = CAMEL_MEDIUM_GET_CLASS (medium);
-       g_return_if_fail (class->free_headers != NULL);
+       g_return_val_if_fail (class->get_headers != NULL, NULL);
 
-       class->free_headers (medium, headers);
+       return class->get_headers (medium);
 }
 
 /**
diff --git a/src/camel/camel-medium.h b/src/camel/camel-medium.h
index 3d83723..9872cc6 100644
--- a/src/camel/camel-medium.h
+++ b/src/camel/camel-medium.h
@@ -27,6 +27,7 @@
 #define CAMEL_MEDIUM_H
 
 #include <camel/camel-data-wrapper.h>
+#include <camel/camel-name-value-array.h>
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_MEDIUM \
@@ -53,11 +54,6 @@ typedef struct _CamelMedium CamelMedium;
 typedef struct _CamelMediumClass CamelMediumClass;
 typedef struct _CamelMediumPrivate CamelMediumPrivate;
 
-typedef struct {
-       const gchar *name;
-       const gchar *value;
-} CamelMediumHeader;
-
 struct _CamelMedium {
        CamelDataWrapper parent;
        CamelMediumPrivate *priv;
@@ -68,37 +64,42 @@ struct _CamelMediumClass {
 
        void            (*add_header)           (CamelMedium *medium,
                                                 const gchar *name,
-                                                gconstpointer value);
+                                                const gchar *value);
        void            (*set_header)           (CamelMedium *medium,
                                                 const gchar *name,
-                                                gconstpointer value);
+                                                const gchar *value);
        void            (*remove_header)        (CamelMedium *medium,
                                                 const gchar *name);
-       gconstpointer   (*get_header)           (CamelMedium *medium,
+       const gchar *   (*get_header)           (CamelMedium *medium,
                                                 const gchar *name);
-       GArray *        (*get_headers)          (CamelMedium *medium);
-       void            (*free_headers)         (CamelMedium *medium,
-                                                GArray *headers);
+       CamelNameValueArray *
+                       (*dup_headers)          (CamelMedium *medium);
+       const CamelNameValueArray *
+                       (*get_headers)          (CamelMedium *medium);
        CamelDataWrapper *
                        (*get_content)          (CamelMedium *medium);
        void            (*set_content)          (CamelMedium *medium,
                                                 CamelDataWrapper *content);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_medium_get_type           (void);
 void           camel_medium_add_header         (CamelMedium *medium,
                                                 const gchar *name,
-                                                gconstpointer value);
+                                                const gchar *value);
 void           camel_medium_set_header         (CamelMedium *medium,
                                                 const gchar *name,
-                                                gconstpointer value);
+                                                const gchar *value);
 void           camel_medium_remove_header      (CamelMedium *medium,
                                                 const gchar *name);
-gconstpointer  camel_medium_get_header         (CamelMedium *medium,
+const gchar *  camel_medium_get_header         (CamelMedium *medium,
                                                 const gchar *name);
-GArray *       camel_medium_get_headers        (CamelMedium *medium);
-void           camel_medium_free_headers       (CamelMedium *medium,
-                                                GArray *headers);
+CamelNameValueArray *
+               camel_medium_dup_headers        (CamelMedium *medium);
+const CamelNameValueArray *
+               camel_medium_get_headers        (CamelMedium *medium);
 CamelDataWrapper *
                camel_medium_get_content        (CamelMedium *medium);
 void           camel_medium_set_content        (CamelMedium *medium,
diff --git a/src/camel/camel-memchunk.c b/src/camel/camel-memchunk.c
index d99f3de..8f3991b 100644
--- a/src/camel/camel-memchunk.c
+++ b/src/camel/camel-memchunk.c
@@ -72,7 +72,7 @@ struct _CamelMemChunk {
 };
 
 /**
- * camel_memchunk_new:
+ * camel_memchunk_new: (skip)
  * @atomcount: the number of atoms stored in a single malloc'd block of memory
  * @atomsize: the size of each allocation
  *
@@ -102,7 +102,7 @@ camel_memchunk_new (gint atomcount,
 }
 
 /**
- * camel_memchunk_alloc:
+ * camel_memchunk_alloc: (skip)
  * @memchunk: an #CamelMemChunk
  *
  * Allocate a new atom size block of memory from an #CamelMemChunk.
@@ -141,7 +141,7 @@ camel_memchunk_alloc (CamelMemChunk *memchunk)
 }
 
 /**
- * camel_memchunk_alloc0:
+ * camel_memchunk_alloc0: (skip)
  * @memchunk: an #CamelMemChunk
  *
  * Allocate a new atom size block of memory from an #CamelMemChunk,
@@ -164,7 +164,7 @@ camel_memchunk_alloc0 (CamelMemChunk *memchunk)
 }
 
 /**
- * camel_memchunk_free:
+ * camel_memchunk_free: (skip)
  * @memchunk: an #CamelMemChunk
  * @mem: address of atom to free
  *
@@ -194,7 +194,7 @@ camel_memchunk_free (CamelMemChunk *memchunk,
 }
 
 /**
- * camel_memchunk_empty:
+ * camel_memchunk_empty: (skip)
  * @memchunk: an #CamelMemChunk
  *
  * Clean out the memchunk buffers.  Marks all allocated memory as free blocks,
@@ -250,7 +250,7 @@ tree_search (struct _cleaninfo *a,
 }
 
 /**
- * camel_memchunk_clean:
+ * camel_memchunk_clean: (skip)
  * @memchunk: an #CamelMemChunk
  *
  * Scan all empty blocks and check for blocks which can be free'd
@@ -328,7 +328,7 @@ camel_memchunk_clean (CamelMemChunk *memchunk)
 }
 
 /**
- * camel_memchunk_destroy:
+ * camel_memchunk_destroy: (skip)
  * @memchunk: an #CamelMemChunk
  *
  * Free the memchunk header, and all associated memory.
diff --git a/src/camel/camel-mempool.c b/src/camel/camel-mempool.c
index bc2fade..2c9bc2b 100644
--- a/src/camel/camel-mempool.c
+++ b/src/camel/camel-mempool.c
@@ -41,7 +41,7 @@ struct _CamelMemPool {
 };
 
 /**
- * camel_mempool_new:
+ * camel_mempool_new: (skip)
  * @blocksize: The base blocksize to use for all system alocations.
  * @threshold: If the allocation exceeds the threshold, then it is
  * allocated separately and stored in a separate list.
@@ -94,7 +94,7 @@ camel_mempool_new (gint blocksize,
 }
 
 /**
- * camel_mempool_alloc:
+ * camel_mempool_alloc: (skip)
  * @pool: a #CamelMemPool
  * @size:
  *
@@ -137,7 +137,7 @@ camel_mempool_alloc (CamelMemPool *pool,
 }
 
 /**
- * camel_mempool_strdup:
+ * camel_mempool_strdup: (skip)
  * @pool: a #CamelMemPool
  * @str:
  *
@@ -158,7 +158,7 @@ camel_mempool_strdup (CamelMemPool *pool,
 }
 
 /**
- * camel_mempool_flush:
+ * camel_mempool_flush: (skip)
  * @pool: a #CamelMemPool
  * @freeall: free all system allocated blocks as well
  *
@@ -203,7 +203,7 @@ camel_mempool_flush (CamelMemPool *pool,
 }
 
 /**
- * camel_mempool_destroy:
+ * camel_mempool_destroy: (skip)
  * @pool: a #CamelMemPool
  *
  * Free all memory associated with a mempool.
diff --git a/src/camel/camel-message-info-base.c b/src/camel/camel-message-info-base.c
new file mode 100644
index 0000000..71b1b70
--- /dev/null
+++ b/src/camel/camel-message-info-base.c
@@ -0,0 +1,877 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+
+#include "camel-folder-summary.h"
+#include "camel-message-info.h"
+
+#include "camel-message-info-base.h"
+
+struct _CamelMessageInfoBasePrivate {
+       guint32 flags;          /* bit-or of CamelMessageFlags */
+       CamelNamedFlags *user_flags;
+       CamelNameValueArray *user_tags;
+       gchar *subject;
+       gchar *from;
+       gchar *to;
+       gchar *cc;
+       gchar *mlist;
+       guint32 size;
+       gint64 date_sent;       /* aka time_t */
+       gint64 date_received;   /* aka time_t */
+       guint64 message_id;
+       GArray *references;     /* guint64, aka CamelSummaryMessageID */
+       CamelNameValueArray *headers;
+};
+
+G_DEFINE_TYPE (CamelMessageInfoBase, camel_message_info_base, CAMEL_TYPE_MESSAGE_INFO)
+
+static guint32
+message_info_base_get_flags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       guint32 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->flags;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_flags (CamelMessageInfo *mi,
+                            guint32 mask,
+                            guint32 set)
+{
+       CamelMessageInfoBase *bmi;
+       guint32 old_flags;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       old_flags = bmi->priv->flags;
+       bmi->priv->flags = (old_flags & ~mask) | (set & mask);
+       changed = old_flags != bmi->priv->flags;
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static gboolean
+message_info_base_get_user_flag (const CamelMessageInfo *mi,
+                                const gchar *name)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       if (bmi->priv->user_flags)
+               result = camel_named_flags_contains (bmi->priv->user_flags, name);
+       else
+               result = FALSE;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_user_flag (CamelMessageInfo *mi,
+                                const gchar *name,
+                                gboolean state)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       if (!bmi->priv->user_flags)
+               bmi->priv->user_flags = camel_named_flags_new ();
+
+       if (state)
+               changed = camel_named_flags_insert (bmi->priv->user_flags, name);
+       else
+               changed = camel_named_flags_remove (bmi->priv->user_flags, name);
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const CamelNamedFlags *
+message_info_base_get_user_flags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const CamelNamedFlags *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->user_flags;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static CamelNamedFlags *
+message_info_base_dup_user_flags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       CamelNamedFlags *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       if (bmi->priv->user_flags)
+               result = camel_named_flags_copy (bmi->priv->user_flags);
+       else
+               result = NULL;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_take_user_flags (CamelMessageInfo *mi,
+                                  CamelNamedFlags *user_flags)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = !camel_named_flags_equal (bmi->priv->user_flags, user_flags);
+
+       if (changed) {
+               camel_named_flags_free (bmi->priv->user_flags);
+               bmi->priv->user_flags = user_flags;
+       } else {
+               camel_named_flags_free (user_flags);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const gchar *
+message_info_base_get_user_tag (const CamelMessageInfo *mi,
+                               const gchar *name)
+{
+       CamelMessageInfoBase *bmi;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+       g_return_val_if_fail (name != NULL, NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       if (bmi->priv->user_tags)
+               result = camel_name_value_array_get_named (bmi->priv->user_tags, 
CAMEL_COMPARE_CASE_SENSITIVE, name);
+       else
+               result = NULL;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_user_tag (CamelMessageInfo *mi,
+                               const gchar *name,
+                               const gchar *value)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       if (!bmi->priv->user_tags)
+               bmi->priv->user_tags = camel_name_value_array_new ();
+
+       if (value)
+               changed = camel_name_value_array_set_named (bmi->priv->user_tags, 
CAMEL_COMPARE_CASE_SENSITIVE, name, value);
+       else
+               changed = camel_name_value_array_remove_named (bmi->priv->user_tags, 
CAMEL_COMPARE_CASE_SENSITIVE, name, FALSE);
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const CamelNameValueArray *
+message_info_base_get_user_tags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->user_tags;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static CamelNameValueArray *
+message_info_base_dup_user_tags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = camel_name_value_array_copy (bmi->priv->user_tags);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_take_user_tags (CamelMessageInfo *mi,
+                                 CamelNameValueArray *user_tags)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = !camel_name_value_array_equal (bmi->priv->user_tags, user_tags, 
CAMEL_COMPARE_CASE_SENSITIVE);
+
+       if (changed) {
+               camel_name_value_array_free (bmi->priv->user_tags);
+               bmi->priv->user_tags = user_tags;
+       } else {
+               camel_name_value_array_free (user_tags);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const gchar *
+message_info_base_get_subject (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->subject;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_subject (CamelMessageInfo *mi,
+                              const gchar *subject)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = g_strcmp0 (bmi->priv->subject, subject) != 0;
+
+       if (changed) {
+               g_free (bmi->priv->subject);
+               bmi->priv->subject = g_strdup (subject);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const gchar *
+message_info_base_get_from (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->from;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_from (CamelMessageInfo *mi,
+                           const gchar *from)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = g_strcmp0 (bmi->priv->from, from) != 0;
+
+       if (changed) {
+               g_free (bmi->priv->from);
+               bmi->priv->from = g_strdup (from);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const gchar *
+message_info_base_get_to (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->to;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_to (CamelMessageInfo *mi,
+                         const gchar *to)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = g_strcmp0 (bmi->priv->to, to) != 0;
+
+       if (changed) {
+               g_free (bmi->priv->to);
+               bmi->priv->to = g_strdup (to);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const gchar *
+message_info_base_get_cc (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->cc;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_cc (CamelMessageInfo *mi,
+                         const gchar *cc)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = g_strcmp0 (bmi->priv->cc, cc) != 0;
+
+       if (changed) {
+               g_free (bmi->priv->cc);
+               bmi->priv->cc = g_strdup (cc);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const gchar *
+message_info_base_get_mlist (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->mlist;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_mlist (CamelMessageInfo *mi,
+                            const gchar *mlist)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = g_strcmp0 (bmi->priv->mlist, mlist) != 0;
+
+       if (changed) {
+               g_free (bmi->priv->mlist);
+               bmi->priv->mlist = g_strdup (mlist);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static guint32
+message_info_base_get_size (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       guint32 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->size;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_size (CamelMessageInfo *mi,
+                           guint32 size)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = bmi->priv->size != size;
+
+       if (changed)
+               bmi->priv->size = size;
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static gint64
+message_info_base_get_date_sent (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       gint64 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->date_sent;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_date_sent (CamelMessageInfo *mi,
+                                gint64 date_sent)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = bmi->priv->date_sent != date_sent;
+
+       if (changed)
+               bmi->priv->date_sent = date_sent;
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static gint64
+message_info_base_get_date_received (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       gint64 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->date_received;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_date_received (CamelMessageInfo *mi,
+                                    gint64 date_received)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = bmi->priv->date_received != date_received;
+
+       if (changed)
+               bmi->priv->date_received = date_received;
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static guint64
+message_info_base_get_message_id (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       guint64 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), 0);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->message_id;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_set_message_id (CamelMessageInfo *mi,
+                                 guint64 message_id)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = bmi->priv->message_id != message_id;
+
+       if (changed)
+               bmi->priv->message_id = message_id;
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const GArray *
+message_info_base_get_references (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const GArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->references;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_references_equal (const GArray *references_a,
+                                   const GArray *references_b)
+{
+       guint ii, len;
+
+       if (references_a == references_b)
+               return TRUE;
+
+       if (!references_a || !references_b)
+               return FALSE;
+
+       len = references_a->len;
+       if (len != references_b->len)
+               return FALSE;
+
+       /* They can be still the same, only having the items on different indexes,
+          but that's too expensive to compare precisely. */
+       for (ii = 0; ii < len; ii++) {
+               if (g_array_index (references_a, guint64, ii) != g_array_index (references_b, guint64, ii))
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean
+message_info_base_take_references (CamelMessageInfo *mi,
+                                  GArray *references)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = !message_info_base_references_equal (bmi->priv->references, references);
+
+       if (changed) {
+               if (bmi->priv->references)
+                       g_array_unref (bmi->priv->references);
+               bmi->priv->references = references;
+       } else if (references) {
+               g_array_unref (references);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static const CamelNameValueArray *
+message_info_base_get_headers (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoBase *bmi;
+       const CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+       result = bmi->priv->headers;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+static gboolean
+message_info_base_take_headers (CamelMessageInfo *mi,
+                               CamelNameValueArray *headers)
+{
+       CamelMessageInfoBase *bmi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO_BASE (mi), FALSE);
+
+       bmi = CAMEL_MESSAGE_INFO_BASE (mi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = !camel_name_value_array_equal (bmi->priv->headers, headers, CAMEL_COMPARE_CASE_SENSITIVE);
+
+       if (changed) {
+               camel_name_value_array_free (bmi->priv->headers);
+               bmi->priv->headers = headers;
+       } else {
+               camel_name_value_array_free (headers);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       return changed;
+}
+
+static void
+message_info_base_dispose (GObject *object)
+{
+       CamelMessageInfoBase *bmi = CAMEL_MESSAGE_INFO_BASE (object);
+
+       camel_named_flags_free (bmi->priv->user_flags);
+       bmi->priv->user_flags = NULL;
+
+       camel_name_value_array_free (bmi->priv->user_tags);
+       bmi->priv->user_tags = NULL;
+
+       #define free_ptr(x) G_STMT_START { g_free (x); x = NULL; } G_STMT_END
+
+       free_ptr (bmi->priv->subject);
+       free_ptr (bmi->priv->from);
+       free_ptr (bmi->priv->to);
+       free_ptr (bmi->priv->cc);
+       free_ptr (bmi->priv->mlist);
+
+       #undef free_ptr
+
+       if (bmi->priv->references) {
+               g_array_unref (bmi->priv->references);
+               bmi->priv->references = NULL;
+       }
+
+       camel_name_value_array_free (bmi->priv->headers);
+       bmi->priv->headers = NULL;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_message_info_base_parent_class)->dispose (object);
+}
+
+static void
+camel_message_info_base_class_init (CamelMessageInfoBaseClass *class)
+{
+       CamelMessageInfoClass *mi_class;
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelMessageInfoBasePrivate));
+
+       mi_class = CAMEL_MESSAGE_INFO_CLASS (class);
+       mi_class->get_flags = message_info_base_get_flags;
+       mi_class->set_flags = message_info_base_set_flags;
+       mi_class->get_user_flag = message_info_base_get_user_flag;
+       mi_class->set_user_flag = message_info_base_set_user_flag;
+       mi_class->get_user_flags = message_info_base_get_user_flags;
+       mi_class->dup_user_flags = message_info_base_dup_user_flags;
+       mi_class->take_user_flags = message_info_base_take_user_flags;
+       mi_class->get_user_tag = message_info_base_get_user_tag;
+       mi_class->set_user_tag = message_info_base_set_user_tag;
+       mi_class->get_user_tags = message_info_base_get_user_tags;
+       mi_class->dup_user_tags = message_info_base_dup_user_tags;
+       mi_class->take_user_tags = message_info_base_take_user_tags;
+       mi_class->get_subject = message_info_base_get_subject;
+       mi_class->set_subject = message_info_base_set_subject;
+       mi_class->get_from = message_info_base_get_from;
+       mi_class->set_from = message_info_base_set_from;
+       mi_class->get_to = message_info_base_get_to;
+       mi_class->set_to = message_info_base_set_to;
+       mi_class->get_cc = message_info_base_get_cc;
+       mi_class->set_cc = message_info_base_set_cc;
+       mi_class->get_mlist = message_info_base_get_mlist;
+       mi_class->set_mlist = message_info_base_set_mlist;
+       mi_class->get_size = message_info_base_get_size;
+       mi_class->set_size = message_info_base_set_size;
+       mi_class->get_date_sent = message_info_base_get_date_sent;
+       mi_class->set_date_sent = message_info_base_set_date_sent;
+       mi_class->get_date_received = message_info_base_get_date_received;
+       mi_class->set_date_received = message_info_base_set_date_received;
+       mi_class->get_message_id = message_info_base_get_message_id;
+       mi_class->set_message_id = message_info_base_set_message_id;
+       mi_class->get_references = message_info_base_get_references;
+       mi_class->take_references = message_info_base_take_references;
+       mi_class->get_headers = message_info_base_get_headers;
+       mi_class->take_headers = message_info_base_take_headers;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = message_info_base_dispose;
+}
+
+static void
+camel_message_info_base_init (CamelMessageInfoBase *bmi)
+{
+       bmi->priv = G_TYPE_INSTANCE_GET_PRIVATE (bmi, CAMEL_TYPE_MESSAGE_INFO_BASE, 
CamelMessageInfoBasePrivate);
+}
diff --git a/src/camel/camel-message-info-base.h b/src/camel/camel-message-info-base.h
new file mode 100644
index 0000000..4343467
--- /dev/null
+++ b/src/camel/camel-message-info-base.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_MESSAGE_INFO_BASE_H
+#define CAMEL_MESSAGE_INFO_BASE_H
+
+#include <glib-object.h>
+
+#include <camel/camel-message-info.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_MESSAGE_INFO_BASE \
+       (camel_message_info_base_get_type ())
+#define CAMEL_MESSAGE_INFO_BASE(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_MESSAGE_INFO_BASE, CamelMessageInfoBase))
+#define CAMEL_MESSAGE_INFO_BASE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_MESSAGE_INFO_BASE, CamelMessageInfoBaseClass))
+#define CAMEL_IS_MESSAGE_INFO_BASE(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_MESSAGE_INFO_BASE))
+#define CAMEL_IS_MESSAGE_INFO_BASE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_MESSAGE_INFO_BASE))
+#define CAMEL_MESSAGE_INFO_BASE_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_MESSAGE_INFO_BASE, CamelMessageInfoBaseClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelMessageInfoBase CamelMessageInfoBase;
+typedef struct _CamelMessageInfoBaseClass CamelMessageInfoBaseClass;
+typedef struct _CamelMessageInfoBasePrivate CamelMessageInfoBasePrivate;
+
+struct _CamelMessageInfoBase {
+       CamelMessageInfo parent;
+       CamelMessageInfoBasePrivate *priv;
+};
+
+struct _CamelMessageInfoBaseClass {
+       CamelMessageInfoClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
+};
+
+GType          camel_message_info_base_get_type        (void);
+
+G_END_DECLS
+
+#endif /* CAMEL_MESSAGE_INFO_BASE_H */
diff --git a/src/camel/camel-message-info.c b/src/camel/camel-message-info.c
new file mode 100644
index 0000000..01664e3
--- /dev/null
+++ b/src/camel/camel-message-info.c
@@ -0,0 +1,2979 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "camel-db.h"
+#include "camel-folder.h"
+#include "camel-folder-summary.h"
+#include "camel-message-info-base.h"
+#include "camel-string-utils.h"
+
+#include "camel-message-info.h"
+
+struct _CamelMessageInfoPrivate {
+       GRecMutex property_lock;
+
+       GWeakRef summary;       /* CamelFolderSummary * */
+       gboolean dirty;         /* whether requires save to local disk/summary */
+       const gchar *uid;       /* allocated in the string pool */
+       gboolean abort_notifications;
+       gboolean thaw_notify_folder;
+       gboolean thaw_notify_folder_with_counts;
+       guint freeze_notifications;
+       guint folder_flagged_stamp;
+};
+
+enum {
+       PROP_0,
+       PROP_SUMMARY,
+       PROP_DIRTY,
+       PROP_FOLDER_FLAGGED,
+       PROP_FOLDER_FLAGGED_STAMP,
+       PROP_ABORT_NOTIFICATIONS,
+       PROP_UID,
+       PROP_FLAGS,
+       PROP_USER_FLAGS,
+       PROP_USER_TAGS,
+       PROP_SUBJECT,
+       PROP_FROM,
+       PROP_TO,
+       PROP_CC,
+       PROP_MLIST,
+       PROP_SIZE,
+       PROP_DATE_SENT,
+       PROP_DATE_RECEIVED,
+       PROP_MESSAGE_ID,
+       PROP_REFERENCES,
+       PROP_HEADERS
+};
+
+G_DEFINE_ABSTRACT_TYPE (CamelMessageInfo, camel_message_info, G_TYPE_OBJECT)
+
+static CamelMessageInfo *
+message_info_clone (const CamelMessageInfo *mi,
+                   CamelFolderSummary *assign_summary)
+{
+       CamelMessageInfo *result;
+       const gchar *uid;
+       const GArray *references;
+       const CamelNameValueArray *headers;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+       if (assign_summary)
+               g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (assign_summary), NULL);
+
+       /* Make sure the 'mi' doesn't change while copying the values. */
+       camel_message_info_property_lock (mi);
+
+       if (!assign_summary) {
+               CamelFolderSummary *mi_summary;
+
+               mi_summary = camel_message_info_ref_summary (mi);
+               result = camel_message_info_new (mi_summary);
+               g_clear_object (&mi_summary);
+       } else {
+               result = camel_message_info_new (assign_summary);
+       }
+
+       g_object_freeze_notify (G_OBJECT (result));
+       camel_message_info_set_abort_notifications (result, TRUE);
+
+       uid = camel_message_info_pooldup_uid (mi);
+       camel_message_info_set_uid (result, uid);
+       camel_pstring_free (uid);
+
+       camel_message_info_take_user_flags (result, camel_message_info_dup_user_flags (mi));
+       camel_message_info_take_user_tags (result, camel_message_info_dup_user_tags (mi));
+       camel_message_info_set_subject (result, camel_message_info_get_subject (mi));
+       camel_message_info_set_from (result, camel_message_info_get_from (mi));
+       camel_message_info_set_to (result, camel_message_info_get_to (mi));
+       camel_message_info_set_cc (result, camel_message_info_get_cc (mi));
+       camel_message_info_set_mlist (result, camel_message_info_get_mlist (mi));
+       camel_message_info_set_size (result, camel_message_info_get_size (mi));
+       camel_message_info_set_date_sent (result, camel_message_info_get_date_sent (mi));
+       camel_message_info_set_date_received (result, camel_message_info_get_date_received (mi));
+       camel_message_info_set_message_id (result, camel_message_info_get_message_id (mi));
+
+       references = camel_message_info_get_references (mi);
+       if (references && references->len) {
+               GArray *copy;
+               guint ii;
+
+               copy = g_array_sized_new (FALSE, FALSE, references->len, sizeof (guint64));
+
+               for (ii = 0; ii < references->len; ii++) {
+                       g_array_append_val (copy, g_array_index (references, guint64, ii));
+               }
+
+               camel_message_info_take_references (result, copy);
+       }
+
+       headers = camel_message_info_get_headers (mi);
+       if (headers) {
+               camel_message_info_take_headers (result,
+                       camel_name_value_array_copy (headers));
+       }
+
+       /* Set flags as the last, to not overwrite 'folder-flagged' flag by
+          the "changes" when copying fields. */
+       camel_message_info_set_flags (result, ~0, camel_message_info_get_flags (mi));
+
+       camel_message_info_property_unlock (mi);
+
+       /* Also ensure 'dirty' flag, thus it can be eventually saved. */
+       camel_message_info_set_dirty (result, TRUE);
+
+       camel_message_info_set_abort_notifications (result, FALSE);
+       g_object_thaw_notify (G_OBJECT (result));
+
+       return result;
+}
+
+static gboolean
+message_info_load (CamelMessageInfo *mi,
+                  const CamelMIRecord *record,
+                  /* const */ gchar **bdata_ptr)
+{
+       gint ii, count;
+       gchar *part, *label;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       camel_message_info_set_uid (mi, record->uid);
+       camel_message_info_set_flags (mi, ~0, record->flags);
+       camel_message_info_set_size (mi, record->size);
+       camel_message_info_set_date_sent (mi, record->dsent);
+       camel_message_info_set_date_received (mi, record->dreceived);
+
+       camel_message_info_set_subject (mi, record->subject);
+       camel_message_info_set_from (mi, record->from);
+       camel_message_info_set_to (mi, record->to);
+       camel_message_info_set_cc (mi, record->cc);
+       camel_message_info_set_mlist (mi, record->mlist);
+
+       /* Extract Message id & References */
+       part = record->part;
+       if (part) {
+               CamelSummaryMessageID message_id;
+
+               message_id.id.part.hi = camel_util_bdata_get_number (&part, 0);
+               message_id.id.part.lo = camel_util_bdata_get_number (&part, 0);
+
+               camel_message_info_set_message_id (mi, message_id.id.id);
+
+               count = camel_util_bdata_get_number (&part, 0);
+
+               if (count > 0) {
+                       GArray *references = g_array_sized_new (FALSE, FALSE, sizeof (guint64), count);
+
+                       for (ii = 0; ii < count; ii++) {
+                               message_id.id.part.hi = camel_util_bdata_get_number (&part, 0);
+                               message_id.id.part.lo = camel_util_bdata_get_number (&part, 0);
+
+                               g_array_append_val (references, message_id.id.id);
+                       }
+
+                       camel_message_info_take_references (mi, references);
+               }
+       }
+
+       /* Extract User flags/labels */
+       part = record->labels;
+       if (part) {
+               CamelNamedFlags *user_flags;
+
+               user_flags = camel_named_flags_new ();
+
+               label = part;
+               for (ii = 0; part[ii]; ii++) {
+                       if (part[ii] == ' ') {
+                               part[ii] = 0;
+                               if (label && *label)
+                                       camel_named_flags_insert (user_flags, label);
+                               label = &(part[ii + 1]);
+                               part[ii] = ' ';
+                       }
+               }
+               if (label && *label)
+                       camel_named_flags_insert (user_flags, label);
+
+               camel_message_info_take_user_flags (mi, user_flags);
+       }
+
+       /* Extract User tags */
+       part = record->usertags;
+       if (part) {
+               CamelNameValueArray *user_tags;
+
+               count = camel_util_bdata_get_number (&part, 0);
+
+               user_tags = camel_name_value_array_new_sized (count);
+
+               for (ii = 0; ii < count; ii++) {
+                       gchar *name, *value;
+
+                       name = camel_util_bdata_get_string (&part, NULL);
+                       value = camel_util_bdata_get_string (&part, NULL);
+
+                       if (name)
+                               camel_name_value_array_set_named (user_tags, CAMEL_COMPARE_CASE_SENSITIVE, 
name, value ? value : "");
+
+                       g_free (name);
+                       g_free (value);
+               }
+
+               camel_message_info_take_user_tags (mi, user_tags);
+       }
+
+       return TRUE;
+}
+
+static gboolean
+message_info_save (const CamelMessageInfo *mi,
+                  CamelMIRecord *record,
+                  GString *bdata_str)
+{
+       GString *tmp;
+       CamelSummaryMessageID message_id;
+       const CamelNamedFlags *user_flags;
+       const CamelNameValueArray *user_tags;
+       const GArray *references;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_str != NULL, FALSE);
+
+       record->uid = (gchar *) camel_pstring_strdup (camel_message_info_get_uid (mi));
+       record->flags = camel_message_info_get_flags (mi);
+
+       record->read = ((record->flags & (CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_JUNK))) 
? 1 : 0;
+       record->deleted = (record->flags & CAMEL_MESSAGE_DELETED) != 0 ? 1 : 0;
+       record->replied = (record->flags & CAMEL_MESSAGE_ANSWERED) != 0 ? 1 : 0;
+       record->important = (record->flags & CAMEL_MESSAGE_FLAGGED) != 0 ? 1 : 0;
+       record->junk = (record->flags & CAMEL_MESSAGE_JUNK) != 0 ? 1 : 0;
+       record->dirty = (record->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 ? 1 : 0;
+       record->attachment = (record->flags & CAMEL_MESSAGE_ATTACHMENTS) != 0 ? 1 : 0;
+
+       record->size = camel_message_info_get_size (mi);
+       record->dsent = camel_message_info_get_date_sent (mi);
+       record->dreceived = camel_message_info_get_date_received (mi);
+
+       record->subject = g_strdup (camel_message_info_get_subject (mi));
+       record->from = g_strdup (camel_message_info_get_from (mi));
+       record->to = g_strdup (camel_message_info_get_to (mi));
+       record->cc = g_strdup (camel_message_info_get_cc (mi));
+       record->mlist = g_strdup (camel_message_info_get_mlist (mi));
+
+       record->followup_flag = g_strdup (camel_message_info_get_user_tag (mi, "follow-up"));
+       record->followup_completed_on = g_strdup (camel_message_info_get_user_tag (mi, "completed-on"));
+       record->followup_due_by = g_strdup (camel_message_info_get_user_tag (mi, "due-by"));
+
+       tmp = g_string_new (NULL);
+       message_id.id.id = camel_message_info_get_message_id (mi);
+       g_string_append_printf (tmp, "%lu %lu ", (gulong) message_id.id.part.hi, (gulong) 
message_id.id.part.lo);
+       references = camel_message_info_get_references (mi);
+       if (references) {
+               guint ii;
+
+               g_string_append_printf (tmp, "%lu", (gulong) references->len);
+               for (ii = 0; ii < references->len; ii++) {
+                       message_id.id.id = g_array_index (references, guint64, ii);
+
+                       g_string_append_printf (tmp, " %lu %lu", (gulong) message_id.id.part.hi, (gulong) 
message_id.id.part.lo);
+               }
+       } else {
+               g_string_append (tmp, "0");
+       }
+       record->part = g_string_free (tmp, FALSE);
+
+       tmp = g_string_new (NULL);
+       user_flags = camel_message_info_get_user_flags (mi);
+       if (user_flags) {
+               guint ii, count;
+
+               count = camel_named_flags_get_length (user_flags);
+               for (ii = 0; ii < count; ii++) {
+                       const gchar *name = camel_named_flags_get (user_flags, ii);
+
+                       if (name && *name) {
+                               if (tmp->len)
+                                       g_string_append (tmp, " ");
+                               g_string_append (tmp, name);
+                       }
+               }
+       }
+       record->labels = g_string_free (tmp, FALSE);
+
+       tmp = g_string_new (NULL);
+       user_tags = camel_message_info_get_user_tags (mi);
+       if (user_tags) {
+               guint ii, count;
+
+               count = camel_name_value_array_get_length (user_tags);
+               g_string_append_printf (tmp, "%lu", (gulong) count);
+
+               for (ii = 0; ii < count; ii++) {
+                       const gchar *name = NULL, *value = NULL;
+
+                       if (camel_name_value_array_get (user_tags, ii, &name, &value)) {
+                               if (!name)
+                                       name = "";
+                               if (!value)
+                                       value = "";
+
+                               g_string_append_printf (tmp, " %lu-%s %lu-%s", (gulong) strlen (name), name, 
(gulong) strlen (value), value);
+                       }
+               }
+       } else {
+               g_string_append (tmp, "0");
+       }
+       record->usertags = g_string_free (tmp, FALSE);
+
+       return TRUE;
+}
+
+static void
+message_info_set_property (GObject *object,
+                          guint property_id,
+                          const GValue *value,
+                          GParamSpec *pspec)
+{
+       CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_SUMMARY:
+               g_weak_ref_set (&mi->priv->summary, g_value_get_object (value));
+               return;
+
+       case PROP_DIRTY:
+               camel_message_info_set_dirty (mi, g_value_get_boolean (value));
+               return;
+
+       case PROP_FOLDER_FLAGGED:
+               camel_message_info_set_folder_flagged (mi, g_value_get_boolean (value));
+               return;
+
+       case PROP_ABORT_NOTIFICATIONS:
+               camel_message_info_set_abort_notifications (mi, g_value_get_boolean (value));
+               return;
+
+       case PROP_UID:
+               camel_message_info_set_uid (mi, g_value_get_string (value));
+               return;
+
+       case PROP_FLAGS:
+               camel_message_info_set_flags (mi, ~0, g_value_get_uint (value));
+               return;
+
+       case PROP_USER_FLAGS:
+               camel_message_info_take_user_flags (mi, g_value_dup_boxed (value));
+               return;
+
+       case PROP_USER_TAGS:
+               camel_message_info_take_user_tags (mi, g_value_dup_boxed (value));
+               return;
+
+       case PROP_SUBJECT:
+               camel_message_info_set_subject (mi, g_value_get_string (value));
+               return;
+
+       case PROP_FROM:
+               camel_message_info_set_from (mi, g_value_get_string (value));
+               return;
+
+       case PROP_TO:
+               camel_message_info_set_to (mi, g_value_get_string (value));
+               return;
+
+       case PROP_CC:
+               camel_message_info_set_cc (mi, g_value_get_string (value));
+               return;
+
+       case PROP_MLIST:
+               camel_message_info_set_mlist (mi, g_value_get_string (value));
+               return;
+
+       case PROP_SIZE:
+               camel_message_info_set_size (mi, g_value_get_uint (value));
+               return;
+
+       case PROP_DATE_SENT:
+               camel_message_info_set_date_sent (mi, g_value_get_int64 (value));
+               return;
+
+       case PROP_DATE_RECEIVED:
+               camel_message_info_set_date_received (mi, g_value_get_int64 (value));
+               return;
+
+       case PROP_MESSAGE_ID:
+               camel_message_info_set_message_id (mi, g_value_get_uint64 (value));
+               return;
+
+       case PROP_REFERENCES:
+               camel_message_info_take_references (mi, g_value_dup_boxed (value));
+               return;
+
+       case PROP_HEADERS:
+               camel_message_info_take_headers (mi, g_value_dup_boxed (value));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+message_info_get_property (GObject *object,
+                          guint property_id,
+                          GValue *value,
+                          GParamSpec *pspec)
+{
+       CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_SUMMARY:
+               g_value_take_object (value, camel_message_info_ref_summary (mi));
+               return;
+
+       case PROP_DIRTY:
+               g_value_set_boolean (value, camel_message_info_get_dirty (mi));
+               return;
+
+       case PROP_FOLDER_FLAGGED:
+               g_value_set_boolean (value, camel_message_info_get_folder_flagged (mi));
+               return;
+
+       case PROP_FOLDER_FLAGGED_STAMP:
+               g_value_set_uint (value, camel_message_info_get_folder_flagged_stamp (mi));
+               return;
+
+       case PROP_ABORT_NOTIFICATIONS:
+               g_value_set_boolean (value, camel_message_info_get_abort_notifications (mi));
+               return;
+
+       case PROP_UID:
+               g_value_set_string (value, camel_message_info_get_uid (mi));
+               return;
+
+       case PROP_FLAGS:
+               g_value_set_uint (value, camel_message_info_get_flags (mi));
+               return;
+
+       case PROP_USER_FLAGS:
+               g_value_take_boxed (value, camel_message_info_dup_user_flags (mi));
+               return;
+
+       case PROP_USER_TAGS:
+               g_value_take_boxed (value, camel_message_info_dup_user_tags (mi));
+               return;
+
+       case PROP_SUBJECT:
+               g_value_set_string (value, camel_message_info_get_subject (mi));
+               return;
+
+       case PROP_FROM:
+               g_value_set_string (value, camel_message_info_get_from (mi));
+               return;
+
+       case PROP_TO:
+               g_value_set_string (value, camel_message_info_get_to (mi));
+               return;
+
+       case PROP_CC:
+               g_value_set_string (value, camel_message_info_get_cc (mi));
+               return;
+
+       case PROP_MLIST:
+               g_value_set_string (value, camel_message_info_get_mlist (mi));
+               return;
+
+       case PROP_SIZE:
+               g_value_set_uint (value, camel_message_info_get_size (mi));
+               return;
+
+       case PROP_DATE_SENT:
+               g_value_set_int64 (value, camel_message_info_get_date_sent (mi));
+               return;
+
+       case PROP_DATE_RECEIVED:
+               g_value_set_int64 (value, camel_message_info_get_date_received (mi));
+               return;
+
+       case PROP_MESSAGE_ID:
+               g_value_set_uint64 (value, camel_message_info_get_message_id (mi));
+               return;
+
+       case PROP_REFERENCES:
+               g_value_take_boxed (value, camel_message_info_dup_references (mi));
+               return;
+
+       case PROP_HEADERS:
+               g_value_take_boxed (value, camel_message_info_dup_headers (mi));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+message_info_dispose (GObject *object)
+{
+       CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object);
+
+       g_weak_ref_set (&mi->priv->summary, NULL);
+       camel_pstring_free (mi->priv->uid);
+       mi->priv->uid = NULL;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_message_info_parent_class)->dispose (object);
+}
+
+static void
+message_info_finalize (GObject *object)
+{
+       CamelMessageInfo *mi = CAMEL_MESSAGE_INFO (object);
+
+       g_weak_ref_clear (&mi->priv->summary);
+       g_rec_mutex_clear (&mi->priv->property_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_message_info_parent_class)->finalize (object);
+}
+
+static void
+camel_message_info_class_init (CamelMessageInfoClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelMessageInfoPrivate));
+
+       class->clone = message_info_clone;
+       class->load = message_info_load;
+       class->save = message_info_save;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = message_info_set_property;
+       object_class->get_property = message_info_get_property;
+       object_class->dispose = message_info_dispose;
+       object_class->finalize = message_info_finalize;
+
+       /**
+        * CamelMessageInfo:summary
+        *
+        * The #CamelFolderSummary to which the message info belongs, or %NULL.
+        * It can be set only during construction of the object.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_SUMMARY,
+               g_param_spec_object (
+                       "summary",
+                       "Summary",
+                       NULL,
+                       CAMEL_TYPE_FOLDER_SUMMARY,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY));
+
+       /**
+        * CamelMessageInfo:uid
+        *
+        * A unique ID of the message in its folder.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_UID,
+               g_param_spec_string (
+                       "uid",
+                       "UID",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:dirty
+        *
+        * Flag, whether the info is changed and requires save to disk.
+        * Compare with CamelMessageInfo:folder-flagged
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_DIRTY,
+               g_param_spec_boolean (
+                       "dirty",
+                       "Dirty",
+                       NULL,
+                       FALSE,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:folder-flagged
+        *
+        * Flag, whether the info is changed and requires save to
+        * the destination store/server. This is different from
+        * the CamelMessageInfo:dirty, which takes care of the local
+        * information only.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_FOLDER_FLAGGED,
+               g_param_spec_boolean (
+                       "folder-flagged",
+                       "Folder Flagged",
+                       NULL,
+                       FALSE,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:folder-flagged-stamp
+        *
+        * The 'folder-flagged-stamp' is a stamp of the 'folder-flagged' flag. This stamp
+        * changes whenever anything would mark the @mi 'folder-flagged', regardless the @mi
+        * being already 'folder-flagged'. It can be used to recognize changes
+        * on the 'folder-flagged' flag during the time.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_FOLDER_FLAGGED_STAMP,
+               g_param_spec_uint (
+                       "folder-flagged-stamp",
+                       "Folder Flagged Stamp",
+                       NULL,
+                       0, G_MAXUINT, 0,
+                       G_PARAM_READABLE));
+
+       /**
+        * CamelMessageInfo:abort-notifications
+        *
+        * Flag, whether the info is currently aborting notifications. It is used to avoid
+        * unnecessary 'folder-flagged' and 'dirty' flags changes and also to avoid
+        * associated folder's "changed" signal.
+        *f
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_ABORT_NOTIFICATIONS,
+               g_param_spec_boolean (
+                       "abort-notifications",
+                       "Abort Notifications",
+                       NULL,
+                       FALSE,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:flags
+        *
+        * Bit-or of #CamelMessageFlags.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_FLAGS,
+               g_param_spec_uint (
+                       "flags",
+                       "Flags",
+                       NULL,
+                       0, G_MAXUINT32, 0,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:user-flags
+        *
+        * User flags for the associated message. Can be %NULL.
+        * Unlike user-tags, which can contain various values, the user-flags
+        * can only be set or not.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_USER_FLAGS,
+               g_param_spec_boxed (
+                       "user-flags",
+                       "User Flags",
+                       NULL,
+                       CAMEL_TYPE_NAMED_FLAGS,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:user-tags
+        *
+        * User tags for the associated message. Can be %NULL.
+        * Unlike user-flags, which can be set or not, the user-tags
+        * can contain various values.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_USER_TAGS,
+               g_param_spec_boxed (
+                       "user-tags",
+                       "User tags",
+                       NULL,
+                       CAMEL_TYPE_NAME_VALUE_ARRAY,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:subject
+        *
+        * Subject of the associated message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_SUBJECT,
+               g_param_spec_string (
+                       "subject",
+                       "Subject",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:from
+        *
+        * From address of the associated message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_FROM,
+               g_param_spec_string (
+                       "from",
+                       "From",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:to
+        *
+        * To address of the associated message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_TO,
+               g_param_spec_string (
+                       "to",
+                       "To",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:cc
+        *
+        * CC address of the associated message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_CC,
+               g_param_spec_string (
+                       "cc",
+                       "CC",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:mlist
+        *
+        * Mailing list address of the associated message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_MLIST,
+               g_param_spec_string (
+                       "mlist",
+                       "mlist",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:size
+        *
+        * Size of the associated message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_SIZE,
+               g_param_spec_uint (
+                       "size",
+                       "Size",
+                       NULL,
+                       0, G_MAXUINT32, 0,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:date-sent
+        *
+        * Sent Date of the associated message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_DATE_SENT,
+               g_param_spec_int64 (
+                       "date-sent",
+                       "Date Sent",
+                       NULL,
+                       G_MININT64, G_MAXINT64, 0,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:date-received
+        *
+        * Received date of the associated message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_DATE_RECEIVED,
+               g_param_spec_int64 (
+                       "date-received",
+                       "Date Received",
+                       NULL,
+                       G_MININT64, G_MAXINT64, 0,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:message-id
+        *
+        * Encoded Message-ID of the associated message as a guint64 number,
+        * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_MESSAGE_ID,
+               g_param_spec_uint64 (
+                       "message-id",
+                       "Message ID",
+                       NULL,
+                       0, G_MAXUINT64, 0,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:references
+        *
+        * Encoded In-Reply-To and References headers of the associated message
+        * as an array of guint64 numbers, partial MD5 sums. Each value can be
+        * cast to #CamelSummaryMessageID.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_REFERENCES,
+               g_param_spec_boxed (
+                       "references",
+                       "References",
+                       NULL,
+                       G_TYPE_ARRAY,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelMessageInfo:headers
+        *
+        * Headers of the associated message. Can be %NULL.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_HEADERS,
+               g_param_spec_boxed (
+                       "headers",
+                       "Headers",
+                       NULL,
+                       CAMEL_TYPE_NAME_VALUE_ARRAY,
+                       G_PARAM_READWRITE));
+}
+
+static void
+camel_message_info_init (CamelMessageInfo *mi)
+{
+       mi->priv = G_TYPE_INSTANCE_GET_PRIVATE (mi, CAMEL_TYPE_MESSAGE_INFO, CamelMessageInfoPrivate);
+
+       g_rec_mutex_init (&mi->priv->property_lock);
+       g_weak_ref_init (&mi->priv->summary, NULL);
+}
+
+/**
+ * camel_message_info_new:
+ * @summary: (nullable): parent #CamelFolderSummary object, or %NULL
+ *
+ * Create a new #CamelMessageInfo object, optionally for given @summary.
+ *
+ * Returns: (transfer full): a new #CamelMessageInfo object
+ *
+ * Since: 3.24
+ **/
+CamelMessageInfo *
+camel_message_info_new (CamelFolderSummary *summary)
+{
+       GType type = CAMEL_TYPE_MESSAGE_INFO_BASE;
+
+       if (summary) {
+               CamelFolderSummaryClass *klass;
+
+               g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
+
+               klass = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary);
+               g_return_val_if_fail (klass != NULL, NULL);
+
+               type = klass->message_info_type;
+       }
+
+       return g_object_new (type, "summary", summary, NULL);
+}
+
+/**
+ * camel_message_info_clone:
+ * @mi: a #CamelMessageInfo to clone
+ * @assign_summary: (nullable): parent #CamelFolderSummary object, or %NULL, to set on the clone
+ *
+ * Clones the @mi as a new #CamelMessageInfo and eventually assigns
+ * a new #CamelFolderSummary to it. If it's not set, then the same
+ * summary as the one with @mi is used.
+ *
+ * Returns: (transfer full): a new #CamelMessageInfo object, clone of the @mi
+ *
+ * Since: 3.24
+ **/
+CamelMessageInfo *
+camel_message_info_clone (const CamelMessageInfo *mi,
+                         CamelFolderSummary *assign_summary)
+{
+       CamelMessageInfoClass *klass;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+       if (assign_summary)
+               g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (assign_summary), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->clone != NULL, NULL);
+
+       return klass->clone (mi, assign_summary);
+}
+
+/**
+ * camel_message_info_load:
+ * @mi: a #CamelMessageInfo to load
+ * @record: a #CamelMIRecord to load the @mi from
+ * @bdata_ptr: a backend specific data (bdata) pointer
+ *
+ * Load content of @mi from the data stored in @record. The @bdata_ptr points
+ * to the current position of the record->bdata, where the read can continue.
+ * Use helper functions camel_util_bdata_get_number() and camel_util_bdata_get_string()
+ * to read data from it and also move forward the *bdata_ptr.
+ *
+ * After successful load of the @mi, the 'dirty' flag is unset.
+ *
+ * Returns: Whether the load was successful.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_load (CamelMessageInfo *mi,
+                        const CamelMIRecord *record,
+                        /* const */ gchar **bdata_ptr)
+{
+       CamelMessageInfoClass *klass;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->load != NULL, FALSE);
+
+       g_object_freeze_notify (G_OBJECT (mi));
+       camel_message_info_property_lock (mi);
+       camel_message_info_set_abort_notifications (mi, TRUE);
+
+       success = klass->load (mi, record, bdata_ptr);
+
+       if (success)
+               camel_message_info_set_dirty (mi, FALSE);
+
+       camel_message_info_set_abort_notifications (mi, FALSE);
+       camel_message_info_property_unlock (mi);
+       g_object_thaw_notify (G_OBJECT (mi));
+
+       return success;
+}
+
+/**
+ * camel_message_info_save:
+ * @mi: a #CamelMessageInfo
+ * @record: a #CamelMIRecord to populate
+ * @bdata_str: a #GString with a string to save as backend specific data (bdata)
+ *
+ * Save the @mi content to the message info record @record. It can populate all
+ * but the record->bdata value, which is set fro mthe @bdata_str. Use helper functions
+ * camel_util_bdata_put_number() and camel_util_bdata_put_string() to put data into the @bdata_str.
+ *
+ * Returns: Whether the save succeeded.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_save (const CamelMessageInfo *mi,
+                        CamelMIRecord *record,
+                        GString *bdata_str)
+{
+       CamelMessageInfoClass *klass;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_str != NULL, FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->save != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+
+       success = klass->save (mi, record, bdata_str);
+
+       camel_message_info_property_unlock (mi);
+
+       return success;
+}
+
+/**
+ * camel_message_info_ref_summary:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer full): Referenced #CamelFolderSummary to which the @mi belongs, or %NULL,
+ * if there is none. Use g_object_unref() for non-NULL returned values when done with it.
+ *
+ * Since: 3.24
+ **/
+CamelFolderSummary *
+camel_message_info_ref_summary (const CamelMessageInfo *mi)
+{
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       return g_weak_ref_get (&mi->priv->summary);
+}
+
+/**
+ * camel_message_info_property_lock:
+ * @mi: a #CamelMessageInfo
+ *
+ * Acquires a property lock, which is used to ensure thread safety
+ * when properties are changing. Release the lock with
+ * camel_message_info_property_unlock().
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_property_lock (const CamelMessageInfo *mi)
+{
+       g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
+
+       g_rec_mutex_lock (&mi->priv->property_lock);
+}
+
+/**
+ * camel_message_info_property_unlock:
+ * @mi: a #CamelMessageInfo
+ *
+ * Releases a property lock, previously acquired with
+ * camel_message_info_property_lock().
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_property_unlock (const CamelMessageInfo *mi)
+{
+       g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
+
+       g_rec_mutex_unlock (&mi->priv->property_lock);
+}
+
+static void
+camel_message_info_update_summary_and_folder (CamelMessageInfo *mi,
+                                             gboolean update_counts)
+{
+       CamelFolderSummary *summary;
+
+       g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
+
+       camel_message_info_property_lock (mi);
+       if (camel_message_info_get_notifications_frozen (mi)) {
+               mi->priv->thaw_notify_folder = TRUE;
+               mi->priv->thaw_notify_folder_with_counts |= update_counts;
+               camel_message_info_property_unlock (mi);
+
+               return;
+       }
+       camel_message_info_property_unlock (mi);
+
+       summary = camel_message_info_ref_summary (mi);
+       if (summary) {
+               CamelFolder *folder;
+               const gchar *uid;
+
+               uid = camel_message_info_pooldup_uid (mi);
+
+               /* This is for cases when a new message info had been created,
+                  but not added into the summary yet. */
+               if (uid && camel_folder_summary_check_uid (summary, uid) &&
+                   camel_folder_summary_peek_loaded (summary, uid) == mi) {
+                       if (update_counts) {
+                               camel_folder_summary_lock (summary);
+                               g_object_freeze_notify (G_OBJECT (summary));
+
+                               camel_folder_summary_replace_flags (summary, mi);
+
+                               g_object_thaw_notify (G_OBJECT (summary));
+                               camel_folder_summary_unlock (summary);
+                       }
+
+                       folder = camel_folder_summary_get_folder (summary);
+                       if (folder) {
+                               CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
+
+                               camel_folder_change_info_change_uid (changes, uid);
+                               camel_folder_changed (folder, changes);
+                               camel_folder_change_info_free (changes);
+                       }
+               }
+
+               g_clear_object (&summary);
+               camel_pstring_free (uid);
+       }
+}
+
+/**
+ * camel_message_info_get_dirty:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Whether the @mi is dirty, which means that it had been
+ *   changed and a save to the local summary is required.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_get_dirty (const CamelMessageInfo *mi)
+{
+       gboolean result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       camel_message_info_property_lock (mi);
+       result = mi->priv->dirty;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_dirty:
+ * @mi: a #CamelMessageInfo
+ * @dirty: a dirty state to set
+ *
+ * Marks the @mi as dirty, which means a save to the local summary
+ * is required. In case the @dirty is %TRUE and the @mi is not aborting notifications,
+ * the 'dirty-stamp' changes too.
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_set_dirty (const CamelMessageInfo *mi,
+                             gboolean dirty)
+{
+       gboolean changed, abort_notifications;
+
+       g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
+
+       camel_message_info_property_lock (mi);
+
+       changed = (!mi->priv->dirty) != (!dirty);
+       if (changed)
+               mi->priv->dirty = dirty;
+       abort_notifications = mi->priv->abort_notifications;
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "dirty");
+
+               if (dirty) {
+                       CamelFolderSummary *summary;
+
+                       summary = camel_message_info_ref_summary (mi);
+                       if (summary)
+                               camel_folder_summary_touch (summary);
+
+                       g_clear_object (&summary);
+               }
+       }
+}
+
+/**
+ * camel_message_info_get_folder_flagged:
+ * @mi: a #CamelMessageInfo
+ *
+ * The folder flagged flag is used to mark the message infor as being changed
+ * and this change should be propagated to the remote store (server). This is
+ * different from the 'dirty' flag, which is set for local changes only. It
+ * can happen that the 'folder-flagged' flag is set, but the 'dirty' flag not.
+ *
+ * This is only a convenient wrapper around CAMEL_MESSAGE_FOLDER_FLAGGED flag,
+ * for better readiness of the code.
+ *
+ * Returns: Whether requires save of the local changes into the remote store.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_get_folder_flagged (const CamelMessageInfo *mi)
+{
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       return (camel_message_info_get_flags (mi) & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0;
+}
+
+/**
+ * camel_message_info_set_folder_flagged:
+ * @mi: a #CamelMessageInfo
+ * folder_flagged: a value to set to
+ *
+ * Changes the folder-flagged flag to the @folder_flagged value. See
+ * camel_message_info_get_folder_flagged() for more information about
+ * the use of this flag.
+ *
+ * This is only a convenient wrapper around CAMEL_MESSAGE_FOLDER_FLAGGED flag,
+ * for better readiness of the code.
+ *
+ * Returns: Whether the flag had been changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_folder_flagged (CamelMessageInfo *mi,
+                                      gboolean folder_flagged)
+{
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       /* g_object_notify (G_OBJECT (mi), "folder-flagged");
+          is called as part of the set_flags function */
+
+       return camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_FLAGGED,
+               folder_flagged ? CAMEL_MESSAGE_FOLDER_FLAGGED : 0);
+}
+
+/**
+ * camel_message_info_get_folder_flagged_stamp:
+ * @mi: a #CamelMessageInfo
+ *
+ * The 'folder-flagged-stamp' is a stamp of the 'folder-flagged' flag. This stamp
+ * changes whenever anything would mark the @mi as 'folder-flagged', regardless
+ * the @mi being already 'folder-flagged'. It can be used to recognize changes
+ * on the 'folder-flagged' flag during the time.
+ *
+ * Returns: Stamp of the 'folder-flagged' flag.
+ *
+ * Since: 3.24
+ **/
+guint
+camel_message_info_get_folder_flagged_stamp (const CamelMessageInfo *mi)
+{
+       guint result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), ~0);
+
+       camel_message_info_property_lock (mi);
+       result = mi->priv->folder_flagged_stamp;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_get_abort_notifications:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Whether the @mi is aborting notifications, which means
+ *   that it will not influence 'dirty' and 'folder-flagged' flags
+ *   in the set/take functions, neither it will emit any GObject::notify
+ *   signals on change, nor associated folder's "changed" signal.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_get_abort_notifications (const CamelMessageInfo *mi)
+{
+       gboolean result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       camel_message_info_property_lock (mi);
+       result = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_abort_notifications:
+ * @mi: a #CamelMessageInfo
+ * @abort_notifications: a state to set
+ *
+ * Marks the @mi to abort any notifications, which means that it
+ * will not influence 'dirty' and 'folder-flagged' flags in
+ * the set/take functions, neither it will emit any GObject::notify
+ * signals on change, nor associated folder's "changed" signal.
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_set_abort_notifications (CamelMessageInfo *mi,
+                                           gboolean abort_notifications)
+{
+       gboolean changed;
+       g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
+
+       camel_message_info_property_lock (mi);
+       changed = (!mi->priv->abort_notifications) != (!abort_notifications);
+       if (changed)
+               mi->priv->abort_notifications = abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed)
+               g_object_notify (G_OBJECT (mi), "abort-notifications");
+}
+
+/**
+ * camel_message_info_freeze_notifications:
+ * @mi: a #CamelMessageInfo
+ *
+ * Freezes all the notifications until the camel_message_info_thaw_notifications() is called.
+ * This function can be called multiple times, where the last thaw will do the notifications.
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_freeze_notifications (CamelMessageInfo *mi)
+{
+       g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
+
+       camel_message_info_property_lock (mi);
+       mi->priv->freeze_notifications++;
+       if (mi->priv->freeze_notifications == 1) {
+               mi->priv->thaw_notify_folder = FALSE;
+               mi->priv->thaw_notify_folder_with_counts = FALSE;
+               g_object_freeze_notify (G_OBJECT (mi));
+       }
+       camel_message_info_property_unlock (mi);
+}
+
+/**
+ * camel_message_info_thaw_notifications:
+ * @mi: a #CamelMessageInfo
+ *
+ * Reverses the call of the camel_message_info_freeze_notifications().
+ * If this is the last freeze, then the associated folder is also notified
+ * about the change, if any happened during the freeze.
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_thaw_notifications (CamelMessageInfo *mi)
+{
+       g_return_if_fail (CAMEL_IS_MESSAGE_INFO (mi));
+
+       camel_message_info_property_lock (mi);
+       if (!mi->priv->freeze_notifications) {
+               camel_message_info_property_unlock (mi);
+
+               g_warn_if_reached ();
+               return;
+       }
+
+       mi->priv->freeze_notifications--;
+       if (!mi->priv->freeze_notifications) {
+               gboolean notify_folder, notify_folder_with_counts;
+
+               notify_folder = mi->priv->thaw_notify_folder;
+               notify_folder_with_counts = mi->priv->thaw_notify_folder_with_counts;
+
+               camel_message_info_property_unlock (mi);
+
+               g_object_thaw_notify (G_OBJECT (mi));
+
+               if (notify_folder)
+                       camel_message_info_update_summary_and_folder (mi, notify_folder_with_counts);
+       } else {
+               camel_message_info_property_unlock (mi);
+       }
+}
+
+/**
+ * camel_message_info_get_notifications_frozen:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Whether the notifications are frozen.
+ *
+ * See: camel_message_info_freeze_notifications()
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_get_notifications_frozen (const CamelMessageInfo *mi)
+{
+       gboolean result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       camel_message_info_property_lock (mi);
+       result = mi->priv->freeze_notifications > 0;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_get_uid:
+ * @mi: a #CamelMessageInfo
+ *
+ * Get the UID of the #mi.
+ *
+ * Returns: (transfer none): The UID of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_message_info_get_uid (const CamelMessageInfo *mi)
+{
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       camel_message_info_property_lock (mi);
+       result = mi->priv->uid;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_pooldup_uid:
+ * @mi: a #CamelMessageInfo
+ *
+ * Get the UID of the #mi, duplicated on the Camel's string pool.
+ * This is good for thread safety, though the UID should not change once set.
+ *
+ * Returns: A newly references string in the string pool, the #mi UID.
+ *   Free it with camel_pstring_free() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_message_info_pooldup_uid (const CamelMessageInfo *mi)
+{
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       camel_message_info_property_lock (mi);
+       result = camel_pstring_strdup (mi->priv->uid);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_uid:
+ * @mi: a #CamelMessageInfo
+ * @uid: a UID to set
+ *
+ * Changes UID of the @mi to @uid. If it changes, the 'dirty' flag
+ * of the @mi is set too, unless the @mi is aborting notifications. This change
+ * does not influence the 'folder-flagged' flag.
+ *
+ * Returns: Whether the UID changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_uid (CamelMessageInfo *mi,
+                           const gchar *uid)
+{
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = mi->priv->uid != uid && g_strcmp0 (mi->priv->uid, uid) != 0;
+       if (changed) {
+               camel_pstring_free (mi->priv->uid);
+               mi->priv->uid = camel_pstring_strdup (uid);
+       }
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "uid");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_flags:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Bit-or of #CamelMessageFlags set on the @mi.
+ *
+ * Since: 3.24
+ **/
+guint32
+camel_message_info_get_flags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       guint32 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, 0);
+       g_return_val_if_fail (klass->get_flags != NULL, 0);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_flags (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_flags:
+ * @mi: a #CamelMessageInfo
+ * @mask: mask of flags to change
+ * @set: state the flags should be changed to
+ *
+ * Change the state of the flags on the @mi. Both @mask and @set are bit-or
+ * of #CamelMessageFlags.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is also emitted
+ * folder's "changed" signal for this @mi, if necessary. In case
+ * the CAMEL_MESSAGE_FOLDER_FLAGGED flag would be set and the @mi is
+ * not aborting notifications, the 'folder-flagged-stamp' changes too.
+ *
+ * Returns: Whether the flags changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_flags (CamelMessageInfo *mi,
+                             guint32 mask,
+                             guint32 set)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_flags != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+
+       changed = klass->set_flags (mi, mask, set);
+       abort_notifications = mi->priv->abort_notifications;
+
+       if (!abort_notifications &&
+           (mask & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 &&
+           (set & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0)
+               mi->priv->folder_flagged_stamp++;
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "flags");
+               camel_message_info_set_dirty (mi, TRUE);
+
+               /* Only if the folder-flagged was not part of the change */
+               if (!(mask & CAMEL_MESSAGE_FOLDER_FLAGGED))
+                       camel_message_info_set_folder_flagged (mi, TRUE);
+               else
+                       g_object_notify (G_OBJECT (mi), "folder-flagged");
+
+               camel_message_info_update_summary_and_folder (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_user_flag:
+ * @mi: a #CamelMessageInfo
+ * @name: user flag name
+ *
+ * Returns: Whther the user flag named @name is set.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_get_user_flag (const CamelMessageInfo *mi,
+                                 const gchar *name)
+{
+       CamelMessageInfoClass *klass;
+       gboolean result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->get_user_flag != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_user_flag (mi, name);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_user_flag:
+ * @mi: a #CamelMessageInfo
+ * @name: user flag name
+ * @state: state to set for the flag
+ *
+ * Change @state of the flag named @name. Unlike user tags, user flags
+ * can only be set or unset, while the user tags can contain certain values.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is also emitted
+ * folder's "changed" signal for this @mi, if necessary.
+ *
+ * Returns: Whether the message info changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_user_flag (CamelMessageInfo *mi,
+                                 const gchar *name,
+                                 gboolean state)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_user_flag != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_user_flag (mi, name, state);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "user-flags");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+
+               camel_message_info_update_summary_and_folder (mi, FALSE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_user_flags:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none) (nullable): A #CamelNamedFlags with all the currently set
+ *   user flags on the @mi. Do not modify it.
+ *
+ * Since: 3.24
+ **/
+const CamelNamedFlags *
+camel_message_info_get_user_flags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const CamelNamedFlags *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_user_flags != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_user_flags (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_dup_user_flags:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer full): A newly allocated #CamelNamedFlags with all the currently set
+ *   user flags on the @mi. Free the returned structure with camel_named_flags_free()
+ *   when no londer needed.
+ *
+ * Since: 3.24
+ **/
+CamelNamedFlags *
+camel_message_info_dup_user_flags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       CamelNamedFlags *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->dup_user_flags != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->dup_user_flags (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_take_user_flags:
+ * @mi: a #CamelMessageInfo
+ * @user_flags: (transfer full) (nullable): user flags to set
+ *
+ * Takes all the @user_flags, which replaces any current user flags on the @mi.
+ * The passed-in @user_flags is consumed by the @mi, which becomes an owner
+ * of it. The caller should not change @user_flags afterwards.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is also emitted
+ * folder's "changed" signal for this @mi, if necessary.
+ *
+ * Note that it's not safe to use the @user_flags after the call to this function,
+ * because it can be freed due to no change.
+ *
+ * Returns: Whether the message info changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_take_user_flags (CamelMessageInfo *mi,
+                                   CamelNamedFlags *user_flags)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->take_user_flags != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->take_user_flags (mi, user_flags);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "user-flags");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+
+               camel_message_info_update_summary_and_folder (mi, FALSE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_user_tag:
+ * @mi: a #CamelMessageInfo
+ * @name: user tag name
+ *
+ * Returns: (transfer none) (nullable): Value of the user tag, or %NULL when
+ *   it is not set.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_message_info_get_user_tag (const CamelMessageInfo *mi,
+                                const gchar *name)
+{
+       CamelMessageInfoClass *klass;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+       g_return_val_if_fail (name != NULL, NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_user_tag != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_user_tag (mi, name);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_dup_user_tag:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer full) (nullable): Value of the user tag as newly allocated
+ *   string, or %NULL when it is not set. Free it with g_free() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+gchar *
+camel_message_info_dup_user_tag (const CamelMessageInfo *mi,
+                                const gchar *name)
+{
+       gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+       g_return_val_if_fail (name != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = g_strdup (camel_message_info_get_user_tag (mi, name));
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_user_tag:
+ * @mi: a #CamelMessageInfo
+ * @name: user tag name
+ * @value: (nullable): user tag value, or %NULL to remove the user tag
+ *
+ * Set user tag @name to @value, or remove it, if @value is %NULL.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is also emitted
+ * folder's "changed" signal for this @mi, if necessary.
+ *
+ * Returns: Whether the @mi changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_user_tag (CamelMessageInfo *mi,
+                                const gchar *name,
+                                const gchar *value)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_user_tag != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_user_tag (mi, name, value);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "user-tags");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+
+               camel_message_info_update_summary_and_folder (mi, FALSE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_user_tags:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none) (nullable): a #CamelNameValueArray containing all set
+ *   user tags of the @mi. Do not modify it.
+ *
+ * Since: 3.24
+ **/
+const CamelNameValueArray *
+camel_message_info_get_user_tags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_user_tags != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_user_tags (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_dup_user_tags:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer full) (nullable): a newly allocated #CamelNameValueArray containing all set
+ *   user tags of the @mi. Free it with camel_name_value_array_free() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+camel_message_info_dup_user_tags (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->dup_user_tags != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->dup_user_tags (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_take_user_tags:
+ * @mi: a #CamelMessageInfo
+ * @user_tags: (transfer full) (nullable): user tags to set
+ *
+ * Takes all the @user_tags, which replaces any current user tags on the @mi.
+ * The passed-in @user_tags is consumed by the @mi, which becomes an owner
+ * of it. The caller should not change @user_tags afterwards.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is also emitted
+ * folder's "changed" signal for this @mi, if necessary.
+ *
+ * Note that it's not safe to use the @user_tags after the call to this function,
+ * because it can be freed due to no change.
+ *
+ * Returns: Whether the @mi changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_take_user_tags (CamelMessageInfo *mi,
+                                  CamelNameValueArray *user_tags)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->take_user_tags != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->take_user_tags (mi, user_tags);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "user-tags");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+
+               camel_message_info_update_summary_and_folder (mi, FALSE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_subject:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): Subject of the #mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_message_info_get_subject (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_subject != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_subject (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_subject:
+ * @mi: a #CamelMessageInfo
+ * @subject: (nullable): a Subject to set
+ *
+ * Sets Subject from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_subject (CamelMessageInfo *mi,
+                               const gchar *subject)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_subject != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_subject (mi, subject);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "subject");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_from:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): From address of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_message_info_get_from (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_from != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_from (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_from:
+ * @mi: a #CamelMessageInfo
+ * @from: (nullable): a From to set
+ *
+ * Sets From from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_from (CamelMessageInfo *mi,
+                            const gchar *from)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_from != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_from (mi, from);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "from");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_to:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): To address of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_message_info_get_to (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_to != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_to (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_to:
+ * @mi: a #CamelMessageInfo
+ * @to: (nullable): a To to set
+ *
+ * Sets To from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_to (CamelMessageInfo *mi,
+                          const gchar *to)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_to != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_to (mi, to);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "to");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_cc:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): CC address of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_message_info_get_cc (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_cc != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_cc (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_cc:
+ * @mi: a #CamelMessageInfo
+ * @cc: (nullable): a CC to set
+ *
+ * Sets CC from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_cc (CamelMessageInfo *mi,
+                          const gchar *cc)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_cc != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_cc (mi, cc);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "cc");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_mlist:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none): Mailing list address of the @mi.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_message_info_get_mlist (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_mlist != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_mlist (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_mlist:
+ * @mi: a #CamelMessageInfo
+ * @mlist: (nullable): a message list address to set
+ *
+ * Sets mesage list address from the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_mlist (CamelMessageInfo *mi,
+                             const gchar *mlist)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_mlist != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_mlist (mi, mlist);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "mlist");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_size:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Size of the associated message.
+ *
+ * Since: 3.24
+ **/
+guint32
+camel_message_info_get_size (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       guint32 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, 0);
+       g_return_val_if_fail (klass->get_size != NULL, 0);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_size (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_size:
+ * @mi: a #CamelMessageInfo
+ * @size: a size to set
+ *
+ * Sets size of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_size (CamelMessageInfo *mi,
+                            guint32 size)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_size != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_size (mi, size);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "size");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_date_sent:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: time_t of the Date header of the message, encoded as gint64.
+ *
+ * Since: 3.24
+ **/
+gint64
+camel_message_info_get_date_sent (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       gint64 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, 0);
+       g_return_val_if_fail (klass->get_date_sent != NULL, 0);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_date_sent (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_date_sent:
+ * @mi: a #CamelMessageInfo
+ * @date_sent: a sent date to set
+ *
+ * Sets sent date (the Date header) of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_date_sent (CamelMessageInfo *mi,
+                                 gint64 date_sent)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_date_sent != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_date_sent (mi, date_sent);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "date-sent");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_date_received:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: time_t of the Received header of the message, encoded as gint64.
+ *
+ * Since: 3.24
+ **/
+gint64
+camel_message_info_get_date_received (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       gint64 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, 0);
+       g_return_val_if_fail (klass->get_date_received != NULL, 0);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_date_received (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_date_received:
+ * @mi: a #CamelMessageInfo
+ * @date_received: a received date to set
+ *
+ * Sets received date (the Received header) of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_date_received (CamelMessageInfo *mi,
+                                     gint64 date_received)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_date_received != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_date_received (mi, date_received);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "date-received");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_message_id:
+ * @mi: a #CamelMessageInfo
+ *
+ * Encoded Message-ID of the associated message as a guint64 number,
+ * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
+ *
+ * Returns: Partial MD5 hash of the Message-ID header of the associated message.
+ *
+ * Since: 3.24
+ **/
+guint64
+camel_message_info_get_message_id (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       guint64 result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), 0);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, 0);
+       g_return_val_if_fail (klass->get_message_id != NULL, 0);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_message_id (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_set_message_id:
+ * @mi: a #CamelMessageInfo
+ * @message_id: a message id to set
+ *
+ * Sets encoded Message-ID of the associated message as a guint64 number,
+ * partial MD5 sum. The value can be cast to #CamelSummaryMessageID.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_set_message_id (CamelMessageInfo *mi,
+                                  guint64 message_id)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->set_message_id != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->set_message_id (mi, message_id);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "message-id");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_references:
+ * @mi: a #CamelMessageInfo
+ *
+ * Gets encoded In-Reply-To and References headers of the associated
+ * message as an array of guint64 numbers, partial MD5 sums. Each value
+ * can be cast to #CamelSummaryMessageID.
+ *
+ * Returns: (transfer none) (nullable) (element-type guint64): A #GArray of
+ *   guint64 encoded Message-ID-s; or %NULL when none are available.
+ *
+ * Since: 3.24
+ **/
+const GArray *
+camel_message_info_get_references (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const GArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_references != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_references (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_dup_references:
+ * @mi: a #CamelMessageInfo
+ *
+ * Duplicates encoded In-Reply-To and References headers of the associated
+ * message as an array of guint64 numbers, partial MD5 sums. Each value
+ * can be cast to #CamelSummaryMessageID.
+ *
+ * Returns: (transfer full) (nullable) (element-type guint64): A #GArray of
+ *   guint64 encoded Message-ID-s; or %NULL when none are available. Free returned
+ *   array with g_array_unref() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+GArray *
+camel_message_info_dup_references (const CamelMessageInfo *mi)
+{
+       const GArray *arr;
+       GArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       camel_message_info_property_lock (mi);
+       arr = camel_message_info_get_references (mi);
+       if (arr) {
+               guint ii;
+
+               result = g_array_sized_new (FALSE, FALSE, sizeof (guint64), arr->len);
+               for (ii = 0; ii < arr->len; ii++) {
+                       g_array_append_val (result, g_array_index (arr, guint64, ii));
+               }
+       } else {
+               result = NULL;
+       }
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_take_references:
+ * @mi: a #CamelMessageInfo
+ * @references: (element-type guint64) (transfer full) (nullable): a references to set
+ *
+ * Takes encoded In-Reply-To and References headers of the associated message
+ * as an array of guint64 numbers, partial MD5 sums. Each value can be
+ * cast to #CamelSummaryMessageID.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Note that it's not safe to use the @references after the call to this function,
+ * because it can be freed due to no change.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_take_references (CamelMessageInfo *mi,
+                                   GArray *references)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->take_references != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->take_references (mi, references);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "references");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_get_headers:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: (transfer none) (nullable): All the message headers of the associated
+ *   message, or %NULL, when none are available.
+ *
+ * Since: 3.24
+ **/
+const CamelNameValueArray *
+camel_message_info_get_headers (const CamelMessageInfo *mi)
+{
+       CamelMessageInfoClass *klass;
+       const CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_headers != NULL, NULL);
+
+       camel_message_info_property_lock (mi);
+       result = klass->get_headers (mi);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_dup_headers:
+ * @mi: a #CamelMessageInfo
+ *
+ * Duplicates array of headers for the @mi.
+ *
+ * Returns: (transfer full) (nullable): All the message headers of the associated
+ *   message, or %NULL, when none are available. Free returned array with
+ *   camel_name_value_array_free() when no longer needed.
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+camel_message_info_dup_headers (const CamelMessageInfo *mi)
+{
+       const CamelNameValueArray *arr;
+       CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       camel_message_info_property_lock (mi);
+       arr = camel_message_info_get_headers (mi);
+       if (arr) {
+               result = camel_name_value_array_copy (arr);
+       } else {
+               result = NULL;
+       }
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * camel_message_info_take_headers:
+ * @mi: a #CamelMessageInfo
+ * @headers: (transfer full) (nullable): headers to set, as #CamelNameValueArray, or %NULL
+ *
+ * Takes headers of the associated message.
+ *
+ * This property is considered static, in a meaning that it should
+ * not change during the life-time of the @mi, the same as it doesn't
+ * change in the associated message.
+ *
+ * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
+ * set automatically, unless the @mi is aborting notifications. There is not emitted
+ * folder's "changed" signal for this @mi.
+ *
+ * Note that it's not safe to use the @headers after the call to this function,
+ * because it can be freed due to no change.
+ *
+ * Returns: Whether the value changed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_message_info_take_headers (CamelMessageInfo *mi,
+                                CamelNameValueArray *headers)
+{
+       CamelMessageInfoClass *klass;
+       gboolean changed, abort_notifications;
+
+       g_return_val_if_fail (CAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       klass = CAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->take_headers != NULL, FALSE);
+
+       camel_message_info_property_lock (mi);
+       changed = klass->take_headers (mi, headers);
+       abort_notifications = mi->priv->abort_notifications;
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !abort_notifications) {
+               g_object_notify (G_OBJECT (mi), "headers");
+               camel_message_info_set_dirty (mi, TRUE);
+               camel_message_info_set_folder_flagged (mi, TRUE);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_message_info_dump:
+ * @mi: a #CamelMessageInfo
+ *
+ * Dumps the mesasge info @mi to stdout. This is meand for debugging
+ * purposes only.
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_dump (CamelMessageInfo *mi)
+{
+       if (!mi) {
+               printf ("No message info\n");
+               return;
+       }
+
+       camel_message_info_property_lock (mi);
+
+       printf ("Message info %s:\n", G_OBJECT_TYPE_NAME (mi));
+       printf ("   UID: %s\n", camel_message_info_get_uid (mi));
+       printf ("   Flags: %04x\n", camel_message_info_get_flags (mi));
+       printf ("   From: %s\n", camel_message_info_get_from (mi));
+       printf ("   To: %s\n", camel_message_info_get_to (mi));
+       printf ("   Cc: %s\n", camel_message_info_get_cc (mi));
+       printf ("   Mailing list: %s\n", camel_message_info_get_mlist (mi));
+       printf ("   Subject: %s\n", camel_message_info_get_subject (mi));
+
+       camel_message_info_property_unlock (mi);
+}
diff --git a/src/camel/camel-message-info.h b/src/camel/camel-message-info.h
new file mode 100644
index 0000000..7b355cb
--- /dev/null
+++ b/src/camel/camel-message-info.h
@@ -0,0 +1,328 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_MESSAGE_INFO_H
+#define CAMEL_MESSAGE_INFO_H
+
+#include <glib-object.h>
+
+#include <camel/camel-named-flags.h>
+#include <camel/camel-name-value-array.h>
+#include <camel/camel-utils.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_MESSAGE_INFO \
+       (camel_message_info_get_type ())
+#define CAMEL_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_MESSAGE_INFO, CamelMessageInfo))
+#define CAMEL_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_MESSAGE_INFO, CamelMessageInfoClass))
+#define CAMEL_IS_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_MESSAGE_INFO))
+#define CAMEL_IS_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_MESSAGE_INFO))
+#define CAMEL_MESSAGE_INFO_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_MESSAGE_INFO, CamelMessageInfoClass))
+
+G_BEGIN_DECLS
+
+/* Forward declarations */
+struct _CamelFolderSummary;
+struct _CamelMIRecord;
+
+/* A summary messageid is a 64 bit identifier (partial md5 hash) */
+typedef struct _CamelSummaryMessageID {
+       union {
+               guint64 id;
+               guchar hash[8];
+               struct {
+                       guint32 hi;
+                       guint32 lo;
+               } part;
+       } id;
+} CamelSummaryMessageID;
+
+/* system flag bits */
+typedef enum _CamelMessageFlags {
+       CAMEL_MESSAGE_ANSWERED = 1 << 0,
+       CAMEL_MESSAGE_DELETED = 1 << 1,
+       CAMEL_MESSAGE_DRAFT = 1 << 2,
+       CAMEL_MESSAGE_FLAGGED = 1 << 3,
+       CAMEL_MESSAGE_SEEN = 1 << 4,
+
+       /* these aren't really system flag bits, but are convenience flags */
+       CAMEL_MESSAGE_ATTACHMENTS = 1 << 5,
+       CAMEL_MESSAGE_ANSWERED_ALL = 1 << 6,
+       CAMEL_MESSAGE_JUNK = 1 << 7,
+       CAMEL_MESSAGE_SECURE = 1 << 8,
+       CAMEL_MESSAGE_NOTJUNK = 1 << 9,
+       CAMEL_MESSAGE_FORWARDED = 1 << 10,
+
+       /* following flags are for the folder, and are not really permanent flags */
+       CAMEL_MESSAGE_FOLDER_FLAGGED = 1 << 16, /* for use by the folder implementation */
+       /* flags after 1 << 16 are used by camel providers,
+        * if adding non permanent flags, add them to the end  */
+
+       CAMEL_MESSAGE_JUNK_LEARN = 1 << 30, /* used when setting CAMEL_MESSAGE_JUNK flag
+                                            * to say that we request junk plugin
+                                            * to learn that message as junk/non junk */
+       CAMEL_MESSAGE_USER = 1 << 31 /* supports user flags */
+} CamelMessageFlags;
+
+/* Changes to system flags will NOT trigger a folder changed event */
+#define CAMEL_MESSAGE_SYSTEM_MASK (0xffff << 16)
+
+typedef struct _CamelMessageInfo CamelMessageInfo;
+typedef struct _CamelMessageInfoClass CamelMessageInfoClass;
+typedef struct _CamelMessageInfoPrivate CamelMessageInfoPrivate;
+
+struct _CamelMessageInfo {
+       GObject parent;
+       CamelMessageInfoPrivate *priv;
+};
+
+struct _CamelMessageInfoClass {
+       GObjectClass parent_class;
+
+       CamelMessageInfo *      (* clone)       (const CamelMessageInfo *mi,
+                                                struct _CamelFolderSummary *assign_summary);
+       gboolean                (* load)        (CamelMessageInfo *mi,
+                                                const struct _CamelMIRecord *record,
+                                                /* const */ gchar **bdata_ptr);
+       gboolean                (* save)        (const CamelMessageInfo *mi,
+                                                struct _CamelMIRecord *record,
+                                                GString *bdata_str);
+       guint32                 (* get_flags)   (const CamelMessageInfo *mi);
+       gboolean                (* set_flags)   (CamelMessageInfo *mi,
+                                                guint32 mask,
+                                                guint32 set);
+       gboolean                (* get_user_flag)
+                                               (const CamelMessageInfo *mi,
+                                                const gchar *name);
+       gboolean                (* set_user_flag)
+                                               (CamelMessageInfo *mi,
+                                                const gchar *name,
+                                                gboolean state);
+       const CamelNamedFlags * (* get_user_flags)
+                                               (const CamelMessageInfo *mi);
+       CamelNamedFlags *       (* dup_user_flags)
+                                               (const CamelMessageInfo *mi);
+       gboolean                (* take_user_flags)
+                                               (CamelMessageInfo *mi,
+                                                CamelNamedFlags *user_flags);
+       const gchar *           (* get_user_tag)(const CamelMessageInfo *mi,
+                                                const gchar *name);
+       gboolean                (* set_user_tag)(CamelMessageInfo *mi,
+                                                const gchar *name,
+                                                const gchar *value);
+       const CamelNameValueArray *
+                               (* get_user_tags)
+                                               (const CamelMessageInfo *mi);
+       CamelNameValueArray *   (* dup_user_tags)
+                                               (const CamelMessageInfo *mi);
+       gboolean                (* take_user_tags)
+                                               (CamelMessageInfo *mi,
+                                                CamelNameValueArray *user_tags);
+       const gchar *           (* get_subject) (const CamelMessageInfo *mi);
+       gboolean                (* set_subject) (CamelMessageInfo *mi,
+                                                const gchar *subject);
+       const gchar *           (* get_from)    (const CamelMessageInfo *mi);
+       gboolean                (* set_from)    (CamelMessageInfo *mi,
+                                                const gchar *from);
+       const gchar *           (* get_to)      (const CamelMessageInfo *mi);
+       gboolean                (* set_to)      (CamelMessageInfo *mi,
+                                                const gchar *to);
+       const gchar *           (* get_cc)      (const CamelMessageInfo *mi);
+       gboolean                (* set_cc)      (CamelMessageInfo *mi,
+                                                const gchar *cc);
+       const gchar *           (* get_mlist)   (const CamelMessageInfo *mi);
+       gboolean                (* set_mlist)   (CamelMessageInfo *mi,
+                                                const gchar *mlist);
+       guint32                 (* get_size)    (const CamelMessageInfo *mi);
+       gboolean                (* set_size)    (CamelMessageInfo *mi,
+                                                guint32 size);
+       gint64                  (* get_date_sent)
+                                               (const CamelMessageInfo *mi);
+       gboolean                (* set_date_sent)
+                                               (CamelMessageInfo *mi,
+                                                gint64 date_sent);
+       gint64                  (* get_date_received)
+                                               (const CamelMessageInfo *mi);
+       gboolean                (* set_date_received)
+                                               (CamelMessageInfo *mi,
+                                                gint64 date_received);
+       guint64                 (* get_message_id)
+                                               (const CamelMessageInfo *mi);
+       gboolean                (* set_message_id)
+                                               (CamelMessageInfo *mi,
+                                                guint64 message_id);
+       const GArray *          (* get_references)
+                                               (const CamelMessageInfo *mi);
+       gboolean                (* take_references)
+                                               (CamelMessageInfo *mi,
+                                                GArray *references);
+       const CamelNameValueArray *
+                               (* get_headers) (const CamelMessageInfo *mi);
+       gboolean                (* take_headers)(CamelMessageInfo *mi,
+                                                CamelNameValueArray *headers);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
+};
+
+GType          camel_message_info_get_type     (void);
+CamelMessageInfo *
+               camel_message_info_new          (struct _CamelFolderSummary *summary);
+CamelMessageInfo *
+               camel_message_info_clone        (const CamelMessageInfo *mi,
+                                                struct _CamelFolderSummary *assign_summary);
+gboolean       camel_message_info_load         (CamelMessageInfo *mi,
+                                                const struct _CamelMIRecord *record,
+                                                /* const */ gchar **bdata_ptr);
+gboolean       camel_message_info_save         (const CamelMessageInfo *mi,
+                                                struct _CamelMIRecord *record,
+                                                GString *bdata_str);
+struct _CamelFolderSummary *
+               camel_message_info_ref_summary  (const CamelMessageInfo *mi);
+void           camel_message_info_property_lock
+                                               (const CamelMessageInfo *mi);
+void           camel_message_info_property_unlock
+                                               (const CamelMessageInfo *mi);
+gboolean       camel_message_info_get_dirty    (const CamelMessageInfo *mi);
+void           camel_message_info_set_dirty    (const CamelMessageInfo *mi,
+                                                gboolean dirty);
+gboolean       camel_message_info_get_folder_flagged
+                                               (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_folder_flagged
+                                               (CamelMessageInfo *mi,
+                                                gboolean folder_flagged);
+guint          camel_message_info_get_folder_flagged_stamp
+                                               (const CamelMessageInfo *mi);
+gboolean       camel_message_info_get_abort_notifications
+                                               (const CamelMessageInfo *mi);
+void           camel_message_info_set_abort_notifications
+                                               (CamelMessageInfo *mi,
+                                                gboolean abort_notifications);
+void           camel_message_info_freeze_notifications
+                                               (CamelMessageInfo *mi);
+void           camel_message_info_thaw_notifications
+                                               (CamelMessageInfo *mi);
+gboolean       camel_message_info_get_notifications_frozen
+                                               (const CamelMessageInfo *mi);
+const gchar *  camel_message_info_get_uid      (const CamelMessageInfo *mi);
+const gchar *  camel_message_info_pooldup_uid  (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_uid      (CamelMessageInfo *mi,
+                                                const gchar *uid);
+guint32                camel_message_info_get_flags    (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_flags    (CamelMessageInfo *mi,
+                                                guint32 mask,
+                                                guint32 set);
+gboolean       camel_message_info_get_user_flag
+                                               (const CamelMessageInfo *mi,
+                                                const gchar *name);
+gboolean       camel_message_info_set_user_flag
+                                               (CamelMessageInfo *mi,
+                                                const gchar *name,
+                                                gboolean state);
+const CamelNamedFlags *
+               camel_message_info_get_user_flags
+                                               (const CamelMessageInfo *mi);
+CamelNamedFlags *
+               camel_message_info_dup_user_flags
+                                               (const CamelMessageInfo *mi);
+gboolean
+               camel_message_info_take_user_flags
+                                               (CamelMessageInfo *mi,
+                                                CamelNamedFlags *user_flags);
+const gchar *  camel_message_info_get_user_tag (const CamelMessageInfo *mi,
+                                                const gchar *name);
+gchar *                camel_message_info_dup_user_tag (const CamelMessageInfo *mi,
+                                                const gchar *name);
+gboolean       camel_message_info_set_user_tag (CamelMessageInfo *mi,
+                                                const gchar *name,
+                                                const gchar *value);
+const CamelNameValueArray *
+               camel_message_info_get_user_tags
+                                               (const CamelMessageInfo *mi);
+CamelNameValueArray *
+               camel_message_info_dup_user_tags
+                                               (const CamelMessageInfo *mi);
+gboolean       camel_message_info_take_user_tags
+                                               (CamelMessageInfo *mi,
+                                                CamelNameValueArray *user_tags);
+const gchar *  camel_message_info_get_subject  (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_subject  (CamelMessageInfo *mi,
+                                                const gchar *subject);
+const gchar *  camel_message_info_get_from     (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_from     (CamelMessageInfo *mi,
+                                                const gchar *from);
+const gchar *  camel_message_info_get_to       (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_to       (CamelMessageInfo *mi,
+                                                const gchar *to);
+const gchar *  camel_message_info_get_cc       (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_cc       (CamelMessageInfo *mi,
+                                                const gchar *cc);
+const gchar *  camel_message_info_get_mlist    (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_mlist    (CamelMessageInfo *mi,
+                                                const gchar *mlist);
+guint32                camel_message_info_get_size     (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_size     (CamelMessageInfo *mi,
+                                                guint32 size);
+gint64         camel_message_info_get_date_sent
+                                               (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_date_sent
+                                               (CamelMessageInfo *mi,
+                                                gint64 date_sent);
+gint64         camel_message_info_get_date_received
+                                               (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_date_received
+                                               (CamelMessageInfo *mi,
+                                                gint64 date_received);
+guint64                camel_message_info_get_message_id
+                                               (const CamelMessageInfo *mi);
+gboolean       camel_message_info_set_message_id
+                                               (CamelMessageInfo *mi,
+                                                guint64 message_id);
+const GArray * camel_message_info_get_references
+                                               (const CamelMessageInfo *mi);
+GArray *       camel_message_info_dup_references
+                                               (const CamelMessageInfo *mi);
+gboolean       camel_message_info_take_references
+                                               (CamelMessageInfo *mi,
+                                                GArray *references);
+const CamelNameValueArray *
+               camel_message_info_get_headers  (const CamelMessageInfo *mi);
+CamelNameValueArray *
+               camel_message_info_dup_headers  (const CamelMessageInfo *mi);
+gboolean       camel_message_info_take_headers (CamelMessageInfo *mi,
+                                                CamelNameValueArray *headers);
+
+/* Debugging functions */
+void           camel_message_info_dump         (CamelMessageInfo *mi);
+
+G_END_DECLS
+
+#endif /* CAMEL_MESSAGE_INFO_H */
diff --git a/src/camel/camel-mime-filter-basic.h b/src/camel/camel-mime-filter-basic.h
index a393632..8ad4f29 100644
--- a/src/camel/camel-mime-filter-basic.h
+++ b/src/camel/camel-mime-filter-basic.h
@@ -59,6 +59,9 @@ struct _CamelMimeFilterBasic {
 
 struct _CamelMimeFilterBasicClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_basic_get_type (void);
diff --git a/src/camel/camel-mime-filter-bestenc.h b/src/camel/camel-mime-filter-bestenc.h
index 9d5f95b..ff4a190 100644
--- a/src/camel/camel-mime-filter-bestenc.h
+++ b/src/camel/camel-mime-filter-bestenc.h
@@ -79,6 +79,9 @@ struct _CamelMimeFilterBestenc {
 
 struct _CamelMimeFilterBestencClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_bestenc_get_type (void);
diff --git a/src/camel/camel-mime-filter-canon.h b/src/camel/camel-mime-filter-canon.h
index 7a725d0..495a065 100644
--- a/src/camel/camel-mime-filter-canon.h
+++ b/src/camel/camel-mime-filter-canon.h
@@ -65,6 +65,9 @@ struct _CamelMimeFilterCanon {
 
 struct _CamelMimeFilterCanonClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_canon_get_type (void);
diff --git a/src/camel/camel-mime-filter-charset.h b/src/camel/camel-mime-filter-charset.h
index a3336dd..27d743c 100644
--- a/src/camel/camel-mime-filter-charset.h
+++ b/src/camel/camel-mime-filter-charset.h
@@ -59,6 +59,9 @@ struct _CamelMimeFilterCharset {
 
 struct _CamelMimeFilterCharsetClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_charset_get_type (void);
diff --git a/src/camel/camel-mime-filter-crlf.h b/src/camel/camel-mime-filter-crlf.h
index 3c2ae69..47dc502 100644
--- a/src/camel/camel-mime-filter-crlf.h
+++ b/src/camel/camel-mime-filter-crlf.h
@@ -60,6 +60,9 @@ struct _CamelMimeFilterCRLF {
 
 struct _CamelMimeFilterCRLFClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_crlf_get_type (void);
diff --git a/src/camel/camel-mime-filter-enriched.h b/src/camel/camel-mime-filter-enriched.h
index 0ffad8e..fbdf797 100644
--- a/src/camel/camel-mime-filter-enriched.h
+++ b/src/camel/camel-mime-filter-enriched.h
@@ -60,6 +60,9 @@ struct _CamelMimeFilterEnriched {
 
 struct _CamelMimeFilterEnrichedClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_enriched_get_type (void);
diff --git a/src/camel/camel-mime-filter-from.h b/src/camel/camel-mime-filter-from.h
index 86b3d20..93f6aef 100644
--- a/src/camel/camel-mime-filter-from.h
+++ b/src/camel/camel-mime-filter-from.h
@@ -58,6 +58,9 @@ struct _CamelMimeFilterFrom {
 
 struct _CamelMimeFilterFromClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_from_get_type (void);
diff --git a/src/camel/camel-mime-filter-gzip.h b/src/camel/camel-mime-filter-gzip.h
index ac2ca5f..0b92411 100644
--- a/src/camel/camel-mime-filter-gzip.h
+++ b/src/camel/camel-mime-filter-gzip.h
@@ -59,6 +59,9 @@ struct _CamelMimeFilterGZip {
 
 struct _CamelMimeFilterGZipClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_gzip_get_type (void);
diff --git a/src/camel/camel-mime-filter-html.h b/src/camel/camel-mime-filter-html.h
index 71e9a9e..664b897 100644
--- a/src/camel/camel-mime-filter-html.h
+++ b/src/camel/camel-mime-filter-html.h
@@ -58,6 +58,9 @@ struct _CamelMimeFilterHTML {
 
 struct _CamelMimeFilterHTMLClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_html_get_type (void);
diff --git a/src/camel/camel-mime-filter-index.h b/src/camel/camel-mime-filter-index.h
index 3ca3881..80a425f 100644
--- a/src/camel/camel-mime-filter-index.h
+++ b/src/camel/camel-mime-filter-index.h
@@ -59,6 +59,9 @@ struct _CamelMimeFilterIndex {
 
 struct _CamelMimeFilterIndexClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_index_get_type (void);
diff --git a/src/camel/camel-mime-filter-linewrap.h b/src/camel/camel-mime-filter-linewrap.h
index 51bf6b7..a1229d1 100644
--- a/src/camel/camel-mime-filter-linewrap.h
+++ b/src/camel/camel-mime-filter-linewrap.h
@@ -63,6 +63,9 @@ struct _CamelMimeFilterLinewrap {
 
 struct _CamelMimeFilterLinewrapClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_linewrap_get_type (void);
diff --git a/src/camel/camel-mime-filter-pgp.h b/src/camel/camel-mime-filter-pgp.h
index a2b9155..11ab23b 100644
--- a/src/camel/camel-mime-filter-pgp.h
+++ b/src/camel/camel-mime-filter-pgp.h
@@ -58,6 +58,9 @@ struct _CamelMimeFilterPgp {
 
 struct _CamelMimeFilterPgpClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_pgp_get_type  (void);
diff --git a/src/camel/camel-mime-filter-progress.h b/src/camel/camel-mime-filter-progress.h
index 9f8a19c..e76f5b8 100644
--- a/src/camel/camel-mime-filter-progress.h
+++ b/src/camel/camel-mime-filter-progress.h
@@ -65,6 +65,9 @@ struct _CamelMimeFilterProgress {
 
 struct _CamelMimeFilterProgressClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_progress_get_type (void);
diff --git a/src/camel/camel-mime-filter-tohtml.h b/src/camel/camel-mime-filter-tohtml.h
index a0b9d2a..ef6d384 100644
--- a/src/camel/camel-mime-filter-tohtml.h
+++ b/src/camel/camel-mime-filter-tohtml.h
@@ -59,6 +59,9 @@ struct _CamelMimeFilterToHTML {
 
 struct _CamelMimeFilterToHTMLClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_tohtml_get_type (void);
diff --git a/src/camel/camel-mime-filter-windows.h b/src/camel/camel-mime-filter-windows.h
index 17a3d2a..99fcd0a 100644
--- a/src/camel/camel-mime-filter-windows.h
+++ b/src/camel/camel-mime-filter-windows.h
@@ -58,6 +58,9 @@ struct _CamelMimeFilterWindows {
 
 struct _CamelMimeFilterWindowsClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_windows_get_type (void);
diff --git a/src/camel/camel-mime-filter-yenc.c b/src/camel/camel-mime-filter-yenc.c
index ba87c9e..8f75192 100644
--- a/src/camel/camel-mime-filter-yenc.c
+++ b/src/camel/camel-mime-filter-yenc.c
@@ -380,12 +380,12 @@ static const gint yenc_crc_table[256] = {
 
 /**
  * camel_ydecode_step:
- * @in: input buffer
+ * @in: (type guchar) (array length=inlen): input buffer
  * @inlen: input buffer length
- * @out: output buffer
- * @state: ydecode state
- * @pcrc: part crc state
- * @crc: crc state
+ * @out: (out) (array): output buffer
+ * @state: (out): ydecode state
+ * @pcrc: (out): part crc state
+ * @crc: (out): crc state
  *
  * Performs a 'decode step' on a chunk of yEncoded data of length
  * @inlen pointed to by @in and writes to @out. Assumes the =ybegin
@@ -463,12 +463,12 @@ camel_ydecode_step (const guchar *in,
 
 /**
  * camel_yencode_step:
- * @in: input buffer
+ * @in: (type guchar) (array length=inlen): input buffer
  * @inlen: input buffer length
- * @out: output buffer
- * @state: yencode state
- * @pcrc: part crc state
- * @crc: crc state
+ * @out: (array) (out): output buffer
+ * @state: (out): yencode state
+ * @pcrc: (out): part crc state
+ * @crc: (out): crc state
  *
  * Performs an yEncode 'encode step' on a chunk of raw data of length
  * @inlen pointed to by @in and writes to @out.
@@ -532,12 +532,12 @@ camel_yencode_step (const guchar *in,
 
 /**
  * camel_yencode_close:
- * @in: input buffer
+ * @in: (type guchar) (array length=inlen): input buffer
  * @inlen: input buffer length
- * @out: output buffer
- * @state: yencode state
- * @pcrc: part crc state
- * @crc: crc state
+ * @out: (array) (out): output buffer
+ * @state: (out): yencode state
+ * @pcrc: (out): part crc state
+ * @crc: (out): crc state
  *
  * Call this function when finished encoding data with
  * camel_yencode_step() to flush off the remaining state.
diff --git a/src/camel/camel-mime-filter-yenc.h b/src/camel/camel-mime-filter-yenc.h
index fa9d6d7..8fce654 100644
--- a/src/camel/camel-mime-filter-yenc.h
+++ b/src/camel/camel-mime-filter-yenc.h
@@ -78,6 +78,9 @@ struct _CamelMimeFilterYenc {
 
 struct _CamelMimeFilterYencClass {
        CamelMimeFilterClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_yenc_get_type (void);
diff --git a/src/camel/camel-mime-filter.h b/src/camel/camel-mime-filter.h
index a064aed..45dfc0d 100644
--- a/src/camel/camel-mime-filter.h
+++ b/src/camel/camel-mime-filter.h
@@ -88,6 +88,9 @@ struct _CamelMimeFilterClass {
                                                 gsize *outlen,
                                                 gsize *outprespace);
        void            (*reset)                (CamelMimeFilter *filter);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_filter_get_type      (void);
diff --git a/src/camel/camel-mime-message.c b/src/camel/camel-mime-message.c
index 8f32c67..195b1f2 100644
--- a/src/camel/camel-mime-message.c
+++ b/src/camel/camel-mime-message.c
@@ -48,7 +48,24 @@
 #endif
 #define d(x)
 
-extern gint camel_verbose_debug;
+struct _CamelMimeMessagePrivate {
+       /* header fields */
+       time_t date;
+       gint date_offset;       /* GMT offset */
+
+       /* cached internal copy */
+       time_t date_received;
+       gint date_received_offset;      /* GMT offset */
+
+       gchar *subject;
+
+       gchar *message_id;
+
+       CamelInternetAddress *reply_to;
+       CamelInternetAddress *from;
+
+       GHashTable *recipients; /* hash table of CamelInternetAddress's */
+};
 
 /* these 2 below should be kept in sync */
 typedef enum {
@@ -100,9 +117,9 @@ process_header (CamelMedium *medium,
                if (camel_address_decode ((CamelAddress *) addr, unfolded) <= 0) {
                        g_object_unref (addr);
                } else {
-                       if (message->from)
-                               g_object_unref (message->from);
-                       message->from = addr;
+                       if (message->priv->from)
+                               g_object_unref (message->priv->from);
+                       message->priv->from = addr;
                }
                g_free (unfolded);
                break;
@@ -112,22 +129,22 @@ process_header (CamelMedium *medium,
                if (camel_address_decode ((CamelAddress *) addr, unfolded) <= 0) {
                        g_object_unref (addr);
                } else {
-                       if (message->reply_to)
-                               g_object_unref (message->reply_to);
-                       message->reply_to = addr;
+                       if (message->priv->reply_to)
+                               g_object_unref (message->priv->reply_to);
+                       message->priv->reply_to = addr;
                }
                g_free (unfolded);
                break;
        case HEADER_SUBJECT:
-               g_free (message->subject);
-               if (((CamelDataWrapper *) message)->mime_type) {
-                       charset = camel_content_type_param (((CamelDataWrapper *) message)->mime_type, 
"charset");
+               g_free (message->priv->subject);
+               if (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (message))) {
+                       charset = camel_content_type_param (camel_data_wrapper_get_mime_type_field 
(CAMEL_DATA_WRAPPER (message)), "charset");
                        charset = camel_iconv_charset_name (charset);
                } else
                        charset = NULL;
 
                unfolded = camel_header_unfold (value);
-               message->subject = g_strstrip (camel_header_decode_string (unfolded, charset));
+               message->priv->subject = g_strstrip (camel_header_decode_string (unfolded, charset));
                g_free (unfolded);
                break;
        case HEADER_TO:
@@ -136,7 +153,7 @@ process_header (CamelMedium *medium,
        case HEADER_RESENT_TO:
        case HEADER_RESENT_CC:
        case HEADER_RESENT_BCC:
-               addr = g_hash_table_lookup (message->recipients, name);
+               addr = g_hash_table_lookup (message->priv->recipients, name);
                if (value) {
                        unfolded = camel_header_unfold (value);
                        camel_address_decode (CAMEL_ADDRESS (addr), unfolded);
@@ -147,18 +164,18 @@ process_header (CamelMedium *medium,
                return FALSE;
        case HEADER_DATE:
                if (value) {
-                       message->date = camel_header_decode_date (value, &message->date_offset);
+                       message->priv->date = camel_header_decode_date (value, &message->priv->date_offset);
                } else {
-                       message->date = CAMEL_MESSAGE_DATE_CURRENT;
-                       message->date_offset = 0;
+                       message->priv->date = CAMEL_MESSAGE_DATE_CURRENT;
+                       message->priv->date_offset = 0;
                }
                break;
        case HEADER_MESSAGE_ID:
-               g_free (message->message_id);
+               g_free (message->priv->message_id);
                if (value)
-                       message->message_id = camel_header_msgid_decode (value);
+                       message->priv->message_id = camel_header_msgid_decode (value);
                else
-                       message->message_id = NULL;
+                       message->priv->message_id = NULL;
                break;
        default:
                return FALSE;
@@ -180,17 +197,17 @@ mime_message_ensure_required_headers (CamelMimeMessage *message)
 {
        CamelMedium *medium = CAMEL_MEDIUM (message);
 
-       if (message->from == NULL) {
+       if (message->priv->from == NULL) {
                camel_medium_set_header (medium, "From", "");
        }
        if (!camel_medium_get_header (medium, "Date"))
                camel_mime_message_set_date (
                        message, CAMEL_MESSAGE_DATE_CURRENT, 0);
 
-       if (message->subject == NULL)
+       if (message->priv->subject == NULL)
                camel_mime_message_set_subject (message, "No Subject");
 
-       if (message->message_id == NULL)
+       if (message->priv->message_id == NULL)
                camel_mime_message_set_message_id (message, NULL);
 
        /* FIXME: "To" header needs to be set explicitly as well ... */
@@ -204,15 +221,8 @@ mime_message_dispose (GObject *object)
 {
        CamelMimeMessage *message = CAMEL_MIME_MESSAGE (object);
 
-       if (message->reply_to != NULL) {
-               g_object_unref (message->reply_to);
-               message->reply_to = NULL;
-       }
-
-       if (message->from != NULL) {
-               g_object_unref (message->from);
-               message->from = NULL;
-       }
+       g_clear_object (&message->priv->reply_to);
+       g_clear_object (&message->priv->from);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (camel_mime_message_parent_class)->dispose (object);
@@ -223,12 +233,11 @@ mime_message_finalize (GObject *object)
 {
        CamelMimeMessage *message = CAMEL_MIME_MESSAGE (object);
 
-       g_free (message->subject);
+       g_free (message->priv->subject);
+       g_free (message->priv->message_id);
 
-       g_free (message->message_id);
-
-       g_hash_table_foreach (message->recipients, unref_recipient, NULL);
-       g_hash_table_destroy (message->recipients);
+       g_hash_table_foreach (message->priv->recipients, unref_recipient, NULL);
+       g_hash_table_destroy (message->priv->recipients);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_mime_message_parent_class)->finalize (object);
@@ -271,7 +280,7 @@ mime_message_write_to_output_stream_sync (CamelDataWrapper *data_wrapper,
 static void
 mime_message_add_header (CamelMedium *medium,
                          const gchar *name,
-                         gconstpointer value)
+                         const gchar *value)
 {
        CamelMediumClass *medium_class;
 
@@ -287,7 +296,7 @@ mime_message_add_header (CamelMedium *medium,
 static void
 mime_message_set_header (CamelMedium *medium,
                          const gchar *name,
-                         gconstpointer value)
+                         const gchar *value)
 {
        process_header (medium, name, value);
 
@@ -363,6 +372,8 @@ camel_mime_message_class_init (CamelMimeMessageClass *class)
        CamelMediumClass *medium_class;
        gint ii;
 
+       g_type_class_add_private (class, sizeof (CamelMimeMessagePrivate));
+
        object_class = G_OBJECT_CLASS (class);
        object_class->dispose = mime_message_dispose;
        object_class->finalize = mime_message_finalize;
@@ -395,23 +406,25 @@ camel_mime_message_init (CamelMimeMessage *mime_message)
 {
        gint ii;
 
-       mime_message->recipients = g_hash_table_new (
+       mime_message->priv = G_TYPE_INSTANCE_GET_PRIVATE (mime_message, CAMEL_TYPE_MIME_MESSAGE, 
CamelMimeMessagePrivate);
+
+       mime_message->priv->recipients = g_hash_table_new (
                camel_strcase_hash, camel_strcase_equal);
        for (ii = 0; recipient_names[ii] != NULL; ii++) {
                g_hash_table_insert (
-                       mime_message->recipients,
+                       mime_message->priv->recipients,
                        (gpointer) recipient_names[ii],
                        camel_internet_address_new ());
        }
 
-       mime_message->subject = NULL;
-       mime_message->reply_to = NULL;
-       mime_message->from = NULL;
-       mime_message->date = CAMEL_MESSAGE_DATE_CURRENT;
-       mime_message->date_offset = 0;
-       mime_message->date_received = CAMEL_MESSAGE_DATE_CURRENT;
-       mime_message->date_received_offset = 0;
-       mime_message->message_id = NULL;
+       mime_message->priv->subject = NULL;
+       mime_message->priv->reply_to = NULL;
+       mime_message->priv->from = NULL;
+       mime_message->priv->date = CAMEL_MESSAGE_DATE_CURRENT;
+       mime_message->priv->date_offset = 0;
+       mime_message->priv->date_received = CAMEL_MESSAGE_DATE_CURRENT;
+       mime_message->priv->date_received_offset = 0;
+       mime_message->priv->message_id = NULL;
 }
 
 /**
@@ -454,8 +467,8 @@ camel_mime_message_set_date (CamelMimeMessage *message,
                camel_localtime_with_offset (date, &local, &tz);
                offset = (((tz / 60 / 60) * 100) + (tz / 60 % 60));
        }
-       message->date = date;
-       message->date_offset = offset;
+       message->priv->date = date;
+       message->priv->date_offset = offset;
 
        datestr = camel_header_format_date (date, offset);
        CAMEL_MEDIUM_CLASS (camel_mime_message_parent_class)->set_header ((CamelMedium *) message, "Date", 
datestr);
@@ -476,9 +489,9 @@ camel_mime_message_get_date (CamelMimeMessage *msg,
                              gint *offset)
 {
        if (offset)
-               *offset = msg->date_offset;
+               *offset = msg->priv->date_offset;
 
-       return msg->date;
+       return msg->priv->date;
 }
 
 /**
@@ -494,20 +507,20 @@ time_t
 camel_mime_message_get_date_received (CamelMimeMessage *msg,
                                       gint *offset)
 {
-       if (msg->date_received == CAMEL_MESSAGE_DATE_CURRENT) {
+       if (msg->priv->date_received == CAMEL_MESSAGE_DATE_CURRENT) {
                const gchar *received;
 
                received = camel_medium_get_header ((CamelMedium *) msg, "received");
                if (received)
                        received = strrchr (received, ';');
                if (received)
-                       msg->date_received = camel_header_decode_date (received + 1, 
&msg->date_received_offset);
+                       msg->priv->date_received = camel_header_decode_date (received + 1, 
&msg->priv->date_received_offset);
        }
 
        if (offset)
-               *offset = msg->date_received_offset;
+               *offset = msg->priv->date_received_offset;
 
-       return msg->date_received;
+       return msg->priv->date_received;
 }
 
 /* **** Message-ID: */
@@ -527,7 +540,7 @@ camel_mime_message_set_message_id (CamelMimeMessage *mime_message,
 
        g_return_if_fail (mime_message);
 
-       g_free (mime_message->message_id);
+       g_free (mime_message->priv->message_id);
 
        if (message_id) {
                id = g_strstrip (g_strdup (message_id));
@@ -547,8 +560,8 @@ camel_mime_message_set_message_id (CamelMimeMessage *mime_message,
                id = camel_header_msgid_generate (domain);
        }
 
-       mime_message->message_id = id;
-       id = g_strdup_printf ("<%s>", mime_message->message_id);
+       mime_message->priv->message_id = id;
+       id = g_strdup_printf ("<%s>", mime_message->priv->message_id);
        CAMEL_MEDIUM_CLASS (camel_mime_message_parent_class)->set_header (CAMEL_MEDIUM (mime_message), 
"Message-ID", id);
        g_free (id);
 }
@@ -566,7 +579,7 @@ camel_mime_message_get_message_id (CamelMimeMessage *mime_message)
 {
        g_return_val_if_fail (mime_message, NULL);
 
-       return mime_message->message_id;
+       return mime_message->priv->message_id;
 }
 
 /* **** Reply-To: */
@@ -586,18 +599,15 @@ camel_mime_message_set_reply_to (CamelMimeMessage *msg,
 
        g_return_if_fail (msg);
 
-       if (msg->reply_to) {
-               g_object_unref (msg->reply_to);
-               msg->reply_to = NULL;
-       }
+       g_clear_object (&msg->priv->reply_to);
 
        if (reply_to == NULL) {
                CAMEL_MEDIUM_CLASS (camel_mime_message_parent_class)->remove_header (CAMEL_MEDIUM (msg), 
"Reply-To");
                return;
        }
 
-       msg->reply_to = (CamelInternetAddress *) camel_address_new_clone ((CamelAddress *) reply_to);
-       addr = camel_address_encode ((CamelAddress *) msg->reply_to);
+       msg->priv->reply_to = (CamelInternetAddress *) camel_address_new_clone ((CamelAddress *) reply_to);
+       addr = camel_address_encode ((CamelAddress *) msg->priv->reply_to);
        CAMEL_MEDIUM_CLASS (camel_mime_message_parent_class)->set_header (CAMEL_MEDIUM (msg), "Reply-To", 
addr);
        g_free (addr);
 }
@@ -617,7 +627,7 @@ camel_mime_message_get_reply_to (CamelMimeMessage *mime_message)
 
        /* TODO: ref for threading? */
 
-       return mime_message->reply_to;
+       return mime_message->priv->reply_to;
 }
 
 /* **** Subject: */
@@ -637,13 +647,13 @@ camel_mime_message_set_subject (CamelMimeMessage *message,
 
        g_return_if_fail (message);
 
-       g_free (message->subject);
+       g_free (message->priv->subject);
 
        if (subject) {
-               message->subject = g_strstrip (g_strdup (subject));
-               text = camel_header_encode_string ((guchar *) message->subject);
+               message->priv->subject = g_strstrip (g_strdup (subject));
+               text = camel_header_encode_string ((guchar *) message->priv->subject);
        } else {
-               message->subject = NULL;
+               message->priv->subject = NULL;
                text = NULL;
        }
 
@@ -664,7 +674,7 @@ camel_mime_message_get_subject (CamelMimeMessage *mime_message)
 {
        g_return_val_if_fail (mime_message, NULL);
 
-       return mime_message->subject;
+       return mime_message->priv->subject;
 }
 
 /* *** From: */
@@ -688,18 +698,15 @@ camel_mime_message_set_from (CamelMimeMessage *msg,
 
        g_return_if_fail (msg);
 
-       if (msg->from) {
-               g_object_unref (msg->from);
-               msg->from = NULL;
-       }
+       g_clear_object (&msg->priv->from);
 
        if (from == NULL || camel_address_length ((CamelAddress *) from) == 0) {
                CAMEL_MEDIUM_CLASS (camel_mime_message_parent_class)->remove_header (CAMEL_MEDIUM (msg), 
"From");
                return;
        }
 
-       msg->from = (CamelInternetAddress *) camel_address_new_clone ((CamelAddress *) from);
-       addr = camel_address_encode ((CamelAddress *) msg->from);
+       msg->priv->from = (CamelInternetAddress *) camel_address_new_clone ((CamelAddress *) from);
+       addr = camel_address_encode ((CamelAddress *) msg->priv->from);
        CAMEL_MEDIUM_CLASS (camel_mime_message_parent_class)->set_header (CAMEL_MEDIUM (msg), "From", addr);
        g_free (addr);
 }
@@ -719,7 +726,7 @@ camel_mime_message_get_from (CamelMimeMessage *mime_message)
 
        /* TODO: we should really ref this for multi-threading to work */
 
-       return mime_message->from;
+       return mime_message->priv->from;
 }
 
 /*  **** To: Cc: Bcc: */
@@ -742,7 +749,7 @@ camel_mime_message_set_recipients (CamelMimeMessage *mime_message,
 
        g_return_if_fail (mime_message);
 
-       addr = g_hash_table_lookup (mime_message->recipients, type);
+       addr = g_hash_table_lookup (mime_message->priv->recipients, type);
        if (addr == NULL) {
                g_warning ("trying to set a non-valid receipient type: %s", type);
                return;
@@ -778,7 +785,7 @@ camel_mime_message_get_recipients (CamelMimeMessage *mime_message,
 {
        g_return_val_if_fail (mime_message, NULL);
 
-       return g_hash_table_lookup (mime_message->recipients, type);
+       return g_hash_table_lookup (mime_message->priv->recipients, type);
 }
 
 void
@@ -951,7 +958,7 @@ find_best_encoding (CamelMimePart *part,
                return CAMEL_TRANSFER_ENCODING_DEFAULT;
        }
 
-       istext = camel_content_type_is (((CamelDataWrapper *) part)->mime_type, "text", "*");
+       istext = camel_content_type_is (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (part)), 
"text", "*");
        if (istext) {
                flags = CAMEL_BESTENC_GET_CHARSET | CAMEL_BESTENC_GET_ENCODING;
                enctype |= CAMEL_BESTENC_TEXT;
@@ -971,7 +978,7 @@ find_best_encoding (CamelMimePart *part,
 
        /* if we're looking for the best charset, then we need to convert to UTF-8 */
        if (istext && (required & CAMEL_BESTENC_GET_CHARSET) != 0
-           && (charsetin = camel_content_type_param (content->mime_type, "charset"))) {
+           && (charsetin = camel_content_type_param (camel_data_wrapper_get_mime_type_field (content), 
"charset"))) {
                charenc = camel_mime_filter_charset_new (charsetin, "UTF-8");
                if (charenc != NULL)
                        idc = camel_stream_filter_add (
@@ -997,7 +1004,7 @@ find_best_encoding (CamelMimePart *part,
                d (printf ("best charset = %s\n", charsetin ? charsetin : "(null)"));
                charset = g_strdup (charsetin);
 
-               charsetin = camel_content_type_param (content->mime_type, "charset");
+               charsetin = camel_content_type_param (camel_data_wrapper_get_mime_type_field (content), 
"charset");
        } else {
                charset = NULL;
        }
@@ -1081,14 +1088,14 @@ best_encoding (CamelMimeMessage *msg,
                camel_mime_part_set_encoding (part, encoding);
 
                if ((data->required & CAMEL_BESTENC_GET_CHARSET) != 0) {
-                       if (camel_content_type_is (((CamelDataWrapper *) part)->mime_type, "text", "*")) {
+                       if (camel_content_type_is (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER 
(part)), "text", "*")) {
                                gchar *newct;
 
                                /* FIXME: ick, the part content_type interface needs fixing bigtime */
                                camel_content_type_set_param (
-                                       ((CamelDataWrapper *) part)->mime_type, "charset",
+                                       camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (part)), 
"charset",
                                        charset ? charset : "us-ascii");
-                               newct = camel_content_type_format (((CamelDataWrapper *) part)->mime_type);
+                               newct = camel_content_type_format (camel_data_wrapper_get_mime_type_field 
(CAMEL_DATA_WRAPPER (part)));
                                if (newct) {
                                        d (printf ("Setting content-type to %s\n", newct));
 
@@ -1217,7 +1224,7 @@ static const gchar tz_days[][4] = {
 gchar *
 camel_mime_message_build_mbox_from (CamelMimeMessage *message)
 {
-       struct _camel_header_raw *header = ((CamelMimePart *) message)->headers;
+       const CamelNameValueArray *headers;
        GString *out = g_string_new ("From ");
        gchar *ret;
        const gchar *tmp;
@@ -1225,9 +1232,10 @@ camel_mime_message_build_mbox_from (CamelMimeMessage *message)
        gint offset;
        struct tm tm;
 
-       tmp = camel_header_raw_find (&header, "Sender", NULL);
+       headers = camel_medium_get_headers (CAMEL_MEDIUM (message));
+       tmp = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, "Sender");
        if (tmp == NULL)
-               tmp = camel_header_raw_find (&header, "From", NULL);
+               tmp = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, "From");
        if (tmp != NULL) {
                CamelHeaderAddress *addr = camel_header_address_decode (tmp, NULL);
 
@@ -1245,7 +1253,7 @@ camel_mime_message_build_mbox_from (CamelMimeMessage *message)
                g_string_append (out, "unknown nodomain now au");
 
        /* try use the received header to get the date */
-       tmp = camel_header_raw_find (&header, "Received", NULL);
+       tmp = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, "Received");
        if (tmp) {
                tmp = strrchr (tmp, ';');
                if (tmp)
@@ -1254,7 +1262,7 @@ camel_mime_message_build_mbox_from (CamelMimeMessage *message)
 
        /* if there isn't one, try the Date field */
        if (tmp == NULL)
-               tmp = camel_header_raw_find (&header, "Date", NULL);
+               tmp = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, "Date");
 
        thetime = camel_header_decode_date (tmp, &offset);
        thetime += ((offset / 100) * (60 * 60)) + (offset % 100) * 60;
@@ -1393,7 +1401,7 @@ cmm_dump_rec (CamelMimeMessage *msg,
        s[depth] = 0;
        /* yes this leaks, so what its only debug stuff */
        printf ("%sclass: %s\n", s, G_OBJECT_TYPE_NAME (part));
-       printf ("%smime-type: %s\n", s, camel_content_type_format (((CamelDataWrapper *) part)->mime_type));
+       printf ("%smime-type: %s\n", s, camel_content_type_format (camel_data_wrapper_get_mime_type_field 
(CAMEL_DATA_WRAPPER (part))));
 
        containee = camel_medium_get_content ((CamelMedium *) part);
 
@@ -1401,7 +1409,7 @@ cmm_dump_rec (CamelMimeMessage *msg,
                return;
 
        printf ("%scontent class: %s\n", s, G_OBJECT_TYPE_NAME (containee));
-       printf ("%scontent mime-type: %s\n", s, camel_content_type_format (((CamelDataWrapper *) 
containee)->mime_type));
+       printf ("%scontent mime-type: %s\n", s, camel_content_type_format 
(camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (containee))));
 
        data = camel_data_wrapper_get_byte_array (containee);
        if (body && data) {
diff --git a/src/camel/camel-mime-message.h b/src/camel/camel-mime-message.h
index 026de17..d10f9c2 100644
--- a/src/camel/camel-mime-message.h
+++ b/src/camel/camel-mime-message.h
@@ -65,30 +65,18 @@ G_BEGIN_DECLS
 
 typedef struct _CamelMimeMessage CamelMimeMessage;
 typedef struct _CamelMimeMessageClass CamelMimeMessageClass;
+typedef struct _CamelMimeMessagePrivate CamelMimeMessagePrivate;
 
 struct _CamelMimeMessage {
        CamelMimePart parent;
-
-       /* header fields */
-       time_t date;
-       gint date_offset;       /* GMT offset */
-
-       /* cached internal copy */
-       time_t date_received;
-       gint date_received_offset;      /* GMT offset */
-
-       gchar *subject;
-
-       gchar *message_id;
-
-       CamelInternetAddress *reply_to;
-       CamelInternetAddress *from;
-
-       GHashTable *recipients; /* hash table of CamelInternetAddress's */
+       CamelMimeMessagePrivate *priv;
 };
 
 struct _CamelMimeMessageClass {
        CamelMimePartClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_message_get_type     (void);
diff --git a/src/camel/camel-mime-parser.c b/src/camel/camel-mime-parser.c
index dccf063..cfbb4c5 100644
--- a/src/camel/camel-mime-parser.c
+++ b/src/camel/camel-mime-parser.c
@@ -60,6 +60,15 @@ gint inend_id = -1,
 #define _header_scan_state _CamelMimeParserPrivate
 #define _PRIVATE(obj) (((CamelMimeParser *)(obj))->priv)
 
+/* a raw rfc822 header */
+/* the value MUST be US-ASCII */
+typedef struct _camel_header_raw {
+       struct _camel_header_raw *next;
+       gchar *name;
+       gchar *value;
+       gint offset;            /* in file, if known */
+} CamelHeaderRaw;
+
 struct _header_scan_state {
 
     /* global state */
@@ -116,7 +125,7 @@ struct _header_scan_stack {
 #ifdef MEMPOOL
        CamelMemPool *pool;     /* memory pool to keep track of headers/etc at this level */
 #endif
-       struct _camel_header_raw *headers;      /* headers for this part */
+       CamelHeaderRaw *headers;        /* headers for this part */
 
        CamelContentType *content_type;
 
@@ -154,8 +163,13 @@ static goffset folder_tell (struct _header_scan_state *s);
 static gint folder_read (struct _header_scan_state *s);
 static void folder_push_part (struct _header_scan_state *s, struct _header_scan_stack *h);
 
+static const gchar * header_raw_find (CamelHeaderRaw **list, const gchar *name, gint *offset);
+
 #ifdef MEMPOOL
 static void header_append_mempool (struct _header_scan_state *s, struct _header_scan_stack *h, gchar 
*header, gint offset);
+#else
+static void header_raw_free (CamelHeaderRaw *l);
+static void header_raw_clear (CamelHeaderRaw *l);
 #endif
 
 #if d(!)0
@@ -317,7 +331,7 @@ camel_mime_parser_header (CamelMimeParser *m,
        struct _header_scan_state *s = _PRIVATE (m);
 
        if (s->parts && s->parts->headers)
-               return camel_header_raw_find (&s->parts->headers, name, offset);
+               return header_raw_find (&s->parts->headers, name, offset);
 
        return NULL;
 }
@@ -330,18 +344,26 @@ camel_mime_parser_header (CamelMimeParser *m,
  * current state of the parser.  These headers are valid
  * until the next call to parser_step(), or parser_drop_step().
  *
- * Returns: (transfer none): The raw headers, or NULL if there are no headers
- * defined for the current part or state.  These are READ ONLY.
+ * Returns: (transfer full): The headers, or %NULL, if there are no headers
+ * defined for the current part or state. Free it with camel_name_value_array_free().
  *
- * Since: 2.22
+ * Since: 3.24
  **/
-struct _camel_header_raw *
-camel_mime_parser_headers_raw (CamelMimeParser *m)
+CamelNameValueArray *
+camel_mime_parser_dup_headers (CamelMimeParser *m)
 {
        struct _header_scan_state *s = _PRIVATE (m);
 
-       if (s->parts)
-               return s->parts->headers;
+       if (s->parts) {
+               CamelHeaderRaw *header = s->parts->headers;
+               CamelNameValueArray *header_copy = camel_name_value_array_new ();
+               while (header) {
+                       camel_name_value_array_append (header_copy, header->name, header->value);
+                       header = header->next;
+               }
+
+               return header_copy;
+       }
        return NULL;
 }
 
@@ -1180,7 +1202,7 @@ header_append_mempool (struct _header_scan_state *s,
                        gchar *header,
                        gint offset)
 {
-       struct _camel_header_raw *l, *n;
+       CamelHeaderRaw *l, *n;
        gchar *content;
 
        content = strchr (header, ':');
@@ -1203,7 +1225,7 @@ header_append_mempool (struct _header_scan_state *s,
 
                n->offset = offset;
 
-               l = (struct _camel_header_raw *) &h->headers;
+               l = (CamelHeaderRaw *) &h->headers;
                while (l->next) {
                        l = l->next;
                }
@@ -1688,7 +1710,7 @@ tail_recurse:
                /* FIXME: should this check for MIME-Version: 1.0 as well? */
 
                type = CAMEL_MIME_PARSER_STATE_HEADER;
-               if ((content = camel_header_raw_find (&h->headers, "Content-Type", NULL))
+               if ((content = header_raw_find (&h->headers, "Content-Type", NULL))
                     && (ct = camel_content_type_decode (content))) {
                        if (!g_ascii_strcasecmp (ct->type, "multipart")) {
                                if (!camel_content_type_is (ct, "multipart", "signed")
@@ -1892,6 +1914,60 @@ folder_scan_drop_step (struct _header_scan_state *s)
        }
 }
 
+static CamelHeaderRaw *
+header_raw_find_node (CamelHeaderRaw **list,
+                      const gchar *name)
+{
+       CamelHeaderRaw *l;
+
+       l = *list;
+       while (l) {
+               if (!g_ascii_strcasecmp (l->name, name))
+                       break;
+               l = l->next;
+       }
+       return l;
+}
+
+static const gchar *
+header_raw_find (CamelHeaderRaw **list,
+                const gchar *name,
+                gint *offset)
+{
+       CamelHeaderRaw *l;
+
+       l = header_raw_find_node (list, name);
+       if (l) {
+               if (offset)
+                       *offset = l->offset;
+               return l->value;
+       } else
+               return NULL;
+}
+
+#ifndef MEMPOOL
+static void
+header_raw_free (CamelHeaderRaw *l)
+{
+       g_free (l->name);
+       g_free (l->value);
+       g_free (l);
+}
+
+static void
+header_raw_clear (CamelHeaderRaw **list)
+{
+       CamelHeaderRaw *l, *n;
+       l = *list;
+       while (l) {
+               n = l->next;
+               header_raw_free (l);
+               l = n;
+       }
+       *list = NULL;
+}
+#endif
+
 #ifdef STANDALONE
 gint main (gint argc, gchar **argv)
 {
@@ -1948,7 +2024,7 @@ gint main (gint argc, gchar **argv)
                                        charset = NULL;
                                }
 
-                               encoding = camel_header_raw_find (&s->parts->headers, 
"Content-transfer-encoding", 0);
+                               encoding = header_raw_find (&s->parts->headers, "Content-transfer-encoding", 
NULL);
                                printf ("encoding = '%s'\n", encoding);
                                if (encoding && !g_ascii_strncasecmp (encoding, " base64", 7)) {
                                        printf ("adding base64 filter\n");
diff --git a/src/camel/camel-mime-parser.h b/src/camel/camel-mime-parser.h
index ce5c098..17cbaaf 100644
--- a/src/camel/camel-mime-parser.h
+++ b/src/camel/camel-mime-parser.h
@@ -27,6 +27,7 @@
 #include <camel/camel-mime-utils.h>
 #include <camel/camel-mime-filter.h>
 #include <camel/camel-stream.h>
+#include <camel/camel-name-value-array.h>
 
 /* Stardard GObject macros */
 #define CAMEL_TYPE_MIME_PARSER \
@@ -89,6 +90,9 @@ struct _CamelMimeParserClass {
        void (*message) (CamelMimeParser *parser, gpointer headers);
        void (*part) (CamelMimeParser *parser);
        void (*content) (CamelMimeParser *parser);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_mime_parser_get_type (void);
@@ -128,8 +132,8 @@ CamelContentType *camel_mime_parser_content_type (CamelMimeParser *parser);
 /* get/change raw header by name */
 const gchar *camel_mime_parser_header (CamelMimeParser *m, const gchar *name, gint *offset);
 
-/* get all raw headers. READ ONLY! */
-struct _camel_header_raw *camel_mime_parser_headers_raw (CamelMimeParser *m);
+/* get all raw headers */
+CamelNameValueArray *camel_mime_parser_dup_headers (CamelMimeParser *m);
 
 /* get multipart pre/postface */
 const gchar *camel_mime_parser_preface (CamelMimeParser *m);
diff --git a/src/camel/camel-mime-part-utils.c b/src/camel/camel-mime-part-utils.c
index 9fe0f9e..77ab61b 100644
--- a/src/camel/camel-mime-part-utils.c
+++ b/src/camel/camel-mime-part-utils.c
@@ -30,6 +30,7 @@
 
 #include "camel-charset-map.h"
 #include "camel-html-parser.h"
+#include "camel-iconv.h"
 #include "camel-mime-filter-basic.h"
 #include "camel-mime-filter-charset.h"
 #include "camel-mime-filter-crlf.h"
@@ -137,7 +138,7 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw,
 
        if (content) {
                if (encoding)
-                       content->encoding = camel_transfer_encoding_from_string (encoding);
+                       camel_data_wrapper_set_encoding (content, camel_transfer_encoding_from_string 
(encoding));
 
                /* would you believe you have to set this BEFORE you set the content object???  oh my god 
!!!! */
                camel_data_wrapper_set_mime_type_field (content, camel_mime_part_get_content_type (dw));
@@ -150,91 +151,188 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw,
        return success;
 }
 
+G_DEFINE_BOXED_TYPE (CamelMessageContentInfo,
+               camel_message_content_info,
+               camel_message_content_info_copy,
+               camel_message_content_info_free)
+
 /**
- * camel_mime_message_build_preview:
+ * camel_message_content_info_new:
  *
- * <note>
- *   <para>
- *     This function blocks like crazy.
- *   </para>
- * </note>
+ * Allocate a new #CamelMessageContentInfo.
  *
- * Since: 2.28
+ * Returns: (transfer full): a newly allocated #CamelMessageContentInfo
  **/
-gboolean
-camel_mime_message_build_preview (CamelMimePart *msg,
-                                  CamelMessageInfo *info)
+CamelMessageContentInfo *
+camel_message_content_info_new (void)
 {
-       CamelDataWrapper *dw;
-       gboolean got_plain = FALSE;
+       return g_slice_alloc0 (sizeof (CamelMessageContentInfo));
+}
+
+/**
+ * camel_message_content_info_copy:
+ * @src: (nullable): a source #CamelMessageContentInfo to copy
+ *
+ * Returns: a copy of @src, or %NULL, if @src was %NULL
+ *
+ * Since: 3.24
+ **/
+CamelMessageContentInfo *
+camel_message_content_info_copy (const CamelMessageContentInfo *src)
+{
+       CamelMessageContentInfo *res;
+
+       if (!src)
+               return NULL;
+
+       res = camel_message_content_info_new ();
+
+       if (src->type) {
+               gchar *content_type;
+
+               content_type = camel_content_type_format (src->type);
+               res->type = camel_content_type_decode (content_type);
+
+               g_free (content_type);
+       }
 
-       dw = camel_medium_get_content ((CamelMedium *) msg);
-       if (camel_content_type_is (dw->mime_type, "multipart", "*")) {
-               gint i, nparts;
-               CamelMultipart *mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) msg);
+       res->id = g_strdup (src->id);
+       res->description = g_strdup (src->description);
+       res->encoding = g_strdup (src->encoding);
+       res->size = src->size;
 
-               g_warn_if_fail (CAMEL_IS_MULTIPART (mp));
+       res->next = camel_message_content_info_copy (src->next);
+       res->childs = camel_message_content_info_copy (src->childs);
 
-               nparts = camel_multipart_get_number (mp);
-               for (i = 0; i < nparts && !got_plain; i++) {
-                       CamelMimePart *part = camel_multipart_get_part (mp, i);
-                       got_plain = camel_mime_message_build_preview (part, info);
+       if (res->childs) {
+               CamelMessageContentInfo *child;
+
+               for (child = res->childs; child; child = child->next) {
+                       child->parent = res;
                }
+       }
+
+       return res;
+}
+
+/**
+ * camel_message_content_info_free:
+ * @ci: a #CamelMessageContentInfo
+ *
+ * Recursively frees the content info @ci, and all associated memory.
+ **/
+void
+camel_message_content_info_free (CamelMessageContentInfo *ci)
+{
+       CamelMessageContentInfo *pw, *pn;
+
+       pw = ci->childs;
+
+       camel_content_type_unref (ci->type);
+       g_free (ci->id);
+       g_free (ci->description);
+       g_free (ci->encoding);
+       g_slice_free1 (sizeof (CamelMessageContentInfo), ci);
+
+       while (pw) {
+               pn = pw->next;
+               camel_message_content_info_free (pw);
+               pw = pn;
+       }
+}
 
-       } else if (camel_content_type_is (dw->mime_type, "text", "*") &&
-               /*    !camel_content_type_is (dw->mime_type, "text", "html") && */
-                   !camel_content_type_is (dw->mime_type, "text", "calendar")) {
-               CamelStream *mstream, *bstream;
-
-               /* FIXME Pass a GCancellable and GError here. */
-               mstream = camel_stream_mem_new ();
-               if (camel_data_wrapper_decode_to_stream_sync (dw, mstream, NULL, NULL) > 0) {
-                       gchar *line = NULL;
-                       GString *str = g_string_new (NULL);
-
-                       g_seekable_seek (
-                               G_SEEKABLE (mstream), 0,
-                               G_SEEK_SET, NULL, NULL);
-
-                       bstream = camel_stream_buffer_new (mstream, CAMEL_STREAM_BUFFER_READ | 
CAMEL_STREAM_BUFFER_BUFFER);
-
-                       /* We should fetch just 200 unquoted lines. */
-                       while ((line = camel_stream_buffer_read_line ((CamelStreamBuffer *) bstream, NULL, 
NULL)) && str->len < 200) {
-                               gchar *tmp = line;
-
-                               if (*line == '>' || strstr (line, "wrote:")) {
-                                       g_free (tmp);
-                                       continue;
-                               }
-                               if (g_str_has_prefix (line, "--")) {
-                                       g_free (tmp);
-                                       line = NULL;
-                                       break;
-                               }
-                               while (*line && ((*line == ' ') || *line == '\t'))
-                                       line++;
-                               if (*line == '\0' || *line == '\n') {
-                                       g_free (tmp);
-                                       continue;
-                               }
-
-                               g_string_append (str, " ");
-                               g_string_append (str, line);
-                               g_free (tmp);
-                               line = NULL;
-                       }
-                       if (str->len > 100) {
-                               g_string_insert (str, 100, "\n");
-                       }
-                       /* We don't mark dirty, as we don't store these */
-                       ((CamelMessageInfoBase *) info)->preview = camel_utf8_make_valid (str->str);
-                       g_string_free (str, TRUE);
-
-                       g_object_unref (bstream);
+CamelMessageContentInfo *
+camel_message_content_info_new_from_parser (CamelMimeParser *mp)
+{
+       CamelMessageContentInfo *ci = NULL;
+       CamelNameValueArray *headers = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_MIME_PARSER (mp), NULL);
+
+       switch (camel_mime_parser_state (mp)) {
+       case CAMEL_MIME_PARSER_STATE_HEADER:
+       case CAMEL_MIME_PARSER_STATE_MESSAGE:
+       case CAMEL_MIME_PARSER_STATE_MULTIPART:
+               headers = camel_mime_parser_dup_headers (mp);
+               ci = camel_message_content_info_new_from_headers (headers);
+               camel_name_value_array_free (headers);
+               if (ci) {
+                       if (ci->type)
+                               camel_content_type_unref (ci->type);
+                       ci->type = camel_mime_parser_content_type (mp);
+                       camel_content_type_ref (ci->type);
                }
-               g_object_unref (mstream);
-               return TRUE;
+               break;
+       default:
+               g_error ("Invalid parser state");
        }
 
-       return got_plain;
+       return ci;
+}
+
+CamelMessageContentInfo *
+camel_message_content_info_new_from_message (CamelMimePart *mp)
+{
+       CamelMessageContentInfo *ci = NULL;
+       const CamelNameValueArray *headers = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_MIME_PART (mp), NULL);
+
+       headers = camel_medium_get_headers (CAMEL_MEDIUM (mp));
+       ci = camel_message_content_info_new_from_headers (headers);
+
+       return ci;
+}
+
+CamelMessageContentInfo *
+camel_message_content_info_new_from_headers (const CamelNameValueArray *headers)
+{
+       CamelMessageContentInfo *ci;
+       const gchar *charset;
+
+       ci = camel_message_content_info_new ();
+
+       charset = camel_iconv_locale_charset ();
+       ci->id = camel_header_msgid_decode (camel_name_value_array_get_named (headers, 
CAMEL_COMPARE_CASE_INSENSITIVE, "Content-ID"));
+       ci->description = camel_header_decode_string (camel_name_value_array_get_named (headers, 
CAMEL_COMPARE_CASE_INSENSITIVE, "Content-Description"), charset);
+       ci->encoding = camel_content_transfer_encoding_decode (camel_name_value_array_get_named (headers, 
CAMEL_COMPARE_CASE_INSENSITIVE, "Content-Transfer-Encoding"));
+       ci->type = camel_content_type_decode (camel_name_value_array_get_named (headers, 
CAMEL_COMPARE_CASE_INSENSITIVE, "Content-Type"));
+
+       return ci;
+}
+
+void
+camel_message_content_info_dump (CamelMessageContentInfo *ci,
+                                gint depth)
+{
+       gchar *p;
+
+       p = alloca (depth * 4 + 1);
+       memset (p, ' ', depth * 4);
+       p[depth * 4] = 0;
+
+       if (ci == NULL) {
+               printf ("%s<empty>\n", p);
+               return;
+       }
+
+       if (ci->type)
+               printf (
+                       "%scontent-type: %s/%s\n",
+                       p, ci->type->type ? ci->type->type : "(null)",
+                       ci->type->subtype ? ci->type->subtype : "(null)");
+       else
+               printf ("%scontent-type: <unset>\n", p);
+       printf (
+               "%scontent-transfer-encoding: %s\n",
+               p, ci->encoding ? ci->encoding : "(null)");
+       printf (
+               "%scontent-description: %s\n",
+               p, ci->description ? ci->description : "(null)");
+       printf ("%ssize: %lu\n", p, (gulong) ci->size);
+       ci = ci->childs;
+       while (ci) {
+               camel_message_content_info_dump (ci, depth + 1);
+               ci = ci->next;
+       }
 }
diff --git a/src/camel/camel-mime-part-utils.h b/src/camel/camel-mime-part-utils.h
index 916cc33..a31f2be 100644
--- a/src/camel/camel-mime-part-utils.h
+++ b/src/camel/camel-mime-part-utils.h
@@ -35,8 +35,43 @@ gboolean     camel_mime_part_construct_content_from_parser
                                                 CamelMimeParser *mp,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_mime_message_build_preview (CamelMimePart *mime_part,
-                                                CamelMessageInfo *info);
+
+typedef struct _CamelMessageContentInfo CamelMessageContentInfo;
+
+/* A tree of message content info structures
+ * describe the content structure of the message (if it has any) */
+struct _CamelMessageContentInfo {
+       CamelMessageContentInfo *next;
+
+       CamelMessageContentInfo *childs;
+       CamelMessageContentInfo *parent;
+
+       CamelContentType *type;
+       gchar *id;
+       gchar *description;
+       gchar *encoding;
+       guint32 size;
+};
+
+GType          camel_message_content_info_get_type
+                                               (void) G_GNUC_CONST;
+CamelMessageContentInfo *
+               camel_message_content_info_new  (void);
+CamelMessageContentInfo *
+               camel_message_content_info_copy (const CamelMessageContentInfo *src);
+void           camel_message_content_info_free (CamelMessageContentInfo *ci);
+CamelMessageContentInfo *
+               camel_message_content_info_new_from_headers
+                                               (const CamelNameValueArray *headers);
+CamelMessageContentInfo *
+               camel_message_content_info_new_from_parser
+                                               (CamelMimeParser *parser);
+CamelMessageContentInfo *
+               camel_message_content_info_new_from_message
+                                               (CamelMimePart *mime_part);
+/* debugging functions */
+void           camel_message_content_info_dump (CamelMessageContentInfo *ci,
+                                                gint depth);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-mime-part.c b/src/camel/camel-mime-part.c
index 70b842b..beabf46 100644
--- a/src/camel/camel-mime-part.c
+++ b/src/camel/camel-mime-part.c
@@ -59,6 +59,8 @@ struct _CamelMimePartPrivate {
        gchar *content_location;
        GList *content_languages;
        CamelTransferEncoding encoding;
+       /* mime headers */
+       CamelNameValueArray *headers;
 };
 
 struct _AsyncContext {
@@ -318,8 +320,8 @@ mime_part_process_header (CamelMedium *medium,
        switch (header_type) {
        case HEADER_DESCRIPTION: /* raw header->utf8 conversion */
                g_free (mime_part->priv->description);
-               if (((CamelDataWrapper *) mime_part)->mime_type) {
-                       charset = camel_content_type_param (((CamelDataWrapper *) mime_part)->mime_type, 
"charset");
+               if (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (mime_part))) {
+                       charset = camel_content_type_param (camel_data_wrapper_get_mime_type_field 
(CAMEL_DATA_WRAPPER (mime_part)), "charset");
                        charset = camel_iconv_charset_name (charset);
                } else
                        charset = NULL;
@@ -346,9 +348,7 @@ mime_part_process_header (CamelMedium *medium,
                mime_part->priv->content_location = camel_header_location_decode (value);
                break;
        case HEADER_CONTENT_TYPE:
-               if (((CamelDataWrapper *) mime_part)->mime_type)
-                       camel_content_type_unref (((CamelDataWrapper *) mime_part)->mime_type);
-               ((CamelDataWrapper *) mime_part)->mime_type = camel_content_type_decode (value);
+               camel_data_wrapper_take_mime_type_field (CAMEL_DATA_WRAPPER (mime_part), 
camel_content_type_decode (value));
                break;
        default:
                return FALSE;
@@ -452,8 +452,7 @@ mime_part_finalize (GObject *object)
 
        g_list_free_full (priv->content_languages, (GDestroyNotify) g_free);
        camel_content_disposition_unref (priv->disposition);
-
-       camel_header_raw_clear (&CAMEL_MIME_PART (object)->headers);
+       camel_name_value_array_free (priv->headers);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_mime_part_parent_class)->finalize (object);
@@ -462,7 +461,7 @@ mime_part_finalize (GObject *object)
 static void
 mime_part_add_header (CamelMedium *medium,
                       const gchar *name,
-                      gconstpointer value)
+                      const gchar *value)
 {
        CamelMimePart *part = CAMEL_MIME_PART (medium);
 
@@ -472,40 +471,42 @@ mime_part_add_header (CamelMedium *medium,
 
        /* If it was one of the headers we handled, it must be unique, set it instead of add */
        if (mime_part_process_header (medium, name, value))
-               camel_header_raw_replace (&part->headers, name, value, -1);
-       else
-               camel_header_raw_append (&part->headers, name, value, -1);
+               camel_name_value_array_remove_named (part->priv->headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
name, TRUE);
+
+       camel_name_value_array_append (part->priv->headers, name, value);
 }
 
 static void
 mime_part_set_header (CamelMedium *medium,
                       const gchar *name,
-                      gconstpointer value)
+                      const gchar *value)
 {
        CamelMimePart *part = CAMEL_MIME_PART (medium);
 
        mime_part_process_header (medium, name, value);
-       camel_header_raw_replace (&part->headers, name, value, -1);
+       camel_name_value_array_remove_named (part->priv->headers, CAMEL_COMPARE_CASE_INSENSITIVE, name, TRUE);
+
+       camel_name_value_array_append (part->priv->headers, name, value);
 }
 
 static void
 mime_part_remove_header (CamelMedium *medium,
                          const gchar *name)
 {
-       CamelMimePart *part = (CamelMimePart *) medium;
+       CamelMimePart *part = CAMEL_MIME_PART (medium);
 
        mime_part_process_header (medium, name, NULL);
-       camel_header_raw_remove (&part->headers, name);
+       camel_name_value_array_remove_named (part->priv->headers, CAMEL_COMPARE_CASE_INSENSITIVE, name, TRUE);
 }
 
-static gconstpointer
+static const gchar *
 mime_part_get_header (CamelMedium *medium,
                       const gchar *name)
 {
-       CamelMimePart *part = (CamelMimePart *) medium;
+       CamelMimePart *part = CAMEL_MIME_PART (medium);
        const gchar *value;
 
-       value = camel_header_raw_find (&part->headers, name, NULL);
+       value = camel_name_value_array_get_named (part->priv->headers, CAMEL_COMPARE_CASE_INSENSITIVE, name);
 
        /* Skip leading whitespace. */
        while (value != NULL && g_ascii_isspace (*value))
@@ -514,29 +515,20 @@ mime_part_get_header (CamelMedium *medium,
        return value;
 }
 
-static GArray *
-mime_part_get_headers (CamelMedium *medium)
+static CamelNameValueArray *
+mime_part_dup_headers (CamelMedium *medium)
 {
-       CamelMimePart *part = (CamelMimePart *) medium;
-       GArray *headers;
-       CamelMediumHeader header;
-       struct _camel_header_raw *h;
-
-       headers = g_array_new (FALSE, FALSE, sizeof (CamelMediumHeader));
-       for (h = part->headers; h; h = h->next) {
-               header.name = h->name;
-               header.value = h->value;
-               g_array_append_val (headers, header);
-       }
+       CamelMimePart *part = CAMEL_MIME_PART (medium);
 
-       return headers;
+       return camel_name_value_array_copy (part->priv->headers);
 }
 
-static void
-mime_part_free_headers (CamelMedium *medium,
-                        GArray *headers)
+static const CamelNameValueArray *
+mime_part_get_headers (CamelMedium *medium)
 {
-       g_array_free (headers, TRUE);
+       CamelMimePart *part = CAMEL_MIME_PART (medium);
+
+       return part->priv->headers;
 }
 
 static void
@@ -552,7 +544,7 @@ mime_part_set_content (CamelMedium *medium,
        medium_class->set_content (medium, content);
 
        content_type = camel_data_wrapper_get_mime_type_field (content);
-       if (mime_part->mime_type != content_type) {
+       if (camel_data_wrapper_get_mime_type_field (mime_part) != content_type) {
                gchar *txt;
 
                txt = camel_content_type_format (content_type);
@@ -574,45 +566,38 @@ mime_part_write_to_stream_sync (CamelDataWrapper *dw,
        gssize total = 0;
        gssize count;
        gint errnosav;
+       guint ii;
+       const gchar *header_name = NULL, *header_value = NULL;
 
        d (printf ("mime_part::write_to_stream\n"));
 
        /* FIXME: something needs to be done about this ... */
        /* TODO: content-languages header? */
 
-       if (mp->headers) {
-               struct _camel_header_raw *h = mp->headers;
-               gchar *val;
+       for (ii = 0; camel_name_value_array_get (mp->priv->headers, ii, &header_name, &header_value); ii++) {
                gssize (*writefn) (
                        gpointer stream,
                        const gchar *name,
                        const gchar *value,
                        GCancellable *cancellable,
                        GError **error);
-
-               /* fold/write the headers.   But dont fold headers that are already formatted
-                * (e.g. ones with parameter-lists, that we know about, and have created) */
-               while (h) {
-                       val = h->value;
-                       if (val == NULL) {
-                               g_warning ("h->value is NULL here for %s", h->name);
-                               count = 0;
-                       } else if ((writefn = g_hash_table_lookup (header_formatted_table, h->name)) == NULL) 
{
-                               val = camel_header_fold (val, strlen (h->name));
-                               count = write_header (
-                                       stream, h->name, val,
-                                       cancellable, error);
-                               g_free (val);
-                       } else {
-                               count = writefn (
-                                       stream, h->name, h->value,
-                                       cancellable, error);
-                       }
-                       if (count == -1)
-                               return -1;
-                       total += count;
-                       h = h->next;
+               if (header_value == NULL) {
+                       g_warning ("header_value is NULL here for %s", header_name);
+                       count = 0;
+               } else if ((writefn = g_hash_table_lookup (header_formatted_table, header_name)) == NULL) {
+                       gchar *val = camel_header_fold (header_value, strlen (header_name));
+                       count = write_header (
+                               stream, header_name, val,
+                               cancellable, error);
+                       g_free (val);
+               } else {
+                       count = writefn (
+                               stream, header_name, header_value,
+                               cancellable, error);
                }
+               if (count == -1)
+                       return -1;
+               total += count;
        }
 
        count = camel_stream_write (stream, "\n", 1, cancellable, error);
@@ -630,9 +615,9 @@ mime_part_write_to_stream_sync (CamelDataWrapper *dw,
                gboolean reencode = FALSE;
                const gchar *filename;
 
-               if (camel_content_type_is (dw->mime_type, "text", "*")) {
-                       content_charset = camel_content_type_param (content->mime_type, "charset");
-                       part_charset = camel_content_type_param (dw->mime_type, "charset");
+               if (camel_content_type_is (camel_data_wrapper_get_mime_type_field (dw), "text", "*")) {
+                       content_charset = camel_content_type_param (camel_data_wrapper_get_mime_type_field 
(content), "charset");
+                       part_charset = camel_content_type_param (camel_data_wrapper_get_mime_type_field (dw), 
"charset");
 
                        if (content_charset && part_charset) {
                                content_charset = camel_iconv_charset_name (content_charset);
@@ -640,7 +625,7 @@ mime_part_write_to_stream_sync (CamelDataWrapper *dw,
                        }
                }
 
-               if (mp->priv->encoding != content->encoding) {
+               if (mp->priv->encoding != camel_data_wrapper_get_encoding (content)) {
                        gchar *content;
 
                        switch (mp->priv->encoding) {
@@ -767,46 +752,39 @@ mime_part_write_to_output_stream_sync (CamelDataWrapper *dw,
        gssize total = 0;
        gssize result;
        gboolean success;
+       guint ii;
+       const gchar *header_name = NULL, *header_value = NULL;
 
        d (printf ("mime_part::write_to_stream\n"));
 
        /* FIXME: something needs to be done about this ... */
        /* TODO: content-languages header? */
 
-       if (mp->headers) {
-               struct _camel_header_raw *h = mp->headers;
-               gchar *val;
+       for (ii = 0; camel_name_value_array_get (mp->priv->headers, ii, &header_name, &header_value); ii++) {
                gssize (*writefn) (
                        gpointer stream,
                        const gchar *name,
                        const gchar *value,
                        GCancellable *cancellable,
                        GError **error);
-
-               /* fold/write the headers.   But dont fold headers that are already formatted
-                * (e.g. ones with parameter-lists, that we know about, and have created) */
-               while (h) {
-                       val = h->value;
-                       if (val == NULL) {
-                               g_warning ("h->value is NULL here for %s", h->name);
-                               bytes_written = 0;
-                               result = 0;
-                       } else if ((writefn = g_hash_table_lookup (header_formatted_table, h->name)) == NULL) 
{
-                               val = camel_header_fold (val, strlen (h->name));
-                               result = write_header (
-                                       output_stream, h->name, val,
-                                       cancellable, error);
-                               g_free (val);
-                       } else {
-                               result = writefn (
-                                       output_stream, h->name, h->value,
-                                       cancellable, error);
-                       }
-                       if (result == -1)
-                               return -1;
-                       total += result;
-                       h = h->next;
+               if (header_value == NULL) {
+                       g_warning ("header_value is NULL here for %s", header_name);
+                       bytes_written = 0;
+                       result = 0;
+               } else if ((writefn = g_hash_table_lookup (header_formatted_table, header_name)) == NULL) {
+                       gchar *val = camel_header_fold (header_value, strlen (header_name));
+                       result = write_header (
+                               output_stream, header_name, val,
+                               cancellable, error);
+                       g_free (val);
+               } else {
+                       result = writefn (
+                               output_stream, header_name, header_value,
+                               cancellable, error);
                }
+               if (result == -1)
+                       return -1;
+               total += result;
        }
 
        success = g_output_stream_write_all (
@@ -828,11 +806,11 @@ mime_part_write_to_output_stream_sync (CamelDataWrapper *dw,
                const gchar *filename;
 
                content_type_is_text =
-                       camel_content_type_is (dw->mime_type, "text", "*");
+                       camel_content_type_is (camel_data_wrapper_get_mime_type_field (dw), "text", "*");
 
                if (content_type_is_text) {
-                       content_charset = camel_content_type_param (content->mime_type, "charset");
-                       part_charset = camel_content_type_param (dw->mime_type, "charset");
+                       content_charset = camel_content_type_param (camel_data_wrapper_get_mime_type_field 
(content), "charset");
+                       part_charset = camel_content_type_param (camel_data_wrapper_get_mime_type_field (dw), 
"charset");
 
                        if (content_charset && part_charset) {
                                content_charset = camel_iconv_charset_name (content_charset);
@@ -840,7 +818,7 @@ mime_part_write_to_output_stream_sync (CamelDataWrapper *dw,
                        }
                }
 
-               if (mp->priv->encoding != content->encoding) {
+               if (mp->priv->encoding != camel_data_wrapper_get_encoding (content)) {
                        gchar *content;
 
                        switch (mp->priv->encoding) {
@@ -972,40 +950,40 @@ mime_part_construct_from_parser_sync (CamelMimePart *mime_part,
                                       GError **error)
 {
        CamelDataWrapper *dw = (CamelDataWrapper *) mime_part;
-       struct _camel_header_raw *headers;
+       CamelNameValueArray *headers;
        const gchar *content;
        gchar *buf;
        gsize len;
        gint err;
+       guint ii;
        gboolean success = TRUE;
+       const gchar *header_name = NULL, *header_value = NULL;
 
        switch (camel_mime_parser_step (parser, &buf, &len)) {
        case CAMEL_MIME_PARSER_STATE_MESSAGE:
                /* set the default type of a message always */
-               if (dw->mime_type)
-                       camel_content_type_unref (dw->mime_type);
-               dw->mime_type = camel_content_type_decode ("message/rfc822");
+               camel_data_wrapper_take_mime_type_field (dw, camel_content_type_decode ("message/rfc822"));
                /* coverity[fallthrough] */
 
        case CAMEL_MIME_PARSER_STATE_HEADER:
        case CAMEL_MIME_PARSER_STATE_MULTIPART:
                /* we have the headers, build them into 'us' */
-               headers = camel_mime_parser_headers_raw (parser);
+               headers = camel_mime_parser_dup_headers (parser);
 
                /* if content-type exists, process it first, set for fallback charset in headers */
-               content = camel_header_raw_find (&headers, "content-type", NULL);
+               content = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
"Content-Type");
                if (content)
-                       mime_part_process_header ((CamelMedium *) dw, "content-type", content);
+                       mime_part_process_header (CAMEL_MEDIUM (dw), "content-type", content);
 
-               while (headers) {
-                       if (g_ascii_strcasecmp (headers->name, "content-type") == 0
-                           && headers->value != content)
-                               camel_medium_add_header ((CamelMedium *) dw, "X-Invalid-Content-Type", 
headers->value);
+               for (ii = 0; camel_name_value_array_get (headers, ii, &header_name, &header_value); ii++) {
+                       if (g_ascii_strcasecmp (header_name, "content-type") == 0 && header_value != content)
+                               camel_medium_add_header (CAMEL_MEDIUM (dw), "X-Invalid-Content-Type", 
header_value);
                        else
-                               camel_medium_add_header ((CamelMedium *) dw, headers->name, headers->value);
-                       headers = headers->next;
+                               camel_medium_add_header (CAMEL_MEDIUM (dw), header_name, header_value);
                }
 
+               camel_name_value_array_free (headers);
+
                success = camel_mime_part_construct_content_from_parser (
                        mime_part, parser, cancellable, error);
                break;
@@ -1045,8 +1023,8 @@ camel_mime_part_class_init (CamelMimePartClass *class)
        medium_class->set_header = mime_part_set_header;
        medium_class->remove_header = mime_part_remove_header;
        medium_class->get_header = mime_part_get_header;
+       medium_class->dup_headers = mime_part_dup_headers;
        medium_class->get_headers = mime_part_get_headers;
-       medium_class->free_headers = mime_part_free_headers;
        medium_class->set_content = mime_part_set_content;
 
        data_wrapper_class = CAMEL_DATA_WRAPPER_CLASS (class);
@@ -1107,13 +1085,11 @@ camel_mime_part_init (CamelMimePart *mime_part)
 
        mime_part->priv = CAMEL_MIME_PART_GET_PRIVATE (mime_part);
        mime_part->priv->encoding = CAMEL_TRANSFER_ENCODING_DEFAULT;
+       mime_part->priv->headers = camel_name_value_array_new ();
 
        data_wrapper = CAMEL_DATA_WRAPPER (mime_part);
 
-       if (data_wrapper->mime_type != NULL)
-               camel_content_type_unref (data_wrapper->mime_type);
-
-       data_wrapper->mime_type = camel_content_type_new ("text", "plain");
+       camel_data_wrapper_take_mime_type_field (data_wrapper, camel_content_type_new ("text", "plain"));
 }
 
 /**
@@ -1538,8 +1514,7 @@ camel_mime_part_get_filename (CamelMimePart *mime_part)
                        return name;
        }
 
-       return camel_content_type_param (
-               ((CamelDataWrapper *) mime_part)->mime_type, "name");
+       return camel_content_type_param (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER 
(mime_part)), "name");
 }
 
 /**
@@ -1571,10 +1546,10 @@ camel_mime_part_set_filename (CamelMimePart *mime_part,
        g_free (str);
 
        dw = (CamelDataWrapper *) mime_part;
-       if (!dw->mime_type)
-               dw->mime_type = camel_content_type_new ("application", "octet-stream");
-       camel_content_type_set_param (dw->mime_type, "name", filename);
-       str = camel_content_type_format (dw->mime_type);
+       if (!camel_data_wrapper_get_mime_type_field (dw))
+               camel_data_wrapper_take_mime_type_field (dw, camel_content_type_new ("application", 
"octet-stream"));
+       camel_content_type_set_param (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (dw)), 
"name", filename);
+       str = camel_content_type_format (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (dw)));
        camel_medium_set_header (medium, "Content-Type", str);
        g_free (str);
 }
diff --git a/src/camel/camel-mime-part.h b/src/camel/camel-mime-part.h
index bcacdcb..b21a486 100644
--- a/src/camel/camel-mime-part.h
+++ b/src/camel/camel-mime-part.h
@@ -29,6 +29,7 @@
 #include <camel/camel-medium.h>
 #include <camel/camel-mime-utils.h>
 #include <camel/camel-mime-parser.h>
+#include <camel/camel-name-value-array.h>
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_MIME_PART \
@@ -58,8 +59,6 @@ typedef struct _CamelMimePartPrivate CamelMimePartPrivate;
 struct _CamelMimePart {
        CamelMedium parent;
        CamelMimePartPrivate *priv;
-
-       struct _camel_header_raw *headers; /* mime headers */
 };
 
 struct _CamelMimePartClass {
@@ -72,8 +71,8 @@ struct _CamelMimePartClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots. */
-       gpointer reserved[2];
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mime_part_get_type        (void);
diff --git a/src/camel/camel-mime-utils.c b/src/camel/camel-mime-utils.c
index 7c33fb8..c49d9a1 100644
--- a/src/camel/camel-mime-utils.c
+++ b/src/camel/camel-mime-utils.c
@@ -41,6 +41,7 @@
 #include "camel-iconv.h"
 #include "camel-mime-utils.h"
 #include "camel-net-utils.h"
+#include "camel-string-utils.h"
 #ifdef G_OS_WIN32
 #include <winsock2.h>
 #include <ws2tcpip.h>
@@ -4464,191 +4465,6 @@ camel_header_location_decode (const gchar *in)
        return res;
 }
 
-/* extra rfc checks */
-#define CHECKS
-
-#ifdef CHECKS
-static void
-check_header (struct _camel_header_raw *header)
-{
-       guchar *cp;
-
-       cp = (guchar *) header->value;
-       while (cp && *cp) {
-               if (!isascii (*cp)) {
-                       w (g_warning ("Appending header violates rfc: %s: %s", header->name, header->value));
-                       return;
-               }
-               cp++;
-       }
-}
-#endif
-
-void
-camel_header_raw_append_parse (struct _camel_header_raw **list,
-                               const gchar *header,
-                               gint offset)
-{
-       register const gchar *in;
-       gsize fieldlen;
-       gchar *name;
-
-       in = header;
-       while (camel_mime_is_fieldname (*in) || *in == ':')
-               in++;
-       fieldlen = in - header - 1;
-       while (camel_mime_is_lwsp (*in))
-               in++;
-       if (fieldlen == 0 || header[fieldlen] != ':') {
-               printf ("Invalid header line: '%s'\n", header);
-               return;
-       }
-       name = g_alloca (fieldlen + 1);
-       memcpy (name, header, fieldlen);
-       name[fieldlen] = 0;
-
-       camel_header_raw_append (list, name, in, offset);
-}
-
-void
-camel_header_raw_append (struct _camel_header_raw **list,
-                         const gchar *name,
-                         const gchar *value,
-                         gint offset)
-{
-       struct _camel_header_raw *l, *n;
-
-       d (printf ("Header: %s: %s\n", name, value));
-
-       n = g_malloc (sizeof (*n));
-       n->next = NULL;
-       n->name = g_strdup (name);
-       n->value = g_strdup (value);
-       n->offset = offset;
-#ifdef CHECKS
-       check_header (n);
-#endif
-       l = (struct _camel_header_raw *) list;
-       while (l->next) {
-               l = l->next;
-       }
-       l->next = n;
-
-       /* debug */
-#if 0
-       if (!g_ascii_strcasecmp (name, "To")) {
-               printf ("- Decoding To\n");
-               camel_header_to_decode (value);
-       } else if (!g_ascii_strcasecmp (name, "Content-type")) {
-               printf ("- Decoding content-type\n");
-               camel_content_type_dump (camel_content_type_decode (value));
-       } else if (!g_ascii_strcasecmp (name, "MIME-Version")) {
-               printf ("- Decoding mime version\n");
-               camel_header_mime_decode (value);
-       }
-#endif
-}
-
-static struct _camel_header_raw *
-header_raw_find_node (struct _camel_header_raw **list,
-                      const gchar *name)
-{
-       struct _camel_header_raw *l;
-
-       l = *list;
-       while (l) {
-               if (!g_ascii_strcasecmp (l->name, name))
-                       break;
-               l = l->next;
-       }
-       return l;
-}
-
-const gchar *
-camel_header_raw_find (struct _camel_header_raw **list,
-                       const gchar *name,
-                       gint *offset)
-{
-       struct _camel_header_raw *l;
-
-       l = header_raw_find_node (list, name);
-       if (l) {
-               if (offset)
-                       *offset = l->offset;
-               return l->value;
-       } else
-               return NULL;
-}
-
-const gchar *
-camel_header_raw_find_next (struct _camel_header_raw **list,
-                            const gchar *name,
-                            gint *offset,
-                            const gchar *last)
-{
-       struct _camel_header_raw *l;
-
-       if (last == NULL || name == NULL)
-               return NULL;
-
-       l = *list;
-       while (l && l->value != last)
-               l = l->next;
-       return camel_header_raw_find (&l, name, offset);
-}
-
-static void
-header_raw_free (struct _camel_header_raw *l)
-{
-       g_free (l->name);
-       g_free (l->value);
-       g_free (l);
-}
-
-void
-camel_header_raw_remove (struct _camel_header_raw **list,
-                         const gchar *name)
-{
-       struct _camel_header_raw *l, *p;
-
-       /* the next pointer is at the head of the structure, so this is safe */
-       p = (struct _camel_header_raw *) list;
-       l = *list;
-       while (l) {
-               if (!g_ascii_strcasecmp (l->name, name)) {
-                       p->next = l->next;
-                       header_raw_free (l);
-                       l = p->next;
-               } else {
-                       p = l;
-                       l = l->next;
-               }
-       }
-}
-
-void
-camel_header_raw_replace (struct _camel_header_raw **list,
-                          const gchar *name,
-                          const gchar *value,
-                          gint offset)
-{
-       camel_header_raw_remove (list, name);
-       camel_header_raw_append (list, name, value, offset);
-}
-
-void
-camel_header_raw_clear (struct _camel_header_raw **list)
-{
-       struct _camel_header_raw *l, *n;
-       l = *list;
-       while (l) {
-               n = l->next;
-               header_raw_free (l);
-               l = n;
-       }
-       *list = NULL;
-}
-
 /**
  * camel_header_msgid_generate:
  * @domain: domain to use (like "example.com") for the ID suffix; can be NULL
@@ -4775,8 +4591,17 @@ mailing_list_init (gpointer param)
        return NULL;
 }
 
+/**
+ * camel_headers_dup_mailing_list:
+ * @headers: a #CamelNameValueArray with headers
+ *
+ * Searches for a mailing list information among known headers and returns
+ * a newly allocated string with its value.
+ *
+ * Returns: (nullable) (transfer full): The mailing list header, or %NULL, if none is found
+ **/
 gchar *
-camel_header_raw_check_mailing_list (struct _camel_header_raw **list)
+camel_headers_dup_mailing_list (const CamelNameValueArray *headers)
 {
        static GOnce once = G_ONCE_INIT;
        const gchar *v;
@@ -4786,7 +4611,7 @@ camel_header_raw_check_mailing_list (struct _camel_header_raw **list)
        g_once (&once, mailing_list_init, NULL);
 
        for (i = 0; i < G_N_ELEMENTS (mail_list_magic); i++) {
-               v = camel_header_raw_find (list, mail_list_magic[i].name, NULL);
+               v = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
mail_list_magic[i].name);
                for (j = 0; j < 3; j++) {
                        match[j].rm_so = -1;
                        match[j].rm_eo = -1;
@@ -4850,69 +4675,77 @@ camel_header_address_new_group (const gchar *name)
 }
 
 CamelHeaderAddress *
-camel_header_address_ref (CamelHeaderAddress *h)
+camel_header_address_ref (CamelHeaderAddress *addrlist)
 {
-       if (h)
-               h->refcount++;
+       if (addrlist)
+               addrlist->refcount++;
 
-       return h;
+       return addrlist;
 }
 
 void
-camel_header_address_unref (CamelHeaderAddress *h)
+camel_header_address_unref (CamelHeaderAddress *addrlist)
 {
-       if (h) {
-               if (h->refcount <= 1) {
-                       if (h->type == CAMEL_HEADER_ADDRESS_GROUP) {
-                               camel_header_address_list_clear (&h->v.members);
-                       } else if (h->type == CAMEL_HEADER_ADDRESS_NAME) {
-                               g_free (h->v.addr);
+       if (addrlist) {
+               if (addrlist->refcount <= 1) {
+                       if (addrlist->type == CAMEL_HEADER_ADDRESS_GROUP) {
+                               camel_header_address_list_clear (&addrlist->v.members);
+                       } else if (addrlist->type == CAMEL_HEADER_ADDRESS_NAME) {
+                               g_free (addrlist->v.addr);
                        }
-                       g_free (h->name);
-                       g_free (h);
+                       g_free (addrlist->name);
+                       g_free (addrlist);
                } else {
-                       h->refcount--;
+                       addrlist->refcount--;
                }
        }
 }
 
 void
-camel_header_address_set_name (CamelHeaderAddress *h,
+camel_header_address_set_name (CamelHeaderAddress *addrlist,
                                const gchar *name)
 {
-       if (h) {
-               g_free (h->name);
-               h->name = g_strdup (name);
+       if (addrlist) {
+               g_free (addrlist->name);
+               addrlist->name = g_strdup (name);
        }
 }
 
 void
-camel_header_address_set_addr (CamelHeaderAddress *h,
+camel_header_address_set_addr (CamelHeaderAddress *addrlist,
                                const gchar *addr)
 {
-       if (h) {
-               if (h->type == CAMEL_HEADER_ADDRESS_NAME
-                   || h->type == CAMEL_HEADER_ADDRESS_NONE) {
-                       h->type = CAMEL_HEADER_ADDRESS_NAME;
-                       g_free (h->v.addr);
-                       h->v.addr = g_strdup (addr);
+       if (addrlist) {
+               if (addrlist->type == CAMEL_HEADER_ADDRESS_NAME
+                   || addrlist->type == CAMEL_HEADER_ADDRESS_NONE) {
+                       addrlist->type = CAMEL_HEADER_ADDRESS_NAME;
+                       g_free (addrlist->v.addr);
+                       addrlist->v.addr = g_strdup (addr);
                } else {
                        g_warning ("Trying to set the address on a group");
                }
        }
 }
 
+/**
+ * camel_header_address_set_members:
+ * @addrlist: a #CamelHeaderAddress object
+ * @group: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderAddress
+ *
+ * TODO: Document me.
+ *
+ **/
 void
-camel_header_address_set_members (CamelHeaderAddress *h,
+camel_header_address_set_members (CamelHeaderAddress *addrlist,
                                   CamelHeaderAddress *group)
 {
-       if (h) {
-               if (h->type == CAMEL_HEADER_ADDRESS_GROUP
-                   || h->type == CAMEL_HEADER_ADDRESS_NONE) {
-                       h->type = CAMEL_HEADER_ADDRESS_GROUP;
-                       camel_header_address_list_clear (&h->v.members);
+       if (addrlist) {
+               if (addrlist->type == CAMEL_HEADER_ADDRESS_GROUP
+                   || addrlist->type == CAMEL_HEADER_ADDRESS_NONE) {
+                       addrlist->type = CAMEL_HEADER_ADDRESS_GROUP;
+                       camel_header_address_list_clear (&addrlist->v.members);
                        /* should this ref them? */
-                       h->v.members = group;
+                       addrlist->v.members = group;
                } else {
                        g_warning ("Trying to set the members on a name, not group");
                }
@@ -4920,52 +4753,75 @@ camel_header_address_set_members (CamelHeaderAddress *h,
 }
 
 void
-camel_header_address_add_member (CamelHeaderAddress *h,
+camel_header_address_add_member (CamelHeaderAddress *addrlist,
                                  CamelHeaderAddress *member)
 {
-       if (h) {
-               if (h->type == CAMEL_HEADER_ADDRESS_GROUP
-                   || h->type == CAMEL_HEADER_ADDRESS_NONE) {
-                       h->type = CAMEL_HEADER_ADDRESS_GROUP;
-                       camel_header_address_list_append (&h->v.members, member);
+       if (addrlist) {
+               if (addrlist->type == CAMEL_HEADER_ADDRESS_GROUP
+                   || addrlist->type == CAMEL_HEADER_ADDRESS_NONE) {
+                       addrlist->type = CAMEL_HEADER_ADDRESS_GROUP;
+                       camel_header_address_list_append (&addrlist->v.members, member);
                }
        }
 }
 
+/**
+ * camel_header_address_list_append_list:
+ * @addrlistp: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderAddress objects
+ * @addrs: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderAddress to add
+ *
+ * TODO: Document me.
+ *
+ **/
 void
-camel_header_address_list_append_list (CamelHeaderAddress **l,
-                                       CamelHeaderAddress **h)
+camel_header_address_list_append_list (CamelHeaderAddress **addrlistp,
+                                       CamelHeaderAddress **addrs)
 {
-       if (l) {
-               CamelHeaderAddress *n = (CamelHeaderAddress *) l;
+       if (addrlistp) {
+               CamelHeaderAddress *n = (CamelHeaderAddress *) addrlistp;
 
                while (n->next)
                        n = n->next;
-               n->next = *h;
+               n->next = *addrs;
        }
 }
 
+/**
+ * camel_header_address_list_append:
+ * @addrlistp: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderAddress objects
+ * @addr: the #CamelHeaderAddress to add
+ *
+ * TODO: Document me.
+ *
+ **/
 void
-camel_header_address_list_append (CamelHeaderAddress **l,
-                                  CamelHeaderAddress *h)
+camel_header_address_list_append (CamelHeaderAddress **addrlistp,
+                                  CamelHeaderAddress *addr)
 {
-       if (h) {
-               camel_header_address_list_append_list (l, &h);
-               h->next = NULL;
+       if (addr) {
+               camel_header_address_list_append_list (addrlistp, &addr);
+               addr->next = NULL;
        }
 }
 
+/**
+ * camel_header_address_list_clear:
+ * @addrlistp: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderAddress objects
+ *
+ * TODO: Document me.
+ *
+ **/
 void
-camel_header_address_list_clear (CamelHeaderAddress **l)
+camel_header_address_list_clear (CamelHeaderAddress **addrlistp)
 {
        CamelHeaderAddress *a, *n;
-       a = *l;
+       a = *addrlistp;
        while (a) {
                n = a->next;
                camel_header_address_unref (a);
                a = n;
        }
-       *l = NULL;
+       *addrlistp = NULL;
 }
 
 /* if encode is true, then the result is suitable for mailing, otherwise
@@ -5012,35 +4868,49 @@ header_address_list_encode_append (GString *out,
        }
 }
 
+/**
+ * camel_header_address_list_encode:
+ * @addrlist: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderAddress objects
+ *
+ * TODO: Document me.
+ *
+ **/
 gchar *
-camel_header_address_list_encode (CamelHeaderAddress *a)
+camel_header_address_list_encode (CamelHeaderAddress *addrlist)
 {
        GString *out;
        gchar *ret;
 
-       if (a == NULL)
+       if (!addrlist)
                return NULL;
 
        out = g_string_new ("");
-       header_address_list_encode_append (out, TRUE, a);
+       header_address_list_encode_append (out, TRUE, addrlist);
        ret = out->str;
        g_string_free (out, FALSE);
 
        return ret;
 }
 
+/**
+ * camel_header_address_list_format:
+ * @addrlist: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderAddress objects
+ *
+ * TODO: Document me.
+ *
+ **/
 gchar *
-camel_header_address_list_format (CamelHeaderAddress *a)
+camel_header_address_list_format (CamelHeaderAddress *addrlist)
 {
        GString *out;
        gchar *ret;
 
-       if (a == NULL)
+       if (!addrlist)
                return NULL;
 
        out = g_string_new ("");
 
-       header_address_list_encode_append (out, FALSE, a);
+       header_address_list_encode_append (out, FALSE, addrlist);
        ret = out->str;
        g_string_free (out, FALSE);
 
diff --git a/src/camel/camel-mime-utils.h b/src/camel/camel-mime-utils.h
index 2a51044..0e42793 100644
--- a/src/camel/camel-mime-utils.h
+++ b/src/camel/camel-mime-utils.h
@@ -29,6 +29,10 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <camel/camel-enums.h>
+#include <camel/camel-utils.h>
+#include <camel/camel-name-value-array.h>
+
+G_BEGIN_DECLS
 
 /* maximum recommended size of a line from camel_header_fold() */
 #define CAMEL_FOLD_SIZE (77)
@@ -43,8 +47,6 @@ typedef enum {
 
 #define CAMEL_UUDECODE_STATE_MASK   (CAMEL_UUDECODE_STATE_BEGIN | CAMEL_UUDECODE_STATE_END)
 
-G_BEGIN_DECLS
-
 typedef struct _camel_header_param {
        struct _camel_header_param *next;
        gchar *name;
@@ -59,15 +61,6 @@ typedef struct {
        guint refcount;
 } CamelContentType;
 
-/* a raw rfc822 header */
-/* the value MUST be US-ASCII */
-struct _camel_header_raw {
-       struct _camel_header_raw *next;
-       gchar *name;
-       gchar *value;
-       gint offset;            /* in file, if known */
-};
-
 typedef struct _CamelContentDisposition {
        gchar *disposition;
        struct _camel_header_param *params;
@@ -81,6 +74,7 @@ typedef enum _camel_header_address_t {
 } CamelHeaderAddressType;
 
 typedef struct _camel_header_address {
+       /* < private > */
        struct _camel_header_address *next;
        CamelHeaderAddressType type;
        gchar *name;
@@ -152,23 +146,13 @@ gchar *camel_content_disposition_format (CamelContentDisposition *disposition);
 /* decode the contents of a content-encoding header */
 gchar *camel_content_transfer_encoding_decode (const gchar *in);
 
-/* raw headers */
-void camel_header_raw_append (struct _camel_header_raw **list, const gchar *name, const gchar *value, gint 
offset);
-void camel_header_raw_append_parse (struct _camel_header_raw **list, const gchar *header, gint offset);
-const gchar *camel_header_raw_find (struct _camel_header_raw **list, const gchar *name, gint *offset);
-const gchar *camel_header_raw_find_next (struct _camel_header_raw **list, const gchar *name, gint *offset, 
const gchar *last);
-void camel_header_raw_replace (struct _camel_header_raw **list, const gchar *name, const gchar *value, gint 
offset);
-void camel_header_raw_remove (struct _camel_header_raw **list, const gchar *name);
-void camel_header_raw_fold (struct _camel_header_raw **list);
-void camel_header_raw_clear (struct _camel_header_raw **list);
-
-gchar *camel_header_raw_check_mailing_list (struct _camel_header_raw **list);
-
 /* fold a header */
 gchar *camel_header_address_fold (const gchar *in, gsize headerlen);
 gchar *camel_header_fold (const gchar *in, gsize headerlen);
 gchar *camel_header_unfold (const gchar *in);
 
+gchar *camel_headers_dup_mailing_list (const CamelNameValueArray *headers);
+
 /* decode a header which is a simple token */
 gchar *camel_header_token_decode (const gchar *in);
 
diff --git a/src/camel/camel-movemail.c b/src/camel/camel-movemail.c
index 4e00e2e..3bda653 100644
--- a/src/camel/camel-movemail.c
+++ b/src/camel/camel-movemail.c
@@ -431,22 +431,24 @@ camel_movemail_copy_filter (gint fromfd,
  * want        to maintain it! */
 static gint
 solaris_header_write (gint fd,
-                      struct _camel_header_raw *header)
+                      CamelNameValueArray *headers)
 {
        struct iovec iv[4];
        gint outlen = 0, len;
+       guint ii;
+       const gchar *header_name = NULL, *header_value = NULL;
 
        iv[1].iov_base = ":";
        iv[1].iov_len = 1;
        iv[3].iov_base = "\n";
        iv[3].iov_len = 1;
 
-       while (header) {
-               if (g_ascii_strcasecmp (header->name, "Content-Length")) {
-                       iv[0].iov_base = header->name;
-                       iv[0].iov_len = strlen (header->name);
-                       iv[2].iov_base = header->value;
-                       iv[2].iov_len = strlen (header->value);
+       for (ii = 0; camel_name_value_array_get (headers, ii, &header_name, &header_value); ii++) {
+               if (g_ascii_strcasecmp (header_name, "Content-Length")) {
+                       iv[0].iov_base = header_name;
+                       iv[0].iov_len = strlen (header_name);
+                       iv[2].iov_base = header_value;
+                       iv[2].iov_len = strlen (header_value);
 
                        do {
                                len = writev (fd, iv, 4);
@@ -456,7 +458,6 @@ solaris_header_write (gint fd,
                                return -1;
                        outlen += len;
                }
-               header = header->next;
        }
 
        do {
@@ -510,6 +511,7 @@ camel_movemail_solaris (gint oldsfd,
                g_return_val_if_fail (camel_mime_parser_from_line (mp), -1);
                from = g_strdup (camel_mime_parser_from_line (mp));
                if (camel_mime_parser_step (mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_FROM_END) {
+                       CamelNameValueArray *headers;
                        const gchar *cl;
                        gint length;
                        gint start, body;
@@ -524,9 +526,13 @@ camel_movemail_solaris (gint oldsfd,
                                goto fail;
 
                        /* write out headers, but NOT content-length header */
-                       if (solaris_header_write (dfd, camel_mime_parser_headers_raw (mp)) == -1)
+                       headers = camel_mime_parser_dup_headers (mp);
+                       if (solaris_header_write (dfd, headers) == -1) {
+                               camel_name_value_array_free (headers);
                                goto fail;
+                       }
 
+                       camel_name_value_array_free (headers);
                        cl = camel_mime_parser_header (mp, "content-length", NULL);
                        if (cl == NULL) {
                                g_warning ("Required Content-Length header is missing from solaris mail box @ 
%d", (gint) camel_mime_parser_tell (mp));
diff --git a/src/camel/camel-msgport.c b/src/camel/camel-msgport.c
index 26a9cd0..75ee41f 100644
--- a/src/camel/camel-msgport.c
+++ b/src/camel/camel-msgport.c
@@ -238,7 +238,7 @@ msgport_sync_with_prpipe (PRFileDesc *prfd)
 }
 
 /**
- * camel_msgport_new:
+ * camel_msgport_new: (skip)
  *
  * Since: 2.24
  **/
@@ -258,7 +258,7 @@ camel_msgport_new (void)
 }
 
 /**
- * camel_msgport_destroy:
+ * camel_msgport_destroy: (skip)
  *
  * Since: 2.24
  **/
@@ -281,7 +281,7 @@ camel_msgport_destroy (CamelMsgPort *msgport)
 }
 
 /**
- * camel_msgport_fd:
+ * camel_msgport_fd: (skip)
  *
  * Since: 2.24
  **/
@@ -302,7 +302,9 @@ camel_msgport_fd (CamelMsgPort *msgport)
 }
 
 /**
- * camel_msgport_prfd:
+ * camel_msgport_prfd: (skip)
+ *
+ * Returns: (transfer none):
  *
  * Since: 2.24
  **/
@@ -323,7 +325,7 @@ camel_msgport_prfd (CamelMsgPort *msgport)
 }
 
 /**
- * camel_msgport_push:
+ * camel_msgport_push: (skip)
  *
  * Since: 2.24
  **/
@@ -374,7 +376,7 @@ camel_msgport_push (CamelMsgPort *msgport,
 }
 
 /**
- * camel_msgport_pop:
+ * camel_msgport_pop: (skip)
  *
  * Since: 2.24
  **/
@@ -402,7 +404,7 @@ camel_msgport_pop (CamelMsgPort *msgport)
 }
 
 /**
- * camel_msgport_try_pop:
+ * camel_msgport_try_pop: (skip)
  *
  * Since: 2.24
  **/
@@ -428,7 +430,7 @@ camel_msgport_try_pop (CamelMsgPort *msgport)
 }
 
 /**
- * camel_msgport_timeout_pop:
+ * camel_msgport_timeout_pop: (skip)
  * @msgport: a #CamelMsgPort
  * @timeout: number of microseconds to wait
  *
@@ -457,7 +459,7 @@ camel_msgport_timeout_pop (CamelMsgPort *msgport,
 }
 
 /**
- * camel_msgport_reply:
+ * camel_msgport_reply: (skip)
  *
  * Since: 2.24
  **/
diff --git a/src/camel/camel-multipart-encrypted.h b/src/camel/camel-multipart-encrypted.h
index dedb469..2566538 100644
--- a/src/camel/camel-multipart-encrypted.h
+++ b/src/camel/camel-multipart-encrypted.h
@@ -65,6 +65,8 @@ struct _CamelMultipartEncrypted {
 struct _CamelMultipartEncryptedClass {
        CamelMultipartClass parent_class;
 
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_multipart_encrypted_get_type      (void) G_GNUC_CONST;
diff --git a/src/camel/camel-multipart-signed.h b/src/camel/camel-multipart-signed.h
index 6d84d0f..aef7d5f 100644
--- a/src/camel/camel-multipart-signed.h
+++ b/src/camel/camel-multipart-signed.h
@@ -69,6 +69,9 @@ struct _CamelMultipartSigned {
 
 struct _CamelMultipartSignedClass {
        CamelMultipartClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_multipart_signed_get_type (void) G_GNUC_CONST;
diff --git a/src/camel/camel-multipart.c b/src/camel/camel-multipart.c
index 0836b5e..ea51717 100644
--- a/src/camel/camel-multipart.c
+++ b/src/camel/camel-multipart.c
@@ -297,7 +297,7 @@ multipart_set_boundary (CamelMultipart *multipart,
        gsize length;
        gint state, save;
 
-       g_return_if_fail (cdw->mime_type != NULL);
+       g_return_if_fail (camel_data_wrapper_get_mime_type_field (cdw) != NULL);
 
        length = g_checksum_type_get_length (G_CHECKSUM_MD5);
        digest = g_alloca (length);
@@ -328,7 +328,7 @@ multipart_set_boundary (CamelMultipart *multipart,
                boundary = bbuf;
        }
 
-       camel_content_type_set_param (cdw->mime_type, "boundary", boundary);
+       camel_content_type_set_param (camel_data_wrapper_get_mime_type_field (cdw), "boundary", boundary);
 }
 
 static const gchar *
@@ -336,8 +336,8 @@ multipart_get_boundary (CamelMultipart *multipart)
 {
        CamelDataWrapper *cdw = CAMEL_DATA_WRAPPER (multipart);
 
-       g_return_val_if_fail (cdw->mime_type != NULL, NULL);
-       return camel_content_type_param (cdw->mime_type, "boundary");
+       g_return_val_if_fail (camel_data_wrapper_get_mime_type_field (cdw) != NULL, NULL);
+       return camel_content_type_param (camel_data_wrapper_get_mime_type_field (cdw), "boundary");
 }
 
 static gint
diff --git a/src/camel/camel-multipart.h b/src/camel/camel-multipart.h
index 171b0eb..8284edc 100644
--- a/src/camel/camel-multipart.h
+++ b/src/camel/camel-multipart.h
@@ -73,6 +73,9 @@ struct _CamelMultipartClass {
        gint            (*construct_from_parser)
                                                (CamelMultipart *multipart,
                                                 CamelMimeParser *parser);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_multipart_get_type        (void) G_GNUC_CONST;
diff --git a/src/camel/camel-name-value-array.c b/src/camel/camel-name-value-array.c
new file mode 100644
index 0000000..0a90e02
--- /dev/null
+++ b/src/camel/camel-name-value-array.c
@@ -0,0 +1,636 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "camel-string-utils.h"
+
+#include "camel-name-value-array.h"
+
+G_DEFINE_BOXED_TYPE (CamelNameValueArray,
+               camel_name_value_array,
+               camel_name_value_array_copy,
+               camel_name_value_array_free)
+
+typedef struct _CamelNameValuePair {
+       gchar *name;
+       gchar *value;
+} CamelNameValuePair;
+
+static void
+free_name_value_content (gpointer ptr)
+{
+       CamelNameValuePair *pair = ptr;
+
+       if (pair) {
+               g_free (pair->name);
+               g_free (pair->value);
+
+               pair->name = NULL;
+               pair->value = NULL;
+       }
+}
+
+/**
+ * camel_name_value_array_new:
+ *
+ * Creates a new #CamelNameValueArray. The returned pointer should be freed
+ * with camel_name_value_array_free() when no longer needed.
+ *
+ * Returns: (transfer full): A new #CamelNameValueArray.
+ *
+ * See: camel_name_value_array_new_sized, camel_name_value_array_copy
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+camel_name_value_array_new (void)
+{
+       GArray *arr;
+
+       arr = g_array_new (FALSE, FALSE, sizeof (CamelNameValuePair));
+       g_array_set_clear_func (arr, free_name_value_content);
+
+       return (CamelNameValueArray *) arr;
+}
+
+/**
+ * camel_name_value_array_new_sized:
+ * @reserve_size: an array size to reserve
+ *
+ * Creates a new #CamelNameValueArray, which has reserved @reserve_size
+ * elements. This value doesn't influence the camel_name_value_array_get_length(),
+ * which returns zero on the array returned from this function. The returned
+ * pointer should be freed with camel_name_value_array_free() when no longer needed.
+ *
+ * Returns: (transfer full): A new #CamelNameValueArray.
+ *
+ * See: camel_name_value_array_new, camel_name_value_array_copy
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+camel_name_value_array_new_sized (guint reserve_size)
+{
+       GArray *arr;
+
+       arr = g_array_sized_new (FALSE, FALSE, sizeof (CamelNameValuePair), reserve_size);
+       g_array_set_clear_func (arr, free_name_value_content);
+
+       return (CamelNameValueArray *) arr;
+}
+
+/**
+ * camel_name_value_array_copy:
+ * @array: (nullable): a #CamelNameValueArray
+ *
+ * Creates a new copy of the @array. The returned pointer should be freed
+ * with camel_name_value_array_free() when no longer needed.
+ *
+ * Returns: (transfer full): A new copy of the @array.
+ *
+ * See: camel_name_value_array_new, camel_name_value_array_new_sized
+ *
+ * Since: 3.24
+ **/
+CamelNameValueArray *
+camel_name_value_array_copy (const CamelNameValueArray *array)
+{
+       CamelNameValueArray *copy;
+       guint ii, len;
+
+       if (!array)
+               return NULL;
+
+       len = camel_name_value_array_get_length (array);
+       copy = camel_name_value_array_new_sized (len);
+
+       for (ii = 0; ii < len; ii++) {
+               const gchar *name = NULL, *value = NULL;
+
+               if (camel_name_value_array_get (array, ii, &name, &value))
+                       camel_name_value_array_append (copy, name, value);
+       }
+
+       return copy;
+}
+
+/**
+ * camel_name_value_array_free:
+ * @array: (nullable): a #CamelNameValueArray, or %NULL
+ *
+ * Frees the @array, previously allocated by camel_name_value_array_new(),
+ * camel_name_value_array_new_sized() or camel_name_value_array_copy().
+ * If the @array is %NULL, then does nothing.
+ *
+ * Since: 3.24
+ **/
+void
+camel_name_value_array_free (CamelNameValueArray *array)
+{
+       if (array)
+               g_array_free ((GArray *) array, TRUE);
+}
+
+/**
+ * camel_name_value_array_get_length:
+ * @array: (nullable): a #CamelNameValueArray
+ *
+ * Returns: Length of the @array, aka how many elements are stored in the @array.
+ *
+ * Since: 3.24
+ **/
+guint
+camel_name_value_array_get_length (const CamelNameValueArray *array)
+{
+       GArray *arr = (GArray *) array;
+
+       if (!array)
+               return 0;
+
+       return arr->len;
+}
+
+/**
+ * camel_name_value_array_get:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ * @out_name: (out) (nullable): A place to store the name of the element, or %NULL
+ * @out_value: (out) (nullable): A place to store the value of the element, or %NULL
+ *
+ * Returns the name and the value of the element at index @index. Either
+ * of the @out_name and @out_value can be %NULL, to not return that part.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * See: camel_name_value_array_get_name, camel_name_value_array_get_value, camel_name_value_array_get_named
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_get (const CamelNameValueArray *array,
+                           guint index,
+                           const gchar **out_name,
+                           const gchar **out_value)
+{
+       GArray *arr = (GArray *) array;
+       CamelNameValuePair *pair;
+
+       g_return_val_if_fail (array != NULL, FALSE);
+
+       if (index >= camel_name_value_array_get_length (array))
+               return FALSE;
+
+       pair = &g_array_index (arr, CamelNameValuePair, index);
+
+       if (out_name)
+               *out_name = pair->name;
+       if (out_value)
+               *out_value= pair->value;
+
+       return TRUE;
+}
+
+static guint
+camel_name_value_array_find_named (const CamelNameValueArray *array,
+                                  CamelCompareType compare_type,
+                                  const gchar *name)
+{
+       GArray *arr = (GArray *) array;
+       gboolean case_sensitive;
+       gint ii;
+
+       g_return_val_if_fail (array != NULL, (guint) -1);
+       g_return_val_if_fail (name != NULL, (guint) -1);
+
+       case_sensitive = compare_type == CAMEL_COMPARE_CASE_SENSITIVE;
+
+       for (ii = 0; ii < arr->len; ii++) {
+               CamelNameValuePair *pair = &g_array_index (arr, CamelNameValuePair, ii);
+
+               if ((case_sensitive && g_strcmp0 (name, pair->name) == 0) ||
+                   (!case_sensitive && pair->name && camel_strcase_equal (name, pair->name))) {
+                       return ii;
+               }
+       }
+
+       return (guint) -1;
+}
+
+/**
+ * camel_name_value_array_get_named:
+ * @array: a #CamelNameValueArray
+ * @compare_type: a compare type, one of #CamelCompareType
+ * @name: a name
+ *
+ * Returns the value of the first element named @name, or %NULL when there
+ * is no element of such @name in the @array. The @compare_type determines
+ * how to compare the names.
+ *
+ * Returns: (transfer none) (nullable): Value of the first element named @name, or %NULL.
+ *
+ * See: camel_name_value_array_get, camel_name_value_array_get_name
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_name_value_array_get_named (const CamelNameValueArray *array,
+                                 CamelCompareType compare_type,
+                                 const gchar *name)
+{
+       guint index;
+
+       g_return_val_if_fail (array != NULL, NULL);
+       g_return_val_if_fail (name != NULL, NULL);
+
+       index = camel_name_value_array_find_named (array, compare_type, name);
+       if (index == (guint) -1)
+               return NULL;
+
+       return camel_name_value_array_get_value (array, index);
+}
+
+/**
+ * camel_name_value_array_get_name:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ *
+ * Returns the name of the element at index @index.
+ *
+ * Returns: (transfer none) (nullable): Name of the element at the given @index,
+ *    or %NULL on error.
+ *
+ * See: camel_name_value_array_get, camel_name_value_array_get_value
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_name_value_array_get_name (const CamelNameValueArray *array,
+                                guint index)
+{
+       const gchar *name = NULL;
+
+       g_return_val_if_fail (array != NULL, NULL);
+
+       if (!camel_name_value_array_get (array, index, &name, NULL))
+               return NULL;
+
+       return name;
+}
+
+/**
+ * camel_name_value_array_get_value:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ *
+ * Returns the value of the element at index @index.
+ *
+ * Returns: (transfer none) (nullable): Value of the element at the given @index,
+ *    or %NULL on error.
+ *
+ * See: camel_name_value_array_get, camel_name_value_array_get_name
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_name_value_array_get_value (const CamelNameValueArray *array,
+                                 guint index)
+{
+       const gchar *value = NULL;
+
+       g_return_val_if_fail (array != NULL, NULL);
+
+       if (!camel_name_value_array_get (array, index, NULL, &value))
+               return NULL;
+
+       return value;
+}
+
+/**
+ * camel_name_value_array_append:
+ * @array: a #CamelNameValueArray
+ * @name: a name
+ * @value: a value
+ *
+ * Appends a new element of the name @name and the value @value
+ * at the end of @array.
+ *
+ * See: camel_name_value_array_set_named
+ *
+ * Since: 3.24
+ **/
+void
+camel_name_value_array_append (CamelNameValueArray *array,
+                              const gchar *name,
+                              const gchar *value)
+{
+       GArray *arr = (GArray *) array;
+       CamelNameValuePair pair;
+
+       g_return_if_fail (array != NULL);
+       g_return_if_fail (name != NULL);
+       g_return_if_fail (value != NULL);
+
+       pair.name = g_strdup (name);
+       pair.value = g_strdup (value);
+
+       g_array_append_val (arr, pair);
+}
+
+static gboolean
+camel_name_value_array_set_internal (CamelNameValueArray *array,
+                                    guint index,
+                                    const gchar *name,
+                                    const gchar *value)
+{
+       GArray *arr = (GArray *) array;
+       CamelNameValuePair *pair;
+       gboolean changed = FALSE;
+
+       g_return_val_if_fail (array != NULL, FALSE);
+       g_return_val_if_fail (index < camel_name_value_array_get_length (array), FALSE);
+
+       pair = &g_array_index (arr, CamelNameValuePair, index);
+
+       if (name && g_strcmp0 (pair->name, name) != 0) {
+               g_free (pair->name);
+               pair->name = g_strdup (name);
+               changed = TRUE;
+       }
+
+       if (value && g_strcmp0 (pair->value, value) != 0) {
+               g_free (pair->value);
+               pair->value = g_strdup (value);
+               changed = TRUE;
+       }
+
+       return changed;
+}
+
+/**
+ * camel_name_value_array_set:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ * @name: a name
+ * @value: a value
+ *
+ * Sets both the @name and the @value of the element at index @index.
+ *
+ * Returns: Whether the @array changed.
+ *
+ * See: camel_name_value_array_append, camel_name_value_array_set_name, camel_name_value_array_set_value
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_set (CamelNameValueArray *array,
+                           guint index,
+                           const gchar *name,
+                           const gchar *value)
+{
+       g_return_val_if_fail (array != NULL, FALSE);
+       g_return_val_if_fail (index < camel_name_value_array_get_length (array), FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+       g_return_val_if_fail (value != NULL, FALSE);
+
+       return camel_name_value_array_set_internal (array, index, name, value);
+}
+
+/**
+ * camel_name_value_array_set_name:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ * @name: a name
+ *
+ * Sets the @name of the element at index @index.
+ *
+ * Returns: Whether the @array changed.
+ *
+ * See: camel_name_value_array_set, camel_name_value_array_set_value
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_set_name (CamelNameValueArray *array,
+                                guint index,
+                                const gchar *name)
+{
+       g_return_val_if_fail (array != NULL, FALSE);
+       g_return_val_if_fail (index < camel_name_value_array_get_length (array), FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+
+       return camel_name_value_array_set_internal (array, index, name, NULL);
+}
+
+/**
+ * camel_name_value_array_set_value:
+ * @array: a #CamelNameValueArray
+ * @index: an index
+ * @value: a value
+ *
+ * Sets the @value of the element at index @index.
+ *
+ * Returns: Whether the @array changed.
+ *
+ * See: camel_name_value_array_set, camel_name_value_array_set_name
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_set_value (CamelNameValueArray *array,
+                                 guint index,
+                                 const gchar *value)
+{
+       g_return_val_if_fail (array != NULL, FALSE);
+       g_return_val_if_fail (index < camel_name_value_array_get_length (array), FALSE);
+       g_return_val_if_fail (value != NULL, FALSE);
+
+       return camel_name_value_array_set_internal (array, index, NULL, value);
+}
+
+/**
+ * camel_name_value_array_set_named:
+ * @array: a #CamelNameValueArray
+ * @compare_type: a compare type, one of #CamelCompareType
+ * @name: a name
+ * @value: a value
+ *
+ * Finds an element named @name and sets its value to @value, or appends
+ * a new element, in case no such named element exists in the @array yet.
+ * In case there are more elements named with @name only the first
+ * occurrence is changed. The @compare_type determines how to compare
+ * the names.
+ *
+ * Returns: Whether the @array changed.
+ *
+ * See: camel_name_value_array_append, camel_name_value_array_set
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_set_named (CamelNameValueArray *array,
+                                 CamelCompareType compare_type,
+                                 const gchar *name,
+                                 const gchar *value)
+{
+       gboolean changed = FALSE;
+       guint index;
+
+       g_return_val_if_fail (array != NULL, FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+       g_return_val_if_fail (value != NULL, FALSE);
+
+       index = camel_name_value_array_find_named (array, compare_type, name);
+       if (index == (guint) -1) {
+               camel_name_value_array_append (array, name, value);
+               changed = TRUE;
+       } else {
+               changed = camel_name_value_array_set_value (array, index, value);
+       }
+
+       return changed;
+}
+
+/**
+ * camel_name_value_array_remove:
+ * @array: a #CamelNameValueArray
+ * @index: an index to remove
+ *
+ * Removes element at index @index.
+ *
+ * Returns: Whether the element was removed.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_remove (CamelNameValueArray *array,
+                              guint index)
+{
+       g_return_val_if_fail (array != NULL, FALSE);
+       g_return_val_if_fail (index < camel_name_value_array_get_length (array), FALSE);
+
+       g_array_remove_index ((GArray *) array, index);
+
+       return TRUE;
+}
+
+/**
+ * camel_name_value_array_remove_named:
+ * @array: a #CamelNameValueArray
+ * @compare_type: a compare type, one of #CamelCompareType
+ * @name: a name to remove
+ * @all_occurrences: whether to remove all occurrences of the @name
+ *
+ * Removes elements of the @array with the given @name.
+ * The @compare_type determines hot to compare the names.
+ * If the @all_occurrences is set to %TRUE, then every elements with the @name
+ * are removed, otherwise only the first occurrence is removed.
+ *
+ * Returns: How many elements had been removed.
+ *
+ * Since: 3.24
+ **/
+guint
+camel_name_value_array_remove_named (CamelNameValueArray *array,
+                                    CamelCompareType compare_type,
+                                    const gchar *name,
+                                    gboolean all_occurrences)
+{
+       guint index, removed = 0;
+
+       g_return_val_if_fail (array != NULL, 0);
+       g_return_val_if_fail (name != NULL, 0);
+
+       while (index = camel_name_value_array_find_named (array, compare_type, name), index != (guint) -1) {
+               if (!camel_name_value_array_remove (array, index))
+                       break;
+
+               removed++;
+
+               if (!all_occurrences)
+                       break;
+       }
+
+       return removed;
+}
+
+/**
+ * camel_name_value_array_clear:
+ * @array: a #CamelNameValueArray
+ *
+ * Removes all elements of the @array.
+ *
+ * Since: 3.24
+ **/
+void
+camel_name_value_array_clear (CamelNameValueArray *array)
+{
+       GArray *arr = (GArray *) array;
+
+       g_return_if_fail (array != NULL);
+
+       g_array_remove_range (arr, 0, arr->len);
+}
+
+/**
+ * camel_name_value_array_equal:
+ * @array_a: (nullable): the first #CamelNameValueArray
+ * @array_b: (nullable): the second #CamelNameValueArray
+ * @compare_type: a compare type, one of #CamelCompareType
+ *
+ * Compares content of the two #CamelNameValueArray and returns whether
+ * they equal. Note this is an expensive operation for large arrays.
+ *
+ * Returns: Whether the two #CamelNameValueArray have the same content.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_name_value_array_equal (const CamelNameValueArray *array_a,
+                             const CamelNameValueArray *array_b,
+                             CamelCompareType compare_type)
+{
+       guint ii, len;
+
+       if (array_a == array_b)
+               return TRUE;
+
+       if (!array_a || !array_b)
+               return FALSE;
+
+       len = camel_name_value_array_get_length (array_a);
+       if (len != camel_name_value_array_get_length (array_b))
+               return FALSE;
+
+       for (ii = 0; ii < len; ii++) {
+               const gchar *value1, *value2;
+
+               value1 = camel_name_value_array_get_value (array_a, ii);
+               value2 = camel_name_value_array_get_named (array_b, compare_type,
+                       camel_name_value_array_get_name (array_a, ii));
+
+               if (g_strcmp0 (value1, value2) != 0)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
diff --git a/src/camel/camel-name-value-array.h b/src/camel/camel-name-value-array.h
new file mode 100644
index 0000000..b3886b7
--- /dev/null
+++ b/src/camel/camel-name-value-array.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_NAME_VALUE_ARRAY_H
+#define CAMEL_NAME_VALUE_ARRAY_H
+
+#include <glib-object.h>
+#include <camel/camel-enums.h>
+
+G_BEGIN_DECLS
+
+/**
+ * CamelNameValueArray:
+ *
+ * Since: 3.24
+ **/
+struct _CamelNameValueArray;
+typedef struct _CamelNameValueArray CamelNameValueArray;
+
+#define CAMEL_TYPE_NAME_VALUE_ARRAY (camel_name_value_array_get_type ())
+
+GType           camel_name_value_array_get_type        (void) G_GNUC_CONST;
+CamelNameValueArray *
+               camel_name_value_array_new      (void);
+CamelNameValueArray *
+               camel_name_value_array_new_sized
+                                               (guint reserve_size);
+CamelNameValueArray *
+               camel_name_value_array_copy     (const CamelNameValueArray *array);
+void           camel_name_value_array_free     (CamelNameValueArray *array);
+guint          camel_name_value_array_get_length
+                                               (const CamelNameValueArray *array);
+gboolean       camel_name_value_array_get      (const CamelNameValueArray *array,
+                                                guint index,
+                                                const gchar **out_name,
+                                                const gchar **out_value);
+const gchar *  camel_name_value_array_get_named
+                                               (const CamelNameValueArray *array,
+                                                CamelCompareType compare_type,
+                                                const gchar *name);
+const gchar *  camel_name_value_array_get_name (const CamelNameValueArray *array,
+                                                guint index);
+const gchar *  camel_name_value_array_get_value
+                                               (const CamelNameValueArray *array,
+                                                guint index);
+void           camel_name_value_array_append   (CamelNameValueArray *array,
+                                                const gchar *name,
+                                                const gchar *value);
+gboolean       camel_name_value_array_set      (CamelNameValueArray *array,
+                                                guint index,
+                                                const gchar *name,
+                                                const gchar *value);
+gboolean       camel_name_value_array_set_name (CamelNameValueArray *array,
+                                                guint index,
+                                                const gchar *name);
+gboolean       camel_name_value_array_set_value
+                                               (CamelNameValueArray *array,
+                                                guint index,
+                                                const gchar *value);
+gboolean       camel_name_value_array_set_named
+                                               (CamelNameValueArray *array,
+                                                CamelCompareType compare_type,
+                                                const gchar *name,
+                                                const gchar *value);
+gboolean       camel_name_value_array_remove   (CamelNameValueArray *array,
+                                                guint index);
+guint          camel_name_value_array_remove_named
+                                               (CamelNameValueArray *array,
+                                                CamelCompareType compare_type,
+                                                const gchar *name,
+                                                gboolean all_occurrences);
+void           camel_name_value_array_clear    (CamelNameValueArray *array);
+gboolean       camel_name_value_array_equal    (const CamelNameValueArray *array_a,
+                                                const CamelNameValueArray *array_b,
+                                                CamelCompareType compare_type);
+
+G_END_DECLS
+
+#endif /* CAMEL_NAME_VALUE_ARRAY_H */
diff --git a/src/camel/camel-named-flags.c b/src/camel/camel-named-flags.c
new file mode 100644
index 0000000..04d9d30
--- /dev/null
+++ b/src/camel/camel-named-flags.c
@@ -0,0 +1,319 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "camel-named-flags.h"
+
+G_DEFINE_BOXED_TYPE (CamelNamedFlags,
+               camel_named_flags,
+               camel_named_flags_copy,
+               camel_named_flags_free)
+
+/**
+ * camel_named_flags_new:
+ *
+ * Creates a new #CamelNamedFlags.
+ *
+ * Returns: (transfer full): A newly allocated #CamelNamedFlags.
+ *    Free it with camel_named_flags_free() when done with it.
+ *
+ * Since: 3.24
+ **/
+CamelNamedFlags *
+camel_named_flags_new (void)
+{
+       return (CamelNamedFlags *) g_ptr_array_new_with_free_func (g_free);
+}
+
+/**
+ * camel_named_flags_new_sized:
+ * @reserve_size: an array size to reserve
+ *
+ * Created a new #CamelNamedFlags, which has reserved @reserve_size
+ * elements. This value doesn't influence the camel_named_flags_get_length(),
+ * which returns zero on the array returned from this function.
+ *
+ * Returns: (transfer full): A newly allocated #CamelNameValueArray.
+ *    Free it with camel_named_flags_free() when done with it.
+ *
+ * See: camel_name_value_array_new, camel_name_value_array_copy
+ *
+ * Since: 3.24
+ **/
+CamelNamedFlags *
+camel_named_flags_new_sized (guint reserve_size)
+{
+       return (CamelNamedFlags *) g_ptr_array_new_full (reserve_size, g_free);
+}
+
+/**
+ * camel_named_flags_copy:
+ * @named_flags: (nullable): a #CamelNamedFlags
+ *
+ * Creates a copy of the @named_flags and returns it.
+ *
+ * Returns: (transfer full): A newly allocated #CamelNamedFlags.
+ *    Free it with camel_named_flags_free() when done with it.
+ *
+ * Since: 3.24
+ **/
+CamelNamedFlags *
+camel_named_flags_copy (const CamelNamedFlags *named_flags)
+{
+       const GPtrArray *src = (const GPtrArray *) named_flags;
+       GPtrArray *arr;
+       guint ii;
+
+       if (!src)
+               return NULL;
+
+       arr = (GPtrArray *) camel_named_flags_new_sized (src->len);
+       for (ii = 0; ii < src->len; ii++) {
+               const gchar *name = g_ptr_array_index (src, ii);
+
+               if (name && *name)
+                       g_ptr_array_add (arr, g_strdup (name));
+       }
+
+       return (CamelNamedFlags *) arr;
+}
+
+/**
+ * camel_named_flags_free:
+ * @named_flags: (nullable): a #CamelNamedFlags, or %NULL
+ *
+ * Frees memory associated iwth the @named_flags. Does nothing,
+ * if @named_flags is %NULL.
+ *
+ * Since: 3.24
+ **/
+void
+camel_named_flags_free (CamelNamedFlags *named_flags)
+{
+       if (named_flags)
+               g_ptr_array_unref ((GPtrArray *) named_flags);
+}
+
+static guint
+camel_named_flags_find (const CamelNamedFlags *named_flags,
+                       const gchar *name)
+{
+       GPtrArray *arr = (GPtrArray *) named_flags;
+       guint ii;
+
+       g_return_val_if_fail (named_flags != NULL, (guint) -1);
+       g_return_val_if_fail (name != NULL, (guint) -1);
+
+       for (ii = 0; ii < arr->len; ii++) {
+               const gchar *nm = g_ptr_array_index (arr, ii);
+
+               if (g_strcmp0 (nm, name) == 0)
+                       return ii;
+       }
+
+       return (guint) -1;
+}
+
+/**
+ * camel_named_flags_insert:
+ * @named_flags: a #CamelNamedFlags
+ * @name: name of the flag
+ *
+ * Inserts a flag named @name into the @named_flags, if it is not included
+ * already (comparing case sensitively), or does nothing otherwise.
+ *
+ * Returns: %TRUE the flag named @name was inserted; %FALSE otherwise.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_named_flags_insert (CamelNamedFlags *named_flags,
+                         const gchar *name)
+{
+       GPtrArray *arr = (GPtrArray *) named_flags;
+       guint index;
+
+       g_return_val_if_fail (named_flags != NULL, FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+
+       index = camel_named_flags_find (named_flags, name);
+
+       /* already there */
+       if (index != (guint) -1)
+               return FALSE;
+
+       g_ptr_array_add (arr, g_strdup (name));
+
+       return TRUE;
+}
+
+/**
+ * camel_named_flags_remove:
+ * @named_flags: a #CamelNamedFlags
+ * @name: name of the flag
+ *
+ * Removes a flag named @name from the @named_flags.
+ *
+ * Returns: %TRUE when the @named_flags contained a flag named @name,
+ *    comparing case sensitively, and it was removed; %FALSE otherwise.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_named_flags_remove (CamelNamedFlags *named_flags,
+                         const gchar *name)
+{
+       GPtrArray *arr = (GPtrArray *) named_flags;
+       guint index;
+
+       g_return_val_if_fail (named_flags != NULL, FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+
+       index = camel_named_flags_find (named_flags, name);
+
+       /* not there */
+       if (index == (guint) -1)
+               return FALSE;
+
+       g_ptr_array_remove_index (arr, index);
+
+       return TRUE;
+}
+
+/**
+ * camel_named_flags_contains:
+ * @named_flags: a #CamelNamedFlags
+ * @name: name of the flag
+ *
+ * Returns: Whether the @named_flags contains a flag named @name,
+ *    comparing case sensitively.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_named_flags_contains (const CamelNamedFlags *named_flags,
+                           const gchar *name)
+{
+       g_return_val_if_fail (named_flags != NULL, FALSE);
+       g_return_val_if_fail (name != NULL, FALSE);
+
+       return camel_named_flags_find (named_flags, name) != (guint) -1;
+}
+
+/**
+ * camel_named_flags_clear:
+ * @named_flags: a #CamelNamedFlags
+ *
+ * Removes all the elements of the array.
+ *
+ * Since: 3.24
+ **/
+void
+camel_named_flags_clear (CamelNamedFlags *named_flags)
+{
+       GPtrArray *arr = (GPtrArray *) named_flags;
+
+       g_return_if_fail (named_flags != NULL);
+
+       if (arr->len)
+               g_ptr_array_remove_range (arr, 0, arr->len);
+}
+
+/**
+ * camel_named_flags_get_length:
+ * @named_flags: (nullable): a #CamelNamedFlags
+ *
+ * Returns: Length of the array, aka how many named flags are stored there.
+ *
+ * Since: 3.24
+ **/
+guint
+camel_named_flags_get_length (const CamelNamedFlags *named_flags)
+{
+       const GPtrArray *arr = (const GPtrArray *) named_flags;
+
+       if (!named_flags)
+               return 0;
+
+       return arr->len;
+}
+
+/**
+ * camel_named_flags_get:
+ * @named_flags: a #CamelNamedFlags
+ * @index: an index of an element
+ *
+ * Returns: (transfer none) (nullable): Name of the flag in at the given @index,
+ *   or %NULL on error.
+ *
+ * Since: 3.24
+ **/
+const gchar *
+camel_named_flags_get (const CamelNamedFlags *named_flags,
+                      guint index)
+{
+       const GPtrArray *arr = (const GPtrArray *) named_flags;
+
+       g_return_val_if_fail (named_flags != NULL, NULL);
+
+       if (index >= camel_named_flags_get_length (named_flags))
+               return NULL;
+
+       return g_ptr_array_index (arr, index);
+}
+
+/**
+ * camel_named_flags_equal:
+ * @named_flags_a: (nullable): the first #CamelNamedFlags
+ * @named_flags_b: (nullable): the second #CamelNamedFlags
+ *
+ * Compares content of the two #CamelNamedFlags and returns whether
+ * they equal. Note this is an expensive operation for large sets.
+ *
+ * Returns: Whether the two #CamelNamedFlags have the same content.
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_named_flags_equal (const CamelNamedFlags *named_flags_a,
+                        const CamelNamedFlags *named_flags_b)
+{
+       guint ii, len;
+
+       if (named_flags_a == named_flags_b)
+               return TRUE;
+
+       if (!named_flags_a || !named_flags_b)
+               return FALSE;
+
+       len = camel_named_flags_get_length (named_flags_a);
+       if (len != camel_named_flags_get_length (named_flags_b))
+               return FALSE;
+
+       for (ii = 0; ii < len; ii++) {
+               if (!camel_named_flags_contains (named_flags_a, camel_named_flags_get (named_flags_b, ii)))
+                       return FALSE;
+       }
+
+       return TRUE;
+}
diff --git a/src/camel/camel-named-flags.h b/src/camel/camel-named-flags.h
new file mode 100644
index 0000000..e5e7ca5
--- /dev/null
+++ b/src/camel/camel-named-flags.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_NAMED_FLAGS_H
+#define CAMEL_NAMED_FLAGS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/**
+ * CamelNamedFlags:
+ *
+ * Since: 3.24
+ **/
+struct _CamelNamedFlags;
+typedef struct _CamelNamedFlags CamelNamedFlags;
+
+#define CAMEL_TYPE_NAMED_FLAGS (camel_named_flags_get_type ())
+
+GType           camel_named_flags_get_type     (void) G_GNUC_CONST;
+CamelNamedFlags *
+               camel_named_flags_new           (void);
+CamelNamedFlags *
+               camel_named_flags_new_sized     (guint reserve_size);
+CamelNamedFlags *
+               camel_named_flags_copy          (const CamelNamedFlags *named_flags);
+void           camel_named_flags_free          (CamelNamedFlags *named_flags);
+gboolean       camel_named_flags_insert        (CamelNamedFlags *named_flags,
+                                                const gchar *name);
+gboolean       camel_named_flags_remove        (CamelNamedFlags *named_flags,
+                                                const gchar *name);
+gboolean       camel_named_flags_contains      (const CamelNamedFlags *named_flags,
+                                                const gchar *name);
+void           camel_named_flags_clear         (CamelNamedFlags *named_flags);
+guint          camel_named_flags_get_length    (const CamelNamedFlags *named_flags);
+const gchar *  camel_named_flags_get           (const CamelNamedFlags *named_flags,
+                                                guint index);
+gboolean       camel_named_flags_equal         (const CamelNamedFlags *named_flags_a,
+                                                const CamelNamedFlags *named_flags_b);
+
+G_END_DECLS
+
+#endif /* CAMEL_NAMED_FLAGS_H */
diff --git a/src/camel/camel-network-service.h b/src/camel/camel-network-service.h
index 4795e9b..92e75a8 100644
--- a/src/camel/camel-network-service.h
+++ b/src/camel/camel-network-service.h
@@ -73,7 +73,8 @@ struct _CamelNetworkServiceInterface {
                        (*new_connectable)
                                        (CamelNetworkService *service);
 
-       gpointer reserved[15];
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_network_service_get_type  (void) G_GNUC_CONST;
diff --git a/src/camel/camel-network-settings.h b/src/camel/camel-network-settings.h
index db79485..9158bf1 100644
--- a/src/camel/camel-network-settings.h
+++ b/src/camel/camel-network-settings.h
@@ -56,6 +56,9 @@ typedef struct _CamelNetworkSettingsInterface CamelNetworkSettingsInterface;
 
 struct _CamelNetworkSettingsInterface {
        GTypeInterface parent_interface;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_network_settings_get_type
diff --git a/src/camel/camel-nntp-address.c b/src/camel/camel-nntp-address.c
index 3e16a29..60729dc 100644
--- a/src/camel/camel-nntp-address.c
+++ b/src/camel/camel-nntp-address.c
@@ -24,20 +24,30 @@
 
 #define d(x)
 
-struct _address {
-       gchar *name;
-       gchar *address;
+struct _CamelNNTPAddressPrivate {
+       GPtrArray *addresses;
 };
 
 G_DEFINE_TYPE (CamelNNTPAddress, camel_nntp_address, CAMEL_TYPE_ADDRESS)
 
+static gint
+nntp_address_length (CamelAddress *paddr)
+{
+       CamelNNTPAddress *nntp_addr = CAMEL_NNTP_ADDRESS (paddr);
+
+       g_return_val_if_fail (nntp_addr != NULL, -1);
+
+       return nntp_addr->priv->addresses->len;
+}
+
 /* since newsgropus are 7bit ascii, decode/unformat are the same */
 static gint
 nntp_address_decode (CamelAddress *address,
                      const gchar *raw)
 {
+       CamelNNTPAddress *nntp_addr = CAMEL_NNTP_ADDRESS (address);
        GSList *ha, *n;
-       gint count = address->addresses->len;
+       gint count = nntp_addr->priv->addresses->len;
 
        ha = camel_header_newsgroups_decode (raw);
        for (n = ha; n != NULL; n = n->next) {
@@ -45,27 +55,28 @@ nntp_address_decode (CamelAddress *address,
        }
 
        g_slist_free_full (ha, g_free);
-       return address->addresses->len - count;
+       return nntp_addr->priv->addresses->len - count;
 }
 
 /* since newsgropus are 7bit ascii, encode/format are the same */
 static gchar *
 nntp_address_encode (CamelAddress *address)
 {
+       CamelNNTPAddress *nntp_addr = CAMEL_NNTP_ADDRESS (address);
        gint i;
        GString *out;
        gchar *ret;
 
-       if (address->addresses->len == 0)
+       if (nntp_addr->priv->addresses->len == 0)
                return NULL;
 
        out = g_string_new ("");
 
-       for (i = 0; i < address->addresses->len; i++) {
+       for (i = 0; i < nntp_addr->priv->addresses->len; i++) {
                if (i != 0)
                        g_string_append (out, ", ");
 
-               g_string_append (out, g_ptr_array_index (address->addresses, i));
+               g_string_append (out, g_ptr_array_index (nntp_addr->priv->addresses, i));
        }
 
        ret = out->str;
@@ -78,14 +89,19 @@ static gint
 nntp_address_cat (CamelAddress *dest,
                   CamelAddress *source)
 {
+       CamelNNTPAddress *dest_nntp_addr;
+       CamelNNTPAddress *source_nntp_addr;
        gint ii;
 
+       g_return_val_if_fail (CAMEL_IS_NNTP_ADDRESS (dest), -1);
        g_return_val_if_fail (CAMEL_IS_NNTP_ADDRESS (source), -1);
 
-       for (ii = 0; ii < source->addresses->len; ii++)
-               camel_nntp_address_add (
-                       CAMEL_NNTP_ADDRESS (dest),
-                       g_ptr_array_index (source->addresses, ii));
+       dest_nntp_addr = CAMEL_NNTP_ADDRESS (dest);
+       source_nntp_addr = CAMEL_NNTP_ADDRESS (source);
+
+       for (ii = 0; ii < source_nntp_addr->priv->addresses->len; ii++) {
+               camel_nntp_address_add (dest_nntp_addr, g_ptr_array_index (source_nntp_addr->priv->addresses, 
ii));
+       }
 
        return ii;
 }
@@ -94,19 +110,41 @@ static void
 nntp_address_remove (CamelAddress *address,
                      gint index)
 {
-       if (index < 0 || index >= address->addresses->len)
+       CamelNNTPAddress *nntp_addr = CAMEL_NNTP_ADDRESS (address);
+
+       if (index < 0 || index >= nntp_addr->priv->addresses->len)
                return;
 
-       g_free (g_ptr_array_index (address->addresses, index));
-       g_ptr_array_remove_index (address->addresses, index);
+       g_free (g_ptr_array_index (nntp_addr->priv->addresses, index));
+       g_ptr_array_remove_index (nntp_addr->priv->addresses, index);
+}
+
+
+static void
+nntp_address_finalize (GObject *object)
+{
+       CamelNNTPAddress *nntp_addr = CAMEL_NNTP_ADDRESS (object);
+
+       camel_address_remove (CAMEL_ADDRESS (nntp_addr), -1);
+       g_ptr_array_free (nntp_addr->priv->addresses, TRUE);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (camel_nntp_address_parent_class)->finalize (object);
 }
 
 static void
 camel_nntp_address_class_init (CamelNNTPAddressClass *class)
 {
        CamelAddressClass *address_class;
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelNNTPAddressPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->finalize = nntp_address_finalize;
 
        address_class = CAMEL_ADDRESS_CLASS (class);
+       address_class->length = nntp_address_length;
        address_class->decode = nntp_address_decode;
        address_class->encode = nntp_address_encode;
        address_class->unformat = nntp_address_decode;
@@ -118,6 +156,8 @@ camel_nntp_address_class_init (CamelNNTPAddressClass *class)
 static void
 camel_nntp_address_init (CamelNNTPAddress *nntp_address)
 {
+       nntp_address->priv = G_TYPE_INSTANCE_GET_PRIVATE (nntp_address, CAMEL_TYPE_NNTP_ADDRESS, 
CamelNNTPAddressPrivate);
+       nntp_address->priv->addresses = g_ptr_array_new ();
 }
 
 /**
@@ -135,7 +175,7 @@ camel_nntp_address_new (void)
 
 /**
  * camel_nntp_address_add:
- * @a: nntp address object
+ * @addr: nntp address object
  * @name:
  *
  * Add a new nntp address to the address object.  Duplicates are not added twice.
@@ -143,26 +183,26 @@ camel_nntp_address_new (void)
  * Returns: Index of added entry, or existing matching entry.
  **/
 gint
-camel_nntp_address_add (CamelNNTPAddress *a,
+camel_nntp_address_add (CamelNNTPAddress *addr,
                         const gchar *name)
 {
        gint index, i;
 
-       g_return_val_if_fail (CAMEL_IS_NNTP_ADDRESS (a), -1);
+       g_return_val_if_fail (CAMEL_IS_NNTP_ADDRESS (addr), -1);
 
-       index = ((CamelAddress *) a)->addresses->len;
+       index = addr->priv->addresses->len;
        for (i = 0; i < index; i++)
-               if (!strcmp (g_ptr_array_index (((CamelAddress *) a)->addresses, i), name))
+               if (!strcmp (g_ptr_array_index (addr->priv->addresses, i), name))
                        return i;
 
-       g_ptr_array_add (((CamelAddress *) a)->addresses, g_strdup (name));
+       g_ptr_array_add (addr->priv->addresses, g_strdup (name));
 
        return index;
 }
 
 /**
  * camel_nntp_address_get:
- * @a: nntp address object
+ * @addr: nntp address object
  * @index: address's array index
  * @namep: Holder for the returned address, or NULL, if not required.
  *
@@ -171,17 +211,17 @@ camel_nntp_address_add (CamelNNTPAddress *a,
  * Returns: TRUE if such an address exists, or FALSE otherwise.
  **/
 gboolean
-camel_nntp_address_get (CamelNNTPAddress *a,
+camel_nntp_address_get (CamelNNTPAddress *addr,
                         gint index,
                         const gchar **namep)
 {
-       g_return_val_if_fail (CAMEL_IS_NNTP_ADDRESS (a), FALSE);
+       g_return_val_if_fail (CAMEL_IS_NNTP_ADDRESS (addr), FALSE);
 
-       if (index < 0 || index >= ((CamelAddress *) a)->addresses->len)
+       if (index < 0 || index >= addr->priv->addresses->len)
                return FALSE;
 
        if (namep)
-               *namep = g_ptr_array_index( ((CamelAddress *)a)->addresses, index);
+               *namep = g_ptr_array_index (addr->priv->addresses, index);
 
        return TRUE;
 }
diff --git a/src/camel/camel-nntp-address.h b/src/camel/camel-nntp-address.h
index 096fcf2..4831aa7 100644
--- a/src/camel/camel-nntp-address.h
+++ b/src/camel/camel-nntp-address.h
@@ -58,14 +58,17 @@ struct _CamelNNTPAddress {
 
 struct _CamelNNTPAddressClass {
        CamelAddressClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_nntp_address_get_type     (void);
 CamelNNTPAddress *
                camel_nntp_address_new          (void);
-gint           camel_nntp_address_add          (CamelNNTPAddress *a,
+gint           camel_nntp_address_add          (CamelNNTPAddress *addr,
                                                 const gchar *name);
-gboolean       camel_nntp_address_get          (CamelNNTPAddress *a,
+gboolean       camel_nntp_address_get          (CamelNNTPAddress *addr,
                                                 gint index,
                                                 const gchar **namep);
 
diff --git a/src/camel/camel-null-output-stream.h b/src/camel/camel-null-output-stream.h
index f113ae4..978763d 100644
--- a/src/camel/camel-null-output-stream.h
+++ b/src/camel/camel-null-output-stream.h
@@ -56,6 +56,9 @@ struct _CamelNullOutputStream {
 
 struct _CamelNullOutputStreamClass {
        GOutputStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_null_output_stream_get_type
diff --git a/src/camel/camel-object-bag.c b/src/camel/camel-object-bag.c
index 79c3cec..b489014 100644
--- a/src/camel/camel-object-bag.c
+++ b/src/camel/camel-object-bag.c
@@ -151,7 +151,7 @@ wref_free_func (gpointer p)
 }
 
 /**
- * camel_object_bag_new:
+ * camel_object_bag_new: (skip)
  * @key_hash_func: (scope call): a hashing function for keys
  * @key_equal_func: (scope call): a comparison function for keys
  * @key_copy_func: (scope call): a function to copy keys
@@ -530,7 +530,7 @@ camel_object_bag_rekey (CamelObjectBag *bag,
  *
  * <informalexample>
  *   <programlisting>
- *     g_ptr_array_foreach (array, g_object_unref, NULL);
+ *     g_ptr_array_foreach (array, (GFunc) g_object_unref, NULL);
  *     g_ptr_array_free (array, TRUE);
  *   </programlisting>
  * </informalexample>
diff --git a/src/camel/camel-object.h b/src/camel/camel-object.h
index 1d96f82..5e76c01 100644
--- a/src/camel/camel-object.h
+++ b/src/camel/camel-object.h
@@ -101,6 +101,9 @@ struct _CamelObjectClass {
                                                 FILE *fp);
        gint            (*state_write)          (CamelObject *object,
                                                 FILE *fp);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_object_get_type           (void);
diff --git a/src/camel/camel-offline-folder.h b/src/camel/camel-offline-folder.h
index 0182cb3..4d04344 100644
--- a/src/camel/camel-offline-folder.h
+++ b/src/camel/camel-offline-folder.h
@@ -66,8 +66,8 @@ struct _CamelOfflineFolderClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots. */
-       gpointer reserved[2];
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_offline_folder_get_type   (void);
diff --git a/src/camel/camel-offline-settings.h b/src/camel/camel-offline-settings.h
index b336a62..c0a562e 100644
--- a/src/camel/camel-offline-settings.h
+++ b/src/camel/camel-offline-settings.h
@@ -64,6 +64,9 @@ struct _CamelOfflineSettings {
 
 struct _CamelOfflineSettingsClass {
        CamelStoreSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_offline_settings_get_type
diff --git a/src/camel/camel-offline-store.c b/src/camel/camel-offline-store.c
index b49b786..3ca0db6 100644
--- a/src/camel/camel-offline-store.c
+++ b/src/camel/camel-offline-store.c
@@ -223,8 +223,7 @@ camel_offline_store_set_online_sync (CamelOfflineStore *store,
                GPtrArray *folders;
                guint ii;
 
-               folders = camel_object_bag_list (
-                       CAMEL_STORE (store)->folders);
+               folders = camel_store_dup_opened_folders (CAMEL_STORE (store));
 
                for (ii = 0; ii < folders->len; ii++) {
                        CamelFolder *folder = folders->pdata[ii];
@@ -288,8 +287,7 @@ camel_offline_store_prepare_for_offline_sync (CamelOfflineStore *store,
                GPtrArray *folders;
                guint ii;
 
-               folders = camel_object_bag_list (
-                       CAMEL_STORE (store)->folders);
+               folders = camel_store_dup_opened_folders (CAMEL_STORE (store));
 
                for (ii = 0; ii < folders->len; ii++) {
                        CamelFolder *folder = folders->pdata[ii];
@@ -359,8 +357,7 @@ camel_offline_store_requires_downsync (CamelOfflineStore *store)
                GPtrArray *folders;
                guint ii;
 
-               folders = camel_object_bag_list (
-                       CAMEL_STORE (store)->folders);
+               folders = camel_store_dup_opened_folders (CAMEL_STORE (store));
 
                for (ii = 0; ii < folders->len && !sync_any_folder; ii++) {
                        CamelFolder *folder = folders->pdata[ii];
diff --git a/src/camel/camel-offline-store.h b/src/camel/camel-offline-store.h
index 35e5ddc..3ca4400 100644
--- a/src/camel/camel-offline-store.h
+++ b/src/camel/camel-offline-store.h
@@ -58,6 +58,9 @@ struct _CamelOfflineStore {
 
 struct _CamelOfflineStoreClass {
        CamelStoreClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_offline_store_get_type (void);
diff --git a/src/camel/camel-operation.h b/src/camel/camel-operation.h
index d8cbd9f..1452470 100644
--- a/src/camel/camel-operation.h
+++ b/src/camel/camel-operation.h
@@ -61,6 +61,9 @@ struct _CamelOperationClass {
        void            (*status)               (CamelOperation *operation,
                                                 const gchar *what,
                                                 gint pc);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_operation_get_type        (void);
diff --git a/src/camel/camel-partition-table.c b/src/camel/camel-partition-table.c
index e51c16b..1e5659b 100644
--- a/src/camel/camel-partition-table.c
+++ b/src/camel/camel-partition-table.c
@@ -49,6 +49,12 @@
 
 struct _CamelPartitionTablePrivate {
        GMutex lock;    /* for locking partition */
+
+       CamelBlockFile *blocks;
+       camel_block_t rootid;
+
+       /* we keep a list of partition blocks active at all times */
+       GQueue partition;
 };
 
 G_DEFINE_TYPE (CamelPartitionTable, camel_partition_table, G_TYPE_OBJECT)
@@ -59,14 +65,14 @@ partition_table_finalize (GObject *object)
        CamelPartitionTable *table = CAMEL_PARTITION_TABLE (object);
        CamelBlock *bl;
 
-       if (table->blocks != NULL) {
-               while ((bl = g_queue_pop_head (&table->partition)) != NULL) {
-                       camel_block_file_sync_block (table->blocks, bl);
-                       camel_block_file_unref_block (table->blocks, bl);
+       if (table->priv->blocks != NULL) {
+               while ((bl = g_queue_pop_head (&table->priv->partition)) != NULL) {
+                       camel_block_file_sync_block (table->priv->blocks, bl);
+                       camel_block_file_unref_block (table->priv->blocks, bl);
                }
-               camel_block_file_sync (table->blocks);
+               camel_block_file_sync (table->priv->blocks);
 
-               g_object_unref (table->blocks);
+               g_object_unref (table->priv->blocks);
        }
 
        g_mutex_clear (&table->priv->lock);
@@ -91,7 +97,7 @@ camel_partition_table_init (CamelPartitionTable *cpi)
 {
        cpi->priv = CAMEL_PARTITION_TABLE_GET_PRIVATE (cpi);
 
-       g_queue_init (&cpi->partition);
+       g_queue_init (&cpi->priv->partition);
        g_mutex_init (&cpi->priv->lock);
 }
 
@@ -138,7 +144,7 @@ find_partition (CamelPartitionTable *cpi,
        GList *head, *link;
 
        /* first, find the block this key might be in, then binary search the block */
-       head = g_queue_peek_head_link (&cpi->partition);
+       head = g_queue_peek_head_link (&cpi->priv->partition);
 
        for (link = head; link != NULL; link = g_list_next (link)) {
                CamelBlock *bl = link->data;
@@ -191,8 +197,8 @@ camel_partition_table_new (CamelBlockFile *bs,
        g_return_val_if_fail (CAMEL_IS_BLOCK_FILE (bs), NULL);
 
        cpi = g_object_new (CAMEL_TYPE_PARTITION_TABLE, NULL);
-       cpi->rootid = root;
-       cpi->blocks = g_object_ref (bs);
+       cpi->priv->rootid = root;
+       cpi->priv->blocks = g_object_ref (bs);
 
        /* read the partition table into memory */
        do {
@@ -205,7 +211,7 @@ camel_partition_table_new (CamelBlockFile *bs,
                d (printf ("Adding partition block, used = %d, hashid = %08x\n", ptb->used, 
ptb->partition[0].hashid));
 
                /* if we have no data, prime initial block */
-               if (ptb->used == 0 && g_queue_is_empty (&cpi->partition) && ptb->next == 0) {
+               if (ptb->used == 0 && g_queue_is_empty (&cpi->priv->partition) && ptb->next == 0) {
                        pblock = camel_block_file_new_block (bs);
                        if (pblock == NULL) {
                                camel_block_file_unref_block (bs, block);
@@ -226,7 +232,7 @@ camel_partition_table_new (CamelBlockFile *bs,
 
                root = ptb->next;
                camel_block_file_detach_block (bs, block);
-               g_queue_push_tail (&cpi->partition, block);
+               g_queue_push_tail (&cpi->priv->partition, block);
        } while (root);
 
        return cpi;
@@ -246,15 +252,15 @@ camel_partition_table_sync (CamelPartitionTable *cpi)
 
        CAMEL_PARTITION_TABLE_LOCK (cpi, lock);
 
-       if (cpi->blocks) {
+       if (cpi->priv->blocks) {
                GList *head, *link;
 
-               head = g_queue_peek_head_link (&cpi->partition);
+               head = g_queue_peek_head_link (&cpi->priv->partition);
 
                for (link = head; link != NULL; link = g_list_next (link)) {
                        CamelBlock *bl = link->data;
 
-                       ret = camel_block_file_sync_block (cpi->blocks, bl);
+                       ret = camel_block_file_sync_block (cpi->priv->blocks, bl);
                        if (ret == -1)
                                goto fail;
                }
@@ -294,7 +300,7 @@ camel_partition_table_lookup (CamelPartitionTable *cpi,
        ptblock = (CamelBlock *) ptblock_link->data;
        ptb = (CamelPartitionMapBlock *) &ptblock->data;
        block = camel_block_file_get_block (
-               cpi->blocks, ptb->partition[index].blockid);
+               cpi->priv->blocks, ptb->partition[index].blockid);
        if (block == NULL) {
                CAMEL_PARTITION_TABLE_UNLOCK (cpi, lock);
                return 0;
@@ -314,7 +320,7 @@ camel_partition_table_lookup (CamelPartitionTable *cpi,
 
        CAMEL_PARTITION_TABLE_UNLOCK (cpi, lock);
 
-       camel_block_file_unref_block (cpi->blocks, block);
+       camel_block_file_unref_block (cpi->priv->blocks, block);
 
        return keyid;
 }
@@ -346,7 +352,7 @@ camel_partition_table_remove (CamelPartitionTable *cpi,
        ptblock = (CamelBlock *) ptblock_link->data;
        ptb = (CamelPartitionMapBlock *) &ptblock->data;
        block = camel_block_file_get_block (
-               cpi->blocks, ptb->partition[index].blockid);
+               cpi->priv->blocks, ptb->partition[index].blockid);
        if (block == NULL) {
                CAMEL_PARTITION_TABLE_UNLOCK (cpi, lock);
                return FALSE;
@@ -365,14 +371,14 @@ camel_partition_table_remove (CamelPartitionTable *cpi,
                                pkb->keys[i].keyid = pkb->keys[i + 1].keyid;
                                pkb->keys[i].hashid = pkb->keys[i + 1].hashid;
                        }
-                       camel_block_file_touch_block (cpi->blocks, block);
+                       camel_block_file_touch_block (cpi->priv->blocks, block);
                        break;
                }
        }
 
        CAMEL_PARTITION_TABLE_UNLOCK (cpi, lock);
 
-       camel_block_file_unref_block (cpi->blocks, block);
+       camel_block_file_unref_block (cpi->priv->blocks, block);
 
        return TRUE;
 }
@@ -422,7 +428,7 @@ camel_partition_table_add (CamelPartitionTable *cpi,
        ptblock = (CamelBlock *) ptblock_link->data;
        ptb = (CamelPartitionMapBlock *) &ptblock->data;
        block = camel_block_file_get_block (
-               cpi->blocks, ptb->partition[index].blockid);
+               cpi->priv->blocks, ptb->partition[index].blockid);
        if (block == NULL) {
                CAMEL_PARTITION_TABLE_UNLOCK (cpi, lock);
                return -1;
@@ -445,17 +451,17 @@ camel_partition_table_add (CamelPartitionTable *cpi,
 
                if (index > 0) {
                        pblock = camel_block_file_get_block (
-                               cpi->blocks, ptb->partition[index - 1].blockid);
+                               cpi->priv->blocks, ptb->partition[index - 1].blockid);
                        if (pblock == NULL)
                                goto fail;
                        pkb = (CamelPartitionKeyBlock *) &pblock->data;
                }
                if (index < (ptb->used - 1)) {
                        nblock = camel_block_file_get_block (
-                               cpi->blocks, ptb->partition[index + 1].blockid);
+                               cpi->priv->blocks, ptb->partition[index + 1].blockid);
                        if (nblock == NULL) {
                                if (pblock)
-                                       camel_block_file_unref_block (cpi->blocks, pblock);
+                                       camel_block_file_unref_block (cpi->priv->blocks, pblock);
                                goto fail;
                        }
                        nkb = (CamelPartitionKeyBlock *) &nblock->data;
@@ -486,15 +492,15 @@ camel_partition_table_add (CamelPartitionTable *cpi,
                        /* See if we have room in the partition table for this block or need to split that 
too */
                        if (ptb->used >= G_N_ELEMENTS (ptb->partition)) {
                                /* TODO: Could check next block to see if it'll fit there first */
-                               ptnblock = camel_block_file_new_block (cpi->blocks);
+                               ptnblock = camel_block_file_new_block (cpi->priv->blocks);
                                if (ptnblock == NULL) {
                                        if (nblock)
-                                               camel_block_file_unref_block (cpi->blocks, nblock);
+                                               camel_block_file_unref_block (cpi->priv->blocks, nblock);
                                        if (pblock)
-                                               camel_block_file_unref_block (cpi->blocks, pblock);
+                                               camel_block_file_unref_block (cpi->priv->blocks, pblock);
                                        goto fail;
                                }
-                               camel_block_file_detach_block (cpi->blocks, ptnblock);
+                               camel_block_file_detach_block (cpi->priv->blocks, ptnblock);
 
                                /* split block and link on-disk, always sorted */
                                ptn = (CamelPartitionMapBlock *) &ptnblock->data;
@@ -507,18 +513,18 @@ camel_partition_table_add (CamelPartitionTable *cpi,
 
                                /* link in-memory */
                                g_queue_insert_after (
-                                       &cpi->partition,
+                                       &cpi->priv->partition,
                                        ptblock_link, ptnblock);
 
                                /* write in right order to ensure structure */
-                               camel_block_file_touch_block (cpi->blocks, ptnblock);
+                               camel_block_file_touch_block (cpi->priv->blocks, ptnblock);
 #ifdef SYNC_UPDATES
-                               camel_block_file_sync_block (cpi->blocks, ptnblock);
+                               camel_block_file_sync_block (cpi->priv->blocks, ptnblock);
 #endif
                                if (index > len) {
-                                       camel_block_file_touch_block (cpi->blocks, ptblock);
+                                       camel_block_file_touch_block (cpi->priv->blocks, ptblock);
 #ifdef SYNC_UPDATES
-                                       camel_block_file_sync_block (cpi->blocks, ptblock);
+                                       camel_block_file_sync_block (cpi->priv->blocks, ptblock);
 #endif
                                        index -= len;
                                        ptb = ptn;
@@ -527,12 +533,12 @@ camel_partition_table_add (CamelPartitionTable *cpi,
                        }
 
                        /* try get newblock before modifying existing */
-                       newblock = camel_block_file_new_block (cpi->blocks);
+                       newblock = camel_block_file_new_block (cpi->priv->blocks);
                        if (newblock == NULL) {
                                if (nblock)
-                                       camel_block_file_unref_block (cpi->blocks, nblock);
+                                       camel_block_file_unref_block (cpi->priv->blocks, nblock);
                                if (pblock)
-                                       camel_block_file_unref_block (cpi->blocks, pblock);
+                                       camel_block_file_unref_block (cpi->priv->blocks, pblock);
                                goto fail;
                        }
 
@@ -550,18 +556,18 @@ camel_partition_table_add (CamelPartitionTable *cpi,
                        ptb->partition[newindex].blockid = newblock->id;
 
                        if (nblock)
-                               camel_block_file_unref_block (cpi->blocks, nblock);
+                               camel_block_file_unref_block (cpi->priv->blocks, nblock);
                        if (pblock)
-                               camel_block_file_unref_block (cpi->blocks, pblock);
+                               camel_block_file_unref_block (cpi->priv->blocks, pblock);
                } else {
                        newkb = (CamelPartitionKeyBlock *) &newblock->data;
 
                        if (newblock == pblock) {
                                if (nblock)
-                                       camel_block_file_unref_block (cpi->blocks, nblock);
+                                       camel_block_file_unref_block (cpi->priv->blocks, nblock);
                        } else {
                                if (pblock)
-                                       camel_block_file_unref_block (cpi->blocks, pblock);
+                                       camel_block_file_unref_block (cpi->priv->blocks, pblock);
                        }
                }
 
@@ -593,16 +599,16 @@ camel_partition_table_add (CamelPartitionTable *cpi,
                        ptb->partition[newindex].hashid = partid;
                }
 
-               camel_block_file_touch_block (cpi->blocks, ptblock);
+               camel_block_file_touch_block (cpi->priv->blocks, ptblock);
 #ifdef SYNC_UPDATES
-               camel_block_file_sync_block (cpi->blocks, ptblock);
+               camel_block_file_sync_block (cpi->priv->blocks, ptblock);
 #endif
-               camel_block_file_touch_block (cpi->blocks, newblock);
-               camel_block_file_unref_block (cpi->blocks, newblock);
+               camel_block_file_touch_block (cpi->priv->blocks, newblock);
+               camel_block_file_unref_block (cpi->priv->blocks, newblock);
        }
 
-       camel_block_file_touch_block (cpi->blocks, block);
-       camel_block_file_unref_block (cpi->blocks, block);
+       camel_block_file_touch_block (cpi->priv->blocks, block);
+       camel_block_file_unref_block (cpi->priv->blocks, block);
 
        ret = 0;
 fail:
@@ -624,6 +630,13 @@ fail:
 
 struct _CamelKeyTablePrivate {
        GMutex lock;    /* for locking key */
+
+       CamelBlockFile *blocks;
+
+       camel_block_t rootid;
+
+       CamelKeyRootBlock *root;
+       CamelBlock *root_block;
 };
 
 G_DEFINE_TYPE (CamelKeyTable, camel_key_table, G_TYPE_OBJECT)
@@ -633,13 +646,13 @@ key_table_finalize (GObject *object)
 {
        CamelKeyTable *table = CAMEL_KEY_TABLE (object);
 
-       if (table->blocks) {
-               if (table->root_block) {
-                       camel_block_file_sync_block (table->blocks, table->root_block);
-                       camel_block_file_unref_block (table->blocks, table->root_block);
+       if (table->priv->blocks) {
+               if (table->priv->root_block) {
+                       camel_block_file_sync_block (table->priv->blocks, table->priv->root_block);
+                       camel_block_file_unref_block (table->priv->blocks, table->priv->root_block);
                }
-               camel_block_file_sync (table->blocks);
-               g_object_unref (table->blocks);
+               camel_block_file_sync (table->priv->blocks);
+               g_object_unref (table->priv->blocks);
        }
 
        g_mutex_clear (&table->priv->lock);
@@ -676,19 +689,19 @@ camel_key_table_new (CamelBlockFile *bs,
 
        ki = g_object_new (CAMEL_TYPE_KEY_TABLE, NULL);
 
-       ki->blocks = g_object_ref (bs);
-       ki->rootid = root;
+       ki->priv->blocks = g_object_ref (bs);
+       ki->priv->rootid = root;
 
-       ki->root_block = camel_block_file_get_block (bs, ki->rootid);
-       if (ki->root_block == NULL) {
+       ki->priv->root_block = camel_block_file_get_block (bs, ki->priv->rootid);
+       if (ki->priv->root_block == NULL) {
                g_object_unref (ki);
                ki = NULL;
        } else {
-               camel_block_file_detach_block (bs, ki->root_block);
-               ki->root = (CamelKeyRootBlock *) &ki->root_block->data;
+               camel_block_file_detach_block (bs, ki->priv->root_block);
+               ki->priv->root = (CamelKeyRootBlock *) &ki->priv->root_block->data;
 
                k (printf ("Opening key index\n"));
-               k (printf (" first %u\n last %u\n free %u\n", ki->root->first, ki->root->last, 
ki->root->free));
+               k (printf (" first %u\n last %u\n free %u\n", ki->priv->root->first, ki->priv->root->last, 
ki->priv->root->free));
        }
 
        return ki;
@@ -702,7 +715,7 @@ camel_key_table_sync (CamelKeyTable *ki)
 #ifdef SYNC_UPDATES
        return 0;
 #else
-       return camel_block_file_sync_block (ki->blocks, ki->root_block);
+       return camel_block_file_sync_block (ki->priv->blocks, ki->priv->root_block);
 #endif
 }
 
@@ -728,16 +741,16 @@ camel_key_table_add (CamelKeyTable *ki,
 
        CAMEL_KEY_TABLE_LOCK (ki, lock);
 
-       if (ki->root->last == 0) {
-               last = camel_block_file_new_block (ki->blocks);
+       if (ki->priv->root->last == 0) {
+               last = camel_block_file_new_block (ki->priv->blocks);
                if (last == NULL)
                        goto fail;
-               ki->root->last = ki->root->first = last->id;
-               camel_block_file_touch_block (ki->blocks, ki->root_block);
-               k (printf ("adding first block, first = %u\n", ki->root->first));
+               ki->priv->root->last = ki->priv->root->first = last->id;
+               camel_block_file_touch_block (ki->priv->blocks, ki->priv->root_block);
+               k (printf ("adding first block, first = %u\n", ki->priv->root->first));
        } else {
                last = camel_block_file_get_block (
-                       ki->blocks, ki->root->last);
+                       ki->priv->blocks, ki->priv->root->last);
                if (last == NULL)
                        goto fail;
        }
@@ -756,18 +769,18 @@ camel_key_table_add (CamelKeyTable *ki,
                        sizeof (kblast->u.keydata) - kblast->u.keys[kblast->used - 1].offset,
                        left, len));
                if (left < len) {
-                       next = camel_block_file_new_block (ki->blocks);
+                       next = camel_block_file_new_block (ki->priv->blocks);
                        if (next == NULL) {
-                               camel_block_file_unref_block (ki->blocks, last);
+                               camel_block_file_unref_block (ki->priv->blocks, last);
                                goto fail;
                        }
                        kbnext = (CamelKeyBlock *) &next->data;
                        kblast->next = next->id;
-                       ki->root->last = next->id;
-                       d (printf ("adding new block, first = %u, last = %u\n", ki->root->first, 
ki->root->last));
-                       camel_block_file_touch_block (ki->blocks, ki->root_block);
-                       camel_block_file_touch_block (ki->blocks, last);
-                       camel_block_file_unref_block (ki->blocks, last);
+                       ki->priv->root->last = next->id;
+                       d (printf ("adding new block, first = %u, last = %u\n", ki->priv->root->first, 
ki->priv->root->last));
+                       camel_block_file_touch_block (ki->priv->blocks, ki->priv->root_block);
+                       camel_block_file_touch_block (ki->priv->blocks, last);
+                       camel_block_file_unref_block (ki->priv->blocks, last);
                        kblast = kbnext;
                        last = next;
                }
@@ -793,11 +806,11 @@ camel_key_table_add (CamelKeyTable *ki,
                goto fail;
        }
 
-       camel_block_file_touch_block (ki->blocks, last);
-       camel_block_file_unref_block (ki->blocks, last);
+       camel_block_file_touch_block (ki->priv->blocks, last);
+       camel_block_file_unref_block (ki->priv->blocks, last);
 
 #ifdef SYNC_UPDATES
-       camel_block_file_sync_block (ki->blocks, ki->root_block);
+       camel_block_file_sync_block (ki->priv->blocks, ki->priv->root_block);
 #endif
 fail:
        CAMEL_KEY_TABLE_UNLOCK (ki, lock);
@@ -821,7 +834,7 @@ camel_key_table_set_data (CamelKeyTable *ki,
        blockid = keyid & (~(CAMEL_BLOCK_SIZE - 1));
        index = keyid & (CAMEL_BLOCK_SIZE - 1);
 
-       bl = camel_block_file_get_block (ki->blocks, blockid);
+       bl = camel_block_file_get_block (ki->priv->blocks, blockid);
        if (bl == NULL)
                return FALSE;
        kb = (CamelKeyBlock *) &bl->data;
@@ -830,12 +843,12 @@ camel_key_table_set_data (CamelKeyTable *ki,
 
        if (kb->u.keys[index].data != data) {
                kb->u.keys[index].data = data;
-               camel_block_file_touch_block (ki->blocks, bl);
+               camel_block_file_touch_block (ki->priv->blocks, bl);
        }
 
        CAMEL_KEY_TABLE_UNLOCK (ki, lock);
 
-       camel_block_file_unref_block (ki->blocks, bl);
+       camel_block_file_unref_block (ki->priv->blocks, bl);
 
        return TRUE;
 }
@@ -858,7 +871,7 @@ camel_key_table_set_flags (CamelKeyTable *ki,
        blockid = keyid & (~(CAMEL_BLOCK_SIZE - 1));
        index = keyid & (CAMEL_BLOCK_SIZE - 1);
 
-       bl = camel_block_file_get_block (ki->blocks, blockid);
+       bl = camel_block_file_get_block (ki->priv->blocks, blockid);
        if (bl == NULL)
                return FALSE;
        kb = (CamelKeyBlock *) &bl->data;
@@ -873,12 +886,12 @@ camel_key_table_set_flags (CamelKeyTable *ki,
        old = kb->u.keys[index].flags;
        if ((old & set) != (flags & set)) {
                kb->u.keys[index].flags = (old & (~set)) | (flags & set);
-               camel_block_file_touch_block (ki->blocks, bl);
+               camel_block_file_touch_block (ki->priv->blocks, bl);
        }
 
        CAMEL_KEY_TABLE_UNLOCK (ki, lock);
 
-       camel_block_file_unref_block (ki->blocks, bl);
+       camel_block_file_unref_block (ki->priv->blocks, bl);
 
        return TRUE;
 }
@@ -906,7 +919,7 @@ camel_key_table_lookup (CamelKeyTable *ki,
        blockid = keyid & (~(CAMEL_BLOCK_SIZE - 1));
        index = keyid & (CAMEL_BLOCK_SIZE - 1);
 
-       bl = camel_block_file_get_block (ki->blocks, blockid);
+       bl = camel_block_file_get_block (ki->priv->blocks, blockid);
        if (bl == NULL)
                return 0;
 
@@ -936,7 +949,7 @@ camel_key_table_lookup (CamelKeyTable *ki,
 
        CAMEL_KEY_TABLE_UNLOCK (ki, lock);
 
-       camel_block_file_unref_block (ki->blocks, bl);
+       camel_block_file_unref_block (ki->priv->blocks, bl);
 
        return blockid;
 }
@@ -966,7 +979,7 @@ camel_key_table_next (CamelKeyTable *ki,
        CAMEL_KEY_TABLE_LOCK (ki, lock);
 
        if (next == 0) {
-               next = ki->root->first;
+               next = ki->priv->root->first;
                if (next == 0) {
                        CAMEL_KEY_TABLE_UNLOCK (ki, lock);
                        return 0;
@@ -978,7 +991,7 @@ camel_key_table_next (CamelKeyTable *ki,
                blockid = next & (~(CAMEL_BLOCK_SIZE - 1));
                index = next & (CAMEL_BLOCK_SIZE - 1);
 
-               bl = camel_block_file_get_block (ki->blocks, blockid);
+               bl = camel_block_file_get_block (ki->priv->blocks, blockid);
                if (bl == NULL) {
                        CAMEL_KEY_TABLE_UNLOCK (ki, lock);
                        return 0;
@@ -990,7 +1003,7 @@ camel_key_table_next (CamelKeyTable *ki,
                if (index >= kb->used) {
                        /* FIXME: check for loops */
                        next = kb->next;
-                       camel_block_file_unref_block (ki->blocks, bl);
+                       camel_block_file_unref_block (ki->priv->blocks, bl);
                        bl = NULL;
                }
        } while (bl == NULL);
@@ -1004,7 +1017,7 @@ camel_key_table_next (CamelKeyTable *ki,
                 /*|| kb->u.keys[index-1].offset < kb->u.keydata - (gchar *)&kb->u.keys[kb->used]))) {*/
                 || kb->u.keys[index - 1].offset < sizeof (kb->u.keys[0]) * kb->used)))) {
                g_warning ("Block %u invalid scanning keys", bl->id);
-               camel_block_file_unref_block (ki->blocks, bl);
+               camel_block_file_unref_block (ki->priv->blocks, bl);
                CAMEL_KEY_TABLE_UNLOCK (ki, lock);
                return 0;
        }
@@ -1030,7 +1043,7 @@ camel_key_table_next (CamelKeyTable *ki,
 
        CAMEL_KEY_TABLE_UNLOCK (ki, lock);
 
-       camel_block_file_unref_block (ki->blocks, bl);
+       camel_block_file_unref_block (ki->priv->blocks, bl);
 
        return next;
 }
diff --git a/src/camel/camel-partition-table.h b/src/camel/camel-partition-table.h
index 8689d4b..50571fa 100644
--- a/src/camel/camel-partition-table.h
+++ b/src/camel/camel-partition-table.h
@@ -103,19 +103,13 @@ struct _CamelPartitionMapBlock {
 struct _CamelPartitionTable {
        GObject parent;
        CamelPartitionTablePrivate *priv;
-
-       CamelBlockFile *blocks;
-       camel_block_t rootid;
-
-       gint (*is_key)(CamelPartitionTable *cpi, const gchar *key, camel_key_t keyid, gpointer data);
-       gpointer is_key_data;
-
-       /* we keep a list of partition blocks active at all times */
-       GQueue partition;
 };
 
 struct _CamelPartitionTableClass {
        GObjectClass parent;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_partition_table_get_type  (void);
@@ -168,17 +162,13 @@ struct _CamelKeyBlock {
 struct _CamelKeyTable {
        GObject parent;
        CamelKeyTablePrivate *priv;
-
-       CamelBlockFile *blocks;
-
-       camel_block_t rootid;
-
-       CamelKeyRootBlock *root;
-       CamelBlock *root_block;
 };
 
 struct _CamelKeyTableClass {
        GObjectClass parent;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_key_table_get_type        (void);
diff --git a/src/camel/camel-provider.c b/src/camel/camel-provider.c
index 45d2611..c9c3bd1 100644
--- a/src/camel/camel-provider.c
+++ b/src/camel/camel-provider.c
@@ -47,6 +47,42 @@ static GRecMutex provider_lock;
 #define LOCK()         (g_rec_mutex_lock(&provider_lock))
 #define UNLOCK()       (g_rec_mutex_unlock(&provider_lock))
 
+CamelProvider *        camel_provider_copy             (CamelProvider *provider);
+void           camel_provider_free             (CamelProvider *provider);
+
+G_DEFINE_BOXED_TYPE (CamelProvider, camel_provider, camel_provider_copy, camel_provider_free)
+
+/*
+ * camel_provider_copy:
+ * @provider: a #CamelProvider to copy
+ *
+ * The function returns @provider, because providers are not allocated
+ * on heap. It's defined only for the introspection purposes.
+ *
+ * Returns: (transfer full): the @provider
+ *
+ * Since: 3.24
+ */
+CamelProvider *
+camel_provider_copy (CamelProvider *provider)
+{
+       return provider;
+}
+
+/*
+ * camel_provider_free:
+ * @provider: a #CamelProvider to copy
+ *
+ * The function does nothing, because providers are not allocated
+ * on heap. It's defined only for the introspection purposes.
+ *
+ * Since: 3.24
+ */
+void
+camel_provider_free (CamelProvider *provider)
+{
+}
+
 /* The vfolder provider is always available */
 static CamelProvider vee_provider = {
        "vfolder",
@@ -138,8 +174,8 @@ provider_setup (gpointer param)
                (GEqualFunc) camel_strcase_equal);
 
        vee_provider.object_types[CAMEL_PROVIDER_STORE] = CAMEL_TYPE_VEE_STORE;
-       vee_provider.url_hash = camel_url_hash;
-       vee_provider.url_equal = camel_url_equal;
+       vee_provider.url_hash = (GHashFunc) camel_url_hash;
+       vee_provider.url_equal = (GEqualFunc) camel_url_equal;
        provider_register_internal (&vee_provider);
 
        return NULL;
diff --git a/src/camel/camel-provider.h b/src/camel/camel-provider.h
index 0f09117..1a1d642 100644
--- a/src/camel/camel-provider.h
+++ b/src/camel/camel-provider.h
@@ -196,6 +196,9 @@ struct _CamelProviderModule {
        guint loaded : 1;
 };
 
+/* Introspection function */
+GType          camel_provider_get_type         (void) G_GNUC_CONST;
+
 void           camel_provider_init             (void);
 gboolean       camel_provider_load             (const gchar *path,
                                                 GError **error);
diff --git a/src/camel/camel-sasl-anonymous.c b/src/camel/camel-sasl-anonymous.c
index 62c1fe0..90ff488 100644
--- a/src/camel/camel-sasl-anonymous.c
+++ b/src/camel/camel-sasl-anonymous.c
@@ -26,6 +26,11 @@
 #include "camel-internet-address.h"
 #include "camel-sasl-anonymous.h"
 
+struct _CamelSaslAnonymousPrivate {
+       gchar *trace_info;
+       CamelSaslAnonTraceType type;
+};
+
 static CamelServiceAuthType sasl_anonymous_auth_type = {
        N_("Anonymous"),
 
@@ -42,7 +47,7 @@ sasl_anonymous_finalize (GObject *object)
 {
        CamelSaslAnonymous *sasl = CAMEL_SASL_ANONYMOUS (object);
 
-       g_free (sasl->trace_info);
+       g_free (sasl->priv->trace_info);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_sasl_anonymous_parent_class)->finalize (object);
@@ -66,33 +71,33 @@ sasl_anonymous_challenge_sync (CamelSasl *sasl,
                return NULL;
        }
 
-       switch (sasl_anon->type) {
+       switch (sasl_anon->priv->type) {
        case CAMEL_SASL_ANON_TRACE_EMAIL:
                cia = camel_internet_address_new ();
-               if (camel_internet_address_add (cia, NULL, sasl_anon->trace_info) != 1) {
+               if (camel_internet_address_add (cia, NULL, sasl_anon->priv->trace_info) != 1) {
                        g_set_error (
                                error, CAMEL_SERVICE_ERROR,
                                CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
                                _("Invalid email address trace information:\n%s"),
-                               sasl_anon->trace_info);
+                               sasl_anon->priv->trace_info);
                        g_object_unref (cia);
                        return NULL;
                }
                g_object_unref (cia);
                ret = g_byte_array_new ();
-               g_byte_array_append (ret, (guint8 *) sasl_anon->trace_info, strlen (sasl_anon->trace_info));
+               g_byte_array_append (ret, (guint8 *) sasl_anon->priv->trace_info, strlen 
(sasl_anon->priv->trace_info));
                break;
        case CAMEL_SASL_ANON_TRACE_OPAQUE:
-               if (strchr (sasl_anon->trace_info, '@')) {
+               if (strchr (sasl_anon->priv->trace_info, '@')) {
                        g_set_error (
                                error, CAMEL_SERVICE_ERROR,
                                CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
                                _("Invalid opaque trace information:\n%s"),
-                               sasl_anon->trace_info);
+                               sasl_anon->priv->trace_info);
                        return NULL;
                }
                ret = g_byte_array_new ();
-               g_byte_array_append (ret, (guint8 *) sasl_anon->trace_info, strlen (sasl_anon->trace_info));
+               g_byte_array_append (ret, (guint8 *) sasl_anon->priv->trace_info, strlen 
(sasl_anon->priv->trace_info));
                break;
        case CAMEL_SASL_ANON_TRACE_EMPTY:
                ret = g_byte_array_new ();
@@ -102,7 +107,7 @@ sasl_anonymous_challenge_sync (CamelSasl *sasl,
                        error, CAMEL_SERVICE_ERROR,
                        CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
                        _("Invalid trace information:\n%s"),
-                       sasl_anon->trace_info);
+                       sasl_anon->priv->trace_info);
                return NULL;
        }
 
@@ -116,6 +121,8 @@ camel_sasl_anonymous_class_init (CamelSaslAnonymousClass *class)
        GObjectClass *object_class;
        CamelSaslClass *sasl_class;
 
+       g_type_class_add_private (class, sizeof (CamelSaslAnonymousPrivate));
+
        object_class = G_OBJECT_CLASS (class);
        object_class->finalize = sasl_anonymous_finalize;
 
@@ -127,6 +134,7 @@ camel_sasl_anonymous_class_init (CamelSaslAnonymousClass *class)
 static void
 camel_sasl_anonymous_init (CamelSaslAnonymous *sasl_anonymous)
 {
+       sasl_anonymous->priv = G_TYPE_INSTANCE_GET_PRIVATE (sasl_anonymous, CAMEL_TYPE_SASL_ANONYMOUS, 
CamelSaslAnonymousPrivate);
 }
 
 /**
@@ -148,8 +156,8 @@ camel_sasl_anonymous_new (CamelSaslAnonTraceType type,
                return NULL;
 
        sasl_anon = g_object_new (CAMEL_TYPE_SASL_ANONYMOUS, NULL);
-       sasl_anon->trace_info = g_strdup (trace_info);
-       sasl_anon->type = type;
+       sasl_anon->priv->trace_info = g_strdup (trace_info);
+       sasl_anon->priv->type = type;
 
        return CAMEL_SASL (sasl_anon);
 }
diff --git a/src/camel/camel-sasl-anonymous.h b/src/camel/camel-sasl-anonymous.h
index 56c570e..43041d3 100644
--- a/src/camel/camel-sasl-anonymous.h
+++ b/src/camel/camel-sasl-anonymous.h
@@ -50,16 +50,18 @@ G_BEGIN_DECLS
 
 typedef struct _CamelSaslAnonymous CamelSaslAnonymous;
 typedef struct _CamelSaslAnonymousClass CamelSaslAnonymousClass;
+typedef struct _CamelSaslAnonymousPrivate CamelSaslAnonymousPrivate;
 
 struct _CamelSaslAnonymous {
        CamelSasl parent;
-
-       gchar *trace_info;
-       CamelSaslAnonTraceType type;
+       CamelSaslAnonymousPrivate *priv;
 };
 
 struct _CamelSaslAnonymousClass {
        CamelSaslClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_sasl_anonymous_get_type (void);
diff --git a/src/camel/camel-sasl-cram-md5.h b/src/camel/camel-sasl-cram-md5.h
index 352c6f3..d885796 100644
--- a/src/camel/camel-sasl-cram-md5.h
+++ b/src/camel/camel-sasl-cram-md5.h
@@ -58,6 +58,9 @@ struct _CamelSaslCramMd5 {
 
 struct _CamelSaslCramMd5Class {
        CamelSaslClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_sasl_cram_md5_get_type (void);
diff --git a/src/camel/camel-sasl-digest-md5.h b/src/camel/camel-sasl-digest-md5.h
index 9e30fa4..1b5da6d 100644
--- a/src/camel/camel-sasl-digest-md5.h
+++ b/src/camel/camel-sasl-digest-md5.h
@@ -59,6 +59,9 @@ struct _CamelSaslDigestMd5 {
 
 struct _CamelSaslDigestMd5Class {
        CamelSaslClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_sasl_digest_md5_get_type (void);
diff --git a/src/camel/camel-sasl-gssapi.c b/src/camel/camel-sasl-gssapi.c
index 08d429d..536fea9 100644
--- a/src/camel/camel-sasl-gssapi.c
+++ b/src/camel/camel-sasl-gssapi.c
@@ -578,8 +578,8 @@ camel_sasl_gssapi_is_available (void)
 
 /**
  * camel_sasl_gssapi_override_host_and_user:
- * @override_host: Host name to use during challenge processing; can be %NULL
- * @override_user: User name to use during challenge processing; can be %NULL
+ * @override_host: (nullable): Host name to use during challenge processing; can be %NULL
+ * @override_user: (nullable): User name to use during challenge processing; can be %NULL
  *
  * Set host and user to use, instead of those in CamelService's settings.
  * It's both or none, aka either set both, or the settings values are used.
diff --git a/src/camel/camel-sasl-gssapi.h b/src/camel/camel-sasl-gssapi.h
index 7629fb3..4e87ba9 100644
--- a/src/camel/camel-sasl-gssapi.h
+++ b/src/camel/camel-sasl-gssapi.h
@@ -59,6 +59,9 @@ struct _CamelSaslGssapi {
 
 struct _CamelSaslGssapiClass {
        CamelSaslClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_sasl_gssapi_get_type      (void);
diff --git a/src/camel/camel-sasl-login.h b/src/camel/camel-sasl-login.h
index 41a53cf..6fab83b 100644
--- a/src/camel/camel-sasl-login.h
+++ b/src/camel/camel-sasl-login.h
@@ -58,6 +58,9 @@ struct _CamelSaslLogin {
 
 struct _CamelSaslLoginClass {
        CamelSaslClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_sasl_login_get_type (void);
diff --git a/src/camel/camel-sasl-ntlm.h b/src/camel/camel-sasl-ntlm.h
index 31d0630..095250f 100644
--- a/src/camel/camel-sasl-ntlm.h
+++ b/src/camel/camel-sasl-ntlm.h
@@ -57,6 +57,9 @@ struct _CamelSaslNTLM {
 
 struct _CamelSaslNTLMClass {
        CamelSaslClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_sasl_ntlm_get_type (void);
diff --git a/src/camel/camel-sasl-plain.h b/src/camel/camel-sasl-plain.h
index 8bdf7f1..f21c9d3 100644
--- a/src/camel/camel-sasl-plain.h
+++ b/src/camel/camel-sasl-plain.h
@@ -58,6 +58,9 @@ struct _CamelSaslPlain {
 
 struct _CamelSaslPlainClass {
        CamelSaslClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_sasl_plain_get_type (void);
diff --git a/src/camel/camel-sasl-popb4smtp.h b/src/camel/camel-sasl-popb4smtp.h
index a079d39..1fa6731 100644
--- a/src/camel/camel-sasl-popb4smtp.h
+++ b/src/camel/camel-sasl-popb4smtp.h
@@ -58,6 +58,9 @@ struct _CamelSaslPOPB4SMTP {
 
 struct _CamelSaslPOPB4SMTPClass {
        CamelSaslClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_sasl_popb4smtp_get_type (void);
diff --git a/src/camel/camel-sasl.c b/src/camel/camel-sasl.c
index 38a55ce..c903545 100644
--- a/src/camel/camel-sasl.c
+++ b/src/camel/camel-sasl.c
@@ -341,7 +341,7 @@ camel_sasl_init (CamelSasl *sasl)
  * @mechanism: the SASL mechanism
  * @service: the CamelService that will be using this SASL
  *
- * Returns: a new #CamelSasl object for the given @service_name,
+ * Returns: (nullable): a new #CamelSasl object for the given @service_name,
  * @mechanism, and @service, or %NULL if the mechanism is not
  * supported.
  **/
diff --git a/src/camel/camel-sasl.h b/src/camel/camel-sasl.h
index e167199..befc009 100644
--- a/src/camel/camel-sasl.h
+++ b/src/camel/camel-sasl.h
@@ -72,8 +72,8 @@ struct _CamelSaslClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots. */
-       gpointer reserved[4];
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_sasl_get_type             (void);
diff --git a/src/camel/camel-search-private.c b/src/camel/camel-search-private.c
index ced34e9..8a38f0f 100644
--- a/src/camel/camel-search-private.c
+++ b/src/camel/camel-search-private.c
@@ -46,6 +46,9 @@
  *
  * A small issue is that case-insenstivity won't work entirely correct
  * for utf8 strings. */
+/**
+ * camel_search_build_match_regex: (skip)
+ **/
 gint
 camel_search_build_match_regex (regex_t *pattern,
                                 camel_search_flags_t type,
@@ -500,6 +503,9 @@ camel_search_header_match (const gchar *value,
 
 /* Performs a 'slow' content-based match. */
 /* There is also an identical copy of this in camel-filter-search.c. */
+/**
+ * camel_search_message_body_contains: (skip)
+ **/
 gboolean
 camel_search_message_body_contains (CamelDataWrapper *object,
                                     regex_t *pattern)
@@ -524,8 +530,8 @@ camel_search_message_body_contains (CamelDataWrapper *object,
        } else if (CAMEL_IS_MIME_MESSAGE (containee)) {
                /* For messages we only look at its contents. */
                truth = camel_search_message_body_contains ((CamelDataWrapper *) containee, pattern);
-       } else if (camel_content_type_is (CAMEL_DATA_WRAPPER (containee)->mime_type, "text", "*")
-               || camel_content_type_is (CAMEL_DATA_WRAPPER (containee)->mime_type, "x-evolution", 
"evolution-rss-feed")) {
+       } else if (camel_content_type_is (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER 
(containee)), "text", "*")
+               || camel_content_type_is (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER 
(containee)), "x-evolution", "evolution-rss-feed")) {
                /* For all other text parts we look
                 * inside, otherwise we don't care. */
                CamelStream *stream;
@@ -535,7 +541,7 @@ camel_search_message_body_contains (CamelDataWrapper *object,
                byte_array = g_byte_array_new ();
                stream = camel_stream_mem_new_with_byte_array (byte_array);
 
-               charset = camel_content_type_param (CAMEL_DATA_WRAPPER (containee)->mime_type, "charset");
+               charset = camel_content_type_param (camel_data_wrapper_get_mime_type_field 
(CAMEL_DATA_WRAPPER (containee)), "charset");
                if (charset && *charset) {
                        CamelMimeFilter *filter = camel_mime_filter_charset_new (charset, "UTF-8");
                        if (filter) {
@@ -831,9 +837,9 @@ camel_search_get_all_headers_decoded (CamelMimeMessage *message)
 {
        CamelMedium *medium;
        GString *str;
-       GArray *headers;
+       const CamelNameValueArray *headers;
        const gchar *default_charset;
-       guint ii;
+       guint ii, length;
 
        g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
 
@@ -845,19 +851,23 @@ camel_search_get_all_headers_decoded (CamelMimeMessage *message)
        default_charset = camel_search_get_default_charset_from_message (message);
        str = g_string_new ("");
 
-       for (ii = 0; ii < headers->len; ii++) {
-               CamelMediumHeader *header;
+       length = camel_name_value_array_get_length (headers);
+       for (ii = 0; ii < length; ii++) {
                gchar *content;
+               const gchar *header_name = NULL;
+               const gchar *header_value = NULL;
 
-               header = &g_array_index (headers, CamelMediumHeader, ii);
-               if (!header->value)
+               if (!camel_name_value_array_get (headers, ii, &header_name, &header_value))
                        continue;
 
-               content = camel_search_get_header_decoded (header->name, header->value, default_charset);
+               if (!header_name || !header_value)
+                       continue;
+
+               content = camel_search_get_header_decoded (header_name, header_value, default_charset);
                if (!content)
                        continue;
 
-               g_string_append (str, header->name);
+               g_string_append (str, header_name);
                if (isspace (content[0]))
                        g_string_append (str, ":");
                else
@@ -868,7 +878,5 @@ camel_search_get_all_headers_decoded (CamelMimeMessage *message)
                g_free (content);
        }
 
-       camel_medium_free_headers (medium, headers);
-
        return g_string_free (str, FALSE);
 }
diff --git a/src/camel/camel-service.c b/src/camel/camel-service.c
index cc4cac9..e53f7d1 100644
--- a/src/camel/camel-service.c
+++ b/src/camel/camel-service.c
@@ -35,8 +35,8 @@
 #include "camel-network-service.h"
 #include "camel-network-settings.h"
 #include "camel-operation.h"
-#include "camel-service.h"
 #include "camel-session.h"
+#include "camel-service.h"
 
 #define d(x)
 #define w(x)
@@ -121,6 +121,7 @@ static void service_task_dispatch           (CamelService *service,
 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
        CamelService, camel_service, CAMEL_TYPE_OBJECT,
        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, camel_service_initable_init))
+G_DEFINE_BOXED_TYPE (CamelServiceAuthType, camel_service_auth_type, camel_service_auth_type_copy, 
camel_service_auth_type_free);
 
 static void
 async_context_free (AsyncContext *async_context)
@@ -1560,14 +1561,14 @@ camel_service_set_proxy_resolver (CamelService *service,
 
 /**
  * camel_service_ref_session:
- * @service: (type CamelService): a #CamelService
+ * @service: a #CamelService
  *
  * Returns the #CamelSession associated with the service.
  *
  * The returned #CamelSession is referenced for thread-safety.  Unreference
  * the #CamelSession with g_object_unref() when finished with it.
  *
- * Returns: (transfer full): the #CamelSession
+ * Returns: (transfer full) (type CamelSession): the #CamelSession
  *
  * Since: 3.8
  **/
@@ -2378,3 +2379,39 @@ camel_service_query_auth_types_finish (CamelService *service,
        return g_task_propagate_pointer (G_TASK (result), error);
 }
 
+/**
+ * camel_service_auth_type_copy:
+ * @service_auth_type: an #CamelServiceAuthType
+ *
+ * Copies the @service_auth_type struct.
+ * Does nothing and returns the given object in reality, needed for the introspection.
+ *
+ * Returns: (transfer full): the copy of @service_auth_type
+ *
+ * Since: 3.24
+ **/
+CamelServiceAuthType *
+camel_service_auth_type_copy (const CamelServiceAuthType *service_auth_type)
+{
+       /* This is needed for the introspection.
+        * In the reality, each CamelSasl subclass has a static reference of it.
+        */
+       return (CamelServiceAuthType *) service_auth_type;
+}
+
+/**
+ * camel_service_auth_type_free:
+ * @service_auth_type: an #CamelServiceAuthType
+ *
+ * Frees the @service_auth_type struct.
+ * Does nothing in reality, needed for the introspection.
+ *
+ * Since: 3.24
+ **/
+void
+camel_service_auth_type_free (CamelServiceAuthType *service_auth_type)
+{
+       /* This is needed for the introspection.
+        * In the reality, each CamelSasl subclass has a static reference of it.
+        */
+}
diff --git a/src/camel/camel-service.h b/src/camel/camel-service.h
index 5dd70f7..fe04223 100644
--- a/src/camel/camel-service.h
+++ b/src/camel/camel-service.h
@@ -51,6 +51,8 @@
 #define CAMEL_SERVICE_GET_CLASS(obj) \
        (G_TYPE_INSTANCE_GET_CLASS \
        ((obj), CAMEL_TYPE_SERVICE, CamelServiceClass))
+#define CAMEL_TYPE_SERVICE_AUTH_TYPE \
+       (camel_service_auth_type_get_type ())
 
 /**
  * CAMEL_SERVICE_ERROR:
@@ -113,8 +115,8 @@ struct _CamelServiceClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots. */
-       gpointer reserved[8];
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 /* query_auth_types returns a GList of these */
@@ -216,6 +218,11 @@ GList *            camel_service_query_auth_types_finish
                                                 GAsyncResult *result,
                                                 GError **error);
 
+GType          camel_service_auth_type_get_type(void);
+CamelServiceAuthType *
+               camel_service_auth_type_copy    (const CamelServiceAuthType *service_auth_type);
+void           camel_service_auth_type_free    (CamelServiceAuthType *service_auth_type);
+
 G_END_DECLS
 
 #endif /* CAMEL_SERVICE_H */
diff --git a/src/camel/camel-session.c b/src/camel/camel-session.c
index 1c4fcc5..c7d76b9 100644
--- a/src/camel/camel-session.c
+++ b/src/camel/camel-session.c
@@ -704,7 +704,7 @@ camel_session_class_init (CamelSessionClass *class)
                NULL, NULL, NULL,
                G_TYPE_NONE, 2,
                G_TYPE_CANCELLABLE,
-               G_TYPE_POINTER);
+               G_TYPE_ERROR);
 
        /**
         * CamelSession::user-alert:
diff --git a/src/camel/camel-session.h b/src/camel/camel-session.h
index e837e0f..1745ac6 100644
--- a/src/camel/camel-session.h
+++ b/src/camel/camel-session.h
@@ -132,8 +132,8 @@ struct _CamelSessionClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots for methods. */
-       gpointer reserved_for_methods[4];
+       /* Padding for future expansion */
+       gpointer reserved_methods[20];
 
        /* Signals */
        void            (*job_started)          (CamelSession *session,
@@ -145,6 +145,9 @@ struct _CamelSessionClass {
                                                 CamelService *service,
                                                 CamelSessionAlertType type,
                                                 const gchar *message);
+
+       /* Padding for future expansion */
+       gpointer reserved_signals[20];
 };
 
 GType          camel_session_get_type          (void);
diff --git a/src/camel/camel-settings.h b/src/camel/camel-settings.h
index 3781b82..c8dcd89 100644
--- a/src/camel/camel-settings.h
+++ b/src/camel/camel-settings.h
@@ -72,6 +72,9 @@ struct _CamelSettingsClass {
        CamelSettings * (*clone)                (CamelSettings *settings);
        gboolean        (*equal)                (CamelSettings *settings_a,
                                                 CamelSettings *settings_b);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_settings_get_type         (void) G_GNUC_CONST;
diff --git a/src/camel/camel-sexp.c b/src/camel/camel-sexp.c
index 41664c4..5487d79 100644
--- a/src/camel/camel-sexp.c
+++ b/src/camel/camel-sexp.c
@@ -91,6 +91,21 @@
 #define r(x)                   /* run debug */
 #define d(x)                   /* general debug */
 
+struct _CamelSExpPrivate {
+       GScanner *scanner;      /* for parsing text version */
+       CamelSExpTerm *tree;    /* root of expression tree */
+
+       /* private stuff */
+       jmp_buf failenv;
+       gchar *error;
+       GSList *operators;
+
+       /* TODO: may also need a pool allocator for term strings,
+        *       so we dont lose them in error conditions? */
+       CamelMemChunk *term_chunks;
+       CamelMemChunk *result_chunks;
+};
+
 G_DEFINE_TYPE (CamelSExp, camel_sexp, G_TYPE_OBJECT)
 
 static CamelSExpTerm * parse_list (CamelSExp *sexp, gint gotbrace);
@@ -159,17 +174,17 @@ camel_sexp_fatal_error (CamelSExp *sexp,
 {
        va_list args;
 
-       /* jumps back to the caller of sexp->failenv,
+       /* jumps back to the caller of sexp->priv->failenv,
         * only to be called from inside a callback */
 
-       if (sexp->error)
-               g_free (sexp->error);
+       if (sexp->priv->error)
+               g_free (sexp->priv->error);
 
        va_start (args, why);
-       sexp->error = g_strdup_vprintf (why, args);
+       sexp->priv->error = g_strdup_vprintf (why, args);
        va_end (args);
 
-       longjmp (sexp->failenv, 1);
+       longjmp (sexp->priv->failenv, 1);
 }
 
 /**
@@ -180,11 +195,11 @@ camel_sexp_fatal_error (CamelSExp *sexp,
 const gchar *
 camel_sexp_error (CamelSExp *sexp)
 {
-       return sexp->error;
+       return sexp->priv->error;
 }
 
 /**
- * camel_sexp_result_new:
+ * camel_sexp_result_new: (skip)
  *
  * Since: 3.4
  **/
@@ -194,7 +209,7 @@ camel_sexp_result_new (CamelSExp *sexp,
 {
        CamelSExpResult *result;
 
-       result = camel_memchunk_alloc0 (sexp->result_chunks);
+       result = camel_memchunk_alloc0 (sexp->priv->result_chunks);
        result->type = type;
        result->occuring_start = 0;
        result->occuring_end = _TIME_MAX;
@@ -231,7 +246,7 @@ camel_sexp_result_free (CamelSExp *sexp,
        default:
                g_return_if_reached ();
        }
-       camel_memchunk_free (sexp->result_chunks, term);
+       camel_memchunk_free (sexp->priv->result_chunks, term);
 }
 
 /**
@@ -301,7 +316,7 @@ term_eval_and (CamelSExp *sexp,
        result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
 
        oper = "AND";
-       sexp->operators = g_slist_prepend (sexp->operators, (gpointer) oper);
+       sexp->priv->operators = g_slist_prepend (sexp->priv->operators, (gpointer) oper);
 
        for (i = 0; bool && i < argc; i++) {
                r1 = camel_sexp_term_eval (sexp, argv[i]);
@@ -343,7 +358,7 @@ term_eval_and (CamelSExp *sexp,
        }
 
        g_hash_table_destroy (ht);
-       sexp->operators = g_slist_remove (sexp->operators, oper);
+       sexp->priv->operators = g_slist_remove (sexp->priv->operators, oper);
 
        return result;
 }
@@ -365,7 +380,7 @@ term_eval_or (CamelSExp *sexp,
        r (printf ("(or \n"));
 
        oper = "OR";
-       sexp->operators = g_slist_prepend (sexp->operators, (gpointer) oper);
+       sexp->priv->operators = g_slist_prepend (sexp->priv->operators, (gpointer) oper);
 
        result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
 
@@ -405,7 +420,7 @@ term_eval_or (CamelSExp *sexp,
        }
        g_hash_table_destroy (ht);
 
-       sexp->operators = g_slist_remove (sexp->operators, oper);
+       sexp->priv->operators = g_slist_remove (sexp->priv->operators, oper);
        return result;
 }
 
@@ -753,7 +768,7 @@ term_eval_begin (CamelSExp *sexp,
 }
 
 /**
- * camel_sexp_term_eval:
+ * camel_sexp_term_eval: (skip)
  *
  * Since: 3.4
  **/
@@ -1195,7 +1210,7 @@ parse_term_new (CamelSExp *sexp,
 {
        CamelSExpTerm *term;
 
-       term = camel_memchunk_alloc0 (sexp->term_chunks);
+       term = camel_memchunk_alloc0 (sexp->priv->term_chunks);
        term->type = type;
 
        return term;
@@ -1233,7 +1248,7 @@ parse_term_free (CamelSExp *sexp,
        default:
                printf ("parse_term_free: unknown type: %d\n", term->type);
        }
-       camel_memchunk_free (sexp->term_chunks, term);
+       camel_memchunk_free (sexp->priv->term_chunks, term);
 }
 
 static CamelSExpTerm **
@@ -1243,7 +1258,7 @@ parse_values (CamelSExp *sexp,
        gint token;
        CamelSExpTerm **terms;
        gint i, size = 0;
-       GScanner *gs = sexp->scanner;
+       GScanner *gs = sexp->priv->scanner;
        GSList *list = NULL, *l;
 
        p (printf ("parsing values\n"));
@@ -1273,7 +1288,7 @@ parse_values (CamelSExp *sexp,
 }
 
 /**
- * camel_sexp_parse_value:
+ * camel_sexp_parse_value: (skip)
  *
  * Since: 3.4
  **/
@@ -1288,7 +1303,7 @@ parse_value (CamelSExp *sexp)
 {
        gint token, negative = FALSE;
        CamelSExpTerm *term = NULL;
-       GScanner *gs = sexp->scanner;
+       GScanner *gs = sexp->priv->scanner;
        CamelSExpSymbol *sym;
 
        p (printf ("parsing value\n"));
@@ -1382,7 +1397,7 @@ parse_list (CamelSExp *sexp,
 {
        gint token;
        CamelSExpTerm *term = NULL;
-       GScanner *gs = sexp->scanner;
+       GScanner *gs = sexp->priv->scanner;
 
        p (printf ("parsing list\n"));
        if (gotbrace)
@@ -1449,19 +1464,19 @@ camel_sexp_finalize (GObject *object)
 {
        CamelSExp *sexp = (CamelSExp *) object;
 
-       if (sexp->tree) {
-               parse_term_free (sexp, sexp->tree);
-               sexp->tree = NULL;
+       if (sexp->priv->tree) {
+               parse_term_free (sexp, sexp->priv->tree);
+               sexp->priv->tree = NULL;
        }
 
-       camel_memchunk_destroy (sexp->term_chunks);
-       camel_memchunk_destroy (sexp->result_chunks);
+       camel_memchunk_destroy (sexp->priv->term_chunks);
+       camel_memchunk_destroy (sexp->priv->result_chunks);
 
-       g_scanner_scope_foreach_symbol (sexp->scanner, 0, free_symbol, NULL);
-       g_scanner_destroy (sexp->scanner);
+       g_scanner_scope_foreach_symbol (sexp->priv->scanner, 0, free_symbol, NULL);
+       g_scanner_destroy (sexp->priv->scanner);
 
-       g_free (sexp->error);
-       sexp->error = NULL;
+       g_free (sexp->priv->error);
+       sexp->priv->error = NULL;
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_sexp_parent_class)->finalize (object);
@@ -1472,6 +1487,8 @@ camel_sexp_class_init (CamelSExpClass *class)
 {
        GObjectClass *object_class;
 
+       g_type_class_add_private (class, sizeof (CamelSExpPrivate));
+
        object_class = G_OBJECT_CLASS (class);
        object_class->finalize = camel_sexp_finalize;
 }
@@ -1503,9 +1520,11 @@ camel_sexp_init (CamelSExp *sexp)
 {
        gint i;
 
-       sexp->scanner = g_scanner_new (&scanner_config);
-       sexp->term_chunks = camel_memchunk_new (16, sizeof (CamelSExpTerm));
-       sexp->result_chunks = camel_memchunk_new (16, sizeof (CamelSExpResult));
+       sexp->priv = G_TYPE_INSTANCE_GET_PRIVATE (sexp, CAMEL_TYPE_SEXP, CamelSExpPrivate);
+
+       sexp->priv->scanner = g_scanner_new (&scanner_config);
+       sexp->priv->term_chunks = camel_memchunk_new (16, sizeof (CamelSExpTerm));
+       sexp->priv->result_chunks = camel_memchunk_new (16, sizeof (CamelSExpResult));
 
        /* load in builtin symbols? */
        for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
@@ -1560,7 +1579,7 @@ camel_sexp_add_function (CamelSExp *sexp,
        sym->type = CAMEL_SEXP_TERM_FUNC;
        sym->data = user_data;
 
-       g_scanner_scope_add_symbol (sexp->scanner, scope, sym->name, sym);
+       g_scanner_scope_add_symbol (sexp->priv->scanner, scope, sym->name, sym);
 }
 
 /**
@@ -1589,7 +1608,7 @@ camel_sexp_add_ifunction (CamelSExp *sexp,
        sym->type = CAMEL_SEXP_TERM_IFUNC;
        sym->data = user_data;
 
-       g_scanner_scope_add_symbol (sexp->scanner, scope, sym->name, sym);
+       g_scanner_scope_add_symbol (sexp->priv->scanner, scope, sym->name, sym);
 }
 
 /**
@@ -1613,7 +1632,7 @@ camel_sexp_add_variable (CamelSExp *sexp,
        sym->type = CAMEL_SEXP_TERM_VAR;
        sym->data = value;
 
-       g_scanner_scope_add_symbol (sexp->scanner, scope, sym->name, sym);
+       g_scanner_scope_add_symbol (sexp->priv->scanner, scope, sym->name, sym);
 }
 
 /**
@@ -1632,10 +1651,10 @@ camel_sexp_remove_symbol (CamelSExp *sexp,
        g_return_if_fail (CAMEL_IS_SEXP (sexp));
        g_return_if_fail (name != NULL);
 
-       oldscope = g_scanner_set_scope (sexp->scanner, scope);
-       sym = g_scanner_lookup_symbol (sexp->scanner, name);
-       g_scanner_scope_remove_symbol (sexp->scanner, scope, name);
-       g_scanner_set_scope (sexp->scanner, oldscope);
+       oldscope = g_scanner_set_scope (sexp->priv->scanner, scope);
+       sym = g_scanner_lookup_symbol (sexp->priv->scanner, name);
+       g_scanner_scope_remove_symbol (sexp->priv->scanner, scope, name);
+       g_scanner_set_scope (sexp->priv->scanner, oldscope);
        if (sym != NULL) {
                g_free (sym->name);
                g_free (sym);
@@ -1653,7 +1672,7 @@ camel_sexp_set_scope (CamelSExp *sexp,
 {
        g_return_val_if_fail (CAMEL_IS_SEXP (sexp), 0);
 
-       return g_scanner_set_scope (sexp->scanner, scope);
+       return g_scanner_set_scope (sexp->priv->scanner, scope);
 }
 
 /**
@@ -1669,7 +1688,7 @@ camel_sexp_input_text (CamelSExp *sexp,
        g_return_if_fail (CAMEL_IS_SEXP (sexp));
        g_return_if_fail (text != NULL);
 
-       g_scanner_input_text (sexp->scanner, text, len);
+       g_scanner_input_text (sexp->priv->scanner, text, len);
 }
 
 /**
@@ -1683,7 +1702,7 @@ camel_sexp_input_file (CamelSExp *sexp,
 {
        g_return_if_fail (CAMEL_IS_SEXP (sexp));
 
-       g_scanner_input_file (sexp->scanner, fd);
+       g_scanner_input_file (sexp->priv->scanner, fd);
 }
 
 /**
@@ -1696,21 +1715,21 @@ camel_sexp_parse (CamelSExp *sexp)
 {
        g_return_val_if_fail (CAMEL_IS_SEXP (sexp), -1);
 
-       if (setjmp (sexp->failenv)) {
-               g_warning ("Error in parsing: %s", sexp->error);
+       if (setjmp (sexp->priv->failenv)) {
+               g_warning ("Error in parsing: %s", sexp->priv->error);
                return -1;
        }
 
-       if (sexp->tree)
-               parse_term_free (sexp, sexp->tree);
+       if (sexp->priv->tree)
+               parse_term_free (sexp, sexp->priv->tree);
 
-       sexp->tree = parse_value (sexp);
+       sexp->priv->tree = parse_value (sexp);
 
        return 0;
 }
 
 /**
- * camel_sexp_eval:
+ * camel_sexp_eval: (skip)
  *
  * Since: 3.4
  **/
@@ -1718,14 +1737,14 @@ CamelSExpResult *
 camel_sexp_eval (CamelSExp *sexp)
 {
        g_return_val_if_fail (CAMEL_IS_SEXP (sexp), NULL);
-       g_return_val_if_fail (sexp->tree != NULL, NULL);
+       g_return_val_if_fail (sexp->priv->tree != NULL, NULL);
 
-       if (setjmp (sexp->failenv)) {
-               g_warning ("Error in execution: %s", sexp->error);
+       if (setjmp (sexp->priv->failenv)) {
+               g_warning ("Error in execution: %s", sexp->priv->error);
                return NULL;
        }
 
-       return camel_sexp_term_eval (sexp, sexp->tree);
+       return camel_sexp_term_eval (sexp, sexp->priv->tree);
 }
 
 /**
@@ -1746,19 +1765,19 @@ camel_sexp_evaluate_occur_times (CamelSExp *sexp,
        CamelSExpResult *result;
        gboolean generator;
        g_return_val_if_fail (CAMEL_IS_SEXP (sexp), FALSE);
-       g_return_val_if_fail (sexp->tree != NULL, FALSE);
+       g_return_val_if_fail (sexp->priv->tree != NULL, FALSE);
        g_return_val_if_fail (start != NULL, FALSE);
        g_return_val_if_fail (end != NULL, FALSE);
 
        *start = *end = -1;
 
-       if (setjmp (sexp->failenv)) {
-               g_warning ("Error in execution: %s", sexp->error);
+       if (setjmp (sexp->priv->failenv)) {
+               g_warning ("Error in execution: %s", sexp->priv->error);
                return FALSE;
        }
 
        result = camel_sexp_term_evaluate_occur_times (
-               sexp, sexp->tree, start, end);
+               sexp, sexp->priv->tree, start, end);
        generator = result->time_generator;
 
        if (generator) {
@@ -1841,8 +1860,8 @@ main (gint argc,
        camel_sexp_input_text (sexp, t, t);
        camel_sexp_parse (sexp);
 
-       if (sexp->tree)
-               parse_dump_term (sexp->tree, 0);
+       if (sexp->priv->tree)
+               parse_dump_term (sexp->priv->tree, 0);
 
        result = camel_sexp_eval (sexp);
        if (result) {
diff --git a/src/camel/camel-sexp.h b/src/camel/camel-sexp.h
index e0d824a..f300568 100644
--- a/src/camel/camel-sexp.h
+++ b/src/camel/camel-sexp.h
@@ -51,6 +51,7 @@ G_BEGIN_DECLS
 
 typedef struct _CamelSExp CamelSExp;
 typedef struct _CamelSExpClass CamelSExpClass;
+typedef struct _CamelSExpPrivate CamelSExpPrivate;
 
 typedef struct _CamelSExpSymbol CamelSExpSymbol;
 typedef struct _CamelSExpResult CamelSExpResult;
@@ -91,6 +92,7 @@ struct _CamelSExpResult {
 
 /**
  * CamelSExpFunc:
+ * @argv: (inout) (array length=argc):
  *
  * Since: 3.4
  **/
@@ -98,17 +100,18 @@ typedef CamelSExpResult *
                        (*CamelSExpFunc)        (CamelSExp *sexp,
                                                 gint argc,
                                                 CamelSExpResult **argv,
-                                                gpointer data);
+                                                gpointer user_data);
 
 /**
  * CamelSExpIFunc:
+ * @argv: (inout) (array length=argc):
  *
  * Since: 3.4
  **/
 typedef CamelSExpResult *
                        (*CamelSExpIFunc)       (CamelSExp *sexp, gint argc,
                                                 CamelSExpTerm **argv,
-                                                gpointer data);
+                                                gpointer user_data);
 
 /**
  * CamelSExpTermType:
@@ -168,22 +171,14 @@ struct _CamelSExpTerm {
  **/
 struct _CamelSExp {
        GObject parent;
-       GScanner *scanner;      /* for parsing text version */
-       CamelSExpTerm *tree;    /* root of expression tree */
-
-       /* private stuff */
-       jmp_buf failenv;
-       gchar *error;
-       GSList *operators;
-
-       /* TODO: may also need a pool allocator for term strings,
-        *       so we dont lose them in error conditions? */
-       CamelMemChunk *term_chunks;
-       CamelMemChunk *result_chunks;
+       CamelSExpPrivate *priv;
 };
 
 struct _CamelSExpClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_sexp_get_type             (void) G_GNUC_CONST;
diff --git a/src/camel/camel-smime-context.c b/src/camel/camel-smime-context.c
index 1e18a1d..adc1689 100644
--- a/src/camel/camel-smime-context.c
+++ b/src/camel/camel-smime-context.c
@@ -871,7 +871,7 @@ smime_context_sign_sync (CamelCipherContext *context,
        g_seekable_seek (G_SEEKABLE (ostream), 0, G_SEEK_SET, NULL, NULL);
        camel_data_wrapper_construct_from_stream_sync (
                dw, ostream, cancellable, NULL);
-       dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;
+       camel_data_wrapper_set_encoding (dw, CAMEL_TRANSFER_ENCODING_BINARY);
 
        if (((CamelSMIMEContext *) context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN) {
                CamelMultipartSigned *mps;
@@ -951,7 +951,7 @@ smime_context_verify_sync (CamelCipherContext *context,
        class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
 
        dw = camel_medium_get_content ((CamelMedium *) ipart);
-       ct = dw->mime_type;
+       ct = camel_data_wrapper_get_mime_type_field (dw);
 
        /* FIXME: we should stream this to the decoder */
        buffer = g_byte_array_new ();
@@ -1175,7 +1175,7 @@ smime_context_encrypt_sync (CamelCipherContext *context,
        camel_data_wrapper_construct_from_stream_sync (
                dw, ostream, NULL, NULL);
        g_object_unref (ostream);
-       dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;
+       camel_data_wrapper_set_encoding (dw, CAMEL_TRANSFER_ENCODING_BINARY);
 
        ct = camel_content_type_new ("application", "x-pkcs7-mime");
        camel_content_type_set_param (ct, "name", "smime.p7m");
diff --git a/src/camel/camel-smime-context.h b/src/camel/camel-smime-context.h
index b1dd0e9..a24e8c2 100644
--- a/src/camel/camel-smime-context.h
+++ b/src/camel/camel-smime-context.h
@@ -71,6 +71,9 @@ struct _CamelSMIMEContext {
 
 struct _CamelSMIMEContextClass {
        CamelCipherContextClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_smime_context_get_type (void);
diff --git a/src/camel/camel-store-settings.h b/src/camel/camel-store-settings.h
index a743cb1..be1b32a 100644
--- a/src/camel/camel-store-settings.h
+++ b/src/camel/camel-store-settings.h
@@ -64,6 +64,9 @@ struct _CamelStoreSettings {
 
 struct _CamelStoreSettingsClass {
        CamelSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_store_settings_get_type   (void) G_GNUC_CONST;
diff --git a/src/camel/camel-store-summary.c b/src/camel/camel-store-summary.c
index 23527bc..85fda17 100644
--- a/src/camel/camel-store-summary.c
+++ b/src/camel/camel-store-summary.c
@@ -31,8 +31,8 @@
 #include <glib/gstdio.h>
 
 #include "camel-file-utils.h"
-#include "camel-store-summary.h"
 #include "camel-folder-summary.h"
+#include "camel-store-summary.h"
 #include "camel-url.h"
 #include "camel-win32.h"
 
@@ -66,6 +66,9 @@ struct _CamelStoreSummaryPrivate {
        GHashTable *folder_summaries; /* CamelFolderSummary->path; doesn't add reference to 
CamelFolderSummary */
 
        guint scheduled_save_id;
+
+       GPtrArray *folders;     /* CamelStoreInfo's */
+       GHashTable *folders_path; /* CamelStoreInfo's by path name */
 };
 
 G_DEFINE_TYPE (CamelStoreSummary, camel_store_summary, G_TYPE_OBJECT)
@@ -76,15 +79,15 @@ store_summary_finalize (GObject *object)
        CamelStoreSummary *summary = CAMEL_STORE_SUMMARY (object);
        guint ii;
 
-       for (ii = 0; ii < summary->folders->len; ii++) {
+       for (ii = 0; ii < summary->priv->folders->len; ii++) {
                CamelStoreInfo *info;
 
-               info = g_ptr_array_index (summary->folders, ii);
+               info = g_ptr_array_index (summary->priv->folders, ii);
                camel_store_summary_info_unref (summary, info);
        }
 
-       g_ptr_array_free (summary->folders, TRUE);
-       g_hash_table_destroy (summary->folders_path);
+       g_ptr_array_free (summary->priv->folders, TRUE);
+       g_hash_table_destroy (summary->priv->folders_path);
        g_hash_table_destroy (summary->priv->folder_summaries);
 
        g_free (summary->priv->summary_path);
@@ -240,10 +243,10 @@ store_summary_store_info_set_string (CamelStoreSummary *summary,
 {
        switch (type) {
        case CAMEL_STORE_INFO_PATH:
-               g_hash_table_remove (summary->folders_path, (gchar *) camel_store_info_path (summary, info));
+               g_hash_table_remove (summary->priv->folders_path, (gchar *) camel_store_info_path (summary, 
info));
                g_free (info->path);
                info->path = g_strdup (str);
-               g_hash_table_insert (summary->folders_path, (gchar *) camel_store_info_path (summary, info), 
info);
+               g_hash_table_insert (summary->priv->folders_path, (gchar *) camel_store_info_path (summary, 
info), info);
                summary->priv->dirty = TRUE;
                break;
        }
@@ -277,8 +280,8 @@ camel_store_summary_init (CamelStoreSummary *summary)
 
        summary->priv->version = CAMEL_STORE_SUMMARY_VERSION;
 
-       summary->folders = g_ptr_array_new ();
-       summary->folders_path = g_hash_table_new (g_str_hash, g_str_equal);
+       summary->priv->folders = g_ptr_array_new ();
+       summary->priv->folders_path = g_hash_table_new (g_str_hash, g_str_equal);
        summary->priv->folder_summaries = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
        summary->priv->scheduled_save_id = 0;
 
@@ -333,7 +336,7 @@ camel_store_summary_count (CamelStoreSummary *summary)
 {
        g_return_val_if_fail (CAMEL_IS_STORE_SUMMARY (summary), -1);
 
-       return summary->folders->len;
+       return summary->priv->folders->len;
 }
 
 /**
@@ -358,9 +361,9 @@ camel_store_summary_array (CamelStoreSummary *summary)
 
        g_rec_mutex_lock (&summary->priv->summary_lock);
 
-       res = g_ptr_array_sized_new (summary->folders->len);
-       for (i = 0; i < summary->folders->len; i++) {
-               info = g_ptr_array_index (summary->folders, i);
+       res = g_ptr_array_sized_new (summary->priv->folders->len);
+       for (i = 0; i < summary->priv->folders->len; i++) {
+               info = g_ptr_array_index (summary->priv->folders, i);
                camel_store_summary_info_ref (summary, info);
                g_ptr_array_add (res, info);
        }
@@ -393,7 +396,7 @@ camel_store_summary_array_free (CamelStoreSummary *summary,
 }
 
 /**
- * camel_store_summary_path:
+ * camel_store_summary_path: (skip)
  * @summary: a #CamelStoreSummary object
  * @path: path to the item
  *
@@ -416,7 +419,7 @@ camel_store_summary_path (CamelStoreSummary *summary,
 
        g_rec_mutex_lock (&summary->priv->summary_lock);
 
-       info = g_hash_table_lookup (summary->folders_path, path);
+       info = g_hash_table_lookup (summary->priv->folders_path, path);
 
        if (info != NULL)
                camel_store_summary_info_ref (summary, info);
@@ -552,9 +555,9 @@ camel_store_summary_save (CamelStoreSummary *summary)
 
        /* FIXME: Locking? */
 
-       count = summary->folders->len;
+       count = summary->priv->folders->len;
        for (i = 0; i < count; i++) {
-               info = summary->folders->pdata[i];
+               info = summary->priv->folders->pdata[i];
                class->store_info_save (summary, out, info);
        }
 
@@ -604,21 +607,21 @@ camel_store_summary_add (CamelStoreSummary *summary,
 
        g_rec_mutex_lock (&summary->priv->summary_lock);
 
-       g_ptr_array_add (summary->folders, info);
-       g_hash_table_insert (summary->folders_path, (gchar *) camel_store_info_path (summary, info), info);
+       g_ptr_array_add (summary->priv->folders, info);
+       g_hash_table_insert (summary->priv->folders_path, (gchar *) camel_store_info_path (summary, info), 
info);
        summary->priv->dirty = TRUE;
 
        g_rec_mutex_unlock (&summary->priv->summary_lock);
 }
 
 /**
- * camel_store_summary_add_from_path:
+ * camel_store_summary_add_from_path: (skip)
  * @summary: a #CamelStoreSummary object
  * @path: item path
  *
  * Build a new info record based on the name, and add it to the summary.
  *
- * Returns: the newly added record
+ * Returns: (transfer none): the newly added record
  **/
 CamelStoreInfo *
 camel_store_summary_add_from_path (CamelStoreSummary *summary,
@@ -631,7 +634,7 @@ camel_store_summary_add_from_path (CamelStoreSummary *summary,
 
        g_rec_mutex_lock (&summary->priv->summary_lock);
 
-       info = g_hash_table_lookup (summary->folders_path, path);
+       info = g_hash_table_lookup (summary->priv->folders_path, path);
        if (info != NULL) {
                g_warning ("Trying to add folder '%s' to summary that already has it", path);
                info = NULL;
@@ -643,8 +646,8 @@ camel_store_summary_add_from_path (CamelStoreSummary *summary,
 
                info = class->store_info_new (summary, path);
 
-               g_ptr_array_add (summary->folders, info);
-               g_hash_table_insert (summary->folders_path, (gchar *) camel_store_info_path (summary, info), 
info);
+               g_ptr_array_add (summary->priv->folders, info);
+               g_hash_table_insert (summary->priv->folders_path, (gchar *) camel_store_info_path (summary, 
info), info);
                summary->priv->dirty = TRUE;
        }
 
@@ -654,13 +657,13 @@ camel_store_summary_add_from_path (CamelStoreSummary *summary,
 }
 
 /**
- * camel_store_summary_info_ref:
+ * camel_store_summary_info_ref: (skip)
  * @summary: a #CamelStoreSummary object
  * @info: a #CamelStoreInfo
  *
  * Add an extra reference to @info.
  *
- * Returns: the @info argument
+ * Returns: (transfer full): the @info argument
  **/
 CamelStoreInfo *
 camel_store_summary_info_ref (CamelStoreSummary *summary,
@@ -731,8 +734,8 @@ camel_store_summary_remove (CamelStoreSummary *summary,
        g_return_if_fail (info != NULL);
 
        g_rec_mutex_lock (&summary->priv->summary_lock);
-       g_hash_table_remove (summary->folders_path, camel_store_info_path (summary, info));
-       g_ptr_array_remove (summary->folders, info);
+       g_hash_table_remove (summary->priv->folders_path, camel_store_info_path (summary, info));
+       g_ptr_array_remove (summary->priv->folders, info);
        summary->priv->dirty = TRUE;
        g_rec_mutex_unlock (&summary->priv->summary_lock);
 
@@ -757,7 +760,7 @@ camel_store_summary_remove_path (CamelStoreSummary *summary,
        g_return_if_fail (path != NULL);
 
        g_rec_mutex_lock (&summary->priv->summary_lock);
-       if (g_hash_table_lookup_extended (summary->folders_path, path, (gpointer) &oldpath, (gpointer) 
&oldinfo)) {
+       if (g_hash_table_lookup_extended (summary->priv->folders_path, path, (gpointer) &oldpath, (gpointer) 
&oldinfo)) {
                /* make sure it doesn't vanish while we're removing it */
                camel_store_summary_info_ref (summary, oldinfo);
                g_rec_mutex_unlock (&summary->priv->summary_lock);
@@ -769,7 +772,7 @@ camel_store_summary_remove_path (CamelStoreSummary *summary,
 }
 
 /**
- * camel_store_summary_info_new:
+ * camel_store_summary_info_new: (skip)
  * @summary: a #CamelStoreSummary object
  *
  * Allocate a new #CamelStoreInfo, suitable for adding to this
@@ -868,6 +871,27 @@ camel_store_info_name (CamelStoreSummary *summary,
        return (cp != NULL) ? cp + 1 : info->path;
 }
 
+/**
+ * camel_store_summary_sort:
+ * @summary: a #CamelStoreSummary
+ * @compare_func: (scope call) (closure user_data): a compare function
+ * @user_data: user data passed to the @compare_func
+ *
+ * Sorts the array of the folders using the @compare_func.
+ *
+ * Since: 3.24
+ **/
+void
+camel_store_summary_sort (CamelStoreSummary *summary,
+                         GCompareDataFunc compare_func,
+                         gpointer user_data)
+{
+       g_return_if_fail (CAMEL_IS_STORE_SUMMARY (summary));
+       g_return_if_fail (compare_func != NULL);
+
+       g_ptr_array_sort_with_data (summary->priv->folders, compare_func, user_data);
+}
+
 static gboolean
 store_summary_save_timeout (gpointer user_data)
 {
diff --git a/src/camel/camel-store-summary.h b/src/camel/camel-store-summary.h
index 68e1557..247439e 100644
--- a/src/camel/camel-store-summary.h
+++ b/src/camel/camel-store-summary.h
@@ -76,9 +76,6 @@ struct _CamelStoreInfo {
 struct _CamelStoreSummary {
        GObject parent;
        CamelStoreSummaryPrivate *priv;
-
-       GPtrArray *folders;     /* CamelStoreInfo's */
-       GHashTable *folders_path; /* CamelStoreInfo's by path name */
 };
 
 struct _CamelStoreSummaryClass {
@@ -112,6 +109,9 @@ struct _CamelStoreSummaryClass {
                                                 CamelStoreInfo *info,
                                                 gint type,
                                                 const gchar *value);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_store_summary_get_type    (void) G_GNUC_CONST;
@@ -171,14 +171,17 @@ const gchar *     camel_store_info_path           (CamelStoreSummary *summary,
                                                 CamelStoreInfo *info);
 const gchar *  camel_store_info_name           (CamelStoreSummary *summary,
                                                 CamelStoreInfo *info);
+void           camel_store_summary_sort        (CamelStoreSummary *summary,
+                                                GCompareDataFunc compare_func,
+                                                gpointer user_data);
 
 gboolean       camel_store_summary_connect_folder_summary
                                                (CamelStoreSummary *summary,
                                                 const gchar *path,
-                                                struct _CamelFolderSummary *folder_summary);
+                                                CamelFolderSummary *folder_summary);
 gboolean       camel_store_summary_disconnect_folder_summary
                                                (CamelStoreSummary *summary,
-                                                struct _CamelFolderSummary *folder_summary);
+                                                CamelFolderSummary *folder_summary);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-store.c b/src/camel/camel-store.c
index 4d4f112..98e470a 100644
--- a/src/camel/camel-store.c
+++ b/src/camel/camel-store.c
@@ -51,6 +51,11 @@ typedef struct _AsyncContext AsyncContext;
 typedef struct _SignalClosure SignalClosure;
 
 struct _CamelStorePrivate {
+       CamelDB *cdb;
+       CamelObjectBag *folders;
+       guint32 flags; /* bit-or of CamelStoreFlags */
+       guint32 permissions; /* bit-or of CamelStorePermissionFlags */
+
        GMutex signal_emission_lock;
        gboolean folder_info_stale_scheduled;
        volatile gint maintenance_lock;
@@ -238,45 +243,6 @@ ignore_no_such_table_exception (GError **error)
                g_clear_error (error);
 }
 
-/* deletes folder/removes it from the folder cache, if it's there */
-static void
-cs_delete_cached_folder (CamelStore *store,
-                         const gchar *folder_name)
-{
-       CamelFolder *folder;
-       CamelVeeFolder *vfolder;
-
-       if (store->folders == NULL)
-               return;
-
-       folder = camel_object_bag_get (store->folders, folder_name);
-       if (folder == NULL)
-               return;
-
-       if (store->flags & CAMEL_STORE_VTRASH) {
-               vfolder = camel_object_bag_get (
-                       store->folders, CAMEL_VTRASH_NAME);
-               if (vfolder != NULL) {
-                       camel_vee_folder_remove_folder (vfolder, folder, NULL);
-                       g_object_unref (vfolder);
-               }
-       }
-
-       if (store->flags & CAMEL_STORE_VJUNK) {
-               vfolder = camel_object_bag_get (
-                       store->folders, CAMEL_VJUNK_NAME);
-               if (vfolder != NULL) {
-                       camel_vee_folder_remove_folder (vfolder, folder, NULL);
-                       g_object_unref (vfolder);
-               }
-       }
-
-       camel_folder_delete (folder);
-
-       camel_object_bag_remove (store->folders, folder);
-       g_object_unref (folder);
-}
-
 static CamelFolder *
 store_get_special (CamelStore *store,
                    CamelVTrashFolderType type)
@@ -286,7 +252,7 @@ store_get_special (CamelStore *store,
        gint i;
 
        folder = camel_vtrash_folder_new (store, type);
-       folders = camel_object_bag_list (store->folders);
+       folders = camel_object_bag_list (store->priv->folders);
        for (i = 0; i < folders->len; i++) {
                if (!CAMEL_IS_VTRASH_FOLDER (folders->pdata[i]))
                        camel_vee_folder_add_folder ((CamelVeeFolder *) folder, (CamelFolder *) 
folders->pdata[i], NULL);
@@ -345,14 +311,10 @@ store_finalize (GObject *object)
 {
        CamelStore *store = CAMEL_STORE (object);
 
-       if (store->folders != NULL)
-               camel_object_bag_destroy (store->folders);
+       if (store->priv->folders != NULL)
+               camel_object_bag_destroy (store->priv->folders);
 
-       if (store->cdb_r != NULL) {
-               camel_db_close (store->cdb_r);
-               store->cdb_r = NULL;
-               store->cdb_w = NULL;
-       }
+       g_clear_object (&store->priv->cdb);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_store_parent_class)->finalize (object);
@@ -373,7 +335,7 @@ store_constructed (GObject *object)
        g_return_if_fail (class->hash_folder_name != NULL);
        g_return_if_fail (class->equal_folder_name != NULL);
 
-       store->folders = camel_object_bag_new (
+       store->priv->folders = camel_object_bag_new (
                class->hash_folder_name,
                class->equal_folder_name,
                (CamelCopyFunc) g_strdup, g_free);
@@ -480,7 +442,7 @@ store_synchronize_sync (CamelStore *store,
                camel_folder_info_free (root);
        } else {
                /* sync only folders opened until now */
-               folders = camel_object_bag_list (store->folders);
+               folders = camel_object_bag_list (store->priv->folders);
        }
 
        /* We don't sync any vFolders, that is used to update certain
@@ -489,8 +451,8 @@ store_synchronize_sync (CamelStore *store,
        for (ii = 0; ii < folders->len; ii++) {
                CamelFolder *folder = folders->pdata[ii];
 
-               if (folder->summary)
-                       camel_folder_summary_save_to_db (folder->summary, NULL);
+               if (camel_folder_get_folder_summary (folder))
+                       camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
 
                if (!CAMEL_IS_VEE_FOLDER (folder) && local_error == NULL) {
                        camel_folder_synchronize_sync (
@@ -544,7 +506,7 @@ store_initable_init (GInitable *initable,
                return FALSE;
 
        service = CAMEL_SERVICE (initable);
-       if ((store->flags & CAMEL_STORE_USE_CACHE_DIR) != 0)
+       if ((store->priv->flags & CAMEL_STORE_USE_CACHE_DIR) != 0)
                user_dir = camel_service_get_user_cache_dir (service);
        else
                user_dir = camel_service_get_user_data_dir (service);
@@ -559,18 +521,15 @@ store_initable_init (GInitable *initable,
 
        /* This is for reading from the store */
        filename = g_build_filename (user_dir, CAMEL_DB_FILE, NULL);
-       store->cdb_r = camel_db_open (filename, error);
+       store->priv->cdb = camel_db_new (filename, error);
        g_free (filename);
 
-       if (store->cdb_r == NULL)
+       if (store->priv->cdb == NULL)
                return FALSE;
 
-       if (camel_db_create_folders_table (store->cdb_r, error))
+       if (camel_db_create_folders_table (store->priv->cdb, error))
                return FALSE;
 
-       /* keep cb_w to not break the ABI */
-       store->cdb_w = store->cdb_r;
-
        return TRUE;
 }
 
@@ -606,7 +565,7 @@ camel_store_class_init (CamelStoreClass *class)
                G_STRUCT_OFFSET (CamelStoreClass, folder_created),
                NULL, NULL, NULL,
                G_TYPE_NONE, 1,
-               G_TYPE_POINTER);
+               CAMEL_TYPE_FOLDER_INFO);
 
        signals[FOLDER_DELETED] = g_signal_new (
                "folder-deleted",
@@ -615,7 +574,7 @@ camel_store_class_init (CamelStoreClass *class)
                G_STRUCT_OFFSET (CamelStoreClass, folder_deleted),
                NULL, NULL, NULL,
                G_TYPE_NONE, 1,
-               G_TYPE_POINTER);
+               CAMEL_TYPE_FOLDER_INFO);
 
        /**
         * CamelStore::folder-info-stale:
@@ -660,7 +619,7 @@ camel_store_class_init (CamelStoreClass *class)
                NULL, NULL, NULL,
                G_TYPE_NONE, 2,
                G_TYPE_STRING,
-               G_TYPE_POINTER);
+               CAMEL_TYPE_FOLDER_INFO);
 }
 
 static void
@@ -682,18 +641,146 @@ camel_store_init (CamelStore *store)
         *  - Include a virtual Trash folder.
         *  - Allow creating/deleting/renaming folders.
         */
-       store->flags =
+       store->priv->flags =
                CAMEL_STORE_VJUNK |
                CAMEL_STORE_VTRASH |
                CAMEL_STORE_CAN_EDIT_FOLDERS;
 
-       store->mode = CAMEL_STORE_READ | CAMEL_STORE_WRITE;
+       store->priv->permissions = CAMEL_STORE_READ | CAMEL_STORE_WRITE;
        store->priv->maintenance_lock = 0;
 }
 
 G_DEFINE_QUARK (camel-store-error-quark, camel_store_error)
 
 /**
+ * camel_store_get_db:
+ * @store: a #CamelStore
+ *
+ * Returns: (transfer none): A #CamelDB instance associated with this @store.
+ *
+ * Since: 3.24
+ **/
+CamelDB *
+camel_store_get_db (CamelStore *store)
+{
+       g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+       return store->priv->cdb;
+}
+
+/**
+ * camel_store_get_folders_bag:
+ * @store: a #CamelStore
+ *
+ * Returns: (transfer none): a #CamelObjectBag of opened #CamelFolder<!-- -->s
+ *
+ * Since: 3.24
+ **/
+CamelObjectBag *
+camel_store_get_folders_bag (CamelStore *store)
+{
+       g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+       return store->priv->folders;
+}
+
+/**
+ * camel_store_dup_opened_folders:
+ * @store: a #CamelStore
+ *
+ * Returns a #GPtrArray of all the opened folders for the @store. The caller owns
+ * both the array and the folder references, so to free the array use:
+ *
+ * <informalexample>
+ *   <programlisting>
+ *     g_ptr_array_foreach (array, (GFunc) g_object_unref, NULL);
+ *     g_ptr_array_free (array, TRUE);
+ *   </programlisting>
+ * </informalexample>
+ *
+ * Returns: (element-type CamelFolder) (transfer full): an array with all currently
+ *   opened folders for the @store.
+ *
+ * Since: 3.24
+ **/
+GPtrArray *
+camel_store_dup_opened_folders (CamelStore *store)
+{
+       g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+       g_return_val_if_fail (store->priv->folders != NULL, NULL);
+
+       return camel_object_bag_list (store->priv->folders);
+}
+
+/**
+ * camel_store_get_flags:
+ * @store: a #CamelStore
+ *
+ * Returns: bit-or of #CamelStoreFlags set for the @store
+ *
+ * Since: 3.24
+ **/
+guint32
+camel_store_get_flags (CamelStore *store)
+{
+       g_return_val_if_fail (CAMEL_IS_STORE (store), 0);
+
+       return store->priv->flags;
+}
+
+/**
+ * camel_store_set_flags:
+ * @store: a #CamelStore
+ * @flags: bit-or of #CamelStoreFlags
+ *
+ * Sets flags for the @store, a bit-or of #CamelStoreFlags.
+ *
+ * Since: 3.24
+ **/
+void
+camel_store_set_flags (CamelStore *store,
+                      guint32 flags)
+{
+       g_return_if_fail (CAMEL_IS_STORE (store));
+
+       store->priv->flags = flags;
+}
+
+/**
+ * camel_store_get_permissions:
+ * @store: a #CamelStore
+ *
+ * Returns: Permissions of the @store, a bit-or of #CamelStorePermissionFlags
+ *
+ * Since: 3.24
+ **/
+guint32
+camel_store_get_permissions (CamelStore *store)
+{
+       g_return_val_if_fail (CAMEL_IS_STORE (store), 0);
+
+       return store->priv->permissions;
+}
+
+/**
+ * camel_store_set_permissions:
+ * @store: a #CamelStore
+ * @permissions: permissions of the @store, a bit-or of #CamelStorePermissionFlags
+ *
+ * Sets permissions for the @store, a bit-or of #CamelStorePermissionFlags
+ *
+ * Since: 3.24
+ **/
+void
+camel_store_set_permissions (CamelStore *store,
+                            guint32 permissions)
+{
+       g_return_if_fail (CAMEL_IS_STORE (store));
+
+       store->priv->permissions = permissions;
+}
+
+/**
  * camel_store_folder_created:
  * @store: a #CamelStore
  * @folder_info: information about the created folder
@@ -1243,7 +1330,7 @@ camel_store_get_folder_sync (CamelStore *store,
 
 try_again:
        /* Try cache first. */
-       folder = camel_object_bag_reserve (store->folders, folder_name);
+       folder = camel_object_bag_reserve (store->priv->folders, folder_name);
        if (folder != NULL) {
                if ((flags & CAMEL_STORE_FOLDER_INFO_REFRESH) != 0)
                        camel_folder_prepare_content_refresh (folder);
@@ -1252,9 +1339,9 @@ try_again:
        }
 
        store_uses_vjunk =
-               ((store->flags & CAMEL_STORE_VJUNK) != 0);
+               ((store->priv->flags & CAMEL_STORE_VJUNK) != 0);
        store_uses_vtrash =
-               ((store->flags & CAMEL_STORE_VTRASH) != 0);
+               ((store->priv->flags & CAMEL_STORE_VTRASH) != 0);
        folder_name_is_vjunk =
                store_uses_vjunk &&
                (strcmp (folder_name, CAMEL_VJUNK_NAME) == 0);
@@ -1264,16 +1351,16 @@ try_again:
 
        if (flags & CAMEL_STORE_IS_MIGRATING) {
                if (folder_name_is_vtrash) {
-                       if (store->folders != NULL)
+                       if (store->priv->folders != NULL)
                                camel_object_bag_abort (
-                                       store->folders, folder_name);
+                                       store->priv->folders, folder_name);
                        return NULL;
                }
 
                if (folder_name_is_vjunk) {
-                       if (store->folders != NULL)
+                       if (store->priv->folders != NULL)
                                camel_object_bag_abort (
-                                       store->folders, folder_name);
+                                       store->priv->folders, folder_name);
                        return NULL;
                }
        }
@@ -1324,11 +1411,11 @@ try_again:
 
                if (folder != NULL && store_uses_vjunk)
                        vjunk = camel_object_bag_get (
-                               store->folders, CAMEL_VJUNK_NAME);
+                               store->priv->folders, CAMEL_VJUNK_NAME);
 
                if (folder != NULL && store_uses_vtrash)
                        vtrash = camel_object_bag_get (
-                               store->folders, CAMEL_VTRASH_NAME);
+                               store->priv->folders, CAMEL_VTRASH_NAME);
        }
 
        /* Release the folder name reservation before adding the
@@ -1336,10 +1423,10 @@ try_again:
         * reduce the chance of deadlock. */
        if (folder != NULL)
                camel_object_bag_add (
-                       store->folders, folder_name, folder);
+                       store->priv->folders, folder_name, folder);
        else
                camel_object_bag_abort (
-                       store->folders, folder_name);
+                       store->priv->folders, folder_name);
 
        /* If this is a normal folder and the store uses a
         * virtual Junk folder, let the virtual Junk folder
@@ -1591,8 +1678,8 @@ camel_store_get_folder_info_sync (CamelStore *store,
        /* For readability. */
        allow_virtual = ((flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0);
        start_at_root = (top == NULL || *top == '\0');
-       store_has_vtrash = ((store->flags & CAMEL_STORE_VTRASH) != 0);
-       store_has_vjunk = ((store->flags & CAMEL_STORE_VJUNK) != 0);
+       store_has_vtrash = ((store->priv->flags & CAMEL_STORE_VTRASH) != 0);
+       store_has_vjunk = ((store->priv->flags & CAMEL_STORE_VJUNK) != 0);
 
        if (info != NULL && start_at_root && allow_virtual) {
                if (store_has_vtrash) {
@@ -1947,7 +2034,7 @@ camel_store_get_junk_folder_sync (CamelStore *store,
 {
        g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
 
-       if ((store->flags & CAMEL_STORE_VJUNK) == 0) {
+       if ((store->priv->flags & CAMEL_STORE_VJUNK) == 0) {
                CamelStoreClass *class;
                CamelFolder *folder;
 
@@ -2073,7 +2160,7 @@ camel_store_get_trash_folder_sync (CamelStore *store,
 {
        g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
 
-       if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
+       if ((store->priv->flags & CAMEL_STORE_VTRASH) == 0) {
                CamelStoreClass *class;
                CamelFolder *folder;
 
@@ -2255,9 +2342,9 @@ store_create_folder_thread (GTask *task,
                gboolean reserved_vfolder_name;
 
                reserved_vfolder_name =
-                       ((store->flags & CAMEL_STORE_VJUNK) &&
+                       ((store->priv->flags & CAMEL_STORE_VJUNK) &&
                        g_str_equal (folder_name, CAMEL_VJUNK_NAME)) ||
-                       ((store->flags & CAMEL_STORE_VTRASH) &&
+                       ((store->priv->flags & CAMEL_STORE_VTRASH) &&
                        g_str_equal (folder_name, CAMEL_VTRASH_NAME));
 
                if (reserved_vfolder_name) {
@@ -2439,9 +2526,9 @@ store_delete_folder_thread (GTask *task,
        g_return_if_fail (class->delete_folder_sync != NULL);
 
        reserved_vfolder_name =
-               ((store->flags & CAMEL_STORE_VJUNK) &&
+               ((store->priv->flags & CAMEL_STORE_VJUNK) &&
                g_str_equal (folder_name, CAMEL_VJUNK_NAME)) ||
-               ((store->flags & CAMEL_STORE_VTRASH) &&
+               ((store->priv->flags & CAMEL_STORE_VTRASH) &&
                g_str_equal (folder_name, CAMEL_VTRASH_NAME));
 
        if (reserved_vfolder_name) {
@@ -2466,7 +2553,7 @@ store_delete_folder_thread (GTask *task,
        if (local_error != NULL) {
                g_task_return_error (task, local_error);
        } else {
-               cs_delete_cached_folder (store, folder_name);
+               camel_store_delete_cached_folder (store, folder_name);
                g_task_return_boolean (task, success);
        }
 }
@@ -2629,9 +2716,9 @@ store_rename_folder_thread (GTask *task,
        }
 
        reserved_vfolder_name =
-               ((store->flags & CAMEL_STORE_VJUNK) &&
+               ((store->priv->flags & CAMEL_STORE_VJUNK) &&
                g_str_equal (old_name, CAMEL_VJUNK_NAME)) ||
-               ((store->flags & CAMEL_STORE_VTRASH) &&
+               ((store->priv->flags & CAMEL_STORE_VTRASH) &&
                g_str_equal (old_name, CAMEL_VTRASH_NAME));
 
        if (reserved_vfolder_name) {
@@ -2648,7 +2735,7 @@ store_rename_folder_thread (GTask *task,
        /* If the folder is open (or any subfolders of the open folder)
         * We need to rename them atomically with renaming the actual
         * folder path. */
-       folders = camel_object_bag_list (store->folders);
+       folders = camel_object_bag_list (store->priv->folders);
        for (ii = 0; ii < folders->len; ii++) {
                const gchar *full_name;
                gsize full_name_len;
@@ -2691,7 +2778,7 @@ store_rename_folder_thread (GTask *task,
                        full_name = camel_folder_get_full_name (folder);
 
                        new = g_strdup_printf ("%s%s", new_name, full_name + strlen (old_name));
-                       camel_object_bag_rekey (store->folders, folder, new);
+                       camel_object_bag_rekey (store->priv->folders, folder, new);
                        camel_folder_rename (folder, new);
                        g_free (new);
 
@@ -3134,8 +3221,60 @@ camel_store_maybe_run_db_maintenance (CamelStore *store,
        if (g_atomic_int_get (&store->priv->maintenance_lock) > 0)
                return TRUE;
 
-       if (!store->cdb_w)
+       if (!store->priv->cdb)
                return TRUE;
 
-       return camel_db_maybe_run_maintenance (store->cdb_w, error);
+       return camel_db_maybe_run_maintenance (store->priv->cdb, error);
+}
+
+/**
+ * camel_store_delete_cached_folder:
+ * @store: a #CamelStore
+ * @folder_name: a folder full name to delete from the cache
+ *
+ * Deletes local data for the given @folder_name. The folder should
+ * be part of the opened folders.
+ *
+ * It doesn't delete the folder in the store (server) as such.
+ * Use camel_store_delete_folder(), or its synchronous variant,
+ * if you want to do that instead.
+ *
+ * Since: 3.24
+ **/
+void
+camel_store_delete_cached_folder (CamelStore *store,
+                                 const gchar *folder_name)
+{
+       CamelFolder *folder;
+       CamelVeeFolder *vfolder;
+
+       if (store->priv->folders == NULL)
+               return;
+
+       folder = camel_object_bag_get (store->priv->folders, folder_name);
+       if (folder == NULL)
+               return;
+
+       if (store->priv->flags & CAMEL_STORE_VTRASH) {
+               vfolder = camel_object_bag_get (
+                       store->priv->folders, CAMEL_VTRASH_NAME);
+               if (vfolder != NULL) {
+                       camel_vee_folder_remove_folder (vfolder, folder, NULL);
+                       g_object_unref (vfolder);
+               }
+       }
+
+       if (store->priv->flags & CAMEL_STORE_VJUNK) {
+               vfolder = camel_object_bag_get (
+                       store->priv->folders, CAMEL_VJUNK_NAME);
+               if (vfolder != NULL) {
+                       camel_vee_folder_remove_folder (vfolder, folder, NULL);
+                       g_object_unref (vfolder);
+               }
+       }
+
+       camel_folder_delete (folder);
+
+       camel_object_bag_remove (store->priv->folders, folder);
+       g_object_unref (folder);
 }
diff --git a/src/camel/camel-store.h b/src/camel/camel-store.h
index 19d930e..5c0c88b 100644
--- a/src/camel/camel-store.h
+++ b/src/camel/camel-store.h
@@ -27,9 +27,7 @@
 #ifndef CAMEL_STORE_H
 #define CAMEL_STORE_H
 
-/* for mode_t */
-#include <sys/types.h>
-
+#include <camel/camel-db.h>
 #include <camel/camel-enums.h>
 #include <camel/camel-folder.h>
 #include <camel/camel-service.h>
@@ -53,6 +51,14 @@
        (G_TYPE_INSTANCE_GET_CLASS \
        ((obj), CAMEL_TYPE_STORE, CamelStoreClass))
 
+#define CAMEL_TYPE_FOLDER_INFO \
+       (camel_folder_info_get_type ())
+#define CAMEL_FOLDER_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_FOLDER_INFO, CamelFolderInfo))
+#define CAMEL_IS_FOLDER_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_FOLDER_INFO))
 /**
  * CAMEL_STORE_ERROR:
  *
@@ -113,8 +119,6 @@ typedef struct _CamelFolderInfo {
        gint32 total;
 } CamelFolderInfo;
 
-struct _CamelDB;
-
 typedef struct _CamelStore CamelStore;
 typedef struct _CamelStoreClass CamelStoreClass;
 typedef struct _CamelStorePrivate CamelStorePrivate;
@@ -133,21 +137,6 @@ typedef enum {
 struct _CamelStore {
        CamelService parent;
        CamelStorePrivate *priv;
-
-       CamelObjectBag *folders;
-       struct _CamelDB *cdb_r;
-       struct _CamelDB *cdb_w;
-
-       CamelStoreFlags flags;
-
-       /* XXX The default "mode" (read/write) is changed only by
-        *     evolution-groupwise for non-writable proxy accounts.
-        *     The mode is only checked by the account combo box in
-        *     Evolution's composer window. */
-       CamelStorePermissionFlags mode;
-
-       /* Future ABI expansion */
-       gpointer later[4];
 };
 
 struct _CamelStoreClass {
@@ -208,8 +197,8 @@ struct _CamelStoreClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots for methods. */
-       gpointer reserved_for_methods[20];
+       /* Padding for future expansion */
+       gpointer reserved_methods[20];
 
        /* Signals */
        void            (*folder_created)       (CamelStore *store,
@@ -222,10 +211,22 @@ struct _CamelStoreClass {
                                                 const gchar *old_name,
                                                 CamelFolderInfo *folder_info);
        void            (*folder_info_stale)    (CamelStore *store);
+
+       /* Padding for future expansion */
+       gpointer reserved_signals[20];
 };
 
 GType          camel_store_get_type            (void);
 GQuark         camel_store_error_quark         (void) G_GNUC_CONST;
+CamelDB *      camel_store_get_db              (CamelStore *store);
+CamelObjectBag *camel_store_get_folders_bag    (CamelStore *store);
+GPtrArray *    camel_store_dup_opened_folders  (CamelStore *store);
+guint32                camel_store_get_flags           (CamelStore *store);
+void           camel_store_set_flags           (CamelStore *store,
+                                                guint32 flags);
+guint32                camel_store_get_permissions     (CamelStore *store);
+void           camel_store_set_permissions     (CamelStore *store,
+                                                guint32 permissions);
 void           camel_store_folder_created      (CamelStore *store,
                                                 CamelFolderInfo *folder_info);
 void           camel_store_folder_deleted      (CamelStore *store,
@@ -404,6 +405,9 @@ gboolean    camel_store_initial_setup_finish
 gboolean       camel_store_maybe_run_db_maintenance
                                                (CamelStore *store,
                                                 GError **error);
+void           camel_store_delete_cached_folder
+                                               (CamelStore *store,
+                                                const gchar *folder_name);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-stream-buffer.c b/src/camel/camel-stream-buffer.c
index 7ad8c62..c490b52 100644
--- a/src/camel/camel-stream-buffer.c
+++ b/src/camel/camel-stream-buffer.c
@@ -400,7 +400,7 @@ camel_stream_buffer_new (CamelStream *stream,
 /**
  * camel_stream_buffer_gets:
  * @sbf: a #CamelStreamBuffer object
- * @buf: (out) (array): Memory to write the string to.
+ * @buf: (array length=max) (type gchar): Memory to write the string to.
  * @max: Maxmimum number of characters to store.
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
diff --git a/src/camel/camel-stream-buffer.h b/src/camel/camel-stream-buffer.h
index d7a014b..ef92cfd 100644
--- a/src/camel/camel-stream-buffer.h
+++ b/src/camel/camel-stream-buffer.h
@@ -77,6 +77,9 @@ struct _CamelStreamBufferClass {
                                         CamelStreamBufferMode mode,
                                         gchar *buf,
                                         guint32 size);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_stream_buffer_get_type    (void);
diff --git a/src/camel/camel-stream-filter.h b/src/camel/camel-stream-filter.h
index 853ae17..c954a8d 100644
--- a/src/camel/camel-stream-filter.h
+++ b/src/camel/camel-stream-filter.h
@@ -59,6 +59,9 @@ struct _CamelStreamFilter {
 
 struct _CamelStreamFilterClass {
        CamelStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_stream_filter_get_type    (void);
diff --git a/src/camel/camel-stream-fs.c b/src/camel/camel-stream-fs.c
index 78045df..beceb3d 100644
--- a/src/camel/camel-stream-fs.c
+++ b/src/camel/camel-stream-fs.c
@@ -39,6 +39,7 @@
        ((obj), CAMEL_TYPE_STREAM_FS, CamelStreamFsPrivate))
 
 struct _CamelStreamFsPrivate {
+       gboolean eos;
        gint fd;        /* file descriptor on the underlying file */
 };
 
@@ -78,7 +79,7 @@ stream_fs_read (CamelStream *stream,
        nread = camel_read (priv->fd, buffer, n, cancellable, error);
 
        if (nread == 0)
-               stream->eos = TRUE;
+               priv->eos = TRUE;
 
        return nread;
 }
@@ -145,6 +146,14 @@ stream_fs_close (CamelStream *stream,
        return 0;
 }
 
+static gboolean
+stream_fs_eos (CamelStream *stream)
+{
+       CamelStreamFs *fs = CAMEL_STREAM_FS (stream);
+
+       return fs->priv->eos;
+}
+
 static goffset
 stream_fs_tell (GSeekable *seekable)
 {
@@ -201,7 +210,7 @@ stream_fs_seek (GSeekable *seekable,
                return FALSE;
        }
 
-       CAMEL_STREAM (seekable)->eos = FALSE;
+       priv->eos = FALSE;
 
        return TRUE;
 }
@@ -242,6 +251,7 @@ camel_stream_fs_class_init (CamelStreamFsClass *class)
        stream_class->write = stream_fs_write;
        stream_class->flush = stream_fs_flush;
        stream_class->close = stream_fs_close;
+       stream_class->eos = stream_fs_eos;
 }
 
 static void
@@ -259,6 +269,7 @@ camel_stream_fs_init (CamelStreamFs *stream)
 {
        stream->priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
        stream->priv->fd = -1;
+       stream->priv->eos = FALSE;
 }
 
 /**
@@ -292,7 +303,7 @@ camel_stream_fs_new_with_fd (gint fd)
  * camel_stream_fs_new_with_name:
  * @name: a local filename
  * @flags: flags as in open(2)
- * @mode: a file mode
+ * @mode: (type guint32): a file mode
  * @error: return location for a #GError, or %NULL
  *
  * Creates a new #CamelStreamFs corresponding to the named file, flags,
diff --git a/src/camel/camel-stream-fs.h b/src/camel/camel-stream-fs.h
index 31cfe8c..7c0547b 100644
--- a/src/camel/camel-stream-fs.h
+++ b/src/camel/camel-stream-fs.h
@@ -64,6 +64,9 @@ struct _CamelStreamFs {
 
 struct _CamelStreamFsClass {
        CamelStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_stream_fs_get_type        (void);
diff --git a/src/camel/camel-stream-mem.h b/src/camel/camel-stream-mem.h
index 385ce86..02fcbd4 100644
--- a/src/camel/camel-stream-mem.h
+++ b/src/camel/camel-stream-mem.h
@@ -61,6 +61,9 @@ struct _CamelStreamMem {
 
 struct _CamelStreamMemClass {
        CamelStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_stream_mem_get_type       (void);
diff --git a/src/camel/camel-stream-null.c b/src/camel/camel-stream-null.c
index db75989..72aa617 100644
--- a/src/camel/camel-stream-null.c
+++ b/src/camel/camel-stream-null.c
@@ -24,6 +24,10 @@
 
 #include "camel-stream-null.h"
 
+struct _CamelStreamNullPrivate {
+       gsize written;
+};
+
 static void camel_stream_null_seekable_init (GSeekableIface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (CamelStreamNull, camel_stream_null, CAMEL_TYPE_STREAM,
@@ -36,7 +40,7 @@ stream_null_write (CamelStream *stream,
                    GCancellable *cancellable,
                    GError **error)
 {
-       CAMEL_STREAM_NULL (stream)->written += n;
+       CAMEL_STREAM_NULL (stream)->priv->written += n;
 
        return n;
 }
@@ -73,7 +77,7 @@ stream_null_seek (GSeekable *seekable,
                return FALSE;
        }
 
-       CAMEL_STREAM_NULL (seekable)->written = 0;
+       CAMEL_STREAM_NULL (seekable)->priv->written = 0;
 
        return TRUE;
 }
@@ -103,6 +107,8 @@ camel_stream_null_class_init (CamelStreamNullClass *class)
 {
        CamelStreamClass *stream_class;
 
+       g_type_class_add_private (class, sizeof (CamelStreamNullPrivate));
+
        stream_class = CAMEL_STREAM_CLASS (class);
        stream_class->write = stream_null_write;
        stream_class->eos = stream_null_eos;
@@ -121,6 +127,7 @@ camel_stream_null_seekable_init (GSeekableIface *iface)
 static void
 camel_stream_null_init (CamelStreamNull *stream_null)
 {
+       stream_null->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream_null, CAMEL_TYPE_STREAM_NULL, 
CamelStreamNullPrivate);
 }
 
 /**
@@ -129,10 +136,27 @@ camel_stream_null_init (CamelStreamNull *stream_null)
  * Returns a null stream.  A null stream is always at eof, and
  * always returns success for all reads and writes.
  *
- * Returns: a new #CamelStreamNull
+ * Returns: (transfer full): a new #CamelStreamNull
  **/
 CamelStream *
 camel_stream_null_new (void)
 {
        return g_object_new (CAMEL_TYPE_STREAM_NULL, NULL);
 }
+
+/**
+ * camel_stream_null_get_bytes_written:
+ * @stream_null: a #CamelStreamNull
+ *
+ * Returns: how many bytes had been written to the @stream_null since
+ *   it was created or rewind to the beginning.
+ *
+ * Since: 3.24
+ **/
+gsize
+camel_stream_null_get_bytes_written (CamelStreamNull *stream_null)
+{
+       g_return_val_if_fail (CAMEL_IS_STREAM_NULL (stream_null), -1);
+
+       return stream_null->priv->written;
+}
diff --git a/src/camel/camel-stream-null.h b/src/camel/camel-stream-null.h
index d0d96d5..51b3da5 100644
--- a/src/camel/camel-stream-null.h
+++ b/src/camel/camel-stream-null.h
@@ -49,20 +49,25 @@ G_BEGIN_DECLS
 
 typedef struct _CamelStreamNull CamelStreamNull;
 typedef struct _CamelStreamNullClass CamelStreamNullClass;
+typedef struct _CamelStreamNullPrivate CamelStreamNullPrivate;
 
 struct _CamelStreamNull {
        CamelStream parent;
-
-       gsize written;
+       CamelStreamNullPrivate *priv;
 };
 
 struct _CamelStreamNullClass {
        CamelStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_stream_null_get_type (void);
 
-CamelStream *camel_stream_null_new (void);
+CamelStream *  camel_stream_null_new           (void);
+gsize          camel_stream_null_get_bytes_written
+                                               (CamelStreamNull *stream_null);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-stream-process.c b/src/camel/camel-stream-process.c
index c8ab3ac..1f6fa29 100644
--- a/src/camel/camel-stream-process.c
+++ b/src/camel/camel-stream-process.c
@@ -46,6 +46,11 @@
 
 extern gint camel_verbose_debug;
 
+struct _CamelStreamProcessPrivate {
+       gint sockfd;
+       pid_t childpid;
+};
+
 G_DEFINE_TYPE (CamelStreamProcess, camel_stream_process, CAMEL_TYPE_STREAM)
 
 static void
@@ -67,7 +72,7 @@ stream_process_read (CamelStream *stream,
                      GError **error)
 {
        CamelStreamProcess *stream_process = CAMEL_STREAM_PROCESS (stream);
-       gint fd = stream_process->sockfd;
+       gint fd = stream_process->priv->sockfd;
 
        return camel_read (fd, buffer, n, cancellable, error);
 }
@@ -80,7 +85,7 @@ stream_process_write (CamelStream *stream,
                       GError **error)
 {
        CamelStreamProcess *stream_process = CAMEL_STREAM_PROCESS (stream);
-       gint fd = stream_process->sockfd;
+       gint fd = stream_process->priv->sockfd;
 
        return camel_write (fd, buffer, n, cancellable, error);
 }
@@ -96,23 +101,23 @@ stream_process_close (CamelStream *object,
                fprintf (
                        stderr,
                        "Process stream close. sockfd %d, childpid %d\n",
-                       stream->sockfd, stream->childpid);
+                       stream->priv->sockfd, stream->priv->childpid);
 
-       if (stream->sockfd != -1) {
-               close (stream->sockfd);
-               stream->sockfd = -1;
+       if (stream->priv->sockfd != -1) {
+               close (stream->priv->sockfd);
+               stream->priv->sockfd = -1;
        }
 
-       if (stream->childpid) {
+       if (stream->priv->childpid) {
                gint ret, i;
                for (i = 0; i < 4; i++) {
-                       ret = waitpid (stream->childpid, NULL, WNOHANG);
+                       ret = waitpid (stream->priv->childpid, NULL, WNOHANG);
                        if (camel_verbose_debug)
                                fprintf (
                                        stderr,
                                        "waitpid() for pid %d returned %d (errno %d)\n",
-                                       stream->childpid, ret, ret == -1 ? errno : 0);
-                       if (ret == stream->childpid || errno == ECHILD)
+                                       stream->priv->childpid, ret, ret == -1 ? errno : 0);
+                       if (ret == stream->priv->childpid || errno == ECHILD)
                                break;
                        switch (i) {
                        case 0:
@@ -120,16 +125,16 @@ stream_process_close (CamelStream *object,
                                        fprintf (
                                                stderr,
                                                "Sending SIGTERM to pid %d\n",
-                                               stream->childpid);
-                               kill (stream->childpid, SIGTERM);
+                                               stream->priv->childpid);
+                               kill (stream->priv->childpid, SIGTERM);
                                break;
                        case 2:
                                if (camel_verbose_debug)
                                        fprintf (
                                                stderr,
                                                "Sending SIGKILL to pid %d\n",
-                                               stream->childpid);
-                               kill (stream->childpid, SIGKILL);
+                                               stream->priv->childpid);
+                               kill (stream->priv->childpid, SIGKILL);
                                break;
                        case 1:
                        case 3:
@@ -138,7 +143,7 @@ stream_process_close (CamelStream *object,
                        }
                }
 
-               stream->childpid = 0;
+               stream->priv->childpid = 0;
        }
 
        return 0;
@@ -158,6 +163,8 @@ camel_stream_process_class_init (CamelStreamProcessClass *class)
        GObjectClass *object_class;
        CamelStreamClass *stream_class;
 
+       g_type_class_add_private (class, sizeof (CamelStreamProcessPrivate));
+
        object_class = G_OBJECT_CLASS (class);
        object_class->finalize = stream_process_finalize;
 
@@ -171,8 +178,9 @@ camel_stream_process_class_init (CamelStreamProcessClass *class)
 static void
 camel_stream_process_init (CamelStreamProcess *stream)
 {
-       stream->sockfd = -1;
-       stream->childpid = 0;
+       stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, CAMEL_TYPE_STREAM_PROCESS, 
CamelStreamProcessPrivate);
+       stream->priv->sockfd = -1;
+       stream->priv->childpid = 0;
 }
 
 /**
@@ -247,24 +255,24 @@ camel_stream_process_connect (CamelStreamProcess *stream,
        g_return_val_if_fail (CAMEL_IS_STREAM_PROCESS (stream), -1);
        g_return_val_if_fail (command != NULL, -1);
 
-       if (stream->sockfd != -1 || stream->childpid)
+       if (stream->priv->sockfd != -1 || stream->priv->childpid)
                camel_stream_close (CAMEL_STREAM (stream), NULL, NULL);
 
        if (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfds))
                goto fail;
 
-       stream->childpid = fork ();
-       if (!stream->childpid) {
+       stream->priv->childpid = fork ();
+       if (!stream->priv->childpid) {
                do_exec_command (sockfds[1], command, (gchar **) env);
-       } else if (stream->childpid == -1) {
+       } else if (stream->priv->childpid == -1) {
                close (sockfds[0]);
                close (sockfds[1]);
-               stream->sockfd = -1;
+               stream->priv->sockfd = -1;
                goto fail;
        }
 
        close (sockfds[1]);
-       stream->sockfd = sockfds[0];
+       stream->priv->sockfd = sockfds[0];
 
        return 0;
 
diff --git a/src/camel/camel-stream-process.h b/src/camel/camel-stream-process.h
index 1c48645..b0de6fb 100644
--- a/src/camel/camel-stream-process.h
+++ b/src/camel/camel-stream-process.h
@@ -49,16 +49,18 @@ G_BEGIN_DECLS
 
 typedef struct _CamelStreamProcess CamelStreamProcess;
 typedef struct _CamelStreamProcessClass CamelStreamProcessClass;
+typedef struct _CamelStreamProcessPrivate CamelStreamProcessPrivate;
 
 struct _CamelStreamProcess {
        CamelStream parent;
-
-       gint sockfd;
-       pid_t childpid;
+       CamelStreamProcessPrivate *priv;
 };
 
 struct _CamelStreamProcessClass {
        CamelStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_stream_process_get_type   (void);
diff --git a/src/camel/camel-stream.c b/src/camel/camel-stream.c
index 3841819..5d43f02 100644
--- a/src/camel/camel-stream.c
+++ b/src/camel/camel-stream.c
@@ -33,6 +33,7 @@
 struct _CamelStreamPrivate {
        GIOStream *base_stream;
        GMutex base_stream_lock;
+       gboolean eos;
 };
 
 enum {
@@ -135,7 +136,7 @@ stream_read (CamelStream *stream,
                g_object_unref (base_stream);
        }
 
-       stream->eos = n_bytes_read <= 0;
+       stream->priv->eos = n_bytes_read <= 0;
 
        return n_bytes_read;
 }
@@ -157,7 +158,7 @@ stream_write (CamelStream *stream,
                gsize n_written = 0;
 
                output_stream = g_io_stream_get_output_stream (base_stream);
-               stream->eos = FALSE;
+               stream->priv->eos = FALSE;
 
                if (g_output_stream_write_all (output_stream, buffer, n, &n_written, cancellable, error))
                        n_bytes_written = (gssize) n_written;
@@ -219,7 +220,7 @@ stream_flush (CamelStream *stream,
 static gboolean
 stream_eos (CamelStream *stream)
 {
-       return stream->eos;
+       return stream->priv->eos;
 }
 
 static goffset
@@ -278,7 +279,7 @@ stream_seek (GSeekable *seekable,
        base_stream = camel_stream_ref_base_stream (stream);
 
        if (G_IS_SEEKABLE (base_stream)) {
-               stream->eos = FALSE;
+               stream->priv->eos = FALSE;
                success = g_seekable_seek (
                        G_SEEKABLE (base_stream),
                        offset, type, cancellable, error);
@@ -479,12 +480,12 @@ camel_stream_set_base_stream (CamelStream *stream,
 /**
  * camel_stream_read:
  * @stream: a #CamelStream object.
- * @buffer: output buffer
+ * @buffer: (array length=n) (type gchar): output buffer
  * @n: max number of bytes to read.
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Attempts to read up to @len bytes from @stream into @buf.
+ * Attempts to read up to @n bytes from @stream into @buffer.
  *
  * Returns: the number of bytes actually read, or %-1 on error and set
  * errno.
@@ -514,7 +515,7 @@ camel_stream_read (CamelStream *stream,
 /**
  * camel_stream_write:
  * @stream: a #CamelStream object
- * @buffer: buffer to write.
+ * @buffer: (array length=n) (type gchar): buffer to write.
  * @n: number of bytes to write
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
diff --git a/src/camel/camel-stream.h b/src/camel/camel-stream.h
index 4e7571e..1bfdbeb 100644
--- a/src/camel/camel-stream.h
+++ b/src/camel/camel-stream.h
@@ -58,8 +58,6 @@ typedef struct _CamelStreamPrivate CamelStreamPrivate;
 struct _CamelStream {
        GObject parent;
        CamelStreamPrivate *priv;
-
-       gboolean eos;
 };
 
 struct _CamelStreamClass {
@@ -82,6 +80,9 @@ struct _CamelStreamClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
        gboolean        (*eos)                  (CamelStream *stream);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_stream_get_type           (void);
diff --git a/src/camel/camel-subscribable.c b/src/camel/camel-subscribable.c
index 3ec4f58..a8f3fa8 100644
--- a/src/camel/camel-subscribable.c
+++ b/src/camel/camel-subscribable.c
@@ -106,46 +106,6 @@ subscribable_emit_folder_unsubscribed_cb (gpointer user_data)
 }
 
 static void
-subscribable_delete_cached_folder (CamelStore *store,
-                                   const gchar *folder_name)
-{
-       CamelFolder *folder;
-       CamelVeeFolder *vfolder;
-
-       /* XXX Copied from camel-store.c.  Should this be public? */
-
-       if (store->folders == NULL)
-               return;
-
-       folder = camel_object_bag_get (store->folders, folder_name);
-       if (folder == NULL)
-               return;
-
-       if (store->flags & CAMEL_STORE_VTRASH) {
-               folder_name = CAMEL_VTRASH_NAME;
-               vfolder = camel_object_bag_get (store->folders, folder_name);
-               if (vfolder != NULL) {
-                       camel_vee_folder_remove_folder (vfolder, folder, NULL);
-                       g_object_unref (vfolder);
-               }
-       }
-
-       if (store->flags & CAMEL_STORE_VJUNK) {
-               folder_name = CAMEL_VJUNK_NAME;
-               vfolder = camel_object_bag_get (store->folders, folder_name);
-               if (vfolder != NULL) {
-                       camel_vee_folder_remove_folder (vfolder, folder, NULL);
-                       g_object_unref (vfolder);
-               }
-       }
-
-       camel_folder_delete (folder);
-
-       camel_object_bag_remove (store->folders, folder);
-       g_object_unref (folder);
-}
-
-static void
 camel_subscribable_default_init (CamelSubscribableInterface *iface)
 {
        signals[FOLDER_SUBSCRIBED] = g_signal_new (
@@ -157,7 +117,7 @@ camel_subscribable_default_init (CamelSubscribableInterface *iface)
                        folder_subscribed),
                NULL, NULL, NULL,
                G_TYPE_NONE, 1,
-               G_TYPE_POINTER);
+               CAMEL_TYPE_FOLDER_INFO);
 
        signals[FOLDER_UNSUBSCRIBED] = g_signal_new (
                "folder-unsubscribed",
@@ -168,7 +128,7 @@ camel_subscribable_default_init (CamelSubscribableInterface *iface)
                        folder_unsubscribed),
                NULL, NULL, NULL,
                G_TYPE_NONE, 1,
-               G_TYPE_POINTER);
+               CAMEL_TYPE_FOLDER_INFO);
 }
 
 /**
@@ -449,8 +409,7 @@ subscribable_unsubscribe_folder_thread (GTask *task,
                subscribable, unsubscribe_folder_sync, success, local_error);
 
        if (success)
-               subscribable_delete_cached_folder (
-                       CAMEL_STORE (subscribable), folder_name);
+               camel_store_delete_cached_folder (CAMEL_STORE (subscribable), folder_name);
 
        camel_operation_pop_message (cancellable);
 
diff --git a/src/camel/camel-subscribable.h b/src/camel/camel-subscribable.h
index 6d53492..c0aafda 100644
--- a/src/camel/camel-subscribable.h
+++ b/src/camel/camel-subscribable.h
@@ -73,8 +73,8 @@ struct _CamelSubscribableInterface {
                                         GCancellable *cancellable,
                                         GError **error);
 
-       /* Reserved slots for methods. */
-       gpointer reserved_for_methods[4];
+       /* Padding for future expansion */
+       gpointer reserved_methods[20];
 
        /* Signals */
        void            (*folder_subscribed)
@@ -83,6 +83,9 @@ struct _CamelSubscribableInterface {
        void            (*folder_unsubscribed)
                                        (CamelSubscribable *subscribable,
                                         CamelFolderInfo *folder_info);
+
+       /* Padding for future expansion */
+       gpointer reserved_signals[20];
 };
 
 GType          camel_subscribable_get_type
diff --git a/src/camel/camel-text-index.c b/src/camel/camel-text-index.c
index 7807753..ba64718 100644
--- a/src/camel/camel-text-index.c
+++ b/src/camel/camel-text-index.c
@@ -234,7 +234,7 @@ text_index_add_name_to_word (CamelIndex *idx,
        CamelTextIndexPrivate *p = CAMEL_TEXT_INDEX (idx)->priv;
        camel_key_t wordid;
        camel_block_t data;
-       struct _CamelTextIndexRoot *rb = (struct _CamelTextIndexRoot *) p->blocks->root;
+       struct _CamelTextIndexRoot *rb = (struct _CamelTextIndexRoot *) camel_block_file_get_root (p->blocks);
 
        w = g_hash_table_lookup (p->words, word);
        if (w == NULL) {
@@ -259,7 +259,7 @@ text_index_add_name_to_word (CamelIndex *idx,
                                return;
                        }
                        rb->words++;
-                       camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+                       camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block (p->blocks));
                } else {
                        data = camel_key_table_lookup (p->word_index, wordid, NULL, NULL);
                        if (data == 0) {
@@ -290,7 +290,7 @@ text_index_add_name_to_word (CamelIndex *idx,
                        if (camel_key_file_write (p->links, &ww->data, ww->used, ww->names) != -1) {
                                io (printf ("  new data [%x]\n", ww->data));
                                rb->keys++;
-                               camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+                               camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block 
(p->blocks));
                                /* if this call fails - we still point to the old data - not fatal */
                                camel_key_table_set_data (
                                        p->word_index, ww->wordid, ww->data);
@@ -318,7 +318,7 @@ text_index_add_name_to_word (CamelIndex *idx,
                        io (printf ("writing key file entry '%s' [%x]\n", w->word, w->data));
                        if (camel_key_file_write (p->links, &w->data, w->used, w->names) != -1) {
                                rb->keys++;
-                               camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+                               camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block 
(p->blocks));
                                /* if this call fails - we still point to the old data - not fatal */
                                camel_key_table_set_data (
                                        p->word_index, w->wordid, w->data);
@@ -344,14 +344,14 @@ text_index_sync (CamelIndex *idx)
            || p->name_index == NULL || p->name_hash == NULL)
                return 0;
 
-       rb = (struct _CamelTextIndexRoot *) p->blocks->root;
+       rb = (struct _CamelTextIndexRoot *) camel_block_file_get_root (p->blocks);
 
        /* sync/flush word cache */
 
        CAMEL_TEXT_INDEX_LOCK (idx, lock);
 
        /* we sync, bump down the cache limits since we dont need them for reading */
-       p->blocks->block_cache_limit = 128;
+       camel_block_file_set_cache_limit (p->blocks, 128);
        /* this doesn't really need to be dropped, its only used in updates anyway */
        p->word_cache_limit = 1024;
 
@@ -361,7 +361,7 @@ text_index_sync (CamelIndex *idx)
                        if (camel_key_file_write (p->links, &ww->data, ww->used, ww->names) != -1) {
                                io (printf ("  new data [%x]\n", ww->data));
                                rb->keys++;
-                               camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+                               camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block 
(p->blocks));
                                camel_key_table_set_data (
                                        p->word_index, ww->wordid, ww->data);
                        } else {
@@ -473,7 +473,7 @@ text_index_compress_nosync (CamelIndex *idx)
 
        CAMEL_TEXT_INDEX_LOCK (idx, lock);
 
-       rb = (struct _CamelTextIndexRoot *) newp->blocks->root;
+       rb = (struct _CamelTextIndexRoot *) camel_block_file_get_root (newp->blocks);
 
        rb->words = 0;
        rb->names = 0;
@@ -562,7 +562,7 @@ text_index_compress_nosync (CamelIndex *idx)
                name = NULL;
        }
 
-       camel_block_file_touch_block (newp->blocks, newp->blocks->root_block);
+       camel_block_file_touch_block (newp->blocks, camel_block_file_get_root_block (newp->blocks));
 
        if (camel_index_sync (CAMEL_INDEX (newidx)) == -1)
                goto fail;
@@ -677,13 +677,13 @@ text_index_add_name (CamelIndex *idx,
        CamelTextIndexPrivate *p = CAMEL_TEXT_INDEX_GET_PRIVATE (idx);
        camel_key_t keyid;
        CamelIndexName *idn;
-       struct _CamelTextIndexRoot *rb = (struct _CamelTextIndexRoot *) p->blocks->root;
+       struct _CamelTextIndexRoot *rb = (struct _CamelTextIndexRoot *) camel_block_file_get_root (p->blocks);
 
        CAMEL_TEXT_INDEX_LOCK (idx, lock);
 
        /* if we're adding words, up the cache limits a lot */
        if (p->word_cache_limit < 8192) {
-               p->blocks->block_cache_limit = 1024;
+               camel_block_file_set_cache_limit (p->blocks, 1024);
                p->word_cache_limit = 8192;
        }
 
@@ -703,7 +703,7 @@ text_index_add_name (CamelIndex *idx,
                rb->names++;
        }
 
-       camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+       camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block (p->blocks));
 
        /* TODO: if keyid == 0, we had a failure, we should somehow flag that, but for
         * now just return a valid object but discard its results, see text_index_write_name */
@@ -759,7 +759,7 @@ text_index_delete_name (CamelIndex *idx,
 {
        CamelTextIndexPrivate *p = CAMEL_TEXT_INDEX_GET_PRIVATE (idx);
        camel_key_t keyid;
-       struct _CamelTextIndexRoot *rb = (struct _CamelTextIndexRoot *) p->blocks->root;
+       struct _CamelTextIndexRoot *rb = (struct _CamelTextIndexRoot *) camel_block_file_get_root (p->blocks);
 
        d (printf ("Delete name: %s\n", name));
 
@@ -770,7 +770,7 @@ text_index_delete_name (CamelIndex *idx,
        keyid = camel_partition_table_lookup (p->name_hash, name);
        if (keyid != 0) {
                rb->deleted++;
-               camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+               camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block (p->blocks));
                camel_key_table_set_flags (p->name_index, keyid, 1, 1);
                camel_partition_table_remove (p->name_hash, name);
        }
@@ -896,7 +896,7 @@ camel_text_index_new (const gchar *path,
        if (p->links == NULL)
                goto fail;
 
-       rb = (struct _CamelTextIndexRoot *) p->blocks->root;
+       rb = (struct _CamelTextIndexRoot *) camel_block_file_get_root (p->blocks);
 
        if (rb->word_index_root == 0) {
                bl = camel_block_file_new_block (p->blocks);
@@ -906,7 +906,7 @@ camel_text_index_new (const gchar *path,
 
                rb->word_index_root = bl->id;
                camel_block_file_unref_block (p->blocks, bl);
-               camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+               camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block (p->blocks));
        }
 
        if (rb->word_hash_root == 0) {
@@ -917,7 +917,7 @@ camel_text_index_new (const gchar *path,
 
                rb->word_hash_root = bl->id;
                camel_block_file_unref_block (p->blocks, bl);
-               camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+               camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block (p->blocks));
        }
 
        if (rb->name_index_root == 0) {
@@ -928,7 +928,7 @@ camel_text_index_new (const gchar *path,
 
                rb->name_index_root = bl->id;
                camel_block_file_unref_block (p->blocks, bl);
-               camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+               camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block (p->blocks));
        }
 
        if (rb->name_hash_root == 0) {
@@ -939,7 +939,7 @@ camel_text_index_new (const gchar *path,
 
                rb->name_hash_root = bl->id;
                camel_block_file_unref_block (p->blocks, bl);
-               camel_block_file_touch_block (p->blocks, p->blocks->root_block);
+               camel_block_file_touch_block (p->blocks, camel_block_file_get_root_block (p->blocks));
        }
 
        p->word_index = camel_key_table_new (p->blocks, rb->word_index_root);
@@ -1064,7 +1064,7 @@ void
 camel_text_index_info (CamelTextIndex *idx)
 {
        CamelTextIndexPrivate *p = idx->priv;
-       struct _CamelTextIndexRoot *rb = (struct _CamelTextIndexRoot *) p->blocks->root;
+       struct _CamelTextIndexRoot *rb = (struct _CamelTextIndexRoot *) camel_block_file_get_root (p->blocks);
        gint frag;
 
        printf ("Path: '%s'\n", idx->parent.path);
@@ -1918,16 +1918,16 @@ main (gint argc,
 #if 0
        bs = camel_block_file_new ("blocks", "TESTINDX", CAMEL_BLOCK_SIZE);
 
-       root = (struct _CamelIndexRoot *) bs->root;
+       root = (struct _CamelIndexRoot *) camel_block_file_get_root (bs);
        if (root->word_root == 0) {
                keyroot = camel_block_file_new_block (bs);
                root->word_root = keyroot->id;
-               camel_block_file_touch_block (bs, bs->root_block);
+               camel_block_file_touch_block (bs, camel_block_file_get_root_block (bs));
        }
        if (root->word_hash_root == 0) {
                partroot = camel_block_file_new_block (bs);
                root->word_hash_root = partroot->id;
-               camel_block_file_touch_block (bs, bs->root_block);
+               camel_block_file_touch_block (bs, camel_block_file_get_root_block (bs));
        }
 
        ki = camel_key_table_new (bs, root->word_root);
diff --git a/src/camel/camel-text-index.h b/src/camel/camel-text-index.h
index c4e2750..9162cc8 100644
--- a/src/camel/camel-text-index.h
+++ b/src/camel/camel-text-index.h
@@ -127,6 +127,9 @@ struct _CamelTextIndexCursor {
 
 struct _CamelTextIndexCursorClass {
        CamelIndexCursorClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_text_index_cursor_get_type (void);
@@ -140,6 +143,9 @@ struct _CamelTextIndexKeyCursor {
 
 struct _CamelTextIndexKeyCursorClass {
        CamelIndexCursorClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_text_index_key_cursor_get_type (void);
@@ -153,6 +159,9 @@ struct _CamelTextIndexName {
 
 struct _CamelTextIndexNameClass {
        CamelIndexNameClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_text_index_name_get_type (void);
@@ -166,6 +175,9 @@ struct _CamelTextIndex {
 
 struct _CamelTextIndexClass {
        CamelIndexClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_text_index_get_type       (void);
diff --git a/src/camel/camel-transport.h b/src/camel/camel-transport.h
index df51094..92e845c 100644
--- a/src/camel/camel-transport.h
+++ b/src/camel/camel-transport.h
@@ -71,8 +71,8 @@ struct _CamelTransportClass {
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-       /* Reserved slots. */
-       gpointer reserved[2];
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_transport_get_type        (void);
diff --git a/src/camel/camel-trie.c b/src/camel/camel-trie.c
index 4d9ea9f..e2f4c33 100644
--- a/src/camel/camel-trie.c
+++ b/src/camel/camel-trie.c
@@ -101,7 +101,7 @@ trie_utf8_getc (const guchar **in,
 }
 
 /**
- * camel_trie_new:
+ * camel_trie_new: (skip)
  * @icase: Case sensitivity for the #CamelTrie.
  *
  * Creates a new #CamelTrie. If @icase is %TRUE, then pattern matching
@@ -132,7 +132,7 @@ camel_trie_new (gboolean icase)
 }
 
 /**
- * camel_trie_free:
+ * camel_trie_free: (skip)
  * @trie: The #CamelTrie to free.
  *
  * Frees the memory associated with the #CamelTrie @trie.
@@ -232,7 +232,7 @@ dump_trie (struct _trie_state *s,
 */
 
 /**
- * camel_trie_add:
+ * camel_trie_add: (skip)
  * @trie: The #CamelTrie to add a pattern to.
  * @pattern: The pattern to add.
  * @pattern_id: The id to use for the pattern.
@@ -329,15 +329,15 @@ camel_trie_add (CamelTrie *trie,
  */
 
 /**
- * camel_trie_search:
+ * camel_trie_search: (skip)
  * @trie: The #CamelTrie to search in.
- * @buffer: The string to match against a pattern in @trie.
+ * @buffer: (array length=buflen) (type gchar): The string to match against a pattern in @trie.
  * @buflen: The length of @buffer.
- * @matched_id: An integer address to store the matched pattern id in.
+ * @matched_id: (out): An integer address to store the matched pattern id in.
  *
  * Try to match the string @buffer with a pattern in @trie.
  *
- * Returns: The matched pattern, or %NULL if no pattern is matched.
+ * Returns: (nullable): The matched pattern, or %NULL if no pattern is matched.
  *
  * Since: 2.24
  **/
diff --git a/src/camel/camel-uid-cache.c b/src/camel/camel-uid-cache.c
index e6fbc28..23237f5 100644
--- a/src/camel/camel-uid-cache.c
+++ b/src/camel/camel-uid-cache.c
@@ -38,7 +38,7 @@ struct _uid_state {
 };
 
 /**
- * camel_uid_cache_new:
+ * camel_uid_cache_new: (skip)
  * @filename: path to load the cache from
  *
  * Creates a new UID cache, initialized from @filename. If @filename
diff --git a/src/camel/camel-url-scanner.c b/src/camel/camel-url-scanner.c
index c977e14..d86a9bc 100644
--- a/src/camel/camel-url-scanner.c
+++ b/src/camel/camel-url-scanner.c
@@ -32,6 +32,11 @@ struct _CamelUrlScanner {
        CamelTrie *trie;
 };
 
+/**
+ * camel_url_scanner_new: (skip)
+ *
+ * Returns: (transfer full): Creates a new #CamelUrlScanner
+ **/
 CamelUrlScanner *
 camel_url_scanner_new (void)
 {
@@ -44,6 +49,12 @@ camel_url_scanner_new (void)
        return scanner;
 }
 
+/**
+ * camel_url_scanner_free: (skip)
+ * @scanner: a #CamelUrlScanner
+ *
+ * Frees the @scanner.
+ **/
 void
 camel_url_scanner_free (CamelUrlScanner *scanner)
 {
@@ -54,6 +65,13 @@ camel_url_scanner_free (CamelUrlScanner *scanner)
        g_free (scanner);
 }
 
+/**
+ * camel_url_scanner_add: (skip)
+ * @scanner: a #CamelUrlScanner
+ * @pattern: a #CamelUrlPattern to add
+ *
+ * Adds a new @pattern into the scanner
+ **/
 void
 camel_url_scanner_add (CamelUrlScanner *scanner,
                        CamelUrlPattern *pattern)
@@ -64,6 +82,17 @@ camel_url_scanner_add (CamelUrlScanner *scanner,
        g_ptr_array_add (scanner->patterns, pattern);
 }
 
+/**
+ * camel_url_scanner_scan: (skip)
+ * @scanner: a #CamelUrlScanner object.
+ * @in: (array length=inlen) (type gchar): the url to scan.
+ * @inlen: length of the in array.
+ * @match: the #CamelUrlMatch structure containing the criterias.
+ *
+ * Scan the @in string with the @match criterias.
+ *
+ * Returns: %TRUE if there is a result.
+ **/
 gboolean
 camel_url_scanner_scan (CamelUrlScanner *scanner,
                         const gchar *in,
diff --git a/src/camel/camel-url.c b/src/camel/camel-url.c
index b51ed09..c089b15 100644
--- a/src/camel/camel-url.c
+++ b/src/camel/camel-url.c
@@ -703,10 +703,15 @@ camel_url_decode (gchar *part)
        } while (*s++);
 }
 
+/**
+ * camel_url_hash:
+ * @u: the base URL
+ *
+ * Returns: the url hash
+ */
 guint
-camel_url_hash (gconstpointer v)
+camel_url_hash (const CamelURL *u)
 {
-       const CamelURL *u = v;
        guint hash = 0;
 
 #define ADD_HASH(s) if (s) hash ^= g_str_hash (s);
@@ -722,7 +727,7 @@ camel_url_hash (gconstpointer v)
        return hash;
 }
 
-static gint
+static gboolean
 check_equal (gchar *s1,
              gchar *s2)
 {
@@ -739,19 +744,24 @@ check_equal (gchar *s1,
        return strcmp (s1, s2) == 0;
 }
 
-gint
-camel_url_equal (gconstpointer v,
-                 gconstpointer v2)
+/**
+ * camel_url_equal:
+ * @u: the base URL
+ * @u2: the URL to compare
+ *
+ * Returns: return %TRUE if the two urls are equal
+ */
+gboolean
+camel_url_equal (const CamelURL *u,
+                 const CamelURL *u2)
 {
-       const CamelURL *u1 = v, *u2 = v2;
-
-       return check_equal (u1->protocol, u2->protocol)
-               && check_equal (u1->user, u2->user)
-               && check_equal (u1->authmech, u2->authmech)
-               && check_equal (u1->host, u2->host)
-               && check_equal (u1->path, u2->path)
-               && check_equal (u1->query, u2->query)
-               && u1->port == u2->port;
+       return check_equal (u->protocol, u2->protocol)
+               && check_equal (u->user, u2->user)
+               && check_equal (u->authmech, u2->authmech)
+               && check_equal (u->host, u2->host)
+               && check_equal (u->path, u2->path)
+               && check_equal (u->query, u2->query)
+               && u->port == u2->port;
 }
 
 /**
@@ -760,7 +770,7 @@ camel_url_equal (gconstpointer v,
  *
  * Copy a #CamelURL.
  *
- * Returns: a duplicate copy of @in
+ * Returns:(transfer full): a duplicate copy of @in
  **/
 CamelURL *
 camel_url_copy (CamelURL *in)
diff --git a/src/camel/camel-url.h b/src/camel/camel-url.h
index db3a26e..951a52a 100644
--- a/src/camel/camel-url.h
+++ b/src/camel/camel-url.h
@@ -62,9 +62,9 @@ CamelURL *    camel_url_new                   (const gchar *url_string,
                                                 GError **error);
 gchar *                camel_url_to_string             (CamelURL *url,
                                                 CamelURLFlags flags);
-guint          camel_url_hash                  (gconstpointer v);
-gint           camel_url_equal                 (gconstpointer v,
-                                                gconstpointer v2);
+guint          camel_url_hash                  (const CamelURL *u);
+gboolean               camel_url_equal                 (const CamelURL *u,
+                                                const CamelURL *u2);
 CamelURL *     camel_url_copy                  (CamelURL *in);
 void           camel_url_free                  (CamelURL *url);
 
diff --git a/src/camel/camel-utf8.c b/src/camel/camel-utf8.c
index b2c7420..d682b80 100644
--- a/src/camel/camel-utf8.c
+++ b/src/camel/camel-utf8.c
@@ -163,18 +163,6 @@ loop:
        return 0xffff;
 }
 
-void
-g_string_append_u (GString *out,
-                   guint32 c)
-{
-       guchar buffer[8];
-       guchar *p = buffer;
-
-       camel_utf8_putc (&p, c);
-       *p = 0;
-       g_string_append (out, (const gchar *) buffer);
-}
-
 static const gchar utf7_alphabet[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
 
@@ -251,11 +239,11 @@ camel_utf7_utf8 (const gchar *ptr)
                                i+=6;
                                if (i >= 16) {
                                        x = (v >> (i - 16)) & 0xffff;
-                                       g_string_append_u (out, x);
+                                       g_string_append_unichar (out, x);
                                        i-=16;
                                }
                        } else {
-                               g_string_append_u (out, c);
+                               g_string_append_unichar (out, c);
                                state = 0;
                        }
                        break;
@@ -379,7 +367,8 @@ camel_utf8_ucs2 (const gchar *pptr)
  *
  * Returns:
  **/
-gchar *camel_ucs2_utf8 (const gchar *ptr)
+gchar *
+camel_ucs2_utf8 (const gchar *ptr)
 {
        guint16 *ucs = (guint16 *) ptr;
        guint32 c;
@@ -387,7 +376,7 @@ gchar *camel_ucs2_utf8 (const gchar *ptr)
        gchar *out;
 
        while ((c = *ucs++))
-               g_string_append_u (work, g_ntohs (c));
+               g_string_append_unichar (work, g_ntohs (c));
 
        out = g_strdup (work->str);
        g_string_free (work, TRUE);
diff --git a/src/camel/camel-utf8.h b/src/camel/camel-utf8.h
index d509f06..48c5e86 100644
--- a/src/camel/camel-utf8.h
+++ b/src/camel/camel-utf8.h
@@ -32,9 +32,6 @@ void camel_utf8_putc (guchar **ptr, guint32 c);
 guint32 camel_utf8_getc (const guchar **ptr);
 guint32 camel_utf8_getc_limit (const guchar **ptr, const guchar *end);
 
-/* utility func for utf8 gstrings */
-void g_string_append_u (GString *out, guint32 c);
-
 /* convert utf7 to/from utf8, actually this is modified IMAP utf7 */
 gchar *camel_utf7_utf8 (const gchar *ptr);
 gchar *camel_utf8_utf7 (const gchar *ptr);
diff --git a/src/camel/camel-utils.c b/src/camel/camel-utils.c
new file mode 100644
index 0000000..b7a0f5d
--- /dev/null
+++ b/src/camel/camel-utils.c
@@ -0,0 +1,173 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "camel-utils.h"
+
+/**
+ * camel_util_bdata_get_number:
+ * @bdata_ptr: a backend specific data (bdata) pointer
+ * @default_value: a value to return, when no data can be read
+ *
+ * Reads a numeric data from the @bdata_ptr and moves the @bdata_ptr
+ * after that number. If the number cannot be read, then the @default_value
+ * is returned instead and the @bdata_ptr is left unchanged. The number
+ * might be previously stored with the camel_util_bdata_put_number().
+ *
+ * Returns: The read number, or the @default_value, if the @bdata_ptr doesn't
+ *    point to a number.
+ *
+ * Since: 3.24
+ **/
+gint64
+camel_util_bdata_get_number (/* const */ gchar **bdata_ptr,
+                            gint64 default_value)
+{
+       gint64 result;
+       gchar *endptr;
+
+       g_return_val_if_fail (bdata_ptr != NULL, default_value);
+
+       if (!bdata_ptr || !*bdata_ptr || !**bdata_ptr)
+               return default_value;
+
+       if (**bdata_ptr == ' ')
+               *bdata_ptr += 1;
+
+       if (!**bdata_ptr)
+               return default_value;
+
+       endptr = *bdata_ptr;
+
+       result = g_ascii_strtoll (*bdata_ptr, &endptr, 10);
+
+       if (endptr == *bdata_ptr)
+               result = default_value;
+       else
+               *bdata_ptr = endptr;
+
+       return result;
+}
+
+/**
+ * camel_util_bdata_put_number:
+ * @bdata_str: a #GString to store a backend specific data (bdata)
+ * @value: a value to store
+ *
+ * Puts the number @value at the end of the @bdata_str. In case the @bdata_str
+ * is not empty a space is added before the numeric @value. The stored value
+ * can be read back with the camel_util_bdata_get_number().
+ *
+ * Since: 3.24
+ **/
+void
+camel_util_bdata_put_number (GString *bdata_str,
+                            gint64 value)
+{
+       g_return_if_fail (bdata_str != NULL);
+
+       if (bdata_str->len && bdata_str->str[bdata_str->len - 1] != ' ')
+               g_string_append_c (bdata_str, ' ');
+
+       g_string_append_printf (bdata_str, "%" G_GINT64_FORMAT, value);
+}
+
+/**
+ * camel_util_bdata_get_string:
+ * @bdata_ptr: a backend specific data (bdata) pointer
+ * @default_value: a value to return, when no data can be read
+ *
+ * Reads a string data from the @bdata_ptr and moves the @bdata_ptr
+ * after that string. If the string cannot be read, then the @default_value
+ * is returned instead and the @bdata_ptr is left unchanged. The string
+ * might be previously stored with the camel_util_bdata_put_string().
+ *
+ * Returns: (transfer full): Newly allocated string, which was read, or
+ *    dupped the @default_value, if the @bdata_ptr doesn't point to a string.
+ *    Free returned pointer with g_free() when done with it.
+ *
+ * Since: 3.24
+ **/
+gchar *
+camel_util_bdata_get_string (/* const */ gchar **bdata_ptr,
+                            const gchar *default_value)
+{
+       gint64 length, has_length;
+       gchar *orig_bdata_ptr;
+       gchar *result;
+
+       g_return_val_if_fail (bdata_ptr != NULL, NULL);
+
+       orig_bdata_ptr = *bdata_ptr;
+
+       length = camel_util_bdata_get_number (bdata_ptr, -1);
+
+       /* might be a '-' sign */
+       if (*bdata_ptr && **bdata_ptr == '-')
+               *bdata_ptr += 1;
+       else
+               length = -1;
+
+       if (length < 0 || !*bdata_ptr || !**bdata_ptr || *bdata_ptr == orig_bdata_ptr) {
+               *bdata_ptr = orig_bdata_ptr;
+
+               return g_strdup (default_value);
+       }
+
+       if (!length)
+               return g_strdup ("");
+
+       has_length = strlen (*bdata_ptr);
+       if (has_length < length)
+               length = has_length;
+
+       result = g_strndup (*bdata_ptr, length);
+       *bdata_ptr += length;
+
+       return result;
+}
+
+/**
+ * camel_util_bdata_put_string:
+ * @bdata_str: a #GString to store a backend specific data (bdata)
+ * @value: a value to store
+ *
+ * Puts the string @value at the end of the @bdata_str. In case the @bdata_str
+ * is not empty a space is added before the string @value. The stored value
+ * can be read back with the camel_util_bdata_get_string().
+ *
+ * The strings are encoded as "length-value", quotes for clarity only.
+ *
+ * Since: 3.24
+ **/
+void
+camel_util_bdata_put_string (GString *bdata_str,
+                            const gchar *value)
+{
+       g_return_if_fail (bdata_str != NULL);
+       g_return_if_fail (value != NULL);
+
+       camel_util_bdata_put_number (bdata_str, strlen (value));
+
+       g_string_append_printf (bdata_str, "-%s", value);
+}
diff --git a/src/camel/camel-utils.h b/src/camel/camel-utils.h
new file mode 100644
index 0000000..25c2864
--- /dev/null
+++ b/src/camel/camel-utils.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_UTILS_H
+#define CAMEL_UTILS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+gint64         camel_util_bdata_get_number     (/* const */ gchar **bdata_ptr,
+                                                gint64 default_value);
+void           camel_util_bdata_put_number     (GString *bdata_str,
+                                                gint64 value);
+gchar *                camel_util_bdata_get_string     (/* const */ gchar **bdata_ptr,
+                                                const gchar *default_value);
+void           camel_util_bdata_put_string     (GString *bdata_str,
+                                                const gchar *value);
+
+G_END_DECLS
+
+#endif /* CAMEL_UTILS_H */
diff --git a/src/camel/camel-vee-data-cache.h b/src/camel/camel-vee-data-cache.h
index 9c42cc4..4220500 100644
--- a/src/camel/camel-vee-data-cache.h
+++ b/src/camel/camel-vee-data-cache.h
@@ -113,6 +113,9 @@ struct _CamelVeeSubfolderData {
 
 struct _CamelVeeSubfolderDataClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_vee_subfolder_data_get_type
@@ -138,6 +141,9 @@ struct _CamelVeeMessageInfoData {
 
 struct _CamelVeeMessageInfoDataClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_vee_message_info_data_get_type
@@ -168,6 +174,9 @@ struct _CamelVeeDataCache {
 
 struct _CamelVeeDataCacheClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_vee_data_cache_get_type   (void) G_GNUC_CONST;
@@ -199,9 +208,7 @@ CamelVeeMessageInfoData *
 void           camel_vee_data_cache_foreach_message_info_data
                                                (CamelVeeDataCache *data_cache,
                                                 CamelFolder *fromfolder,
-                                                void (* func) (CamelVeeMessageInfoData *mi_data,
-                                                CamelFolder *subfolder,
-                                                gpointer user_data),
+                                                CamelForeachInfoData func,
                                                 gpointer user_data);
 void           camel_vee_data_cache_remove_message_info_data
                                                (CamelVeeDataCache *data_cache,
diff --git a/src/camel/camel-vee-folder.c b/src/camel/camel-vee-folder.c
index a6355ad..91af03d 100644
--- a/src/camel/camel-vee-folder.c
+++ b/src/camel/camel-vee-folder.c
@@ -46,6 +46,7 @@ typedef struct _FolderChangedData FolderChangedData;
        ((obj), CAMEL_TYPE_VEE_FOLDER, CamelVeeFolderPrivate))
 
 struct _CamelVeeFolderPrivate {
+       guint32 flags;          /* folder open flags */
        gboolean destroyed;
        GList *subfolders;              /* lock using subfolder_lock before changing/accessing */
        GHashTable *ignore_changed;     /* hash of subfolder pointers to ignore the next folder's 'changed' 
signal */
@@ -137,7 +138,7 @@ vee_folder_note_added_uid (CamelVeeFolder *vfolder,
        const gchar *vuid;
 
        vuid = camel_vee_message_info_data_get_vee_message_uid (added_mi_data);
-       if (!camel_folder_summary_check_uid (&vsummary->summary, vuid)) {
+       if (!camel_folder_summary_check_uid (CAMEL_FOLDER_SUMMARY (vsummary), vuid)) {
                /* add it only if it wasn't in yet */
                CamelVeeMessageInfo *vmi;
 
@@ -145,7 +146,7 @@ vee_folder_note_added_uid (CamelVeeFolder *vfolder,
                if (vmi) {
                        if (changes)
                                camel_folder_change_info_add_uid (changes, vuid);
-                       camel_message_info_unref (vmi);
+                       g_clear_object (&vmi);
 
                        if (vfolder->priv->parent_vee_store)
                                camel_vee_store_note_vuid_used (vfolder->priv->parent_vee_store, 
added_mi_data, vfolder);
@@ -168,7 +169,7 @@ vee_folder_note_unmatch_uid (CamelVeeFolder *vfolder,
        const gchar *vuid;
 
        vuid = camel_vee_message_info_data_get_vee_message_uid (unmatched_mi_data);
-       if (camel_folder_summary_check_uid (&vsummary->summary, vuid)) {
+       if (camel_folder_summary_check_uid (CAMEL_FOLDER_SUMMARY (vsummary), vuid)) {
                g_object_ref (unmatched_mi_data);
 
                /* this one doesn't belong to us anymore */
@@ -263,7 +264,7 @@ vee_folder_merge_matching (CamelVeeFolder *vfolder,
        folder = CAMEL_FOLDER (vfolder);
        g_return_if_fail (folder != NULL);
 
-       vsummary = CAMEL_VEE_SUMMARY (folder->summary);
+       vsummary = CAMEL_VEE_SUMMARY (camel_folder_get_folder_summary (folder));
        g_return_if_fail (vsummary != NULL);
 
        data_cache = vee_folder_get_data_cache (vfolder);
@@ -323,7 +324,7 @@ vee_folder_rebuild_folder_with_changes (CamelVeeFolder *vfolder,
        if (!g_cancellable_is_cancelled (cancellable)) {
                GHashTable *all_uids;
 
-               all_uids = camel_folder_summary_get_hash (subfolder->summary);
+               all_uids = camel_folder_summary_get_hash (camel_folder_get_folder_summary (subfolder));
                vee_folder_merge_matching (vfolder, subfolder, all_uids, match, changes, FALSE);
                g_hash_table_destroy (all_uids);
        }
@@ -394,7 +395,7 @@ vee_folder_subfolder_changed (CamelVeeFolder *vfolder,
 
        changes = camel_folder_change_info_new ();
        v_folder = CAMEL_FOLDER (vfolder);
-       vsummary = CAMEL_VEE_SUMMARY (v_folder->summary);
+       vsummary = CAMEL_VEE_SUMMARY (camel_folder_get_folder_summary (v_folder));
 
        camel_folder_freeze (v_folder);
 
@@ -434,7 +435,7 @@ vee_folder_subfolder_changed (CamelVeeFolder *vfolder,
                                                continue;
 
                                        vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
-                                       if (camel_folder_summary_check_uid (v_folder->summary, vuid))
+                                       if (camel_folder_summary_check_uid (camel_folder_get_folder_summary 
(v_folder), vuid))
                                                g_ptr_array_add (match, (gpointer) camel_pstring_strdup 
(test_uids->pdata[ii]));
                                        g_object_unref (mi_data);
                                }
@@ -557,7 +558,7 @@ vee_folder_dispose (GObject *object)
        folder = CAMEL_FOLDER (object);
 
        /* parent's class frees summary on dispose, thus depend on it */
-       if (folder->summary) {
+       if (camel_folder_get_folder_summary (folder)) {
                CamelVeeFolder *vfolder;
 
                vfolder = CAMEL_VEE_FOLDER (object);
@@ -679,7 +680,7 @@ vee_folder_propagate_skipped_changes (CamelVeeFolder *vf)
 
                changes = camel_folder_change_info_new ();
                v_folder = CAMEL_FOLDER (vf);
-               vsummary = CAMEL_VEE_SUMMARY (v_folder->summary);
+               vsummary = CAMEL_VEE_SUMMARY (camel_folder_get_folder_summary (v_folder));
 
                /* first remove ... */
                g_hash_table_iter_init (&iter, vf->priv->unmatched_remove_changed);
@@ -727,6 +728,17 @@ vee_folder_propagate_skipped_changes (CamelVeeFolder *vf)
        }
 }
 
+static guint32
+vee_folder_get_permanent_flags (CamelFolder *folder)
+{
+       /* FIXME: what to do about user flags if the subfolder doesn't support them? */
+       return CAMEL_MESSAGE_ANSWERED |
+               CAMEL_MESSAGE_DELETED |
+               CAMEL_MESSAGE_DRAFT |
+               CAMEL_MESSAGE_FLAGGED |
+               CAMEL_MESSAGE_SEEN;
+}
+
 static GPtrArray *
 vee_folder_search_by_expression (CamelFolder *folder,
                                  const gchar *expression,
@@ -902,12 +914,12 @@ vee_folder_get_message_sync (CamelFolder *folder,
        CamelVeeMessageInfo *mi;
        CamelMimeMessage *msg = NULL;
 
-       mi = (CamelVeeMessageInfo *) camel_folder_summary_get (folder->summary, uid);
+       mi = (CamelVeeMessageInfo *) camel_folder_summary_get (camel_folder_get_folder_summary (folder), uid);
        if (mi) {
                msg = camel_folder_get_message_sync (
-                       camel_folder_summary_get_folder (mi->orig_summary), camel_message_info_get_uid (mi) + 
8,
+                       camel_vee_message_info_get_original_folder (mi), camel_message_info_get_uid 
(CAMEL_MESSAGE_INFO (mi)) + 8,
                        cancellable, error);
-               camel_message_info_unref (mi);
+               g_clear_object (&mi);
        } else {
                g_set_error (
                        error, CAMEL_FOLDER_ERROR,
@@ -1081,12 +1093,12 @@ vee_folder_remove_folder (CamelVeeFolder *vfolder,
 
        camel_folder_freeze (v_folder);
 
-       uids = camel_vee_summary_get_uids_for_subfolder (CAMEL_VEE_SUMMARY (v_folder->summary), subfolder);
+       uids = camel_vee_summary_get_uids_for_subfolder (CAMEL_VEE_SUMMARY (camel_folder_get_folder_summary 
(v_folder)), subfolder);
        if (uids) {
                struct RemoveUnmatchedData rud;
 
                rud.vfolder = vfolder;
-               rud.vsummary = CAMEL_VEE_SUMMARY (v_folder->summary);
+               rud.vsummary = CAMEL_VEE_SUMMARY (camel_folder_get_folder_summary (v_folder));
                rud.subfolder = subfolder;
                rud.data_cache = vee_folder_get_data_cache (vfolder);
                rud.changes = changes;
@@ -1190,6 +1202,7 @@ camel_vee_folder_class_init (CamelVeeFolderClass *class)
        object_class->set_property = vee_folder_set_property;
 
        folder_class = CAMEL_FOLDER_CLASS (class);
+       folder_class->get_permanent_flags = vee_folder_get_permanent_flags;
        folder_class->search_by_expression = vee_folder_search_by_expression;
        folder_class->search_by_uids = vee_folder_search_by_uids;
        folder_class->count_by_expression = vee_folder_count_by_expression;
@@ -1229,14 +1242,7 @@ camel_vee_folder_init (CamelVeeFolder *vee_folder)
 
        vee_folder->priv = CAMEL_VEE_FOLDER_GET_PRIVATE (vee_folder);
 
-       folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
-
-       /* FIXME: what to do about user flags if the subfolder doesn't support them? */
-       folder->permanent_flags = CAMEL_MESSAGE_ANSWERED |
-               CAMEL_MESSAGE_DELETED |
-               CAMEL_MESSAGE_DRAFT |
-               CAMEL_MESSAGE_FLAGGED |
-               CAMEL_MESSAGE_SEEN;
+       camel_folder_set_flags (folder, camel_folder_get_flags (folder) | 
CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY);
 
        g_rec_mutex_init (&vee_folder->priv->subfolder_lock);
        g_rec_mutex_init (&vee_folder->priv->changed_lock);
@@ -1253,6 +1259,14 @@ camel_vee_folder_init (CamelVeeFolder *vee_folder)
                (GDestroyNotify) vee_folder_changed_data_free);
 }
 
+/**
+ * camel_vee_folder_construct:
+ * @vf: a #CamelVeeFolder
+ * @flags: flags for the @vf
+ *
+ * Initializes internal structures of the @vf. This is meant to be
+ * called by the descendants of #CamelVeeFolder.
+ **/
 void
 camel_vee_folder_construct (CamelVeeFolder *vf,
                             guint32 flags)
@@ -1260,7 +1274,7 @@ camel_vee_folder_construct (CamelVeeFolder *vf,
        CamelFolder *folder = (CamelFolder *) vf;
        CamelStore *parent_store;
 
-       vf->flags = flags;
+       vf->priv->flags = flags;
 
        parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (vf));
        if (CAMEL_IS_VEE_STORE (parent_store))
@@ -1268,7 +1282,7 @@ camel_vee_folder_construct (CamelVeeFolder *vf,
        else
                vf->priv->vee_data_cache = camel_vee_data_cache_new ();
 
-       folder->summary = camel_vee_summary_new (folder);
+       camel_folder_take_folder_summary (folder, camel_vee_summary_new (folder));
 
        /* only for subfolders of vee-store */
        if (vf->priv->parent_vee_store) {
@@ -1293,6 +1307,22 @@ camel_vee_folder_construct (CamelVeeFolder *vf,
 }
 
 /**
+ * camel_vee_folder_get_flags:
+ * @vf: a #CamelVeeFolder
+ *
+ * Returns: flags of @vf, as set by camel_vee_folder_construct()
+ *
+ * Since: 3.24
+ **/
+guint32
+camel_vee_folder_get_flags (CamelVeeFolder *vf)
+{
+       g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (vf), 0);
+
+       return vf->priv->flags;
+}
+
+/**
  * camel_vee_folder_new:
  * @parent_store: the parent CamelVeeStore
  * @full: the full path to the vfolder.
@@ -1531,6 +1561,9 @@ camel_vee_folder_set_folders (CamelVeeFolder *vf,
 
 /**
  * camel_vee_folder_add_vuid:
+ * @vfolder:
+ * @mi_data: (type CamelVeeMessageInfoData):
+ * @changes:
  *
  * FIXME Document me!
  *
@@ -1576,12 +1609,15 @@ camel_vee_folder_add_vuid (CamelVeeFolder *vfolder,
 
        g_rec_mutex_unlock (&vfolder->priv->changed_lock);
 
-       vsummary = CAMEL_VEE_SUMMARY (CAMEL_FOLDER (vfolder)->summary);
+       vsummary = CAMEL_VEE_SUMMARY (camel_folder_get_folder_summary (CAMEL_FOLDER (vfolder)));
        vee_folder_note_added_uid (vfolder, vsummary, mi_data, changes, FALSE);
 }
 
 /**
  * camel_vee_folder_remove_vuid:
+ * @vfolder:
+ * @mi_data: (type CamelVeeMessageInfoData):
+ * @changes:
  *
  * FIXME Document me!
  *
@@ -1628,7 +1664,7 @@ camel_vee_folder_remove_vuid (CamelVeeFolder *vfolder,
 
        g_rec_mutex_unlock (&vfolder->priv->changed_lock);
 
-       vsummary = CAMEL_VEE_SUMMARY (CAMEL_FOLDER (vfolder)->summary);
+       vsummary = CAMEL_VEE_SUMMARY (camel_folder_get_folder_summary (CAMEL_FOLDER (vfolder)));
        data_cache = vee_folder_get_data_cache (vfolder);
 
        /* It can be NULL on dispose of the CamelVeeStore */
@@ -1653,25 +1689,29 @@ camel_vee_folder_get_location (CamelVeeFolder *vf,
                                gchar **realuid)
 {
        CamelFolder *folder;
+       const gchar *uid;
 
        g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (vf), NULL);
        g_return_val_if_fail (vinfo != NULL, NULL);
 
-       folder = camel_folder_summary_get_folder (vinfo->orig_summary);
+       folder = camel_vee_message_info_get_original_folder (vinfo);
+       uid = camel_message_info_get_uid (CAMEL_MESSAGE_INFO (vinfo));
+
+       g_return_val_if_fail (uid != NULL && strlen (uid) > 8, NULL);
 
        /* locking?  yes?  no?  although the vfolderinfo is valid when obtained
         * the folder in it might not necessarily be so ...? */
        if (CAMEL_IS_VEE_FOLDER (folder)) {
                CamelFolder *res;
-               const CamelVeeMessageInfo *vfinfo;
+               CamelMessageInfo *vfinfo;
 
-               vfinfo = (CamelVeeMessageInfo *) camel_folder_get_message_info (folder, 
camel_message_info_get_uid (vinfo) + 8);
-               res = camel_vee_folder_get_location ((CamelVeeFolder *) folder, vfinfo, realuid);
-               camel_message_info_unref ((CamelMessageInfo *) vfinfo);
+               vfinfo = camel_folder_get_message_info (folder, uid + 8);
+               res = camel_vee_folder_get_location ((CamelVeeFolder *) folder, CAMEL_VEE_MESSAGE_INFO 
(vfinfo), realuid);
+               g_clear_object (&vfinfo);
                return res;
        } else {
                if (realuid)
-                       *realuid = g_strdup (camel_message_info_get_uid (vinfo)+8);
+                       *realuid = g_strdup (uid + 8);
 
                return folder;
        }
diff --git a/src/camel/camel-vee-folder.h b/src/camel/camel-vee-folder.h
index c1854bc..bee2eed 100644
--- a/src/camel/camel-vee-folder.h
+++ b/src/camel/camel-vee-folder.h
@@ -57,8 +57,6 @@ typedef struct _CamelVeeFolderPrivate CamelVeeFolderPrivate;
 struct _CamelVeeFolder {
        CamelFolder parent;
        CamelVeeFolderPrivate *priv;
-
-       guint32 flags;          /* folder open flags */
 };
 
 struct _CamelVeeFolderClass {
@@ -83,6 +81,9 @@ struct _CamelVeeFolderClass {
        void            (*folder_changed)       (CamelVeeFolder *vfolder,
                                                 CamelFolder *subfolder,
                                                 CamelFolderChangeInfo *changes);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 #define CAMEL_UNMATCHED_NAME "UNMATCHED"
@@ -93,9 +94,9 @@ CamelFolder * camel_vee_folder_new                    (CamelStore *parent_store,
                                                         guint32 flags);
 void           camel_vee_folder_construct              (CamelVeeFolder *vf,
                                                         guint32 flags);
-
+guint32                camel_vee_folder_get_flags              (CamelVeeFolder *vf);
 CamelFolder *  camel_vee_folder_get_location           (CamelVeeFolder *vf,
-                                                        const struct _CamelVeeMessageInfo *vinfo,
+                                                        const CamelVeeMessageInfo *vinfo,
                                                         gchar **realuid);
 CamelFolder *  camel_vee_folder_get_vee_uid_folder     (CamelVeeFolder *vf,
                                                         const gchar *vee_message_uid);
diff --git a/src/camel/camel-vee-message-info.c b/src/camel/camel-vee-message-info.c
new file mode 100644
index 0000000..b0b3e0d
--- /dev/null
+++ b/src/camel/camel-vee-message-info.c
@@ -0,0 +1,532 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+
+#include "camel-folder.h"
+#include "camel-folder-summary.h"
+#include "camel-message-info.h"
+#include "camel-string-utils.h"
+#include "camel-vee-folder.h"
+#include "camel-vee-summary.h"
+#include "camel-vtrash-folder.h"
+
+#include "camel-vee-message-info.h"
+
+struct _CamelVeeMessageInfoPrivate {
+       CamelFolderSummary *orig_summary;
+};
+
+G_DEFINE_TYPE (CamelVeeMessageInfo, camel_vee_message_info, CAMEL_TYPE_MESSAGE_INFO)
+
+static CamelMessageInfo *
+vee_message_info_clone (const CamelMessageInfo *mi,
+                       CamelFolderSummary *assign_summary)
+{
+       CamelMessageInfo *result;
+
+       g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO (mi), NULL);
+
+       result = CAMEL_MESSAGE_INFO_CLASS (camel_vee_message_info_parent_class)->clone (mi, assign_summary);
+       if (!result)
+               return NULL;
+
+       if (CAMEL_IS_VEE_MESSAGE_INFO (result)) {
+               CamelVeeMessageInfo *vmi, *vmi_result;
+
+               vmi = CAMEL_VEE_MESSAGE_INFO (mi);
+               vmi_result = CAMEL_VEE_MESSAGE_INFO (result);
+
+               if (vmi->priv->orig_summary)
+                       vmi_result->priv->orig_summary = g_object_ref (vmi->priv->orig_summary);
+       }
+
+       return result;
+}
+
+static void
+vee_message_info_notify_mi_changed (CamelFolder *folder,
+                                   const gchar *mi_uid)
+{
+       CamelFolderChangeInfo *changes;
+
+       g_return_if_fail (CAMEL_IS_VEE_FOLDER (folder));
+       g_return_if_fail (mi_uid != NULL);
+
+       changes = camel_folder_change_info_new ();
+       camel_folder_change_info_change_uid (changes, mi_uid);
+       camel_folder_changed (folder, changes);
+       camel_folder_change_info_free (changes);
+}
+
+#define vee_call_from_parent_mi(_err_ret, _ret_type, _call_what, _call_args, _is_set) G_STMT_START {   \
+               CamelVeeMessageInfo *vmi;                                                       \
+               CamelMessageInfo *orig_mi;                                                      \
+               CamelFolderSummary *this_summary, *sub_summary;                                 \
+               CamelFolder *this_folder, *sub_folder;                                          \
+               gboolean ignore_changes;                                                        \
+               const gchar *uid;                                                               \
+               _ret_type result;                                                               \
+                                                                                               \
+               g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO (mi), _err_ret);                \
+                                                                                               \
+               vmi = CAMEL_VEE_MESSAGE_INFO (mi);                                              \
+               g_return_val_if_fail (vmi->priv->orig_summary != NULL, _err_ret);               \
+                                                                                               \
+               uid = camel_message_info_pooldup_uid (mi);                                      \
+               g_return_val_if_fail (uid != NULL, _err_ret);                                   \
+                                                                                               \
+               if (!uid[0] || !uid[1] || !uid[2] || !uid[3] || !uid[4] ||                      \
+                   !uid[5] || !uid[6] || !uid[7] || !uid[8]) {                                 \
+                       camel_pstring_free (uid);                                               \
+                       g_warn_if_reached ();                                                   \
+                       return _err_ret;                                                        \
+               }                                                                               \
+                                                                                               \
+               orig_mi = (CamelMessageInfo *) camel_folder_summary_get (vmi->priv->orig_summary, uid + 8);   
          \
+               if (!orig_mi) {                                                                 \
+                       g_warning ("%s: Failed to get orig uid '%s'\n", G_STRFUNC, uid);        \
+                       camel_pstring_free (uid);                                               \
+                       return _err_ret;                                                        \
+               }                                                                               \
+                                                                                               \
+               this_summary = camel_message_info_ref_summary (mi);                             \
+               this_folder = this_summary ? camel_folder_summary_get_folder (this_summary) : NULL; \
+               sub_summary = camel_message_info_ref_summary (orig_mi);                         \
+               sub_folder = sub_summary ? camel_folder_summary_get_folder (sub_summary) : NULL; \
+                                                                                               \
+               ignore_changes = _is_set && !CAMEL_IS_VTRASH_FOLDER (this_folder);              \
+                                                                                               \
+               /* ignore changes done in the folder itself,                                    \
+                * unless it's a vTrash or vJunk folder */                                      \
+               if (ignore_changes)                                                             \
+                       camel_vee_folder_ignore_next_changed_event (CAMEL_VEE_FOLDER (this_folder), 
sub_folder); \
+                                                                                               \
+               result = _call_what _call_args;                                                 \
+                                                                                               \
+               if (ignore_changes) {                                                           \
+                       if (result)                                                             \
+                               vee_message_info_notify_mi_changed (this_folder, uid);          \
+                       else                                                                    \
+                               camel_vee_folder_remove_from_ignore_changed_event (             \
+                                       CAMEL_VEE_FOLDER (this_folder), sub_folder);            \
+               }                                                                               \
+                                                                                               \
+               g_clear_object (&this_summary);                                                 \
+               g_clear_object (&sub_summary);                                                  \
+               g_clear_object (&orig_mi);                                                      \
+               camel_pstring_free (uid);                                                       \
+                                                                                               \
+               return result;                                                                  \
+       } G_STMT_END
+
+static guint32
+vee_message_info_get_flags (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (0, guint32, camel_message_info_get_flags, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_flags_real (CamelMessageInfo *mi,
+                                guint32 mask,
+                                guint32 set)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_flags, (orig_mi, mask, set), TRUE);
+}
+
+static gboolean
+vee_message_info_set_flags (CamelMessageInfo *mi,
+                           guint32 mask,
+                           guint32 set)
+{
+       gboolean result;
+
+       result = vee_message_info_set_flags_real (mi, mask, set);
+
+       if (result) {
+               CamelFolderSummary *summary;
+
+               summary = camel_message_info_ref_summary (mi);
+               if (summary)
+                       camel_folder_summary_replace_flags (summary, mi);
+               g_clear_object (&summary);
+       }
+
+       return result;
+}
+
+static gboolean
+vee_message_info_get_user_flag (const CamelMessageInfo *mi,
+                               const gchar *name)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_get_user_flag, (orig_mi, name), FALSE);
+}
+
+static gboolean
+vee_message_info_set_user_flag (CamelMessageInfo *mi,
+                               const gchar *name,
+                               gboolean state)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_user_flag, (orig_mi, name, state), 
TRUE);
+}
+
+static const CamelNamedFlags *
+vee_message_info_get_user_flags (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const CamelNamedFlags *, camel_message_info_get_user_flags, (orig_mi), 
FALSE);
+}
+
+static CamelNamedFlags *
+vee_message_info_dup_user_flags (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, CamelNamedFlags *, camel_message_info_dup_user_flags, (orig_mi), 
FALSE);
+}
+
+static gboolean
+vee_message_info_take_user_flags (CamelMessageInfo *mi,
+                                 CamelNamedFlags *user_flags)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_take_user_flags, (orig_mi, user_flags), 
TRUE);
+}
+
+static const gchar *
+vee_message_info_get_user_tag (const CamelMessageInfo *mi,
+                              const gchar *name)
+{
+       vee_call_from_parent_mi (NULL, const gchar *, camel_message_info_get_user_tag, (orig_mi, name), 
FALSE);
+}
+
+static gboolean
+vee_message_info_set_user_tag (CamelMessageInfo *mi,
+                              const gchar *name,
+                              const gchar *value)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_user_tag, (orig_mi, name, value), 
TRUE);
+}
+
+static CamelNameValueArray *
+vee_message_info_dup_user_tags (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, CamelNameValueArray *, camel_message_info_dup_user_tags, (orig_mi), 
FALSE);
+}
+
+static const CamelNameValueArray *
+vee_message_info_get_user_tags (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const CamelNameValueArray *, camel_message_info_get_user_tags, 
(orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_take_user_tags (CamelMessageInfo *mi,
+                                CamelNameValueArray *user_tags)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_take_user_tags, (orig_mi, user_tags), 
TRUE);
+}
+
+static const gchar *
+vee_message_info_get_subject (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const gchar *, camel_message_info_get_subject, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_subject (CamelMessageInfo *mi,
+                             const gchar *subject)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_subject, (orig_mi, subject), TRUE);
+}
+
+static const gchar *
+vee_message_info_get_from (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const gchar *, camel_message_info_get_from, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_from (CamelMessageInfo *mi,
+                          const gchar *from)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_from, (orig_mi, from), TRUE);
+}
+
+static const gchar *
+vee_message_info_get_to (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const gchar *, camel_message_info_get_to, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_to (CamelMessageInfo *mi,
+                        const gchar *to)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_to, (orig_mi, to), TRUE);
+}
+
+static const gchar *
+vee_message_info_get_cc (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const gchar *, camel_message_info_get_cc, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_cc (CamelMessageInfo *mi,
+                        const gchar *cc)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_cc, (orig_mi, cc), TRUE);
+}
+
+static const gchar *
+vee_message_info_get_mlist (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const gchar *, camel_message_info_get_mlist, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_mlist (CamelMessageInfo *mi,
+                           const gchar *mlist)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_mlist, (orig_mi, mlist), TRUE);
+}
+
+static guint32
+vee_message_info_get_size (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (0, guint32, camel_message_info_get_size, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_size (CamelMessageInfo *mi,
+                          guint32 size)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_size, (orig_mi, size), TRUE);
+}
+
+static gint64
+vee_message_info_get_date_sent (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (0, gint64, camel_message_info_get_date_sent, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_date_sent (CamelMessageInfo *mi,
+                               gint64 date_sent)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_date_sent, (orig_mi, date_sent), 
TRUE);
+}
+
+static gint64
+vee_message_info_get_date_received (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (0, gint64, camel_message_info_get_date_received, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_date_received (CamelMessageInfo *mi,
+                                   gint64 date_received)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_date_received, (orig_mi, 
date_received), TRUE);
+}
+
+static guint64
+vee_message_info_get_message_id (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (0, guint64, camel_message_info_get_message_id, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_set_message_id (CamelMessageInfo *mi,
+                                guint64 message_id)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_set_message_id, (orig_mi, message_id), 
TRUE);
+}
+
+static const GArray *
+vee_message_info_get_references (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const GArray *, camel_message_info_get_references, (orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_take_references (CamelMessageInfo *mi,
+                                 GArray *references)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_take_references, (orig_mi, references), 
TRUE);
+}
+
+static const CamelNameValueArray *
+vee_message_info_get_headers (const CamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const CamelNameValueArray *, camel_message_info_get_headers, 
(orig_mi), FALSE);
+}
+
+static gboolean
+vee_message_info_take_headers (CamelMessageInfo *mi,
+                              CamelNameValueArray *headers)
+{
+       vee_call_from_parent_mi (FALSE, gboolean, camel_message_info_take_headers, (orig_mi, headers), TRUE);
+}
+
+#undef vee_call_from_parent_mi
+
+static void
+vee_message_info_dispose (GObject *object)
+{
+       CamelVeeMessageInfo *vmi = CAMEL_VEE_MESSAGE_INFO (object);
+
+       g_clear_object (&vmi->priv->orig_summary);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_vee_message_info_parent_class)->dispose (object);
+}
+
+static void
+camel_vee_message_info_class_init (CamelVeeMessageInfoClass *class)
+{
+       CamelMessageInfoClass *mi_class;
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelVeeMessageInfoPrivate));
+
+       mi_class = CAMEL_MESSAGE_INFO_CLASS (class);
+       mi_class->clone = vee_message_info_clone;
+       mi_class->get_flags = vee_message_info_get_flags;
+       mi_class->set_flags = vee_message_info_set_flags;
+       mi_class->get_user_flag = vee_message_info_get_user_flag;
+       mi_class->set_user_flag = vee_message_info_set_user_flag;
+       mi_class->get_user_flags = vee_message_info_get_user_flags;
+       mi_class->dup_user_flags = vee_message_info_dup_user_flags;
+       mi_class->take_user_flags = vee_message_info_take_user_flags;
+       mi_class->get_user_tag = vee_message_info_get_user_tag;
+       mi_class->set_user_tag = vee_message_info_set_user_tag;
+       mi_class->get_user_tags = vee_message_info_get_user_tags;
+       mi_class->dup_user_tags = vee_message_info_dup_user_tags;
+       mi_class->take_user_tags = vee_message_info_take_user_tags;
+       mi_class->get_subject = vee_message_info_get_subject;
+       mi_class->set_subject = vee_message_info_set_subject;
+       mi_class->get_from = vee_message_info_get_from;
+       mi_class->set_from = vee_message_info_set_from;
+       mi_class->get_to = vee_message_info_get_to;
+       mi_class->set_to = vee_message_info_set_to;
+       mi_class->get_cc = vee_message_info_get_cc;
+       mi_class->set_cc = vee_message_info_set_cc;
+       mi_class->get_mlist = vee_message_info_get_mlist;
+       mi_class->set_mlist = vee_message_info_set_mlist;
+       mi_class->get_size = vee_message_info_get_size;
+       mi_class->set_size = vee_message_info_set_size;
+       mi_class->get_date_sent = vee_message_info_get_date_sent;
+       mi_class->set_date_sent = vee_message_info_set_date_sent;
+       mi_class->get_date_received = vee_message_info_get_date_received;
+       mi_class->set_date_received = vee_message_info_set_date_received;
+       mi_class->get_message_id = vee_message_info_get_message_id;
+       mi_class->set_message_id = vee_message_info_set_message_id;
+       mi_class->get_references = vee_message_info_get_references;
+       mi_class->take_references = vee_message_info_take_references;
+       mi_class->get_headers = vee_message_info_get_headers;
+       mi_class->take_headers = vee_message_info_take_headers;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = vee_message_info_dispose;
+}
+
+static void
+camel_vee_message_info_init (CamelVeeMessageInfo *vmi)
+{
+       vmi->priv = G_TYPE_INSTANCE_GET_PRIVATE (vmi, CAMEL_TYPE_VEE_MESSAGE_INFO, 
CamelVeeMessageInfoPrivate);
+}
+
+/**
+ * camel_vee_message_info_new:
+ * @summary: a #CamelVeeSummary, the "owner" of the created message info
+ * @original_summary: an original #CamelFolderSummary to reference to
+ * @vuid: what UID to set on the resulting message info
+ *
+ * Creates a new instance of #CamelVeeMessageInfo which references
+ * a message from the @original_summary internally.
+ *
+ * The @vuid should be encoded in a way which the vFolder understands,
+ * which is like the one returned by camel_vee_message_info_data_get_vee_message_uid().
+ *
+ * Returns: (transfer full): a newly created #CamelVeeMessageInfo
+ *   which references @orig_mi. Free with g_object_unref() when done
+ *   with it.
+ *
+ * Since: 3.24
+ **/
+CamelMessageInfo *
+camel_vee_message_info_new (CamelFolderSummary *summary,
+                           CamelFolderSummary *original_summary,
+                           const gchar *vuid)
+{
+       CamelMessageInfo *mi;
+       CamelVeeMessageInfo *vmi;
+
+       g_return_val_if_fail (CAMEL_IS_VEE_SUMMARY (summary), NULL);
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (original_summary), NULL);
+       g_return_val_if_fail (vuid != NULL, NULL);
+       g_return_val_if_fail (vuid[0] && vuid[1] && vuid[2] && vuid[3] && vuid[4] && vuid[5] && vuid[6] && 
vuid[7] && vuid[8], NULL);
+
+       mi = camel_message_info_new (summary);
+       g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO (mi), NULL);
+
+       vmi = CAMEL_VEE_MESSAGE_INFO (mi);
+       vmi->priv->orig_summary = g_object_ref (original_summary);
+
+       camel_message_info_set_uid (mi, vuid);
+
+       return mi;
+}
+
+/**
+ * camel_vee_message_info_get_original_summary:
+ * @vmi: a #CamelVeeMessageInfo
+ *
+ * Returns: (transfer none): A #CamelFolderSummary of the original
+ *   message info, which this @vmi is proxying.
+ *
+ * Since: 3.24
+ **/
+CamelFolderSummary *
+camel_vee_message_info_get_original_summary (const CamelVeeMessageInfo *vmi)
+{
+       g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO (vmi), NULL);
+
+       return vmi->priv->orig_summary;
+}
+
+/**
+ * camel_vee_message_info_get_original_folder:
+ * @vmi: a #CamelVeeMessageInfo
+ *
+ * Returns: (transfer none): A #CamelFolder of the original
+ *   message info, which this @vmi is proxying.
+ *
+ * Since: 3.24
+ **/
+CamelFolder *
+camel_vee_message_info_get_original_folder (const CamelVeeMessageInfo *vmi)
+{
+       g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO (vmi), NULL);
+
+       if (!vmi->priv->orig_summary)
+               return NULL;
+
+       return camel_folder_summary_get_folder (vmi->priv->orig_summary);
+}
diff --git a/src/camel/camel-vee-message-info.h b/src/camel/camel-vee-message-info.h
new file mode 100644
index 0000000..3ba0b72
--- /dev/null
+++ b/src/camel/camel-vee-message-info.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_VEE_MESSAGE_INFO_H
+#define CAMEL_VEE_MESSAGE_INFO_H
+
+#include <glib-object.h>
+
+#include <camel/camel-message-info.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_VEE_MESSAGE_INFO \
+       (camel_vee_message_info_get_type ())
+#define CAMEL_VEE_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_VEE_MESSAGE_INFO, CamelVeeMessageInfo))
+#define CAMEL_VEE_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_VEE_MESSAGE_INFO, CamelVeeMessageInfoClass))
+#define CAMEL_IS_VEE_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_VEE_MESSAGE_INFO))
+#define CAMEL_IS_VEE_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_VEE_MESSAGE_INFO))
+#define CAMEL_VEE_MESSAGE_INFO_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_VEE_MESSAGE_INFO, CamelVeeMessageInfoClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelVeeMessageInfo CamelVeeMessageInfo;
+typedef struct _CamelVeeMessageInfoClass CamelVeeMessageInfoClass;
+typedef struct _CamelVeeMessageInfoPrivate CamelVeeMessageInfoPrivate;
+
+struct _CamelVeeMessageInfo {
+       CamelMessageInfo parent;
+       CamelVeeMessageInfoPrivate *priv;
+};
+
+struct _CamelVeeMessageInfoClass {
+       CamelMessageInfoClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
+};
+
+GType          camel_vee_message_info_get_type (void);
+CamelMessageInfo *
+               camel_vee_message_info_new      (CamelFolderSummary *summary,
+                                                CamelFolderSummary *original_summary,
+                                                const gchar *vuid);
+CamelFolderSummary *
+               camel_vee_message_info_get_original_summary
+                                               (const CamelVeeMessageInfo *vmi);
+CamelFolder *
+               camel_vee_message_info_get_original_folder
+                                               (const CamelVeeMessageInfo *vmi);
+
+G_END_DECLS
+
+#endif /* CAMEL_VEE_MESSAGE_INFO_H */
diff --git a/src/camel/camel-vee-store.c b/src/camel/camel-vee-store.c
index 393207c..0b5d31a 100644
--- a/src/camel/camel-vee-store.c
+++ b/src/camel/camel-vee-store.c
@@ -220,7 +220,7 @@ vee_store_get_folder_sync (CamelStore *store,
        gsize name_len;
 
        vf = (CamelVeeFolder *) camel_vee_folder_new (store, folder_name, flags);
-       if (vf && ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0)) {
+       if (vf && ((camel_vee_folder_get_flags (vf) & CAMEL_STORE_FOLDER_PRIVATE) == 0)) {
                const gchar *full_name;
 
                full_name = camel_folder_get_full_name (CAMEL_FOLDER (vf));
@@ -233,11 +233,11 @@ vee_store_get_folder_sync (CamelStore *store,
                while ( (p = strchr (p, '/'))) {
                        *p = 0;
 
-                       folder = camel_object_bag_reserve (store->folders, name);
+                       folder = camel_object_bag_reserve (camel_store_get_folders_bag (store), name);
                        if (folder == NULL) {
                                /* create a dummy vFolder for this, makes get_folder_info simpler */
                                folder = camel_vee_folder_new (store, name, flags);
-                               camel_object_bag_add (store->folders, name, folder);
+                               camel_object_bag_add (camel_store_get_folders_bag (store), name, folder);
                                change_folder (store, name, CHANGE_ADD | CHANGE_NOSELECT, 0);
                                /* FIXME: this sort of leaks folder, nobody owns a ref to it but us */
                        } else {
@@ -285,7 +285,7 @@ vee_store_get_folder_info_sync (CamelStore *store,
        d (printf ("Get folder info '%s'\n", top ? top:"<null>"));
 
        infos_hash = g_hash_table_new (g_str_hash, g_str_equal);
-       folders = camel_object_bag_list (store->folders);
+       folders = camel_store_dup_opened_folders (store);
        qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), vee_folder_cmp);
        for (i = 0; i < folders->len; i++) {
                CamelVeeFolder *folder = folders->pdata[i];
@@ -366,8 +366,8 @@ vee_store_get_folder_info_sync (CamelStore *store,
                }
 
                g_free (pname);
-               g_object_unref (folder);
        }
+       g_ptr_array_foreach (folders, (GFunc) g_object_unref, NULL);
        g_ptr_array_free (folders, TRUE);
        g_hash_table_destroy (infos_hash);
 
@@ -422,7 +422,7 @@ vee_store_delete_folder_sync (CamelStore *store,
                return FALSE;
        }
 
-       folder = camel_object_bag_get (store->folders, folder_name);
+       folder = camel_object_bag_get (camel_store_get_folders_bag (store), folder_name);
        if (folder) {
                CamelObject *object = CAMEL_OBJECT (folder);
                const gchar *state_filename;
@@ -433,7 +433,7 @@ vee_store_delete_folder_sync (CamelStore *store,
                        camel_object_set_state_filename (object, NULL);
                }
 
-               if ((((CamelVeeFolder *) folder)->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
+               if ((camel_vee_folder_get_flags (CAMEL_VEE_FOLDER (folder)) & CAMEL_STORE_FOLDER_PRIVATE) == 
0) {
                        /* what about now-empty parents?  ignore? */
                        change_folder (store, folder_name, CHANGE_DELETE, -1);
                }
@@ -473,7 +473,7 @@ vee_store_rename_folder_sync (CamelStore *store,
        }
 
        /* See if it exists, for vfolders, all folders are in the folders hash */
-       oldfolder = camel_object_bag_get (store->folders, old);
+       oldfolder = camel_object_bag_get (camel_store_get_folders_bag (store), old);
        if (oldfolder == NULL) {
                g_set_error (
                        error, CAMEL_STORE_ERROR,
@@ -490,11 +490,11 @@ vee_store_rename_folder_sync (CamelStore *store,
        while ( (p = strchr (p, '/'))) {
                *p = 0;
 
-               folder = camel_object_bag_reserve (store->folders, name);
+               folder = camel_object_bag_reserve (camel_store_get_folders_bag (store), name);
                if (folder == NULL) {
                        /* create a dummy vFolder for this, makes get_folder_info simpler */
-                       folder = camel_vee_folder_new (store, name, ((CamelVeeFolder *) oldfolder)->flags);
-                       camel_object_bag_add (store->folders, name, folder);
+                       folder = camel_vee_folder_new (store, name, camel_vee_folder_get_flags 
(CAMEL_VEE_FOLDER (oldfolder)));
+                       camel_object_bag_add (camel_store_get_folders_bag (store), name, folder);
                        change_folder (store, name, CHANGE_ADD | CHANGE_NOSELECT, 0);
                        /* FIXME: this sort of leaks folder, nobody owns a ref to it but us */
                } else {
@@ -556,7 +556,7 @@ camel_vee_store_init (CamelVeeStore *vee_store)
        vee_store->priv->unmatched_enabled = TRUE;
 
        /* we dont want a vtrash/vjunk on this one */
-       store->flags &= ~(CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK);
+       camel_store_set_flags (store, camel_store_get_flags (store) & ~(CAMEL_STORE_VTRASH | 
CAMEL_STORE_VJUNK));
 }
 
 /**
@@ -577,7 +577,7 @@ camel_vee_store_new (void)
  *
  * FIXME Document me!
  *
- * Returns: (transfer none):
+ * Returns: (type CamelVeeFolder) (transfer none):
  *
  * Since: 3.6
  **/
@@ -686,6 +686,9 @@ add_to_unmatched_folder_cb (CamelVeeMessageInfoData *mi_data,
 
 /**
  * camel_vee_store_note_subfolder_used:
+ * @vstore:
+ * @subfolder:
+ * @used_by: (type CamelVeeFolder):
  *
  * FIXME Document me!
  *
@@ -765,6 +768,9 @@ remove_vuid_count_record_cb (CamelVeeMessageInfoData *mi_data,
 
 /**
  * camel_vee_store_note_subfolder_unused:
+ * @vstore:
+ * @subfolder:
+ * @unused_by: (type CamelVeeFolder):
  *
  * FIXME Document me!
  *
@@ -814,6 +820,9 @@ camel_vee_store_note_subfolder_unused (CamelVeeStore *vstore,
 
 /**
  * camel_vee_store_note_vuid_used:
+ * @vstore:
+ * @mi_data:
+ * @used_by: (type CamelVeeFolder):
  *
  * FIXME Document me!
  *
@@ -871,6 +880,9 @@ camel_vee_store_note_vuid_used (CamelVeeStore *vstore,
 
 /**
  * camel_vee_store_note_vuid_unused:
+ * @vstore:
+ * @mi_data:
+ * @unused_by: (type CamelVeeFolder):
  *
  * FIXME Document me!
  *
diff --git a/src/camel/camel-vee-store.h b/src/camel/camel-vee-store.h
index d0fde35..3857323 100644
--- a/src/camel/camel-vee-store.h
+++ b/src/camel/camel-vee-store.h
@@ -60,6 +60,9 @@ struct _CamelVeeStore {
 
 struct _CamelVeeStoreClass {
        CamelStoreClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType                  camel_vee_store_get_type                        (void);
diff --git a/src/camel/camel-vee-summary.c b/src/camel/camel-vee-summary.c
index ddd527d..11e6a4e 100644
--- a/src/camel/camel-vee-summary.c
+++ b/src/camel/camel-vee-summary.c
@@ -29,12 +29,14 @@
 #include "camel-debug.h"
 #include "camel-folder.h"
 #include "camel-store.h"
-#include "camel-vee-summary.h"
 #include "camel-vee-folder.h"
+#include "camel-vee-message-info.h"
 #include "camel-vee-store.h"
 #include "camel-vtrash-folder.h"
 #include "camel-string-utils.h"
 
+#include "camel-vee-summary.h"
+
 #define d(x)
 
 #define CAMEL_VEE_SUMMARY_GET_PRIVATE(obj) \
@@ -48,240 +50,6 @@ struct _CamelVeeSummaryPrivate {
 
 G_DEFINE_TYPE (CamelVeeSummary, camel_vee_summary, CAMEL_TYPE_FOLDER_SUMMARY)
 
-static void
-vee_message_info_free (CamelFolderSummary *s,
-                       CamelMessageInfo *info)
-{
-       CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *) info;
-
-       g_object_unref (mi->orig_summary);
-
-       CAMEL_FOLDER_SUMMARY_CLASS (camel_vee_summary_parent_class)->message_info_free (s, info);
-}
-
-static CamelMessageInfo *
-vee_message_info_clone (CamelFolderSummary *s,
-                        const CamelMessageInfo *mi)
-{
-       CamelVeeMessageInfo *to;
-       const CamelVeeMessageInfo *from = (const CamelVeeMessageInfo *) mi;
-
-       to = (CamelVeeMessageInfo *) camel_message_info_new (s);
-
-       to->orig_summary = g_object_ref (from->orig_summary);
-       to->info.summary = s;
-       to->info.uid = camel_pstring_strdup (from->info.uid);
-
-       return (CamelMessageInfo *) to;
-}
-
-#define HANDLE_NULL_INFO(value) if (!rmi) { d(g_warning (G_STRLOC ": real info is NULL for %s, 
safeguarding\n", mi->uid)); return value; }
-
-static gconstpointer
-vee_info_ptr (const CamelMessageInfo *mi,
-              gint id)
-{
-       CamelVeeMessageInfo *vmi = (CamelVeeMessageInfo *) mi;
-       CamelMessageInfo *rmi;
-       gpointer p;
-
-       rmi = camel_folder_summary_get (vmi->orig_summary, mi->uid + 8);
-       HANDLE_NULL_INFO (NULL);
-       p = (gpointer) camel_message_info_get_ptr (rmi, id);
-       camel_message_info_unref (rmi);
-
-       return p;
-}
-
-static guint32
-vee_info_uint32 (const CamelMessageInfo *mi,
-                 gint id)
-{
-       CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid 
+ 8);
-       guint32 ret;
-
-       HANDLE_NULL_INFO (0);
-       ret = camel_message_info_get_uint32 (rmi, id);
-       camel_message_info_unref (rmi);
-
-       return ret;
-
-}
-
-static time_t
-vee_info_time (const CamelMessageInfo *mi,
-               gint id)
-{
-       CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid 
+ 8);
-       time_t ret;
-
-       HANDLE_NULL_INFO (0);
-       ret = camel_message_info_get_time (rmi, id);
-       camel_message_info_unref (rmi);
-
-       return ret;
-}
-
-static gboolean
-vee_info_user_flag (const CamelMessageInfo *mi,
-                    const gchar *id)
-{
-       CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid 
+ 8);
-       gboolean ret;
-
-       HANDLE_NULL_INFO (FALSE);
-       ret = camel_message_info_get_user_flag (rmi, id);
-       camel_message_info_unref (rmi);
-
-       return ret;
-}
-
-static const gchar *
-vee_info_user_tag (const CamelMessageInfo *mi,
-                   const gchar *id)
-{
-       CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid 
+ 8);
-       const gchar *ret;
-
-       HANDLE_NULL_INFO ("");
-       ret = camel_message_info_get_user_tag (rmi, id);
-       camel_message_info_unref (rmi);
-
-       return ret;
-}
-
-static void
-vee_summary_notify_mi_changed (CamelVeeFolder *vfolder,
-                               CamelMessageInfo *mi)
-{
-       CamelFolderChangeInfo *changes;
-
-       g_return_if_fail (vfolder != NULL);
-       g_return_if_fail (mi != NULL);
-
-       changes = camel_folder_change_info_new ();
-
-       camel_folder_change_info_change_uid (changes, camel_message_info_get_uid (mi));
-       camel_folder_changed (CAMEL_FOLDER (vfolder), changes);
-       camel_folder_change_info_free (changes);
-}
-
-static gboolean
-vee_info_set_user_flag (CamelMessageInfo *mi,
-                        const gchar *name,
-                        gboolean value)
-{
-       gint res = FALSE;
-       CamelVeeFolder *vf = (CamelVeeFolder *) camel_folder_summary_get_folder (mi->summary);
-
-       if (mi->uid) {
-               CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, 
mi->uid + 8);
-               gboolean ignore_changes = !CAMEL_IS_VTRASH_FOLDER (vf);
-
-               HANDLE_NULL_INFO (FALSE);
-
-               /* ignore changes done in the folder itself,
-                * unless it's a vTrash or vJunk folder */
-               if (ignore_changes)
-                       camel_vee_folder_ignore_next_changed_event (vf, camel_folder_summary_get_folder 
(rmi->summary));
-
-               res = camel_message_info_set_user_flag (rmi, name, value);
-
-               if (ignore_changes) {
-                       if (res)
-                               vee_summary_notify_mi_changed (vf, mi);
-                       else
-                               camel_vee_folder_remove_from_ignore_changed_event (vf, 
camel_folder_summary_get_folder (rmi->summary));
-               }
-
-               camel_message_info_unref (rmi);
-       }
-
-       return res;
-}
-
-static gboolean
-vee_info_set_user_tag (CamelMessageInfo *mi,
-                       const gchar *name,
-                       const gchar *value)
-{
-       gint res = FALSE;
-
-       if (mi->uid) {
-               CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, 
mi->uid + 8);
-               CamelVeeFolder *vf = (CamelVeeFolder *) camel_folder_summary_get_folder (mi->summary);
-               gboolean ignore_changes = !CAMEL_IS_VTRASH_FOLDER (vf);
-
-               HANDLE_NULL_INFO (FALSE);
-
-               /* ignore changes done in the folder itself,
-                * unless it's a vTrash or vJunk folder */
-               if (ignore_changes)
-                       camel_vee_folder_ignore_next_changed_event (vf, camel_folder_summary_get_folder 
(rmi->summary));
-
-               res = camel_message_info_set_user_tag (rmi, name, value);
-
-               if (ignore_changes) {
-                       if (res)
-                               vee_summary_notify_mi_changed (vf, mi);
-                       else
-                               camel_vee_folder_remove_from_ignore_changed_event (vf, 
camel_folder_summary_get_folder (rmi->summary));
-               }
-
-               camel_message_info_unref (rmi);
-       }
-
-       return res;
-}
-
-static gboolean
-vee_info_set_flags (CamelMessageInfo *mi,
-                    guint32 flags,
-                    guint32 set)
-{
-       gint res = FALSE;
-       CamelVeeFolder *vf = CAMEL_VEE_FOLDER (camel_folder_summary_get_folder (mi->summary));
-
-       /* first update original message info... */
-       if (mi->uid) {
-               CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, 
mi->uid + 8);
-               gboolean ignore_changes = !CAMEL_IS_VTRASH_FOLDER (vf);
-
-               HANDLE_NULL_INFO (FALSE);
-
-               /* ignore changes done in the folder itself,
-                * unless it's a vTrash or vJunk folder */
-               if (ignore_changes)
-                       camel_vee_folder_ignore_next_changed_event (vf, camel_folder_summary_get_folder 
(rmi->summary));
-
-               res = camel_message_info_set_flags (rmi, flags, set);
-
-               if (res) {
-                       /* update flags on itself too */
-                       camel_folder_summary_replace_flags (mi->summary, mi);
-               }
-
-               if (ignore_changes) {
-                       if (res)
-                               vee_summary_notify_mi_changed (vf, mi);
-                       else
-                               camel_vee_folder_remove_from_ignore_changed_event (vf, 
camel_folder_summary_get_folder (rmi->summary));
-               }
-
-               camel_message_info_unref (rmi);
-       }
-
-       /* Do not call parent class' info_set_flags, to not do flood
-        * of change notifications, rather wait for a notification
-        * from original folder, and propagate the change in counts
-        * through camel_vee_summary_replace_flags().
-       */
-       /*if (res)
-               CAMEL_FOLDER_SUMMARY_CLASS (camel_vee_summary_parent_class)->info_set_flags (mi, flags, 
set);*/
-
-       return res;
-}
-
 static CamelMessageInfo *
 message_info_from_uid (CamelFolderSummary *s,
                        const gchar *uid)
@@ -290,7 +58,6 @@ message_info_from_uid (CamelFolderSummary *s,
 
        info = camel_folder_summary_peek_loaded (s, uid);
        if (!info) {
-               CamelVeeMessageInfo *vinfo;
                CamelFolder *orig_folder;
 
                /* This function isn't really nice. But no great way
@@ -305,22 +72,16 @@ message_info_from_uid (CamelFolderSummary *s,
                        return NULL;
                }
 
-               /* Create the info and load it, its so easy. */
-               info = camel_message_info_new (s);
-               info->dirty = FALSE;
-               info->uid = camel_pstring_strdup (uid);
-
                orig_folder = camel_vee_folder_get_vee_uid_folder (
                        (CamelVeeFolder *) camel_folder_summary_get_folder (s), uid);
                g_return_val_if_fail (orig_folder != NULL, NULL);
 
-               vinfo = (CamelVeeMessageInfo *) info;
-               vinfo->orig_summary = orig_folder->summary;
+               /* Create the info and load it, its so easy. */
+               info = camel_vee_message_info_new (s, camel_folder_get_folder_summary (orig_folder), uid);
 
-               g_object_ref (vinfo->orig_summary);
-               camel_message_info_ref (info);
+               camel_message_info_set_dirty (info, FALSE);
 
-               camel_folder_summary_insert (s, info, FALSE);
+               camel_folder_summary_add (s, info, TRUE);
        }
 
        return info;
@@ -351,18 +112,7 @@ camel_vee_summary_class_init (CamelVeeSummaryClass *class)
        object_class->finalize = vee_summary_finalize;
 
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
-       folder_summary_class->message_info_size = sizeof (CamelVeeMessageInfo);
-       folder_summary_class->content_info_size = 0;
-       folder_summary_class->message_info_clone = vee_message_info_clone;
-       folder_summary_class->message_info_free = vee_message_info_free;
-       folder_summary_class->info_ptr = vee_info_ptr;
-       folder_summary_class->info_uint32 = vee_info_uint32;
-       folder_summary_class->info_time = vee_info_time;
-       folder_summary_class->info_user_flag = vee_info_user_flag;
-       folder_summary_class->info_user_tag = vee_info_user_tag;
-       folder_summary_class->info_set_user_flag = vee_info_set_user_flag;
-       folder_summary_class->info_set_user_tag = vee_info_set_user_tag;
-       folder_summary_class->info_set_flags = vee_info_set_flags;
+       folder_summary_class->message_info_type = CAMEL_TYPE_VEE_MESSAGE_INFO;
        folder_summary_class->message_info_from_uid = message_info_from_uid;
 }
 
@@ -395,12 +145,12 @@ camel_vee_summary_new (CamelFolder *parent)
        const gchar *full_name;
 
        summary = g_object_new (CAMEL_TYPE_VEE_SUMMARY, "folder", parent, NULL);
-       summary->flags |= CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY;
+       camel_folder_summary_set_flags (summary, camel_folder_summary_get_flags (summary) | 
CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY);
 
        /* not using DB for vee folder summaries, drop the table */
        full_name = camel_folder_get_full_name (parent);
        parent_store = camel_folder_get_parent_store (parent);
-       camel_db_delete_folder (parent_store->cdb_w, full_name, NULL);
+       camel_db_delete_folder (camel_store_get_db (parent_store), full_name, NULL);
 
        return summary;
 }
@@ -431,7 +181,7 @@ camel_vee_summary_get_uids_for_subfolder (CamelVeeSummary *summary,
        g_return_val_if_fail (CAMEL_IS_VEE_SUMMARY (summary), NULL);
        g_return_val_if_fail (CAMEL_IS_FOLDER (subfolder), NULL);
 
-       camel_folder_summary_lock (&summary->summary);
+       camel_folder_summary_lock (CAMEL_FOLDER_SUMMARY (summary));
 
        /* uses direct hash, because strings are supposed to be from the string pool */
        known_uids = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) 
camel_pstring_free, NULL);
@@ -441,14 +191,22 @@ camel_vee_summary_get_uids_for_subfolder (CamelVeeSummary *summary,
                g_hash_table_foreach (vuids, get_uids_for_subfolder, known_uids);
        }
 
-       camel_folder_summary_unlock (&summary->summary);
+       camel_folder_summary_unlock (CAMEL_FOLDER_SUMMARY (summary));
 
        return known_uids;
 }
 
-/* unref returned pointer with camel_message_info_unref() */
+/**
+ * camel_vee_summary_add:
+ * @summary: the CamelVeeSummary
+ * @mi_data: (type CamelVeeMessageInfoData): the #CamelVeeMessageInfoData to add
+ *
+ * Unref returned pointer with g_object_unref()
+ *
+ * Returns: (transfer full): A new #CamelVeeMessageInfo object.
+ **/
 CamelVeeMessageInfo *
-camel_vee_summary_add (CamelVeeSummary *s,
+camel_vee_summary_add (CamelVeeSummary *summary,
                        CamelVeeMessageInfoData *mi_data)
 {
        CamelVeeMessageInfo *vmi;
@@ -457,44 +215,39 @@ camel_vee_summary_add (CamelVeeSummary *s,
        CamelFolder *orig_folder;
        GHashTable *vuids;
 
-       g_return_val_if_fail (CAMEL_IS_VEE_SUMMARY (s), NULL);
+       g_return_val_if_fail (CAMEL_IS_VEE_SUMMARY (summary), NULL);
        g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (mi_data), NULL);
 
-       camel_folder_summary_lock (&s->summary);
+       camel_folder_summary_lock (CAMEL_FOLDER_SUMMARY (summary));
 
        sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
        vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
        orig_folder = camel_vee_subfolder_data_get_folder (sf_data);
 
-       vmi = (CamelVeeMessageInfo *) camel_folder_summary_peek_loaded (&s->summary, vuid);
+       vmi = (CamelVeeMessageInfo *) camel_folder_summary_peek_loaded (CAMEL_FOLDER_SUMMARY (summary), vuid);
        if (vmi) {
                /* Possible that the entry is loaded, see if it has the summary */
                d (g_message ("%s - already there\n", vuid));
-               if (!vmi->orig_summary)
-                       vmi->orig_summary = g_object_ref (orig_folder->summary);
+               g_warn_if_fail (camel_vee_message_info_get_original_summary (vmi) != NULL);
 
-               camel_folder_summary_unlock (&s->summary);
+               camel_folder_summary_unlock (CAMEL_FOLDER_SUMMARY (summary));
 
                return vmi;
        }
 
-       vmi = (CamelVeeMessageInfo *) camel_message_info_new (&s->summary);
-       vmi->orig_summary = g_object_ref (orig_folder->summary);
-       vmi->info.uid = (gchar *) camel_pstring_strdup (vuid);
-
-       camel_message_info_ref (vmi);
+       vmi = (CamelVeeMessageInfo *) camel_vee_message_info_new (CAMEL_FOLDER_SUMMARY (summary), 
camel_folder_get_folder_summary (orig_folder), vuid);
 
-       vuids = g_hash_table_lookup (s->priv->vuids_by_subfolder, orig_folder);
+       vuids = g_hash_table_lookup (summary->priv->vuids_by_subfolder, orig_folder);
        if (vuids) {
                g_hash_table_insert (vuids, (gpointer) camel_pstring_strdup (vuid), GINT_TO_POINTER (1));
        } else {
                vuids = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) 
camel_pstring_free, NULL);
                g_hash_table_insert (vuids, (gpointer) camel_pstring_strdup (vuid), GINT_TO_POINTER (1));
-               g_hash_table_insert (s->priv->vuids_by_subfolder, orig_folder, vuids);
+               g_hash_table_insert (summary->priv->vuids_by_subfolder, orig_folder, vuids);
        }
 
-       camel_folder_summary_insert (&s->summary, (CamelMessageInfo *) vmi, FALSE);
-       camel_folder_summary_unlock (&s->summary);
+       camel_folder_summary_add (CAMEL_FOLDER_SUMMARY (summary), (CamelMessageInfo *) vmi, TRUE);
+       camel_folder_summary_unlock (CAMEL_FOLDER_SUMMARY (summary));
 
        return vmi;
 }
@@ -518,7 +271,7 @@ camel_vee_summary_remove (CamelVeeSummary *summary,
        g_return_if_fail (vuid != NULL);
        g_return_if_fail (subfolder != NULL);
 
-       camel_folder_summary_lock (&summary->summary);
+       camel_folder_summary_lock (CAMEL_FOLDER_SUMMARY (summary));
 
        vuids = g_hash_table_lookup (summary->priv->vuids_by_subfolder, subfolder);
        if (vuids) {
@@ -527,18 +280,18 @@ camel_vee_summary_remove (CamelVeeSummary *summary,
                        g_hash_table_remove (summary->priv->vuids_by_subfolder, subfolder);
        }
 
-       mi = camel_folder_summary_peek_loaded (&summary->summary, vuid);
+       mi = camel_folder_summary_peek_loaded (CAMEL_FOLDER_SUMMARY (summary), vuid);
 
-       camel_folder_summary_remove_uid (&summary->summary, vuid);
+       camel_folder_summary_remove_uid (CAMEL_FOLDER_SUMMARY (summary), vuid);
 
        if (mi) {
                /* under twice, the first for camel_folder_summary_peek_loaded(),
                 * the second to actually free the mi */
-               camel_message_info_unref (mi);
-               camel_message_info_unref (mi);
+               g_clear_object (&mi);
+               g_clear_object (&mi);
        }
 
-       camel_folder_summary_unlock (&summary->summary);
+       camel_folder_summary_unlock (CAMEL_FOLDER_SUMMARY (summary));
 }
 
 /**
@@ -561,16 +314,16 @@ camel_vee_summary_replace_flags (CamelVeeSummary *summary,
        g_return_if_fail (CAMEL_IS_VEE_SUMMARY (summary));
        g_return_if_fail (uid != NULL);
 
-       camel_folder_summary_lock (&summary->summary);
+       camel_folder_summary_lock (CAMEL_FOLDER_SUMMARY (summary));
 
-       mi = camel_folder_summary_get (&summary->summary, uid);
+       mi = camel_folder_summary_get (CAMEL_FOLDER_SUMMARY (summary), uid);
        if (!mi) {
-               camel_folder_summary_unlock (&summary->summary);
+               camel_folder_summary_unlock (CAMEL_FOLDER_SUMMARY (summary));
                return;
        }
 
-       camel_folder_summary_replace_flags (&summary->summary, mi);
-       camel_message_info_unref (mi);
+       camel_folder_summary_replace_flags (CAMEL_FOLDER_SUMMARY (summary), mi);
+       g_clear_object (&mi);
 
-       camel_folder_summary_unlock (&summary->summary);
+       camel_folder_summary_unlock (CAMEL_FOLDER_SUMMARY (summary));
 }
diff --git a/src/camel/camel-vee-summary.h b/src/camel/camel-vee-summary.h
index 94a95dc..5bdfdac 100644
--- a/src/camel/camel-vee-summary.h
+++ b/src/camel/camel-vee-summary.h
@@ -25,6 +25,7 @@
 #define CAMEL_VEE_SUMMARY_H
 
 #include <camel/camel-folder-summary.h>
+#include <camel/camel-vee-message-info.h>
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_VEE_SUMMARY \
@@ -55,28 +56,24 @@ typedef struct _CamelVeeSummary CamelVeeSummary;
 typedef struct _CamelVeeSummaryClass CamelVeeSummaryClass;
 typedef struct _CamelVeeSummaryPrivate CamelVeeSummaryPrivate;
 
-typedef struct _CamelVeeMessageInfo CamelVeeMessageInfo;
-
-struct _CamelVeeMessageInfo {
-       CamelMessageInfoBase info;
-       CamelFolderSummary *orig_summary;
-};
-
 struct _CamelVeeSummary {
-       CamelFolderSummary summary;
+       CamelFolderSummary parent;
 
        CamelVeeSummaryPrivate *priv;
 };
 
 struct _CamelVeeSummaryClass {
        CamelFolderSummaryClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_vee_summary_get_type      (void);
 CamelFolderSummary *
-               camel_vee_summary_new           (struct _CamelFolder *parent);
+               camel_vee_summary_new           (CamelFolder *parent);
 CamelVeeMessageInfo *
-               camel_vee_summary_add           (CamelVeeSummary *s,
+               camel_vee_summary_add           (CamelVeeSummary *summary,
                                                 struct _CamelVeeMessageInfoData *mi_data);
 void           camel_vee_summary_remove        (CamelVeeSummary *summary,
                                                 const gchar *vuid,
diff --git a/src/camel/camel-vtrash-folder.c b/src/camel/camel-vtrash-folder.c
index b8eef41..79198e8 100644
--- a/src/camel/camel-vtrash-folder.c
+++ b/src/camel/camel-vtrash-folder.c
@@ -31,6 +31,11 @@
 #include "camel-vtrash-folder.h"
 #include "camel-string-utils.h"
 
+struct _CamelVTrashFolderPrivate {
+       CamelVTrashFolderType type;
+       guint32 bit;
+};
+
 static struct {
        const gchar *full_name;
        const gchar *name;
@@ -79,7 +84,7 @@ transfer_messages (CamelFolder *folder,
                CamelMessageInfo *mi = camel_folder_get_message_info (md->source_folder, 
md->source_uids->pdata[i]);
                if (mi) {
                        camel_message_info_set_flags (mi, md->sbit, md->sbit);
-                       camel_message_info_unref (mi);
+                       g_clear_object (&mi);
                }
        }
 
@@ -104,7 +109,7 @@ vtrash_folder_append_message_sync (CamelFolder *folder,
 {
        g_set_error (
                error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, "%s",
-               _(vdata[((CamelVTrashFolder *) folder)->type].error_copy));
+               _(vdata[((CamelVTrashFolder *) folder)->priv->type].error_copy));
 
        return FALSE;
 }
@@ -123,7 +128,7 @@ vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
        GHashTable *batch = NULL;
        const gchar *tuid;
        struct _transfer_data *md;
-       guint32 sbit = ((CamelVTrashFolder *) source)->bit;
+       guint32 sbit = ((CamelVTrashFolder *) source)->priv->bit;
 
        /* This is a special case of transfer_messages_to: Either the
         * source or the destination is a vtrash folder (but not both
@@ -138,7 +143,7 @@ vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
                if (!delete_originals) {
                        g_set_error (
                                error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, "%s",
-                               _(vdata[((CamelVTrashFolder *) dest)->type].error_copy));
+                               _(vdata[((CamelVTrashFolder *) dest)->priv->type].error_copy));
                        return FALSE;
                }
 
@@ -146,7 +151,7 @@ vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
                for (i = 0; i < uids->len; i++)
                        camel_folder_set_message_flags (
                                source, uids->pdata[i],
-                               ((CamelVTrashFolder *) dest)->bit, ~0);
+                               ((CamelVTrashFolder *) dest)->priv->bit, ~0);
                return TRUE;
        }
 
@@ -166,18 +171,18 @@ vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
                        continue;
                }
 
-               if (dest == camel_folder_summary_get_folder (mi->orig_summary)) {
+               if (dest == camel_vee_message_info_get_original_folder (mi)) {
                        /* Just unset the flag on the original message */
                        camel_folder_set_message_flags (
                                source, uids->pdata[i], sbit, 0);
                } else {
                        if (batch == NULL)
                                batch = g_hash_table_new (NULL, NULL);
-                       md = g_hash_table_lookup (batch, camel_folder_summary_get_folder (mi->orig_summary));
+                       md = g_hash_table_lookup (batch, camel_vee_message_info_get_original_folder (mi));
                        if (md == NULL) {
                                md = g_malloc0 (sizeof (*md));
                                md->cancellable = cancellable;
-                               md->folder = g_object_ref (camel_folder_summary_get_folder 
(mi->orig_summary));
+                               md->folder = g_object_ref (camel_vee_message_info_get_original_folder (mi));
                                md->uids = g_ptr_array_new ();
                                md->dest = dest;
                                md->delete = delete_originals;
@@ -187,7 +192,7 @@ vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
                                if (cancellable != NULL)
                                        g_object_ref (cancellable);
                                camel_folder_freeze (md->folder);
-                               g_hash_table_insert (batch, camel_folder_summary_get_folder 
(mi->orig_summary), md);
+                               g_hash_table_insert (batch, camel_vee_message_info_get_original_folder (mi), 
md);
                        }
 
                        /* unset the bit temporarily */
@@ -199,7 +204,7 @@ vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
                        g_ptr_array_add (md->uids, g_strdup (tuid));
                        g_ptr_array_add (md->source_uids, uids->pdata[i]);
                }
-               camel_message_info_unref (mi);
+               g_clear_object (&mi);
        }
 
        if (batch) {
@@ -218,6 +223,8 @@ camel_vtrash_folder_class_init (CamelVTrashFolderClass *class)
 {
        CamelFolderClass *folder_class;
 
+       g_type_class_add_private (class, sizeof (CamelVTrashFolderPrivate));
+
        folder_class = CAMEL_FOLDER_CLASS (class);
        folder_class->append_message_sync = vtrash_folder_append_message_sync;
        folder_class->transfer_messages_to_sync = vtrash_folder_transfer_messages_to_sync;
@@ -226,6 +233,7 @@ camel_vtrash_folder_class_init (CamelVTrashFolderClass *class)
 static void
 camel_vtrash_folder_init (CamelVTrashFolder *vtrash_folder)
 {
+       vtrash_folder->priv = G_TYPE_INSTANCE_GET_PRIVATE (vtrash_folder, CAMEL_TYPE_VTRASH_FOLDER, 
CamelVTrashFolderPrivate);
 }
 
 /**
@@ -257,10 +265,26 @@ camel_vtrash_folder_new (CamelStore *parent_store,
                CAMEL_STORE_FOLDER_PRIVATE |
                CAMEL_STORE_FOLDER_CREATE);
 
-       ((CamelFolder *) vtrash)->folder_flags |= vdata[type].flags;
+       camel_folder_set_flags (CAMEL_FOLDER (vtrash), camel_folder_get_flags (CAMEL_FOLDER (vtrash)) | 
vdata[type].flags);
        camel_vee_folder_set_expression ((CamelVeeFolder *) vtrash, vdata[type].expr);
-       vtrash->bit = vdata[type].bit;
-       vtrash->type = type;
+       vtrash->priv->bit = vdata[type].bit;
+       vtrash->priv->type = type;
 
        return (CamelFolder *) vtrash;
 }
+
+/**
+ * camel_vtrash_folder_get_folder_type:
+ * @vtrash_folder: a #CamelVTrashFolder
+ *
+ * Returns: a @vtrash_folder folder type (#CamelVTrashFolderType)
+ *
+ * Since: 3.24
+ **/
+CamelVTrashFolderType
+camel_vtrash_folder_get_folder_type (CamelVTrashFolder *vtrash_folder)
+{
+       g_return_val_if_fail (CAMEL_IS_VTRASH_FOLDER (vtrash_folder), CAMEL_VTRASH_FOLDER_LAST);
+
+       return vtrash_folder->priv->type;
+}
diff --git a/src/camel/camel-vtrash-folder.h b/src/camel/camel-vtrash-folder.h
index bf0c6d4..94bd73b 100644
--- a/src/camel/camel-vtrash-folder.h
+++ b/src/camel/camel-vtrash-folder.h
@@ -53,6 +53,7 @@ G_BEGIN_DECLS
 
 typedef struct _CamelVTrashFolder CamelVTrashFolder;
 typedef struct _CamelVTrashFolderClass CamelVTrashFolderClass;
+typedef struct _CamelVTrashFolderPrivate CamelVTrashFolderPrivate;
 
 typedef enum {
        CAMEL_VTRASH_FOLDER_TRASH,
@@ -62,18 +63,22 @@ typedef enum {
 
 struct _CamelVTrashFolder {
        CamelVeeFolder parent;
-
-       CamelVTrashFolderType type;
-       guint32 bit;
+       CamelVTrashFolderPrivate *priv;
 };
 
 struct _CamelVTrashFolderClass {
        CamelVeeFolderClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_vtrash_folder_get_type    (void);
 CamelFolder *  camel_vtrash_folder_new         (CamelStore *parent_store,
                                                 CamelVTrashFolderType type);
+CamelVTrashFolderType
+               camel_vtrash_folder_get_folder_type
+                                               (CamelVTrashFolder *vtrash_folder);
 
 G_END_DECLS
 
diff --git a/src/camel/camel.h b/src/camel/camel.h
index 5710717..b405baf 100644
--- a/src/camel/camel.h
+++ b/src/camel/camel.h
@@ -56,6 +56,8 @@
 #include <camel/camel-medium.h>
 #include <camel/camel-memchunk.h>
 #include <camel/camel-mempool.h>
+#include <camel/camel-message-info.h>
+#include <camel/camel-message-info-base.h>
 #include <camel/camel-mime-filter.h>
 #include <camel/camel-mime-filter-basic.h>
 #include <camel/camel-mime-filter-bestenc.h>
@@ -83,6 +85,8 @@
 #include <camel/camel-multipart.h>
 #include <camel/camel-multipart-encrypted.h>
 #include <camel/camel-multipart-signed.h>
+#include <camel/camel-named-flags.h>
+#include <camel/camel-name-value-array.h>
 #include <camel/camel-net-utils.h>
 #include <camel/camel-network-service.h>
 #include <camel/camel-nntp-address.h>
@@ -128,8 +132,10 @@
 #include <camel/camel-url.h>
 #include <camel/camel-url-scanner.h>
 #include <camel/camel-utf8.h>
+#include <camel/camel-utils.h>
 #include <camel/camel-vee-data-cache.h>
 #include <camel/camel-vee-folder.h>
+#include <camel/camel-vee-message-info.h>
 #include <camel/camel-vee-store.h>
 #include <camel/camel-vee-summary.h>
 #include <camel/camel-vtrash-folder.h>
diff --git a/src/camel/providers/imapx/CMakeLists.txt b/src/camel/providers/imapx/CMakeLists.txt
index 5395f24..dcdf24b 100644
--- a/src/camel/providers/imapx/CMakeLists.txt
+++ b/src/camel/providers/imapx/CMakeLists.txt
@@ -16,6 +16,8 @@ set(SOURCES
        camel-imapx-logger.h
        camel-imapx-mailbox.c
        camel-imapx-mailbox.h
+       camel-imapx-message-info.c
+       camel-imapx-message-info.h
        camel-imapx-namespace.c
        camel-imapx-namespace.h
        camel-imapx-namespace-response.c
diff --git a/src/camel/providers/imapx/camel-imapx-command.c b/src/camel/providers/imapx/camel-imapx-command.c
index cf54416..7e9ec7f 100644
--- a/src/camel/providers/imapx/camel-imapx-command.c
+++ b/src/camel/providers/imapx/camel-imapx-command.c
@@ -188,7 +188,7 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
        gint d;
        glong l;
        guint32 f;
-       CamelFlag *F;
+       const CamelNamedFlags *F;
        CamelDataWrapper *D;
        CamelSasl *A;
        gchar literal_format[16];
@@ -307,7 +307,7 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
                                goto output_string;
                        case 'F': /* IMAP flags set */
                                f = va_arg (ap, guint32);
-                               F = va_arg (ap, CamelFlag *);
+                               F = va_arg (ap, const CamelNamedFlags *);
                                imapx_write_flags (buffer, f, F);
                                break;
                        case 'c':
diff --git a/src/camel/providers/imapx/camel-imapx-conn-manager.c 
b/src/camel/providers/imapx/camel-imapx-conn-manager.c
index 983c69b..e82de56 100644
--- a/src/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/src/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -1654,7 +1654,7 @@ imapx_conn_manager_move_to_real_trash_sync (CamelIMAPXConnManager *conn_man,
                destination = camel_imapx_folder_list_mailbox (
                        CAMEL_IMAPX_FOLDER (folder),
                        cancellable, error);
-               folder_deleted_count = camel_folder_summary_get_deleted_count (folder->summary);
+               folder_deleted_count = camel_folder_summary_get_deleted_count 
(camel_folder_get_folder_summary (folder));
                g_object_unref (folder);
        }
 
diff --git a/src/camel/providers/imapx/camel-imapx-conn-manager.h 
b/src/camel/providers/imapx/camel-imapx-conn-manager.h
index f0edd54..eac6db2 100644
--- a/src/camel/providers/imapx/camel-imapx-conn-manager.h
+++ b/src/camel/providers/imapx/camel-imapx-conn-manager.h
@@ -64,6 +64,9 @@ struct _CamelIMAPXConnManagerClass {
        /* Signals */
        void    (* connection_created) (CamelIMAPXConnManager *conn_man,
                                        CamelIMAPXServer *server);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_conn_manager_get_type (void);
diff --git a/src/camel/providers/imapx/camel-imapx-folder.c b/src/camel/providers/imapx/camel-imapx-folder.c
index 0d73287..2d1080e 100644
--- a/src/camel/providers/imapx/camel-imapx-folder.c
+++ b/src/camel/providers/imapx/camel-imapx-folder.c
@@ -207,7 +207,7 @@ imapx_folder_dispose (GObject *object)
        if (store != NULL) {
                camel_store_summary_disconnect_folder_summary (
                        CAMEL_IMAPX_STORE (store)->summary,
-                       CAMEL_FOLDER (folder)->summary);
+                       camel_folder_get_folder_summary (CAMEL_FOLDER (folder)));
        }
 
        g_weak_ref_set (&folder->priv->mailbox, NULL);
@@ -442,7 +442,7 @@ imapx_append_message_sync (CamelFolder *folder,
                goto exit;
 
        success = camel_imapx_conn_manager_append_message_sync (
-               conn_man, mailbox, folder->summary,
+               conn_man, mailbox, camel_folder_get_folder_summary (folder),
                CAMEL_IMAPX_FOLDER (folder)->cache, message,
                info, appended_uid, cancellable, error);
 
@@ -475,7 +475,7 @@ imapx_expunge_sync (CamelFolder *folder,
        if (mailbox == NULL)
                goto exit;
 
-       if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
+       if ((camel_store_get_flags (store) & CAMEL_STORE_VTRASH) == 0) {
                CamelFolder *trash;
                const gchar *full_name;
 
@@ -484,25 +484,27 @@ imapx_expunge_sync (CamelFolder *folder,
                trash = camel_store_get_trash_folder_sync (store, cancellable, &local_error);
 
                if (local_error == NULL && trash && (folder == trash || g_ascii_strcasecmp (full_name, 
camel_folder_get_full_name (trash)) == 0)) {
+                       CamelFolderSummary *folder_summary;
                        CamelMessageInfo *info;
                        GPtrArray *known_uids;
                        gint ii;
 
-                       camel_folder_summary_lock (folder->summary);
+                       folder_summary = camel_folder_get_folder_summary (folder);
+                       camel_folder_summary_lock (folder_summary);
 
-                       camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
-                       known_uids = camel_folder_summary_get_array (folder->summary);
+                       camel_folder_summary_prepare_fetch_all (folder_summary, NULL);
+                       known_uids = camel_folder_summary_get_array (folder_summary);
 
                        /* it's a real trash folder, thus delete all mails from there */
                        for (ii = 0; known_uids && ii < known_uids->len; ii++) {
-                               info = camel_folder_summary_get (folder->summary, g_ptr_array_index 
(known_uids, ii));
+                               info = camel_folder_summary_get (camel_folder_get_folder_summary (folder), 
g_ptr_array_index (known_uids, ii));
                                if (info) {
                                        camel_message_info_set_flags (info, CAMEL_MESSAGE_DELETED, 
CAMEL_MESSAGE_DELETED);
-                                       camel_message_info_unref (info);
+                                       g_clear_object (&info);
                                }
                        }
 
-                       camel_folder_summary_unlock (folder->summary);
+                       camel_folder_summary_unlock (folder_summary);
 
                        camel_folder_summary_free_array (known_uids);
                }
@@ -609,7 +611,7 @@ imapx_get_message_sync (CamelFolder *folder,
                        return NULL;
 
                stream = camel_imapx_conn_manager_get_message_sync (
-                       conn_man, mailbox, folder->summary,
+                       conn_man, mailbox, camel_folder_get_folder_summary (folder),
                        CAMEL_IMAPX_FOLDER (folder)->cache, uid,
                        cancellable, error);
 
@@ -635,7 +637,7 @@ imapx_get_message_sync (CamelFolder *folder,
        if (msg != NULL) {
                CamelMessageInfo *mi;
 
-               mi = camel_folder_summary_get (folder->summary, uid);
+               mi = camel_folder_summary_get (camel_folder_get_folder_summary (folder), uid);
                if (mi != NULL) {
                        CamelMessageFlags flags;
                        gboolean has_attachment;
@@ -649,7 +651,7 @@ imapx_get_message_sync (CamelFolder *folder,
                                        has_attachment ? CAMEL_MESSAGE_ATTACHMENTS : 0);
                        }
 
-                       camel_message_info_unref (mi);
+                       g_clear_object (&mi);
                }
        }
 
@@ -781,7 +783,7 @@ imapx_synchronize_sync (CamelFolder *folder,
                success = mailbox != NULL;
        } else {
                success = camel_imapx_conn_manager_sync_changes_sync (conn_man, mailbox, cancellable, error);
-               if (success && expunge && camel_folder_summary_get_deleted_count (folder->summary) > 0) {
+               if (success && expunge && camel_folder_summary_get_deleted_count 
(camel_folder_get_folder_summary (folder)) > 0) {
                        success = camel_imapx_conn_manager_expunge_sync (conn_man, mailbox, cancellable, 
error);
                }
        }
@@ -815,7 +817,7 @@ imapx_synchronize_message_sync (CamelFolder *folder,
                goto exit;
 
        success = camel_imapx_conn_manager_sync_message_sync (
-               conn_man, mailbox, folder->summary,
+               conn_man, mailbox, camel_folder_get_folder_summary (folder),
                CAMEL_IMAPX_FOLDER (folder)->cache, uid,
                cancellable, error);
 
@@ -900,6 +902,17 @@ imapx_folder_changed (CamelFolder *folder,
        CAMEL_FOLDER_CLASS (camel_imapx_folder_parent_class)->changed (folder, info);
 }
 
+static guint32
+imapx_get_permanent_flags (CamelFolder *folder)
+{
+       return CAMEL_MESSAGE_ANSWERED |
+               CAMEL_MESSAGE_DELETED |
+               CAMEL_MESSAGE_DRAFT |
+               CAMEL_MESSAGE_FLAGGED |
+               CAMEL_MESSAGE_SEEN |
+               CAMEL_MESSAGE_USER;
+}
+
 static void
 imapx_rename (CamelFolder *folder,
               const gchar *new_name)
@@ -912,7 +925,7 @@ imapx_rename (CamelFolder *folder,
        imapx_store = CAMEL_IMAPX_STORE (store);
 
        camel_store_summary_disconnect_folder_summary (
-               imapx_store->summary, folder->summary);
+               imapx_store->summary, camel_folder_get_folder_summary (folder));
 
        /* Chain up to parent's rename() method. */
        CAMEL_FOLDER_CLASS (camel_imapx_folder_parent_class)->
@@ -921,7 +934,7 @@ imapx_rename (CamelFolder *folder,
        folder_name = camel_folder_get_full_name (folder);
 
        camel_store_summary_connect_folder_summary (
-               imapx_store->summary, folder_name, folder->summary);
+               imapx_store->summary, folder_name, camel_folder_get_folder_summary (folder));
 }
 
 static void
@@ -939,6 +952,7 @@ camel_imapx_folder_class_init (CamelIMAPXFolderClass *class)
        object_class->finalize = imapx_folder_finalize;
 
        folder_class = CAMEL_FOLDER_CLASS (class);
+       folder_class->get_permanent_flags = imapx_get_permanent_flags;
        folder_class->rename = imapx_rename;
        folder_class->search_by_expression = imapx_search_by_expression;
        folder_class->search_by_uids = imapx_search_by_uids;
@@ -1012,15 +1026,7 @@ camel_imapx_folder_init (CamelIMAPXFolder *imapx_folder)
 
        imapx_folder->priv = CAMEL_IMAPX_FOLDER_GET_PRIVATE (imapx_folder);
 
-       folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
-
-       folder->permanent_flags =
-               CAMEL_MESSAGE_ANSWERED |
-               CAMEL_MESSAGE_DELETED |
-               CAMEL_MESSAGE_DRAFT |
-               CAMEL_MESSAGE_FLAGGED |
-               CAMEL_MESSAGE_SEEN |
-               CAMEL_MESSAGE_USER;
+       camel_folder_set_flags (folder, camel_folder_get_flags (folder) | 
CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY);
 
        camel_folder_set_lock_async (folder, TRUE);
 
@@ -1043,6 +1049,7 @@ camel_imapx_folder_new (CamelStore *store,
                         GError **error)
 {
        CamelFolder *folder;
+       CamelFolderSummary *folder_summary;
        CamelService *service;
        CamelSettings *settings;
        CamelIMAPXFolder *imapx_folder;
@@ -1052,6 +1059,7 @@ camel_imapx_folder_new (CamelStore *store,
        gboolean filter_inbox;
        gboolean filter_junk;
        gboolean filter_junk_inbox;
+       guint32 add_folder_flags = 0;
 
        d ("opening imap folder '%s'\n", folder_dir);
 
@@ -1081,21 +1089,25 @@ camel_imapx_folder_new (CamelStore *store,
                "full_name", folder_name,
                "parent-store", store, NULL);
 
-       folder->summary = camel_imapx_summary_new (folder);
-       if (folder->summary == NULL) {
+       folder_summary = camel_imapx_summary_new (folder);
+       if (!folder_summary) {
                g_set_error (
                        error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                        _("Could not create folder summary for %s"),
                        short_name);
+               g_object_unref (folder);
                return NULL;
        }
 
+       camel_folder_take_folder_summary (folder, folder_summary);
+
        imapx_folder = CAMEL_IMAPX_FOLDER (folder);
        imapx_folder->cache = camel_data_cache_new (folder_dir, error);
        if (imapx_folder->cache == NULL) {
                g_prefix_error (
                        error, _("Could not create cache for %s: "),
                        short_name);
+               g_object_unref (folder);
                return NULL;
        }
 
@@ -1118,25 +1130,27 @@ camel_imapx_folder_new (CamelStore *store,
        imapx_folder->search = camel_imapx_search_new (CAMEL_IMAPX_STORE (store));
 
        if (filter_all)
-               folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+               add_folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
 
        if (camel_imapx_mailbox_is_inbox (folder_name)) {
                if (filter_inbox)
-                       folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+                       add_folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
 
                if (filter_junk)
-                       folder->folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
+                       add_folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
        } else {
                if (filter_junk && !filter_junk_inbox)
-                       folder->folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
+                       add_folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
 
                if (imapx_folder_get_apply_filters (imapx_folder))
-                       folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+                       add_folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
        }
 
+       camel_folder_set_flags (folder, camel_folder_get_flags (folder) | add_folder_flags);
+
        camel_store_summary_connect_folder_summary (
                CAMEL_IMAPX_STORE (store)->summary,
-               folder_name, folder->summary);
+               folder_name, camel_folder_get_folder_summary (folder));
 
        return folder;
 }
@@ -1188,7 +1202,7 @@ camel_imapx_folder_set_mailbox (CamelIMAPXFolder *folder,
 
        g_weak_ref_set (&folder->priv->mailbox, mailbox);
 
-       imapx_summary = CAMEL_IMAPX_SUMMARY (CAMEL_FOLDER (folder)->summary);
+       imapx_summary = CAMEL_IMAPX_SUMMARY (camel_folder_get_folder_summary (CAMEL_FOLDER (folder)));
        uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
 
        if (uidvalidity > 0 && uidvalidity != imapx_summary->validity)
@@ -1330,7 +1344,7 @@ camel_imapx_folder_copy_message_map (CamelIMAPXFolder *folder)
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), NULL);
 
-       summary = CAMEL_FOLDER (folder)->summary;
+       summary = camel_folder_get_folder_summary (CAMEL_FOLDER (folder));
        array = camel_folder_summary_get_array (summary);
        camel_folder_sort_uids (CAMEL_FOLDER (folder), array);
 
@@ -1366,7 +1380,7 @@ camel_imapx_folder_add_move_to_real_junk (CamelIMAPXFolder *folder,
 {
        g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
        g_return_if_fail (message_uid != NULL);
-       g_return_if_fail (camel_folder_summary_check_uid (CAMEL_FOLDER (folder)->summary, message_uid));
+       g_return_if_fail (camel_folder_summary_check_uid (camel_folder_get_folder_summary (CAMEL_FOLDER 
(folder)), message_uid));
 
        g_mutex_lock (&folder->priv->move_to_hash_table_lock);
 
@@ -1397,7 +1411,7 @@ camel_imapx_folder_add_move_to_real_trash (CamelIMAPXFolder *folder,
 {
        g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
        g_return_if_fail (message_uid != NULL);
-       g_return_if_fail (camel_folder_summary_check_uid (CAMEL_FOLDER (folder)->summary, message_uid));
+       g_return_if_fail (camel_folder_summary_check_uid (camel_folder_get_folder_summary (CAMEL_FOLDER 
(folder)), message_uid));
 
        g_mutex_lock (&folder->priv->move_to_hash_table_lock);
 
@@ -1434,7 +1448,7 @@ camel_imapx_folder_invalidate_local_cache (CamelIMAPXFolder *folder,
        g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
        g_return_if_fail (new_uidvalidity > 0);
 
-       summary = CAMEL_FOLDER (folder)->summary;
+       summary = camel_folder_get_folder_summary (CAMEL_FOLDER (folder));
 
        changes = camel_folder_change_info_new ();
        array = camel_folder_summary_get_array (summary);
@@ -1446,7 +1460,7 @@ camel_imapx_folder_invalidate_local_cache (CamelIMAPXFolder *folder,
 
        CAMEL_IMAPX_SUMMARY (summary)->validity = new_uidvalidity;
        camel_folder_summary_touch (summary);
-       camel_folder_summary_save_to_db (summary, NULL);
+       camel_folder_summary_save (summary, NULL);
 
        camel_data_cache_clear (folder->cache, "cache");
        camel_data_cache_clear (folder->cache, "cur");
diff --git a/src/camel/providers/imapx/camel-imapx-folder.h b/src/camel/providers/imapx/camel-imapx-folder.h
index 12c3d9b..98d4bc0 100644
--- a/src/camel/providers/imapx/camel-imapx-folder.h
+++ b/src/camel/providers/imapx/camel-imapx-folder.h
@@ -65,6 +65,9 @@ struct _CamelIMAPXFolder {
 
 struct _CamelIMAPXFolderClass {
        CamelOfflineFolderClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_folder_get_type     (void);
diff --git a/src/camel/providers/imapx/camel-imapx-input-stream.h 
b/src/camel/providers/imapx/camel-imapx-input-stream.h
index e379a3a..f2a7cc4 100644
--- a/src/camel/providers/imapx/camel-imapx-input-stream.h
+++ b/src/camel/providers/imapx/camel-imapx-input-stream.h
@@ -68,6 +68,9 @@ struct _CamelIMAPXInputStream {
 
 struct _CamelIMAPXInputStreamClass {
        GFilterInputStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GQuark         camel_imapx_error_quark         (void) G_GNUC_CONST;
diff --git a/src/camel/providers/imapx/camel-imapx-job.h b/src/camel/providers/imapx/camel-imapx-job.h
index de0c5d1..b27de5f 100644
--- a/src/camel/providers/imapx/camel-imapx-job.h
+++ b/src/camel/providers/imapx/camel-imapx-job.h
@@ -121,4 +121,3 @@ void                camel_imapx_job_wait_sync       (CamelIMAPXJob *job,
 G_END_DECLS
 
 #endif /* CAMEL_IMAPX_JOB_H */
-
diff --git a/src/camel/providers/imapx/camel-imapx-list-response.h 
b/src/camel/providers/imapx/camel-imapx-list-response.h
index b0419bf..3fdb38d 100644
--- a/src/camel/providers/imapx/camel-imapx-list-response.h
+++ b/src/camel/providers/imapx/camel-imapx-list-response.h
@@ -84,6 +84,9 @@ struct _CamelIMAPXListResponse {
 
 struct _CamelIMAPXListResponseClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_list_response_get_type
diff --git a/src/camel/providers/imapx/camel-imapx-logger.h b/src/camel/providers/imapx/camel-imapx-logger.h
index cdf9231..d697ad4 100644
--- a/src/camel/providers/imapx/camel-imapx-logger.h
+++ b/src/camel/providers/imapx/camel-imapx-logger.h
@@ -60,6 +60,9 @@ struct _CamelIMAPXLogger {
 
 struct _CamelIMAPXLoggerClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_logger_get_type     (void) G_GNUC_CONST;
diff --git a/src/camel/providers/imapx/camel-imapx-mailbox.h b/src/camel/providers/imapx/camel-imapx-mailbox.h
index 9ec86df..9421457 100644
--- a/src/camel/providers/imapx/camel-imapx-mailbox.h
+++ b/src/camel/providers/imapx/camel-imapx-mailbox.h
@@ -69,6 +69,9 @@ struct _CamelIMAPXMailbox {
 
 struct _CamelIMAPXMailboxClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_mailbox_get_type
diff --git a/src/camel/providers/imapx/camel-imapx-message-info.c 
b/src/camel/providers/imapx/camel-imapx-message-info.c
new file mode 100644
index 0000000..c7d7fe4
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-message-info.c
@@ -0,0 +1,435 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+
+#include "camel/camel.h"
+#include "camel-imapx-summary.h"
+
+#include "camel-imapx-message-info.h"
+
+struct _CamelIMAPXMessageInfoPrivate {
+       guint32 server_flags;
+       CamelNamedFlags *server_user_flags;
+       CamelNameValueArray *server_user_tags;
+};
+
+enum {
+       PROP_0,
+       PROP_SERVER_FLAGS,
+       PROP_SERVER_USER_FLAGS,
+       PROP_SERVER_USER_TAGS
+};
+
+G_DEFINE_TYPE (CamelIMAPXMessageInfo, camel_imapx_message_info, CAMEL_TYPE_MESSAGE_INFO_BASE)
+
+static CamelMessageInfo *
+imapx_message_info_clone (const CamelMessageInfo *mi,
+                         CamelFolderSummary *assign_summary)
+{
+       CamelMessageInfo *result;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (mi), NULL);
+
+       result = CAMEL_MESSAGE_INFO_CLASS (camel_imapx_message_info_parent_class)->clone (mi, assign_summary);
+       if (!result)
+               return NULL;
+
+       if (CAMEL_IS_IMAPX_MESSAGE_INFO (result)) {
+               CamelIMAPXMessageInfo *imi, *imi_result;
+
+               imi = CAMEL_IMAPX_MESSAGE_INFO (mi);
+               imi_result = CAMEL_IMAPX_MESSAGE_INFO (result);
+
+               camel_imapx_message_info_set_server_flags (imi_result, 
camel_imapx_message_info_get_server_flags (imi));
+               camel_imapx_message_info_take_server_user_flags (imi_result, 
camel_imapx_message_info_dup_server_user_flags (imi));
+               camel_imapx_message_info_take_server_user_tags (imi_result, 
camel_imapx_message_info_dup_server_user_tags (imi));
+       }
+
+       return result;
+}
+
+static gboolean
+imapx_message_info_load (CamelMessageInfo *mi,
+                        const CamelMIRecord *record,
+                        /* const */ gchar **bdata_ptr)
+{
+       CamelIMAPXMessageInfo *imi;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       if (!CAMEL_MESSAGE_INFO_CLASS (camel_imapx_message_info_parent_class)->load ||
+           !CAMEL_MESSAGE_INFO_CLASS (camel_imapx_message_info_parent_class)->load (mi, record, bdata_ptr))
+               return FALSE;
+
+       imi = CAMEL_IMAPX_MESSAGE_INFO (mi);
+
+       camel_imapx_message_info_set_server_flags (imi, camel_util_bdata_get_number (bdata_ptr, 0));
+
+       /* Reset server-side information, which is not saved into the summary. */
+       camel_imapx_message_info_take_server_user_flags (imi, NULL);
+       camel_imapx_message_info_take_server_user_tags (imi, NULL);
+
+       return TRUE;
+}
+
+static gboolean
+imapx_message_info_save (const CamelMessageInfo *mi,
+                        CamelMIRecord *record,
+                        GString *bdata_str)
+{
+       CamelIMAPXMessageInfo *imi;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_str != NULL, FALSE);
+
+       if (!CAMEL_MESSAGE_INFO_CLASS (camel_imapx_message_info_parent_class)->save ||
+           !CAMEL_MESSAGE_INFO_CLASS (camel_imapx_message_info_parent_class)->save (mi, record, bdata_str))
+               return FALSE;
+
+       imi = CAMEL_IMAPX_MESSAGE_INFO (mi);
+
+       camel_util_bdata_put_number (bdata_str, camel_imapx_message_info_get_server_flags (imi));
+
+       return TRUE;
+}
+
+static void
+imapx_message_info_set_property (GObject *object,
+                                guint property_id,
+                                const GValue *value,
+                                GParamSpec *pspec)
+{
+       CamelIMAPXMessageInfo *imi = CAMEL_IMAPX_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_SERVER_FLAGS:
+               camel_imapx_message_info_set_server_flags (imi, g_value_get_uint (value));
+               return;
+
+       case PROP_SERVER_USER_FLAGS:
+               camel_imapx_message_info_take_server_user_flags (imi, g_value_dup_boxed (value));
+               return;
+
+       case PROP_SERVER_USER_TAGS:
+               camel_imapx_message_info_take_server_user_tags (imi, g_value_dup_boxed (value));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+imapx_message_info_get_property (GObject *object,
+                                guint property_id,
+                                GValue *value,
+                                GParamSpec *pspec)
+{
+       CamelIMAPXMessageInfo *imi = CAMEL_IMAPX_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_SERVER_FLAGS:
+               g_value_set_uint (value, camel_imapx_message_info_get_server_flags (imi));
+               return;
+
+       case PROP_SERVER_USER_FLAGS:
+               g_value_take_boxed (value, camel_imapx_message_info_dup_server_user_flags (imi));
+               return;
+
+       case PROP_SERVER_USER_TAGS:
+               g_value_take_boxed (value, camel_imapx_message_info_dup_server_user_tags (imi));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+imapx_message_info_dispose (GObject *object)
+{
+       CamelIMAPXMessageInfo *imi = CAMEL_IMAPX_MESSAGE_INFO (object);
+
+       camel_named_flags_free (imi->priv->server_user_flags);
+       imi->priv->server_user_flags = NULL;
+
+       camel_name_value_array_free (imi->priv->server_user_tags);
+       imi->priv->server_user_tags = NULL;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_imapx_message_info_parent_class)->dispose (object);
+}
+
+static void
+camel_imapx_message_info_class_init (CamelIMAPXMessageInfoClass *class)
+{
+       CamelMessageInfoClass *mi_class;
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelIMAPXMessageInfoPrivate));
+
+       mi_class = CAMEL_MESSAGE_INFO_CLASS (class);
+       mi_class->clone = imapx_message_info_clone;
+       mi_class->load = imapx_message_info_load;
+       mi_class->save = imapx_message_info_save;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = imapx_message_info_set_property;
+       object_class->get_property = imapx_message_info_get_property;
+       object_class->dispose = imapx_message_info_dispose;
+
+       /**
+        * CamelIMAPXMessageInfo:server-flags
+        *
+        * Bit-or of #CamelMessageFlags of the flags stored on the server.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_SERVER_FLAGS,
+               g_param_spec_uint (
+                       "server-flags",
+                       "Server Flags",
+                       NULL,
+                       0, G_MAXUINT32, 0,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelIMAPXMessageInfo:server-user-flags
+        *
+        * User flags for the associated message, as stored on the server.
+        * Can be %NULL.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_SERVER_USER_FLAGS,
+               g_param_spec_boxed (
+                       "server-user-flags",
+                       "Server User Flags",
+                       NULL,
+                       CAMEL_TYPE_NAMED_FLAGS,
+                       G_PARAM_READWRITE));
+
+       /**
+        * CamelIMAPXMessageInfo:server-user-tags
+        *
+        * User tags for the associated message, as stored on the server.
+        * Can be %NULL.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_SERVER_USER_TAGS,
+               g_param_spec_boxed (
+                       "server-user-tags",
+                       "Server User tags",
+                       NULL,
+                       CAMEL_TYPE_NAME_VALUE_ARRAY,
+                       G_PARAM_READWRITE));
+}
+
+static void
+camel_imapx_message_info_init (CamelIMAPXMessageInfo *imi)
+{
+       imi->priv = G_TYPE_INSTANCE_GET_PRIVATE (imi, CAMEL_TYPE_IMAPX_MESSAGE_INFO, 
CamelIMAPXMessageInfoPrivate);
+}
+
+guint32
+camel_imapx_message_info_get_server_flags (const CamelIMAPXMessageInfo *imi)
+{
+       CamelMessageInfo *mi;
+       guint32 result;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (imi), 0);
+
+       mi = CAMEL_MESSAGE_INFO (imi);
+
+       camel_message_info_property_lock (mi);
+       result = imi->priv->server_flags;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gboolean
+camel_imapx_message_info_set_server_flags (CamelIMAPXMessageInfo *imi,
+                                          guint32 server_flags)
+{
+       CamelMessageInfo *mi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (imi), FALSE);
+
+       mi = CAMEL_MESSAGE_INFO (imi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = imi->priv->server_flags != server_flags;
+       if (changed)
+               imi->priv->server_flags = server_flags;
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !camel_message_info_get_abort_notifications (mi)) {
+               g_object_notify (G_OBJECT (imi), "server-flags");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
+
+const CamelNamedFlags *
+camel_imapx_message_info_get_server_user_flags (const CamelIMAPXMessageInfo *imi)
+{
+       CamelMessageInfo *mi;
+       const CamelNamedFlags *result;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (imi), NULL);
+
+       mi = CAMEL_MESSAGE_INFO (imi);
+
+       camel_message_info_property_lock (mi);
+       result = imi->priv->server_user_flags;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+CamelNamedFlags *
+camel_imapx_message_info_dup_server_user_flags (const CamelIMAPXMessageInfo *imi)
+{
+       CamelMessageInfo *mi;
+       CamelNamedFlags *result;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (imi), NULL);
+
+       mi = CAMEL_MESSAGE_INFO (imi);
+
+       camel_message_info_property_lock (mi);
+       result = camel_named_flags_copy (imi->priv->server_user_flags);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gboolean
+camel_imapx_message_info_take_server_user_flags (CamelIMAPXMessageInfo *imi,
+                                                CamelNamedFlags *server_user_flags)
+{
+       CamelMessageInfo *mi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (imi), FALSE);
+
+       mi = CAMEL_MESSAGE_INFO (imi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = !camel_named_flags_equal (imi->priv->server_user_flags, server_user_flags);
+
+       if (changed) {
+               camel_named_flags_free (imi->priv->server_user_flags);
+               imi->priv->server_user_flags = server_user_flags;
+       } else {
+               camel_named_flags_free (server_user_flags);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !camel_message_info_get_abort_notifications (mi)) {
+               g_object_notify (G_OBJECT (imi), "server-user-flags");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
+
+const CamelNameValueArray *
+camel_imapx_message_info_get_server_user_tags (const CamelIMAPXMessageInfo *imi)
+{
+       CamelMessageInfo *mi;
+       const CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (imi), NULL);
+
+       mi = CAMEL_MESSAGE_INFO (imi);
+
+       camel_message_info_property_lock (mi);
+       result = imi->priv->server_user_tags;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+CamelNameValueArray *
+camel_imapx_message_info_dup_server_user_tags (const CamelIMAPXMessageInfo *imi)
+{
+       CamelMessageInfo *mi;
+       CamelNameValueArray *result;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (imi), NULL);
+
+       mi = CAMEL_MESSAGE_INFO (imi);
+
+       camel_message_info_property_lock (mi);
+       result = camel_name_value_array_copy (imi->priv->server_user_tags);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gboolean
+camel_imapx_message_info_take_server_user_tags (CamelIMAPXMessageInfo *imi,
+                                               CamelNameValueArray *server_user_tags)
+{
+       CamelMessageInfo *mi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MESSAGE_INFO (imi), FALSE);
+
+       mi = CAMEL_MESSAGE_INFO (imi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = !camel_name_value_array_equal (imi->priv->server_user_tags, server_user_tags, 
CAMEL_COMPARE_CASE_SENSITIVE);
+
+       if (changed) {
+               camel_name_value_array_free (imi->priv->server_user_tags);
+               imi->priv->server_user_tags = server_user_tags;
+       } else {
+               camel_name_value_array_free (server_user_tags);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !camel_message_info_get_abort_notifications (mi)) {
+               g_object_notify (G_OBJECT (imi), "server-user-tags");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
diff --git a/src/camel/providers/imapx/camel-imapx-message-info.h 
b/src/camel/providers/imapx/camel-imapx-message-info.h
new file mode 100644
index 0000000..f553559
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-message-info.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#ifndef CAMEL_IMAPX_MESSAGE_INFO_H
+#define CAMEL_IMAPX_MESSAGE_INFO_H
+
+#include <glib-object.h>
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_IMAPX_MESSAGE_INFO \
+       (camel_imapx_message_info_get_type ())
+#define CAMEL_IMAPX_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_IMAPX_MESSAGE_INFO, CamelIMAPXMessageInfo))
+#define CAMEL_IMAPX_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_IMAPX_MESSAGE_INFO, CamelIMAPXMessageInfoClass))
+#define CAMEL_IS_IMAPX_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_IMAPX_MESSAGE_INFO))
+#define CAMEL_IS_IMAPX_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_IMAPX_MESSAGE_INFO))
+#define CAMEL_IMAPX_MESSAGE_INFO_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_IMAPX_MESSAGE_INFO, CamelIMAPXMessageInfoClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelIMAPXMessageInfo CamelIMAPXMessageInfo;
+typedef struct _CamelIMAPXMessageInfoClass CamelIMAPXMessageInfoClass;
+typedef struct _CamelIMAPXMessageInfoPrivate CamelIMAPXMessageInfoPrivate;
+
+struct _CamelIMAPXMessageInfo {
+       CamelMessageInfoBase parent;
+       CamelIMAPXMessageInfoPrivate *priv;
+};
+
+struct _CamelIMAPXMessageInfoClass {
+       CamelMessageInfoBaseClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
+};
+
+GType          camel_imapx_message_info_get_type       (void);
+
+guint32                camel_imapx_message_info_get_server_flags
+                                                       (const CamelIMAPXMessageInfo *imi);
+gboolean       camel_imapx_message_info_set_server_flags
+                                                       (CamelIMAPXMessageInfo *imi,
+                                                        guint32 server_flags);
+const CamelNamedFlags *
+               camel_imapx_message_info_get_server_user_flags
+                                                       (const CamelIMAPXMessageInfo *imi);
+CamelNamedFlags *
+               camel_imapx_message_info_dup_server_user_flags
+                                                       (const CamelIMAPXMessageInfo *imi);
+gboolean       camel_imapx_message_info_take_server_user_flags
+                                                       (CamelIMAPXMessageInfo *imi,
+                                                        CamelNamedFlags *server_user_flags);
+const CamelNameValueArray *
+               camel_imapx_message_info_get_server_user_tags
+                                                       (const CamelIMAPXMessageInfo *imi);
+CamelNameValueArray *
+               camel_imapx_message_info_dup_server_user_tags
+                                                       (const CamelIMAPXMessageInfo *imi);
+gboolean       camel_imapx_message_info_take_server_user_tags
+                                                       (CamelIMAPXMessageInfo *imi,
+                                                        CamelNameValueArray *server_user_tags);
+
+G_END_DECLS
+
+#endif /* CAMEL_IMAPX_MESSAGE_INFO_H */
diff --git a/src/camel/providers/imapx/camel-imapx-namespace-response.h 
b/src/camel/providers/imapx/camel-imapx-namespace-response.h
index 0321dd3..af71b8a 100644
--- a/src/camel/providers/imapx/camel-imapx-namespace-response.h
+++ b/src/camel/providers/imapx/camel-imapx-namespace-response.h
@@ -61,6 +61,9 @@ struct _CamelIMAPXNamespaceResponse {
 
 struct _CamelIMAPXNamespaceResponseClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_namespace_response_get_type
diff --git a/src/camel/providers/imapx/camel-imapx-namespace.h 
b/src/camel/providers/imapx/camel-imapx-namespace.h
index d6fdb5f..5d42cf2 100644
--- a/src/camel/providers/imapx/camel-imapx-namespace.h
+++ b/src/camel/providers/imapx/camel-imapx-namespace.h
@@ -78,6 +78,9 @@ struct _CamelIMAPXNamespace {
 
 struct _CamelIMAPXNamespaceClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_namespace_get_type
diff --git a/src/camel/providers/imapx/camel-imapx-search.c b/src/camel/providers/imapx/camel-imapx-search.c
index b4e0a80..f06215b 100644
--- a/src/camel/providers/imapx/camel-imapx-search.c
+++ b/src/camel/providers/imapx/camel-imapx-search.c
@@ -116,19 +116,23 @@ imapx_search_result_match_all (CamelSExp *sexp,
 
        g_return_val_if_fail (search != NULL, NULL);
 
-       if (search->current != NULL) {
+       if (camel_folder_search_get_current_message_info (search)) {
                result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
                result->value.boolean = TRUE;
        } else {
+               GPtrArray *summary;
                gint ii;
 
+               summary = camel_folder_search_get_summary (search);
+
                result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_ARRAY_PTR);
                result->value.ptrarray = g_ptr_array_new ();
 
-               for (ii = 0; ii < search->summary->len; ii++)
+               for (ii = 0; summary && ii < summary->len; ii++) {
                        g_ptr_array_add (
                                result->value.ptrarray,
-                               (gpointer) search->summary->pdata[ii]);
+                               (gpointer) summary->pdata[ii]);
+               }
        }
 
        return result;
@@ -142,7 +146,7 @@ imapx_search_result_match_none (CamelSExp *sexp,
 
        g_return_val_if_fail (search != NULL, NULL);
 
-       if (search->current != NULL) {
+       if (camel_folder_search_get_current_message_info (search)) {
                result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
                result->value.boolean = FALSE;
        } else {
@@ -169,7 +173,7 @@ imapx_search_process_criteria (CamelSExp *sexp,
        GError *local_error = NULL;
 
        mailbox = camel_imapx_folder_list_mailbox (
-               CAMEL_IMAPX_FOLDER (search->folder), imapx_search->priv->cancellable, &local_error);
+               CAMEL_IMAPX_FOLDER (camel_folder_search_get_folder (search)), 
imapx_search->priv->cancellable, &local_error);
 
        /* Sanity check. */
        g_return_val_if_fail (
@@ -205,7 +209,7 @@ imapx_search_process_criteria (CamelSExp *sexp,
                uids = g_ptr_array_new ();
        }
 
-       if (search->current != NULL) {
+       if (camel_folder_search_get_current_message_info (search)) {
                result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
                result->value.boolean = (uids && uids->len > 0);
        } else {
@@ -234,7 +238,7 @@ imapx_search_match_all (CamelSExp *sexp,
                return imapx_search_result_match_none (sexp, search);
 
        imapx_store = camel_imapx_search_ref_store (CAMEL_IMAPX_SEARCH (search));
-       if (!imapx_store || search->current || !search->summary) {
+       if (!imapx_store || camel_folder_search_get_current_message_info (search) || 
!camel_folder_search_get_summary (search)) {
                g_clear_object (&imapx_store);
 
                /* Chain up to parent's method. */
@@ -247,19 +251,18 @@ imapx_search_match_all (CamelSExp *sexp,
        prev_local_data_search = imapx_search->priv->local_data_search;
        imapx_search->priv->local_data_search = &local_data_search;
 
-       summary = search->summary_set ? search->summary_set : search->summary;
+       summary = camel_folder_search_get_current_summary (search);
 
-       if (!CAMEL_IS_VEE_FOLDER (search->folder)) {
-               camel_folder_summary_prepare_fetch_all (search->folder->summary, NULL);
+       if (!CAMEL_IS_VEE_FOLDER (camel_folder_search_get_folder (search))) {
+               camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary 
(camel_folder_search_get_folder (search)), NULL);
        }
 
        for (ii = 0; ii < summary->len; ii++) {
-               search->current = camel_folder_summary_get (search->folder->summary, summary->pdata[ii]);
-               if (search->current) {
+               camel_folder_search_take_current_message_info (search, camel_folder_summary_get 
(camel_folder_get_folder_summary (camel_folder_search_get_folder (search)), summary->pdata[ii]));
+               if (camel_folder_search_get_current_message_info (search)) {
                        result = camel_sexp_term_eval (sexp, argv[0]);
                        camel_sexp_result_free (sexp, result);
-                       camel_message_info_unref (search->current);
-                       search->current = NULL;
+                       camel_folder_search_set_current_message_info (search, NULL);
                        break;
                }
        }
@@ -360,7 +363,7 @@ imapx_search_body_contains (CamelSExp *sexp,
                return imapx_search_result_match_all (sexp, search);
 
        /* Match nothing if empty argv or empty summary. */
-       if (argc == 0 || search->summary->len == 0)
+       if (argc == 0 || camel_folder_search_get_summary_empty (search))
                return imapx_search_result_match_none (sexp, search);
 
        imapx_store = camel_imapx_search_ref_store (CAMEL_IMAPX_SEARCH (search));
@@ -376,11 +379,11 @@ imapx_search_body_contains (CamelSExp *sexp,
 
        criteria = g_string_sized_new (128);
 
-       if (search->current != NULL) {
+       if (camel_folder_search_get_current_message_info (search)) {
                const gchar *uid;
 
                /* Limit the search to a single UID. */
-               uid = camel_message_info_get_uid (search->current);
+               uid = camel_message_info_get_uid (camel_folder_search_get_current_message_info (search));
                g_string_append_printf (criteria, "UID %s", uid);
        }
 
@@ -421,7 +424,7 @@ imapx_search_header_contains (CamelSExp *sexp,
        /* Match nothing if empty argv or empty summary. */
        if (argc <= 1 ||
            argv[0]->type != CAMEL_SEXP_RES_STRING ||
-           search->summary->len == 0)
+           camel_folder_search_get_summary_empty (search))
                return imapx_search_result_match_none (sexp, search);
 
        headername = argv[0]->value.string;
@@ -454,11 +457,11 @@ imapx_search_header_contains (CamelSExp *sexp,
 
        criteria = g_string_sized_new (128);
 
-       if (search->current != NULL) {
+       if (camel_folder_search_get_current_message_info (search)) {
                const gchar *uid;
 
                /* Limit the search to a single UID. */
-               uid = camel_message_info_get_uid (search->current);
+               uid = camel_message_info_get_uid (camel_folder_search_get_current_message_info (search));
                g_string_append_printf (criteria, "UID %s", uid);
        }
 
@@ -501,7 +504,7 @@ imapx_search_header_exists (CamelSExp *sexp,
        gint ii;
 
        /* Match nothing if empty argv or empty summary. */
-       if (argc == 0 || search->summary->len == 0)
+       if (argc == 0 || camel_folder_search_get_summary_empty (search))
                return imapx_search_result_match_none (sexp, search);
 
        /* Check if asking for locally stored headers only */
@@ -543,11 +546,11 @@ imapx_search_header_exists (CamelSExp *sexp,
 
        criteria = g_string_sized_new (128);
 
-       if (search->current != NULL) {
+       if (camel_folder_search_get_current_message_info (search)) {
                const gchar *uid;
 
                /* Limit the search to a single UID. */
-               uid = camel_message_info_get_uid (search->current);
+               uid = camel_message_info_get_uid (camel_folder_search_get_current_message_info (search));
                g_string_append_printf (criteria, "UID %s", uid);
        }
 
diff --git a/src/camel/providers/imapx/camel-imapx-search.h b/src/camel/providers/imapx/camel-imapx-search.h
index acdba79..93b8daa 100644
--- a/src/camel/providers/imapx/camel-imapx-search.h
+++ b/src/camel/providers/imapx/camel-imapx-search.h
@@ -62,6 +62,9 @@ struct _CamelIMAPXSearch {
 
 struct _CamelIMAPXSearchClass {
        CamelFolderSearchClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_search_get_type     (void) G_GNUC_CONST;
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index 5665ad7..1c91744 100644
--- a/src/camel/providers/imapx/camel-imapx-server.c
+++ b/src/camel/providers/imapx/camel-imapx-server.c
@@ -41,6 +41,7 @@
 #include "camel-imapx-input-stream.h"
 #include "camel-imapx-job.h"
 #include "camel-imapx-logger.h"
+#include "camel-imapx-message-info.h"
 #include "camel-imapx-settings.h"
 #include "camel-imapx-store.h"
 #include "camel-imapx-summary.h"
@@ -362,7 +363,7 @@ G_DEFINE_TYPE (CamelIMAPXServer, camel_imapx_server, G_TYPE_OBJECT)
 
 typedef struct _FetchChangesInfo {
        guint32 server_flags;
-       CamelFlag *server_user_flags;
+       CamelNamedFlags *server_user_flags;
 } FetchChangesInfo;
 
 static void
@@ -371,7 +372,7 @@ fetch_changes_info_free (gpointer ptr)
        FetchChangesInfo *nfo = ptr;
 
        if (nfo) {
-               camel_flag_list_free (&nfo->server_user_flags);
+               camel_named_flags_free (nfo->server_user_flags);
                g_free (nfo);
        }
 }
@@ -760,7 +761,7 @@ imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
 
        g_return_if_fail (is->priv->changes != NULL);
 
-       camel_folder_summary_remove_uid (folder->summary, uid);
+       camel_folder_summary_remove_uid (camel_folder_get_folder_summary (folder), uid);
 
        g_mutex_lock (&is->priv->changes_lock);
 
@@ -774,7 +775,7 @@ imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
 
                g_mutex_unlock (&is->priv->changes_lock);
 
-               camel_folder_summary_save_to_db (folder->summary, NULL);
+               camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
                imapx_update_store_summary (folder);
                camel_folder_changed (folder, changes);
 
@@ -969,7 +970,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
        g_mutex_unlock (&is->priv->changes_lock);
 
        uid_list = g_list_reverse (uid_list);
-       camel_folder_summary_remove_uids (folder->summary, uid_list);
+       camel_folder_summary_remove_uids (camel_folder_get_folder_summary (folder), uid_list);
 
        /* If the response is truly unsolicited (e.g. via NOTIFY)
         * then go ahead and emit the change notification now. */
@@ -987,7 +988,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 
                        g_mutex_unlock (&is->priv->changes_lock);
 
-                       camel_folder_summary_save_to_db (folder->summary, NULL);
+                       camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
                        imapx_update_store_summary (folder);
 
                        camel_folder_changed (folder, changes);
@@ -1069,7 +1070,7 @@ imapx_untagged_exists (CamelIMAPXServer *is,
        if (camel_imapx_server_is_in_idle (is)) {
                guint count;
 
-               count = camel_folder_summary_count (folder->summary);
+               count = camel_folder_summary_count (camel_folder_get_folder_summary (folder));
                if (count < exists)
                        g_signal_emit (is, signals[REFRESH_MAILBOX], 0, mailbox);
        }
@@ -1243,7 +1244,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
                        }
 
                        if (uid) {
-                               mi = camel_folder_summary_get (select_folder->summary, uid);
+                               mi = camel_folder_summary_get (camel_folder_get_folder_summary 
(select_folder), uid);
                                if (mi) {
                                        /* It's unsolicited _unless_ select_pending (i.e. during
                                         * a QRESYNC SELECT */
@@ -1271,7 +1272,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
                        g_free (uid);
 
                        if (changed && camel_imapx_server_is_in_idle (is)) {
-                               camel_folder_summary_save_to_db (select_folder->summary, NULL);
+                               camel_folder_summary_save (camel_folder_get_folder_summary (select_folder), 
NULL);
                                imapx_update_store_summary (select_folder);
 
                                g_mutex_lock (&is->priv->changes_lock);
@@ -1282,8 +1283,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
                                g_mutex_unlock (&is->priv->changes_lock);
                        }
 
-                       if (mi)
-                               camel_message_info_unref (mi);
+                       g_clear_object (&mi);
 
                        g_object_unref (select_folder);
                }
@@ -1332,16 +1332,17 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
                mp = camel_mime_parser_new ();
                camel_mime_parser_init_with_bytes (mp, finfo->header);
-               mi = camel_folder_summary_info_new_from_parser (folder->summary, mp);
+               mi = camel_folder_summary_info_new_from_parser (camel_folder_get_folder_summary (folder), mp);
                g_object_unref (mp);
 
                if (mi != NULL) {
                        guint32 server_flags;
-                       CamelFlag *server_user_flags;
-                       CamelMessageInfoBase *binfo;
+                       CamelNamedFlags *server_user_flags;
                        gboolean free_user_flags = FALSE;
 
-                       mi->uid = camel_pstring_strdup (finfo->uid);
+                       camel_message_info_set_abort_notifications (mi, TRUE);
+
+                       camel_message_info_set_uid (mi, finfo->uid);
 
                        if (!(finfo->got & FETCH_FLAGS) && is->priv->fetch_changes_infos) {
                                FetchChangesInfo *nfo;
@@ -1367,45 +1368,44 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
                        if (!(server_flags & CAMEL_MESSAGE_SEEN)) {
                                guint64 uidl;
 
-                               uidl = strtoull (mi->uid, NULL, 10);
+                               uidl = strtoull (finfo->uid, NULL, 10);
 
                                if (uidl >= uidnext) {
-                                       c (is->priv->tagprefix, "Updating unseen count for new message %s\n", 
mi->uid);
+                                       c (is->priv->tagprefix, "Updating unseen count for new message %s\n", 
finfo->uid);
                                        camel_imapx_mailbox_set_unseen (mailbox, unseen + 1);
                                } else {
-                                       c (is->priv->tagprefix, "Not updating unseen count for new message 
%s\n", mi->uid);
+                                       c (is->priv->tagprefix, "Not updating unseen count for new message 
%s\n", finfo->uid);
                                }
                        }
 
-                       binfo = (CamelMessageInfoBase *) mi;
-                       binfo->size = finfo->size;
+                       camel_message_info_set_size (mi, finfo->size);
+                       camel_message_info_set_abort_notifications (mi, FALSE);
 
-                       camel_folder_summary_lock (folder->summary);
+                       camel_folder_summary_lock (camel_folder_get_folder_summary (folder));
 
-                       if (!camel_folder_summary_check_uid (folder->summary, mi->uid)) {
+                       if (!camel_folder_summary_check_uid (camel_folder_get_folder_summary (folder), 
finfo->uid)) {
                                imapx_set_message_info_flags_for_new_message (mi, server_flags, 
server_user_flags, FALSE, NULL, camel_imapx_mailbox_get_permanentflags (mailbox));
-                               camel_folder_summary_add (folder->summary, mi);
+                               camel_folder_summary_add (camel_folder_get_folder_summary (folder), mi, 
FALSE);
 
                                g_mutex_lock (&is->priv->changes_lock);
 
-                               camel_folder_change_info_add_uid (is->priv->changes, mi->uid);
-                               camel_folder_change_info_recent_uid (is->priv->changes, mi->uid);
+                               camel_folder_change_info_add_uid (is->priv->changes, finfo->uid);
+                               camel_folder_change_info_recent_uid (is->priv->changes, finfo->uid);
 
                                g_mutex_unlock (&is->priv->changes_lock);
 
                                if (messages > 0) {
-                                       gint cnt = (camel_folder_summary_count (folder->summary) * 100) / 
messages;
+                                       gint cnt = (camel_folder_summary_count 
(camel_folder_get_folder_summary (folder)) * 100) / messages;
 
                                        camel_operation_progress (cancellable, cnt ? cnt : 1);
                                }
-                       } else {
-                               camel_message_info_unref (mi);
                        }
 
-                       camel_folder_summary_unlock (folder->summary);
+                       g_clear_object (&mi);
+                       camel_folder_summary_unlock (camel_folder_get_folder_summary (folder));
 
-                       if (free_user_flags && server_user_flags)
-                               camel_flag_list_free (&server_user_flags);
+                       if (free_user_flags)
+                               camel_named_flags_free (server_user_flags);
                }
 
                g_clear_object (&mailbox);
@@ -2332,7 +2332,7 @@ imapx_completion (CamelIMAPXServer *is,
                        folder = imapx_server_ref_folder (is, mailbox);
                        g_return_val_if_fail (folder != NULL, FALSE);
 
-                       camel_folder_summary_save_to_db (folder->summary, NULL);
+                       camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
 
                        imapx_update_store_summary (folder);
                        camel_folder_changed (folder, changes);
@@ -4082,12 +4082,12 @@ camel_imapx_server_get_message_sync (CamelIMAPXServer *is,
 
        cache_stream = camel_data_cache_add (message_cache, "tmp", message_uid, error);
        if (cache_stream == NULL) {
-               camel_message_info_unref (mi);
+               g_clear_object (&mi);
                return NULL;
        }
 
        settings = camel_imapx_server_ref_settings (is);
-       data_size = ((CamelMessageInfoBase *) mi)->size;
+       data_size = camel_message_info_get_size (mi);
        use_multi_fetch = data_size > MULTI_SIZE && camel_imapx_settings_get_use_multi_fetch (settings);
        g_object_unref (settings);
 
@@ -4303,8 +4303,8 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
        folder = imapx_server_ref_folder (is, mailbox);
        g_return_val_if_fail (folder != NULL, FALSE);
 
-       remove_deleted_flags = remove_deleted_flags || (folder->folder_flags & CAMEL_FOLDER_IS_TRASH) != 0;
-       remove_junk_flags = (folder->folder_flags & CAMEL_FOLDER_IS_JUNK) != 0;
+       remove_deleted_flags = remove_deleted_flags || (camel_folder_get_flags (folder) & 
CAMEL_FOLDER_IS_TRASH) != 0;
+       remove_junk_flags = (camel_folder_get_flags (folder) & CAMEL_FOLDER_IS_JUNK) != 0;
 
        /* If we're moving messages, prefer "UID MOVE" if supported. */
        if (delete_originals) {
@@ -4318,14 +4318,14 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
                g_mutex_unlock (&is->priv->stream_lock);
        }
 
-       source_infos = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, camel_message_info_unref);
+       source_infos = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
        data_uids = g_ptr_array_new ();
 
        for (ii = 0; ii < uids->len; ii++) {
                gchar *uid = (gchar *) camel_pstring_strdup (uids->pdata[ii]);
 
                g_ptr_array_add (data_uids, uid);
-               g_hash_table_insert (source_infos, uid, camel_folder_summary_get (folder->summary, uid));
+               g_hash_table_insert (source_infos, uid, camel_folder_summary_get 
(camel_folder_get_folder_summary (folder), uid));
        }
 
        g_ptr_array_sort (data_uids, (GCompareFunc) imapx_uids_array_cmp);
@@ -4393,40 +4393,41 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
                                                        continue;
 
                                                uid = g_strdup_printf ("%d", g_array_index 
(copyuid_status->u.copyuid.copied_uids, guint32, ii));
-                                               destination_info = camel_folder_summary_get (folder->summary, 
uid);
+                                               destination_info = camel_folder_summary_get 
(camel_folder_get_folder_summary (folder), uid);
 
                                                if (!destination_info) {
                                                        is_new = TRUE;
-                                                       destination_info = camel_message_info_clone 
(source_info);
-                                                       destination_info->summary = 
destination_folder->summary;
-                                                       camel_pstring_free (destination_info->uid);
-                                                       destination_info->uid = camel_pstring_strdup (uid);
+                                                       destination_info = camel_message_info_clone 
(source_info, camel_folder_get_folder_summary (destination_folder));
+                                                       camel_message_info_set_uid (destination_info, uid);
                                                }
 
                                                g_free (uid);
 
+                                               camel_message_info_property_lock (source_info);
+
                                                imapx_set_message_info_flags_for_new_message (
                                                        destination_info,
-                                                       ((CamelMessageInfoBase *) source_info)->flags,
-                                                       ((CamelMessageInfoBase *) source_info)->user_flags,
+                                                       camel_message_info_get_flags (source_info),
+                                                       camel_message_info_get_user_flags (source_info),
                                                        TRUE,
-                                                       ((CamelMessageInfoBase *) source_info)->user_tags,
+                                                       camel_message_info_get_user_tags (source_info),
                                                        camel_imapx_mailbox_get_permanentflags (destination));
                                                if (remove_deleted_flags)
                                                        camel_message_info_set_flags (destination_info, 
CAMEL_MESSAGE_DELETED, 0);
                                                if (remove_junk_flags)
                                                        camel_message_info_set_flags (destination_info, 
CAMEL_MESSAGE_JUNK, 0);
                                                if (is_new)
-                                                       camel_folder_summary_add 
(destination_folder->summary, destination_info);
-                                               camel_folder_change_info_add_uid (changes, 
destination_info->uid);
+                                                       camel_folder_summary_add 
(camel_folder_get_folder_summary (destination_folder), destination_info, FALSE);
+                                               camel_folder_change_info_add_uid (changes, 
camel_message_info_get_uid (destination_info));
+
+                                               camel_message_info_property_unlock (source_info);
 
-                                               if (!is_new)
-                                                       camel_message_info_unref (destination_info);
+                                               g_clear_object (&destination_info);
                                        }
 
                                        if (camel_folder_change_info_changed (changes)) {
-                                               camel_folder_summary_touch (destination_folder->summary);
-                                               camel_folder_summary_save_to_db (destination_folder->summary, 
NULL);
+                                               camel_folder_summary_touch (camel_folder_get_folder_summary 
(destination_folder));
+                                               camel_folder_summary_save (camel_folder_get_folder_summary 
(destination_folder), NULL);
                                                camel_folder_changed (destination_folder, changes);
                                        }
 
@@ -4447,7 +4448,7 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
                                        if (delete_originals) {
                                                camel_folder_delete_message (folder, uid);
                                        } else {
-                                               if (camel_folder_summary_remove_uid (folder->summary, uid)) {
+                                               if (camel_folder_summary_remove_uid 
(camel_folder_get_folder_summary (folder), uid)) {
                                                        if (!changes)
                                                                changes = camel_folder_change_info_new ();
 
@@ -4457,8 +4458,8 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
                                }
 
                                if (changes && camel_folder_change_info_changed (changes)) {
-                                       camel_folder_summary_touch (folder->summary);
-                                       camel_folder_summary_save_to_db (folder->summary, NULL);
+                                       camel_folder_summary_touch (camel_folder_get_folder_summary (folder));
+                                       camel_folder_summary_save (camel_folder_get_folder_summary (folder), 
NULL);
                                        camel_folder_changed (folder, changes);
                                }
 
@@ -4572,35 +4573,22 @@ camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
 
        date_time = camel_mime_message_get_date (message, NULL);
        path = camel_data_cache_get_filename (message_cache, "new", uid);
-       info = camel_folder_summary_info_new_from_message (summary, message, NULL);
-       info->uid = camel_pstring_strdup (uid);
+       info = camel_folder_summary_info_new_from_message (summary, message);
+
+       camel_message_info_set_abort_notifications (info, TRUE);
+       camel_message_info_set_uid (info, uid);
 
        if (mi != NULL) {
                struct icaltimetype icaltime;
-               CamelMessageInfoBase *base_info = (CamelMessageInfoBase *) info;
-               const CamelFlag *flag;
-               const CamelTag *tag;
-
-               base_info->flags = camel_message_info_get_flags (mi);
-               base_info->size = camel_message_info_get_size (mi);
-
-               flag = camel_message_info_get_user_flags (mi);
-               while (flag != NULL) {
-                       if (*flag->name != '\0')
-                               camel_flag_set (
-                                       &base_info->user_flags,
-                                       flag->name, TRUE);
-                       flag = flag->next;
-               }
 
-               tag = camel_message_info_get_user_tags (mi);
-               while (tag != NULL) {
-                       if (*tag->name != '\0')
-                               camel_tag_set (
-                                       &base_info->user_tags,
-                                       tag->name, tag->value);
-                       tag = tag->next;
-               }
+               camel_message_info_property_lock (mi);
+
+               camel_message_info_set_flags (info, ~0, camel_message_info_get_flags (mi));
+               camel_message_info_set_size (info, camel_message_info_get_size (mi));
+               camel_message_info_take_user_flags (info,
+                       camel_named_flags_copy (camel_message_info_get_user_flags (mi)));
+               camel_message_info_take_user_tags (info,
+                       camel_name_value_array_copy (camel_message_info_get_user_tags (mi)));
 
                if (date_time > 0) {
                        icaltime = icaltime_from_timet (date_time, FALSE);
@@ -4616,22 +4604,18 @@ camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
                        if (!icaltime_is_valid_time (icaltime))
                                date_time = -1;
                }
+
+               camel_message_info_property_unlock (mi);
        }
 
        if (!camel_message_info_get_size (info)) {
-               CamelStreamNull *sn = (CamelStreamNull *) camel_stream_null_new ();
-
-               camel_data_wrapper_write_to_stream_sync (
-                       CAMEL_DATA_WRAPPER (message),
-                       CAMEL_STREAM (sn), NULL, NULL);
-               ((CamelMessageInfoBase *) info)->size = sn->written;
-               g_object_unref (sn);
+               camel_message_info_set_size (info, camel_data_wrapper_calculate_size_sync (CAMEL_DATA_WRAPPER 
(message), NULL, NULL));
        }
 
        g_free (uid);
 
        if (camel_mime_message_has_attachment (message))
-               ((CamelMessageInfoBase *) info)->flags |= CAMEL_MESSAGE_ATTACHMENTS;
+               camel_message_info_set_flags (info, CAMEL_MESSAGE_ATTACHMENTS, CAMEL_MESSAGE_ATTACHMENTS);
 
        if (date_time > 0) {
                gchar *date_time_str;
@@ -4651,8 +4635,8 @@ camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
 
                ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_APPEND_MESSAGE, "APPEND %M %F %t %P",
                        mailbox,
-                       ((CamelMessageInfoBase *) info)->flags,
-                       ((CamelMessageInfoBase *) info)->user_flags,
+                       camel_message_info_get_flags (info),
+                       camel_message_info_get_user_flags (info),
                        date_time_str,
                        path);
 
@@ -4660,11 +4644,13 @@ camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
        } else {
                ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_APPEND_MESSAGE, "APPEND %M %F %P",
                        mailbox,
-                       ((CamelMessageInfoBase *) info)->flags,
-                       ((CamelMessageInfoBase *) info)->user_flags,
+                       camel_message_info_get_flags (info),
+                       camel_message_info_get_user_flags (info),
                        path);
        }
 
+       camel_message_info_set_abort_notifications (info, FALSE);
+
        success = camel_imapx_server_process_command_sync (is, ic, _("Error appending message"), cancellable, 
error);
 
        if (success) {
@@ -4687,36 +4673,42 @@ camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
                 * numbered MessageInfo, without losing any information.  Otherwise
                 * we have to wait for the server to let us know it was appended. */
 
-               mi = camel_message_info_clone (info);
-               old_uid = g_strdup (info->uid);
+               mi = camel_message_info_clone (info, NULL);
+               old_uid = g_strdup (camel_message_info_get_uid (info));
 
                if (ic->status && ic->status->condition == IMAPX_APPENDUID) {
                        c (is->priv->tagprefix, "Got appenduid %d %d\n", (gint) 
ic->status->u.appenduid.uidvalidity, (gint) ic->status->u.appenduid.uid);
                        if (ic->status->u.appenduid.uidvalidity == uidvalidity) {
-                               if (appended_uid)
-                                       *appended_uid = g_strdup_printf ("%u", (guint) 
ic->status->u.appenduid.uid);
-                               mi->uid = camel_pstring_add (g_strdup_printf ("%u", (guint) 
ic->status->u.appenduid.uid), TRUE);
+                               gchar *uid;
+
+                               uid = g_strdup_printf ("%u", (guint) ic->status->u.appenduid.uid);
+                               camel_message_info_set_uid (mi, uid);
 
-                               cur = camel_data_cache_get_filename  (imapx_folder->cache, "cur", mi->uid);
+                               cur = camel_data_cache_get_filename  (imapx_folder->cache, "cur", uid);
                                if (g_rename (path, cur) == -1 && errno != ENOENT) {
                                        g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC, path, 
cur, g_strerror (errno));
                                }
 
                                imapx_set_message_info_flags_for_new_message (
                                        mi,
-                                       ((CamelMessageInfoBase *) info)->flags,
-                                       ((CamelMessageInfoBase *) info)->user_flags,
+                                       camel_message_info_get_flags (info),
+                                       camel_message_info_get_user_flags (info),
                                        TRUE,
-                                       ((CamelMessageInfoBase *) info)->user_tags,
+                                       camel_message_info_get_user_tags (info),
                                        camel_imapx_mailbox_get_permanentflags (mailbox));
 
-                               camel_folder_summary_add (folder->summary, mi);
+                               camel_folder_summary_add (camel_folder_get_folder_summary (folder), mi, 
FALSE);
 
                                g_mutex_lock (&is->priv->changes_lock);
-                               camel_folder_change_info_add_uid (is->priv->changes, mi->uid);
+                               camel_folder_change_info_add_uid (is->priv->changes, 
camel_message_info_get_uid (mi));
                                g_mutex_unlock (&is->priv->changes_lock);
 
-                               mi = NULL;
+                               if (appended_uid)
+                                       *appended_uid = uid;
+                               else
+                                       g_free (uid);
+
+                               g_clear_object (&mi);
 
                                g_free (cur);
                        } else {
@@ -4728,8 +4720,7 @@ camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
                g_free (old_uid);
 
                camel_imapx_command_unref (ic);
-               if (mi)
-                       camel_message_info_unref (mi);
+               g_clear_object (&mi);
                g_object_unref (folder);
        }
 
@@ -4827,7 +4818,7 @@ imapx_server_process_fetch_changes_infos (CamelIMAPXServer *is,
        if (out_fetch_summary_uids)
                g_return_if_fail (*out_fetch_summary_uids == NULL);
 
-       summary = folder->summary;
+       summary = camel_folder_get_folder_summary (folder);
 
        g_hash_table_iter_init (&iter, infos);
        while (g_hash_table_iter_next (&iter, &key, &value)) {
@@ -4862,7 +4853,7 @@ imapx_server_process_fetch_changes_infos (CamelIMAPXServer *is,
                        g_mutex_unlock (&is->priv->changes_lock);
                }
 
-               camel_message_info_unref (minfo);
+               g_clear_object (&minfo);
        }
 }
 
@@ -5027,20 +5018,20 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
        folder = imapx_server_ref_folder (is, mailbox);
        g_return_val_if_fail (folder != NULL, FALSE);
 
-       imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
+       imapx_summary = CAMEL_IMAPX_SUMMARY (camel_folder_get_folder_summary (folder));
 
        messages = camel_imapx_mailbox_get_messages (mailbox);
        unseen = camel_imapx_mailbox_get_unseen (mailbox);
        uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
        uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
        highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-       total = camel_folder_summary_count (folder->summary);
+       total = camel_folder_summary_count (camel_folder_get_folder_summary (folder));
 
        need_rescan =
                (uidvalidity > 0 && uidvalidity != imapx_summary->validity) ||
                total != messages ||
                imapx_summary->uidnext != uidnext ||
-               camel_folder_summary_get_unread_count (folder->summary) != unseen ||
+               camel_folder_summary_get_unread_count (camel_folder_get_folder_summary (folder)) != unseen ||
                imapx_summary->modseq != highestmodseq;
 
        if (!need_rescan) {
@@ -5056,7 +5047,7 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
        if (is->priv->use_qresync && imapx_summary->modseq > 0 && uidvalidity > 0) {
                imapx_summary->modseq = highestmodseq;
                if (total != messages ||
-                   camel_folder_summary_get_unread_count (folder->summary) != unseen ||
+                   camel_folder_summary_get_unread_count (camel_folder_get_folder_summary (folder)) != 
unseen ||
                    imapx_summary->modseq != highestmodseq) {
                        c (
                                is->priv->tagprefix,
@@ -5064,7 +5055,7 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
                                "total %u / %u, unread %u / %u, modseq %"
                                G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
                                total, messages,
-                               camel_folder_summary_get_unread_count (folder->summary),
+                               camel_folder_summary_get_unread_count (camel_folder_get_folder_summary 
(folder)),
                                unseen,
                                imapx_summary->modseq,
                                highestmodseq);
@@ -5075,7 +5066,7 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
                                "total %u / %u, unread %u / %u, modseq %"
                                G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
                                total, messages,
-                               camel_folder_summary_get_unread_count (folder->summary),
+                               camel_folder_summary_get_unread_count (camel_folder_get_folder_summary 
(folder)),
                                unseen,
                                imapx_summary->modseq,
                                highestmodseq);
@@ -5097,7 +5088,7 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
                uidl = 1;
        }
 
-       camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
+       camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary (folder), NULL);
 
        known_uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, 
NULL);
 
@@ -5111,11 +5102,11 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
                GPtrArray *array;
                gint ii;
 
-               camel_folder_summary_lock (folder->summary);
+               camel_folder_summary_lock (camel_folder_get_folder_summary (folder));
 
                changes = camel_folder_change_info_new ();
 
-               array = camel_folder_summary_get_array (folder->summary);
+               array = camel_folder_summary_get_array (camel_folder_get_folder_summary (folder));
                for (ii = 0; array && ii < array->len; ii++) {
                        const gchar *uid = array->pdata[ii];
 
@@ -5128,18 +5119,18 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
                        }
                }
 
-               camel_folder_summary_unlock (folder->summary);
+               camel_folder_summary_unlock (camel_folder_get_folder_summary (folder));
 
                if (removed != NULL) {
-                       camel_folder_summary_remove_uids (folder->summary, removed);
-                       camel_folder_summary_touch (folder->summary);
+                       camel_folder_summary_remove_uids (camel_folder_get_folder_summary (folder), removed);
+                       camel_folder_summary_touch (camel_folder_get_folder_summary (folder));
 
                        /* Shares UIDs with the 'array'. */
                        g_list_free (removed);
                }
 
                if (camel_folder_change_info_changed (changes)) {
-                       camel_folder_summary_save_to_db (folder->summary, NULL);
+                       camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
                        imapx_update_store_summary (folder);
                        camel_folder_changed (folder, changes);
                }
@@ -5169,7 +5160,7 @@ imapx_sync_free_user (GArray *user_set)
 
                for (j = 0; j < infos->len; j++) {
                        CamelMessageInfo *info = g_ptr_array_index (infos, j);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
 
                g_ptr_array_free (infos, TRUE);
@@ -5194,42 +5185,20 @@ imapx_unset_folder_flagged_flag (CamelFolderSummary *summary,
                info = camel_folder_summary_get (summary, changed_uids->pdata[ii]);
 
                if (info) {
-                       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
-
                        /* some infos could be only 'dirty' (needed to save into summary) */
-                       if ((mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 &&
-                          (!except_deleted_messages || (mi->flags & CAMEL_MESSAGE_DELETED) == 0)) {
-                               mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
-                               mi->dirty = TRUE;
+                       if (camel_message_info_get_folder_flagged (info) &&
+                          (!except_deleted_messages || (camel_message_info_get_flags (info) & 
CAMEL_MESSAGE_DELETED) == 0)) {
+                               camel_message_info_set_folder_flagged (info, FALSE);
                                changed = TRUE;
                        }
 
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
        }
 
        if (changed) {
                camel_folder_summary_touch (summary);
-               camel_folder_summary_save_to_db (summary, NULL);
-       }
-}
-
-static void
-imapx_server_info_changed_cb (CamelIMAPXSummary *summary,
-                             CamelMessageInfo *info,
-                             gpointer user_data)
-{
-       GHashTable *changed_meanwhile = user_data;
-
-       g_return_if_fail (info != NULL);
-       g_return_if_fail (changed_meanwhile != NULL);
-
-       /* The UID can be NULL in case of a newly fetched message, for example when creating
-          the message info in imapx_untagged_fetch() by camel_folder_summary_info_new_from_parser() */
-       if (camel_message_info_get_uid (info)) {
-               g_hash_table_insert (changed_meanwhile,
-                       (gpointer) camel_pstring_strdup (camel_message_info_get_uid (info)),
-                       GINT_TO_POINTER (1));
+               camel_folder_summary_save (summary, NULL);
        }
 }
 
@@ -5244,9 +5213,8 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
        GPtrArray *changed_uids;
        GArray *on_user = NULL, *off_user = NULL;
        CamelFolder *folder;
-       CamelIMAPXMessageInfo *info;
-       GHashTable *changed_meanwhile;
-       gulong changed_meanwhile_handler_id;
+       CamelMessageInfo *info;
+       GHashTable *stamps;
        guint32 permanentflags;
        struct _uidset_state uidset;
        gint unread_change = 0;
@@ -5272,7 +5240,7 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
         * one for each flag being turned off, including each
         * info being turned off, and one for each flag being turned on.
         */
-       changed_uids = camel_folder_summary_get_changed (folder->summary);
+       changed_uids = camel_folder_summary_get_changed (camel_folder_get_folder_summary (folder));
 
        if (changed_uids->len == 0) {
                camel_folder_free_uids (folder, changed_uids);
@@ -5280,9 +5248,7 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                return TRUE;
        }
 
-       changed_meanwhile = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) 
camel_pstring_free, NULL);
-       changed_meanwhile_handler_id = g_signal_connect (folder->summary, "info-changed",
-               G_CALLBACK (imapx_server_info_changed_cb), changed_meanwhile);
+       stamps = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, NULL);
 
        if (can_influence_flags) {
                CamelIMAPXSettings *settings;
@@ -5312,30 +5278,38 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
        }
 
        if (changed_uids->len > 20)
-               camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
+               camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary (folder), NULL);
 
        off_orset = on_orset = 0;
        for (i = 0; i < changed_uids->len; i++) {
+               CamelIMAPXMessageInfo *xinfo;
                guint32 flags, sflags;
-               CamelFlag *uflags, *suflags;
+               const CamelNamedFlags *local_uflags, *server_uflags;
                const gchar *uid;
                guint j = 0;
 
                uid = g_ptr_array_index (changed_uids, i);
 
-               info = (CamelIMAPXMessageInfo *)
-                       camel_folder_summary_get (folder->summary, uid);
+               info = camel_folder_summary_get (camel_folder_get_folder_summary (folder), uid);
+               xinfo = info ? CAMEL_IMAPX_MESSAGE_INFO (info) : NULL;
 
-               if (info == NULL)
+               if (!info || !xinfo) {
+                       g_clear_object (&info);
                        continue;
+               }
 
-               if (!(info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
-                       camel_message_info_unref (info);
+               if (!camel_message_info_get_folder_flagged (info)) {
+                       g_clear_object (&info);
                        continue;
                }
 
-               flags = info->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
-               sflags = info->server_flags & CAMEL_IMAPX_SERVER_FLAGS;
+               camel_message_info_property_lock (info);
+
+               g_hash_table_insert (stamps, (gpointer) camel_message_info_pooldup_uid (info),
+                       GUINT_TO_POINTER (camel_message_info_get_folder_flagged_stamp (info)));
+
+               flags = camel_message_info_get_flags (info) & CAMEL_IMAPX_SERVER_FLAGS;
+               sflags = camel_imapx_message_info_get_server_flags (xinfo) & CAMEL_IMAPX_SERVER_FLAGS;
 
                if (can_influence_flags) {
                        gboolean move_to_real_junk;
@@ -5363,63 +5337,76 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                        on_orset |= (flags ^ sflags) & flags;
                }
 
-               uflags = info->info.user_flags;
-               suflags = info->server_user_flags;
-               while (uflags || suflags) {
-                       gint res;
-
-                       if (uflags) {
-                               if (suflags)
-                                       res = strcmp (uflags->name, suflags->name);
-                               else if (*uflags->name)
-                                       res = -1;
-                               else {
-                                       uflags = uflags->next;
-                                       continue;
-                               }
-                       } else {
-                               res = 1;
-                       }
+               local_uflags = camel_message_info_get_user_flags (info);
+               server_uflags = camel_imapx_message_info_get_server_user_flags (xinfo);
 
-                       if (res == 0) {
-                               uflags = uflags->next;
-                               suflags = suflags->next;
-                       } else {
-                               GArray *user_set;
-                               CamelFlag *user_flag;
-                               struct _imapx_flag_change *change = NULL, add = { 0 };
-
-                               if (res < 0) {
-                                       if (on_user == NULL)
-                                               on_user = g_array_new (FALSE, FALSE, sizeof (struct 
_imapx_flag_change));
-                                       user_set = on_user;
-                                       user_flag = uflags;
-                                       uflags = uflags->next;
+               if (!camel_named_flags_equal (local_uflags, server_uflags)) {
+                       guint ii, jj, llen, slen;
+
+                       llen = local_uflags ? camel_named_flags_get_length (local_uflags) : 0;
+                       slen = server_uflags ? camel_named_flags_get_length (server_uflags) : 0;
+                       for (ii = 0, jj = 0; ii < llen || jj < slen;) {
+                               gint res;
+
+                               if (ii < llen) {
+                                       const gchar *local_name = camel_named_flags_get (local_uflags, ii);
+
+                                       if (jj < slen) {
+                                               const gchar *server_name = camel_named_flags_get 
(server_uflags, jj);
+
+                                               res = g_strcmp0 (local_name, server_name);
+                                       } else if (local_name && *local_name)
+                                               res = -1;
+                                       else {
+                                               ii++;
+                                               continue;
+                                       }
                                } else {
-                                       if (off_user == NULL)
-                                               off_user = g_array_new (FALSE, FALSE, sizeof (struct 
_imapx_flag_change));
-                                       user_set = off_user;
-                                       user_flag = suflags;
-                                       suflags = suflags->next;
+                                       res = 1;
                                }
 
-                               /* Could sort this and binary search */
-                               for (j = 0; j < user_set->len; j++) {
-                                       change = &g_array_index (user_set, struct _imapx_flag_change, j);
-                                       if (strcmp (change->name, user_flag->name) == 0)
-                                               goto found;
+                               if (res == 0) {
+                                       ii++;
+                                       jj++;
+                               } else {
+                                       GArray *user_set;
+                                       const gchar *user_flag_name;
+                                       struct _imapx_flag_change *change = NULL, add = { 0 };
+
+                                       if (res < 0) {
+                                               if (on_user == NULL)
+                                                       on_user = g_array_new (FALSE, FALSE, sizeof (struct 
_imapx_flag_change));
+                                               user_set = on_user;
+                                               user_flag_name = camel_named_flags_get (local_uflags, ii);
+                                               ii++;
+                                       } else {
+                                               if (off_user == NULL)
+                                                       off_user = g_array_new (FALSE, FALSE, sizeof (struct 
_imapx_flag_change));
+                                               user_set = off_user;
+                                               user_flag_name = camel_named_flags_get (server_uflags, jj);
+                                               jj++;
+                                       }
+
+                                       /* Could sort this and binary search */
+                                       for (j = 0; j < user_set->len; j++) {
+                                               change = &g_array_index (user_set, struct _imapx_flag_change, 
j);
+                                               if (g_strcmp0 (change->name, user_flag_name) == 0)
+                                                       goto found;
+                                       }
+                                       add.name = g_strdup (user_flag_name);
+                                       add.infos = g_ptr_array_new ();
+                                       g_array_append_val (user_set, add);
+                                       change = &add;
+                               found:
+                                       g_object_ref (info);
+                                       g_ptr_array_add (change->infos, info);
                                }
-                               add.name = g_strdup (user_flag->name);
-                               add.infos = g_ptr_array_new ();
-                               g_array_append_val (user_set, add);
-                               change = &add;
-                       found:
-                               camel_message_info_ref (info);
-                               g_ptr_array_add (change->infos, info);
                        }
                }
 
-               camel_message_info_unref (info);
+               camel_message_info_property_unlock (info);
+
+               g_clear_object (&info);
        }
 
        nothing_to_do =
@@ -5429,24 +5416,20 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                (off_user == NULL);
 
        if (nothing_to_do) {
-               g_signal_handler_disconnect (folder->summary, changed_meanwhile_handler_id);
-
                imapx_sync_free_user (on_user);
                imapx_sync_free_user (off_user);
-               imapx_unset_folder_flagged_flag (folder->summary, changed_uids, remove_deleted_flags);
+               imapx_unset_folder_flagged_flag (camel_folder_get_folder_summary (folder), changed_uids, 
remove_deleted_flags);
                camel_folder_free_uids (folder, changed_uids);
-               g_hash_table_destroy (changed_meanwhile);
+               g_hash_table_destroy (stamps);
                g_object_unref (folder);
                return TRUE;
        }
 
        if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error)) {
-               g_signal_handler_disconnect (folder->summary, changed_meanwhile_handler_id);
-
                imapx_sync_free_user (on_user);
                imapx_sync_free_user (off_user);
                camel_folder_free_uids (folder, changed_uids);
-               g_hash_table_destroy (changed_meanwhile);
+               g_hash_table_destroy (stamps);
                g_object_unref (folder);
                return FALSE;
        }
@@ -5468,22 +5451,23 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                        c (is->priv->tagprefix, "checking/storing %s flags '%s'\n", on ? "on" : "off", 
flags_table[jj].name);
                        imapx_uidset_init (&uidset, 0, 100);
                        for (i = 0; i < changed_uids->len && success; i++) {
-                               CamelIMAPXMessageInfo *info;
+                               CamelMessageInfo *info;
+                               CamelIMAPXMessageInfo *xinfo;
                                gboolean remove_deleted_flag;
                                guint32 flags;
                                guint32 sflags;
                                gint send;
 
-                               info = (CamelIMAPXMessageInfo *)
-                                       camel_folder_summary_get (
-                                               folder->summary,
-                                               changed_uids->pdata[i]);
+                               info = camel_folder_summary_get (camel_folder_get_folder_summary (folder), 
changed_uids->pdata[i]);
+                               xinfo = info ? CAMEL_IMAPX_MESSAGE_INFO (info) : NULL;
 
-                               if (info == NULL)
+                               if (!info || !xinfo) {
+                                       g_clear_object (&info);
                                        continue;
+                               }
 
-                               flags = (info->info.flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
-                               sflags = (info->server_flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
+                               flags = (camel_message_info_get_flags (info) & CAMEL_IMAPX_SERVER_FLAGS) & 
permanentflags;
+                               sflags = (camel_imapx_message_info_get_server_flags (xinfo) & 
CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
                                send = 0;
 
                                remove_deleted_flag =
@@ -5527,10 +5511,11 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                                /* The second round and the server doesn't support saving user flags,
                                   thus store them at least locally */
                                if (on && (permanentflags & CAMEL_MESSAGE_USER) == 0) {
-                                       camel_flag_list_copy (&info->server_user_flags, 
&info->info.user_flags);
+                                       camel_imapx_message_info_take_server_user_flags (xinfo,
+                                               camel_message_info_dup_user_flags (info));
                                }
 
-                               camel_message_info_unref (info);
+                               g_clear_object (&info);
                        }
 
                        g_warn_if_fail (ic == NULL);
@@ -5544,7 +5529,7 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
 
                                imapx_uidset_init (&uidset, 0, 100);
                                for (i = 0; i < c->infos->len; i++) {
-                                       CamelIMAPXMessageInfo *info = c->infos->pdata[i];
+                                       CamelMessageInfo *info = c->infos->pdata[i];
 
                                        if (ic == NULL)
                                                ic = camel_imapx_command_new (is, 
CAMEL_IMAPX_JOB_SYNC_CHANGES, "UID STORE ");
@@ -5572,45 +5557,64 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                }
        }
 
-       g_signal_handler_disconnect (folder->summary, changed_meanwhile_handler_id);
-
        if (success) {
+               CamelFolderSummary *folder_summary;
                CamelStore *parent_store;
                guint32 unseen;
 
                parent_store = camel_folder_get_parent_store (folder);
+               folder_summary = camel_folder_get_folder_summary (folder);
 
-               camel_folder_summary_lock (folder->summary);
+               camel_folder_summary_lock (folder_summary);
 
                for (i = 0; i < changed_uids->len; i++) {
-                       CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get 
(folder->summary,
-                                       changed_uids->pdata[i]);
+                       CamelMessageInfo *info;
+                       CamelIMAPXMessageInfo *xinfo;
+                       gboolean set_folder_flagged;
+                       guint32 has_flags, set_server_flags;
+                       gboolean changed_meanwhile;
+
+                       info = camel_folder_summary_get (folder_summary, changed_uids->pdata[i]);
+                       xinfo = info ? CAMEL_IMAPX_MESSAGE_INFO (info) : NULL;
 
-                       if (!xinfo)
+                       if (!info || !xinfo) {
+                               g_clear_object (&info);
                                continue;
+                       }
+
+                       camel_message_info_property_lock (info);
+
+                       changed_meanwhile = camel_message_info_get_folder_flagged_stamp (info) !=
+                               GPOINTER_TO_UINT (g_hash_table_lookup (stamps, changed_uids->pdata[i]));
 
-                       xinfo->server_flags = xinfo->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
+                       has_flags = camel_message_info_get_flags (info);
+                       set_server_flags = has_flags & CAMEL_IMAPX_SERVER_FLAGS;
                        if (!remove_deleted_flags ||
-                           !(xinfo->info.flags & CAMEL_MESSAGE_DELETED)) {
-                               xinfo->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+                           !(has_flags & CAMEL_MESSAGE_DELETED)) {
+                               set_folder_flagged = FALSE;
                        } else {
                                /* to stare back the \Deleted flag */
-                               xinfo->server_flags &= ~CAMEL_MESSAGE_DELETED;
-                               xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+                               set_server_flags &= ~CAMEL_MESSAGE_DELETED;
+                               set_folder_flagged = TRUE;
                        }
-                       xinfo->info.dirty = TRUE;
+
                        if ((permanentflags & CAMEL_MESSAGE_USER) != 0 ||
-                           camel_flag_list_size (&xinfo->server_user_flags) == 0)
-                               camel_flag_list_copy (&xinfo->server_user_flags, &xinfo->info.user_flags);
+                           !camel_named_flags_get_length (camel_imapx_message_info_get_server_user_flags 
(xinfo))) {
+                               camel_imapx_message_info_take_server_user_flags (xinfo, 
camel_message_info_dup_user_flags (info));
+                       }
+
+                       if (changed_meanwhile)
+                               set_folder_flagged = TRUE;
 
-                       if (g_hash_table_lookup (changed_meanwhile, changed_uids->pdata[i]))
-                               xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+                       camel_imapx_message_info_set_server_flags (xinfo, set_server_flags);
+                       camel_message_info_set_folder_flagged (info, set_folder_flagged);
 
-                       camel_folder_summary_touch (folder->summary);
-                       camel_message_info_unref (xinfo);
+                       camel_message_info_property_unlock (info);
+                       camel_folder_summary_touch (folder_summary);
+                       g_clear_object (&info);
                }
 
-               camel_folder_summary_unlock (folder->summary);
+               camel_folder_summary_unlock (folder_summary);
 
                /* Apply the changes to server-side unread count; it won't tell
                 * us of these changes, of course. */
@@ -5618,16 +5622,16 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                unseen += unread_change;
                camel_imapx_mailbox_set_unseen (mailbox, unseen);
 
-               if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
+               if ((camel_folder_summary_get_flags (folder_summary) & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
                        CamelStoreInfo *si;
 
                        /* ... and store's summary when folder's summary is dirty */
                        si = camel_store_summary_path (CAMEL_IMAPX_STORE (parent_store)->summary, 
camel_folder_get_full_name (folder));
                        if (si) {
-                               if (si->total != camel_folder_summary_get_saved_count (folder->summary) ||
-                                   si->unread != camel_folder_summary_get_unread_count (folder->summary)) {
-                                       si->total = camel_folder_summary_get_saved_count (folder->summary);
-                                       si->unread = camel_folder_summary_get_unread_count (folder->summary);
+                               if (si->total != camel_folder_summary_get_saved_count (folder_summary) ||
+                                   si->unread != camel_folder_summary_get_unread_count (folder_summary)) {
+                                       si->total = camel_folder_summary_get_saved_count (folder_summary);
+                                       si->unread = camel_folder_summary_get_unread_count (folder_summary);
                                        camel_store_summary_touch (CAMEL_IMAPX_STORE (parent_store)->summary);
                                }
 
@@ -5635,14 +5639,14 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                        }
                }
 
-               camel_folder_summary_save_to_db (folder->summary, NULL);
+               camel_folder_summary_save (folder_summary, NULL);
                camel_store_summary_save (CAMEL_IMAPX_STORE (parent_store)->summary);
        }
 
        imapx_sync_free_user (on_user);
        imapx_sync_free_user (off_user);
        camel_folder_free_uids (folder, changed_uids);
-       g_hash_table_destroy (changed_meanwhile);
+       g_hash_table_destroy (stamps);
        g_object_unref (folder);
 
        return success;
@@ -5674,15 +5678,17 @@ camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
                if (success) {
                        GPtrArray *uids;
                        CamelStore *parent_store;
+                       CamelFolderSummary *folder_summary;
                        const gchar *full_name;
 
                        full_name = camel_folder_get_full_name (folder);
                        parent_store = camel_folder_get_parent_store (folder);
+                       folder_summary = camel_folder_get_folder_summary (folder);
 
-                       camel_folder_summary_lock (folder->summary);
+                       camel_folder_summary_lock (folder_summary);
 
-                       camel_folder_summary_save_to_db (folder->summary, NULL);
-                       uids = camel_db_get_folder_deleted_uids (parent_store->cdb_r, full_name, NULL);
+                       camel_folder_summary_save (folder_summary, NULL);
+                       uids = camel_db_get_folder_deleted_uids (camel_store_get_db (parent_store), 
full_name, NULL);
 
                        if (uids && uids->len) {
                                CamelFolderChangeInfo *changes;
@@ -5695,8 +5701,8 @@ camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
                                        removed = g_list_prepend (removed, (gpointer) uids->pdata[i]);
                                }
 
-                               camel_folder_summary_remove_uids (folder->summary, removed);
-                               camel_folder_summary_save_to_db (folder->summary, NULL);
+                               camel_folder_summary_remove_uids (folder_summary, removed);
+                               camel_folder_summary_save (folder_summary, NULL);
 
                                camel_folder_changed (folder, changes);
                                camel_folder_change_info_free (changes);
@@ -5708,7 +5714,7 @@ camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
                        if (uids)
                                g_ptr_array_free (uids, TRUE);
 
-                       camel_folder_summary_unlock (folder->summary);
+                       camel_folder_summary_unlock (folder_summary);
                }
 
                camel_imapx_command_unref (ic);
diff --git a/src/camel/providers/imapx/camel-imapx-server.h b/src/camel/providers/imapx/camel-imapx-server.h
index 16d5090..c51e005 100644
--- a/src/camel/providers/imapx/camel-imapx-server.h
+++ b/src/camel/providers/imapx/camel-imapx-server.h
@@ -114,6 +114,9 @@ struct _CamelIMAPXServerClass {
        /* Signals */
        void            (*refresh_mailbox)      (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_server_get_type     (void);
diff --git a/src/camel/providers/imapx/camel-imapx-settings.h 
b/src/camel/providers/imapx/camel-imapx-settings.h
index f1e402e..4de7306 100644
--- a/src/camel/providers/imapx/camel-imapx-settings.h
+++ b/src/camel/providers/imapx/camel-imapx-settings.h
@@ -52,6 +52,9 @@ struct _CamelIMAPXSettings {
 
 struct _CamelIMAPXSettingsClass {
        CamelOfflineSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_settings_get_type   (void) G_GNUC_CONST;
diff --git a/src/camel/providers/imapx/camel-imapx-status-response.h 
b/src/camel/providers/imapx/camel-imapx-status-response.h
index 49af19a..47ce8cd 100644
--- a/src/camel/providers/imapx/camel-imapx-status-response.h
+++ b/src/camel/providers/imapx/camel-imapx-status-response.h
@@ -62,6 +62,9 @@ struct _CamelIMAPXStatusResponse {
 
 struct _CamelIMAPXStatusResponseClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_status_response_get_type
diff --git a/src/camel/providers/imapx/camel-imapx-store-summary.h 
b/src/camel/providers/imapx/camel-imapx-store-summary.h
index 2d919d1..390bb74 100644
--- a/src/camel/providers/imapx/camel-imapx-store-summary.h
+++ b/src/camel/providers/imapx/camel-imapx-store-summary.h
@@ -60,6 +60,9 @@ struct _CamelIMAPXStoreSummary {
 
 struct _CamelIMAPXStoreSummaryClass {
        CamelStoreSummaryClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_store_summary_get_type
diff --git a/src/camel/providers/imapx/camel-imapx-store.c b/src/camel/providers/imapx/camel-imapx-store.c
index 96bbb84..9a8282e 100644
--- a/src/camel/providers/imapx/camel-imapx-store.c
+++ b/src/camel/providers/imapx/camel-imapx-store.c
@@ -153,23 +153,27 @@ imapx_store_update_store_flags (CamelStore *store)
        CamelService *service;
        CamelSettings *settings;
        CamelIMAPXSettings *imapx_settings;
+       guint32 store_flags;
 
        service = CAMEL_SERVICE (store);
        settings = camel_service_ref_settings (service);
        imapx_settings = CAMEL_IMAPX_SETTINGS (settings);
+       store_flags = camel_store_get_flags (store);
 
        if (camel_imapx_settings_get_use_real_junk_path (imapx_settings)) {
-               store->flags &= ~CAMEL_STORE_VJUNK;
-               store->flags |= CAMEL_STORE_REAL_JUNK_FOLDER;
+               store_flags &= ~CAMEL_STORE_VJUNK;
+               store_flags |= CAMEL_STORE_REAL_JUNK_FOLDER;
        } else {
-               store->flags |= CAMEL_STORE_VJUNK;
-               store->flags &= ~CAMEL_STORE_REAL_JUNK_FOLDER;
+               store_flags |= CAMEL_STORE_VJUNK;
+               store_flags &= ~CAMEL_STORE_REAL_JUNK_FOLDER;
        }
 
        if (camel_imapx_settings_get_use_real_trash_path (imapx_settings))
-               store->flags &= ~CAMEL_STORE_VTRASH;
+               store_flags &= ~CAMEL_STORE_VTRASH;
        else
-               store->flags |= CAMEL_STORE_VTRASH;
+               store_flags |= CAMEL_STORE_VTRASH;
+
+       camel_store_set_flags (store, store_flags);
 
        g_object_unref (settings);
 }
@@ -226,7 +230,7 @@ imapx_store_build_folder_info (CamelIMAPXStore *imapx_store,
                fi->display_name = g_strdup (name);
        }
 
-       if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
+       if ((camel_store_get_flags (store) & CAMEL_STORE_VTRASH) == 0) {
                const gchar *trash_path;
 
                trash_path = camel_imapx_settings_get_real_trash_path (
@@ -235,7 +239,7 @@ imapx_store_build_folder_info (CamelIMAPXStore *imapx_store,
                        fi->flags |= CAMEL_FOLDER_TYPE_TRASH;
        }
 
-       if ((store->flags & CAMEL_STORE_REAL_JUNK_FOLDER) != 0) {
+       if ((camel_store_get_flags (store) & CAMEL_STORE_REAL_JUNK_FOLDER) != 0) {
                const gchar *junk_path;
 
                junk_path = camel_imapx_settings_get_real_junk_path (
@@ -351,8 +355,7 @@ imapx_store_add_mailbox_to_folder (CamelIMAPXStore *store,
 
        folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
 
-       folder = camel_object_bag_get (
-               CAMEL_STORE (store)->folders, folder_path);
+       folder = camel_object_bag_get (camel_store_get_folders_bag (CAMEL_STORE (store)), folder_path);
 
        if (folder != NULL) {
                camel_imapx_folder_set_mailbox (folder, mailbox);
@@ -557,14 +560,14 @@ imapx_store_process_mailbox_status (CamelIMAPXStore *imapx_store,
        store = CAMEL_STORE (imapx_store);
 
        /* Update only already opened folders */
-       folder = camel_object_bag_reserve (store->folders, folder_path);
+       folder = camel_object_bag_reserve (camel_store_get_folders_bag (store), folder_path);
        if (folder != NULL) {
                CamelIMAPXFolder *imapx_folder;
                CamelIMAPXSummary *imapx_summary;
                guint32 uidvalidity;
 
                imapx_folder = CAMEL_IMAPX_FOLDER (folder);
-               imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
+               imapx_summary = CAMEL_IMAPX_SUMMARY (camel_folder_get_folder_summary (folder));
 
                uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
 
@@ -574,7 +577,7 @@ imapx_store_process_mailbox_status (CamelIMAPXStore *imapx_store,
 
                g_object_unref (folder);
        } else {
-               camel_object_bag_abort (store->folders, folder_path);
+               camel_object_bag_abort (camel_store_get_folders_bag (store), folder_path);
        }
 
        g_free (folder_path);
@@ -945,14 +948,14 @@ fill_fi (CamelStore *store,
 {
        CamelFolder *folder;
 
-       folder = camel_object_bag_peek (store->folders, fi->full_name);
+       folder = camel_object_bag_peek (camel_store_get_folders_bag (store), fi->full_name);
        if (folder) {
                CamelIMAPXFolder *imapx_folder;
                CamelIMAPXSummary *ims;
                CamelIMAPXMailbox *mailbox;
 
-               if (folder->summary)
-                       ims = (CamelIMAPXSummary *) folder->summary;
+               if (camel_folder_get_folder_summary (folder))
+                       ims = CAMEL_IMAPX_SUMMARY (camel_folder_get_folder_summary (folder));
                else
                        ims = (CamelIMAPXSummary *) camel_imapx_summary_new (folder);
 
@@ -964,7 +967,7 @@ fill_fi (CamelStore *store,
 
                g_clear_object (&mailbox);
 
-               if (!folder->summary)
+               if (!camel_folder_get_folder_summary (folder))
                        g_object_unref (ims);
                g_object_unref (folder);
        }
@@ -997,8 +1000,7 @@ imapx_delete_folder_from_cache (CamelIMAPXStore *imapx_store,
        g_unlink (state_file);
        g_free (state_file);
 
-       camel_db_delete_folder (
-               CAMEL_STORE (imapx_store)->cdb_w, folder_path, NULL);
+       camel_db_delete_folder (camel_store_get_db (CAMEL_STORE (imapx_store)), folder_path, NULL);
        g_rmdir (folder_dir);
 
        state_file = g_build_filename (folder_dir, "subfolders", NULL);
@@ -1046,8 +1048,8 @@ get_folder_info_offline (CamelStore *store,
                        return NULL;
 
                fi = imapx_store_build_folder_info (imapx_store, top, 0);
-               fi->unread = camel_folder_summary_get_unread_count (vfolder->summary);
-               fi->total = camel_folder_summary_get_saved_count (vfolder->summary);
+               fi->unread = camel_folder_summary_get_unread_count (camel_folder_get_folder_summary 
(vfolder));
+               fi->total = camel_folder_summary_get_saved_count (camel_folder_get_folder_summary (vfolder));
 
                if (g_strcmp0 (top, CAMEL_VTRASH_NAME) == 0)
                        fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) |
@@ -1790,7 +1792,7 @@ imapx_store_get_folder_sync (CamelStore *store,
                        real_junk_path = g_strdup ("");
 
                if (g_ascii_strcasecmp (real_junk_path, folder_name) == 0)
-                       folder->folder_flags |= CAMEL_FOLDER_IS_JUNK;
+                       camel_folder_set_flags (folder, camel_folder_get_flags (folder) | 
CAMEL_FOLDER_IS_JUNK);
 
                g_free (real_junk_path);
        }
@@ -1807,7 +1809,7 @@ imapx_store_get_folder_sync (CamelStore *store,
                        real_trash_path = g_strdup ("");
 
                if (g_ascii_strcasecmp (real_trash_path, folder_name) == 0)
-                       folder->folder_flags |= CAMEL_FOLDER_IS_TRASH;
+                       camel_folder_set_flags (folder, camel_folder_get_flags (folder) | 
CAMEL_FOLDER_IS_TRASH);
 
                g_free (real_trash_path);
        }
@@ -2603,7 +2605,7 @@ imapx_store_initable_init (GInitable *initable,
        store = CAMEL_STORE (initable);
        service = CAMEL_SERVICE (initable);
 
-       store->flags |= CAMEL_STORE_USE_CACHE_DIR | CAMEL_STORE_SUPPORTS_INITIAL_SETUP;
+       camel_store_set_flags (store, camel_store_get_flags (store) | CAMEL_STORE_USE_CACHE_DIR | 
CAMEL_STORE_SUPPORTS_INITIAL_SETUP);
        imapx_migrate_to_user_cache_dir (service);
 
        /* Chain up to parent interface's init() method. */
diff --git a/src/camel/providers/imapx/camel-imapx-store.h b/src/camel/providers/imapx/camel-imapx-store.h
index e25eccd..c9f5d2f 100644
--- a/src/camel/providers/imapx/camel-imapx-store.h
+++ b/src/camel/providers/imapx/camel-imapx-store.h
@@ -72,6 +72,9 @@ struct _CamelIMAPXStoreClass {
                                                 const gchar *oldname);
        void            (*mailbox_updated)      (CamelIMAPXStore *imapx_store,
                                                 CamelIMAPXMailbox *mailbox);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_store_get_type      (void);
diff --git a/src/camel/providers/imapx/camel-imapx-summary.c b/src/camel/providers/imapx/camel-imapx-summary.c
index 6e3a2d2..b1af6bf 100644
--- a/src/camel/providers/imapx/camel-imapx-summary.c
+++ b/src/camel/providers/imapx/camel-imapx-summary.c
@@ -28,16 +28,13 @@
 
 #include <camel/camel.h>
 
+#include "camel-imapx-message-info.h"
 #include "camel-imapx-summary.h"
 
-#define CAMEL_IMAPX_SUMMARY_VERSION (4)
-
-enum {
-       INFO_CHANGED,
-       LAST_SIGNAL
-};
+/* Don't do DB sort. Its pretty slow to load */
+/* #define SORT_DB 1 */
 
-static guint signals[LAST_SIGNAL];
+#define CAMEL_IMAPX_SUMMARY_VERSION (4)
 
 G_DEFINE_TYPE (
        CamelIMAPXSummary,
@@ -45,15 +42,13 @@ G_DEFINE_TYPE (
        CAMEL_TYPE_FOLDER_SUMMARY)
 
 static gboolean
-imapx_summary_summary_header_from_db (CamelFolderSummary *s,
-                                      CamelFIRecord *mir)
+imapx_summary_summary_header_load (CamelFolderSummary *s,
+                                  CamelFIRecord *mir)
 {
        gboolean success;
 
-       /* Chain up to parent's summary_header_from_db() method. */
-       success = CAMEL_FOLDER_SUMMARY_CLASS (
-               camel_imapx_summary_parent_class)->
-               summary_header_from_db (s, mir);
+       /* Chain up to parent's summary_header_load() method. */
+       success = CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->summary_header_load (s, mir);
 
        if (success) {
                CamelIMAPXSummary *ims;
@@ -61,12 +56,12 @@ imapx_summary_summary_header_from_db (CamelFolderSummary *s,
 
                ims = CAMEL_IMAPX_SUMMARY (s);
 
-               ims->version = bdata_extract_digit (&part);
-               ims->validity = bdata_extract_digit (&part);
+               ims->version = camel_util_bdata_get_number (&part, 0);
+               ims->validity = camel_util_bdata_get_number (&part, 0);
 
                if (ims->version >= 4) {
-                       ims->uidnext = bdata_extract_digit (&part);
-                       ims->modseq = bdata_extract_digit (&part);
+                       ims->uidnext = camel_util_bdata_get_number (&part, 0);
+                       ims->modseq = camel_util_bdata_get_number (&part, 0);
                }
 
                if (ims->version > CAMEL_IMAPX_SUMMARY_VERSION) {
@@ -80,15 +75,13 @@ imapx_summary_summary_header_from_db (CamelFolderSummary *s,
 }
 
 static CamelFIRecord *
-imapx_summary_summary_header_to_db (CamelFolderSummary *s,
-                                    GError **error)
+imapx_summary_summary_header_save (CamelFolderSummary *s,
+                                  GError **error)
 {
        struct _CamelFIRecord *fir;
 
-       /* Chain up to parent's summary_header_to_db() method. */
-       fir = CAMEL_FOLDER_SUMMARY_CLASS (
-               camel_imapx_summary_parent_class)->
-               summary_header_to_db (s, error);
+       /* Chain up to parent's summary_header_save() method. */
+       fir = CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->summary_header_save (s, error);
 
        if (fir != NULL) {
                CamelIMAPXSummary *ims;
@@ -109,236 +102,19 @@ imapx_summary_summary_header_to_db (CamelFolderSummary *s,
        return fir;
 }
 
-static CamelMessageInfo *
-imapx_summary_message_info_from_db (CamelFolderSummary *s,
-                                    CamelMIRecord *mir)
-{
-       CamelMessageInfo *info;
-
-       /* Chain up parent's message_info_from_db() method. */
-       info = CAMEL_FOLDER_SUMMARY_CLASS (
-               camel_imapx_summary_parent_class)->
-               message_info_from_db (s, mir);
-
-       if (info != NULL) {
-               CamelIMAPXMessageInfo *imapx_info;
-               gchar *part = mir->bdata;
-
-               imapx_info = (CamelIMAPXMessageInfo *) info;
-               imapx_info->server_flags = bdata_extract_digit (&part);
-       }
-
-       return info;
-}
-
-static CamelMIRecord *
-imapx_summary_message_info_to_db (CamelFolderSummary *s,
-                                  CamelMessageInfo *info)
-{
-       struct _CamelMIRecord *mir;
-
-       /* Chain up to parent's message_info_to_db() method. */
-       mir = CAMEL_FOLDER_SUMMARY_CLASS (
-               camel_imapx_summary_parent_class)->
-               message_info_to_db (s, info);
-
-       if (mir != NULL) {
-               CamelIMAPXMessageInfo *imapx_info;
-
-               imapx_info = (CamelIMAPXMessageInfo *) info;
-               mir->bdata = g_strdup_printf ("%u", imapx_info->server_flags);
-       }
-
-       return mir;
-}
-
-static CamelMessageContentInfo *
-imapx_summary_content_info_from_db (CamelFolderSummary *summary,
-                                    CamelMIRecord *mir)
-{
-       gchar *part = mir->cinfo;
-       guint32 type = 0;
-
-       if (part != NULL) {
-               if (*part == ' ')
-                       part++;
-               if (part != NULL)
-                       type = bdata_extract_digit (&part);
-       }
-       mir->cinfo = part;
-
-       if (type) {
-               /* Chain up to parent's content_info_from_db() method. */
-               return CAMEL_FOLDER_SUMMARY_CLASS (
-                       camel_imapx_summary_parent_class)->
-                       content_info_from_db (summary, mir);
-       } else {
-               return camel_folder_summary_content_info_new (summary);
-       }
-}
-
-static gboolean
-imapx_summary_content_info_to_db (CamelFolderSummary *summary,
-                                  CamelMessageContentInfo *info,
-                                  CamelMIRecord *mir)
-{
-       gchar *oldr;
-
-       if (info->type) {
-               oldr = mir->cinfo;
-               if (oldr != NULL)
-                       mir->cinfo = g_strdup_printf ("%s 1", oldr);
-               else
-                       mir->cinfo = g_strdup ("1");
-               g_free (oldr);
-
-               /* Chain up to parent's content_info_to_db() method. */
-               return CAMEL_FOLDER_SUMMARY_CLASS (
-                       camel_imapx_summary_parent_class)->
-                       content_info_to_db (summary, info, mir);
-
-       } else {
-               oldr = mir->cinfo;
-               if (oldr != NULL)
-                       mir->cinfo = g_strdup_printf ("%s 0", oldr);
-               else
-                       mir->cinfo = g_strdup ("0");
-               g_free (oldr);
-
-               return TRUE;
-       }
-}
-
-static void
-imapx_summary_message_info_free (CamelFolderSummary *summary,
-                                 CamelMessageInfo *info)
-{
-       CamelIMAPXMessageInfo *imapx_info;
-
-       imapx_info = (CamelIMAPXMessageInfo *) info;
-       camel_flag_list_free (&imapx_info->server_user_flags);
-
-       /* Chain up to parent's message_info_free() method. */
-       CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->
-               message_info_free (summary, info);
-}
-
-static CamelMessageInfo *
-imapx_summary_message_info_clone (CamelFolderSummary *summary,
-                                  const CamelMessageInfo *info)
-{
-       CamelMessageInfo *copy;
-       CamelIMAPXMessageInfo *imapx_copy;
-       CamelIMAPXMessageInfo *imapx_info;
-
-       /* Chain up to parent's message_info_clone() method. */
-       copy = CAMEL_FOLDER_SUMMARY_CLASS (
-               camel_imapx_summary_parent_class)->
-               message_info_clone (summary, info);
-
-       imapx_info = (CamelIMAPXMessageInfo *) info;
-       imapx_copy = (CamelIMAPXMessageInfo *) copy;
-
-       if (imapx_info->server_user_flags) {
-               camel_flag_list_copy (
-                       &imapx_copy->server_user_flags,
-                       &imapx_info->server_user_flags);
-       }
-
-       imapx_copy->server_flags = imapx_info->server_flags;
-
-       /* FIXME: parent clone should do this */
-       imapx_copy->info.content =
-               camel_folder_summary_content_info_new (summary);
-
-       return copy;
-}
-
-static void
-imapx_summary_emit_info_changed (CamelMessageInfo *info)
-{
-       g_return_if_fail (info != NULL);
-       g_return_if_fail (CAMEL_IS_IMAPX_SUMMARY (info->summary));
-
-       g_signal_emit (info->summary, signals[INFO_CHANGED], 0, info);
-}
-
-static gboolean
-imapx_summary_info_set_user_flag (CamelMessageInfo *info,
-                                  const gchar *id,
-                                  gboolean state)
-{
-       gboolean changed;
-
-       /* Chain up to parent's method. */
-       changed = CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->info_set_user_flag (info, 
id, state);
-
-       if (changed)
-               imapx_summary_emit_info_changed (info);
-
-       return changed;
-}
-
-static gboolean
-imapx_summary_info_set_user_tag (CamelMessageInfo *info,
-                                const gchar *name,
-                                const gchar *value)
-{
-       gboolean changed;
-
-       /* Chain up to parent's method. */
-       changed = CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->info_set_user_tag (info, 
name, value);
-
-       if (changed)
-               imapx_summary_emit_info_changed (info);
-
-       return changed;
-}
-
-static gboolean
-imapx_summary_info_set_flags (CamelMessageInfo *info,
-                             guint32 flags,
-                             guint32 set)
-{
-       gboolean changed;
-
-       /* Chain up to parent's method. */
-       changed = CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->info_set_flags (info, flags, 
set);
-
-       if (changed)
-               imapx_summary_emit_info_changed (info);
-
-       return changed;
-}
-
 static void
 camel_imapx_summary_class_init (CamelIMAPXSummaryClass *class)
 {
        CamelFolderSummaryClass *folder_summary_class;
 
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
-       folder_summary_class->message_info_size = sizeof (CamelIMAPXMessageInfo);
-       folder_summary_class->content_info_size = sizeof (CamelIMAPXMessageContentInfo);
-       folder_summary_class->summary_header_from_db = imapx_summary_summary_header_from_db;
-       folder_summary_class->summary_header_to_db = imapx_summary_summary_header_to_db;
-       folder_summary_class->message_info_from_db = imapx_summary_message_info_from_db;
-       folder_summary_class->message_info_to_db = imapx_summary_message_info_to_db;
-       folder_summary_class->content_info_from_db = imapx_summary_content_info_from_db;
-       folder_summary_class->content_info_to_db = imapx_summary_content_info_to_db;
-       folder_summary_class->message_info_free = imapx_summary_message_info_free;
-       folder_summary_class->message_info_clone = imapx_summary_message_info_clone;
-       folder_summary_class->info_set_user_flag = imapx_summary_info_set_user_flag;
-       folder_summary_class->info_set_user_tag = imapx_summary_info_set_user_tag;
-       folder_summary_class->info_set_flags = imapx_summary_info_set_flags;
-
-       signals[INFO_CHANGED] = g_signal_new (
-               "info-changed",
-               G_OBJECT_CLASS_TYPE (class),
-               G_SIGNAL_RUN_LAST,
-               0 /* G_STRUCT_OFFSET (CamelIMAPXSummaryClass, info_changed) */,
-               NULL, NULL, NULL,
-               G_TYPE_NONE, 1,
-               G_TYPE_POINTER /* CamelMessageInfo * */);
+       folder_summary_class->message_info_type = CAMEL_TYPE_IMAPX_MESSAGE_INFO;
+#ifdef SORT_DB
+       folder_summary_class->sort_by = "uid";
+       folder_summary_class->collate = "imapx_uid_sort";
+#endif
+       folder_summary_class->summary_header_load = imapx_summary_summary_header_load;
+       folder_summary_class->summary_header_save = imapx_summary_summary_header_save;
 }
 
 static void
@@ -346,6 +122,7 @@ camel_imapx_summary_init (CamelIMAPXSummary *obj)
 {
 }
 
+#ifdef SORT_DB
 static gint
 sort_uid_cmp (gpointer enc,
               gint len1,
@@ -373,6 +150,7 @@ sort_uid_cmp (gpointer enc,
 
        return (a1 < a2) ? -1 : (a1 > a2) ? 1 : 0;
 }
+#endif
 
 /**
  * camel_imapx_summary_new:
@@ -386,24 +164,20 @@ sort_uid_cmp (gpointer enc,
 CamelFolderSummary *
 camel_imapx_summary_new (CamelFolder *folder)
 {
+#ifdef SORT_DB
        CamelStore *parent_store;
+#endif
        CamelFolderSummary *summary;
        GError *local_error = NULL;
 
-       parent_store = camel_folder_get_parent_store (folder);
-
        summary = g_object_new (CAMEL_TYPE_IMAPX_SUMMARY, "folder", folder, NULL);
 
-       /* Don't do DB sort. Its pretty slow to load */
-       if (folder && 0) {
-               camel_db_set_collate (parent_store->cdb_r, "uid", "imapx_uid_sort", (CamelDBCollate) 
sort_uid_cmp);
-               summary->sort_by = "uid";
-               summary->collate = "imapx_uid_sort";
-       }
-
-       camel_folder_summary_set_build_content (summary, TRUE);
+#ifdef SORT_DB
+       parent_store = camel_folder_get_parent_store (folder);
+       camel_db_set_collate (camel_store_get_db (parent_store), "uid", "imapx_uid_sort", (CamelDBCollate) 
sort_uid_cmp);
+#endif
 
-       if (!camel_folder_summary_load_from_db (summary, &local_error)) {
+       if (!camel_folder_summary_load (summary, &local_error)) {
                /* FIXME: Isn't this dangerous ? We clear the summary
                if it cannot be loaded, for some random reason.
                We need to pass the error and find out why it is not loaded etc. ? */
@@ -414,4 +188,3 @@ camel_imapx_summary_new (CamelFolder *folder)
 
        return summary;
 }
-
diff --git a/src/camel/providers/imapx/camel-imapx-summary.h b/src/camel/providers/imapx/camel-imapx-summary.h
index c515c19..3f4d989 100644
--- a/src/camel/providers/imapx/camel-imapx-summary.h
+++ b/src/camel/providers/imapx/camel-imapx-summary.h
@@ -55,20 +55,6 @@ G_BEGIN_DECLS
 typedef struct _CamelIMAPXSummary CamelIMAPXSummary;
 typedef struct _CamelIMAPXSummaryClass CamelIMAPXSummaryClass;
 
-typedef struct _CamelIMAPXMessageInfo CamelIMAPXMessageInfo;
-typedef struct _CamelIMAPXMessageContentInfo CamelIMAPXMessageContentInfo;
-
-struct _CamelIMAPXMessageContentInfo {
-       CamelMessageContentInfo info;
-};
-
-struct _CamelIMAPXMessageInfo {
-       CamelMessageInfoBase info;
-
-       guint32 server_flags;
-       CamelFlag *server_user_flags;
-};
-
 struct _CamelIMAPXSummary {
        CamelFolderSummary parent;
 
@@ -80,6 +66,9 @@ struct _CamelIMAPXSummary {
 
 struct _CamelIMAPXSummaryClass {
        CamelFolderSummaryClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_imapx_summary_get_type    (void);
diff --git a/src/camel/providers/imapx/camel-imapx-utils.c b/src/camel/providers/imapx/camel-imapx-utils.c
index c60666d..3d981f4 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.c
+++ b/src/camel/providers/imapx/camel-imapx-utils.c
@@ -24,6 +24,7 @@
 
 #include "camel-imapx-command.h"
 #include "camel-imapx-folder.h"
+#include "camel-imapx-message-info.h"
 #include "camel-imapx-settings.h"
 #include "camel-imapx-summary.h"
 #include "camel-imapx-store.h"
@@ -101,7 +102,7 @@ static struct {
 gboolean
 imapx_parse_flags (CamelIMAPXInputStream *stream,
                    guint32 *flagsp,
-                   CamelFlag **user_flagsp,
+                   CamelNamedFlags *user_flags,
                    GCancellable *cancellable,
                    GError **error)
 {
@@ -149,7 +150,7 @@ imapx_parse_flags (CamelIMAPXInputStream *stream,
                                }
                        }
 
-                       if (!match_found && user_flagsp != NULL) {
+                       if (!match_found && user_flags) {
                                const gchar *flag_name;
                                gchar *utf8;
 
@@ -163,7 +164,7 @@ imapx_parse_flags (CamelIMAPXInputStream *stream,
                                        utf8 = NULL;
                                }
 
-                               camel_flag_set (user_flagsp, utf8 ? utf8 : flag_name, TRUE);
+                               camel_named_flags_insert (user_flags, utf8 ? utf8 : flag_name);
 
                                g_free (utf8);
                        }
@@ -225,44 +226,50 @@ rename_label_flag (const gchar *flag,
 void
 imapx_write_flags (GString *string,
                    guint32 flags,
-                   CamelFlag *user_flags)
+                   const CamelNamedFlags *user_flags)
 {
-       gint i;
+       guint ii;
        gboolean first = TRUE;
 
        g_string_append_c (string, '(');
 
-       for (i = 0; flags != 0 && i< G_N_ELEMENTS (flag_table); i++) {
-               if (flag_table[i].flag & flags) {
-                       if (flag_table[i].flag & CAMEL_IMAPX_MESSAGE_RECENT)
+       for (ii = 0; flags != 0 && ii < G_N_ELEMENTS (flag_table); ii++) {
+               if (flag_table[ii].flag & flags) {
+                       if (flag_table[ii].flag & CAMEL_IMAPX_MESSAGE_RECENT)
                                continue;
                        if (!first)
                                g_string_append_c (string, ' ');
                        first = FALSE;
-                       g_string_append (string, flag_table[i].name);
+                       g_string_append (string, flag_table[ii].name);
 
-                       flags &= ~flag_table[i].flag;
+                       flags &= ~flag_table[ii].flag;
                }
        }
 
-       while (user_flags) {
-               const gchar *flag_name;
-               gchar *utf7;
+       if (user_flags) {
+               guint len = camel_named_flags_get_length (user_flags);
+
+               for (ii = 0; ii < len; ii++) {
+                       const gchar *name = camel_named_flags_get (user_flags, ii);
+                       const gchar *flag_name;
+                       gchar *utf7;
 
-               flag_name = rename_label_flag (
-                       user_flags->name, strlen (user_flags->name), FALSE);
+                       if (!name || !*name)
+                               continue;
 
-               if (!first)
-                       g_string_append_c (string, ' ');
-               first = FALSE;
 
-               utf7 = camel_utf8_utf7 (flag_name);
+                       flag_name = rename_label_flag (name, strlen (name), FALSE);
+
+                       if (!first)
+                               g_string_append_c (string, ' ');
+                       first = FALSE;
 
-               g_string_append (string, utf7 ? utf7 : flag_name);
+                       utf7 = camel_utf8_utf7 (flag_name);
 
-               g_free (utf7);
+                       g_string_append (string, utf7 ? utf7 : flag_name);
 
-               user_flags = user_flags->next;
+                       g_free (utf7);
+               }
        }
 
        g_string_append_c (string, ')');
@@ -270,26 +277,38 @@ imapx_write_flags (GString *string,
 
 static gboolean
 imapx_update_user_flags (CamelMessageInfo *info,
-                         CamelFlag *server_user_flags)
+                        const CamelNamedFlags *server_user_flags)
 {
        gboolean changed = FALSE;
-       CamelMessageInfoBase *binfo = (CamelMessageInfoBase *) info;
-       CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) info;
+       const CamelNamedFlags *mi_user_flags;
        gboolean set_cal = FALSE, set_note = FALSE;
 
-       if (camel_flag_get (&binfo->user_flags, "$has_cal"))
+       mi_user_flags = camel_message_info_get_user_flags (info);
+       if (camel_named_flags_equal (mi_user_flags, server_user_flags)) {
+               mi_user_flags = camel_imapx_message_info_get_server_user_flags (CAMEL_IMAPX_MESSAGE_INFO 
(info));
+
+               if (!camel_named_flags_equal (mi_user_flags, server_user_flags)) {
+                       camel_imapx_message_info_take_server_user_flags (CAMEL_IMAPX_MESSAGE_INFO (info),
+                               camel_named_flags_copy (server_user_flags));
+               }
+
+               return FALSE;
+       }
+
+       if (mi_user_flags && camel_named_flags_contains (mi_user_flags, "$has_cal"))
                set_cal = TRUE;
-       if (camel_flag_get (&binfo->user_flags, "$has_note"))
+       if (mi_user_flags && camel_named_flags_contains (mi_user_flags, "$has_note"))
                set_note = TRUE;
 
-       changed = camel_flag_list_copy (&binfo->user_flags, &server_user_flags);
-       camel_flag_list_copy (&xinfo->server_user_flags, &server_user_flags);
+       changed = camel_message_info_take_user_flags (info, camel_named_flags_copy (server_user_flags));
+       camel_imapx_message_info_take_server_user_flags (CAMEL_IMAPX_MESSAGE_INFO (info),
+               camel_named_flags_copy (server_user_flags));
 
        /* reset the flags as they were set in messageinfo before */
        if (set_cal)
-               camel_flag_set (&binfo->user_flags, "$has_cal", TRUE);
+               camel_message_info_set_user_flag (info, "$has_cal", TRUE);
        if (set_note)
-               camel_flag_set (&binfo->user_flags, "$has_note", TRUE);
+               camel_message_info_set_user_flag (info, "$has_note", TRUE);
 
        return changed;
 }
@@ -297,16 +316,16 @@ imapx_update_user_flags (CamelMessageInfo *info,
 gboolean
 imapx_update_message_info_flags (CamelMessageInfo *info,
                                  guint32 server_flags,
-                                 CamelFlag *server_user_flags,
+                                 const CamelNamedFlags *server_user_flags,
                                  guint32 permanent_flags,
                                  CamelFolder *folder,
                                  gboolean unsolicited)
 {
        gboolean changed = FALSE;
-       CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) info;
+       CamelIMAPXMessageInfo *xinfo = CAMEL_IMAPX_MESSAGE_INFO (info);
 
        /* Locally made changes should not be overwritten, it'll be (re)saved later */
-       if ((camel_message_info_get_flags (info) & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0) {
+       if (camel_message_info_get_folder_flagged (info)) {
                d ('?', "Skipping update of locally changed uid:'%s'\n", camel_message_info_get_uid (info));
                return FALSE;
        }
@@ -314,15 +333,21 @@ imapx_update_message_info_flags (CamelMessageInfo *info,
        /* This makes sure that server flags has precedence from locally stored flags,
         * thus a user actually sees what is stored on the server */
        if ((camel_message_info_get_flags (info) & CAMEL_IMAPX_SERVER_FLAGS) != (server_flags & 
CAMEL_IMAPX_SERVER_FLAGS)) {
-               xinfo->server_flags = (xinfo->server_flags & ~CAMEL_IMAPX_SERVER_FLAGS) |
-                                     (camel_message_info_get_flags (info) & CAMEL_IMAPX_SERVER_FLAGS);
+               guint32 old_server_flags;
+
+               old_server_flags = camel_imapx_message_info_get_server_flags (xinfo);
+
+               camel_imapx_message_info_set_server_flags (xinfo,
+                       (old_server_flags & ~CAMEL_IMAPX_SERVER_FLAGS) |
+                       (camel_message_info_get_flags (info) & CAMEL_IMAPX_SERVER_FLAGS));
        }
 
-       if (server_flags != xinfo->server_flags) {
-               guint32 server_set, server_cleared;
+       if (server_flags != camel_imapx_message_info_get_server_flags (xinfo)) {
+               guint32 server_set, server_cleared, old_server_flags;
 
-               server_set = server_flags & ~xinfo->server_flags;
-               server_cleared = xinfo->server_flags & ~server_flags;
+               old_server_flags = camel_imapx_message_info_get_server_flags (xinfo);
+               server_set = server_flags & ~old_server_flags;
+               server_cleared = old_server_flags & ~server_flags;
 
                /* Don't clear non-permanent server-side flags.
                 * This avoids overwriting local flags that we
@@ -330,13 +355,11 @@ imapx_update_message_info_flags (CamelMessageInfo *info,
                if (permanent_flags > 0)
                        server_cleared &= permanent_flags;
 
-               changed = camel_message_info_set_flags ((
-                       CamelMessageInfo *) xinfo,
+               changed = camel_message_info_set_flags (info,
                        server_set | server_cleared,
-                       (xinfo->info.flags | server_set) & ~server_cleared);
+                       (camel_message_info_get_flags (info) | server_set) & ~server_cleared);
 
-               xinfo->server_flags = server_flags;
-               xinfo->info.dirty = TRUE;
+               camel_imapx_message_info_set_server_flags (xinfo, server_flags);
        }
 
        if ((permanent_flags & CAMEL_MESSAGE_USER) != 0 && imapx_update_user_flags (info, server_user_flags))
@@ -348,29 +371,22 @@ imapx_update_message_info_flags (CamelMessageInfo *info,
 void
 imapx_set_message_info_flags_for_new_message (CamelMessageInfo *info,
                                               guint32 server_flags,
-                                              CamelFlag *server_user_flags,
+                                              const CamelNamedFlags *server_user_flags,
                                              gboolean force_user_flags,
-                                             CamelTag *user_tags,
+                                             const CamelNameValueArray *user_tags,
                                              guint32 permanent_flags)
 {
-       CamelMessageInfoBase *binfo = (CamelMessageInfoBase *) info;
-       CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) info;
-
-       binfo->flags |= server_flags;
-       camel_message_info_set_flags (info, server_flags, binfo->flags | server_flags);
+       CamelIMAPXMessageInfo *xinfo = CAMEL_IMAPX_MESSAGE_INFO (info);
 
-       xinfo->server_flags = server_flags;
+       camel_message_info_set_flags (info, server_flags, camel_message_info_get_flags (info) | server_flags);
+       camel_imapx_message_info_set_server_flags (xinfo, server_flags);
 
        if (force_user_flags || (permanent_flags & CAMEL_MESSAGE_USER) != 0)
                imapx_update_user_flags (info, server_user_flags);
 
-       while (user_tags) {
-               camel_message_info_set_user_tag (info, user_tags->name, user_tags->value);
-               user_tags = user_tags->next;
-       }
+       camel_message_info_take_user_tags (info, camel_name_value_array_copy (user_tags));
 
-       binfo->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
-       binfo->dirty = TRUE;
+       camel_message_info_set_folder_flagged (info, FALSE);
 }
 
 void
@@ -394,8 +410,8 @@ imapx_update_store_summary (CamelFolder *folder)
        if (si == NULL)
                return;
 
-       total = camel_folder_summary_count (folder->summary);
-       unread = camel_folder_summary_get_unread_count (folder->summary);
+       total = camel_folder_summary_count (camel_folder_get_folder_summary (folder));
+       unread = camel_folder_summary_get_unread_count (camel_folder_get_folder_summary (folder));
 
        if (si->unread != unread || si->total != total) {
                si->unread = unread;
@@ -416,7 +432,7 @@ camel_imapx_dup_uid_from_summary_index (CamelFolder *folder,
 
        g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
 
-       summary = folder->summary;
+       summary = camel_folder_get_folder_summary (folder);
        g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
 
        array = camel_folder_summary_get_array (summary);
@@ -1150,7 +1166,7 @@ imapx_parse_address_list (CamelIMAPXInputStream *stream,
        return list;
 }
 
-struct _CamelMessageInfo *
+CamelMessageInfo *
 imapx_parse_envelope (CamelIMAPXInputStream *stream,
                       GCancellable *cancellable,
                       GError **error)
@@ -1160,7 +1176,7 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
        guchar *token;
        CamelHeaderAddress *addr, *addr_from;
        gchar *addrstr;
-       struct _CamelMessageInfoBase *minfo = NULL;
+       CamelMessageInfo *info;
        GError *local_error = NULL;
 
        /* envelope        ::= "(" env_date SPACE env_subject SPACE env_from
@@ -1168,7 +1184,7 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
         * SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
         * SPACE env_message_id ")" */
 
-       minfo = (CamelMessageInfoBase *) camel_message_info_new (NULL);
+       info = camel_message_info_new (NULL);
 
        tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, &local_error);
@@ -1178,7 +1194,7 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 
        if (tok != '(') {
                g_clear_error (&local_error);
-               camel_message_info_unref (minfo);
+               g_clear_object (&info);
                g_set_error (error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED, 
"envelope: expecting '('");
                return NULL;
        }
@@ -1188,14 +1204,14 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
        if (local_error)
                goto error;
 
-       minfo->date_sent = camel_header_decode_date ((gchar *) token, NULL);
+       camel_message_info_set_date_sent (info, camel_header_decode_date ((gchar *) token, NULL));
 
        /* env_subject     ::= nstring */
        camel_imapx_input_stream_nstring (stream, &token, cancellable, &local_error);
        if (local_error)
                goto error;
 
-       minfo->subject = camel_pstring_strdup ((gchar *) token);
+       camel_message_info_set_subject (info, (const gchar *) token);
 
        /* we merge from/sender into from, append should probably merge more smartly? */
 
@@ -1218,7 +1234,7 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 
        if (addr_from) {
                addrstr = camel_header_address_list_format (addr_from);
-               minfo->from = camel_pstring_strdup (addrstr);
+               camel_message_info_set_from (info, addrstr);
                g_free (addrstr);
                camel_header_address_list_clear (&addr_from);
        }
@@ -1236,7 +1252,7 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
        addr = imapx_parse_address_list (stream, cancellable, &local_error);
        if (addr) {
                addrstr = camel_header_address_list_format (addr);
-               minfo->to = camel_pstring_strdup (addrstr);
+               camel_message_info_set_to (info, addrstr);
                g_free (addrstr);
                camel_header_address_list_clear (&addr);
        }
@@ -1248,7 +1264,7 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
        addr = imapx_parse_address_list (stream, cancellable, &local_error);
        if (addr) {
                addrstr = camel_header_address_list_format (addr);
-               minfo->cc = camel_pstring_strdup (addrstr);
+               camel_message_info_set_cc (info, addrstr);
                g_free (addrstr);
                camel_header_address_list_clear (&addr);
        }
@@ -1285,7 +1301,7 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 
        if (tok != ')') {
                g_clear_error (&local_error);
-               camel_message_info_unref (minfo);
+               g_clear_object (&info);
                g_set_error (error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED, 
"expecting ')'");
                return NULL;
        }
@@ -1294,15 +1310,14 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
        /* CHEN TODO handle exceptions better */
        if (local_error != NULL) {
                g_propagate_error (error, local_error);
-               if (minfo)
-                       camel_message_info_unref (minfo);
+               g_clear_object (&info);
                return NULL;
        }
 
-       return (CamelMessageInfo *) minfo;
+       return info;
 }
 
-struct _CamelMessageContentInfo *
+CamelMessageContentInfo *
 imapx_parse_body (CamelIMAPXInputStream *stream,
                   GCancellable *cancellable,
                   GError **error)
@@ -1449,7 +1464,7 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 
                        /* what do we do with the message content info?? */
                        //((CamelMessageInfoBase *) minfo)->content = imapx_parse_body (stream);
-                       camel_message_info_unref (minfo);
+                       g_clear_object (&minfo);
                        minfo = NULL;
                }
 
@@ -1673,11 +1688,10 @@ imapx_free_fetch (struct _fetch_info *finfo)
                g_bytes_unref (finfo->text);
        if (finfo->header)
                g_bytes_unref (finfo->header);
-       if (finfo->minfo)
-               camel_message_info_unref (finfo->minfo);
        if (finfo->cinfo)
                imapx_free_body (finfo->cinfo);
-       camel_flag_list_free (&finfo->user_flags);
+       camel_named_flags_free (finfo->user_flags);
+       g_clear_object (&finfo->minfo);
        g_free (finfo->date);
        g_free (finfo->section);
        g_free (finfo->uid);
@@ -1853,7 +1867,7 @@ imapx_parse_fetch_flags (CamelIMAPXInputStream *stream,
        gboolean success;
 
        success = imapx_parse_flags (
-               stream, &finfo->flags, &finfo->user_flags,
+               stream, &finfo->flags, finfo->user_flags,
                cancellable, error);
 
        if (success)
@@ -2003,6 +2017,7 @@ imapx_parse_fetch (CamelIMAPXInputStream *stream,
        struct _fetch_info *finfo;
 
        finfo = g_malloc0 (sizeof (*finfo));
+       finfo->user_flags = camel_named_flags_new ();
 
        tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
@@ -2632,7 +2647,7 @@ camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
        g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), FALSE);
 
        imapx_folder = CAMEL_IMAPX_FOLDER (folder);
-       imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
+       imapx_summary = CAMEL_IMAPX_SUMMARY (camel_folder_get_folder_summary (folder));
 
        mailbox = camel_imapx_folder_ref_mailbox (imapx_folder);
        if (!mailbox)
@@ -2644,7 +2659,7 @@ camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
 
        /* XXX This should return an unsigned integer to
         *     avoid the possibility of a negative count. */
-       summary_total = camel_folder_summary_count (folder->summary);
+       summary_total = camel_folder_summary_count (camel_folder_get_folder_summary (folder));
        g_return_val_if_fail (summary_total >= 0, FALSE);
 
        if (summary_total > 0) {
diff --git a/src/camel/providers/imapx/camel-imapx-utils.h b/src/camel/providers/imapx/camel-imapx-utils.h
index 7fc055b..d9d7e34 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.h
+++ b/src/camel/providers/imapx/camel-imapx-utils.h
@@ -30,7 +30,6 @@ G_BEGIN_DECLS
  *       enum/struct definitions and helper macros, so we don't
  *       have these conflicting header dependencies. */
 struct _CamelIMAPXCommand;
-struct _CamelFlag;
 struct _CamelIMAPXStore;
 
 /* list of strings we know about that can be *quickly* tokenised */
@@ -136,24 +135,24 @@ GArray *  imapx_parse_uids                (CamelIMAPXInputStream *stream,
                                                 GError **error);
 gboolean       imapx_parse_flags               (CamelIMAPXInputStream *stream,
                                                 guint32 *flagsp,
-                                                struct _CamelFlag **user_flagsp,
+                                                CamelNamedFlags *user_flags,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           imapx_write_flags               (GString *string,
                                                 guint32 flags,
-                                                struct _CamelFlag *user_flags);
+                                                const CamelNamedFlags *user_flags);
 gboolean       imapx_update_message_info_flags (CamelMessageInfo *info,
                                                 guint32 server_flags,
-                                                CamelFlag *server_user_flags,
+                                                const CamelNamedFlags *server_user_flags,
                                                 guint32 permanent_flags,
                                                 CamelFolder *folder,
                                                 gboolean unsolicited);
 void           imapx_set_message_info_flags_for_new_message
                                                (CamelMessageInfo *info,
                                                 guint32 server_flags,
-                                                CamelFlag *server_user_flags,
+                                                const CamelNamedFlags *server_user_flags,
                                                 gboolean force_user_flags,
-                                                CamelTag *user_tags,
+                                                const CamelNameValueArray *user_tags,
                                                 guint32 permanent_flags);
 void           imapx_update_store_summary      (CamelFolder *folder);
 
@@ -218,11 +217,11 @@ CamelHeaderAddress *
                imapx_parse_address_list        (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
-struct _CamelMessageInfo *
+CamelMessageInfo *
                imapx_parse_envelope            (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
-struct _CamelMessageContentInfo *
+CamelMessageContentInfo *
                imapx_parse_body                (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
@@ -245,7 +244,7 @@ struct _fetch_info {
        guint32 offset;         /* start offset of a BODY[]<offset.length> request */
        guint32 flags;          /* FLAGS */
        guint64 modseq;         /* MODSEQ */
-       CamelFlag *user_flags;
+       CamelNamedFlags *user_flags;
        gchar *date;            /* INTERNALDATE */
        gchar *section;         /* section for a BODY[section] request */
        gchar *uid;             /* UID */
diff --git a/src/camel/providers/local/CMakeLists.txt b/src/camel/providers/local/CMakeLists.txt
index 169e489..24afeb4 100644
--- a/src/camel/providers/local/CMakeLists.txt
+++ b/src/camel/providers/local/CMakeLists.txt
@@ -10,12 +10,16 @@ set(SOURCES
        camel-local-provider.c
        camel-maildir-folder.c
        camel-maildir-folder.h
+       camel-maildir-message-info.c
+       camel-maildir-message-info.h
        camel-maildir-store.c
        camel-maildir-store.h
        camel-maildir-summary.c
        camel-maildir-summary.h
        camel-mbox-folder.c
        camel-mbox-folder.h
+       camel-mbox-message-info.c
+       camel-mbox-message-info.h
        camel-mbox-store.c
        camel-mbox-store.h
        camel-mbox-summary.c
diff --git a/src/camel/providers/local/camel-local-folder.c b/src/camel/providers/local/camel-local-folder.c
index 47ba761..1b451aa 100644
--- a/src/camel/providers/local/camel-local-folder.c
+++ b/src/camel/providers/local/camel-local-folder.c
@@ -102,17 +102,16 @@ local_folder_dispose (GObject *object)
        folder = CAMEL_FOLDER (object);
        local_folder = CAMEL_LOCAL_FOLDER (object);
 
-       if (folder->summary) {
+       if (camel_folder_get_folder_summary (folder)) {
                /* Something can hold the reference to the folder longer than
                   the parent store is alive, thus count with it. */
                if (camel_folder_get_parent_store (folder)) {
                        camel_local_summary_sync (
-                               CAMEL_LOCAL_SUMMARY (folder->summary),
+                               CAMEL_LOCAL_SUMMARY (camel_folder_get_folder_summary (folder)),
                                FALSE, local_folder->changes, NULL, NULL);
                }
        }
 
-       g_clear_object (&folder->summary);
        g_clear_object (&local_folder->search);
        g_clear_object (&local_folder->index);
 
@@ -223,6 +222,18 @@ local_folder_constructed (GObject *object)
        g_free (path);
 }
 
+static guint32
+local_folder_get_permanent_flags (CamelFolder *folder)
+{
+       return CAMEL_MESSAGE_ANSWERED |
+               CAMEL_MESSAGE_DELETED |
+               CAMEL_MESSAGE_DRAFT |
+               CAMEL_MESSAGE_FLAGGED |
+               CAMEL_MESSAGE_SEEN |
+               CAMEL_MESSAGE_ANSWERED_ALL |
+               CAMEL_MESSAGE_USER;
+}
+
 static GPtrArray *
 local_folder_search_by_expression (CamelFolder *folder,
                                    const gchar *expression,
@@ -331,8 +342,8 @@ local_folder_rename (CamelFolder *folder,
        g_free (statepath);
 
        /* FIXME: Poke some internals, sigh */
-       g_free (((CamelLocalSummary *) folder->summary)->folder_path);
-       ((CamelLocalSummary *) folder->summary)->folder_path = g_strdup (lf->folder_path);
+       g_free (((CamelLocalSummary *) camel_folder_get_folder_summary (folder))->folder_path);
+       ((CamelLocalSummary *) camel_folder_get_folder_summary (folder))->folder_path = g_strdup 
(lf->folder_path);
 
        CAMEL_FOLDER_CLASS (camel_local_folder_parent_class)->rename (folder, newname);
 }
@@ -399,7 +410,7 @@ local_folder_refresh_info_sync (CamelFolder *folder,
                CAMEL_LOCAL_STORE (parent_store));
 
        if (need_summary_check &&
-           camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, cancellable, 
error) == -1)
+           camel_local_summary_check ((CamelLocalSummary *) camel_folder_get_folder_summary (folder), 
lf->changes, cancellable, error) == -1)
                return FALSE;
 
        if (camel_folder_change_info_changed (lf->changes)) {
@@ -428,7 +439,7 @@ local_folder_synchronize_sync (CamelFolder *folder,
 
        /* if sync fails, we'll pass it up on exit through ex */
        success = (camel_local_summary_sync (
-               (CamelLocalSummary *) folder->summary,
+               (CamelLocalSummary *) camel_folder_get_folder_summary (folder),
                expunge, lf->changes, cancellable, error) == 0);
        camel_local_folder_unlock (lf);
 
@@ -470,6 +481,7 @@ camel_local_folder_class_init (CamelLocalFolderClass *class)
        object_class->constructed = local_folder_constructed;
 
        folder_class = CAMEL_FOLDER_CLASS (class);
+       folder_class->get_permanent_flags = local_folder_get_permanent_flags;
        folder_class->search_by_expression = local_folder_search_by_expression;
        folder_class->search_by_uids = local_folder_search_by_uids;
        folder_class->search_free = local_folder_search_free;
@@ -504,14 +516,8 @@ camel_local_folder_init (CamelLocalFolder *local_folder)
        local_folder->priv = CAMEL_LOCAL_FOLDER_GET_PRIVATE (local_folder);
        g_mutex_init (&local_folder->priv->search_lock);
 
-       folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
-
-       folder->permanent_flags = CAMEL_MESSAGE_ANSWERED |
-           CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT |
-           CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN |
-           CAMEL_MESSAGE_ANSWERED_ALL | CAMEL_MESSAGE_USER;
+       camel_folder_set_flags (folder, camel_folder_get_flags (folder) | 
CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY);
 
-       folder->summary = NULL;
        local_folder->search = NULL;
 }
 
@@ -622,13 +628,13 @@ camel_local_folder_construct (CamelLocalFolder *lf,
                forceindex = FALSE;
        }
 
-       folder->summary = (CamelFolderSummary *) CAMEL_LOCAL_FOLDER_GET_CLASS (lf)->create_summary (lf, 
lf->folder_path, lf->index);
-       if (!(flags & CAMEL_STORE_IS_MIGRATING) && !camel_local_summary_load ((CamelLocalSummary *) 
folder->summary, forceindex, NULL)) {
+       camel_folder_take_folder_summary (folder, CAMEL_FOLDER_SUMMARY (CAMEL_LOCAL_FOLDER_GET_CLASS 
(lf)->create_summary (lf, lf->folder_path, lf->index)));
+       if (!(flags & CAMEL_STORE_IS_MIGRATING) && !camel_local_summary_load ((CamelLocalSummary *) 
camel_folder_get_folder_summary (folder), forceindex, NULL)) {
                /* ? */
                if (need_summary_check &&
-                   camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, 
cancellable, error) == 0) {
+                   camel_local_summary_check ((CamelLocalSummary *) camel_folder_get_folder_summary 
(folder), lf->changes, cancellable, error) == 0) {
                        /* we sync here so that any hard work setting up the folder isn't lost */
-                       if (camel_local_summary_sync ((CamelLocalSummary *) folder->summary, FALSE, 
lf->changes, cancellable, error) == -1) {
+                       if (camel_local_summary_sync ((CamelLocalSummary *) camel_folder_get_folder_summary 
(folder), FALSE, lf->changes, cancellable, error) == -1) {
                                g_object_unref (folder);
                                return NULL;
                        }
diff --git a/src/camel/providers/local/camel-local-folder.h b/src/camel/providers/local/camel-local-folder.h
index 00bcb8e..e09c410 100644
--- a/src/camel/providers/local/camel-local-folder.h
+++ b/src/camel/providers/local/camel-local-folder.h
@@ -89,6 +89,9 @@ struct _CamelLocalFolderClass {
 
        /* Unlock the folder for my operations */
        void            (*unlock)               (CamelLocalFolder *);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_local_folder_get_type     (void);
diff --git a/src/camel/providers/local/camel-local-store.c b/src/camel/providers/local/camel-local-store.c
index 324a44e..6790b95 100644
--- a/src/camel/providers/local/camel-local-store.c
+++ b/src/camel/providers/local/camel-local-store.c
@@ -532,7 +532,7 @@ local_store_rename_folder_sync (CamelStore *store,
 
        d (printf ("local rename folder '%s' '%s'\n", old, new));
 
-       folder = camel_object_bag_get (store->folders, old);
+       folder = camel_object_bag_get (camel_store_get_folders_bag (store), old);
        if (folder && folder->index) {
                if (camel_index_rename (folder->index, newibex) == -1)
                        goto ibex_failed;
diff --git a/src/camel/providers/local/camel-local-store.h b/src/camel/providers/local/camel-local-store.h
index 32e492f..a71d920 100644
--- a/src/camel/providers/local/camel-local-store.h
+++ b/src/camel/providers/local/camel-local-store.h
@@ -62,6 +62,9 @@ struct _CamelLocalStoreClass {
        gchar *         (*get_meta_path)        (CamelLocalStore *ls,
                                                 const gchar *full_name,
                                                 const gchar *ext);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_local_store_get_type      (void);
diff --git a/src/camel/providers/local/camel-local-summary.c b/src/camel/providers/local/camel-local-summary.c
index 9fee506..1d0a2c3 100644
--- a/src/camel/providers/local/camel-local-summary.c
+++ b/src/camel/providers/local/camel-local-summary.c
@@ -37,25 +37,23 @@
 
 #define CAMEL_LOCAL_SUMMARY_VERSION (1)
 
-#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
-
 static CamelFIRecord *
-               summary_header_to_db            (CamelFolderSummary *,
+               summary_header_save             (CamelFolderSummary *,
                                                 GError **error);
-static gboolean        summary_header_from_db          (CamelFolderSummary *,
+static gboolean        summary_header_load             (CamelFolderSummary *,
                                                 CamelFIRecord *);
 
 static CamelMessageInfo *
-               message_info_new_from_header    (CamelFolderSummary *,
-                                                struct _camel_header_raw *);
+               message_info_new_from_headers   (CamelFolderSummary *,
+                                                const CamelNameValueArray *);
 
 static gint    local_summary_decode_x_evolution
                                                (CamelLocalSummary *cls,
                                                 const gchar *xev,
-                                                CamelLocalMessageInfo *mi);
+                                                CamelMessageInfo *mi);
 static gchar * local_summary_encode_x_evolution
                                                (CamelLocalSummary *cls,
-                                                const CamelLocalMessageInfo *mi);
+                                                const CamelMessageInfo *mi);
 
 static gint    local_summary_load              (CamelLocalSummary *cls,
                                                 gint forceindex,
@@ -119,11 +117,9 @@ camel_local_summary_class_init (CamelLocalSummaryClass *class)
        object_class->finalize = local_summary_finalize;
 
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
-       folder_summary_class->message_info_size = sizeof (CamelLocalMessageInfo);
-       folder_summary_class->content_info_size = sizeof (CamelMessageContentInfo);
-       folder_summary_class->summary_header_from_db = summary_header_from_db;
-       folder_summary_class->summary_header_to_db = summary_header_to_db;
-       folder_summary_class->message_info_new_from_header = message_info_new_from_header;
+       folder_summary_class->summary_header_load = summary_header_load;
+       folder_summary_class->summary_header_save = summary_header_save;
+       folder_summary_class->message_info_new_from_headers = message_info_new_from_headers;
 
        class->load = local_summary_load;
        class->check = local_summary_check;
@@ -142,7 +138,7 @@ camel_local_summary_init (CamelLocalSummary *local_summary)
        folder_summary = CAMEL_FOLDER_SUMMARY (local_summary);
 
        /* and a unique file version */
-       folder_summary->version += CAMEL_LOCAL_SUMMARY_VERSION;
+       camel_folder_summary_set_version (folder_summary, camel_folder_summary_get_version (folder_summary) + 
CAMEL_LOCAL_SUMMARY_VERSION);
 }
 
 void
@@ -150,7 +146,6 @@ camel_local_summary_construct (CamelLocalSummary *new,
                                const gchar *local_name,
                                CamelIndex *index)
 {
-       camel_folder_summary_set_build_content (CAMEL_FOLDER_SUMMARY (new), FALSE);
        new->folder_path = g_strdup (local_name);
        new->index = index;
        if (index)
@@ -163,7 +158,7 @@ local_summary_load (CamelLocalSummary *cls,
                     GError **error)
 {
        d (g_print ("\nlocal_summary_load called \n"));
-       return camel_folder_summary_load_from_db ((CamelFolderSummary *) cls, error);
+       return camel_folder_summary_load ((CamelFolderSummary *) cls, error);
 }
 
 /* load/check the summary */
@@ -195,7 +190,7 @@ void camel_local_summary_check_force (CamelLocalSummary *cls)
 
 gchar *
 camel_local_summary_encode_x_evolution (CamelLocalSummary *cls,
-                                        const CamelLocalMessageInfo *info)
+                                        const CamelMessageInfo *info)
 {
        return CAMEL_LOCAL_SUMMARY_GET_CLASS (cls)->encode_x_evolution (cls, info);
 }
@@ -203,7 +198,7 @@ camel_local_summary_encode_x_evolution (CamelLocalSummary *cls,
 gint
 camel_local_summary_decode_x_evolution (CamelLocalSummary *cls,
                                         const gchar *xev,
-                                        CamelLocalMessageInfo *info)
+                                        CamelMessageInfo *info)
 {
        return CAMEL_LOCAL_SUMMARY_GET_CLASS (cls)->decode_x_evolution (cls, xev, info);
 }
@@ -315,7 +310,7 @@ camel_local_summary_check (CamelLocalSummary *cls,
                for (i = 0; i < camel_folder_summary_count (s); i++) {
                        CamelMessageInfo *info = camel_folder_summary_get (s, g_ptr_array_index (known_uids, 
i));
                        do_stat_mi (cls, &stats, info);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
                camel_folder_summary_free_array (known_uids);
 
@@ -378,7 +373,7 @@ camel_local_summary_add (CamelLocalSummary *cls,
 /**
  * camel_local_summary_write_headers:
  * @fd:
- * @header:
+ * @headers:
  * @xevline:
  * @status:
  * @xstatus:
@@ -392,13 +387,15 @@ camel_local_summary_add (CamelLocalSummary *cls,
  **/
 gint
 camel_local_summary_write_headers (gint fd,
-                                   struct _camel_header_raw *header,
+                                   CamelNameValueArray *headers,
                                    const gchar *xevline,
                                    const gchar *status,
                                    const gchar *xstatus)
 {
        gint outlen = 0, len;
        gint newfd;
+       guint ii;
+       const gchar *header_name = NULL, *header_value = NULL;
        FILE *out;
 
        /* dum de dum, maybe the whole sync function should just use stdio for output */
@@ -413,18 +410,17 @@ camel_local_summary_write_headers (gint fd,
                return -1;
        }
 
-       while (header) {
-               if (strcmp (header->name, "X-Evolution") != 0
-                   && (status == NULL || strcmp (header->name, "Status") != 0)
-                   && (xstatus == NULL || strcmp (header->name, "X-Status") != 0)) {
-                       len = fprintf (out, "%s:%s\n", header->name, header->value);
+       for (ii = 0; camel_name_value_array_get (headers, ii, &header_name, &header_value); ii++) {
+               if (strcmp (header_name, "X-Evolution") != 0
+                   && (status == NULL || strcmp (header_name, "Status") != 0)
+                   && (xstatus == NULL || strcmp (header_name, "X-Status") != 0)) {
+                       len = fprintf (out, "%s:%s\n", header_name, header_value);
                        if (len == -1) {
                                fclose (out);
                                return -1;
                        }
                        outlen += len;
                }
-               header = header->next;
        }
 
        if (status) {
@@ -488,7 +484,7 @@ local_summary_sync (CamelLocalSummary *cls,
 
        folder_summary = CAMEL_FOLDER_SUMMARY (cls);
 
-       if (!camel_folder_summary_save_to_db (folder_summary, error)) {
+       if (!camel_folder_summary_save (folder_summary, error)) {
                g_warning ("Could not save summary for local providers");
                return -1;
        }
@@ -516,52 +512,34 @@ local_summary_add (CamelLocalSummary *cls,
 {
        CamelFolderSummary *summary;
        CamelMessageInfo *mi;
-       CamelMessageInfoBase *mi_base;
        gchar *xev;
 
        d (printf ("Adding message to summary\n"));
 
        summary = CAMEL_FOLDER_SUMMARY (cls);
 
-       mi = camel_folder_summary_info_new_from_message (summary, msg, NULL);
-       camel_folder_summary_add (summary, mi);
-
-       mi_base = (CamelMessageInfoBase *) mi;
+       mi = camel_folder_summary_info_new_from_message (summary, msg);
+       camel_message_info_set_abort_notifications (mi, TRUE);
 
        if (info) {
-               const CamelTag *tag = camel_message_info_get_user_tags (info);
-               const CamelFlag *flag = camel_message_info_get_user_flags (info);
-
-               while (flag) {
-                       camel_message_info_set_user_flag (mi, flag->name, TRUE);
-                       flag = flag->next;
-               }
-
-               while (tag) {
-                       camel_message_info_set_user_tag (mi, tag->name, tag->value);
-                       tag = tag->next;
-               }
-
-               camel_message_info_set_flags (mi, 0xffff, camel_message_info_get_flags (info));
-               mi_base->size = camel_message_info_get_size (info);
+               camel_message_info_take_user_flags (mi, camel_message_info_dup_user_flags (info));
+               camel_message_info_take_user_tags (mi, camel_message_info_dup_user_tags (info));
+               camel_message_info_set_flags (mi, ~0, camel_message_info_get_flags (info));
+               camel_message_info_set_size (mi, camel_message_info_get_size (info));
        }
 
        /* we need to calculate the size ourselves */
        if (camel_message_info_get_size (mi) == 0) {
-               CamelStreamNull *sn = (CamelStreamNull *) camel_stream_null_new ();
-
-               camel_data_wrapper_write_to_stream_sync (
-                       (CamelDataWrapper *) msg,
-                       (CamelStream *) sn, NULL, NULL);
-               mi_base->size = sn->written;
-               g_object_unref (sn);
+               camel_message_info_set_size (mi, camel_data_wrapper_calculate_size_sync (CAMEL_DATA_WRAPPER 
(msg), NULL, NULL));
        }
 
-       mi_base->flags &= ~(CAMEL_MESSAGE_FOLDER_NOXEV);
-       xev = camel_local_summary_encode_x_evolution (
-               cls, (CamelLocalMessageInfo *) mi);
+       camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_NOXEV, 0);
+       xev = camel_local_summary_encode_x_evolution (cls, mi);
        camel_medium_set_header ((CamelMedium *) msg, "X-Evolution", xev);
        g_free (xev);
+
+       camel_message_info_set_abort_notifications (mi, FALSE);
+       camel_folder_summary_add (summary, mi, FALSE);
        camel_folder_change_info_add_uid (ci, camel_message_info_get_uid (mi));
 
        return mi;
@@ -569,65 +547,86 @@ local_summary_add (CamelLocalSummary *cls,
 
 static gchar *
 local_summary_encode_x_evolution (CamelLocalSummary *cls,
-                                  const CamelLocalMessageInfo *mi)
+                                  const CamelMessageInfo *mi)
 {
        GString *out = g_string_new ("");
        struct _camel_header_param *params = NULL;
-       CamelFlag *flag = mi->info.user_flags;
-       CamelTag *tag = mi->info.user_tags;
+       guint32 flags;
+       const CamelNamedFlags *user_flags;
+       const CamelNameValueArray *user_tags;
        gchar *ret;
        const gchar *p, *uidstr;
        guint32 uid;
 
+       camel_message_info_property_lock (mi);
+
        /* FIXME: work out what to do with uid's that aren't stored here? */
        /* FIXME: perhaps make that a mbox folder only issue?? */
        p = uidstr = camel_message_info_get_uid (mi);
+       flags = camel_message_info_get_flags (mi);
        while (*p && isdigit (*p))
                p++;
        if (*p == 0 && sscanf (uidstr, "%u", &uid) == 1) {
-               g_string_printf (out, "%08x-%04x", uid, mi->info.flags & 0xffff);
+               g_string_printf (out, "%08x-%04x", uid, flags & 0xffff);
        } else {
-               g_string_printf (out, "%s-%04x", uidstr, mi->info.flags & 0xffff);
+               g_string_printf (out, "%s-%04x", uidstr, flags & 0xffff);
        }
 
-       if (flag || tag) {
+       user_flags = camel_message_info_get_user_flags (mi);
+       user_tags = camel_message_info_get_user_tags (mi);
+
+       if (user_flags || user_tags) {
                GString *val = g_string_new ("");
+               const gchar *name, *value;
+               guint ii, len;
+
+               len = camel_named_flags_get_length (user_flags);
+               if (len) {
+                       for (ii = 0; ii < len; ii++) {
+                               name = camel_named_flags_get (user_flags, ii);
+                               if (!name)
+                                       continue;
 
-               if (flag) {
-                       while (flag) {
-                               g_string_append (val, flag->name);
-                               if (flag->next)
+                               if (val->len)
                                        g_string_append_c (val, ',');
-                               flag = flag->next;
+                               g_string_append (val, name);
                        }
                        camel_header_set_param (&params, "flags", val->str);
                        g_string_truncate (val, 0);
                }
-               if (tag) {
-                       while (tag) {
-                               g_string_append (val, tag->name);
-                               g_string_append_c (val, '=');
-                               g_string_append (val, tag->value);
-                               if (tag->next)
+
+               len = camel_name_value_array_get_length (user_tags);
+               if (len) {
+                       for (ii = 0; ii < len; ii++) {
+                               if (!camel_name_value_array_get (user_tags, ii, &name, &value))
+                                       continue;
+
+                               if (val->len)
                                        g_string_append_c (val, ',');
-                               tag = tag->next;
+
+                               g_string_append (val, name);
+                               g_string_append_c (val, '=');
+                               g_string_append (val, value);
                        }
                        camel_header_set_param (&params, "tags", val->str);
                }
                g_string_free (val, TRUE);
+
                camel_header_param_list_format_append (out, params);
                camel_header_param_list_free (params);
        }
        ret = out->str;
        g_string_free (out, FALSE);
 
+       camel_message_info_property_unlock (mi);
+
        return ret;
 }
 
 static gint
 local_summary_decode_x_evolution (CamelLocalSummary *cls,
                                   const gchar *xev,
-                                  CamelLocalMessageInfo *mi)
+                                  CamelMessageInfo *mi)
 {
        struct _camel_header_param *params, *scan;
        guint32 uid, flags;
@@ -662,7 +661,7 @@ local_summary_decode_x_evolution (CamelLocalSummary *cls,
                                gchar **flagv = g_strsplit (scan->value, ",", 1000);
 
                                for (i = 0; flagv[i]; i++)
-                                       camel_message_info_set_user_flag ((CamelMessageInfo *) mi, flagv[i], 
TRUE);
+                                       camel_message_info_set_user_flag (mi, flagv[i], TRUE);
                                g_strfreev (flagv);
                        } else if (!g_ascii_strcasecmp (scan->name, "tags")) {
                                gchar **tagv = g_strsplit (scan->value, ",", 10000);
@@ -672,7 +671,7 @@ local_summary_decode_x_evolution (CamelLocalSummary *cls,
                                        val = strchr (tagv[i], '=');
                                        if (val) {
                                                *val++ = 0;
-                                               camel_message_info_set_user_tag ((CamelMessageInfo *) mi, 
tagv[i], val);
+                                               camel_message_info_set_user_tag (mi, tagv[i], val);
                                                val[-1]='=';
                                        }
                                }
@@ -683,27 +682,27 @@ local_summary_decode_x_evolution (CamelLocalSummary *cls,
                camel_header_param_list_free (params);
        }
 
-       mi->info.uid = camel_pstring_strdup (uidstr);
-       mi->info.flags = flags;
+       camel_message_info_set_uid (mi, uidstr);
+       camel_message_info_set_flags (mi, ~0, flags);
 
        return 0;
 }
 
 static gboolean
-summary_header_from_db (CamelFolderSummary *s,
-                        CamelFIRecord *fir)
+summary_header_load (CamelFolderSummary *s,
+                    CamelFIRecord *fir)
 {
        CamelLocalSummary *cls = (CamelLocalSummary *) s;
        gchar *part, *tmp;
 
        /* We dont actually add our own headers, but version that we don't anyway */
 
-       if (!CAMEL_FOLDER_SUMMARY_CLASS (camel_local_summary_parent_class)->summary_header_from_db (s, fir))
+       if (!CAMEL_FOLDER_SUMMARY_CLASS (camel_local_summary_parent_class)->summary_header_load (s, fir))
                return FALSE;
 
        part = fir->bdata;
        if (part) {
-               EXTRACT_FIRST_DIGIT (cls->version)
+               cls->version = camel_util_bdata_get_number (&part, 0);
        }
 
        /* keep only the rest of the bdata there (strip our version digit) */
@@ -715,15 +714,15 @@ summary_header_from_db (CamelFolderSummary *s,
 }
 
 static struct _CamelFIRecord *
-summary_header_to_db (CamelFolderSummary *s,
-                      GError **error)
+summary_header_save (CamelFolderSummary *s,
+                    GError **error)
 {
        CamelFolderSummaryClass *folder_summary_class;
        struct _CamelFIRecord *fir;
 
-       /* Chain up to parent's summary_header_to_db() method. */
+       /* Chain up to parent's summary_header_save() method. */
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (camel_local_summary_parent_class);
-       fir = folder_summary_class->summary_header_to_db (s, NULL);
+       fir = folder_summary_class->summary_header_save (s, NULL);
        if (fir)
                fir->bdata = g_strdup_printf ("%d", CAMEL_LOCAL_SUMMARY_VERSION);
 
@@ -731,24 +730,28 @@ summary_header_to_db (CamelFolderSummary *s,
 }
 
 static CamelMessageInfo *
-message_info_new_from_header (CamelFolderSummary *s,
-                              struct _camel_header_raw *h)
+message_info_new_from_headers (CamelFolderSummary *summary,
+                              const CamelNameValueArray *headers)
 {
-       CamelLocalMessageInfo *mi;
-       CamelLocalSummary *cls = (CamelLocalSummary *) s;
+       CamelMessageInfo *mi;
+       CamelLocalSummary *cls = (CamelLocalSummary *) summary;
 
-       mi = (CamelLocalMessageInfo *) CAMEL_FOLDER_SUMMARY_CLASS 
(camel_local_summary_parent_class)->message_info_new_from_header (s, h);
+       mi = CAMEL_FOLDER_SUMMARY_CLASS (camel_local_summary_parent_class)->message_info_new_from_headers 
(summary, headers);
        if (mi) {
                const gchar *xev;
                gint doindex = FALSE;
 
-               xev = camel_header_raw_find (&h, "X-Evolution", NULL);
+               xev = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
"X-Evolution");
                if (xev == NULL || camel_local_summary_decode_x_evolution (cls, xev, mi) == -1) {
+                       gchar *uid;
+
+                       uid = camel_folder_summary_next_uid_string (summary);
+
                        /* to indicate it has no xev header */
-                       mi->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV;
-                       mi->info.dirty = TRUE;
-                       camel_pstring_free (mi->info.uid);
-                       mi->info.uid = camel_pstring_add (camel_folder_summary_next_uid_string (s), TRUE);
+                       camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_FLAGGED | 
CAMEL_MESSAGE_FOLDER_NOXEV, CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV);
+                       camel_message_info_set_uid (mi, uid);
+
+                       g_free (uid);
 
                        /* shortcut, no need to look it up in the index library */
                        doindex = TRUE;
@@ -759,12 +762,12 @@ message_info_new_from_header (CamelFolderSummary *s,
                        || cls->index_force
                        || !camel_index_has_name (cls->index, camel_message_info_get_uid (mi)))) {
                        d (printf ("Am indexing message %s\n", camel_message_info_get_uid (mi)));
-                       camel_folder_summary_set_index (s, cls->index);
+                       camel_folder_summary_set_index (summary, cls->index);
                } else {
                        d (printf ("Not indexing message %s\n", camel_message_info_get_uid (mi)));
-                       camel_folder_summary_set_index (s, NULL);
+                       camel_folder_summary_set_index (summary, NULL);
                }
        }
 
-       return (CamelMessageInfo *) mi;
+       return mi;
 }
diff --git a/src/camel/providers/local/camel-local-summary.h b/src/camel/providers/local/camel-local-summary.h
index 496b787..284aca2 100644
--- a/src/camel/providers/local/camel-local-summary.h
+++ b/src/camel/providers/local/camel-local-summary.h
@@ -52,12 +52,6 @@ enum {
        CAMEL_MESSAGE_FOLDER_NOTSEEN = 1 << 19 /* have we seen this in processing this loop? */
 };
 
-typedef struct _CamelLocalMessageInfo CamelLocalMessageInfo;
-
-struct _CamelLocalMessageInfo {
-       CamelMessageInfoBase info;
-};
-
 struct _CamelLocalSummary {
        CamelFolderSummary parent;
 
@@ -78,9 +72,12 @@ struct _CamelLocalSummaryClass {
        gint (*sync)(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, 
GCancellable *cancellable, GError **error);
        CamelMessageInfo *(*add)(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, 
CamelFolderChangeInfo *, GError **error);
 
-       gchar *(*encode_x_evolution)(CamelLocalSummary *cls, const CamelLocalMessageInfo *info);
-       gint (*decode_x_evolution)(CamelLocalSummary *cls, const gchar *xev, CamelLocalMessageInfo *info);
+       gchar *(*encode_x_evolution)(CamelLocalSummary *cls, const CamelMessageInfo *info);
+       gint (*decode_x_evolution)(CamelLocalSummary *cls, const gchar *xev, CamelMessageInfo *info);
        gint (*need_index)(void);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType  camel_local_summary_get_type    (void);
@@ -99,11 +96,11 @@ CamelMessageInfo *camel_local_summary_add (CamelLocalSummary *cls, CamelMimeMess
 void camel_local_summary_check_force (CamelLocalSummary *cls);
 
 /* generate an X-Evolution header line */
-gchar *camel_local_summary_encode_x_evolution (CamelLocalSummary *cls, const CamelLocalMessageInfo *info);
-gint camel_local_summary_decode_x_evolution (CamelLocalSummary *cls, const gchar *xev, CamelLocalMessageInfo 
*info);
+gchar *camel_local_summary_encode_x_evolution (CamelLocalSummary *cls, const CamelMessageInfo *info);
+gint camel_local_summary_decode_x_evolution (CamelLocalSummary *cls, const gchar *xev, CamelMessageInfo 
*info);
 
 /* utility functions - write headers to a file with optional X-Evolution header and/or status header */
-gint camel_local_summary_write_headers (gint fd, struct _camel_header_raw *header, const gchar *xevline, 
const gchar *status, const gchar *xstatus);
+gint camel_local_summary_write_headers (gint fd, CamelNameValueArray *headers, const gchar *xevline, const 
gchar *status, const gchar *xstatus);
 
 G_END_DECLS
 
diff --git a/src/camel/providers/local/camel-maildir-folder.c 
b/src/camel/providers/local/camel-maildir-folder.c
index 7ec56fd..494b6fb 100644
--- a/src/camel/providers/local/camel-maildir-folder.c
+++ b/src/camel/providers/local/camel-maildir-folder.c
@@ -48,17 +48,17 @@ maildir_folder_cmp_uids (CamelFolder *folder,
        time_t tma, tmb;
 
        g_return_val_if_fail (folder != NULL, 0);
-       g_return_val_if_fail (folder->summary != NULL, 0);
+       g_return_val_if_fail (camel_folder_get_folder_summary (folder) != NULL, 0);
 
-       a = camel_folder_summary_get (folder->summary, uid1);
-       b = camel_folder_summary_get (folder->summary, uid2);
+       a = camel_folder_summary_get (camel_folder_get_folder_summary (folder), uid1);
+       b = camel_folder_summary_get (camel_folder_get_folder_summary (folder), uid2);
 
        if (!a || !b) {
                /* It's not a problem when one of the messages is not in the summary */
                if (a)
-                       camel_message_info_unref (a);
+                       g_object_unref (a);
                if (b)
-                       camel_message_info_unref (b);
+                       g_object_unref (b);
 
                if (a == b)
                        return 0;
@@ -70,8 +70,8 @@ maildir_folder_cmp_uids (CamelFolder *folder,
        tma = camel_message_info_get_date_received (a);
        tmb = camel_message_info_get_date_received (b);
 
-       camel_message_info_unref (a);
-       camel_message_info_unref (b);
+       g_clear_object (&a);
+       g_clear_object (&b);
 
        return tma < tmb ? -1 : tma == tmb ? 0 : 1;
 }
@@ -84,7 +84,7 @@ maildir_folder_sort_uids (CamelFolder *folder,
        g_return_if_fail (folder != NULL);
 
        if (uids && uids->len > 1)
-               camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
+               camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary (folder), NULL);
 
        /* Chain up to parent's sort_uids() method. */
        CAMEL_FOLDER_CLASS (camel_maildir_folder_parent_class)->sort_uids (folder, uids);
@@ -101,20 +101,20 @@ maildir_folder_get_filename (CamelFolder *folder,
        gchar *res;
 
        /* get the message summary info */
-       if ((info = camel_folder_summary_get (folder->summary, uid)) == NULL) {
+       if ((info = camel_folder_summary_get (camel_folder_get_folder_summary (folder), uid)) == NULL) {
                set_cannot_get_message_ex (
                        error, CAMEL_FOLDER_ERROR_INVALID_UID,
                        uid, lf->folder_path, _("No such message"));
                return NULL;
        }
 
-       mdi = (CamelMaildirMessageInfo *) info;
+       mdi = CAMEL_MAILDIR_MESSAGE_INFO (info);
 
        /* If filename is NULL, it means folder_summary_check is not yet executed.
         * Try to find the file in the folder and use it, otherwise construct its
         * name based on actual flags.
        */
-       if (!camel_maildir_info_filename (mdi)) {
+       if (!camel_maildir_message_info_get_filename (mdi)) {
                const gchar *uid = camel_message_info_get_uid (info);
 
                if (uid) {
@@ -131,7 +131,7 @@ maildir_folder_get_filename (CamelFolder *folder,
 
                                while (filename = g_dir_read_name (dir), filename) {
                                        if (g_str_has_prefix (filename, uid) && (filename[uid_len] == '\0' || 
filename[uid_len] == CAMEL_MAILDIR_FLAG_SEP)) {
-                                               camel_maildir_info_set_filename (mdi, g_strdup (filename));
+                                               camel_maildir_message_info_take_filename (mdi, g_strdup 
(filename));
                                                break;
                                        }
                                }
@@ -140,14 +140,14 @@ maildir_folder_get_filename (CamelFolder *folder,
                        }
                }
 
-               if (!camel_maildir_info_filename (mdi)) {
-                       camel_maildir_info_set_filename (mdi, camel_maildir_summary_info_to_name (mdi));
+               if (!camel_maildir_message_info_get_filename (mdi)) {
+                       camel_maildir_message_info_take_filename (mdi, camel_maildir_summary_info_to_name 
(info));
                }
        }
 
-       res = g_strdup_printf ("%s/cur/%s", lf->folder_path, camel_maildir_info_filename (mdi));
+       res = g_strdup_printf ("%s/cur/%s", lf->folder_path, camel_maildir_message_info_get_filename (mdi));
 
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        return res;
 }
@@ -175,7 +175,7 @@ maildir_folder_append_message_sync (CamelFolder *folder,
 
        /* add it to the summary/assign the uid, etc */
        mi = camel_local_summary_add (
-               CAMEL_LOCAL_SUMMARY (folder->summary),
+               CAMEL_LOCAL_SUMMARY (camel_folder_get_folder_summary (folder)),
                message, info, lf->changes, error);
        if (mi == NULL)
                goto check_changed;
@@ -203,7 +203,7 @@ maildir_folder_append_message_sync (CamelFolder *folder,
                goto fail_write;
 
        /* now move from tmp to cur (bypass new, does it matter?) */
-       dest = g_strdup_printf ("%s/cur/%s", lf->folder_path, camel_maildir_info_filename (mdi));
+       dest = g_strdup_printf ("%s/cur/%s", lf->folder_path, camel_maildir_message_info_get_filename (mdi));
        if (g_rename (name, dest) == -1) {
                g_set_error (
                        error, G_IO_ERROR,
@@ -226,7 +226,7 @@ maildir_folder_append_message_sync (CamelFolder *folder,
  fail_write:
 
        /* remove the summary info so we are not out-of-sync with the mh folder */
-       camel_folder_summary_remove (CAMEL_FOLDER_SUMMARY (folder->summary), mi);
+       camel_folder_summary_remove (CAMEL_FOLDER_SUMMARY (camel_folder_get_folder_summary (folder)), mi);
 
        g_prefix_error (
                error, _("Cannot append message to maildir folder: %s: "),
@@ -250,6 +250,8 @@ maildir_folder_append_message_sync (CamelFolder *folder,
                camel_folder_change_info_clear (lf->changes);
        }
 
+       g_clear_object (&mi);
+
        return success;
 }
 
@@ -336,7 +338,7 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
                        CamelMaildirMessageInfo *mdi;
                        CamelMessageInfo *info;
 
-                       if ((info = camel_folder_summary_get (source->summary, uid)) == NULL) {
+                       if ((info = camel_folder_summary_get (camel_folder_get_folder_summary (source), uid)) 
== NULL) {
                                set_cannot_get_message_ex (
                                        error, CAMEL_FOLDER_ERROR_INVALID_UID,
                                        uid, lf->folder_path, _("No such message"));
@@ -344,10 +346,10 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
                        }
 
                        mdi = (CamelMaildirMessageInfo *) info;
-                       new_filename = camel_maildir_summary_info_to_name (mdi);
+                       new_filename = camel_maildir_summary_info_to_name (info);
 
                        d_filename = g_strdup_printf ("%s/cur/%s", df->folder_path, new_filename);
-                       s_filename = g_strdup_printf ("%s/cur/%s", lf->folder_path, 
camel_maildir_info_filename (mdi));
+                       s_filename = g_strdup_printf ("%s/cur/%s", lf->folder_path, 
camel_maildir_message_info_get_filename (mdi));
 
                        if (g_rename (s_filename, d_filename) != 0) {
                                if (errno == EXDEV) {
@@ -359,7 +361,7 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
                                                g_io_error_from_errno (errno),
                                                _("Cannot transfer message to destination folder: %s"),
                                                g_strerror (errno));
-                                       camel_message_info_unref (info);
+                                       g_clear_object (&info);
                                        g_free (s_filename);
                                        g_free (d_filename);
                                        g_free (new_filename);
@@ -367,22 +369,17 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
                                }
                        } else {
                                CamelMessageInfo *clone;
-                               CamelMaildirMessageInfo *mclone;
 
-                               clone = camel_message_info_clone (info);
-                               clone->summary = dest->summary;
+                               clone = camel_message_info_clone (info, camel_folder_get_folder_summary 
(dest));
 
-                               mclone = (CamelMaildirMessageInfo *) clone;
-                               /* preserve also UID, as it matches the file name */
-                               mclone->info.info.uid = camel_pstring_strdup (camel_message_info_get_uid 
(info));
-                               camel_maildir_info_set_filename (clone, g_strdup (new_filename));
+                               camel_maildir_message_info_set_filename (CAMEL_MAILDIR_MESSAGE_INFO (clone), 
new_filename);
                                /* unset deleted flag when transferring from trash folder */
-                               if ((source->folder_flags & CAMEL_FOLDER_IS_TRASH) != 0)
+                               if ((camel_folder_get_flags (source) & CAMEL_FOLDER_IS_TRASH) != 0)
                                        camel_message_info_set_flags (info, CAMEL_MESSAGE_DELETED, 0);
                                /* unset junk flag when transferring from junk folder */
-                               if ((source->folder_flags & CAMEL_FOLDER_IS_JUNK) != 0)
+                               if ((camel_folder_get_flags (source) & CAMEL_FOLDER_IS_JUNK) != 0)
                                        camel_message_info_set_flags (info, CAMEL_MESSAGE_JUNK, 0);
-                               camel_folder_summary_add (dest->summary, clone);
+                               camel_folder_summary_add (camel_folder_get_folder_summary (dest), clone, 
FALSE);
 
                                camel_folder_change_info_add_uid (df->changes, camel_message_info_get_uid 
(clone));
 
@@ -390,10 +387,11 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
                                        source, uid, CAMEL_MESSAGE_DELETED |
                                        CAMEL_MESSAGE_SEEN, ~0);
                                camel_folder_change_info_remove_uid (lf->changes, camel_message_info_get_uid 
(info));
-                               camel_folder_summary_remove (source->summary, info);
+                               camel_folder_summary_remove (camel_folder_get_folder_summary (source), info);
+                               g_clear_object (&clone);
                        }
 
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                        g_free (s_filename);
                        g_free (d_filename);
                        g_free (new_filename);
@@ -498,7 +496,7 @@ camel_maildir_folder_new (CamelStore *parent_store,
        g_object_unref (settings);
 
        if (filter_inbox && (g_str_equal (full_name, ".") || g_ascii_strcasecmp (full_name, "Inbox") == 0))
-               folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+               camel_folder_set_flags (folder, camel_folder_get_flags (folder) | CAMEL_FOLDER_FILTER_RECENT);
 
        folder = (CamelFolder *) camel_local_folder_construct (
                CAMEL_LOCAL_FOLDER (folder), flags, cancellable, error);
diff --git a/src/camel/providers/local/camel-maildir-folder.h 
b/src/camel/providers/local/camel-maildir-folder.h
index 08a08de..cbafc03 100644
--- a/src/camel/providers/local/camel-maildir-folder.h
+++ b/src/camel/providers/local/camel-maildir-folder.h
@@ -52,6 +52,9 @@ struct _CamelMaildirFolder {
 
 struct _CamelMaildirFolderClass {
        CamelLocalFolderClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_maildir_folder_get_type   (void);
diff --git a/src/camel/providers/local/camel-maildir-message-info.c 
b/src/camel/providers/local/camel-maildir-message-info.c
new file mode 100644
index 0000000..7d85cc9
--- /dev/null
+++ b/src/camel/providers/local/camel-maildir-message-info.c
@@ -0,0 +1,251 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+
+#include "camel/camel.h"
+#include "camel-maildir-summary.h"
+
+#include "camel-maildir-message-info.h"
+
+struct _CamelMaildirMessageInfoPrivate {
+       gchar *filename;
+};
+
+enum {
+       PROP_0,
+       PROP_FILENAME
+};
+
+G_DEFINE_TYPE (CamelMaildirMessageInfo, camel_maildir_message_info, CAMEL_TYPE_MESSAGE_INFO_BASE)
+
+static CamelMessageInfo *
+maildir_message_info_clone (const CamelMessageInfo *mi,
+                           CamelFolderSummary *assign_summary)
+{
+       CamelMessageInfo *result;
+
+       g_return_val_if_fail (CAMEL_IS_MAILDIR_MESSAGE_INFO (mi), NULL);
+
+       result = CAMEL_MESSAGE_INFO_CLASS (camel_maildir_message_info_parent_class)->clone (mi, 
assign_summary);
+       if (!result)
+               return NULL;
+
+       if (CAMEL_IS_MAILDIR_MESSAGE_INFO (result)) {
+               CamelMaildirMessageInfo *mmi, *mmi_result;
+
+               mmi = CAMEL_MAILDIR_MESSAGE_INFO (mi);
+               mmi_result = CAMEL_MAILDIR_MESSAGE_INFO (result);
+
+               /* safe-guard that the mmi's filename doesn't change before it's copied to mmi_result */
+               camel_message_info_property_lock (mi);
+
+               camel_maildir_message_info_set_filename (mmi_result, camel_maildir_message_info_get_filename 
(mmi));
+
+               camel_message_info_property_unlock (mi);
+       }
+
+       return result;
+}
+
+static gboolean
+maildir_message_info_load (CamelMessageInfo *mi,
+                          const CamelMIRecord *record,
+                          /* const */ gchar **bdata_ptr)
+{
+       CamelMaildirMessageInfo *mmi;
+
+       g_return_val_if_fail (CAMEL_IS_MAILDIR_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       if (!CAMEL_MESSAGE_INFO_CLASS (camel_maildir_message_info_parent_class)->load ||
+           !CAMEL_MESSAGE_INFO_CLASS (camel_maildir_message_info_parent_class)->load (mi, record, bdata_ptr))
+               return FALSE;
+
+       mmi = CAMEL_MAILDIR_MESSAGE_INFO (mi);
+
+       camel_maildir_message_info_take_filename (mmi, camel_maildir_summary_info_to_name (mi));
+
+       return TRUE;
+}
+
+static void
+maildir_message_info_set_property (GObject *object,
+                                  guint property_id,
+                                  const GValue *value,
+                                  GParamSpec *pspec)
+{
+       CamelMaildirMessageInfo *mmi = CAMEL_MAILDIR_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_FILENAME:
+               camel_maildir_message_info_set_filename (mmi, g_value_get_string (value));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+maildir_message_info_get_property (GObject *object,
+                                  guint property_id,
+                                  GValue *value,
+                                  GParamSpec *pspec)
+{
+       CamelMaildirMessageInfo *mmi = CAMEL_MAILDIR_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_FILENAME:
+               g_value_set_string (value, camel_maildir_message_info_get_filename (mmi));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+maildir_message_info_dispose (GObject *object)
+{
+       CamelMaildirMessageInfo *mmi = CAMEL_MAILDIR_MESSAGE_INFO (object);
+
+       g_free (mmi->priv->filename);
+       mmi->priv->filename = NULL;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_maildir_message_info_parent_class)->dispose (object);
+}
+
+static void
+camel_maildir_message_info_class_init (CamelMaildirMessageInfoClass *class)
+{
+       CamelMessageInfoClass *mi_class;
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelMaildirMessageInfoPrivate));
+
+       mi_class = CAMEL_MESSAGE_INFO_CLASS (class);
+       mi_class->clone = maildir_message_info_clone;
+       mi_class->load = maildir_message_info_load;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = maildir_message_info_set_property;
+       object_class->get_property = maildir_message_info_get_property;
+       object_class->dispose = maildir_message_info_dispose;
+
+       /**
+        * CamelMaildirMessageInfo:filename
+        *
+        * File name of the message on the disk.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_FILENAME,
+               g_param_spec_string (
+                       "filename",
+                       "Filename",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+}
+
+static void
+camel_maildir_message_info_init (CamelMaildirMessageInfo *mmi)
+{
+       mmi->priv = G_TYPE_INSTANCE_GET_PRIVATE (mmi, CAMEL_TYPE_MAILDIR_MESSAGE_INFO, 
CamelMaildirMessageInfoPrivate);
+}
+
+const gchar *
+camel_maildir_message_info_get_filename (const CamelMaildirMessageInfo *mmi)
+{
+       CamelMessageInfo *mi;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MAILDIR_MESSAGE_INFO (mmi), NULL);
+
+       mi = CAMEL_MESSAGE_INFO (mmi);
+
+       camel_message_info_property_lock (mi);
+       result = mmi->priv->filename;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gchar *
+camel_maildir_message_info_dup_filename (const CamelMaildirMessageInfo *mmi)
+{
+       CamelMessageInfo *mi;
+       gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_MAILDIR_MESSAGE_INFO (mmi), NULL);
+
+       mi = CAMEL_MESSAGE_INFO (mmi);
+
+       camel_message_info_property_lock (mi);
+       result = g_strdup (mmi->priv->filename);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gboolean
+camel_maildir_message_info_set_filename (CamelMaildirMessageInfo *mmi,
+                                        const gchar *filename)
+{
+       g_return_val_if_fail (CAMEL_IS_MAILDIR_MESSAGE_INFO (mmi), FALSE);
+
+       return camel_maildir_message_info_take_filename (mmi, g_strdup (filename));
+}
+
+gboolean
+camel_maildir_message_info_take_filename (CamelMaildirMessageInfo *mmi,
+                                         gchar *filename)
+{
+       CamelMessageInfo *mi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MAILDIR_MESSAGE_INFO (mmi), FALSE);
+
+       mi = CAMEL_MESSAGE_INFO (mmi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = g_strcmp0 (mmi->priv->filename, filename) != 0;
+
+       if (changed) {
+               g_free (mmi->priv->filename);
+               mmi->priv->filename = filename;
+       } else if (filename != mmi->priv->filename) {
+               g_free (filename);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !camel_message_info_get_abort_notifications (mi)) {
+               g_object_notify (G_OBJECT (mmi), "filename");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
diff --git a/src/camel/providers/local/camel-maildir-message-info.h 
b/src/camel/providers/local/camel-maildir-message-info.h
new file mode 100644
index 0000000..5264762
--- /dev/null
+++ b/src/camel/providers/local/camel-maildir-message-info.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#ifndef CAMEL_MAILDIR_MESSAGE_INFO_H
+#define CAMEL_MAILDIR_MESSAGE_INFO_H
+
+#include <glib-object.h>
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_MAILDIR_MESSAGE_INFO \
+       (camel_maildir_message_info_get_type ())
+#define CAMEL_MAILDIR_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_MAILDIR_MESSAGE_INFO, CamelMaildirMessageInfo))
+#define CAMEL_MAILDIR_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_MAILDIR_MESSAGE_INFO, CamelMaildirMessageInfoClass))
+#define CAMEL_IS_MAILDIR_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_MAILDIR_MESSAGE_INFO))
+#define CAMEL_IS_MAILDIR_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_MAILDIR_MESSAGE_INFO))
+#define CAMEL_MAILDIR_MESSAGE_INFO_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_MAILDIR_MESSAGE_INFO, CamelMaildirMessageInfoClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelMaildirMessageInfo CamelMaildirMessageInfo;
+typedef struct _CamelMaildirMessageInfoClass CamelMaildirMessageInfoClass;
+typedef struct _CamelMaildirMessageInfoPrivate CamelMaildirMessageInfoPrivate;
+
+struct _CamelMaildirMessageInfo {
+       CamelMessageInfoBase parent;
+       CamelMaildirMessageInfoPrivate *priv;
+};
+
+struct _CamelMaildirMessageInfoClass {
+       CamelMessageInfoBaseClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
+};
+
+GType          camel_maildir_message_info_get_type     (void);
+
+const gchar *  camel_maildir_message_info_get_filename (const CamelMaildirMessageInfo *mmi);
+gchar *                camel_maildir_message_info_dup_filename (const CamelMaildirMessageInfo *mmi);
+gboolean       camel_maildir_message_info_set_filename (CamelMaildirMessageInfo *mmi,
+                                                        const gchar *filename);
+gboolean       camel_maildir_message_info_take_filename
+                                                       (CamelMaildirMessageInfo *mmi,
+                                                        gchar *filename);
+
+G_END_DECLS
+
+#endif /* CAMEL_MAILDIR_MESSAGE_INFO_H */
diff --git a/src/camel/providers/local/camel-maildir-store.c b/src/camel/providers/local/camel-maildir-store.c
index be483b1..8b070fc 100644
--- a/src/camel/providers/local/camel-maildir-store.c
+++ b/src/camel/providers/local/camel-maildir-store.c
@@ -441,7 +441,7 @@ fill_fi (CamelStore *store,
 {
        CamelFolder *folder;
 
-       folder = camel_object_bag_peek (store->folders, fi->full_name);
+       folder = camel_object_bag_peek (camel_store_get_folders_bag (store), fi->full_name);
        if (folder) {
                if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
                        camel_folder_refresh_info_sync (folder, cancellable, NULL);
@@ -476,7 +476,7 @@ fill_fi (CamelStore *store,
                g_free (root);
 
                s = (CamelFolderSummary *) camel_maildir_summary_new (NULL, folderpath, NULL);
-               if (camel_folder_summary_header_load_from_db (s, store, fi->full_name, NULL)) {
+               if (camel_folder_summary_header_load (s, store, fi->full_name, NULL)) {
                        fi->unread = camel_folder_summary_get_unread_count (s);
                        fi->total = camel_folder_summary_get_saved_count (s);
                }
diff --git a/src/camel/providers/local/camel-maildir-store.h b/src/camel/providers/local/camel-maildir-store.h
index d949597..dbae0da 100644
--- a/src/camel/providers/local/camel-maildir-store.h
+++ b/src/camel/providers/local/camel-maildir-store.h
@@ -54,6 +54,9 @@ struct _CamelMaildirStore {
 
 struct _CamelMaildirStoreClass {
        CamelLocalStoreClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_maildir_store_get_type (void);
diff --git a/src/camel/providers/local/camel-maildir-summary.c 
b/src/camel/providers/local/camel-maildir-summary.c
index 2c5a56b..7b240f6 100644
--- a/src/camel/providers/local/camel-maildir-summary.c
+++ b/src/camel/providers/local/camel-maildir-summary.c
@@ -36,6 +36,7 @@
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 
+#include "camel-maildir-message-info.h"
 #include "camel-maildir-summary.h"
 
 #define CAMEL_MAILDIR_SUMMARY_GET_PRIVATE(obj) \
@@ -47,14 +48,8 @@
 #define CAMEL_MAILDIR_SUMMARY_VERSION (0x2000)
 
 static CamelMessageInfo *
-               message_info_new_from_header    (CamelFolderSummary *,
-                                                struct _camel_header_raw *);
-static CamelMessageInfo *
-               maildir_message_info_from_db    (CamelFolderSummary *summary,
-                                                CamelMIRecord *record);
-static void    message_info_free               (CamelFolderSummary *,
-                                                CamelMessageInfo *mi);
-
+               message_info_new_from_headers   (CamelFolderSummary *,
+                                                const CamelNameValueArray *);
 static gint    maildir_summary_load            (CamelLocalSummary *cls,
                                                 gint forceindex,
                                                 GError **error);
@@ -78,10 +73,10 @@ static gchar *      maildir_summary_next_uid_string (CamelFolderSummary *s);
 static gint    maildir_summary_decode_x_evolution
                                                (CamelLocalSummary *cls,
                                                 const gchar *xev,
-                                                CamelLocalMessageInfo *mi);
+                                                CamelMessageInfo *mi);
 static gchar * maildir_summary_encode_x_evolution
                                                (CamelLocalSummary *cls,
-                                                const CamelLocalMessageInfo *mi);
+                                                const CamelMessageInfo *mi);
 
 typedef struct _CamelMaildirMessageContentInfo CamelMaildirMessageContentInfo;
 
@@ -129,11 +124,10 @@ camel_maildir_summary_class_init (CamelMaildirSummaryClass *class)
        object_class->finalize = maildir_summary_finalize;
 
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
-       folder_summary_class->message_info_size = sizeof (CamelMaildirMessageInfo);
-       folder_summary_class->content_info_size = sizeof (CamelMaildirMessageContentInfo);
-       folder_summary_class->message_info_new_from_header = message_info_new_from_header;
-       folder_summary_class->message_info_from_db = maildir_message_info_from_db;
-       folder_summary_class->message_info_free = message_info_free;
+       folder_summary_class->message_info_type = CAMEL_TYPE_MAILDIR_MESSAGE_INFO;
+       folder_summary_class->sort_by = "dreceived";
+       folder_summary_class->collate = NULL;
+       folder_summary_class->message_info_new_from_headers = message_info_new_from_headers;
        folder_summary_class->next_uid_string = maildir_summary_next_uid_string;
 
        local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (class);
@@ -157,7 +151,7 @@ camel_maildir_summary_init (CamelMaildirSummary *maildir_summary)
                CAMEL_MAILDIR_SUMMARY_GET_PRIVATE (maildir_summary);
 
        /* set unique file version */
-       folder_summary->version += CAMEL_MAILDIR_SUMMARY_VERSION;
+       camel_folder_summary_set_version (folder_summary, camel_folder_summary_get_version (folder_summary) + 
CAMEL_MAILDIR_SUMMARY_VERSION);
 
        if (gethostname (hostname, 256) == 0) {
                maildir_summary->priv->hostname = g_strdup (hostname);
@@ -186,9 +180,7 @@ CamelMaildirSummary
                CamelStore *parent_store;
 
                parent_store = camel_folder_get_parent_store (folder);
-               camel_db_set_collate (parent_store->cdb_r, "dreceived", NULL, NULL);
-               ((CamelFolderSummary *) o)->sort_by = "dreceived";
-               ((CamelFolderSummary *) o)->collate = NULL;
+               camel_db_set_collate (camel_store_get_db (parent_store), "dreceived", NULL, NULL);
        }
        camel_local_summary_construct ((CamelLocalSummary *) o, maildirdir, index);
        return o;
@@ -208,17 +200,20 @@ static struct {
 };
 
 /* convert the uid + flags into a unique:info maildir format */
-gchar *camel_maildir_summary_info_to_name (const CamelMaildirMessageInfo *info)
+gchar *
+camel_maildir_summary_info_to_name (const CamelMessageInfo *info)
 {
        const gchar *uid;
+       guint32 flags;
        gchar *p, *buf;
        gint i;
 
        uid = camel_message_info_get_uid (info);
        buf = g_alloca (strlen (uid) + strlen (CAMEL_MAILDIR_FLAG_SEP_S "2,") + G_N_ELEMENTS (flagbits) + 1);
        p = buf + sprintf (buf, "%s" CAMEL_MAILDIR_FLAG_SEP_S "2,", uid);
+       flags = camel_message_info_get_flags (info);
        for (i = 0; i < G_N_ELEMENTS (flagbits); i++) {
-               if (info->info.info.flags & flagbits[i].flagbit)
+               if ((flags & flagbits[i].flagbit) != 0)
                        *p++ = flagbits[i].flag;
        }
 
@@ -227,48 +222,48 @@ gchar *camel_maildir_summary_info_to_name (const CamelMaildirMessageInfo *info)
        return g_strdup (buf);
 }
 
-/* returns 0 if the info matches (or there was none), otherwise we changed it */
-gint camel_maildir_summary_name_to_info (CamelMaildirMessageInfo *info, const gchar *name)
+/* returns whether the @info changed */
+gboolean
+camel_maildir_summary_name_to_info (CamelMessageInfo *info,
+                                   const gchar *name)
 {
        gchar *p, c;
        guint32 set = 0;        /* what we set */
-       /*guint32 all = 0;*/    /* all flags */
        gint i;
 
        p = strstr (name, CAMEL_MAILDIR_FLAG_SEP_S "2,");
 
        if (p) {
-               p+=3;
+               guint32 flags;
+
+               flags = camel_message_info_get_flags (info);
+
+               p += 3;
                while ((c = *p++)) {
                        /* we could assume that the flags are in order, but its just as easy not to require */
                        for (i = 0; i < G_N_ELEMENTS (flagbits); i++) {
-                               if (flagbits[i].flag == c && (info->info.info.flags & flagbits[i].flagbit) == 
0) {
+                               if (flagbits[i].flag == c && (flags & flagbits[i].flagbit) == 0) {
                                        set |= flagbits[i].flagbit;
                                }
-                               /*all |= flagbits[i].flagbit;*/
                        }
                }
 
                /* changed? */
-               /*if ((info->flags & all) != set) {*/
-               if ((info->info.info.flags & set) != set) {
-                       /* ok, they did change, only add the new flags ('merge flags'?) */
-                       /*info->flags &= all;  if we wanted to set only the new flags, which we probably dont 
*/
-                       info->info.info.flags |= set;
-                       return 1;
+               if ((flags & set) != set) {
+                       return camel_message_info_set_flags (info, set, set);
                }
        }
 
-       return 0;
+       return FALSE;
 }
 
 /* for maildir, x-evolution isn't used, so dont try and get anything out of it */
-static gint maildir_summary_decode_x_evolution (CamelLocalSummary *cls, const gchar *xev, 
CamelLocalMessageInfo *mi)
+static gint maildir_summary_decode_x_evolution (CamelLocalSummary *cls, const gchar *xev, CamelMessageInfo 
*mi)
 {
        return -1;
 }
 
-static gchar *maildir_summary_encode_x_evolution (CamelLocalSummary *cls, const CamelLocalMessageInfo *mi)
+static gchar *maildir_summary_encode_x_evolution (CamelLocalSummary *cls, const CamelMessageInfo *mi)
 {
        return NULL;
 }
@@ -284,16 +279,17 @@ maildir_summary_add (CamelLocalSummary *cls,
                      GError **error)
 {
        CamelLocalSummaryClass *local_summary_class;
-       CamelMaildirMessageInfo *mi;
+       CamelMessageInfo *mi;
 
        /* Chain up to parent's add() method. */
        local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (camel_maildir_summary_parent_class);
-       mi = (CamelMaildirMessageInfo *) local_summary_class->add (
-               cls, msg, info, changes, error);
+       mi = local_summary_class->add (cls, msg, info, changes, error);
        if (mi) {
                if (info) {
-                       camel_maildir_info_set_filename (mi, camel_maildir_summary_info_to_name (mi));
-                       d (printf ("Setting filename to %s\n", camel_maildir_info_filename (mi)));
+                       CamelMaildirMessageInfo *mdi = CAMEL_MAILDIR_MESSAGE_INFO (mi);
+
+                       camel_maildir_message_info_take_filename (mdi, camel_maildir_summary_info_to_name 
(mi));
+                       d (printf ("Setting filename to %s\n", camel_maildir_message_info_get_filename 
(mdi)));
 
                        /* Inherit the Received date from the passed-in info only if it is set and
                           the new message info doesn't have it set or it's set to the default
@@ -302,42 +298,43 @@ maildir_summary_add (CamelLocalSummary *cls,
                            (camel_message_info_get_date_received (mi) <= 0 ||
                            (camel_message_info_get_uid (mi) &&
                             camel_message_info_get_date_received (mi) == strtoul (camel_message_info_get_uid 
(mi), NULL, 10))))
-                               mi->info.info.date_received = camel_message_info_get_date_received (info);
+                               camel_message_info_set_date_received (mi, 
camel_message_info_get_date_received (info));
                }
        }
 
-       return (CamelMessageInfo *) mi;
+       return mi;
 }
 
 static CamelMessageInfo *
-message_info_new_from_header (CamelFolderSummary *s,
-                              struct _camel_header_raw *h)
+message_info_new_from_headers (CamelFolderSummary *summary,
+                              const CamelNameValueArray *headers)
 {
        CamelMessageInfo *mi, *info;
-       CamelMaildirSummary *mds = (CamelMaildirSummary *) s;
-       CamelMaildirMessageInfo *mdi;
+       CamelMaildirSummary *mds = (CamelMaildirSummary *) summary;
        const gchar *uid;
 
-       mi = ((CamelFolderSummaryClass *) camel_maildir_summary_parent_class)->message_info_new_from_header 
(s, h);
+       mi = ((CamelFolderSummaryClass *) camel_maildir_summary_parent_class)->message_info_new_from_headers 
(summary, headers);
        /* assign the uid and new filename */
        if (mi) {
-               mdi = (CamelMaildirMessageInfo *) mi;
-
                uid = camel_message_info_get_uid (mi);
-               if (uid == NULL || uid[0] == 0)
-                       mdi->info.info.uid = camel_pstring_add (camel_folder_summary_next_uid_string (s), 
TRUE);
+               if (uid == NULL || uid[0] == 0) {
+                       gchar *new_uid = camel_folder_summary_next_uid_string (summary);
+
+                       camel_message_info_set_uid (mi, new_uid);
+                       g_free (new_uid);
+               }
 
                /* handle 'duplicates' */
-               info = camel_folder_summary_peek_loaded (s, uid);
+               info = (uid && *uid) ? camel_folder_summary_peek_loaded (summary, uid) : NULL;
                if (info) {
                        d (printf ("already seen uid '%s', just summarising instead\n", uid));
-                       camel_message_info_unref (mi);
-                       mdi = (CamelMaildirMessageInfo *)(mi = info);
+                       g_clear_object (&mi);
+                       mi = info;
                }
 
-               if (mdi->info.info.date_received <= 0) {
+               if (camel_message_info_get_date_received (mi) <= 0) {
                        /* with maildir we know the real received date, from the filename */
-                       mdi->info.info.date_received = strtoul (camel_message_info_get_uid (mi), NULL, 10);
+                       camel_message_info_set_date_received (mi, strtoul (camel_message_info_get_uid (mi), 
NULL, 10));
                }
 
                if (mds->priv->current_file) {
@@ -346,8 +343,8 @@ message_info_new_from_header (CamelFolderSummary *s,
                        gulong uid;
 #endif
                        /* if setting from a file, grab the flags from it */
-                       camel_maildir_info_set_filename (mi, g_strdup (mds->priv->current_file));
-                       camel_maildir_summary_name_to_info (mdi, mds->priv->current_file);
+                       camel_maildir_message_info_take_filename (CAMEL_MAILDIR_MESSAGE_INFO (mi), g_strdup 
(mds->priv->current_file));
+                       camel_maildir_summary_name_to_info (mi, mds->priv->current_file);
 
 #if 0
                        /* Actually, I dont think all this effort is worth it at all ... */
@@ -367,42 +364,16 @@ message_info_new_from_header (CamelFolderSummary *s,
 #endif
                } else {
                        /* if creating a file, set its name from the flags we have */
-                       camel_maildir_info_set_filename (mdi, camel_maildir_summary_info_to_name (mdi));
-                       d (printf ("Setting filename to %s\n", camel_maildir_info_filename (mi)));
+                       camel_maildir_message_info_take_filename (CAMEL_MAILDIR_MESSAGE_INFO (mi), 
camel_maildir_summary_info_to_name (mi));
+                       d (printf ("Setting filename to %s\n", camel_maildir_message_info_get_filename 
(CAMEL_MAILDIR_MESSAGE_INFO (mi))));
                }
        }
 
        return mi;
 }
 
-static CamelMessageInfo *
-maildir_message_info_from_db (CamelFolderSummary *summary,
-                              CamelMIRecord *record)
-{
-       CamelMessageInfo *mi;
-
-       mi = ((CamelFolderSummaryClass *) camel_maildir_summary_parent_class)->message_info_from_db (summary, 
record);
-       if (mi) {
-               CamelMaildirMessageInfo *mdi = (CamelMaildirMessageInfo *) mi;
-
-               camel_maildir_info_set_filename (mdi, camel_maildir_summary_info_to_name (mdi));
-       }
-
-       return mi;
-}
-
-static void
-message_info_free (CamelFolderSummary *s,
-                   CamelMessageInfo *mi)
-{
-       CamelMaildirMessageInfo *mdi = (CamelMaildirMessageInfo *) mi;
-
-       g_free (mdi->filename);
-
-       ((CamelFolderSummaryClass *) camel_maildir_summary_parent_class)->message_info_free (s, mi);
-}
-
-static gchar *maildir_summary_next_uid_string (CamelFolderSummary *s)
+static gchar *
+maildir_summary_next_uid_string (CamelFolderSummary *s)
 {
        CamelMaildirSummary *mds = (CamelMaildirSummary *) s;
 
@@ -546,7 +517,8 @@ camel_maildir_summary_add (CamelLocalSummary *cls,
        maildirs->priv->current_file = (gchar *) name;
 
        info = camel_folder_summary_info_new_from_parser (summary, mp);
-       camel_folder_summary_add (summary, info);
+       camel_folder_summary_add (summary, info, FALSE);
+       g_clear_object (&info);
 
        g_object_unref (mp);
        maildirs->priv->current_file = NULL;
@@ -571,7 +543,7 @@ remove_summary (gchar *key,
        if (rd->changes)
                camel_folder_change_info_remove_uid (rd->changes, key);
        camel_folder_summary_remove ((CamelFolderSummary *) rd->cls, info);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 }
 
 static gint
@@ -667,7 +639,7 @@ maildir_summary_check (CamelLocalSummary *cls,
                info = g_hash_table_lookup (left, uid);
                if (info) {
                        g_hash_table_remove (left, uid);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
 
                info = camel_folder_summary_get ((CamelFolderSummary *) cls, uid);
@@ -685,13 +657,12 @@ maildir_summary_check (CamelLocalSummary *cls,
                        }
 
                        mdi = (CamelMaildirMessageInfo *) info;
-                       filename = camel_maildir_info_filename (mdi);
+                       filename = camel_maildir_message_info_get_filename (mdi);
                        /* TODO: only store the extension in the mdi->filename struct, not the whole lot */
                        if (filename == NULL || strcmp (filename, d->d_name) != 0) {
-                               g_free (mdi->filename);
-                               mdi->filename = g_strdup (d->d_name);
+                               camel_maildir_message_info_set_filename (mdi, d->d_name);
                        }
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
                g_free (uid);
        }
@@ -734,7 +705,7 @@ maildir_summary_check (CamelLocalSummary *cls,
 
                        /* already in summary?  shouldn't happen, but just incase ... */
                        if ((info = camel_folder_summary_get ((CamelFolderSummary *) cls, name))) {
-                               camel_message_info_unref (info);
+                               g_clear_object (&info);
                                newname = destname = camel_folder_summary_next_uid_string (s);
                        } else {
                                gchar *nm;
@@ -813,9 +784,9 @@ maildir_summary_sync (CamelLocalSummary *cls,
                camel_operation_progress (cancellable, (known_uids->len - i) * 100 / known_uids->len);
 
                info = camel_folder_summary_get ((CamelFolderSummary *) cls, g_ptr_array_index (known_uids, 
i));
-               mdi = (CamelMaildirMessageInfo *) info;
-               if (mdi && (mdi->info.info.flags & CAMEL_MESSAGE_DELETED) && expunge) {
-                       name = g_strdup_printf ("%s/cur/%s", cls->folder_path, camel_maildir_info_filename 
(mdi));
+               mdi = CAMEL_MAILDIR_MESSAGE_INFO (info);
+               if (mdi && (camel_message_info_get_flags (info) & CAMEL_MESSAGE_DELETED) != 0 && expunge) {
+                       name = g_strdup_printf ("%s/cur/%s", cls->folder_path, 
camel_maildir_message_info_get_filename (mdi));
                        d (printf ("deleting %s\n", name));
                        if (unlink (name) == 0 || errno == ENOENT) {
 
@@ -827,16 +798,16 @@ maildir_summary_sync (CamelLocalSummary *cls,
                                removed_uids = g_list_prepend (removed_uids, (gpointer) camel_pstring_strdup 
(camel_message_info_get_uid (info)));
                        }
                        g_free (name);
-               } else if (mdi && (mdi->info.info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
-                       gchar *newname = camel_maildir_summary_info_to_name (mdi);
+               } else if (mdi && camel_message_info_get_folder_flagged (info)) {
+                       gchar *newname = camel_maildir_summary_info_to_name (info);
                        gchar *dest;
 
                        /* do we care about additional metainfo stored inside the message? */
                        /* probably should all go in the filename? */
 
                        /* have our flags/ i.e. name changed? */
-                       if (strcmp (newname, camel_maildir_info_filename (mdi))) {
-                               name = g_strdup_printf ("%s/cur/%s", cls->folder_path, 
camel_maildir_info_filename (mdi));
+                       if (strcmp (newname, camel_maildir_message_info_get_filename (mdi))) {
+                               name = g_strdup_printf ("%s/cur/%s", cls->folder_path, 
camel_maildir_message_info_get_filename (mdi));
                                dest = g_strdup_printf ("%s/cur/%s", cls->folder_path, newname);
                                if (g_rename (name, dest) == -1) {
                                        g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC, name, 
dest, g_strerror (errno));
@@ -848,19 +819,18 @@ maildir_summary_sync (CamelLocalSummary *cls,
                                        /* TODO: If this is made mt-safe, then this code could be a problem, 
since
                                         * the estrv is being modified.
                                         * Sigh, this may mean the maildir name has to be cached another way 
*/
-                                       g_free (mdi->filename);
-                                       mdi->filename = newname;
+                                       camel_maildir_message_info_set_filename (mdi, newname);
                                }
                                g_free (name);
                                g_free (dest);
-                       } else {
-                               g_free (newname);
                        }
 
+                       g_free (newname);
+
                        /* strip FOLDER_MESSAGE_FLAGED, etc */
-                       mdi->info.info.flags &= 0xffff;
+                       camel_message_info_set_flags (info, 0xffff, camel_message_info_get_flags (info));
                }
-               camel_message_info_unref (info);
+               g_clear_object (&info);
        }
 
        if (removed_uids) {
@@ -875,4 +845,3 @@ maildir_summary_sync (CamelLocalSummary *cls,
        local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (camel_maildir_summary_parent_class);
        return local_summary_class->sync (cls, expunge, changes, cancellable, error);
 }
-
diff --git a/src/camel/providers/local/camel-maildir-summary.h 
b/src/camel/providers/local/camel-maildir-summary.h
index 77cbdd3..e188b54 100644
--- a/src/camel/providers/local/camel-maildir-summary.h
+++ b/src/camel/providers/local/camel-maildir-summary.h
@@ -19,6 +19,7 @@
 #ifndef CAMEL_MAILDIR_SUMMARY_H
 #define CAMEL_MAILDIR_SUMMARY_H
 
+#include "camel-maildir-message-info.h"
 #include "camel-local-summary.h"
 
 /* Standard GObject macros */
@@ -54,12 +55,6 @@ typedef struct _CamelMaildirSummary CamelMaildirSummary;
 typedef struct _CamelMaildirSummaryClass CamelMaildirSummaryClass;
 typedef struct _CamelMaildirSummaryPrivate CamelMaildirSummaryPrivate;
 
-typedef struct _CamelMaildirMessageInfo {
-       CamelLocalMessageInfo info;
-
-       gchar *filename;                /* maildir has this annoying status on the end of the filename, use 
this to get the real message id */
-} CamelMaildirMessageInfo;
-
 struct _CamelMaildirSummary {
        CamelLocalSummary parent;
        CamelMaildirSummaryPrivate *priv;
@@ -67,18 +62,17 @@ struct _CamelMaildirSummary {
 
 struct _CamelMaildirSummaryClass {
        CamelLocalSummaryClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType   camel_maildir_summary_get_type (void);
 CamelMaildirSummary    *camel_maildir_summary_new      (struct _CamelFolder *folder, const gchar 
*maildirdir, CamelIndex *index);
 
 /* convert some info->flags to/from the messageinfo */
-gchar *camel_maildir_summary_info_to_name (const CamelMaildirMessageInfo *info);
-gint camel_maildir_summary_name_to_info (CamelMaildirMessageInfo *info, const gchar *name);
-
-/* TODO: could proably use get_string stuff */
-#define camel_maildir_info_filename(x) (((CamelMaildirMessageInfo *)x)->filename)
-#define camel_maildir_info_set_filename(x, s) (g_free(((CamelMaildirMessageInfo 
*)x)->filename),((CamelMaildirMessageInfo *)x)->filename = s)
+gchar *camel_maildir_summary_info_to_name (const CamelMessageInfo *info);
+gboolean camel_maildir_summary_name_to_info (CamelMessageInfo *info, const gchar *name);
 
 G_END_DECLS
 
diff --git a/src/camel/providers/local/camel-mbox-folder.c b/src/camel/providers/local/camel-mbox-folder.c
index 56ca428..094772c 100644
--- a/src/camel/providers/local/camel-mbox-folder.c
+++ b/src/camel/providers/local/camel-mbox-folder.c
@@ -33,6 +33,7 @@
 #include <glib/gstdio.h>
 
 #include "camel-mbox-folder.h"
+#include "camel-mbox-message-info.h"
 #include "camel-mbox-store.h"
 #include "camel-mbox-summary.h"
 
@@ -50,20 +51,21 @@ mbox_folder_cmp_uids (CamelFolder *folder,
                       const gchar *uid2)
 {
        CamelMboxMessageInfo *a, *b;
+       goffset aoffset, boffset;
        gint res;
 
        g_return_val_if_fail (folder != NULL, 0);
-       g_return_val_if_fail (folder->summary != NULL, 0);
+       g_return_val_if_fail (camel_folder_get_folder_summary (folder) != NULL, 0);
 
-       a = (CamelMboxMessageInfo *) camel_folder_summary_get (folder->summary, uid1);
-       b = (CamelMboxMessageInfo *) camel_folder_summary_get (folder->summary, uid2);
+       a = (CamelMboxMessageInfo *) camel_folder_summary_get (camel_folder_get_folder_summary (folder), 
uid1);
+       b = (CamelMboxMessageInfo *) camel_folder_summary_get (camel_folder_get_folder_summary (folder), 
uid2);
 
        if (!a || !b) {
                /* It's not a problem when one of the messages is not in the summary */
                if (a)
-                       camel_message_info_unref (a);
+                       g_object_unref (a);
                if (b)
-                       camel_message_info_unref (b);
+                       g_object_unref (b);
 
                if (a == b)
                        return 0;
@@ -72,10 +74,13 @@ mbox_folder_cmp_uids (CamelFolder *folder,
                return 1;
        }
 
-       res = a->frompos < b->frompos ? -1 : a->frompos == b->frompos ? 0 : 1;
+       aoffset = camel_mbox_message_info_get_offset (a);
+       boffset = camel_mbox_message_info_get_offset (b);
 
-       camel_message_info_unref (a);
-       camel_message_info_unref (b);
+       res = aoffset < boffset ? -1 : aoffset == boffset ? 0 : 1;
+
+       g_clear_object (&a);
+       g_clear_object (&b);
 
        return res;
 }
@@ -88,7 +93,7 @@ mbox_folder_sort_uids (CamelFolder *folder,
        g_return_if_fail (folder != NULL);
 
        if (uids && uids->len > 1)
-               camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
+               camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary (folder), NULL);
 
        CAMEL_FOLDER_CLASS (camel_mbox_folder_parent_class)->sort_uids (folder, uids);
 }
@@ -100,7 +105,6 @@ mbox_folder_get_filename (CamelFolder *folder,
 {
        CamelLocalFolder *lf = (CamelLocalFolder *) folder;
        CamelMboxMessageInfo *info;
-       goffset frompos;
        gchar *filename = NULL;
 
        d (printf ("Getting message %s\n", uid));
@@ -110,32 +114,28 @@ mbox_folder_get_filename (CamelFolder *folder,
                return NULL;
 
        /* check for new messages always */
-       if (camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, NULL, error) == 
-1) {
+       if (camel_local_summary_check ((CamelLocalSummary *) camel_folder_get_folder_summary (folder), 
lf->changes, NULL, error) == -1) {
                camel_local_folder_unlock (lf);
                return NULL;
        }
 
        /* get the message summary info */
-       info = (CamelMboxMessageInfo *) camel_folder_summary_get (folder->summary, uid);
+       info = (CamelMboxMessageInfo *) camel_folder_summary_get (camel_folder_get_folder_summary (folder), 
uid);
 
        if (info == NULL) {
                set_cannot_get_message_ex (
                        error, CAMEL_FOLDER_ERROR_INVALID_UID,
                        uid, lf->folder_path, _("No such message"));
-               goto fail;
-       }
+       } else {
+               goffset frompos;
 
-       if (info->frompos == -1) {
-               camel_message_info_unref (info);
-               goto fail;
-       }
+               frompos = camel_mbox_message_info_get_offset (info);
+               g_clear_object (&info);
 
-       frompos = info->frompos;
-       camel_message_info_unref (info);
-
-       filename = g_strdup_printf ("%s%s!%" PRId64, lf->folder_path, G_DIR_SEPARATOR_S, (gint64) frompos);
+               if (frompos != -1)
+                       filename = g_strdup_printf ("%s%s!%" G_GINT64_FORMAT, lf->folder_path, 
G_DIR_SEPARATOR_S, (gint64) frompos);
+       }
 
-fail:
        /* and unlock now we're finished with it */
        camel_local_folder_unlock (lf);
 
@@ -153,8 +153,8 @@ mbox_folder_append_message_sync (CamelFolder *folder,
        CamelLocalFolder *lf = (CamelLocalFolder *) folder;
        CamelStream *output_stream = NULL, *filter_stream = NULL;
        CamelMimeFilter *filter_from;
-       CamelMboxSummary *mbs = (CamelMboxSummary *) folder->summary;
-       CamelMessageInfo *mi;
+       CamelMboxSummary *mbs = (CamelMboxSummary *) camel_folder_get_folder_summary (folder);
+       CamelMessageInfo *mi = NULL;
        gchar *fromline = NULL;
        struct stat st;
        gint retval;
@@ -169,12 +169,12 @@ mbox_folder_append_message_sync (CamelFolder *folder,
        d (printf ("Appending message\n"));
 
        /* first, check the summary is correct (updates folder_size too) */
-       retval = camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, cancellable, 
error);
+       retval = camel_local_summary_check ((CamelLocalSummary *) camel_folder_get_folder_summary (folder), 
lf->changes, cancellable, error);
        if (retval == -1)
                goto fail;
 
        /* add it to the summary/assign the uid, etc */
-       mi = camel_local_summary_add ((CamelLocalSummary *) folder->summary, message, info, lf->changes, 
error);
+       mi = camel_local_summary_add ((CamelLocalSummary *) camel_folder_get_folder_summary (folder), 
message, info, lf->changes, error);
        if (mi == NULL)
                goto fail;
 
@@ -197,13 +197,13 @@ mbox_folder_append_message_sync (CamelFolder *folder,
        }
 
        /* and we need to set the frompos/XEV explicitly */
-       ((CamelMboxMessageInfo *) mi)->frompos = mbs->folder_size;
+       camel_mbox_message_info_set_offset (CAMEL_MBOX_MESSAGE_INFO (mi), mbs->folder_size);
 #if 0
-       xev = camel_local_summary_encode_x_evolution ((CamelLocalSummary *) folder->summary, mi);
+       xev = camel_local_summary_encode_x_evolution ((CamelLocalSummary *) camel_folder_get_folder_summary 
(folder), mi);
        if (xev) {
                /* the x-ev header should match the 'current' flags, no problem, so store as much */
                camel_medium_set_header ((CamelMedium *) message, "X-Evolution", xev);
-               mi->flags &= ~ CAMEL_MESSAGE_FOLDER_NOXEV | CAMEL_MESSAGE_FOLDER_FLAGGED;
+               camel_mesage_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_NOXEV | CAMEL_MESSAGE_FOLDER_FLAGGED, 
0);
                g_free (xev);
        }
 #endif
@@ -230,15 +230,10 @@ mbox_folder_append_message_sync (CamelFolder *folder,
        g_object_unref (output_stream);
        g_free (fromline);
 
-       if (!((CamelMessageInfoBase *) mi)->preview && camel_folder_summary_get_need_preview 
(folder->summary)) {
-               if (camel_mime_message_build_preview ((CamelMimePart *) message, mi) && 
((CamelMessageInfoBase *) mi)->preview)
-                       camel_folder_summary_add_preview (folder->summary, mi);
-       }
-
        /* now we 'fudge' the summary  to tell it its uptodate, because its idea of uptodate has just changed 
*/
        /* the stat really shouldn't fail, we just wrote to it */
        if (g_stat (lf->folder_path, &st) == 0) {
-               ((CamelFolderSummary *) mbs)->time = st.st_mtime;
+               camel_folder_summary_set_timestamp (CAMEL_FOLDER_SUMMARY (mbs), st.st_mtime);
                mbs->folder_size = st.st_size;
        }
 
@@ -253,6 +248,8 @@ mbox_folder_append_message_sync (CamelFolder *folder,
        if (appended_uid)
                *appended_uid = g_strdup(camel_message_info_get_uid(mi));
 
+       g_clear_object (&mi);
+
        return TRUE;
 
 fail_write:
@@ -284,7 +281,7 @@ fail_write:
 
        /* and tell the summary it's up-to-date */
        if (g_stat (lf->folder_path, &st) == 0) {
-               ((CamelFolderSummary *) mbs)->time = st.st_mtime;
+               camel_folder_summary_set_timestamp (CAMEL_FOLDER_SUMMARY (mbs), st.st_mtime);
                mbs->folder_size = st.st_size;
        }
 
@@ -298,6 +295,8 @@ fail:
                camel_folder_change_info_clear (lf->changes);
        }
 
+       g_clear_object (&mi);
+
        return FALSE;
 }
 
@@ -322,14 +321,14 @@ mbox_folder_get_message_sync (CamelFolder *folder,
                return NULL;
 
        /* check for new messages always */
-       if (camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, cancellable, 
error) == -1) {
+       if (camel_local_summary_check ((CamelLocalSummary *) camel_folder_get_folder_summary (folder), 
lf->changes, cancellable, error) == -1) {
                camel_local_folder_unlock (lf);
                return NULL;
        }
 
 retry:
        /* get the message summary info */
-       info = (CamelMboxMessageInfo *) camel_folder_summary_get (folder->summary, uid);
+       info = (CamelMboxMessageInfo *) camel_folder_summary_get (camel_folder_get_folder_summary (folder), 
uid);
 
        if (info == NULL) {
                set_cannot_get_message_ex (
@@ -338,13 +337,11 @@ retry:
                goto fail;
        }
 
-       if (info->frompos == -1) {
-               camel_message_info_unref (info);
-               goto fail;
-       }
+       frompos = camel_mbox_message_info_get_offset (CAMEL_MBOX_MESSAGE_INFO (info));
+       g_clear_object (&info);
 
-       frompos = info->frompos;
-       camel_message_info_unref (info);
+       if (frompos == -1)
+               goto fail;
 
        /* we use an fd instead of a normal stream here - the reason is subtle, camel_mime_part will cache
         * the whole message in memory if the stream is non-seekable (which it is when built from a parser
@@ -378,8 +375,8 @@ retry:
 
                if (!retried) {
                        retried = TRUE;
-                       camel_local_summary_check_force ((CamelLocalSummary *) folder->summary);
-                       retval = camel_local_summary_check ((CamelLocalSummary *) folder->summary, 
lf->changes, cancellable, error);
+                       camel_local_summary_check_force ((CamelLocalSummary *) 
camel_folder_get_folder_summary (folder));
+                       retval = camel_local_summary_check ((CamelLocalSummary *) 
camel_folder_get_folder_summary (folder), lf->changes, cancellable, error);
                        if (retval != -1)
                                goto retry;
                }
diff --git a/src/camel/providers/local/camel-mbox-folder.h b/src/camel/providers/local/camel-mbox-folder.h
index f309d02..1e72efa 100644
--- a/src/camel/providers/local/camel-mbox-folder.h
+++ b/src/camel/providers/local/camel-mbox-folder.h
@@ -55,6 +55,9 @@ struct _CamelMboxFolder {
 
 struct _CamelMboxFolderClass {
        CamelLocalFolderClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mbox_folder_get_type      (void);
diff --git a/src/camel/providers/local/camel-mbox-message-info.c 
b/src/camel/providers/local/camel-mbox-message-info.c
new file mode 100644
index 0000000..9a278e4
--- /dev/null
+++ b/src/camel/providers/local/camel-mbox-message-info.c
@@ -0,0 +1,255 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+
+#include "camel/camel.h"
+#include "camel-mbox-summary.h"
+
+#include "camel-mbox-message-info.h"
+
+struct _CamelMboxMessageInfoPrivate {
+       goffset offset;
+};
+
+enum {
+       PROP_0,
+       PROP_OFFSET
+};
+
+G_DEFINE_TYPE (CamelMboxMessageInfo, camel_mbox_message_info, CAMEL_TYPE_MESSAGE_INFO_BASE)
+
+static CamelMessageInfo *
+mbox_message_info_clone (const CamelMessageInfo *mi,
+                        CamelFolderSummary *assign_summary)
+{
+       CamelMessageInfo *result;
+
+       g_return_val_if_fail (CAMEL_IS_MBOX_MESSAGE_INFO (mi), NULL);
+
+       result = CAMEL_MESSAGE_INFO_CLASS (camel_mbox_message_info_parent_class)->clone (mi, assign_summary);
+       if (!result)
+               return NULL;
+
+       if (CAMEL_IS_MBOX_MESSAGE_INFO (result)) {
+               CamelMboxMessageInfo *mmi, *mmi_result;
+
+               mmi = CAMEL_MBOX_MESSAGE_INFO (mi);
+               mmi_result = CAMEL_MBOX_MESSAGE_INFO (result);
+
+               camel_mbox_message_info_set_offset (mmi_result, camel_mbox_message_info_get_offset (mmi));
+       }
+
+       return result;
+}
+
+static gboolean
+mbox_message_info_load (CamelMessageInfo *mi,
+                       const CamelMIRecord *record,
+                       /* const */ gchar **bdata_ptr)
+{
+       CamelMboxMessageInfo *mmi;
+       gint64 offset;
+
+       g_return_val_if_fail (CAMEL_IS_MBOX_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       if (!CAMEL_MESSAGE_INFO_CLASS (camel_mbox_message_info_parent_class)->load ||
+           !CAMEL_MESSAGE_INFO_CLASS (camel_mbox_message_info_parent_class)->load (mi, record, bdata_ptr))
+               return FALSE;
+
+       mmi = CAMEL_MBOX_MESSAGE_INFO (mi);
+
+       offset = camel_util_bdata_get_number (bdata_ptr, -1);
+       if (offset < 0)
+               return FALSE;
+
+       camel_mbox_message_info_set_offset (mmi, offset);
+
+       return TRUE;
+}
+
+static gboolean
+mbox_message_info_save (const CamelMessageInfo *mi,
+                       CamelMIRecord *record,
+                       GString *bdata_str)
+{
+       CamelMboxMessageInfo *mmi;
+
+       g_return_val_if_fail (CAMEL_IS_MBOX_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_str != NULL, FALSE);
+
+       if (!CAMEL_MESSAGE_INFO_CLASS (camel_mbox_message_info_parent_class)->save ||
+           !CAMEL_MESSAGE_INFO_CLASS (camel_mbox_message_info_parent_class)->save (mi, record, bdata_str))
+               return FALSE;
+
+       mmi = CAMEL_MBOX_MESSAGE_INFO (mi);
+
+       camel_util_bdata_put_number (bdata_str, camel_mbox_message_info_get_offset (mmi));
+
+       return TRUE;
+}
+
+static gboolean
+mbox_message_info_set_flags (CamelMessageInfo *mi,
+                            guint32 mask,
+                            guint32 set)
+{
+       CamelFolderSummary *summary;
+       CamelMboxSummary *mbox_summary;
+
+       summary = camel_message_info_ref_summary (mi);
+       mbox_summary = summary ? CAMEL_MBOX_SUMMARY (summary) : NULL;
+
+       /* Basically, if anything could change the Status line, presume it does */
+       if (mbox_summary && mbox_summary->xstatus
+           && (mask & (CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_ANSWERED | 
CAMEL_MESSAGE_DELETED))) {
+               mask |= CAMEL_MESSAGE_FOLDER_XEVCHANGE | CAMEL_MESSAGE_FOLDER_FLAGGED;
+               set |= CAMEL_MESSAGE_FOLDER_XEVCHANGE | CAMEL_MESSAGE_FOLDER_FLAGGED;
+       }
+
+       g_clear_object (&summary);
+
+       return CAMEL_MESSAGE_INFO_CLASS (camel_mbox_message_info_parent_class)->set_flags (mi, mask, set);
+}
+
+static void
+mbox_message_info_set_property (GObject *object,
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+       CamelMboxMessageInfo *mmi = CAMEL_MBOX_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_OFFSET:
+               camel_mbox_message_info_set_offset (mmi, g_value_get_int64 (value));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mbox_message_info_get_property (GObject *object,
+                               guint property_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+       CamelMboxMessageInfo *mmi = CAMEL_MBOX_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_OFFSET:
+               g_value_set_int64 (value, camel_mbox_message_info_get_offset (mmi));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+camel_mbox_message_info_class_init (CamelMboxMessageInfoClass *class)
+{
+       CamelMessageInfoClass *mi_class;
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelMboxMessageInfoPrivate));
+
+       mi_class = CAMEL_MESSAGE_INFO_CLASS (class);
+       mi_class->clone = mbox_message_info_clone;
+       mi_class->load = mbox_message_info_load;
+       mi_class->save = mbox_message_info_save;
+       mi_class->set_flags = mbox_message_info_set_flags;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = mbox_message_info_set_property;
+       object_class->get_property = mbox_message_info_get_property;
+
+       /**
+        * CamelMboxMessageInfo:offset
+        *
+        * Offset in the file to the related message.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_OFFSET,
+               g_param_spec_int64 (
+                       "offset",
+                       "Offset",
+                       NULL,
+                       0, G_MAXINT64, 0,
+                       G_PARAM_READWRITE));
+}
+
+static void
+camel_mbox_message_info_init (CamelMboxMessageInfo *mmi)
+{
+       mmi->priv = G_TYPE_INSTANCE_GET_PRIVATE (mmi, CAMEL_TYPE_MBOX_MESSAGE_INFO, 
CamelMboxMessageInfoPrivate);
+}
+
+goffset
+camel_mbox_message_info_get_offset (const CamelMboxMessageInfo *mmi)
+{
+       CamelMessageInfo *mi;
+       goffset result;
+
+       g_return_val_if_fail (CAMEL_IS_MBOX_MESSAGE_INFO (mmi), 0);
+
+       mi = CAMEL_MESSAGE_INFO (mmi);
+
+       camel_message_info_property_lock (mi);
+       result = mmi->priv->offset;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gboolean
+camel_mbox_message_info_set_offset (CamelMboxMessageInfo *mmi,
+                                   goffset offset)
+{
+       CamelMessageInfo *mi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_MBOX_MESSAGE_INFO (mmi), FALSE);
+
+       mi = CAMEL_MESSAGE_INFO (mmi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = mmi->priv->offset != offset;
+
+       if (changed)
+               mmi->priv->offset = offset;
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !camel_message_info_get_abort_notifications (mi)) {
+               g_object_notify (G_OBJECT (mmi), "offset");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
diff --git a/src/camel/providers/local/camel-mbox-message-info.h 
b/src/camel/providers/local/camel-mbox-message-info.h
new file mode 100644
index 0000000..c493d8d
--- /dev/null
+++ b/src/camel/providers/local/camel-mbox-message-info.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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/>.
+ */
+
+#ifndef CAMEL_MBOX_MESSAGE_INFO_H
+#define CAMEL_MBOX_MESSAGE_INFO_H
+
+#include <glib-object.h>
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_MBOX_MESSAGE_INFO \
+       (camel_mbox_message_info_get_type ())
+#define CAMEL_MBOX_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_MBOX_MESSAGE_INFO, CamelMboxMessageInfo))
+#define CAMEL_MBOX_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_MBOX_MESSAGE_INFO, CamelMboxMessageInfoClass))
+#define CAMEL_IS_MBOX_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_MBOX_MESSAGE_INFO))
+#define CAMEL_IS_MBOX_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_MBOX_MESSAGE_INFO))
+#define CAMEL_MBOX_MESSAGE_INFO_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_MBOX_MESSAGE_INFO, CamelMboxMessageInfoClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelMboxMessageInfo CamelMboxMessageInfo;
+typedef struct _CamelMboxMessageInfoClass CamelMboxMessageInfoClass;
+typedef struct _CamelMboxMessageInfoPrivate CamelMboxMessageInfoPrivate;
+
+struct _CamelMboxMessageInfo {
+       CamelMessageInfoBase parent;
+       CamelMboxMessageInfoPrivate *priv;
+};
+
+struct _CamelMboxMessageInfoClass {
+       CamelMessageInfoBaseClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
+};
+
+GType          camel_mbox_message_info_get_type        (void);
+
+goffset                camel_mbox_message_info_get_offset      (const CamelMboxMessageInfo *mmi);
+gboolean       camel_mbox_message_info_set_offset      (CamelMboxMessageInfo *mmi,
+                                                        goffset offset);
+
+G_END_DECLS
+
+#endif /* CAMEL_MBOX_MESSAGE_INFO_H */
diff --git a/src/camel/providers/local/camel-mbox-store.c b/src/camel/providers/local/camel-mbox-store.c
index cff6ff1..01ec20d 100644
--- a/src/camel/providers/local/camel-mbox-store.c
+++ b/src/camel/providers/local/camel-mbox-store.c
@@ -112,7 +112,7 @@ fill_fi (CamelStore *store,
 
        fi->unread = -1;
        fi->total = -1;
-       folder = camel_object_bag_peek (store->folders, fi->full_name);
+       folder = camel_object_bag_peek (camel_store_get_folders_bag (store), fi->full_name);
        if (folder) {
                if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
                        camel_folder_refresh_info_sync (folder, NULL, NULL);
@@ -134,7 +134,7 @@ fill_fi (CamelStore *store,
                mbs = (CamelMboxSummary *) camel_mbox_summary_new (
                        NULL, folderpath, NULL);
                /* FIXME[disk-summary] track exception */
-               if (camel_folder_summary_header_load_from_db ((CamelFolderSummary *) mbs, store, 
fi->full_name, NULL)) {
+               if (camel_folder_summary_header_load ((CamelFolderSummary *) mbs, store, fi->full_name, 
NULL)) {
                        fi->unread = camel_folder_summary_get_unread_count (
                                (CamelFolderSummary *) mbs);
                        fi->total = camel_folder_summary_get_saved_count (
@@ -830,7 +830,7 @@ mbox_store_rename_folder_sync (CamelStore *store,
                newdir = NULL;
        }
 
-       folder = camel_object_bag_get (store->folders, old);
+       folder = camel_object_bag_get (camel_store_get_folders_bag (store), old);
        if (folder && folder->index) {
                if (camel_index_rename (folder->index, newibex) == -1 && errno != ENOENT) {
                        errnosav = errno;
diff --git a/src/camel/providers/local/camel-mbox-store.h b/src/camel/providers/local/camel-mbox-store.h
index be38efd..82b8a56 100644
--- a/src/camel/providers/local/camel-mbox-store.h
+++ b/src/camel/providers/local/camel-mbox-store.h
@@ -52,6 +52,9 @@ struct _CamelMboxStore {
 
 struct _CamelMboxStoreClass {
        CamelLocalStoreClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_mbox_store_get_type (void);
diff --git a/src/camel/providers/local/camel-mbox-summary.c b/src/camel/providers/local/camel-mbox-summary.c
index 4e82fdc..f7c0765 100644
--- a/src/camel/providers/local/camel-mbox-summary.c
+++ b/src/camel/providers/local/camel-mbox-summary.c
@@ -31,14 +31,14 @@
 #include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
 
+#include "camel-mbox-message-info.h"
 #include "camel-mbox-summary.h"
 #include "camel-local-private.h"
 
 #define io(x)
 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
 
-/* Enable the use of elm/pine style "Status" & "X-Status" headers */
-#define STATUS_PINE
+/* This uses elm/pine style "Status" & "X-Status" headers */
 
 #define CAMEL_MBOX_SUMMARY_VERSION (1)
 
@@ -55,26 +55,19 @@ struct _CamelMboxMessageContentInfo {
 };
 
 static CamelFIRecord *
-               summary_header_to_db            (CamelFolderSummary *,
+               summary_header_save             (CamelFolderSummary *,
                                                 GError **error);
-static gboolean        summary_header_from_db          (CamelFolderSummary *,
+static gboolean        summary_header_load             (CamelFolderSummary *,
                                                 CamelFIRecord *);
 static CamelMessageInfo *
-               message_info_from_db            (CamelFolderSummary *s,
-                                                CamelMIRecord *record);
-static CamelMIRecord *
-               message_info_to_db              (CamelFolderSummary *s,
-                                                CamelMessageInfo *info);
-
-static CamelMessageInfo *
-               message_info_new_from_header    (CamelFolderSummary *,
-                                                struct _camel_header_raw *);
+               message_info_new_from_headers   (CamelFolderSummary *,
+                                                const CamelNameValueArray *);
 static CamelMessageInfo *
                message_info_new_from_parser    (CamelFolderSummary *,
                                                 CamelMimeParser *);
 
 static gchar * mbox_summary_encode_x_evolution (CamelLocalSummary *cls,
-                                                const CamelLocalMessageInfo *mi);
+                                                const CamelMessageInfo *mi);
 
 static gint    mbox_summary_check              (CamelLocalSummary *cls,
                                                 CamelFolderChangeInfo *changeinfo,
@@ -85,15 +78,12 @@ static gint mbox_summary_sync               (CamelLocalSummary *cls,
                                                 CamelFolderChangeInfo *changeinfo,
                                                 GCancellable *cancellable,
                                                 GError **error);
-#ifdef STATUS_PINE
 static CamelMessageInfo *
                mbox_summary_add                (CamelLocalSummary *cls,
                                                 CamelMimeMessage *msg,
                                                 const CamelMessageInfo *info,
                                                 CamelFolderChangeInfo *ci,
                                                 GError **error);
-#endif
-
 static gint    mbox_summary_sync_quick         (CamelMboxSummary *cls,
                                                 gboolean expunge,
                                                 CamelFolderChangeInfo *changeinfo,
@@ -105,7 +95,6 @@ static gint  mbox_summary_sync_full          (CamelMboxSummary *cls,
                                                 GCancellable *cancellable,
                                                 GError **error);
 
-#ifdef STATUS_PINE
 /* Which status flags are stored in each separate header */
 #define STATUS_XSTATUS \
        (CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_DELETED)
@@ -113,59 +102,12 @@ static gint       mbox_summary_sync_full          (CamelMboxSummary *cls,
 
 static void encode_status (guint32 flags, gchar status[8]);
 static guint32 decode_status (const gchar *status);
-#endif
 
 G_DEFINE_TYPE (
        CamelMboxSummary,
        camel_mbox_summary,
        CAMEL_TYPE_LOCAL_SUMMARY)
 
-static gboolean
-mbox_info_set_user_flag (CamelMessageInfo *mi,
-                         const gchar *name,
-                         gboolean value)
-{
-       gint res;
-
-       res = CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->info_set_user_flag (mi, name, 
value);
-       if (res)
-               ((CamelLocalMessageInfo *) mi)->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
-
-       return res;
-}
-
-static gboolean
-mbox_info_set_user_tag (CamelMessageInfo *mi,
-                        const gchar *name,
-                        const gchar *value)
-{
-       gint res;
-
-       res = CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->info_set_user_tag (mi, name, 
value);
-       if (res)
-               ((CamelLocalMessageInfo *) mi)->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
-
-       return res;
-}
-
-#ifdef STATUS_PINE
-static gboolean
-mbox_info_set_flags (CamelMessageInfo *mi,
-                     guint32 flags,
-                     guint32 set)
-{
-       /* Basically, if anything could change the Status line, presume it does */
-       if (((CamelMboxSummary *) mi->summary)->xstatus
-           && (flags & (CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_ANSWERED | 
CAMEL_MESSAGE_DELETED))) {
-               flags |= CAMEL_MESSAGE_FOLDER_XEVCHANGE | CAMEL_MESSAGE_FOLDER_FLAGGED;
-               set |= CAMEL_MESSAGE_FOLDER_XEVCHANGE | CAMEL_MESSAGE_FOLDER_FLAGGED;
-       }
-
-       return CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->
-               info_set_flags (mi, flags, set);
-}
-#endif
-
 static void
 camel_mbox_summary_class_init (CamelMboxSummaryClass *class)
 {
@@ -173,27 +115,19 @@ camel_mbox_summary_class_init (CamelMboxSummaryClass *class)
        CamelLocalSummaryClass *local_summary_class;
 
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
-       folder_summary_class->message_info_size = sizeof (CamelMboxMessageInfo);
-       folder_summary_class->content_info_size = sizeof (CamelMboxMessageContentInfo);
-       folder_summary_class->summary_header_from_db = summary_header_from_db;
-       folder_summary_class->summary_header_to_db = summary_header_to_db;
-       folder_summary_class->message_info_from_db = message_info_from_db;
-       folder_summary_class->message_info_to_db = message_info_to_db;
-       folder_summary_class->message_info_new_from_header = message_info_new_from_header;
+       folder_summary_class->message_info_type = CAMEL_TYPE_MBOX_MESSAGE_INFO;
+       folder_summary_class->sort_by = "bdata";
+       folder_summary_class->collate = "mbox_frompos_sort";
+       folder_summary_class->summary_header_load = summary_header_load;
+       folder_summary_class->summary_header_save = summary_header_save;
+       folder_summary_class->message_info_new_from_headers = message_info_new_from_headers;
        folder_summary_class->message_info_new_from_parser = message_info_new_from_parser;
-       folder_summary_class->info_set_user_flag = mbox_info_set_user_flag;
-       folder_summary_class->info_set_user_tag = mbox_info_set_user_tag;
-#ifdef STATUS_PINE
-       folder_summary_class->info_set_flags = mbox_info_set_flags;
-#endif
 
        local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (class);
        local_summary_class->encode_x_evolution = mbox_summary_encode_x_evolution;
        local_summary_class->check = mbox_summary_check;
        local_summary_class->sync = mbox_summary_sync;
-#ifdef STATUS_PINE
        local_summary_class->add = mbox_summary_add;
-#endif
 
        class->sync_quick = mbox_summary_sync_quick;
        class->sync_full = mbox_summary_sync_full;
@@ -207,7 +141,7 @@ camel_mbox_summary_init (CamelMboxSummary *mbox_summary)
        folder_summary = CAMEL_FOLDER_SUMMARY (mbox_summary);
 
        /* and a unique file version */
-       folder_summary->version += CAMEL_MBOX_SUMMARY_VERSION;
+       camel_folder_summary_set_version (folder_summary, camel_folder_summary_get_version (folder_summary) + 
CAMEL_MBOX_SUMMARY_VERSION);
 }
 
 /**
@@ -226,16 +160,12 @@ camel_mbox_summary_new (CamelFolder *folder,
 
        new = g_object_new (CAMEL_TYPE_MBOX_SUMMARY, "folder", folder, NULL);
        if (folder) {
-               CamelFolderSummary *summary = (CamelFolderSummary *) new;
                CamelStore *parent_store;
 
                parent_store = camel_folder_get_parent_store (folder);
 
                /* Set the functions for db sorting */
-               camel_db_set_collate (parent_store->cdb_r, "bdata", "mbox_frompos_sort", (CamelDBCollate) 
camel_local_frompos_sort);
-               summary->sort_by = "bdata";
-               summary->collate = "mbox_frompos_sort";
-
+               camel_db_set_collate (camel_store_get_db (parent_store), "bdata", "mbox_frompos_sort", 
(CamelDBCollate) camel_local_frompos_sort);
        }
        camel_local_summary_construct ((CamelLocalSummary *) new, mbox_name, index);
        return new;
@@ -248,54 +178,56 @@ void camel_mbox_summary_xstatus (CamelMboxSummary *mbs, gint state)
 
 static gchar *
 mbox_summary_encode_x_evolution (CamelLocalSummary *cls,
-                                 const CamelLocalMessageInfo *mi)
+                                 const CamelMessageInfo *mi)
 {
        const gchar *p, *uidstr;
-       guint32 uid;
+       guint32 uid, flags;
 
        /* This is busted, it is supposed to encode ALL DATA */
        p = uidstr = camel_message_info_get_uid (mi);
        while (*p && isdigit (*p))
                p++;
 
+       flags = camel_message_info_get_flags (mi);
+
        if (*p == 0 && sscanf (uidstr, "%u", &uid) == 1) {
-               return g_strdup_printf ("%08x-%04x", uid, mi->info.flags & 0xffff);
+               return g_strdup_printf ("%08x-%04x", uid, flags & 0xffff);
        } else {
-               return g_strdup_printf ("%s-%04x", uidstr, mi->info.flags & 0xffff);
+               return g_strdup_printf ("%s-%04x", uidstr, flags & 0xffff);
        }
 }
 
 static gboolean
-summary_header_from_db (CamelFolderSummary *s,
-                        struct _CamelFIRecord *fir)
+summary_header_load (CamelFolderSummary *s,
+                    struct _CamelFIRecord *fir)
 {
        CamelMboxSummary *mbs = CAMEL_MBOX_SUMMARY (s);
        gchar *part;
 
-       if (!CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->summary_header_from_db (s, fir))
+       if (!CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->summary_header_load (s, fir))
                return FALSE;
 
        part = fir->bdata;
        if (part) {
-               mbs->version = bdata_extract_digit (&part);
-               mbs->folder_size = bdata_extract_digit (&part);
+               mbs->version = camel_util_bdata_get_number (&part, 0);
+               mbs->folder_size = camel_util_bdata_get_number (&part, 0);
        }
 
        return TRUE;
 }
 
 static CamelFIRecord *
-summary_header_to_db (CamelFolderSummary *s,
-                      GError **error)
+summary_header_save (CamelFolderSummary *s,
+                    GError **error)
 {
        CamelFolderSummaryClass *folder_summary_class;
        CamelMboxSummary *mbs = CAMEL_MBOX_SUMMARY (s);
        struct _CamelFIRecord *fir;
        gchar *tmp;
 
-       /* Chain up to parent's summary_header_to_db() method. */
+       /* Chain up to parent's summary_header_save() method. */
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class);
-       fir = folder_summary_class->summary_header_to_db (s, error);
+       fir = folder_summary_class->summary_header_save (s, error);
        if (fir) {
                tmp = fir->bdata;
                fir->bdata = g_strdup_printf ("%s %d %d", tmp ? tmp : "", CAMEL_MBOX_SUMMARY_VERSION, (gint) 
mbs->folder_size);
@@ -306,48 +238,47 @@ summary_header_to_db (CamelFolderSummary *s,
 }
 
 static CamelMessageInfo *
-message_info_new_from_header (CamelFolderSummary *s,
-                              struct _camel_header_raw *h)
+message_info_new_from_headers (CamelFolderSummary *summary,
+                              const CamelNameValueArray *headers)
 {
-       CamelMboxMessageInfo *mi;
-       CamelMboxSummary *mbs = (CamelMboxSummary *) s;
+       CamelMessageInfo *mi;
+       CamelMboxSummary *mbs = (CamelMboxSummary *) summary;
 
-       mi = (CamelMboxMessageInfo *) CAMEL_FOLDER_SUMMARY_CLASS 
(camel_mbox_summary_parent_class)->message_info_new_from_header (s, h);
+       mi = CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->message_info_new_from_headers 
(summary, headers);
        if (mi) {
                const gchar *xev, *uid;
-               CamelMboxMessageInfo *info = NULL;
+               CamelMessageInfo *info = NULL;
                gint add = 0;   /* bitmask of things to add, 1 assign uid, 2, just add as new, 4 = recent */
-#ifdef STATUS_PINE
                const gchar *status = NULL, *xstatus = NULL;
                guint32 flags = 0;
 
                if (mbs->xstatus) {
                        /* check for existance of status & x-status headers */
-                       status = camel_header_raw_find (&h, "Status", NULL);
+                       status = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
"Status");
                        if (status)
                                flags = decode_status (status);
-                       xstatus = camel_header_raw_find (&h, "X-Status", NULL);
+                       xstatus = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
"X-Status");
                        if (xstatus)
                                flags |= decode_status (xstatus);
                }
-#endif
+
                /* if we have an xev header, use it, else assign a new one */
-               xev = camel_header_raw_find (&h, "X-Evolution", NULL);
+               xev = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, 
"X-Evolution");
                if (xev != NULL
-                   && camel_local_summary_decode_x_evolution ((CamelLocalSummary *) s, xev, &mi->info) == 0) 
{
+                   && camel_local_summary_decode_x_evolution ((CamelLocalSummary *) summary, xev, mi) == 0) {
                        uid = camel_message_info_get_uid (mi);
                        d (printf ("found valid x-evolution: %s\n", uid));
                        /* If one is there, it should be there already */
-                       info = (CamelMboxMessageInfo *) camel_folder_summary_peek_loaded (s, uid);
+                       info = camel_folder_summary_peek_loaded (summary, uid);
                        if (info) {
-                               if ((info->info.info.flags & CAMEL_MESSAGE_FOLDER_NOTSEEN)) {
-                                       info->info.info.flags &= ~CAMEL_MESSAGE_FOLDER_NOTSEEN;
-                                       camel_message_info_unref (mi);
+                               if ((camel_message_info_get_flags (info) & CAMEL_MESSAGE_FOLDER_NOTSEEN)) {
+                                       camel_message_info_set_flags (info, CAMEL_MESSAGE_FOLDER_NOTSEEN, 0);
+                                       g_clear_object (&mi);
                                        mi = info;
                                } else {
                                        add = 7;
                                        d (printf ("seen '%s' before, adding anew\n", uid));
-                                       camel_message_info_unref (info);
+                                       g_clear_object (&info);
                                }
                        } else {
                                add = 2;
@@ -358,22 +289,25 @@ message_info_new_from_header (CamelFolderSummary *s,
                        add = 7;
                }
 
-               if (add&1) {
-                       mi->info.info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV;
-                       camel_pstring_free (mi->info.info.uid);
-                       mi->info.info.uid = camel_pstring_add (camel_folder_summary_next_uid_string (s), 
TRUE);
+               if ((add & 1) != 0) {
+                       gchar *new_uid = camel_folder_summary_next_uid_string (summary);
+
+                       camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_FLAGGED | 
CAMEL_MESSAGE_FOLDER_NOXEV, CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV);
+                       camel_message_info_set_uid (mi, new_uid);
+
+                       g_free (new_uid);
                } else {
-                       camel_folder_summary_set_next_uid (s, strtoul (camel_message_info_get_uid (mi), NULL, 
10));
+                       camel_folder_summary_set_next_uid (summary, strtoul (camel_message_info_get_uid (mi), 
NULL, 10));
                }
-#ifdef STATUS_PINE
-               if (mbs->xstatus && add&2) {
+
+               if (mbs->xstatus && (add & 2) != 0) {
                        /* use the status as the flags when we read it the first time */
                        if (status)
-                               mi->info.info.flags = (mi->info.info.flags & ~(STATUS_STATUS)) | (flags & 
STATUS_STATUS);
+                               camel_message_info_set_flags (mi, STATUS_STATUS, flags);
                        if (xstatus)
-                               mi->info.info.flags = (mi->info.info.flags & ~(STATUS_XSTATUS)) | (flags & 
STATUS_XSTATUS);
+                               camel_message_info_set_flags (mi, STATUS_XSTATUS, flags);
                }
-#endif
+
                if (mbs->changes) {
                        if (add&2)
                                camel_folder_change_info_add_uid (mbs->changes, camel_message_info_get_uid 
(mi));
@@ -381,7 +315,7 @@ message_info_new_from_header (CamelFolderSummary *s,
                                camel_folder_change_info_recent_uid (mbs->changes, camel_message_info_get_uid 
(mi));
                }
 
-               mi->frompos = -1;
+               camel_mbox_message_info_set_offset (CAMEL_MBOX_MESSAGE_INFO (mi), -1);
        }
 
        return (CamelMessageInfo *) mi;
@@ -395,46 +329,12 @@ message_info_new_from_parser (CamelFolderSummary *s,
 
        mi = CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->message_info_new_from_parser (s, 
mp);
        if (mi) {
-               CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *) mi;
-
-               mbi->frompos = camel_mime_parser_tell_start_from (mp);
+               camel_mbox_message_info_set_offset (CAMEL_MBOX_MESSAGE_INFO (mi), 
camel_mime_parser_tell_start_from (mp));
        }
 
        return mi;
 }
 
-static CamelMessageInfo *
-message_info_from_db (CamelFolderSummary *s,
-                      struct _CamelMIRecord *mir)
-{
-       CamelMessageInfo *mi;
-
-       mi = CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->message_info_from_db (s, mir);
-
-       if (mi) {
-               CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *) mi;
-               gchar *part = mir->bdata;
-               if (part) {
-                       mbi->frompos = bdata_extract_digit (&part);
-               }
-       }
-
-       return mi;
-}
-
-static struct _CamelMIRecord *
-message_info_to_db (CamelFolderSummary *s,
-                    CamelMessageInfo *info)
-{
-       CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *) info;
-       struct _CamelMIRecord *mir;
-
-       mir = CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_parent_class)->message_info_to_db (s, info);
-       mir->bdata = g_strdup_printf ("%" G_GOFFSET_FORMAT, mbi->frompos);
-
-       return mir;
-}
-
 /* like summary_rebuild, but also do changeinfo stuff (if supplied) */
 static gint
 summary_update (CamelLocalSummary *cls,
@@ -447,7 +347,7 @@ summary_update (CamelLocalSummary *cls,
        CamelFolderSummary *s = (CamelFolderSummary *) cls;
        CamelMboxSummary *mbs = (CamelMboxSummary *) cls;
        CamelMimeParser *mp;
-       CamelMboxMessageInfo *mi;
+       CamelMessageInfo *mi;
        CamelStore *parent_store;
        const gchar *full_name;
        gint fd;
@@ -503,12 +403,9 @@ summary_update (CamelLocalSummary *cls,
        camel_folder_summary_prepare_fetch_all (s, NULL);
        known_uids = camel_folder_summary_get_array (s);
        for (i = 0; known_uids && i < known_uids->len; i++) {
-               mi = (CamelMboxMessageInfo *) camel_folder_summary_get (s, g_ptr_array_index (known_uids, i));
-               if (offset == 0)
-                       mi->info.info.flags |= CAMEL_MESSAGE_FOLDER_NOTSEEN;
-               else
-                       mi->info.info.flags &= ~CAMEL_MESSAGE_FOLDER_NOTSEEN;
-               camel_message_info_unref (mi);
+               mi = camel_folder_summary_get (s, g_ptr_array_index (known_uids, i));
+               camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_NOTSEEN, offset == 0 ? 
CAMEL_MESSAGE_FOLDER_NOTSEEN : 0);
+               g_clear_object (&mi);
        }
        camel_folder_summary_free_array (known_uids);
        mbs->changes = changeinfo;
@@ -526,7 +423,8 @@ summary_update (CamelLocalSummary *cls,
                camel_operation_progress (cancellable, progress);
 
                info = camel_folder_summary_info_new_from_parser (s, mp);
-               camel_folder_summary_add (s, info);
+               camel_folder_summary_add (s, info, FALSE);
+               g_clear_object (&info);
 
                g_warn_if_fail (camel_mime_parser_step (mp, NULL, NULL) == CAMEL_MIME_PARSER_STATE_FROM_END);
        }
@@ -541,19 +439,18 @@ summary_update (CamelLocalSummary *cls,
                if (!uid)
                        continue;
 
-               mi = (CamelMboxMessageInfo *) camel_folder_summary_get (s, uid);
+               mi = camel_folder_summary_get (s, uid);
                /* must've dissapeared from the file? */
-               if (!mi || mi->info.info.flags & CAMEL_MESSAGE_FOLDER_NOTSEEN) {
+               if (!mi || (camel_message_info_get_flags (mi) & CAMEL_MESSAGE_FOLDER_NOTSEEN) != 0) {
                        d (printf ("uid '%s' vanished, removing", uid));
                        if (changeinfo)
                                camel_folder_change_info_remove_uid (changeinfo, uid);
                        del = g_list_prepend (del, (gpointer) camel_pstring_strdup (uid));
                        if (mi)
-                               camel_folder_summary_remove (s, (CamelMessageInfo *) mi);
+                               camel_folder_summary_remove (s, mi);
                }
 
-               if (mi)
-                       camel_message_info_unref (mi);
+               g_clear_object (&mi);
        }
 
        if (known_uids)
@@ -562,7 +459,7 @@ summary_update (CamelLocalSummary *cls,
        /* Delete all in one transaction */
        full_name = camel_folder_get_full_name (camel_folder_summary_get_folder (s));
        parent_store = camel_folder_get_parent_store (camel_folder_summary_get_folder (s));
-       camel_db_delete_uids (parent_store->cdb_w, full_name, del, NULL);
+       camel_db_delete_uids (camel_store_get_db (parent_store), full_name, del, NULL);
        g_list_foreach (del, (GFunc) camel_pstring_free, NULL);
        g_list_free (del);
 
@@ -573,7 +470,7 @@ summary_update (CamelLocalSummary *cls,
                if (g_stat (cls->folder_path, &st) == 0) {
                        camel_folder_summary_touch (s);
                        mbs->folder_size = st.st_size;
-                       s->time = st.st_mtime;
+                       camel_folder_summary_set_timestamp (s, st.st_mtime);
                }
        }
 
@@ -627,7 +524,7 @@ mbox_summary_check (CamelLocalSummary *cls,
 
                        if (info) {
                                camel_folder_change_info_remove_uid (changes, camel_message_info_get_uid 
(info));
-                               camel_message_info_unref (info);
+                               g_clear_object (&info);
                        }
                }
                camel_folder_summary_free_array (known_uids);
@@ -635,7 +532,7 @@ mbox_summary_check (CamelLocalSummary *cls,
                ret = 0;
        } else {
                /* is the summary uptodate? */
-               if (st.st_size != mbs->folder_size || st.st_mtime != s->time) {
+               if (st.st_size != mbs->folder_size || st.st_mtime != camel_folder_summary_get_timestamp (s)) {
                        if (mbs->folder_size < st.st_size) {
                                /* this will automatically rescan from 0 if there is a problem */
                                d (printf ("folder grew, attempting to rebuild from %d\n", mbs->folder_size));
@@ -652,9 +549,9 @@ mbox_summary_check (CamelLocalSummary *cls,
        /* FIXME: move upstream? */
 
        if (ret != -1) {
-               if (mbs->folder_size != st.st_size || s->time != st.st_mtime) {
+               if (mbs->folder_size != st.st_size || camel_folder_summary_get_timestamp (s) != st.st_mtime) {
                        mbs->folder_size = st.st_size;
-                       s->time = st.st_mtime;
+                       camel_folder_summary_set_timestamp (s, st.st_mtime);
                        camel_folder_summary_touch (s);
                }
        }
@@ -790,20 +687,25 @@ cms_sort_frompos (gconstpointer a,
 {
        CamelFolderSummary *summary = (CamelFolderSummary *) data;
        CamelMboxMessageInfo *info1, *info2;
+       goffset afrompos, bfrompos;
        gint ret = 0;
 
        /* Things are in memory already. Sorting speeds up syncing, if things are sorted by from pos. */
        info1 = (CamelMboxMessageInfo *) camel_folder_summary_get (summary, *(gchar **) a);
        info2 = (CamelMboxMessageInfo *) camel_folder_summary_get (summary, *(gchar **) b);
 
-       if (info1->frompos > info2->frompos)
+       afrompos = camel_mbox_message_info_get_offset (info1);
+       bfrompos = camel_mbox_message_info_get_offset (info2);
+
+       if (afrompos > bfrompos)
                ret = 1;
-       else if  (info1->frompos < info2->frompos)
+       else if  (afrompos < bfrompos)
                ret = -1;
        else
                ret = 0;
-       camel_message_info_unref (info1);
-       camel_message_info_unref (info2);
+
+       g_clear_object (&info1);
+       g_clear_object (&info2);
 
        return ret;
 
@@ -821,7 +723,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
        CamelFolderSummary *s = (CamelFolderSummary *) mbs;
        CamelMimeParser *mp = NULL;
        gint i;
-       CamelMboxMessageInfo *info = NULL;
+       CamelMessageInfo *info = NULL;
        gint fd = -1, pfd;
        gchar *xevnew, *xevtmp;
        const gchar *xev;
@@ -871,24 +773,26 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
                g_ptr_array_sort_with_data (summary, cms_sort_frompos, mbs);
 
        for (i = 0; i < summary->len; i++) {
+               goffset frompos;
                gint xevoffset;
                gint pc = (i + 1) * 100 / summary->len;
 
                camel_operation_progress (cancellable, pc);
 
-               info = (CamelMboxMessageInfo *) camel_folder_summary_get (s, summary->pdata[i]);
+               info = camel_folder_summary_get (s, summary->pdata[i]);
 
-               d (printf ("Checking message %s %08x\n", camel_message_info_get_uid (info), 
((CamelMessageInfoBase *) info)->flags));
+               d (printf ("Checking message %s %08x\n", camel_message_info_get_uid (info), 
camel_message_info_get_flags (info)));
 
-               if ((info->info.info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) == 0) {
-                       camel_message_info_unref (info);
-                       info = NULL;
+               if (!camel_message_info_get_folder_flagged (info)) {
+                       g_clear_object (&info);
                        continue;
                }
 
-               d (printf ("Updating message %s: %d\n", camel_message_info_get_uid (info), (gint) 
info->frompos));
+               frompos = camel_mbox_message_info_get_offset (CAMEL_MBOX_MESSAGE_INFO (info));
 
-               camel_mime_parser_seek (mp, info->frompos, SEEK_SET);
+               d (printf ("Updating message %s: %d\n", camel_message_info_get_uid (info), (gint) frompos));
+
+               camel_mime_parser_seek (mp, frompos, SEEK_SET);
 
                if (camel_mime_parser_step (mp, NULL, NULL) != CAMEL_MIME_PARSER_STATE_FROM) {
                        g_set_error (
@@ -897,10 +801,10 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
                        goto error;
                }
 
-               if (camel_mime_parser_tell_start_from (mp) != info->frompos) {
+               if (camel_mime_parser_tell_start_from (mp) != frompos) {
                        g_warning (
                                "Didn't get the next message where I expected (%d) got %d instead",
-                               (gint) info->frompos, (gint) camel_mime_parser_tell_start_from (mp));
+                               (gint) frompos, (gint) camel_mime_parser_tell_start_from (mp));
                        g_set_error (
                                error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                                _("Summary and folder mismatch, even after a sync"));
@@ -917,7 +821,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
                        g_warning ("We're supposed to have a valid x-ev header, but we dont");
                        goto error;
                }
-               xevnew = camel_local_summary_encode_x_evolution (cls, &info->info);
+               xevnew = camel_local_summary_encode_x_evolution (cls, info);
                /* SIGH: encode_param_list is about the only function which folds headers by itself.
                 * This should be fixed somehow differently (either parser doesn't fold headers,
                 * or param_list doesn't, or something */
@@ -949,10 +853,8 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
                camel_mime_parser_drop_step (mp);
                camel_mime_parser_drop_step (mp);
 
-               info->info.info.flags &= 0xffff;
-               info->info.info.dirty = TRUE;
-               camel_message_info_unref (info);
-               info = NULL;
+               camel_message_info_set_flags (info, 0xffff, camel_message_info_get_flags (info));
+               g_clear_object (&info);
        }
 
        d (printf ("Closing folders\n"));
@@ -983,7 +885,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
        if (fd != -1)
                close (fd);
        if (info)
-               camel_message_info_unref (info);
+               g_clear_object (&info);
 
        camel_operation_pop_message (cancellable);
        camel_folder_summary_unlock (s);
@@ -1023,14 +925,14 @@ mbox_summary_sync (CamelLocalSummary *cls,
 
        summary = camel_folder_summary_get_changed ((CamelFolderSummary *) mbs);
        for (i = 0; i < summary->len; i++) {
-               CamelMboxMessageInfo *info = (CamelMboxMessageInfo *) camel_folder_summary_get (s, 
summary->pdata[i]);
+               CamelMessageInfo *info = camel_folder_summary_get (s, summary->pdata[i]);
 
-               if ((expunge && (info->info.info.flags & CAMEL_MESSAGE_DELETED)) ||
-                   (info->info.info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV | CAMEL_MESSAGE_FOLDER_XEVCHANGE)))
+               if ((expunge && (camel_message_info_get_flags (info) & CAMEL_MESSAGE_DELETED) != 0) ||
+                   (camel_message_info_get_flags (info) & (CAMEL_MESSAGE_FOLDER_NOXEV | 
CAMEL_MESSAGE_FOLDER_XEVCHANGE)) != 0)
                        quick = FALSE;
                else
-                       work |= (info->info.info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0;
-               camel_message_info_unref (info);
+                       work |= camel_message_info_get_folder_flagged (info);
+               g_clear_object (&info);
        }
 
        g_ptr_array_foreach (summary, (GFunc) camel_pstring_free, NULL);
@@ -1039,7 +941,7 @@ mbox_summary_sync (CamelLocalSummary *cls,
        if (quick && expunge) {
                guint32 dcount =0;
 
-               if (camel_db_count_deleted_message_info (parent_store->cdb_w, full_name, &dcount, error) == 
-1) {
+               if (camel_db_count_deleted_message_info (camel_store_get_db (parent_store), full_name, 
&dcount, error) == -1) {
                        camel_folder_summary_unlock (s);
                        return -1;
                }
@@ -1077,8 +979,8 @@ mbox_summary_sync (CamelLocalSummary *cls,
                return -1;
        }
 
-       if (mbs->folder_size != st.st_size || s->time != st.st_mtime) {
-               s->time = st.st_mtime;
+       if (mbs->folder_size != st.st_size || camel_folder_summary_get_timestamp (s) != st.st_mtime) {
+               camel_folder_summary_set_timestamp (s, st.st_mtime);
                mbs->folder_size = st.st_size;
                camel_folder_summary_touch (s);
        }
@@ -1104,7 +1006,7 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
        CamelStore *parent_store;
        const gchar *full_name;
        gint i;
-       CamelMboxMessageInfo *info = NULL;
+       CamelMessageInfo *info = NULL;
        gchar *buffer, *xevnew = NULL;
        gsize len;
        const gchar *fromline;
@@ -1112,9 +1014,7 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
        gboolean touched = FALSE;
        GList *del = NULL;
        GPtrArray *known_uids = NULL;
-#ifdef STATUS_PINE
        gchar statnew[8], xstatnew[8];
-#endif
 
        d (printf ("performing full summary/sync\n"));
 
@@ -1144,10 +1044,11 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
                g_ptr_array_sort_with_data (known_uids, cms_sort_frompos, mbs);
        for (i = 0; known_uids && i < known_uids->len; i++) {
                gint pc = (i + 1) * 100 / known_uids->len;
+               goffset frompos;
 
                camel_operation_progress (cancellable, pc);
 
-               info = (CamelMboxMessageInfo *) camel_folder_summary_get (s, g_ptr_array_index (known_uids, 
i));
+               info = camel_folder_summary_get (s, g_ptr_array_index (known_uids, i));
 
                if (!info)
                        continue;
@@ -1156,13 +1057,15 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
                        "Looking at message %s\n",
                        camel_message_info_get_uid (info)));
 
+               frompos = camel_mbox_message_info_get_offset (CAMEL_MBOX_MESSAGE_INFO (info));
+
                d (printf (
                        "seeking (%s) to %d\n",
-                       ((CamelMessageInfo *) info)->uid,
-                       (gint) info->frompos));
+                       camel_message_info_get_uid (info),
+                       (gint) frompos));
 
                if (lastdel)
-                       camel_mime_parser_seek (mp, info->frompos, SEEK_SET);
+                       camel_mime_parser_seek (mp, frompos, SEEK_SET);
 
                if (camel_mime_parser_step (mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_FROM) {
                        g_set_error (
@@ -1172,10 +1075,10 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
                        goto error;
                }
 
-               if (camel_mime_parser_tell_start_from (mp) != info->frompos) {
+               if (camel_mime_parser_tell_start_from (mp) != frompos) {
                        g_warning (
                                "Didn't get the next message where I expected (%d) got %d instead",
-                               (gint) info->frompos,
+                               (gint) frompos,
                                (gint) camel_mime_parser_tell_start_from (mp));
                        g_set_error (
                                error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
@@ -1184,7 +1087,7 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
                }
 
                lastdel = FALSE;
-               if ((flags&1) && info->info.info.flags & CAMEL_MESSAGE_DELETED) {
+               if ((flags & 1) && (camel_message_info_get_flags (info) & CAMEL_MESSAGE_DELETED) != 0) {
                        const gchar *uid = camel_message_info_get_uid (info);
                        d (printf ("Deleting %s\n", uid));
 
@@ -1195,8 +1098,7 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
                        camel_folder_change_info_remove_uid (changeinfo, uid);
                        camel_folder_summary_remove (s, (CamelMessageInfo *) info);
                        del = g_list_prepend (del, (gpointer) camel_pstring_strdup (uid));
-                       camel_message_info_unref (info);
-                       info = NULL;
+                       g_clear_object (&info);
                        lastdel = TRUE;
                        touched = TRUE;
                } else {
@@ -1205,33 +1107,37 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
                        if (i > 0)
                                write (fdout, "\n", 1);
 #endif
-                       info->frompos = lseek (fdout, 0, SEEK_CUR);
-                       ((CamelMessageInfo *) info)->dirty = TRUE;
+                       frompos = lseek (fdout, 0, SEEK_CUR);
+                       camel_mbox_message_info_set_offset (CAMEL_MBOX_MESSAGE_INFO (info), frompos);
+                       camel_message_info_set_dirty (info, TRUE);
                        fromline = camel_mime_parser_from_line (mp);
-                       d (printf ("Saving %s:%d\n", camel_message_info_get_uid (info), info->frompos));
+                       d (printf ("Saving %s:%d\n", camel_message_info_get_uid (info), frompos));
                        g_warn_if_fail (write (fdout, fromline, strlen (fromline)) != -1);
                }
 
-               if (info && info->info.info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV | 
CAMEL_MESSAGE_FOLDER_FLAGGED)) {
-                       d (printf ("Updating header for %s flags = %08x\n", camel_message_info_get_uid 
(info), info->info.flags));
+               if (info && (camel_message_info_get_flags (info) & (CAMEL_MESSAGE_FOLDER_NOXEV | 
CAMEL_MESSAGE_FOLDER_FLAGGED)) != 0) {
+                       CamelNameValueArray *header = NULL;
+                       d (printf ("Updating header for %s flags = %08x\n", camel_message_info_get_uid 
(info), camel_message_info_get_flags (info)));
 
                        if (camel_mime_parser_step (mp, &buffer, &len) == CAMEL_MIME_PARSER_STATE_FROM_END) {
                                g_warning ("camel_mime_parser_step failed (2)");
                                goto error;
                        }
 
-                       xevnew = camel_local_summary_encode_x_evolution ((CamelLocalSummary *) cls, 
&info->info);
-#ifdef STATUS_PINE
+                       header = camel_mime_parser_dup_headers (mp);
+                       xevnew = camel_local_summary_encode_x_evolution ((CamelLocalSummary *) cls, info);
                        if (mbs->xstatus) {
-                               encode_status (info->info.info.flags & STATUS_STATUS, statnew);
-                               encode_status (info->info.info.flags & STATUS_XSTATUS, xstatnew);
-                               len = camel_local_summary_write_headers (fdout, camel_mime_parser_headers_raw 
(mp), xevnew, statnew, xstatnew);
+                               guint32 flags = camel_message_info_get_flags (info);
+
+                               encode_status (flags & STATUS_STATUS, statnew);
+                               encode_status (flags & STATUS_XSTATUS, xstatnew);
+
+                               len = camel_local_summary_write_headers (fdout, header, xevnew, statnew, 
xstatnew);
                        } else {
-#endif
-                               len = camel_local_summary_write_headers (fdout, camel_mime_parser_headers_raw 
(mp), xevnew, NULL, NULL);
-#ifdef STATUS_PINE
+                               len = camel_local_summary_write_headers (fdout, header, xevnew, NULL, NULL);
                        }
-#endif
+
+                       camel_name_value_array_free (header);
                        if (len == -1) {
                                d (printf ("Error writing to temporary mailbox\n"));
                                g_set_error (
@@ -1241,7 +1147,7 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
                                        g_strerror (errno));
                                goto error;
                        }
-                       info->info.info.flags &= 0xffff;
+                       camel_message_info_set_flags (info, 0xffff, camel_message_info_get_flags (info));
                        g_free (xevnew);
                        xevnew = NULL;
                        camel_mime_parser_drop_step (mp);
@@ -1277,14 +1183,13 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
                                (gint) camel_mime_parser_tell (mp),
                                (gint) camel_mime_parser_tell_start_from (mp)));
                        camel_mime_parser_unstep (mp);
-                       camel_message_info_unref (info);
-                       info = NULL;
+                       g_clear_object (&info);
                }
        }
 
        full_name = camel_folder_get_full_name (camel_folder_summary_get_folder (s));
        parent_store = camel_folder_get_parent_store (camel_folder_summary_get_folder (s));
-       camel_db_delete_uids (parent_store->cdb_w, full_name, del, NULL);
+       camel_db_delete_uids (camel_store_get_db (parent_store), full_name, del, NULL);
        g_list_foreach (del, (GFunc) camel_pstring_free, NULL);
        g_list_free (del);
 
@@ -1298,24 +1203,17 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
 
        /* clear working flags */
        for (i = 0; known_uids && i < known_uids->len; i++) {
-               info = (CamelMboxMessageInfo *) camel_folder_summary_get (s, g_ptr_array_index (known_uids, 
i));
+               info = camel_folder_summary_get (s, g_ptr_array_index (known_uids, i));
                if (info) {
-                       if (info->info.info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV | 
CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_XEVCHANGE)) {
-                               info->info.info.flags &= ~(CAMEL_MESSAGE_FOLDER_NOXEV
-                                                          |CAMEL_MESSAGE_FOLDER_FLAGGED
-                                                          |CAMEL_MESSAGE_FOLDER_XEVCHANGE);
-                               ((CamelMessageInfo *) info)->dirty = TRUE;
-                               camel_folder_summary_touch (s);
-                       }
-                       camel_message_info_unref (info);
-                       info = NULL;
+                       camel_message_info_set_flags (info, CAMEL_MESSAGE_FOLDER_NOXEV | 
CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_XEVCHANGE, 0);
+                       g_clear_object (&info);
                }
        }
 
        camel_folder_summary_free_array (known_uids);
 
        if (touched)
-               camel_folder_summary_header_save_to_db (s, NULL);
+               camel_folder_summary_header_save (s, NULL);
 
        camel_folder_summary_unlock (s);
 
@@ -1323,9 +1221,7 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
  error:
        g_free (xevnew);
        g_object_unref (mp);
-
-       if (info)
-               camel_message_info_unref (info);
+       g_clear_object (&info);
 
        camel_folder_summary_free_array (known_uids);
        camel_folder_summary_unlock (s);
@@ -1333,7 +1229,6 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
        return -1;
 }
 
-#ifdef STATUS_PINE
 static CamelMessageInfo *
 mbox_summary_add (CamelLocalSummary *cls,
                   CamelMimeMessage *msg,
@@ -1342,23 +1237,23 @@ mbox_summary_add (CamelLocalSummary *cls,
                   GError **error)
 {
        CamelLocalSummaryClass *local_summary_class;
-       CamelMboxMessageInfo *mi;
+       CamelMessageInfo *mi;
 
        /* Chain up to parent's add() method. */
        local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (camel_mbox_summary_parent_class);
-       mi = (CamelMboxMessageInfo *) local_summary_class->add (
-               cls, msg, info, ci, error);
+       mi = local_summary_class->add (cls, msg, info, ci, error);
        if (mi && ((CamelMboxSummary *) cls)->xstatus) {
                gchar status[8];
+               guint32 flags = camel_message_info_get_flags (mi);
 
                /* we snoop and add status/x-status headers to suit */
-               encode_status (mi->info.info.flags & STATUS_STATUS, status);
+               encode_status (flags & STATUS_STATUS, status);
                camel_medium_set_header ((CamelMedium *) msg, "Status", status);
-               encode_status (mi->info.info.flags & STATUS_XSTATUS, status);
+               encode_status (flags & STATUS_XSTATUS, status);
                camel_medium_set_header ((CamelMedium *) msg, "X-Status", status);
        }
 
-       return (CamelMessageInfo *) mi;
+       return mi;
 }
 
 static struct {
@@ -1403,5 +1298,3 @@ decode_status (const gchar *status)
 
        return flags;
 }
-
-#endif /* STATUS_PINE */
diff --git a/src/camel/providers/local/camel-mbox-summary.h b/src/camel/providers/local/camel-mbox-summary.h
index 37f6bad..1c610c2 100644
--- a/src/camel/providers/local/camel-mbox-summary.h
+++ b/src/camel/providers/local/camel-mbox-summary.h
@@ -45,12 +45,6 @@ G_BEGIN_DECLS
 typedef struct _CamelMboxSummary CamelMboxSummary;
 typedef struct _CamelMboxSummaryClass CamelMboxSummaryClass;
 
-typedef struct _CamelMboxMessageInfo {
-       CamelLocalMessageInfo info;
-
-       goffset frompos;
-} CamelMboxMessageInfo;
-
 struct _CamelMboxSummary {
        CamelLocalSummary parent;
 
@@ -78,6 +72,9 @@ struct _CamelMboxSummaryClass {
                                                 CamelFolderChangeInfo *changeinfo,
                                                 GCancellable *cancellable,
                                                 GError **error);
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mbox_summary_get_type     (void);
diff --git a/src/camel/providers/local/camel-mh-folder.c b/src/camel/providers/local/camel-mh-folder.c
index 7eaafe9..f3cc140 100644
--- a/src/camel/providers/local/camel-mh-folder.c
+++ b/src/camel/providers/local/camel-mh-folder.c
@@ -71,7 +71,7 @@ mh_folder_append_message_sync (CamelFolder *folder,
                return FALSE;
 
        /* add it to the summary/assign the uid, etc */
-       mi = camel_local_summary_add ((CamelLocalSummary *) folder->summary, message, info, lf->changes, 
error);
+       mi = camel_local_summary_add ((CamelLocalSummary *) camel_folder_get_folder_summary (folder), 
message, info, lf->changes, error);
        if (mi == NULL)
                goto check_changed;
 
@@ -108,7 +108,7 @@ mh_folder_append_message_sync (CamelFolder *folder,
  fail_write:
 
        /* remove the summary info so we are not out-of-sync with the mh folder */
-       camel_folder_summary_remove (CAMEL_FOLDER_SUMMARY (folder->summary), mi);
+       camel_folder_summary_remove (camel_folder_get_folder_summary (folder), mi);
 
        g_prefix_error (
                error, _("Cannot append message to mh folder: %s: "), name);
@@ -128,6 +128,8 @@ mh_folder_append_message_sync (CamelFolder *folder,
                camel_folder_change_info_clear (lf->changes);
        }
 
+       g_clear_object (&mi);
+
        return TRUE;
 }
 
@@ -149,7 +151,7 @@ mh_folder_get_message_sync (CamelFolder *folder,
                return NULL;
 
        /* get the message summary info */
-       if ((info = camel_folder_summary_get (folder->summary, uid)) == NULL) {
+       if ((info = camel_folder_summary_get (camel_folder_get_folder_summary (folder), uid)) == NULL) {
                set_cannot_get_message_ex (
                        error, CAMEL_FOLDER_ERROR_INVALID_UID,
                        uid, lf->folder_path, _("No such message"));
@@ -157,7 +159,7 @@ mh_folder_get_message_sync (CamelFolder *folder,
        }
 
        /* we only need it to check the message exists */
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        name = g_strdup_printf ("%s/%s", lf->folder_path, uid);
        message_stream = camel_stream_fs_new_with_name (
diff --git a/src/camel/providers/local/camel-mh-folder.h b/src/camel/providers/local/camel-mh-folder.h
index c905c2e..169abc1 100644
--- a/src/camel/providers/local/camel-mh-folder.h
+++ b/src/camel/providers/local/camel-mh-folder.h
@@ -51,6 +51,9 @@ struct _CamelMhFolder {
 
 struct _CamelMhFolderClass {
        CamelLocalFolderClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mh_folder_get_type        (void);
diff --git a/src/camel/providers/local/camel-mh-settings.h b/src/camel/providers/local/camel-mh-settings.h
index 0ec8561..a9b633c 100644
--- a/src/camel/providers/local/camel-mh-settings.h
+++ b/src/camel/providers/local/camel-mh-settings.h
@@ -52,6 +52,9 @@ struct _CamelMhSettings {
 
 struct _CamelMhSettingsClass {
        CamelLocalSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mh_settings_get_type      (void) G_GNUC_CONST;
diff --git a/src/camel/providers/local/camel-mh-store.c b/src/camel/providers/local/camel-mh-store.c
index 7f771ec..9dc7752 100644
--- a/src/camel/providers/local/camel-mh-store.c
+++ b/src/camel/providers/local/camel-mh-store.c
@@ -189,7 +189,7 @@ fill_fi (CamelStore *store,
        CamelFolder *folder;
 
        local_store = CAMEL_LOCAL_STORE (store);
-       folder = camel_object_bag_peek (store->folders, fi->full_name);
+       folder = camel_object_bag_peek (camel_store_get_folders_bag (store), fi->full_name);
 
        if (folder != NULL) {
                fi->unread = camel_folder_get_unread_message_count (folder);
@@ -220,10 +220,8 @@ fill_fi (CamelStore *store,
                 * every file, i.e. very very slow */
 
                folderpath = g_strdup_printf ("%s/%s", path, fi->full_name);
-               s = (CamelFolderSummary *) camel_mh_summary_new (
-                       NULL, folderpath, NULL);
-               if (camel_folder_summary_header_load_from_db (
-                       s, store, fi->full_name, NULL)) {
+               s = (CamelFolderSummary *) camel_mh_summary_new (NULL, folderpath, NULL);
+               if (camel_folder_summary_header_load (s, store, fi->full_name, NULL)) {
                        fi->unread = camel_folder_summary_get_unread_count (s);
                        fi->total = camel_folder_summary_get_saved_count (s);
                }
diff --git a/src/camel/providers/local/camel-mh-store.h b/src/camel/providers/local/camel-mh-store.h
index c478d48..fd78f39 100644
--- a/src/camel/providers/local/camel-mh-store.h
+++ b/src/camel/providers/local/camel-mh-store.h
@@ -54,6 +54,9 @@ struct _CamelMhStore {
 
 struct _CamelMhStoreClass {
        CamelLocalStoreClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mh_store_get_type         (void);
diff --git a/src/camel/providers/local/camel-mh-summary.c b/src/camel/providers/local/camel-mh-summary.c
index b653192..6c33a58 100644
--- a/src/camel/providers/local/camel-mh-summary.c
+++ b/src/camel/providers/local/camel-mh-summary.c
@@ -43,7 +43,7 @@
 
 static gint mh_summary_check (CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, GCancellable 
*cancellable, GError **error);
 static gint mh_summary_sync (CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, 
GCancellable *cancellable, GError **error);
-static gint mh_summary_decode_x_evolution (CamelLocalSummary *cls, const gchar *xev, CamelLocalMessageInfo 
*info);
+static gint mh_summary_decode_x_evolution (CamelLocalSummary *cls, const gchar *xev, CamelMessageInfo *info);
 /*static gint mh_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, CamelMessageInfo *info, 
CamelFolderChangeInfo *, GError **error);*/
 
 static gchar *mh_summary_next_uid_string (CamelFolderSummary *s);
@@ -63,6 +63,8 @@ camel_mh_summary_class_init (CamelMhSummaryClass *class)
        g_type_class_add_private (class, sizeof (CamelMhSummaryPrivate));
 
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
+       folder_summary_class->sort_by = "uid";
+       folder_summary_class->collate = "mh_uid_sort";
        folder_summary_class->next_uid_string = mh_summary_next_uid_string;
 
        local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (class);
@@ -81,7 +83,7 @@ camel_mh_summary_init (CamelMhSummary *mh_summary)
        folder_summary = CAMEL_FOLDER_SUMMARY (mh_summary);
 
        /* set unique file version */
-       folder_summary->version += CAMEL_MH_SUMMARY_VERSION;
+       camel_folder_summary_set_version (folder_summary, camel_folder_summary_get_version (folder_summary) + 
CAMEL_MH_SUMMARY_VERSION);
 }
 
 /**
@@ -103,9 +105,7 @@ camel_mh_summary_new (CamelFolder *folder,
                CamelStore *parent_store;
 
                parent_store = camel_folder_get_parent_store (folder);
-               camel_db_set_collate (parent_store->cdb_r, "uid", "mh_uid_sort", (CamelDBCollate) 
camel_local_frompos_sort);
-               ((CamelFolderSummary *) o)->sort_by = "uid";
-               ((CamelFolderSummary *) o)->collate = "mh_uid_sort";
+               camel_db_set_collate (camel_store_get_db (parent_store), "uid", "mh_uid_sort", 
(CamelDBCollate) camel_local_frompos_sort);
        }
 
        camel_local_summary_construct ((CamelLocalSummary *) o, mhdir, index);
@@ -183,7 +183,8 @@ camel_mh_summary_add (CamelLocalSummary *cls,
        mhs->priv->current_uid = (gchar *) name;
 
        info = camel_folder_summary_info_new_from_parser (summary, mp);
-       camel_folder_summary_add (summary, info);
+       camel_folder_summary_add (summary, info, FALSE);
+       g_clear_object (&info);
 
        g_object_unref (mp);
        mhs->priv->current_uid = NULL;
@@ -202,7 +203,7 @@ remove_summary (gchar *key,
        if (cls->index)
                camel_index_delete_name (cls->index, camel_message_info_get_uid (info));
        camel_folder_summary_remove ((CamelFolderSummary *) cls, info);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 }
 
 static gint
@@ -265,11 +266,11 @@ mh_summary_check (CamelLocalSummary *cls,
 
                                        if (old) {
                                                g_hash_table_remove (left, camel_message_info_get_uid (info));
-                                               camel_message_info_unref (old);
+                                               g_clear_object (&old);
                                        }
 
                                        camel_folder_summary_remove ((CamelFolderSummary *) cls, info);
-                                       camel_message_info_unref (info);
+                                       g_clear_object (&info);
                                }
                                camel_mh_summary_add (cls, d->d_name, forceindex, cancellable);
                        } else {
@@ -278,9 +279,9 @@ mh_summary_check (CamelLocalSummary *cls,
 
                                if (old) {
                                        g_hash_table_remove (left, uid);
-                                       camel_message_info_unref (old);
+                                       g_clear_object (&old);
                                }
-                               camel_message_info_unref (info);
+                               g_clear_object (&info);
                        }
                }
        }
@@ -302,7 +303,7 @@ mh_summary_sync (CamelLocalSummary *cls,
        CamelLocalSummaryClass *local_summary_class;
        gint i;
        GPtrArray *known_uids;
-       CamelLocalMessageInfo *info;
+       CamelMessageInfo *info;
        gchar *name;
        const gchar *uid;
 
@@ -318,9 +319,9 @@ mh_summary_sync (CamelLocalSummary *cls,
        camel_folder_summary_prepare_fetch_all ((CamelFolderSummary *) cls, error);
        known_uids = camel_folder_summary_get_array ((CamelFolderSummary *) cls);
        for (i = (known_uids ? known_uids->len : 0) - 1; i >= 0; i--) {
-               info = (CamelLocalMessageInfo *) camel_folder_summary_get ((CamelFolderSummary *) cls, 
g_ptr_array_index (known_uids, i));
+               info = camel_folder_summary_get ((CamelFolderSummary *) cls, g_ptr_array_index (known_uids, 
i));
                g_return_val_if_fail (info, -1);
-               if (expunge && (info->info.flags & CAMEL_MESSAGE_DELETED)) {
+               if (expunge && (camel_message_info_get_flags (info) & CAMEL_MESSAGE_DELETED) != 0) {
                        uid = camel_message_info_get_uid (info);
                        name = g_strdup_printf ("%s/%s", cls->folder_path, uid);
                        d (printf ("deleting %s\n", name));
@@ -334,10 +335,10 @@ mh_summary_sync (CamelLocalSummary *cls,
                                camel_folder_summary_remove ((CamelFolderSummary *) cls, (CamelMessageInfo *) 
info);
                        }
                        g_free (name);
-               } else if (info->info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV | CAMEL_MESSAGE_FOLDER_FLAGGED)) {
-                       info->info.flags &= 0xffff;
+               } else if ((camel_message_info_get_flags (info) & (CAMEL_MESSAGE_FOLDER_NOXEV | 
CAMEL_MESSAGE_FOLDER_FLAGGED)) != 0) {
+                       camel_message_info_set_flags (info, 0xffff, camel_message_info_get_flags (info));
                }
-               camel_message_info_unref (info);
+               g_clear_object (&info);
        }
 
        camel_folder_summary_free_array (known_uids);
@@ -350,7 +351,7 @@ mh_summary_sync (CamelLocalSummary *cls,
 static gint
 mh_summary_decode_x_evolution (CamelLocalSummary *cls,
                                const gchar *xev,
-                               CamelLocalMessageInfo *info)
+                               CamelMessageInfo *info)
 {
        CamelLocalSummaryClass *local_summary_class;
        CamelMhSummary *mh_summary;
@@ -365,8 +366,7 @@ mh_summary_decode_x_evolution (CamelLocalSummary *cls,
        /* do not use UID from the header, rather use the one provided, if any */
        mh_summary = CAMEL_MH_SUMMARY (cls);
        if (mh_summary->priv->current_uid) {
-               camel_pstring_free (info->info.uid);
-               info->info.uid = camel_pstring_strdup (mh_summary->priv->current_uid);
+               camel_message_info_set_uid (info, mh_summary->priv->current_uid);
        }
 
        return ret;
diff --git a/src/camel/providers/local/camel-mh-summary.h b/src/camel/providers/local/camel-mh-summary.h
index 3c3ef20..e99ab8a 100644
--- a/src/camel/providers/local/camel-mh-summary.h
+++ b/src/camel/providers/local/camel-mh-summary.h
@@ -53,6 +53,9 @@ struct _CamelMhSummary {
 
 struct _CamelMhSummaryClass {
        CamelLocalSummaryClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_mh_summary_get_type       (void);
diff --git a/src/camel/providers/local/camel-spool-folder.c b/src/camel/providers/local/camel-spool-folder.c
index af8c064..d98d3b2 100644
--- a/src/camel/providers/local/camel-spool-folder.c
+++ b/src/camel/providers/local/camel-spool-folder.c
@@ -159,15 +159,14 @@ camel_spool_folder_new (CamelStore *parent_store,
                "parent-store", parent_store, NULL);
 
        if (filter_inbox && strcmp (full_name, "INBOX") == 0)
-               folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+               camel_folder_set_flags (folder, camel_folder_get_flags (folder) | CAMEL_FOLDER_FILTER_RECENT);
        flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX;
 
        folder = (CamelFolder *) camel_local_folder_construct (
                (CamelLocalFolder *) folder, flags, cancellable, error);
 
        if (folder != NULL && use_xstatus_headers)
-               camel_mbox_summary_xstatus (
-                       CAMEL_MBOX_SUMMARY (folder->summary), TRUE);
+               camel_mbox_summary_xstatus (CAMEL_MBOX_SUMMARY (camel_folder_get_folder_summary (folder)), 
TRUE);
 
        g_free (basename);
 
diff --git a/src/camel/providers/local/camel-spool-folder.h b/src/camel/providers/local/camel-spool-folder.h
index 1de8e2d..88e1e6d 100644
--- a/src/camel/providers/local/camel-spool-folder.h
+++ b/src/camel/providers/local/camel-spool-folder.h
@@ -57,6 +57,9 @@ struct _CamelSpoolFolder {
 
 struct _CamelSpoolFolderClass {
        CamelMboxFolderClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_spool_folder_get_type     (void);
diff --git a/src/camel/providers/local/camel-spool-settings.h 
b/src/camel/providers/local/camel-spool-settings.h
index 5ee0ecc..53d8d5a 100644
--- a/src/camel/providers/local/camel-spool-settings.h
+++ b/src/camel/providers/local/camel-spool-settings.h
@@ -52,6 +52,9 @@ struct _CamelSpoolSettings {
 
 struct _CamelSpoolSettingsClass {
        CamelLocalSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_spool_settings_get_type   (void) G_GNUC_CONST;
diff --git a/src/camel/providers/local/camel-spool-store.c b/src/camel/providers/local/camel-spool-store.c
index b97810d..3478091 100644
--- a/src/camel/providers/local/camel-spool-store.c
+++ b/src/camel/providers/local/camel-spool-store.c
@@ -125,7 +125,7 @@ spool_fill_fi (CamelStore *store,
 
        fi->unread = -1;
        fi->total = -1;
-       folder = camel_object_bag_peek (store->folders, fi->full_name);
+       folder = camel_object_bag_peek (camel_store_get_folders_bag (store), fi->full_name);
        if (folder) {
                if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
                        camel_folder_refresh_info_sync (folder, cancellable, NULL);
@@ -256,8 +256,7 @@ scan_dir (CamelStore *store,
                                gint isfolder = FALSE;
 
                                /* first, see if we already have it open */
-                               folder = camel_object_bag_peek (
-                                       store->folders, fname);
+                               folder = camel_object_bag_peek (camel_store_get_folders_bag (store), fname);
                                if (folder == NULL) {
                                        fp = fopen (tmp, "r");
                                        if (fp != NULL) {
diff --git a/src/camel/providers/local/camel-spool-store.h b/src/camel/providers/local/camel-spool-store.h
index d6974d1..d2e6e33 100644
--- a/src/camel/providers/local/camel-spool-store.h
+++ b/src/camel/providers/local/camel-spool-store.h
@@ -54,6 +54,9 @@ struct _CamelSpoolStore {
 
 struct _CamelSpoolStoreClass {
        CamelMboxStoreClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_spool_store_get_type      (void);
diff --git a/src/camel/providers/local/camel-spool-summary.c b/src/camel/providers/local/camel-spool-summary.c
index 44e3719..a0992d3 100644
--- a/src/camel/providers/local/camel-spool-summary.c
+++ b/src/camel/providers/local/camel-spool-summary.c
@@ -31,10 +31,11 @@
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 
-#include "camel-spool-summary.h"
 #include "camel-local-private.h"
 #include "camel-win32.h"
 
+#include "camel-spool-summary.h"
+
 #define io(x)
 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
 
@@ -60,9 +61,14 @@ G_DEFINE_TYPE (CamelSpoolSummary, camel_spool_summary, CAMEL_TYPE_MBOX_SUMMARY)
 static void
 camel_spool_summary_class_init (CamelSpoolSummaryClass *class)
 {
+       CamelFolderSummaryClass *folder_summary_class;
        CamelLocalSummaryClass *local_summary_class;
        CamelMboxSummaryClass *mbox_summary_class;
 
+       folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
+       folder_summary_class->sort_by = "bdata";
+       folder_summary_class->collate = "spool_frompos_sort";
+
        local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (class);
        local_summary_class->load = spool_summary_load;
        local_summary_class->check = spool_summary_check;
@@ -82,7 +88,7 @@ camel_spool_summary_init (CamelSpoolSummary *spool_summary)
        /* message info size is from mbox parent */
 
        /* and a unique file version */
-       folder_summary->version += CAMEL_SPOOL_SUMMARY_VERSION;
+       camel_folder_summary_set_version (folder_summary, camel_folder_summary_get_version (folder_summary) + 
CAMEL_SPOOL_SUMMARY_VERSION);
 }
 
 CamelSpoolSummary *
@@ -96,12 +102,10 @@ camel_spool_summary_new (CamelFolder *folder,
                CamelStore *parent_store;
 
                parent_store = camel_folder_get_parent_store (folder);
-               camel_db_set_collate (parent_store->cdb_r, "bdata", "spool_frompos_sort", (CamelDBCollate) 
camel_local_frompos_sort);
-               ((CamelFolderSummary *) new)->sort_by = "bdata";
-               ((CamelFolderSummary *) new)->collate = "spool_frompos_sort";
+               camel_db_set_collate (camel_store_get_db (parent_store), "bdata", "spool_frompos_sort", 
(CamelDBCollate) camel_local_frompos_sort);
        }
        camel_local_summary_construct ((CamelLocalSummary *) new, mbox_name, NULL);
-       camel_folder_summary_load_from_db ((CamelFolderSummary *) new, NULL);
+       camel_folder_summary_load ((CamelFolderSummary *) new, NULL);
        return new;
 }
 
@@ -332,10 +336,10 @@ spool_summary_check (CamelLocalSummary *cls,
        camel_folder_summary_prepare_fetch_all (s, error);
        known_uids = camel_folder_summary_get_array (s);
        for (i = 0; !work && known_uids && i < known_uids->len; i++) {
-               CamelMboxMessageInfo *info = (CamelMboxMessageInfo *) camel_folder_summary_get (s, 
g_ptr_array_index (known_uids, i));
+               CamelMessageInfo *info = camel_folder_summary_get (s, g_ptr_array_index (known_uids, i));
                g_return_val_if_fail (info, -1);
-               work = (info->info.info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV)) != 0;
-               camel_message_info_unref (info);
+               work = (camel_message_info_get_flags (info) & (CAMEL_MESSAGE_FOLDER_NOXEV)) != 0;
+               g_clear_object (&info);
        }
        camel_folder_summary_free_array (known_uids);
 
@@ -357,7 +361,7 @@ spool_summary_check (CamelLocalSummary *cls,
                }
 
                ((CamelMboxSummary *) cls)->folder_size = st.st_size;
-               ((CamelFolderSummary *) cls)->time = st.st_mtime;
+               camel_folder_summary_set_timestamp (CAMEL_FOLDER_SUMMARY (cls), st.st_mtime);
        }
 
        return 0;
diff --git a/src/camel/providers/local/camel-spool-summary.h b/src/camel/providers/local/camel-spool-summary.h
index b08adfb..74e49e3 100644
--- a/src/camel/providers/local/camel-spool-summary.h
+++ b/src/camel/providers/local/camel-spool-summary.h
@@ -49,11 +49,13 @@ typedef struct _CamelSpoolSummaryClass CamelSpoolSummaryClass;
 
 struct _CamelSpoolSummary {
        CamelMboxSummary parent;
-
 };
 
 struct _CamelSpoolSummaryClass {
        CamelMboxSummaryClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType  camel_spool_summary_get_type    (void);
@@ -75,9 +77,6 @@ CamelMessageInfo *camel_spool_summary_add (CamelSpoolSummary *cls, CamelMimeMess
 gchar *camel_spool_summary_encode_x_evolution (CamelSpoolSummary *cls, const CamelMessageInfo *info);
 gint camel_spool_summary_decode_x_evolution (CamelSpoolSummary *cls, const gchar *xev, CamelMessageInfo 
*info);
 
-/* utility functions - write headers to a file with optional X-Evolution header */
-gint camel_spool_summary_write_headers (gint fd, struct _camel_header_raw *header, gchar *xevline);
-
 G_END_DECLS
 
 #endif /* CAMEL_SPOOL_SUMMARY_H */
diff --git a/src/camel/providers/nntp/camel-nntp-folder.c b/src/camel/providers/nntp/camel-nntp-folder.c
index 8e45b11..8ff03a1 100644
--- a/src/camel/providers/nntp/camel-nntp-folder.c
+++ b/src/camel/providers/nntp/camel-nntp-folder.c
@@ -114,7 +114,7 @@ nntp_folder_dispose (GObject *object)
        CamelStore *store;
 
        folder = CAMEL_FOLDER (object);
-       camel_folder_summary_save_to_db (folder->summary, NULL);
+       camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
 
        store = camel_folder_get_parent_store (folder);
        if (store != NULL) {
@@ -124,7 +124,7 @@ nntp_folder_dispose (GObject *object)
                        CAMEL_NNTP_STORE (store));
                camel_store_summary_disconnect_folder_summary (
                        CAMEL_STORE_SUMMARY (nntp_store_summary),
-                       folder->summary);
+                       camel_folder_get_folder_summary (folder));
                g_clear_object (&nntp_store_summary);
        }
 
@@ -163,7 +163,7 @@ camel_nntp_folder_selected (CamelNNTPFolder *nntp_folder,
        parent_store = camel_folder_get_parent_store (folder);
 
        res = camel_nntp_summary_check (
-               CAMEL_NNTP_SUMMARY (folder->summary),
+               CAMEL_NNTP_SUMMARY (camel_folder_get_folder_summary (folder)),
                CAMEL_NNTP_STORE (parent_store),
                line, nntp_folder->changes,
                cancellable, error);
@@ -189,14 +189,8 @@ unset_flagged_flag (const gchar *uid,
 
        info = camel_folder_summary_get (summary, uid);
        if (info) {
-               CamelMessageInfoBase *base = (CamelMessageInfoBase *) info;
-
-               if ((base->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0) {
-                       base->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
-                       base->dirty = TRUE;
-               }
-
-               camel_message_info_unref (info);
+               camel_message_info_set_folder_flagged (info, FALSE);
+               g_clear_object (&info);
        }
 }
 
@@ -410,8 +404,9 @@ nntp_folder_append_message_sync (CamelFolder *folder,
        CamelStream *filtered_stream;
        CamelMimeFilter *crlffilter;
        gint ret;
-       guint u;
-       struct _camel_header_raw *header, *savedhdrs, *n, *tail;
+       guint u, ii;
+       CamelNameValueArray *previous_headers = NULL;
+       const gchar *header_name = NULL, *header_value = NULL;
        const gchar *full_name;
        gchar *group, *line;
        gboolean success = TRUE;
@@ -445,24 +440,11 @@ nntp_folder_append_message_sync (CamelFolder *folder,
        /* the 'Newsgroups: ' header */
        group = g_strdup_printf ("Newsgroups: %s\r\n", full_name);
 
-       /* remove mail 'To', 'CC', and 'BCC' headers */
-       savedhdrs = NULL;
-       tail = (struct _camel_header_raw *) &savedhdrs;
-
-       header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers;
-       n = header->next;
-       while (n != NULL) {
-               if (!g_ascii_strcasecmp (n->name, "To") || !g_ascii_strcasecmp (n->name, "Cc") || 
!g_ascii_strcasecmp (n->name, "Bcc")) {
-                       header->next = n->next;
-                       tail->next = n;
-                       n->next = NULL;
-                       tail = n;
-               } else {
-                       header = n;
-               }
-
-               n = header->next;
-       }
+       /* remove mail 'To', 'Cc', and 'Bcc' headers */
+       previous_headers = camel_medium_dup_headers (CAMEL_MEDIUM (message));
+       camel_medium_remove_header (CAMEL_MEDIUM (message), "To");
+       camel_medium_remove_header (CAMEL_MEDIUM (message), "Cc");
+       camel_medium_remove_header (CAMEL_MEDIUM (message), "Bcc");
 
        nntp_stream = camel_nntp_store_ref_stream (nntp_store);
 
@@ -509,7 +491,16 @@ nntp_folder_append_message_sync (CamelFolder *folder,
 
        g_object_unref (filtered_stream);
        g_free (group);
-       header->next = savedhdrs;
+       /* restore the bcc headers */
+       for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); ii++) {
+               if (!g_ascii_strcasecmp (header_name, "To") ||
+                   !g_ascii_strcasecmp (header_name, "Cc") ||
+                   !g_ascii_strcasecmp (header_name, "Bcc")) {
+                       camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value);
+               }
+       }
+
+       camel_name_value_array_free (previous_headers);
 
 exit:
        g_clear_object (&nntp_stream);
@@ -527,7 +518,7 @@ nntp_folder_expunge_sync (CamelFolder *folder,
        GPtrArray *known_uids;
        guint ii;
 
-       summary = folder->summary;
+       summary = camel_folder_get_folder_summary (folder);
 
        camel_folder_summary_prepare_fetch_all (summary, NULL);
        known_uids = camel_folder_summary_get_array (summary);
@@ -549,10 +540,10 @@ nntp_folder_expunge_sync (CamelFolder *folder,
                        camel_folder_summary_remove (summary, info);
                }
 
-               camel_message_info_unref (info);
+               g_clear_object (&info);
        }
 
-       camel_folder_summary_save_to_db (summary, NULL);
+       camel_folder_summary_save (summary, NULL);
        camel_folder_changed (folder, changes);
 
        camel_folder_change_info_free (changes);
@@ -695,7 +686,7 @@ nntp_folder_synchronize_sync (CamelFolder *folder,
                        return FALSE;
        }
 
-       summary = folder->summary;
+       summary = camel_folder_get_folder_summary (folder);
 
        changed = camel_folder_summary_get_changed (summary);
        if (changed != NULL) {
@@ -707,7 +698,7 @@ nntp_folder_synchronize_sync (CamelFolder *folder,
                g_ptr_array_free (changed, TRUE);
        }
 
-       return camel_folder_summary_save_to_db (summary, error);
+       return camel_folder_summary_save (summary, error);
 }
 
 static gboolean
@@ -813,7 +804,7 @@ camel_nntp_folder_new (CamelStore *parent,
                "parent-store", parent, NULL);
        nntp_folder = (CamelNNTPFolder *) folder;
 
-       folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
+       camel_folder_set_flags (folder, camel_folder_get_flags (folder) | 
CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY);
 
        storage_path = g_build_filename (user_cache_dir, folder_name, NULL);
        root = g_strdup_printf ("%s.cmeta", storage_path);
@@ -822,12 +813,12 @@ camel_nntp_folder_new (CamelStore *parent,
        g_free (root);
        g_free (storage_path);
 
-       folder->summary = (CamelFolderSummary *) camel_nntp_summary_new (folder);
+       camel_folder_take_folder_summary (folder, (CamelFolderSummary *) camel_nntp_summary_new (folder));
 
        if (filter_all || nntp_folder_get_apply_filters (nntp_folder))
-               folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+               camel_folder_set_flags (folder, camel_folder_get_flags (folder) | CAMEL_FOLDER_FILTER_RECENT);
 
-       camel_folder_summary_load_from_db (folder->summary, NULL);
+       camel_folder_summary_load (camel_folder_get_folder_summary (folder), NULL);
 
        nntp_store = CAMEL_NNTP_STORE (parent);
        nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
@@ -843,7 +834,7 @@ camel_nntp_folder_new (CamelStore *parent,
 
        camel_store_summary_connect_folder_summary (
                CAMEL_STORE_SUMMARY (nntp_store_summary),
-               folder_name, folder->summary);
+               folder_name, camel_folder_get_folder_summary (folder));
 
        g_clear_object (&nntp_store_summary);
 
diff --git a/src/camel/providers/nntp/camel-nntp-folder.h b/src/camel/providers/nntp/camel-nntp-folder.h
index 7f8308d..b3ba625 100644
--- a/src/camel/providers/nntp/camel-nntp-folder.h
+++ b/src/camel/providers/nntp/camel-nntp-folder.h
@@ -58,6 +58,9 @@ struct _CamelNNTPFolder {
 
 struct _CamelNNTPFolderClass {
        CamelOfflineFolderClass parent;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_nntp_folder_get_type      (void);
diff --git a/src/camel/providers/nntp/camel-nntp-settings.h b/src/camel/providers/nntp/camel-nntp-settings.h
index c934456..74b198e 100644
--- a/src/camel/providers/nntp/camel-nntp-settings.h
+++ b/src/camel/providers/nntp/camel-nntp-settings.h
@@ -52,6 +52,9 @@ struct _CamelNNTPSettings {
 
 struct _CamelNNTPSettingsClass {
        CamelOfflineSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_nntp_settings_get_type
diff --git a/src/camel/providers/nntp/camel-nntp-store-summary.h 
b/src/camel/providers/nntp/camel-nntp-store-summary.h
index c7cd5a5..40abc42 100644
--- a/src/camel/providers/nntp/camel-nntp-store-summary.h
+++ b/src/camel/providers/nntp/camel-nntp-store-summary.h
@@ -76,6 +76,9 @@ struct _CamelNNTPStoreSummary {
 
 struct _CamelNNTPStoreSummaryClass {
        CamelStoreSummaryClass summary_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_nntp_store_summary_get_type
diff --git a/src/camel/providers/nntp/camel-nntp-store.c b/src/camel/providers/nntp/camel-nntp-store.c
index 100dd09..8d0586e 100644
--- a/src/camel/providers/nntp/camel-nntp-store.c
+++ b/src/camel/providers/nntp/camel-nntp-store.c
@@ -1140,7 +1140,8 @@ store_info_remove (gpointer key,
 
 static gint
 store_info_sort (gconstpointer a,
-                 gconstpointer b)
+                gconstpointer b,
+                gpointer user_data)
 {
        return strcmp ((*(CamelNNTPStoreInfo **) a)->full_name, (*(CamelNNTPStoreInfo **) b)->full_name);
 }
@@ -1276,9 +1277,8 @@ nntp_store_get_folder_info_all (CamelNNTPStore *nntp_store,
                }
 
                /* sort the list */
-               g_ptr_array_sort (
-                       CAMEL_STORE_SUMMARY (nntp_store_summary)->folders,
-                       store_info_sort);
+               camel_store_summary_sort (CAMEL_STORE_SUMMARY (nntp_store_summary), store_info_sort, NULL);
+
                if (ret < 0)
                        goto error;
 
@@ -1471,7 +1471,7 @@ nntp_store_initable_init (GInitable *initable,
        store = CAMEL_STORE (initable);
        service = CAMEL_SERVICE (initable);
 
-       store->flags |= CAMEL_STORE_USE_CACHE_DIR;
+       camel_store_set_flags (store, camel_store_get_flags (store) | CAMEL_STORE_USE_CACHE_DIR);
        nntp_migrate_to_user_cache_dir (service);
 
        /* Chain up to parent interface's init() method. */
@@ -1783,7 +1783,7 @@ camel_nntp_store_init (CamelNNTPStore *nntp_store)
 
        /* Clear the default flags.  We don't want a virtual Junk or Trash
         * folder and the user can't create/delete/rename newsgroup folders. */
-       CAMEL_STORE (nntp_store)->flags = 0;
+       camel_store_set_flags (CAMEL_STORE (nntp_store), 0);
 }
 
 /**
diff --git a/src/camel/providers/nntp/camel-nntp-store.h b/src/camel/providers/nntp/camel-nntp-store.h
index 8050b96..69f1832 100644
--- a/src/camel/providers/nntp/camel-nntp-store.h
+++ b/src/camel/providers/nntp/camel-nntp-store.h
@@ -81,6 +81,9 @@ struct _CamelNNTPStore {
 
 struct _CamelNNTPStoreClass {
        CamelOfflineStoreClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_nntp_store_get_type       (void);
diff --git a/src/camel/providers/nntp/camel-nntp-stream.h b/src/camel/providers/nntp/camel-nntp-stream.h
index a54ca16..cb33405 100644
--- a/src/camel/providers/nntp/camel-nntp-stream.h
+++ b/src/camel/providers/nntp/camel-nntp-stream.h
@@ -65,6 +65,9 @@ struct _CamelNNTPStream {
 
 struct _CamelNNTPStreamClass {
        CamelStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_nntp_stream_get_type      (void);
diff --git a/src/camel/providers/nntp/camel-nntp-summary.c b/src/camel/providers/nntp/camel-nntp-summary.c
index d4c47aa..bae3279 100644
--- a/src/camel/providers/nntp/camel-nntp-summary.c
+++ b/src/camel/providers/nntp/camel-nntp-summary.c
@@ -51,9 +51,9 @@ struct _CamelNNTPSummaryPrivate {
        gint xover_setup;
 };
 
-static CamelMessageInfo * message_info_new_from_header (CamelFolderSummary *, struct _camel_header_raw *);
-static gboolean summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir);
-static CamelFIRecord * summary_header_to_db (CamelFolderSummary *s, GError **error);
+static CamelMessageInfo * message_info_new_from_headers (CamelFolderSummary *, const CamelNameValueArray *);
+static gboolean summary_header_load (CamelFolderSummary *s, CamelFIRecord *mir);
+static CamelFIRecord * summary_header_save (CamelFolderSummary *s, GError **error);
 
 G_DEFINE_TYPE (CamelNNTPSummary, camel_nntp_summary, CAMEL_TYPE_FOLDER_SUMMARY)
 
@@ -65,11 +65,9 @@ camel_nntp_summary_class_init (CamelNNTPSummaryClass *class)
        g_type_class_add_private (class, sizeof (CamelNNTPSummaryPrivate));
 
        folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
-       folder_summary_class->message_info_size = sizeof (CamelMessageInfoBase);
-       folder_summary_class->content_info_size = sizeof (CamelMessageContentInfo);
-       folder_summary_class->message_info_new_from_header = message_info_new_from_header;
-       folder_summary_class->summary_header_from_db = summary_header_from_db;
-       folder_summary_class->summary_header_to_db = summary_header_to_db;
+       folder_summary_class->message_info_new_from_headers = message_info_new_from_headers;
+       folder_summary_class->summary_header_load = summary_header_load;
+       folder_summary_class->summary_header_save = summary_header_save;
 }
 
 static void
@@ -80,7 +78,7 @@ camel_nntp_summary_init (CamelNNTPSummary *nntp_summary)
        nntp_summary->priv = CAMEL_NNTP_SUMMARY_GET_PRIVATE (nntp_summary);
 
        /* and a unique file version */
-       summary->version += CAMEL_NNTP_SUMMARY_VERSION;
+       camel_folder_summary_set_version (summary, camel_folder_summary_get_version (summary) + 
CAMEL_NNTP_SUMMARY_VERSION);
 }
 
 CamelNNTPSummary *
@@ -90,60 +88,57 @@ camel_nntp_summary_new (CamelFolder *folder)
 
        cns = g_object_new (CAMEL_TYPE_NNTP_SUMMARY, "folder", folder, NULL);
 
-       camel_folder_summary_set_build_content ((CamelFolderSummary *) cns, FALSE);
-
        return cns;
 }
 
 static CamelMessageInfo *
-message_info_new_from_header (CamelFolderSummary *s,
-                              struct _camel_header_raw *h)
+message_info_new_from_headers (CamelFolderSummary *summary,
+                              const CamelNameValueArray *headers)
 {
-       CamelMessageInfoBase *mi;
-       CamelNNTPSummary *cns = (CamelNNTPSummary *) s;
+       CamelMessageInfo *mi;
+       CamelNNTPSummary *cns = (CamelNNTPSummary *) summary;
 
        /* error to call without this setup */
        if (cns->priv->uid == NULL)
                return NULL;
 
-       mi = (CamelMessageInfoBase *) CAMEL_FOLDER_SUMMARY_CLASS 
(camel_nntp_summary_parent_class)->message_info_new_from_header (s, h);
+       mi = CAMEL_FOLDER_SUMMARY_CLASS (camel_nntp_summary_parent_class)->message_info_new_from_headers 
(summary, headers);
        if (mi) {
-               camel_pstring_free (mi->uid);
-               mi->uid = camel_pstring_strdup (cns->priv->uid);
+               camel_message_info_set_uid (mi, cns->priv->uid);
                g_free (cns->priv->uid);
                cns->priv->uid = NULL;
        }
 
-       return (CamelMessageInfo *) mi;
+       return mi;
 }
 
 static gboolean
-summary_header_from_db (CamelFolderSummary *s,
-                        CamelFIRecord *mir)
+summary_header_load (CamelFolderSummary *s,
+                    CamelFIRecord *mir)
 {
        CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY (s);
        gchar *part;
 
-       if (!CAMEL_FOLDER_SUMMARY_CLASS (camel_nntp_summary_parent_class)->summary_header_from_db (s, mir))
+       if (!CAMEL_FOLDER_SUMMARY_CLASS (camel_nntp_summary_parent_class)->summary_header_load (s, mir))
                return FALSE;
 
        part = mir->bdata;
 
-       cns->version = bdata_extract_digit (&part);
-       cns->high = bdata_extract_digit (&part);
-       cns->low = bdata_extract_digit (&part);
+       cns->version = camel_util_bdata_get_number (&part, 0);
+       cns->high = camel_util_bdata_get_number (&part, 0);
+       cns->low = camel_util_bdata_get_number (&part, 0);
 
        return TRUE;
 }
 
 static CamelFIRecord *
-summary_header_to_db (CamelFolderSummary *s,
-                      GError **error)
+summary_header_save (CamelFolderSummary *s,
+                    GError **error)
 {
        CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY (s);
        struct _CamelFIRecord *fir;
 
-       fir = CAMEL_FOLDER_SUMMARY_CLASS (camel_nntp_summary_parent_class)->summary_header_to_db (s, error);
+       fir = CAMEL_FOLDER_SUMMARY_CLASS (camel_nntp_summary_parent_class)->summary_header_save (s, error);
        if (!fir)
                return NULL;
        fir->bdata = g_strdup_printf ("%d %d %d", CAMEL_NNTP_SUMMARY_VERSION, cns->high, cns->low);
@@ -169,7 +164,7 @@ add_range_xover (CamelNNTPSummary *cns,
        CamelSettings *settings;
        CamelService *service;
        CamelFolderSummary *s;
-       struct _camel_header_raw *headers = NULL;
+       CamelNameValueArray *headers = NULL;
        gchar *line, *tab;
        gchar *host;
        guint len;
@@ -180,7 +175,7 @@ add_range_xover (CamelNNTPSummary *cns,
 
        s = (CamelFolderSummary *) cns;
        folder_filter_recent = camel_folder_summary_get_folder (s) &&
-               (camel_folder_summary_get_folder (s)->folder_flags & CAMEL_FOLDER_FILTER_RECENT) != 0;
+               (camel_folder_get_flags (camel_folder_summary_get_folder (s)) & CAMEL_FOLDER_FILTER_RECENT) 
!= 0;
 
        service = CAMEL_SERVICE (nntp_store);
 
@@ -222,6 +217,7 @@ add_range_xover (CamelNNTPSummary *cns,
 
        count = 0;
        total = high - low + 1;
+       headers = camel_name_value_array_new ();
        while ((ret = camel_nntp_stream_line (nntp_stream, (guchar **) &line, &len, cancellable, error)) > 0) 
{
                camel_operation_progress (cancellable, (count * 100) / total);
                count++;
@@ -243,7 +239,7 @@ add_range_xover (CamelNNTPSummary *cns,
                        if (xover->name) {
                                line += xover->skip;
                                if (line < tab) {
-                                       camel_header_raw_append (&headers, xover->name, line, -1);
+                                       camel_name_value_array_append (headers, xover->name, line);
                                        switch (xover->type) {
                                        case XOVER_STRING:
                                                break;
@@ -267,14 +263,15 @@ add_range_xover (CamelNNTPSummary *cns,
                        if (!camel_folder_summary_check_uid (s, cns->priv->uid)) {
                                CamelMessageInfo *mi;
 
-                               mi = camel_folder_summary_info_new_from_header (s, headers);
-                               ((CamelMessageInfoBase *) mi)->size = size;
-                               camel_folder_summary_add (s, mi);
+                               mi = camel_folder_summary_info_new_from_headers (s, headers);
+                               camel_message_info_set_size (mi, size);
+                               camel_folder_summary_add (s, mi, FALSE);
 
                                cns->high = n;
                                camel_folder_change_info_add_uid (changes, camel_message_info_get_uid (mi));
                                if (folder_filter_recent)
                                        camel_folder_change_info_recent_uid (changes, 
camel_message_info_get_uid (mi));
+                               g_clear_object (&mi);
                        }
                }
 
@@ -283,9 +280,10 @@ add_range_xover (CamelNNTPSummary *cns,
                        cns->priv->uid = NULL;
                }
 
-               camel_header_raw_clear (&headers);
+               camel_name_value_array_clear (headers);
        }
 
+       camel_name_value_array_free (headers);
        g_clear_object (&nntp_stream);
 
        camel_operation_pop_message (cancellable);
@@ -318,7 +316,7 @@ add_range_head (CamelNNTPSummary *cns,
 
        s = (CamelFolderSummary *) cns;
        folder_filter_recent = camel_folder_summary_get_folder (s) &&
-               (camel_folder_summary_get_folder (s)->folder_flags & CAMEL_FOLDER_FILTER_RECENT) != 0;
+               (camel_folder_get_flags (camel_folder_summary_get_folder (s)) & CAMEL_FOLDER_FILTER_RECENT) 
!= 0;
 
        mp = camel_mime_parser_new ();
 
@@ -370,7 +368,7 @@ add_range_head (CamelNNTPSummary *cns,
                                if (camel_mime_parser_init_with_stream (mp, CAMEL_STREAM (nntp_stream), 
error) == -1)
                                        goto error;
                                mi = camel_folder_summary_info_new_from_parser (s, mp);
-                               camel_folder_summary_add (s, mi);
+                               camel_folder_summary_add (s, mi, FALSE);
                                while (camel_mime_parser_step (mp, NULL, NULL) != CAMEL_MIME_PARSER_STATE_EOF)
                                        ;
                                if (mi == NULL) {
@@ -380,6 +378,7 @@ add_range_head (CamelNNTPSummary *cns,
                                camel_folder_change_info_add_uid (changes, camel_message_info_get_uid (mi));
                                if (folder_filter_recent)
                                        camel_folder_change_info_recent_uid (changes, 
camel_message_info_get_uid (mi));
+                               g_clear_object (&mi);
                        }
                        if (cns->priv->uid) {
                                g_free (cns->priv->uid);
@@ -504,7 +503,7 @@ camel_nntp_summary_check (CamelNNTPSummary *cns,
                                        mi = camel_folder_summary_peek_loaded (s, uid);
                                        if (mi) {
                                                camel_folder_summary_remove (s, mi);
-                                               camel_message_info_unref (mi);
+                                               g_clear_object (&mi);
                                        } else {
                                                camel_folder_summary_remove_uid (s, uid);
                                        }
@@ -517,7 +516,7 @@ camel_nntp_summary_check (CamelNNTPSummary *cns,
                g_clear_object (&nntp_cache);
        }
 
-       camel_db_delete_uids (parent_store->cdb_w, full_name, del, NULL);
+       camel_db_delete_uids (camel_store_get_db (parent_store), full_name, del, NULL);
        g_list_foreach (del, (GFunc) camel_pstring_free, NULL);
        g_list_free (del);
 
@@ -537,7 +536,7 @@ camel_nntp_summary_check (CamelNNTPSummary *cns,
 
        /* TODO: not from here */
        camel_folder_summary_touch (s);
-       camel_folder_summary_save_to_db (s, NULL);
+       camel_folder_summary_save (s, NULL);
 
 update:
        /* update store summary if we have it */
@@ -554,8 +553,7 @@ update:
                guint32 unread = 0;
 
                count = camel_folder_summary_count (s);
-               camel_db_count_unread_message_info (
-                       parent_store->cdb_r, full_name, &unread, NULL);
+               camel_db_count_unread_message_info (camel_store_get_db (parent_store), full_name, &unread, 
NULL);
 
                if (si->info.unread != unread
                    || si->info.total != count
diff --git a/src/camel/providers/nntp/camel-nntp-summary.h b/src/camel/providers/nntp/camel-nntp-summary.h
index 941721a..f8a2c36 100644
--- a/src/camel/providers/nntp/camel-nntp-summary.h
+++ b/src/camel/providers/nntp/camel-nntp-summary.h
@@ -59,6 +59,9 @@ struct _CamelNNTPSummary {
 
 struct _CamelNNTPSummaryClass {
        CamelFolderSummaryClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_nntp_summary_get_type     (void);
diff --git a/src/camel/providers/pop3/camel-pop3-engine.h b/src/camel/providers/pop3/camel-pop3-engine.h
index c71a464..768fd6f 100644
--- a/src/camel/providers/pop3/camel-pop3-engine.h
+++ b/src/camel/providers/pop3/camel-pop3-engine.h
@@ -139,6 +139,9 @@ struct _CamelPOP3Engine {
 
 struct _CamelPOP3EngineClass {
        GObjectClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_pop3_engine_get_type      (void);
diff --git a/src/camel/providers/pop3/camel-pop3-folder.c b/src/camel/providers/pop3/camel-pop3-folder.c
index bb7042e..2beb51e 100644
--- a/src/camel/providers/pop3/camel-pop3-folder.c
+++ b/src/camel/providers/pop3/camel-pop3-folder.c
@@ -90,10 +90,12 @@ cmd_builduid (CamelPOP3Engine *pe,
 {
        GChecksum *checksum;
        CamelPOP3FolderInfo *fi = data;
-       struct _camel_header_raw *h;
+       CamelNameValueArray *h;
        CamelMimeParser *mp;
        guint8 *digest;
        gsize length;
+       guint ii;
+       const gchar *header_name = NULL, *header_value = NULL;
 
        length = g_checksum_type_get_length (G_CHECKSUM_MD5);
        digest = g_alloca (length);
@@ -109,15 +111,16 @@ cmd_builduid (CamelPOP3Engine *pe,
        case CAMEL_MIME_PARSER_STATE_HEADER:
        case CAMEL_MIME_PARSER_STATE_MESSAGE:
        case CAMEL_MIME_PARSER_STATE_MULTIPART:
-               h = camel_mime_parser_headers_raw (mp);
-               while (h) {
-                       if (g_ascii_strcasecmp (h->name, "status") != 0
-                           && g_ascii_strcasecmp (h->name, "x-status") != 0) {
-                               g_checksum_update (checksum, (guchar *) h->name, -1);
-                               g_checksum_update (checksum, (guchar *) h->value, -1);
+               h = camel_mime_parser_dup_headers (mp);
+               for (ii = 0; camel_name_value_array_get (h, ii, &header_name, &header_value); ii++) {
+                       if (g_ascii_strcasecmp (header_name, "status") != 0
+                           && g_ascii_strcasecmp (header_name, "x-status") != 0) {
+                               g_checksum_update (checksum, (guchar *) header_name, -1);
+                               g_checksum_update (checksum, (guchar *) header_value, -1);
                        }
-                       h = h->next;
                }
+
+               camel_name_value_array_free (h);
        default:
                break;
        }
@@ -372,8 +375,8 @@ pop3_folder_get_filename (CamelFolder *folder,
 static gboolean
 pop3_folder_set_message_flags (CamelFolder *folder,
                                const gchar *uid,
-                               CamelMessageFlags flags,
-                               CamelMessageFlags set)
+                               guint32 flags,
+                               guint32 set)
 {
        CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder);
        CamelPOP3FolderInfo *fi;
@@ -1005,8 +1008,10 @@ pop3_get_message_time_from_cache (CamelFolder *folder,
                }
 
                if (message) {
+                       gint date_offset = 0;
+
                        res = TRUE;
-                       *message_time = message->date + message->date_offset;
+                       *message_time = camel_mime_message_get_date (message, &date_offset) + date_offset;
 
                        g_object_unref (message);
                }
@@ -1092,7 +1097,8 @@ camel_pop3_folder_delete_old (CamelFolder *folder,
                        message = pop3_folder_get_message_internal_sync (
                                folder, fi->uid, TRUE, cancellable, error);
                        if (message) {
-                               message_time = message->date + message->date_offset;
+                               gint date_offset = 0;
+                               message_time = camel_mime_message_get_date (message, &date_offset) + 
date_offset;
                                g_object_unref (message);
                        }
                }
diff --git a/src/camel/providers/pop3/camel-pop3-folder.h b/src/camel/providers/pop3/camel-pop3-folder.h
index 2cd2ab1..67a25d1 100644
--- a/src/camel/providers/pop3/camel-pop3-folder.h
+++ b/src/camel/providers/pop3/camel-pop3-folder.h
@@ -69,6 +69,9 @@ struct _CamelPOP3Folder {
 
 struct _CamelPOP3FolderClass {
        CamelFolderClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_pop3_folder_get_type      (void);
diff --git a/src/camel/providers/pop3/camel-pop3-settings.h b/src/camel/providers/pop3/camel-pop3-settings.h
index 2f5d2f3..d69b71b 100644
--- a/src/camel/providers/pop3/camel-pop3-settings.h
+++ b/src/camel/providers/pop3/camel-pop3-settings.h
@@ -52,6 +52,9 @@ struct _CamelPOP3Settings {
 
 struct _CamelPOP3SettingsClass {
        CamelStoreSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_pop3_settings_get_type    (void) G_GNUC_CONST;
diff --git a/src/camel/providers/pop3/camel-pop3-store.h b/src/camel/providers/pop3/camel-pop3-store.h
index 58432d6..63e559e 100644
--- a/src/camel/providers/pop3/camel-pop3-store.h
+++ b/src/camel/providers/pop3/camel-pop3-store.h
@@ -58,6 +58,9 @@ struct _CamelPOP3Store {
 
 struct _CamelPOP3StoreClass {
        CamelStoreClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_pop3_store_get_type       (void);
diff --git a/src/camel/providers/pop3/camel-pop3-stream.h b/src/camel/providers/pop3/camel-pop3-stream.h
index 2c4a51a..bb6dbb9 100644
--- a/src/camel/providers/pop3/camel-pop3-stream.h
+++ b/src/camel/providers/pop3/camel-pop3-stream.h
@@ -68,6 +68,9 @@ struct _CamelPOP3Stream {
 
 struct _CamelPOP3StreamClass {
        CamelStreamClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_pop3_stream_get_type      (void);
diff --git a/src/camel/providers/sendmail/camel-sendmail-provider.c 
b/src/camel/providers/sendmail/camel-sendmail-provider.c
index 7a8124a..a79afc7 100644
--- a/src/camel/providers/sendmail/camel-sendmail-provider.c
+++ b/src/camel/providers/sendmail/camel-sendmail-provider.c
@@ -52,8 +52,8 @@ camel_provider_module_init (void)
        sendmail_provider.object_types[CAMEL_PROVIDER_TRANSPORT] =
                CAMEL_TYPE_SENDMAIL_TRANSPORT;
 
-       sendmail_provider.url_hash = camel_url_hash;
-       sendmail_provider.url_equal = camel_url_equal;
+       sendmail_provider.url_hash = (GHashFunc) camel_url_hash;
+       sendmail_provider.url_equal = (GEqualFunc) camel_url_equal;
        sendmail_provider.translation_domain = GETTEXT_PACKAGE;
 
        camel_provider_register (&sendmail_provider);
diff --git a/src/camel/providers/sendmail/camel-sendmail-settings.h 
b/src/camel/providers/sendmail/camel-sendmail-settings.h
index 5c3d152..4afa013 100644
--- a/src/camel/providers/sendmail/camel-sendmail-settings.h
+++ b/src/camel/providers/sendmail/camel-sendmail-settings.h
@@ -52,6 +52,9 @@ struct _CamelSendmailSettings {
 
 struct _CamelSendmailSettingsClass {
        CamelSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_sendmail_settings_get_type
diff --git a/src/camel/providers/sendmail/camel-sendmail-transport.c 
b/src/camel/providers/sendmail/camel-sendmail-transport.c
index 7767945..ca1edf6 100644
--- a/src/camel/providers/sendmail/camel-sendmail-transport.c
+++ b/src/camel/providers/sendmail/camel-sendmail-transport.c
@@ -112,7 +112,8 @@ sendmail_send_to_sync (CamelTransport *transport,
                        GCancellable *cancellable,
                        GError **error)
 {
-       struct _camel_header_raw *header, *savedbcc, *n, *tail;
+       CamelNameValueArray *previous_headers = NULL;
+       const gchar *header_name = NULL, *header_value = NULL;
        const gchar *from_addr, *addr;
        GPtrArray *argv_arr;
        gint i, len, fd[2], nullfd, wstat;
@@ -125,6 +126,7 @@ sendmail_send_to_sync (CamelTransport *transport,
        gchar *custom_binary = NULL, *custom_args = NULL;
        gboolean success;
        pid_t pid;
+       guint ii;
 
        success = camel_internet_address_get (
                CAMEL_INTERNET_ADDRESS (from), 0, NULL, &from_addr);
@@ -203,23 +205,8 @@ sendmail_send_to_sync (CamelTransport *transport,
        }
 
        /* unlink the bcc headers */
-       savedbcc = NULL;
-       tail = (struct _camel_header_raw *) &savedbcc;
-
-       header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers;
-       n = header->next;
-       while (n != NULL) {
-               if (!g_ascii_strcasecmp (n->name, "Bcc")) {
-                       header->next = n->next;
-                       tail->next = n;
-                       n->next = NULL;
-                       tail = n;
-               } else {
-                       header = n;
-               }
-
-               n = header->next;
-       }
+       previous_headers = camel_medium_dup_headers (CAMEL_MEDIUM (message));
+       camel_medium_remove_header (CAMEL_MEDIUM (message), "Bcc");
 
        if (pipe (fd) == -1) {
                g_set_error (
@@ -229,7 +216,13 @@ sendmail_send_to_sync (CamelTransport *transport,
                        "mail not sent"), binary, g_strerror (errno));
 
                /* restore the bcc headers */
-               header->next = savedbcc;
+               for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); 
ii++) {
+                       if (!g_ascii_strcasecmp (header_name, "Bcc")) {
+                               camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value);
+                       }
+               }
+
+               camel_name_value_array_free (previous_headers);
                g_free (custom_binary);
                g_free (custom_args);
                g_ptr_array_free (argv_arr, TRUE);
@@ -257,7 +250,13 @@ sendmail_send_to_sync (CamelTransport *transport,
                sigprocmask (SIG_SETMASK, &omask, NULL);
 
                /* restore the bcc headers */
-               header->next = savedbcc;
+               for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); 
ii++) {
+                       if (!g_ascii_strcasecmp (header_name, "Bcc")) {
+                               camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value);
+                       }
+               }
+
+               camel_name_value_array_free (previous_headers);
                g_free (custom_binary);
                g_free (custom_args);
                g_ptr_array_free (argv_arr, TRUE);
@@ -308,7 +307,13 @@ sendmail_send_to_sync (CamelTransport *transport,
                sigprocmask (SIG_SETMASK, &omask, NULL);
 
                /* restore the bcc headers */
-               header->next = savedbcc;
+               for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); 
ii++) {
+                       if (!g_ascii_strcasecmp (header_name, "Bcc")) {
+                               camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value);
+                       }
+               }
+
+               camel_name_value_array_free (previous_headers);
                g_free (custom_binary);
                g_free (custom_args);
 
@@ -324,7 +329,13 @@ sendmail_send_to_sync (CamelTransport *transport,
        sigprocmask (SIG_SETMASK, &omask, NULL);
 
        /* restore the bcc headers */
-       header->next = savedbcc;
+       for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); ii++) {
+               if (!g_ascii_strcasecmp (header_name, "Bcc")) {
+                       camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value);
+               }
+       }
+
+       camel_name_value_array_free (previous_headers);
 
        if (!WIFEXITED (wstat)) {
                g_set_error (
diff --git a/src/camel/providers/sendmail/camel-sendmail-transport.h 
b/src/camel/providers/sendmail/camel-sendmail-transport.h
index 77171cb..cb548ed 100644
--- a/src/camel/providers/sendmail/camel-sendmail-transport.h
+++ b/src/camel/providers/sendmail/camel-sendmail-transport.h
@@ -53,6 +53,9 @@ struct _CamelSendmailTransport {
 
 struct _CamelSendmailTransportClass {
        CamelTransportClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_sendmail_transport_get_type (void);
diff --git a/src/camel/providers/smtp/camel-smtp-settings.h b/src/camel/providers/smtp/camel-smtp-settings.h
index b37739a..e2dd454 100644
--- a/src/camel/providers/smtp/camel-smtp-settings.h
+++ b/src/camel/providers/smtp/camel-smtp-settings.h
@@ -52,6 +52,9 @@ struct _CamelSmtpSettings {
 
 struct _CamelSmtpSettingsClass {
        CamelSettingsClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType          camel_smtp_settings_get_type    (void) G_GNUC_CONST;
diff --git a/src/camel/providers/smtp/camel-smtp-transport.c b/src/camel/providers/smtp/camel-smtp-transport.c
index 44e96bf..dc39930 100644
--- a/src/camel/providers/smtp/camel-smtp-transport.c
+++ b/src/camel/providers/smtp/camel-smtp-transport.c
@@ -1639,13 +1639,15 @@ smtp_data (CamelSmtpTransport *transport,
            GCancellable *cancellable,
            GError **error)
 {
-       struct _camel_header_raw *header, *savedbcc, *n, *tail;
+       CamelNameValueArray *previous_headers;
+       const gchar *header_name = NULL, *header_value = NULL;
        CamelBestencEncoding enctype = CAMEL_BESTENC_8BIT;
        CamelStream *filtered_stream;
        gchar *cmdbuf, *respbuf = NULL;
        CamelMimeFilter *filter;
-       CamelStreamNull *null;
+       gsize bytes_written;
        gint ret;
+       guint ii;
 
        /* If the server doesn't support 8BITMIME, set our required encoding to be 7bit */
        if (!(transport->flags & CAMEL_SMTP_TRANSPORT_8BITMIME))
@@ -1694,42 +1696,23 @@ smtp_data (CamelSmtpTransport *transport,
        g_free (respbuf);
        respbuf = NULL;
 
-       /* unlink the bcc headers */
-       savedbcc = NULL;
-       tail = (struct _camel_header_raw *) &savedbcc;
-
-       header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers;
-       n = header->next;
-       while (n != NULL) {
-               if (!g_ascii_strcasecmp (n->name, "Bcc")) {
-                       header->next = n->next;
-                       tail->next = n;
-                       n->next = NULL;
-                       tail = n;
-               } else {
-                       header = n;
-               }
-
-               n = header->next;
-       }
+       /* unlink the bcc headers and keep a copy of them */
+       previous_headers = camel_medium_dup_headers (CAMEL_MEDIUM (message));
+       camel_medium_remove_header (CAMEL_MEDIUM (message), "Bcc");
 
        /* find out how large the message is... */
-       null = CAMEL_STREAM_NULL (camel_stream_null_new ());
-       camel_data_wrapper_write_to_stream_sync (
-               CAMEL_DATA_WRAPPER (message),
-               CAMEL_STREAM (null), NULL, NULL);
+       bytes_written = camel_data_wrapper_calculate_size_sync (CAMEL_DATA_WRAPPER (message), NULL, NULL);
 
        /* Set the upload timeout to an equal of 512 bytes per second */
-       smtp_maybe_update_socket_timeout (ostream, null->written / 512);
+       smtp_maybe_update_socket_timeout (ostream, bytes_written / 512);
 
        filtered_stream = camel_stream_filter_new (ostream);
 
        /* setup progress reporting for message sending... */
-       filter = camel_mime_filter_progress_new (cancellable, null->written);
+       filter = camel_mime_filter_progress_new (cancellable, bytes_written);
        camel_stream_filter_add (
                CAMEL_STREAM_FILTER (filtered_stream), filter);
        g_object_unref (filter);
-       g_object_unref (null);
 
        /* setup LF->CRLF conversion */
        filter = camel_mime_filter_crlf_new (
@@ -1745,7 +1728,13 @@ smtp_data (CamelSmtpTransport *transport,
                filtered_stream, cancellable, error);
 
        /* restore the bcc headers */
-       header->next = savedbcc;
+       for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); ii++) {
+               if (!g_ascii_strcasecmp (header_name, "Bcc")) {
+                       camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value);
+               }
+       }
+
+       camel_name_value_array_free (previous_headers);
 
        if (ret == -1) {
                g_prefix_error (error, _("DATA command failed: "));
diff --git a/src/camel/providers/smtp/camel-smtp-transport.h b/src/camel/providers/smtp/camel-smtp-transport.h
index c5a20de..f513639 100644
--- a/src/camel/providers/smtp/camel-smtp-transport.h
+++ b/src/camel/providers/smtp/camel-smtp-transport.h
@@ -65,6 +65,9 @@ struct _CamelSmtpTransport {
 
 struct _CamelSmtpTransportClass {
        CamelTransportClass parent_class;
+
+       /* Padding for future expansion */
+       gpointer reserved[20];
 };
 
 GType camel_smtp_transport_get_type (void);
diff --git a/src/camel/tests/CMakeLists.txt b/src/camel/tests/CMakeLists.txt
index c1b1063..e12ab64 100644
--- a/src/camel/tests/CMakeLists.txt
+++ b/src/camel/tests/CMakeLists.txt
@@ -1,7 +1,8 @@
 macro(add_camel_test_one _part _name _src_file)
        set(_test_ident cameltest-${_part}-${_name})
 
-       add_executable(${_test_ident} EXCLUDE_FROM_ALL ${_src_file})
+       # Not using EXCLUDE_FROM_ALL here, to have these built always
+       add_executable(${_test_ident} ${_src_file})
 
        target_compile_definitions(${_test_ident} PRIVATE
                -DG_LOG_DOMAIN=\"${_test_ident}\"
diff --git a/src/camel/tests/folder/test10.c b/src/camel/tests/folder/test10.c
index 5331df9..4d23126 100644
--- a/src/camel/tests/folder/test10.c
+++ b/src/camel/tests/folder/test10.c
@@ -101,7 +101,8 @@ main (gint argc,
                        for (i = 0; i < MAX_THREADS; i++) {
                                GError *error = NULL;
 
-                               threads[i] = g_thread_new (NULL, worker, NULL);
+                               threads[i] = g_thread_try_new (NULL, worker, NULL, &error);
+                               check_msg (error == NULL, "g_thread_try_new() failed: %s", error->message);
                        }
 
                        for (i = 0; i < MAX_THREADS; i++) {
diff --git a/src/camel/tests/folder/test11.c b/src/camel/tests/folder/test11.c
index 3727720..6fd7c6f 100644
--- a/src/camel/tests/folder/test11.c
+++ b/src/camel/tests/folder/test11.c
@@ -22,6 +22,7 @@
 
 #define MAX_LOOP (10000)
 #define MAX_THREADS (5)
+#define GC(x) ((gchar *) (x))
 
 static const gchar *local_drivers[] = { "local" };
 
@@ -30,25 +31,25 @@ static CamelSession *session;
 /* FIXME: flags aren't really right yet */
 /* ASCII sorted on full_name */
 static CamelFolderInfo fi_list_1[] = {
-       { NULL, NULL, NULL, ".", "Inbox", CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOCHILDREN, -1, -1 },
-       { NULL, NULL, NULL, ".#evolution/Junk", "Junk", CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOCHILDREN, -1, -1 
},
-       { NULL, NULL, NULL, ".#evolution/Trash", "Trash", CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOCHILDREN, -1, 
-1 },
-       { NULL, NULL, NULL, "testbox", "testbox", CAMEL_FOLDER_CHILDREN, -1, -1 },
-       { NULL, NULL, NULL, "testbox/foo", "foo", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
-       { NULL, NULL, NULL, "testbox2", "testbox2", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("."), GC ("Inbox"), CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC (".#evolution/Junk"), GC ("Junk"), CAMEL_FOLDER_SYSTEM | 
CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC (".#evolution/Trash"), GC ("Trash"), CAMEL_FOLDER_SYSTEM | 
CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("testbox"), GC ("testbox"), CAMEL_FOLDER_CHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("testbox/foo"), GC ("foo"), CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("testbox2"), GC ("testbox2"), CAMEL_FOLDER_NOCHILDREN, -1, -1 },
 };
 
 static CamelFolderInfo fi_list_2[] = {
-       { NULL, NULL, NULL, ".", "Inbox", CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOCHILDREN, -1, -1 },
-       { NULL, NULL, NULL, ".#evolution/Junk", "Junk", CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOCHILDREN, -1, -1 
},
-       { NULL, NULL, NULL, ".#evolution/Trash", "Trash", CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOCHILDREN, -1, 
-1 },
-       { NULL, NULL, NULL, "testbox", "testbox", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
-       { NULL, NULL, NULL, "testbox2", "testbox2", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("."), GC ("Inbox"), CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC (".#evolution/Junk"), GC ("Junk"), CAMEL_FOLDER_SYSTEM | 
CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC (".#evolution/Trash"), GC ("Trash"), CAMEL_FOLDER_SYSTEM | 
CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("testbox"), GC ("testbox"), CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("testbox2"), GC ("testbox2"), CAMEL_FOLDER_NOCHILDREN, -1, -1 },
 };
 
 static CamelFolderInfo fi_list_3[] = {
-       { NULL, NULL, NULL, "testbox", "testbox", CAMEL_FOLDER_CHILDREN, -1, -1 },
-       { NULL, NULL, NULL, "testbox/foo", "foo", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("testbox"), GC ("testbox"), CAMEL_FOLDER_CHILDREN, -1, -1 },
+       { NULL, NULL, NULL, GC ("testbox/foo"), GC ("foo"), CAMEL_FOLDER_NOCHILDREN, -1, -1 },
 };
 
 static gint
diff --git a/src/camel/tests/folder/test2.c b/src/camel/tests/folder/test2.c
index 85b66ff..b43bb0e 100644
--- a/src/camel/tests/folder/test2.c
+++ b/src/camel/tests/folder/test2.c
@@ -47,7 +47,7 @@ gint main (gint argc, gchar **argv)
 
        /* we iterate over all stores we want to test, with indexing or indexing turned on or off */
        for (i = 0; i < G_N_ELEMENTS (stores); i++) {
-               gchar *name = stores[i];
+               const gchar *name = stores[i];
 
                test_folder_message_ops (session, name, TRUE, "testbox");
        }
diff --git a/src/camel/tests/folder/test8.c b/src/camel/tests/folder/test8.c
index 1a56706..1c5ee94 100644
--- a/src/camel/tests/folder/test8.c
+++ b/src/camel/tests/folder/test8.c
@@ -193,7 +193,8 @@ gint main (gint argc, gchar **argv)
                                info->id = i * MAX_MESSAGES;
                                info->folder = folder;
 
-                               threads[i] = g_thread_new (NULL, worker, info);
+                               threads[i] = g_thread_try_new (NULL, worker, info, &error);
+                               check_msg (error == NULL, "g_thread_try_new() failed: %s", error->message);
                        }
 
                        for (i = 0; i < MAX_THREADS; i++) {
diff --git a/src/camel/tests/lib/folders.c b/src/camel/tests/lib/folders.c
index 4db8c89..a2edadb 100644
--- a/src/camel/tests/lib/folders.c
+++ b/src/camel/tests/lib/folders.c
@@ -52,7 +52,7 @@ test_folder_counts (CamelFolder *folder,
                info = camel_folder_get_message_info (folder, s->pdata[i]);
                if (camel_message_info_get_flags (info) & CAMEL_MESSAGE_SEEN)
                        myunread--;
-               camel_message_info_unref (info);
+               g_clear_object (&info);
        }
        check (unread == myunread);
        camel_folder_free_uids (folder, s);
@@ -109,7 +109,7 @@ test_folder_message (CamelFolder *folder,
        info = camel_folder_get_message_info (folder, uid);
        check (info != NULL);
        check (strcmp (camel_message_info_get_uid (info), uid) == 0);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        /* then, getting message */
        msg = camel_folder_get_message_sync (folder, uid, NULL, &error);
@@ -462,7 +462,7 @@ test_folder_message_ops (CamelSession *session,
                                check_msg (
                                        strcmp (camel_message_info_get_subject (info), subject) == 0,
                                        "info->subject %s", camel_message_info_get_subject (info));
-                               camel_message_info_unref (info);
+                               g_clear_object (&info);
                        }
                        camel_folder_free_uids (folder, uids);
                        pull ();
@@ -515,7 +515,7 @@ test_folder_message_ops (CamelSession *session,
                                strcmp (camel_message_info_get_subject (info), subject) == 0,
                                "info->subject %s", camel_message_info_get_subject (info));
                        test_free (subject);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                        pull ();
                }
 
@@ -544,7 +544,7 @@ test_folder_message_ops (CamelSession *session,
                                strcmp (camel_message_info_get_subject (info), subject) == 0,
                                "info->subject %s", camel_message_info_get_subject (info));
                        test_free (subject);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                        pull ();
                }
                pull ();
@@ -575,7 +575,7 @@ test_folder_message_ops (CamelSession *session,
                                strcmp (camel_message_info_get_subject (info), subject) == 0,
                                "info->subject %s", camel_message_info_get_subject (info));
                        test_free (subject);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                        pull ();
                }
                pull ();
diff --git a/src/camel/tests/lib/messages.c b/src/camel/tests/lib/messages.c
index dbe674b..ea7b0a0 100644
--- a/src/camel/tests/lib/messages.c
+++ b/src/camel/tests/lib/messages.c
@@ -238,8 +238,6 @@ test_message_compare (CamelMimeMessage *msg)
        g_seekable_seek (G_SEEKABLE (stream2), 0, G_SEEK_SET, NULL, NULL);
 
        if (byte_array1->len != byte_array2->len) {
-               CamelDataWrapper *content;
-
                printf ("stream1 stream:\n%.*s\n", byte_array1->len, byte_array1->data);
                printf ("stream2 stream:\n%.*s\n\n", byte_array2->len, byte_array2->data);
 
@@ -247,8 +245,6 @@ test_message_compare (CamelMimeMessage *msg)
                test_message_dump_structure (msg);
                printf ("msg2:\n");
                test_message_dump_structure (msg2);
-
-               content = camel_medium_get_content ((CamelMedium *) msg);
        }
 
        check_unref (msg2, 1);
@@ -298,7 +294,7 @@ message_dump_rec (CamelMimeMessage *msg,
        printf ("%sPart <%s>\n", s, G_OBJECT_TYPE_NAME (part));
        printf ("%sContent-Type: %s\n", s, mime_type);
        g_free (mime_type);
-       printf ("%s encoding: %s\n", s, camel_transfer_encoding_to_string (((CamelDataWrapper *) 
part)->encoding));
+       printf ("%s encoding: %s\n", s, camel_transfer_encoding_to_string (camel_data_wrapper_get_encoding 
((CamelDataWrapper *) part)));
        printf ("%s part encoding: %s\n", s, camel_transfer_encoding_to_string (camel_mime_part_get_encoding 
(part)));
 
        containee = camel_medium_get_content (CAMEL_MEDIUM (part));
@@ -310,7 +306,7 @@ message_dump_rec (CamelMimeMessage *msg,
        printf ("%sContent <%s>\n", s, G_OBJECT_TYPE_NAME (containee));
        printf ("%sContent-Type: %s\n", s, mime_type);
        g_free (mime_type);
-       printf ("%s encoding: %s\n", s, camel_transfer_encoding_to_string (((CamelDataWrapper *) 
containee)->encoding));
+       printf ("%s encoding: %s\n", s, camel_transfer_encoding_to_string (camel_data_wrapper_get_encoding 
((CamelDataWrapper *) containee)));
 
        /* using the object types is more accurate than using the mime/types */
        if (CAMEL_IS_MULTIPART (containee)) {
diff --git a/src/camel/tests/message/test2.c b/src/camel/tests/message/test2.c
index ada3c1d..f00e23a 100644
--- a/src/camel/tests/message/test2.c
+++ b/src/camel/tests/message/test2.c
@@ -41,13 +41,13 @@ static gchar *convert (const gchar *in, const gchar *from, const gchar *to)
        outp = out = g_malloc (outlen);
        inp = in;
 
-       if (iconv (ic, &inp, &inlen, &outp, &outlen) == -1) {
+       if (camel_iconv (ic, &inp, &inlen, &outp, &outlen) == -1) {
                test_free (out);
                g_iconv_close (ic);
                return g_strdup (in);
        }
 
-       if (iconv (ic, NULL, 0, &outp, &outlen) == -1) {
+       if (camel_iconv (ic, NULL, 0, &outp, &outlen) == -1) {
                test_free (out);
                g_iconv_close (ic);
                return g_strdup (in);
diff --git a/src/camel/tests/mime-filter/test-charset.c b/src/camel/tests/mime-filter/test-charset.c
index c490396..c68e688 100644
--- a/src/camel/tests/mime-filter/test-charset.c
+++ b/src/camel/tests/mime-filter/test-charset.c
@@ -80,8 +80,7 @@ test_case (const gchar *basename)
        }
        g_free (filename);
 
-       filename = g_strdup_printf (
-               "%s/%.*s.out", SOURCEDIR, ext - basename, basename);
+       filename = g_strdup_printf ("%s/%.*s.out", SOURCEDIR, (gint) (ext - basename), basename);
 
        file = g_file_new_for_path (filename);
        correct_stream = g_file_read (file, NULL, &local_error);
diff --git a/src/camel/tests/misc/split.c b/src/camel/tests/misc/split.c
index eac9548..9f7f418 100644
--- a/src/camel/tests/misc/split.c
+++ b/src/camel/tests/misc/split.c
@@ -78,7 +78,7 @@ main (gint argc,
        for (i = 0; i < G_N_ELEMENTS (split_tests); i++) {
                camel_test_push ("split %d '%s'", i, split_tests[i].word);
 
-               words = camel_search_words_split (split_tests[i].word);
+               words = camel_search_words_split ((const guchar *) split_tests[i].word);
                check (words != NULL);
                check_msg (words->len == split_tests[i].count, "words->len = %d, count = %d", words->len, 
split_tests[i].count);
 
@@ -100,7 +100,7 @@ main (gint argc,
        for (i = 0; i < G_N_ELEMENTS (simple_tests); i++) {
                camel_test_push ("simple split %d '%s'", i, simple_tests[i].word);
 
-               tmp = camel_search_words_split (simple_tests[i].word);
+               tmp = camel_search_words_split ((const guchar *) simple_tests[i].word);
                check (tmp != NULL);
 
                words = camel_search_words_simple (tmp);
diff --git a/src/camel/tests/misc/utf7.c b/src/camel/tests/misc/utf7.c
index b79cf10..567de2f 100644
--- a/src/camel/tests/misc/utf7.c
+++ b/src/camel/tests/misc/utf7.c
@@ -103,7 +103,7 @@ main (gint argc,
                do {
                        u = tests[i].unicode[j++];
                        camel_utf8_putc ((guchar **) &p, u);
-                       g_string_append_u (out, u);
+                       g_string_append_unichar (out, u);
                } while (u);
 
                check (strcmp (utf8enc, out->str) == 0);
diff --git a/src/camel/tests/smime/pgp.c b/src/camel/tests/smime/pgp.c
index 05f7771..139aa3c 100644
--- a/src/camel/tests/smime/pgp.c
+++ b/src/camel/tests/smime/pgp.c
@@ -49,7 +49,6 @@ G_DEFINE_TYPE (CamelPgpSession, camel_pgp_session, camel_test_session_get_type (
 static gchar *
 pgp_session_get_password (CamelSession *session,
                           CamelService *service,
-                          const gchar *domain,
                           const gchar *prompt,
                           const gchar *item,
                           guint32 flags,
diff --git a/src/vala/Camel-1.2.metadata b/src/vala/Camel-1.2.metadata
index eb66385..74aded7 100644
--- a/src/vala/Camel-1.2.metadata
+++ b/src/vala/Camel-1.2.metadata
@@ -6,7 +6,9 @@ FilterDriver.set* skip=false
 
 // We need to skip the methods because the signals and virtual methods have the same name
 Object.state_read#method skip
+Object.state_read.fp type="GLib.FileStream"
 Object.state_write#method skip
+Object.state_write.fp type="GLib.FileStream"
 Operation.pop_message skip
 Operation.progress skip
 
@@ -23,3 +25,13 @@ localtime_with_offset.tm type="Posix.tm"
 mktime_utc.tm type="Posix.tm"
 
 HeaderAddress.new_name#constructor name="with_name"
+
+// FILE* are supported by Vala
+StoreSummary.store_info_save.file type="GLib.FileStream"
+StoreSummary.summary_header_load.file type="GLib.FileStream"
+StoreSummary.summary_header_save.file type="GLib.FileStream"
+CertDB.cert_load.istream type="GLib.FileStream"
+CertDB.cert_save.ostream type="GLib.FileStream"
+CertDB.header_load.istream type="GLib.FileStream"
+CertDB.header_save.ostream type="GLib.FileStream"
+FilterDriver.set_logfile.logfile type="GLib.FileStream"


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