[evolution-data-server/wip/camel-more-gobject: 16/16] Bug 764065 (part 1) - [Camel] Port more classes to GObject



commit 6bffc8c0c72f420bff31257abfb876e796ec9c1c
Author: Milan Crha <mcrha redhat com>
Date:   Tue Oct 11 21:46:17 2016 +0200

    Bug 764065 (part 1) - [Camel] Port more classes to GObject

 CMakeLists.txt                                     |    2 +-
 src/camel/CMakeLists.txt                           |   12 +
 src/camel/camel-charset-map.c                      |   12 +-
 src/camel/camel-cipher-context.c                   |    8 +-
 src/camel/camel-db.c                               |  162 +-
 src/camel/camel-db.h                               |   14 +-
 src/camel/camel-filter-driver.c                    |   21 +-
 src/camel/camel-filter-driver.h                    |    2 +-
 src/camel/camel-filter-search.c                    |   97 +-
 src/camel/camel-folder-search.c                    |    7 +-
 src/camel/camel-folder-summary.c                   | 2587 ++----------------
 src/camel/camel-folder-summary.h                   |  385 +---
 src/camel/camel-folder-thread.c                    |   62 +-
 src/camel/camel-folder.c                           |   71 +-
 src/camel/camel-folder.h                           |   22 +-
 src/camel/camel-index.h                            |    2 +-
 src/camel/camel-message-info-base.c                |  877 ++++++
 src/camel/camel-message-info-base.h                |   67 +
 src/camel/camel-message-info.c                     | 2979 ++++++++++++++++++++
 src/camel/camel-message-info.h                     |  328 +++
 src/camel/camel-mime-filter-yenc.c                 |   30 +-
 src/camel/camel-mime-message.c                     |    2 +-
 src/camel/camel-mime-parser.c                      |    8 +-
 src/camel/camel-mime-parser.h                      |    2 +-
 src/camel/camel-mime-part-utils.c                  |  189 +-
 src/camel/camel-mime-part-utils.h                  |   35 +-
 src/camel/camel-mime-part.c                        |    8 +-
 src/camel/camel-mime-part.h                        |    2 +-
 src/camel/camel-mime-utils.c                       |  119 +-
 src/camel/camel-mime-utils.h                       |   28 +-
 src/camel/camel-movemail.c                         |    2 +-
 src/camel/camel-msgport.c                          |    1 +
 src/camel/camel-name-value-array.c                 |  633 +++++
 src/camel/camel-name-value-array.h                 |   96 +
 src/camel/camel-named-flags.c                      |  317 +++
 src/camel/camel-named-flags.h                      |   62 +
 src/camel/camel-provider.c                         |    4 +-
 src/camel/camel-sasl-gssapi.c                      |    4 +-
 src/camel/camel-sasl.c                             |    2 +-
 src/camel/camel-service.c                          |    6 +-
 src/camel/camel-session.c                          |    2 +-
 src/camel/camel-sexp.h                             |    6 +-
 src/camel/camel-store-summary.c                    |    2 +-
 src/camel/camel-store-summary.h                    |    4 +-
 src/camel/camel-store.c                            |    6 +-
 src/camel/camel-store.h                            |    8 +
 src/camel/camel-stream-buffer.c                    |    2 +-
 src/camel/camel-stream.c                           |    6 +-
 src/camel/camel-subscribable.c                     |    4 +-
 src/camel/camel-trie.c                             |    6 +-
 src/camel/camel-url-scanner.c                      |   11 +
 src/camel/camel-url.c                              |   42 +-
 src/camel/camel-url.h                              |    6 +-
 src/camel/camel-utils.c                            |  173 ++
 src/camel/camel-utils.h                            |   40 +
 src/camel/camel-vee-data-cache.h                   |    4 +-
 src/camel/camel-vee-folder.c                       |   28 +-
 src/camel/camel-vee-folder.h                       |    2 +-
 src/camel/camel-vee-message-info.c                 |  532 ++++
 src/camel/camel-vee-message-info.h                 |   77 +
 src/camel/camel-vee-store.c                        |   14 +-
 src/camel/camel-vee-summary.c                      |  293 +--
 src/camel/camel-vee-summary.h                      |   10 +-
 src/camel/camel-vtrash-folder.c                    |   12 +-
 src/camel/camel.h                                  |    6 +
 src/camel/providers/imapx/CMakeLists.txt           |    2 +
 src/camel/providers/imapx/camel-imapx-command.c    |    4 +-
 src/camel/providers/imapx/camel-imapx-folder.c     |    4 +-
 .../providers/imapx/camel-imapx-message-info.c     |  435 +++
 .../providers/imapx/camel-imapx-message-info.h     |   87 +
 src/camel/providers/imapx/camel-imapx-search.c     |    3 +-
 src/camel/providers/imapx/camel-imapx-server.c     |  416 ++--
 src/camel/providers/imapx/camel-imapx-summary.c    |  242 +--
 src/camel/providers/imapx/camel-imapx-summary.h    |   14 -
 src/camel/providers/imapx/camel-imapx-utils.c      |  171 +-
 src/camel/providers/imapx/camel-imapx-utils.h      |   17 +-
 src/camel/providers/local/CMakeLists.txt           |    4 +
 src/camel/providers/local/camel-local-summary.c    |  144 +-
 src/camel/providers/local/camel-local-summary.h    |   16 +-
 src/camel/providers/local/camel-maildir-folder.c   |   46 +-
 .../providers/local/camel-maildir-message-info.c   |  251 ++
 .../providers/local/camel-maildir-message-info.h   |   71 +
 src/camel/providers/local/camel-maildir-summary.c  |  173 +-
 src/camel/providers/local/camel-maildir-summary.h  |   15 +-
 src/camel/providers/local/camel-mbox-folder.c      |   59 +-
 .../providers/local/camel-mbox-message-info.c      |  255 ++
 .../providers/local/camel-mbox-message-info.h      |   67 +
 src/camel/providers/local/camel-mbox-summary.c     |  339 +--
 src/camel/providers/local/camel-mbox-summary.h     |    6 -
 src/camel/providers/local/camel-mh-folder.c        |    4 +-
 src/camel/providers/local/camel-mh-summary.c       |   32 +-
 src/camel/providers/local/camel-spool-summary.c    |    9 +-
 src/camel/providers/local/camel-spool-summary.h    |    2 +-
 src/camel/providers/nntp/camel-nntp-folder.c       |   18 +-
 src/camel/providers/nntp/camel-nntp-summary.c      |   35 +-
 src/camel/providers/pop3/camel-pop3-folder.c       |    6 +-
 .../providers/sendmail/camel-sendmail-provider.c   |    4 +-
 .../providers/sendmail/camel-sendmail-transport.c  |    6 +-
 src/camel/providers/smtp/camel-smtp-transport.c    |    6 +-
 src/camel/tests/lib/folders.c                      |   12 +-
 src/vala/Camel-1.2.metadata                        |   12 +
 101 files changed, 8934 insertions(+), 4616 deletions(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index aec781a..384a5f8 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 6e7ea43..a0a4f81 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-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..0fcffff 100644
--- a/src/camel/camel-cipher-context.c
+++ b/src/camel/camel-cipher-context.c
@@ -1232,7 +1232,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.
  *
@@ -1399,9 +1399,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
  **/
diff --git a/src/camel/camel-db.c b/src/camel/camel-db.c
index dffad32..222a880 100644
--- a/src/camel/camel-db.c
+++ b/src/camel/camel-db.c
@@ -1418,104 +1418,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:
  *
@@ -1598,19 +1500,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 +1507,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 +1856,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 +1876,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;
 }
 
@@ -2242,10 +2115,6 @@ 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);
@@ -2342,23 +2211,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,10 +2251,6 @@ 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;
@@ -2444,20 +2305,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 +2484,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 +2505,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 },
diff --git a/src/camel/camel-db.h b/src/camel/camel-db.h
index b454af9..726686c 100644
--- a/src/camel/camel-db.h
+++ b/src/camel/camel-db.h
@@ -161,7 +161,6 @@ struct _CamelDB {
  *     content info string - composite string
  * @bdata:
  *     provider specific data
- * @bodystructure:
  *
  * The extensive DB format, supporting basic searching and sorting.
  *
@@ -179,8 +178,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 +193,6 @@ typedef struct _CamelMIRecord {
        gchar *usertags;
        gchar *cinfo;
        gchar *bdata;
-       gchar *bodystructure;
 } CamelMIRecord;
 
 /**
@@ -228,7 +226,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 +247,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,7 +268,7 @@ CamelDBKnownColumnNames camel_db_get_column_ident (GHashTable **hash, gint index
  *
  * Since: 2.24
  **/
-typedef gint (*CamelDBSelectCB) (gpointer data, gint ncol, gchar **colvalues, gchar **colnames);
+typedef gint (*CamelDBSelectCB) (gpointer user_data, gint ncol, gchar **colvalues, gchar **colnames);
 
 CamelDB * camel_db_open (const gchar *path, GError **error);
 CamelDB * camel_db_clone (CamelDB *cdb, GError **error);
@@ -332,10 +328,6 @@ gint camel_db_set_collate (CamelDB *cdb, const gchar *col, const gchar *collate,
 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);
 
diff --git a/src/camel/camel-filter-driver.c b/src/camel/camel-filter-driver.c
index b0e73b4..ed32998 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;
 }
 
@@ -1452,9 +1453,9 @@ camel_filter_driver_filter_mbox (CamelFilterDriver *driver,
                /* Try and see if it has X-Evolution headers */
                xev = camel_header_raw_find (&mime_part->headers, "X-Evolution", NULL);
                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 +1467,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 +1477,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 +1566,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 +1691,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;
+               CamelHeaderRaw *h;
 
                if (message) {
                        g_object_ref (message);
@@ -1865,7 +1866,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 +1878,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..383b5e0 100644
--- a/src/camel/camel-filter-driver.h
+++ b/src/camel/camel-filter-driver.h
@@ -74,7 +74,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-search.c b/src/camel/camel-filter-search.c
index 68f0b63..b32cb89 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,7 +254,7 @@ 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;
+                       CamelHeaderRaw *header;
                        const gchar *charset = NULL;
                        camel_search_t type = CAMEL_SEARCH_TYPE_ENCODED;
                        CamelContentType *ct;
@@ -845,7 +850,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,34 +892,48 @@ 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;
 
-               node = node->next;
+                       if (!hdr_name || !hdr_value)
+                               continue;
+
+                       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;
+               CamelHeaderRaw *h;
 
                for (h = CAMEL_MIME_PART (message)->headers; h; h = h->next) {
                        const gchar *value;
diff --git a/src/camel/camel-folder-search.c b/src/camel/camel-folder-search.c
index ffb4add..bda0ce6 100644
--- a/src/camel/camel-folder-search.c
+++ b/src/camel/camel-folder-search.c
@@ -272,8 +272,7 @@ get_current_message (CamelFolderSearch *search)
        if (!search || !search->folder || !search->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->folder, camel_message_info_get_uid (search->current), 
search->priv->cancellable, NULL);
 }
 
 static CamelSExpResult *
@@ -299,7 +298,7 @@ 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;
+               CamelHeaderRaw *raw_header;
 
                /* only a subset of headers are supported .. */
                headername = argv[0]->value.string;
@@ -910,7 +909,7 @@ 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->current);
        }
        search->current = NULL;
        return r;
diff --git a/src/camel/camel-folder-summary.c b/src/camel/camel-folder-summary.c
index aec35e3..237d554 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"
@@ -79,9 +81,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 +89,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 +113,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_header (CamelFolderSummary *, CamelHeaderRaw *);
 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 +135,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 +163,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 +222,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 +253,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 +313,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);
@@ -553,282 +505,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
@@ -915,231 +591,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 +604,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->message_info_new_from_header = message_info_new_from_header;
        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 +721,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
@@ -1336,9 +735,6 @@ camel_folder_summary_init (CamelFolderSummary *summary)
        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 +748,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.
  *
@@ -1483,8 +879,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 +912,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 +1152,7 @@ camel_folder_summary_get_hash (CamelFolderSummary *summary)
 /**
  * camel_folder_summary_peek_loaded:
  *
+ * Returns: (nullable) (transfer full):
  * Since: 2.26
  **/
 CamelMessageInfo *
@@ -1837,7 +1166,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;
 }
@@ -1906,7 +1235,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 +1252,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 +1307,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 +1363,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 +1384,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;
        }
@@ -2116,8 +1412,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 +1549,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)
@@ -2398,54 +1584,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);
 }
 
 /**
@@ -2539,6 +1677,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 +1694,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 +1780,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;
 
+       if (!camel_message_info_get_dirty (mi))
+               return;
+
+       summary = camel_message_info_ref_summary (mi);
+       if (!summary)
+               return;
+
        full_name = camel_folder_get_full_name (summary->priv->folder);
        parent_store = camel_folder_get_parent_store (summary->priv->folder);
-       if (!parent_store)
+       if (!parent_store) {
+               g_clear_object (&summary);
                return;
+       }
 
        cdb = parent_store->cdb_w;
 
-       if (!mi->dirty)
-               return;
+       mir = g_new0 (CamelMIRecord, 1);
+       bdata_str = g_string_new (NULL);
 
-       mir = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->message_info_to_db (summary, (CamelMessageInfo *) mi);
-
-       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;
-               }
+       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
@@ -2808,23 +1915,6 @@ 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:
  *
@@ -2854,12 +1944,6 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
        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);
-       }
 
        summary->flags &= ~CAMEL_FOLDER_SUMMARY_DIRTY;
 
@@ -3020,35 +2104,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);
+
+       info_uid = camel_message_info_get_uid (info);
+
+       if (!info_uid || !*info_uid) {
+               new_uid = camel_folder_summary_next_uid_string (summary);
 
-       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);
+               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 +2156,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 +2204,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,56 +2212,18 @@ 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:
  * @summary: a #CamelFolderSummary object
  * @headers: rfc822 headers
  *
  * 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.
  **/
 CamelMessageInfo *
 camel_folder_summary_info_new_from_header (CamelFolderSummary *summary,
-                                           struct _camel_header_raw *h)
+                                           CamelHeaderRaw *h)
 {
        CamelFolderSummaryClass *class;
 
@@ -3180,8 +2253,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 +2291,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 +2302,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 +2311,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 +2350,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 +2365,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
  *
@@ -3413,7 +2462,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;
        }
 
@@ -3508,7 +2557,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);
                }
        }
@@ -3527,36 +2576,6 @@ 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,
@@ -3579,57 +2598,15 @@ 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_header (summary, 
((CamelMimePart *) msg)->headers);
 }
 
 static gchar *
-summary_format_address (struct _camel_header_raw *h,
+summary_format_address (CamelHeaderRaw *h,
                         const gchar *name,
                         const gchar *charset)
 {
@@ -3656,7 +2633,7 @@ summary_format_address (struct _camel_header_raw *h,
 }
 
 static gchar *
-summary_format_string (struct _camel_header_raw *h,
+summary_format_string (CamelHeaderRaw *h,
                        const gchar *name,
                        const gchar *charset)
 {
@@ -3675,35 +2652,15 @@ summary_format_string (struct _camel_header_raw *h,
        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)
+                              CamelHeaderRaw *h)
 {
        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,7 +2669,9 @@ 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))
             && (ct = camel_content_type_decode (content))
@@ -3731,53 +2690,62 @@ message_info_new_from_header (CamelFolderSummary *summary,
        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);
+               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);
        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));
        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));
        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 +2758,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 +2768,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);
+       camel_message_info_set_abort_notifications (mi, FALSE);
 
-       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_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 +2795,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 +2929,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 +2937,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,33 +2946,27 @@ 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 CamelHeaderRaw *header;
        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);
-
        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 */
@@ -4139,20 +3022,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 +3056,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,59 +3113,6 @@ 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:
  * @summary: a #CamelFolderSummary object or %NULL
  * @header: raw header
@@ -4623,623 +3124,15 @@ camel_message_info_ref (gpointer o)
  **/
 CamelMessageInfo *
 camel_message_info_new_from_header (CamelFolderSummary *summary,
-                                    struct _camel_header_raw *header)
+                                    CamelHeaderRaw *header)
 {
        if (summary != NULL)
-               return CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->
-                       message_info_new_from_header (summary, header);
+               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);
-       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);
-}
-
-/**
  * camel_folder_summary_lock:
  * @summary: a #CamelFolderSummary
  *
@@ -5270,47 +3163,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..6bf2dde 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:
@@ -245,9 +95,7 @@ struct _CamelFIRecord;
 struct _CamelFolderSummaryClass {
        GObjectClass parent_class;
 
-       /* sizes of memory objects */
-       gsize message_info_size;
-       gsize content_info_size;
+       GType message_info_type;
 
        /* Load/Save folder summary from DB*/
        gboolean        (*summary_header_from_db)
@@ -257,28 +105,12 @@ struct _CamelFolderSummaryClass {
                        (*summary_header_to_db)
                                        (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)
                                        (CamelFolderSummary *summary,
-                                        struct _camel_header_raw *header);
+                                        CamelHeaderRaw *header);
        CamelMessageInfo *
                        (*message_info_new_from_parser)
                                        (CamelFolderSummary *summary,
@@ -286,32 +118,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 +129,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);
@@ -374,16 +156,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,
@@ -417,7 +189,7 @@ void                camel_folder_summary_touch      (CamelFolderSummary *summary);
 CamelMessageInfo *
                camel_folder_summary_info_new_from_header
                                                (CamelFolderSummary *summary,
-                                                struct _camel_header_raw *headers);
+                                                CamelHeaderRaw *headers);
 CamelMessageInfo *
                camel_folder_summary_info_new_from_parser
                                                (CamelFolderSummary *summary,
@@ -425,28 +197,12 @@ 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);
@@ -499,134 +255,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
                                                (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);
-
+                                                CamelHeaderRaw *header);
 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 277ccea..b3183f5 100644
--- a/src/camel/camel-folder-thread.c
+++ b/src/camel/camel-folder-thread.c
@@ -372,12 +372,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",
                                p, (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", p, (gpointer) c);
@@ -462,18 +466,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 */
@@ -491,15 +495,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
@@ -508,9 +517,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"));
@@ -522,21 +533,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) {
@@ -550,6 +566,8 @@ thread_summary (CamelFolderThread *thread,
                                child = c;
                        }
                }
+
+               camel_message_info_property_unlock (mi);
        }
 
        d (printf ("\n\n"));
@@ -713,7 +731,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)
@@ -782,7 +800,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..b15ae5b 100644
--- a/src/camel/camel-folder.c
+++ b/src/camel/camel-folder.c
@@ -135,7 +135,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);
@@ -299,7 +299,7 @@ folder_filter (CamelSession *session,
                                continue;
 
                        camel_message_info_set_flags (info, CAMEL_MESSAGE_JUNK_LEARN, 0);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
        }
 
@@ -310,7 +310,7 @@ folder_filter (CamelSession *session,
                                continue;
 
                        camel_message_info_set_flags (info, CAMEL_MESSAGE_JUNK_LEARN, 0);
-                       camel_message_info_unref (info);
+                       g_clear_object (&info);
                }
        }
 
@@ -444,7 +444,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);
@@ -493,8 +493,8 @@ folder_transfer_message_to (CamelFolder *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);
+               info = camel_message_info_clone (minfo, NULL);
+               g_clear_object (&minfo);
        } else
                info = camel_message_info_new_from_header (NULL, ((CamelMimePart *) msg)->headers);
 
@@ -517,7 +517,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
@@ -706,18 +706,18 @@ folder_get_message_count (CamelFolder *folder)
        return camel_folder_summary_count (folder->summary);
 }
 
-static CamelMessageFlags
+static guint32
 folder_get_permanent_flags (CamelFolder *folder)
 {
        return folder->permanent_flags;
 }
 
-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);
 
@@ -726,7 +726,7 @@ folder_get_message_flags (CamelFolder *folder,
                return 0;
 
        flags = camel_message_info_get_flags (info);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        return flags;
 }
@@ -734,8 +734,8 @@ 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;
@@ -746,8 +746,8 @@ folder_set_message_flags (CamelFolder *folder,
        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;
 }
@@ -767,7 +767,7 @@ folder_get_message_user_flag (CamelFolder *folder,
                return FALSE;
 
        ret = camel_message_info_get_user_flag (info, name);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        return ret;
 }
@@ -787,7 +787,7 @@ folder_set_message_user_flag (CamelFolder *folder,
                return;
 
        camel_message_info_set_user_flag (info, name, value);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 }
 
 static const gchar *
@@ -805,7 +805,7 @@ folder_get_message_user_tag (CamelFolder *folder,
                return NULL;
 
        ret = camel_message_info_get_user_tag (info, name);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 
        return ret;
 }
@@ -825,7 +825,7 @@ folder_set_message_user_tag (CamelFolder *folder,
                return;
 
        camel_message_info_set_user_tag (info, name, value);
-       camel_message_info_unref (info);
+       g_clear_object (&info);
 }
 
 static GPtrArray *
@@ -1113,7 +1113,7 @@ 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]);
@@ -1704,7 +1704,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 +1727,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 +1746,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 +1764,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 +1775,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 +1905,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,
@@ -2807,7 +2802,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);
diff --git a/src/camel/camel-folder.h b/src/camel/camel-folder.h
index df2cdbb..70d7898 100644
--- a/src/camel/camel-folder.h
+++ b/src/camel/camel-folder.h
@@ -125,7 +125,7 @@ struct _CamelFolder {
        CamelFolderSummary *summary;
 
        CamelFolderFlags folder_flags;
-       CamelMessageFlags permanent_flags;
+       guint32 permanent_flags; /* bit-or of CamelMessageFlags */
 
        /* Future ABI expansion */
        gpointer later[4];
@@ -136,15 +136,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);
@@ -283,17 +281,15 @@ 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_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,
diff --git a/src/camel/camel-index.h b/src/camel/camel-index.h
index 5bec6cf..8ed26bd 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);
 
 /* ********************************************************************** */
 
diff --git a/src/camel/camel-message-info-base.c b/src/camel/camel-message-info-base.c
new file mode 100644
index 0000000..ce8315e
--- /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, TRUE, 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, TRUE, name, value);
+       else
+               changed = camel_name_value_array_remove_named (bmi->priv->user_tags, TRUE, 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, TRUE);
+
+       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, TRUE);
+
+       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..70b8a0e
--- /dev/null
+++ b/src/camel/camel-message-info-base.h
@@ -0,0 +1,67 @@
+/* -*- 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;
+};
+
+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..c4d4152
--- /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, TRUE, 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): 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): 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: (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-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-message.c b/src/camel/camel-mime-message.c
index d41b030..c7ea3a0 100644
--- a/src/camel/camel-mime-message.c
+++ b/src/camel/camel-mime-message.c
@@ -1217,7 +1217,7 @@ static const gchar tz_days[][4] = {
 gchar *
 camel_mime_message_build_mbox_from (CamelMimeMessage *message)
 {
-       struct _camel_header_raw *header = ((CamelMimePart *) message)->headers;
+       CamelHeaderRaw *header = ((CamelMimePart *) message)->headers;
        GString *out = g_string_new ("From ");
        gchar *ret;
        const gchar *tmp;
diff --git a/src/camel/camel-mime-parser.c b/src/camel/camel-mime-parser.c
index dccf063..51fefcd 100644
--- a/src/camel/camel-mime-parser.c
+++ b/src/camel/camel-mime-parser.c
@@ -116,7 +116,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;
 
@@ -335,7 +335,7 @@ camel_mime_parser_header (CamelMimeParser *m,
  *
  * Since: 2.22
  **/
-struct _camel_header_raw *
+CamelHeaderRaw *
 camel_mime_parser_headers_raw (CamelMimeParser *m)
 {
        struct _header_scan_state *s = _PRIVATE (m);
@@ -1180,7 +1180,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 +1203,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;
                }
diff --git a/src/camel/camel-mime-parser.h b/src/camel/camel-mime-parser.h
index ce5c098..a50da80 100644
--- a/src/camel/camel-mime-parser.h
+++ b/src/camel/camel-mime-parser.h
@@ -129,7 +129,7 @@ CamelContentType *camel_mime_parser_content_type (CamelMimeParser *parser);
 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);
+CamelHeaderRaw *camel_mime_parser_headers_raw (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..e27977d 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"
@@ -150,91 +151,129 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw,
        return success;
 }
 
+
 /**
- * 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: 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));
+}
 
-       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);
+/**
+ * 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;
 
-               g_warn_if_fail (CAMEL_IS_MULTIPART (mp));
+       pw = ci->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);
-               }
+       camel_content_type_unref (ci->type);
+       g_free (ci->id);
+       g_free (ci->description);
+       g_free (ci->encoding);
+       g_slice_free1 (sizeof (CamelMessageContentInfo), ci);
 
-       } 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);
+       while (pw) {
+               pn = pw->next;
+               camel_message_content_info_free (pw);
+               pw = pn;
+       }
+}
+
+CamelMessageContentInfo *
+camel_message_content_info_new_from_parser (CamelMimeParser *mp)
+{
+       CamelMessageContentInfo *ci = 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:
+               ci = camel_message_content_info_new_from_header (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);
                }
-               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)
+{
+       g_return_val_if_fail (CAMEL_IS_MIME_PART (mp), NULL);
+
+       return camel_message_content_info_new_from_header (mp->headers);
+}
+
+CamelMessageContentInfo *
+camel_message_content_info_new_from_header (CamelHeaderRaw *h)
+{
+       CamelMessageContentInfo *ci;
+       const gchar *charset;
+
+       ci = camel_message_content_info_new ();
+
+       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;
+}
+
+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..c76a686 100644
--- a/src/camel/camel-mime-part-utils.h
+++ b/src/camel/camel-mime-part-utils.h
@@ -35,8 +35,39 @@ 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;
+};
+
+CamelMessageContentInfo *
+               camel_message_content_info_new  (void);
+void           camel_message_content_info_free (CamelMessageContentInfo *ci);
+CamelMessageContentInfo *
+               camel_message_content_info_new_from_header
+                                               (CamelHeaderRaw *header);
+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..82e63e5 100644
--- a/src/camel/camel-mime-part.c
+++ b/src/camel/camel-mime-part.c
@@ -520,7 +520,7 @@ mime_part_get_headers (CamelMedium *medium)
        CamelMimePart *part = (CamelMimePart *) medium;
        GArray *headers;
        CamelMediumHeader header;
-       struct _camel_header_raw *h;
+       CamelHeaderRaw *h;
 
        headers = g_array_new (FALSE, FALSE, sizeof (CamelMediumHeader));
        for (h = part->headers; h; h = h->next) {
@@ -581,7 +581,7 @@ mime_part_write_to_stream_sync (CamelDataWrapper *dw,
        /* TODO: content-languages header? */
 
        if (mp->headers) {
-               struct _camel_header_raw *h = mp->headers;
+               CamelHeaderRaw *h = mp->headers;
                gchar *val;
                gssize (*writefn) (
                        gpointer stream,
@@ -774,7 +774,7 @@ mime_part_write_to_output_stream_sync (CamelDataWrapper *dw,
        /* TODO: content-languages header? */
 
        if (mp->headers) {
-               struct _camel_header_raw *h = mp->headers;
+               CamelHeaderRaw *h = mp->headers;
                gchar *val;
                gssize (*writefn) (
                        gpointer stream,
@@ -972,7 +972,7 @@ mime_part_construct_from_parser_sync (CamelMimePart *mime_part,
                                       GError **error)
 {
        CamelDataWrapper *dw = (CamelDataWrapper *) mime_part;
-       struct _camel_header_raw *headers;
+       CamelHeaderRaw *headers;
        const gchar *content;
        gchar *buf;
        gsize len;
diff --git a/src/camel/camel-mime-part.h b/src/camel/camel-mime-part.h
index bcacdcb..9284b17 100644
--- a/src/camel/camel-mime-part.h
+++ b/src/camel/camel-mime-part.h
@@ -59,7 +59,7 @@ struct _CamelMimePart {
        CamelMedium parent;
        CamelMimePartPrivate *priv;
 
-       struct _camel_header_raw *headers; /* mime headers */
+       CamelHeaderRaw *headers; /* mime headers */
 };
 
 struct _CamelMimePartClass {
diff --git a/src/camel/camel-mime-utils.c b/src/camel/camel-mime-utils.c
index 7c33fb8..03bdd1a 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>
@@ -4469,7 +4470,7 @@ camel_header_location_decode (const gchar *in)
 
 #ifdef CHECKS
 static void
-check_header (struct _camel_header_raw *header)
+check_header (CamelHeaderRaw *header)
 {
        guchar *cp;
 
@@ -4484,8 +4485,16 @@ check_header (struct _camel_header_raw *header)
 }
 #endif
 
+/**
+ * camel_header_raw_append_parse:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ * @header: an unparsed header
+ * @offset: the given offset
+ *
+ * Appends the parsed header to the list with the given offset.
+ **/
 void
-camel_header_raw_append_parse (struct _camel_header_raw **list,
+camel_header_raw_append_parse (CamelHeaderRaw **list,
                                const gchar *header,
                                gint offset)
 {
@@ -4510,13 +4519,22 @@ camel_header_raw_append_parse (struct _camel_header_raw **list,
        camel_header_raw_append (list, name, in, offset);
 }
 
+/**
+ * camel_header_raw_append:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ * @name: the given name
+ * @value: the given value
+ * @offset: the given offset
+ *
+ * Appends a value with the given name and the given value to the list.
+ **/
 void
-camel_header_raw_append (struct _camel_header_raw **list,
+camel_header_raw_append (CamelHeaderRaw **list,
                          const gchar *name,
                          const gchar *value,
                          gint offset)
 {
-       struct _camel_header_raw *l, *n;
+       CamelHeaderRaw *l, *n;
 
        d (printf ("Header: %s: %s\n", name, value));
 
@@ -4528,7 +4546,7 @@ camel_header_raw_append (struct _camel_header_raw **list,
 #ifdef CHECKS
        check_header (n);
 #endif
-       l = (struct _camel_header_raw *) list;
+       l = (CamelHeaderRaw *) list;
        while (l->next) {
                l = l->next;
        }
@@ -4549,11 +4567,20 @@ camel_header_raw_append (struct _camel_header_raw **list,
 #endif
 }
 
-static struct _camel_header_raw *
-header_raw_find_node (struct _camel_header_raw **list,
+/**
+ * header_raw_find_node:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ * @name: the name to find
+ *
+ * Searches for the node with a given name.
+ *
+ * Returns: (transfer none) (nullable): the found #CamelHeaderRaw or NULL.
+ **/
+static CamelHeaderRaw *
+header_raw_find_node (CamelHeaderRaw **list,
                       const gchar *name)
 {
-       struct _camel_header_raw *l;
+       CamelHeaderRaw *l;
 
        l = *list;
        while (l) {
@@ -4564,12 +4591,22 @@ header_raw_find_node (struct _camel_header_raw **list,
        return l;
 }
 
+/**
+ * camel_header_raw_find:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ * @name: the name to find
+ * @offset: (out) (nullable): the offset corresponding to the name
+ *
+ * Searches for the first node with a given name and returns its value.
+ *
+ * Returns: (transfer none) (nullable): the value associated with the name
+ **/
 const gchar *
-camel_header_raw_find (struct _camel_header_raw **list,
+camel_header_raw_find (CamelHeaderRaw **list,
                        const gchar *name,
                        gint *offset)
 {
-       struct _camel_header_raw *l;
+       CamelHeaderRaw *l;
 
        l = header_raw_find_node (list, name);
        if (l) {
@@ -4580,13 +4617,24 @@ camel_header_raw_find (struct _camel_header_raw **list,
                return NULL;
 }
 
+/**
+ * camel_header_raw_find_next:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ * @name: the name to find
+ * @offset: (out) (nullable): the offset corresponding to the name
+ * @last: the last found value
+ *
+ * Searches for the next node with a given name and returns its value.
+ *
+ * Returns: (transfer none) (nullable): the value associated with the name
+ **/
 const gchar *
-camel_header_raw_find_next (struct _camel_header_raw **list,
+camel_header_raw_find_next (CamelHeaderRaw **list,
                             const gchar *name,
                             gint *offset,
                             const gchar *last)
 {
-       struct _camel_header_raw *l;
+       CamelHeaderRaw *l;
 
        if (last == NULL || name == NULL)
                return NULL;
@@ -4598,21 +4646,28 @@ camel_header_raw_find_next (struct _camel_header_raw **list,
 }
 
 static void
-header_raw_free (struct _camel_header_raw *l)
+header_raw_free (CamelHeaderRaw *l)
 {
        g_free (l->name);
        g_free (l->value);
        g_free (l);
 }
 
+/**
+ * camel_header_raw_remove:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ * @name: the name to remove
+ *
+ * Remove all values associated with the given name
+ **/
 void
-camel_header_raw_remove (struct _camel_header_raw **list,
+camel_header_raw_remove (CamelHeaderRaw **list,
                          const gchar *name)
 {
-       struct _camel_header_raw *l, *p;
+       CamelHeaderRaw *l, *p;
 
        /* the next pointer is at the head of the structure, so this is safe */
-       p = (struct _camel_header_raw *) list;
+       p = (CamelHeaderRaw *) list;
        l = *list;
        while (l) {
                if (!g_ascii_strcasecmp (l->name, name)) {
@@ -4626,8 +4681,17 @@ camel_header_raw_remove (struct _camel_header_raw **list,
        }
 }
 
+/**
+ * camel_header_raw_replace:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ * @name: the name to remove
+ * @value: the new value
+ * @offset: the new offset
+ *
+ * Replace the row associated with the given name by another value and offset.
+ **/
 void
-camel_header_raw_replace (struct _camel_header_raw **list,
+camel_header_raw_replace (CamelHeaderRaw **list,
                           const gchar *name,
                           const gchar *value,
                           gint offset)
@@ -4636,10 +4700,17 @@ camel_header_raw_replace (struct _camel_header_raw **list,
        camel_header_raw_append (list, name, value, offset);
 }
 
+
+/**
+ * camel_header_raw_clear:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ *
+ * Removes all the raws of the list.
+ **/
 void
-camel_header_raw_clear (struct _camel_header_raw **list)
+camel_header_raw_clear (CamelHeaderRaw **list)
 {
-       struct _camel_header_raw *l, *n;
+       CamelHeaderRaw *l, *n;
        l = *list;
        while (l) {
                n = l->next;
@@ -4775,8 +4846,16 @@ mailing_list_init (gpointer param)
        return NULL;
 }
 
+/**
+ * camel_header_raw_check_mailing_list:
+ * @list: (array zero-terminated=1): a NULL-terminated list of #CamelHeaderRaw
+ *
+ * TODO: Document me.
+ *
+ * Returns: (transfer full) (nullable):
+ **/
 gchar *
-camel_header_raw_check_mailing_list (struct _camel_header_raw **list)
+camel_header_raw_check_mailing_list (CamelHeaderRaw **list)
 {
        static GOnce once = G_ONCE_INIT;
        const gchar *v;
diff --git a/src/camel/camel-mime-utils.h b/src/camel/camel-mime-utils.h
index 2a51044..12c647e 100644
--- a/src/camel/camel-mime-utils.h
+++ b/src/camel/camel-mime-utils.h
@@ -29,6 +29,9 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <camel/camel-enums.h>
+#include <camel/camel-utils.h>
+
+G_BEGIN_DECLS
 
 /* maximum recommended size of a line from camel_header_fold() */
 #define CAMEL_FOLD_SIZE (77)
@@ -43,8 +46,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;
@@ -61,12 +62,12 @@ typedef struct {
 
 /* a raw rfc822 header */
 /* the value MUST be US-ASCII */
-struct _camel_header_raw {
+typedef struct _camel_header_raw {
        struct _camel_header_raw *next;
        gchar *name;
        gchar *value;
        gint offset;            /* in file, if known */
-};
+} CamelHeaderRaw;
 
 typedef struct _CamelContentDisposition {
        gchar *disposition;
@@ -153,16 +154,15 @@ gchar *camel_content_disposition_format (CamelContentDisposition *disposition);
 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);
+void camel_header_raw_append (CamelHeaderRaw **list, const gchar *name, const gchar *value, gint offset);
+void camel_header_raw_append_parse (CamelHeaderRaw **list, const gchar *header, gint offset);
+const gchar *camel_header_raw_find (CamelHeaderRaw **list, const gchar *name, gint *offset);
+const gchar *camel_header_raw_find_next (CamelHeaderRaw **list, const gchar *name, gint *offset, const gchar 
*last);
+void camel_header_raw_replace (CamelHeaderRaw **list, const gchar *name, const gchar *value, gint offset);
+void camel_header_raw_remove (CamelHeaderRaw **list, const gchar *name);
+void camel_header_raw_clear (CamelHeaderRaw **list);
+
+gchar *camel_header_raw_check_mailing_list (CamelHeaderRaw **list);
 
 /* fold a header */
 gchar *camel_header_address_fold (const gchar *in, gsize headerlen);
diff --git a/src/camel/camel-movemail.c b/src/camel/camel-movemail.c
index 4e00e2e..05f065b 100644
--- a/src/camel/camel-movemail.c
+++ b/src/camel/camel-movemail.c
@@ -431,7 +431,7 @@ camel_movemail_copy_filter (gint fromfd,
  * want        to maintain it! */
 static gint
 solaris_header_write (gint fd,
-                      struct _camel_header_raw *header)
+                      CamelHeaderRaw *header)
 {
        struct iovec iv[4];
        gint outlen = 0, len;
diff --git a/src/camel/camel-msgport.c b/src/camel/camel-msgport.c
index 26a9cd0..d604cb5 100644
--- a/src/camel/camel-msgport.c
+++ b/src/camel/camel-msgport.c
@@ -304,6 +304,7 @@ camel_msgport_fd (CamelMsgPort *msgport)
 /**
  * camel_msgport_prfd:
  *
+ * Returns: (transfer none):
  * Since: 2.24
  **/
 PRFileDesc *
diff --git a/src/camel/camel-name-value-array.c b/src/camel/camel-name-value-array.c
new file mode 100644
index 0000000..4b76aeb
--- /dev/null
+++ b/src/camel/camel-name-value-array.c
@@ -0,0 +1,633 @@
+/* -*- 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:
+ *
+ * Created 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
+ *
+ * Created 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
+ *
+ * Created 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);
+       g_return_val_if_fail (index < camel_name_value_array_get_length (array), 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,
+                                  gboolean case_sensitive,
+                                  const gchar *name)
+{
+       GArray *arr = (GArray *) array;
+       gint ii;
+
+       g_return_val_if_fail (array != NULL, (guint) -1);
+       g_return_val_if_fail (name != NULL, (guint) -1);
+
+       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
+ * @case_sensitive: whether to compare names case sensitively
+ * @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 @case_sensitive determines
+ * whether compare names case sensitively (%TRUE) or insensitively (%FALSE).
+ *
+ * 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,
+                                 gboolean case_sensitive,
+                                 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, case_sensitive, 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);
+       g_return_val_if_fail (index < camel_name_value_array_get_length (array), 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);
+       g_return_val_if_fail (index < camel_name_value_array_get_length (array), 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
+ * @case_sensitive: whether to compare names case sensitively
+ * @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 lement exists in the @array yet.
+ * In case there are more elements named with @name only the first
+ * occurrence is changed. The @case_sensitive determines whether compare
+ * names case sensitively (%TRUE) or insensitively (%FALSE).
+ *
+ * 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,
+                                 gboolean case_sensitive,
+                                 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, case_sensitive, 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
+ * @case_sensitive: whether to compare names case sensitively
+ * @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 @case_sensitive
+ * determines whether compare case sensitively (%TRUE) or insensitively (%FALSE).
+ * 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,
+                                    gboolean case_sensitive,
+                                    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, case_sensitive, 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
+ * @case_sensitive: whether to search for names case sensitively
+ *
+ * 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,
+                             gboolean case_sensitive)
+{
+       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, case_sensitive,
+                       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..aa902a9
--- /dev/null
+++ b/src/camel/camel-name-value-array.h
@@ -0,0 +1,96 @@
+/* -*- 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>
+
+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,
+                                                gboolean case_sensitive,
+                                                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,
+                                                gboolean case_sensitive,
+                                                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,
+                                                gboolean case_sensitive,
+                                                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,
+                                                gboolean case_sensitive);
+
+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..c2869b4
--- /dev/null
+++ b/src/camel/camel-named-flags.c
@@ -0,0 +1,317 @@
+/* -*- 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);
+       g_return_val_if_fail (index < camel_named_flags_get_length (named_flags), 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-provider.c b/src/camel/camel-provider.c
index 45d2611..625dd10 100644
--- a/src/camel/camel-provider.c
+++ b/src/camel/camel-provider.c
@@ -138,8 +138,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-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.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-service.c b/src/camel/camel-service.c
index cc4cac9..cd6e681 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)
@@ -1560,14 +1560,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
  **/
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-sexp.h b/src/camel/camel-sexp.h
index e0d824a..d4d9aa7 100644
--- a/src/camel/camel-sexp.h
+++ b/src/camel/camel-sexp.h
@@ -91,6 +91,7 @@ struct _CamelSExpResult {
 
 /**
  * CamelSExpFunc:
+ * @argv: (inout) (array length=argc):
  *
  * Since: 3.4
  **/
@@ -98,17 +99,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:
diff --git a/src/camel/camel-store-summary.c b/src/camel/camel-store-summary.c
index 23527bc..f43e6f8 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"
 
diff --git a/src/camel/camel-store-summary.h b/src/camel/camel-store-summary.h
index 68e1557..d46fa80 100644
--- a/src/camel/camel-store-summary.h
+++ b/src/camel/camel-store-summary.h
@@ -175,10 +175,10 @@ const gchar *     camel_store_info_name           (CamelStoreSummary *summary,
 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..7325343 100644
--- a/src/camel/camel-store.c
+++ b/src/camel/camel-store.c
@@ -606,7 +606,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 +615,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 +660,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
diff --git a/src/camel/camel-store.h b/src/camel/camel-store.h
index 19d930e..c0690cd 100644
--- a/src/camel/camel-store.h
+++ b/src/camel/camel-store.h
@@ -53,6 +53,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:
  *
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.c b/src/camel/camel-stream.c
index 3841819..8204b0e 100644
--- a/src/camel/camel-stream.c
+++ b/src/camel/camel-stream.c
@@ -479,12 +479,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 +514,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-subscribable.c b/src/camel/camel-subscribable.c
index 3ec4f58..ebb0683 100644
--- a/src/camel/camel-subscribable.c
+++ b/src/camel/camel-subscribable.c
@@ -157,7 +157,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 +168,7 @@ camel_subscribable_default_init (CamelSubscribableInterface *iface)
                        folder_unsubscribed),
                NULL, NULL, NULL,
                G_TYPE_NONE, 1,
-               G_TYPE_POINTER);
+               CAMEL_TYPE_FOLDER_INFO);
 }
 
 /**
diff --git a/src/camel/camel-trie.c b/src/camel/camel-trie.c
index 4d9ea9f..641643f 100644
--- a/src/camel/camel-trie.c
+++ b/src/camel/camel-trie.c
@@ -331,13 +331,13 @@ camel_trie_add (CamelTrie *trie,
 /**
  * camel_trie_search:
  * @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-url-scanner.c b/src/camel/camel-url-scanner.c
index c977e14..1438d70 100644
--- a/src/camel/camel-url-scanner.c
+++ b/src/camel/camel-url-scanner.c
@@ -64,6 +64,17 @@ camel_url_scanner_add (CamelUrlScanner *scanner,
        g_ptr_array_add (scanner->patterns, pattern);
 }
 
+/**
+ * camel_url_scanner_scan:
+ * @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-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..3228597 100644
--- a/src/camel/camel-vee-data-cache.h
+++ b/src/camel/camel-vee-data-cache.h
@@ -199,9 +199,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..d82b276 100644
--- a/src/camel/camel-vee-folder.c
+++ b/src/camel/camel-vee-folder.c
@@ -145,7 +145,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);
@@ -905,9 +905,9 @@ vee_folder_get_message_sync (CamelFolder *folder,
        mi = (CamelVeeMessageInfo *) camel_folder_summary_get (folder->summary, 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,
@@ -1531,6 +1531,9 @@ camel_vee_folder_set_folders (CamelVeeFolder *vf,
 
 /**
  * camel_vee_folder_add_vuid:
+ * @vfolder:
+ * @mi_data: (type CamelVeeMessageInfoData):
+ * @changes:
  *
  * FIXME Document me!
  *
@@ -1582,6 +1585,9 @@ camel_vee_folder_add_vuid (CamelVeeFolder *vfolder,
 
 /**
  * camel_vee_folder_remove_vuid:
+ * @vfolder:
+ * @mi_data: (type CamelVeeMessageInfoData):
+ * @changes:
  *
  * FIXME Document me!
  *
@@ -1653,25 +1659,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..ebb43b7 100644
--- a/src/camel/camel-vee-folder.h
+++ b/src/camel/camel-vee-folder.h
@@ -95,7 +95,7 @@ void          camel_vee_folder_construct              (CamelVeeFolder *vf,
                                                         guint32 flags);
 
 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..fa79459
--- /dev/null
+++ b/src/camel/camel-vee-message-info.h
@@ -0,0 +1,77 @@
+/* -*- 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;
+};
+
+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..8e789a5 100644
--- a/src/camel/camel-vee-store.c
+++ b/src/camel/camel-vee-store.c
@@ -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-summary.c b/src/camel/camel-vee-summary.c
index ddd527d..e1ac50f 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, orig_folder->summary, 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;
 }
 
@@ -446,7 +196,15 @@ camel_vee_summary_get_uids_for_subfolder (CamelVeeSummary *summary,
        return known_uids;
 }
 
-/* unref returned pointer with camel_message_info_unref() */
+/**
+ * camel_vee_summary_add:
+ * @s: 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,
                        CamelVeeMessageInfoData *mi_data)
@@ -470,19 +228,14 @@ camel_vee_summary_add (CamelVeeSummary *s,
        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);
 
                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 (s), 
orig_folder->summary, vuid);
 
        vuids = g_hash_table_lookup (s->priv->vuids_by_subfolder, orig_folder);
        if (vuids) {
@@ -493,7 +246,7 @@ camel_vee_summary_add (CamelVeeSummary *s,
                g_hash_table_insert (s->priv->vuids_by_subfolder, orig_folder, vuids);
        }
 
-       camel_folder_summary_insert (&s->summary, (CamelMessageInfo *) vmi, FALSE);
+       camel_folder_summary_add (&s->summary, (CamelMessageInfo *) vmi, TRUE);
        camel_folder_summary_unlock (&s->summary);
 
        return vmi;
@@ -534,8 +287,8 @@ camel_vee_summary_remove (CamelVeeSummary *summary,
        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);
@@ -570,7 +323,7 @@ camel_vee_summary_replace_flags (CamelVeeSummary *summary,
        }
 
        camel_folder_summary_replace_flags (&summary->summary, mi);
-       camel_message_info_unref (mi);
+       g_clear_object (&mi);
 
        camel_folder_summary_unlock (&summary->summary);
 }
diff --git a/src/camel/camel-vee-summary.h b/src/camel/camel-vee-summary.h
index 94a95dc..629b2f4 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,13 +56,6 @@ 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;
 
@@ -74,7 +68,7 @@ struct _CamelVeeSummaryClass {
 
 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,
                                                 struct _CamelVeeMessageInfoData *mi_data);
diff --git a/src/camel/camel-vtrash-folder.c b/src/camel/camel-vtrash-folder.c
index b8eef41..6b0888d 100644
--- a/src/camel/camel-vtrash-folder.c
+++ b/src/camel/camel-vtrash-folder.c
@@ -79,7 +79,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);
                }
        }
 
@@ -166,18 +166,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 +187,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 +199,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) {
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-folder.c b/src/camel/providers/imapx/camel-imapx-folder.c
index 0d73287..c14b3fb 100644
--- a/src/camel/providers/imapx/camel-imapx-folder.c
+++ b/src/camel/providers/imapx/camel-imapx-folder.c
@@ -498,7 +498,7 @@ imapx_expunge_sync (CamelFolder *folder,
                                info = camel_folder_summary_get (folder->summary, 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);
                                }
                        }
 
@@ -649,7 +649,7 @@ imapx_get_message_sync (CamelFolder *folder,
                                        has_attachment ? CAMEL_MESSAGE_ATTACHMENTS : 0);
                        }
 
-                       camel_message_info_unref (mi);
+                       g_clear_object (&mi);
                }
        }
 
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..9a324d1
--- /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, TRUE);
+
+       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..748c75b
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-message-info.h
@@ -0,0 +1,87 @@
+/* -*- 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;
+};
+
+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-search.c b/src/camel/providers/imapx/camel-imapx-search.c
index b4e0a80..48e6760 100644
--- a/src/camel/providers/imapx/camel-imapx-search.c
+++ b/src/camel/providers/imapx/camel-imapx-search.c
@@ -258,8 +258,7 @@ imapx_search_match_all (CamelSExp *sexp,
                if (search->current) {
                        result = camel_sexp_term_eval (sexp, argv[0]);
                        camel_sexp_result_free (sexp, result);
-                       camel_message_info_unref (search->current);
-                       search->current = NULL;
+                       g_clear_object (&search->current);
                        break;
                }
        }
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index 518dbe3..dd3eac5 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);
        }
 }
@@ -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);
                }
@@ -1337,11 +1337,12 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
                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,29 +1368,29 @@ 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);
 
-                       if (!camel_folder_summary_check_uid (folder->summary, mi->uid)) {
+                       if (!camel_folder_summary_check_uid (folder->summary, 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 (folder->summary, 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);
 
@@ -1398,14 +1399,13 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
                                        camel_operation_progress (cancellable, cnt ? cnt : 1);
                                }
-                       } else {
-                               camel_message_info_unref (mi);
                        }
 
+                       g_clear_object (&mi);
                        camel_folder_summary_unlock (folder->summary);
 
-                       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);
@@ -4080,12 +4080,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);
 
@@ -4316,7 +4316,7 @@ 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++) {
@@ -4395,31 +4395,32 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
 
                                                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, destination_folder->summary);
+                                                       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 
(destination_folder->summary, 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)) {
@@ -4570,35 +4571,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);
@@ -4614,6 +4602,8 @@ 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)) {
@@ -4622,14 +4612,14 @@ camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
                camel_data_wrapper_write_to_stream_sync (
                        CAMEL_DATA_WRAPPER (message),
                        CAMEL_STREAM (sn), NULL, NULL);
-               ((CamelMessageInfoBase *) info)->size = sn->written;
+               camel_message_info_set_size (info, sn->written);
                g_object_unref (sn);
        }
 
        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;
@@ -4649,8 +4639,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);
 
@@ -4658,11 +4648,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) {
@@ -4685,36 +4677,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;
 
-                               cur = camel_data_cache_get_filename  (imapx_folder->cache, "cur", mi->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", 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 (folder->summary, 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 {
@@ -4726,8 +4724,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);
        }
 
@@ -4860,7 +4857,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);
        }
 }
 
@@ -5167,7 +5164,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);
@@ -5192,17 +5189,14 @@ 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);
                }
        }
 
@@ -5212,25 +5206,6 @@ imapx_unset_folder_flagged_flag (CamelFolderSummary *summary,
        }
 }
 
-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));
-       }
-}
-
 gboolean
 camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                                      CamelIMAPXMailbox *mailbox,
@@ -5242,9 +5217,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;
@@ -5278,9 +5252,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;
@@ -5314,26 +5286,34 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
 
        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 (folder->summary, 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;
@@ -5361,63 +5341,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 =
@@ -5427,24 +5420,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);
                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;
        }
@@ -5466,22 +5455,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 (folder->summary, 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 =
@@ -5525,10 +5515,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);
@@ -5542,7 +5533,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 ");
@@ -5570,8 +5561,6 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                }
        }
 
-       g_signal_handler_disconnect (folder->summary, changed_meanwhile_handler_id);
-
        if (success) {
                CamelStore *parent_store;
                guint32 unseen;
@@ -5581,31 +5570,50 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
                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_message_info_property_unlock (info);
                        camel_folder_summary_touch (folder->summary);
-                       camel_message_info_unref (xinfo);
+                       g_clear_object (&info);
                }
 
                camel_folder_summary_unlock (folder->summary);
@@ -5640,7 +5648,7 @@ camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
        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;
diff --git a/src/camel/providers/imapx/camel-imapx-summary.c b/src/camel/providers/imapx/camel-imapx-summary.c
index 6e3a2d2..7485af3 100644
--- a/src/camel/providers/imapx/camel-imapx-summary.c
+++ b/src/camel/providers/imapx/camel-imapx-summary.c
@@ -28,17 +28,11 @@
 
 #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
-};
-
-static guint signals[LAST_SIGNAL];
-
 G_DEFINE_TYPE (
        CamelIMAPXSummary,
        camel_imapx_summary,
@@ -61,12 +55,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) {
@@ -109,236 +103,15 @@ 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->message_info_type = CAMEL_TYPE_IMAPX_MESSAGE_INFO;
        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 * */);
 }
 
 static void
@@ -401,8 +174,6 @@ camel_imapx_summary_new (CamelFolder *folder)
                summary->collate = "imapx_uid_sort";
        }
 
-       camel_folder_summary_set_build_content (summary, TRUE);
-
        if (!camel_folder_summary_load_from_db (summary, &local_error)) {
                /* FIXME: Isn't this dangerous ? We clear the summary
                if it cannot be loaded, for some random reason.
@@ -414,4 +185,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..0db09fa 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;
 
diff --git a/src/camel/providers/imapx/camel-imapx-utils.c b/src/camel/providers/imapx/camel-imapx-utils.c
index c60666d..6522db4 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
@@ -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);
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-summary.c b/src/camel/providers/local/camel-local-summary.c
index 9fee506..8b86dfd 100644
--- a/src/camel/providers/local/camel-local-summary.c
+++ b/src/camel/providers/local/camel-local-summary.c
@@ -37,8 +37,6 @@
 
 #define CAMEL_LOCAL_SUMMARY_VERSION (1)
 
-#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
-
 static CamelFIRecord *
                summary_header_to_db            (CamelFolderSummary *,
                                                 GError **error);
@@ -47,15 +45,15 @@ static gboolean     summary_header_from_db          (CamelFolderSummary *,
 
 static CamelMessageInfo *
                message_info_new_from_header    (CamelFolderSummary *,
-                                                struct _camel_header_raw *);
+                                                CamelHeaderRaw *);
 
 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,8 +117,6 @@ 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;
@@ -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)
@@ -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);
 
@@ -392,7 +387,7 @@ camel_local_summary_add (CamelLocalSummary *cls,
  **/
 gint
 camel_local_summary_write_headers (gint fd,
-                                   struct _camel_header_raw *header,
+                                   CamelHeaderRaw *header,
                                    const gchar *xevline,
                                    const gchar *status,
                                    const gchar *xstatus)
@@ -516,34 +511,20 @@ 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 */
@@ -553,15 +534,17 @@ local_summary_add (CamelLocalSummary *cls,
                camel_data_wrapper_write_to_stream_sync (
                        (CamelDataWrapper *) msg,
                        (CamelStream *) sn, NULL, NULL);
-               mi_base->size = sn->written;
+               camel_message_info_set_size (mi, sn->written);
                g_object_unref (sn);
        }
 
-       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 +552,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 +666,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 +676,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,8 +687,8 @@ 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;
 }
@@ -703,7 +707,7 @@ summary_header_from_db (CamelFolderSummary *s,
 
        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) */
@@ -732,23 +736,27 @@ summary_header_to_db (CamelFolderSummary *s,
 
 static CamelMessageInfo *
 message_info_new_from_header (CamelFolderSummary *s,
-                              struct _camel_header_raw *h)
+                              CamelHeaderRaw *h)
 {
-       CamelLocalMessageInfo *mi;
+       CamelMessageInfo *mi;
        CamelLocalSummary *cls = (CamelLocalSummary *) s;
 
-       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_header (s, 
h);
        if (mi) {
                const gchar *xev;
                gint doindex = FALSE;
 
                xev = camel_header_raw_find (&h, "X-Evolution", NULL);
                if (xev == NULL || camel_local_summary_decode_x_evolution (cls, xev, mi) == -1) {
+                       gchar *uid;
+
+                       uid = camel_folder_summary_next_uid_string (s);
+
                        /* 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;
@@ -766,5 +774,5 @@ message_info_new_from_header (CamelFolderSummary *s,
                }
        }
 
-       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..cd230e5 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,8 +72,8 @@ 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);
 };
 
@@ -99,11 +93,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, CamelHeaderRaw *header, 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..cfc9656 100644
--- a/src/camel/providers/local/camel-maildir-folder.c
+++ b/src/camel/providers/local/camel-maildir-folder.c
@@ -56,9 +56,9 @@ maildir_folder_cmp_uids (CamelFolder *folder,
        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;
 }
@@ -108,13 +108,13 @@ maildir_folder_get_filename (CamelFolder *folder,
                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;
 }
@@ -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,
@@ -250,6 +250,8 @@ maildir_folder_append_message_sync (CamelFolder *folder,
                camel_folder_change_info_clear (lf->changes);
        }
 
+       g_clear_object (&mi);
+
        return success;
 }
 
@@ -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, dest->summary);
 
-                               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)
                                        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)
                                        camel_message_info_set_flags (info, CAMEL_MESSAGE_JUNK, 0);
-                               camel_folder_summary_add (dest->summary, clone);
+                               camel_folder_summary_add (dest->summary, clone, FALSE);
 
                                camel_folder_change_info_add_uid (df->changes, camel_message_info_get_uid 
(clone));
 
@@ -391,9 +388,10 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
                                        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);
+                               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);
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..226bf50
--- /dev/null
+++ b/src/camel/providers/local/camel-maildir-message-info.h
@@ -0,0 +1,71 @@
+/* -*- 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;
+};
+
+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-summary.c 
b/src/camel/providers/local/camel-maildir-summary.c
index 2c5a56b..9f7aa6a 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) \
@@ -48,13 +49,7 @@
 
 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);
-
+                                                CamelHeaderRaw *);
 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,8 @@ 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_type = CAMEL_TYPE_MAILDIR_MESSAGE_INFO;
        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->next_uid_string = maildir_summary_next_uid_string;
 
        local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (class);
@@ -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)
+                              CamelHeaderRaw *h)
 {
        CamelMessageInfo *mi, *info;
        CamelMaildirSummary *mds = (CamelMaildirSummary *) s;
-       CamelMaildirMessageInfo *mdi;
        const gchar *uid;
 
        mi = ((CamelFolderSummaryClass *) camel_maildir_summary_parent_class)->message_info_new_from_header 
(s, h);
        /* 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 (s);
+
+                       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 (s, 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..61040d4 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;
@@ -73,12 +68,8 @@ 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..f222a13 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,6 +51,7 @@ 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);
@@ -61,9 +63,9 @@ mbox_folder_cmp_uids (CamelFolder *folder,
        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;
 }
@@ -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));
@@ -122,20 +126,16 @@ mbox_folder_get_filename (CamelFolder *folder,
                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);
 
@@ -154,7 +154,7 @@ mbox_folder_append_message_sync (CamelFolder *folder,
        CamelStream *output_stream = NULL, *filter_stream = NULL;
        CamelMimeFilter *filter_from;
        CamelMboxSummary *mbs = (CamelMboxSummary *) folder->summary;
-       CamelMessageInfo *mi;
+       CamelMessageInfo *mi = NULL;
        gchar *fromline = NULL;
        struct stat st;
        gint retval;
@@ -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);
        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,11 +230,6 @@ 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) {
@@ -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:
@@ -298,6 +295,8 @@ fail:
                camel_folder_change_info_clear (lf->changes);
        }
 
+       g_clear_object (&mi);
+
        return FALSE;
 }
 
@@ -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
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..89d894d
--- /dev/null
+++ b/src/camel/providers/local/camel-mbox-message-info.h
@@ -0,0 +1,67 @@
+/* -*- 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;
+};
+
+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-summary.c b/src/camel/providers/local/camel-mbox-summary.c
index 4e82fdc..a5e683f 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)
 
@@ -60,21 +60,14 @@ static CamelFIRecord *
 static gboolean        summary_header_from_db          (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 *);
+                                                CamelHeaderRaw *);
 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,17 @@ 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->message_info_type = CAMEL_TYPE_MBOX_MESSAGE_INFO;
        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_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;
@@ -248,20 +180,22 @@ 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);
        }
 }
 
@@ -277,8 +211,8 @@ summary_header_from_db (CamelFolderSummary *s,
 
        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;
@@ -307,17 +241,16 @@ summary_header_to_db (CamelFolderSummary *s,
 
 static CamelMessageInfo *
 message_info_new_from_header (CamelFolderSummary *s,
-                              struct _camel_header_raw *h)
+                              CamelHeaderRaw *h)
 {
-       CamelMboxMessageInfo *mi;
+       CamelMessageInfo *mi;
        CamelMboxSummary *mbs = (CamelMboxSummary *) s;
 
-       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_header (s, 
h);
        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;
 
@@ -330,24 +263,24 @@ message_info_new_from_header (CamelFolderSummary *s,
                        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);
                if (xev != NULL
-                   && camel_local_summary_decode_x_evolution ((CamelLocalSummary *) s, xev, &mi->info) == 0) 
{
+                   && camel_local_summary_decode_x_evolution ((CamelLocalSummary *) s, 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 (s, 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 +291,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 (s);
+
+                       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));
                }
-#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 +317,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 +331,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 +349,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 +405,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 +425,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 +441,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)
@@ -627,7 +526,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);
@@ -790,20 +689,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 +725,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 +775,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 +803,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 +823,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 +855,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 +887,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 +927,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);
@@ -1104,7 +1008,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 +1016,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 +1046,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 +1059,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 +1077,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 +1089,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 +1100,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 +1109,33 @@ 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) {
+                       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
+                       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);
+                               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, camel_mime_parser_headers_raw 
(mp), xevnew, statnew, xstatnew);
                        } else {
-#endif
                                len = camel_local_summary_write_headers (fdout, camel_mime_parser_headers_raw 
(mp), xevnew, NULL, NULL);
-#ifdef STATUS_PINE
                        }
-#endif
+
                        if (len == -1) {
                                d (printf ("Error writing to temporary mailbox\n"));
                                g_set_error (
@@ -1241,7 +1145,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,8 +1181,7 @@ 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);
                }
        }
 
@@ -1298,17 +1201,10 @@ 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);
                }
        }
 
@@ -1323,9 +1219,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 +1227,6 @@ camel_mbox_summary_sync_mbox (CamelMboxSummary *cls,
        return -1;
 }
 
-#ifdef STATUS_PINE
 static CamelMessageInfo *
 mbox_summary_add (CamelLocalSummary *cls,
                   CamelMimeMessage *msg,
@@ -1342,23 +1235,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 +1296,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..594cca4 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;
 
diff --git a/src/camel/providers/local/camel-mh-folder.c b/src/camel/providers/local/camel-mh-folder.c
index 7eaafe9..fa56572 100644
--- a/src/camel/providers/local/camel-mh-folder.c
+++ b/src/camel/providers/local/camel-mh-folder.c
@@ -128,6 +128,8 @@ mh_folder_append_message_sync (CamelFolder *folder,
                camel_folder_change_info_clear (lf->changes);
        }
 
+       g_clear_object (&mi);
+
        return TRUE;
 }
 
@@ -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-summary.c b/src/camel/providers/local/camel-mh-summary.c
index b653192..b471eea 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);
@@ -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-spool-summary.c b/src/camel/providers/local/camel-spool-summary.c
index 44e3719..e78cfc9 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))*/
 
@@ -332,10 +333,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);
 
diff --git a/src/camel/providers/local/camel-spool-summary.h b/src/camel/providers/local/camel-spool-summary.h
index b08adfb..fdd4f91 100644
--- a/src/camel/providers/local/camel-spool-summary.h
+++ b/src/camel/providers/local/camel-spool-summary.h
@@ -76,7 +76,7 @@ gchar *camel_spool_summary_encode_x_evolution (CamelSpoolSummary *cls, const Cam
 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);
+gint camel_spool_summary_write_headers (gint fd, CamelHeaderRaw *header, gchar *xevline);
 
 G_END_DECLS
 
diff --git a/src/camel/providers/nntp/camel-nntp-folder.c b/src/camel/providers/nntp/camel-nntp-folder.c
index 8e45b11..868ad45 100644
--- a/src/camel/providers/nntp/camel-nntp-folder.c
+++ b/src/camel/providers/nntp/camel-nntp-folder.c
@@ -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);
        }
 }
 
@@ -411,7 +405,7 @@ nntp_folder_append_message_sync (CamelFolder *folder,
        CamelMimeFilter *crlffilter;
        gint ret;
        guint u;
-       struct _camel_header_raw *header, *savedhdrs, *n, *tail;
+       CamelHeaderRaw *header, *savedhdrs, *n, *tail;
        const gchar *full_name;
        gchar *group, *line;
        gboolean success = TRUE;
@@ -447,9 +441,9 @@ nntp_folder_append_message_sync (CamelFolder *folder,
 
        /* remove mail 'To', 'CC', and 'BCC' headers */
        savedhdrs = NULL;
-       tail = (struct _camel_header_raw *) &savedhdrs;
+       tail = (CamelHeaderRaw *) &savedhdrs;
 
-       header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers;
+       header = (CamelHeaderRaw *) &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")) {
@@ -549,7 +543,7 @@ 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);
diff --git a/src/camel/providers/nntp/camel-nntp-summary.c b/src/camel/providers/nntp/camel-nntp-summary.c
index d4c47aa..bc0646e 100644
--- a/src/camel/providers/nntp/camel-nntp-summary.c
+++ b/src/camel/providers/nntp/camel-nntp-summary.c
@@ -51,7 +51,7 @@ struct _CamelNNTPSummaryPrivate {
        gint xover_setup;
 };
 
-static CamelMessageInfo * message_info_new_from_header (CamelFolderSummary *, struct _camel_header_raw *);
+static CamelMessageInfo * message_info_new_from_header (CamelFolderSummary *, CamelHeaderRaw *);
 static gboolean summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir);
 static CamelFIRecord * summary_header_to_db (CamelFolderSummary *s, GError **error);
 
@@ -65,8 +65,6 @@ 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;
@@ -90,31 +88,28 @@ 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)
+                              CamelHeaderRaw *h)
 {
-       CamelMessageInfoBase *mi;
+       CamelMessageInfo *mi;
        CamelNNTPSummary *cns = (CamelNNTPSummary *) s;
 
        /* 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_header (s, 
h);
        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
@@ -129,9 +124,9 @@ summary_header_from_db (CamelFolderSummary *s,
 
        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;
 }
@@ -169,7 +164,7 @@ add_range_xover (CamelNNTPSummary *cns,
        CamelSettings *settings;
        CamelService *service;
        CamelFolderSummary *s;
-       struct _camel_header_raw *headers = NULL;
+       CamelHeaderRaw *headers = NULL;
        gchar *line, *tab;
        gchar *host;
        guint len;
@@ -268,13 +263,14 @@ add_range_xover (CamelNNTPSummary *cns,
                                CamelMessageInfo *mi;
 
                                mi = camel_folder_summary_info_new_from_header (s, headers);
-                               ((CamelMessageInfoBase *) mi)->size = size;
-                               camel_folder_summary_add (s, mi);
+                               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);
                        }
                }
 
@@ -370,7 +366,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 +376,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 +501,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);
                                        }
diff --git a/src/camel/providers/pop3/camel-pop3-folder.c b/src/camel/providers/pop3/camel-pop3-folder.c
index bb7042e..65ffef5 100644
--- a/src/camel/providers/pop3/camel-pop3-folder.c
+++ b/src/camel/providers/pop3/camel-pop3-folder.c
@@ -90,7 +90,7 @@ cmd_builduid (CamelPOP3Engine *pe,
 {
        GChecksum *checksum;
        CamelPOP3FolderInfo *fi = data;
-       struct _camel_header_raw *h;
+       CamelHeaderRaw *h;
        CamelMimeParser *mp;
        guint8 *digest;
        gsize length;
@@ -372,8 +372,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;
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-transport.c 
b/src/camel/providers/sendmail/camel-sendmail-transport.c
index 7767945..0e069d5 100644
--- a/src/camel/providers/sendmail/camel-sendmail-transport.c
+++ b/src/camel/providers/sendmail/camel-sendmail-transport.c
@@ -112,7 +112,7 @@ sendmail_send_to_sync (CamelTransport *transport,
                        GCancellable *cancellable,
                        GError **error)
 {
-       struct _camel_header_raw *header, *savedbcc, *n, *tail;
+       CamelHeaderRaw *header, *savedbcc, *n, *tail;
        const gchar *from_addr, *addr;
        GPtrArray *argv_arr;
        gint i, len, fd[2], nullfd, wstat;
@@ -204,9 +204,9 @@ sendmail_send_to_sync (CamelTransport *transport,
 
        /* unlink the bcc headers */
        savedbcc = NULL;
-       tail = (struct _camel_header_raw *) &savedbcc;
+       tail = (CamelHeaderRaw *) &savedbcc;
 
-       header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers;
+       header = (CamelHeaderRaw *) &CAMEL_MIME_PART (message)->headers;
        n = header->next;
        while (n != NULL) {
                if (!g_ascii_strcasecmp (n->name, "Bcc")) {
diff --git a/src/camel/providers/smtp/camel-smtp-transport.c b/src/camel/providers/smtp/camel-smtp-transport.c
index 44e96bf..1a555c3 100644
--- a/src/camel/providers/smtp/camel-smtp-transport.c
+++ b/src/camel/providers/smtp/camel-smtp-transport.c
@@ -1639,7 +1639,7 @@ smtp_data (CamelSmtpTransport *transport,
            GCancellable *cancellable,
            GError **error)
 {
-       struct _camel_header_raw *header, *savedbcc, *n, *tail;
+       CamelHeaderRaw *header, *savedbcc, *n, *tail;
        CamelBestencEncoding enctype = CAMEL_BESTENC_8BIT;
        CamelStream *filtered_stream;
        gchar *cmdbuf, *respbuf = NULL;
@@ -1696,9 +1696,9 @@ smtp_data (CamelSmtpTransport *transport,
 
        /* unlink the bcc headers */
        savedbcc = NULL;
-       tail = (struct _camel_header_raw *) &savedbcc;
+       tail = (CamelHeaderRaw *) &savedbcc;
 
-       header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers;
+       header = (CamelHeaderRaw *) &CAMEL_MIME_PART (message)->headers;
        n = header->next;
        while (n != NULL) {
                if (!g_ascii_strcasecmp (n->name, "Bcc")) {
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/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]