[evolution-data-server/wip/camel-more-gobject] Prototype load/save CamelMessageInfo methods



commit 1b75b7415a3f90c83e5b8e6ab293a3c7008b2312
Author: Milan Crha <mcrha redhat com>
Date:   Tue Sep 6 15:11:44 2016 +0200

    Prototype load/save CamelMessageInfo methods

 camel/camel-message-info-base.c                    |   36 +
 camel/camel-message-info.c                         |  759 ++++++++++++++++++--
 camel/camel-message-info.h                         |   42 ++-
 camel/camel-vee-message-info.c                     |   14 +
 camel/providers/imapx/camel-imapx-message-info.c   |   32 +-
 camel/providers/local/camel-maildir-message-info.c |   38 +-
 camel/providers/local/camel-maildir-message-info.h |    3 +
 camel/providers/local/camel-mbox-message-info.c    |   67 ++-
 8 files changed, 899 insertions(+), 92 deletions(-)
---
diff --git a/camel/camel-message-info-base.c b/camel/camel-message-info-base.c
index 9a4950f..ddeb031 100644
--- a/camel/camel-message-info-base.c
+++ b/camel/camel-message-info-base.c
@@ -129,6 +129,23 @@ message_info_base_set_user_flag (xCamelMessageInfo *mi,
        return changed;
 }
 
+static const CamelNamedFlags *
+message_info_base_get_user_flags (const xCamelMessageInfo *mi)
+{
+       xCamelMessageInfoBase *bmi;
+       const CamelNamedFlags *result;
+
+       g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+       xcamel_message_info_property_lock (mi);
+       result = bmi->priv->user_flags;
+       xcamel_message_info_property_unlock (mi);
+
+       return result;
+}
+
 static CamelNamedFlags *
 message_info_base_dup_user_flags (const xCamelMessageInfo *mi)
 {
@@ -218,6 +235,23 @@ message_info_base_set_user_tag (xCamelMessageInfo *mi,
        return changed;
 }
 
+static const CamelNameValueArray *
+message_info_base_get_user_tags (const xCamelMessageInfo *mi)
+{
+       xCamelMessageInfoBase *bmi;
+       const CamelNameValueArray *result;
+
+       g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO_BASE (mi), NULL);
+
+       bmi = XCAMEL_MESSAGE_INFO_BASE (mi);
+
+       xcamel_message_info_property_lock (mi);
+       result = bmi->priv->user_tags;
+       xcamel_message_info_property_unlock (mi);
+
+       return result;
+}
+
 static CamelNameValueArray *
 message_info_base_dup_user_tags (const xCamelMessageInfo *mi)
 {
@@ -836,10 +870,12 @@ xcamel_message_info_base_class_init (xCamelMessageInfoBaseClass *class)
        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;
diff --git a/camel/camel-message-info.c b/camel/camel-message-info.c
index bd5110d..f89d975 100644
--- a/camel/camel-message-info.c
+++ b/camel/camel-message-info.c
@@ -20,7 +20,9 @@
 #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"
@@ -34,6 +36,7 @@ struct _xCamelMessageInfoPrivate {
        GWeakRef summary;       /* CamelFolderSummary * */
        gboolean dirty;         /* whether requires save to local disk/summary */
        const gchar *uid;       /* allocated in the string pool */
+       gboolean loading;
 };
 
 enum {
@@ -41,6 +44,7 @@ enum {
        PROP_SUMMARY,
        PROP_DIRTY,
        PROP_FOLDER_FLAGGED,
+       PROP_LOADING,
        PROP_UID,
        PROP_FLAGS,
        PROP_USER_FLAGS,
@@ -80,6 +84,7 @@ message_info_clone (const xCamelMessageInfo *mi,
        result = xcamel_message_info_new (assign_summary);
 
        g_object_freeze_notify (G_OBJECT (result));
+       xcamel_message_info_set_loading (result, TRUE);
 
        uid = xcamel_message_info_pooldup_uid (mi);
        xcamel_message_info_set_uid (result, uid);
@@ -127,11 +132,216 @@ message_info_clone (const xCamelMessageInfo *mi,
        /* Also ensure 'dirty' flag, thus it can be eventually saved. */
        xcamel_message_info_set_dirty (result, TRUE);
 
+       xcamel_message_info_set_loading (result, FALSE);
        g_object_thaw_notify (G_OBJECT (result));
 
        return result;
 }
 
+static gboolean
+message_info_load (xCamelMessageInfo *mi,
+                  const CamelMIRecord *record,
+                  /* const */ gchar **bdata_ptr)
+{
+       gint ii, count;
+       gchar *part, *label;
+
+       g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       xcamel_message_info_set_uid (mi, record->uid);
+       xcamel_message_info_set_flags (mi, ~0, record->flags);
+       xcamel_message_info_set_size (mi, record->size);
+       xcamel_message_info_set_date_sent (mi, record->dsent);
+       xcamel_message_info_set_date_received (mi, record->dreceived);
+
+       xcamel_message_info_set_subject (mi, record->subject);
+       xcamel_message_info_set_from (mi, record->from);
+       xcamel_message_info_set_to (mi, record->to);
+       xcamel_message_info_set_cc (mi, record->cc);
+       xcamel_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_message_info_util_bdata_get_number (&part, 0);
+               message_id.id.part.lo = camel_message_info_util_bdata_get_number (&part, 0);
+
+               xcamel_message_info_set_message_id (mi, message_id.id.id);
+
+               count = camel_message_info_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_message_info_util_bdata_get_number (&part, 0);
+                               message_id.id.part.lo = camel_message_info_util_bdata_get_number (&part, 0);
+
+                               g_array_append_val (references, message_id.id.id);
+                       }
+
+                       xcamel_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]);
+                       }
+               }
+               if (label && *label)
+                       camel_named_flags_insert (user_flags, label);
+
+               xcamel_message_info_take_user_flags (mi, user_flags);
+       }
+
+       /* Extract User tags */
+       part = record->usertags;
+       if (part) {
+               CamelNameValueArray *user_tags;
+
+               count = camel_message_info_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_message_info_util_bdata_get_string (&part, NULL);
+                       value = camel_message_info_util_bdata_get_string (&part, NULL);
+
+                       if (name && value)
+                               camel_name_value_array_set_named (user_tags, TRUE, name, value);
+
+                       g_free (name);
+                       g_free (value);
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean
+message_info_save (const xCamelMessageInfo *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 (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_str != NULL, FALSE);
+
+       #warning Change camel_db_camel_mir_free() to pstring_free only the UID and g_free() all other text 
fields
+
+       record->uid = (gchar *) camel_pstring_strdup (xcamel_message_info_get_uid (mi));
+       record->flags = xcamel_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 = xcamel_message_info_get_size (mi);
+       record->dsent = xcamel_message_info_get_date_sent (mi);
+       record->dreceived = xcamel_message_info_get_date_received (mi);
+
+       record->subject = g_strdup (xcamel_message_info_get_subject (mi));
+       record->from = g_strdup (xcamel_message_info_get_from (mi));
+       record->to = g_strdup (xcamel_message_info_get_to (mi));
+       record->cc = g_strdup (xcamel_message_info_get_cc (mi));
+       record->mlist = g_strdup (xcamel_message_info_get_mlist (mi));
+
+       record->followup_flag = g_strdup (xcamel_message_info_get_user_tag (mi, "follow-up"));
+       record->followup_completed_on = g_strdup (xcamel_message_info_get_user_tag (mi, "completed-on"));
+       record->followup_due_by = g_strdup (xcamel_message_info_get_user_tag (mi, "due-by"));
+
+       tmp = g_string_new (NULL);
+       message_id.id.id = xcamel_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 = xcamel_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 = xcamel_message_info_dup_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 = xcamel_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,
@@ -153,6 +363,10 @@ message_info_set_property (GObject *object,
                xcamel_message_info_set_folder_flagged (mi, g_value_get_boolean (value));
                return;
 
+       case PROP_LOADING:
+               xcamel_message_info_set_loading (mi, g_value_get_boolean (value));
+               return;
+
        case PROP_UID:
                xcamel_message_info_set_uid (mi, g_value_get_string (value));
                return;
@@ -235,11 +449,15 @@ message_info_get_property (GObject *object,
                return;
 
        case PROP_DIRTY:
-               xcamel_message_info_set_dirty (mi, g_value_get_boolean (value));
+               g_value_set_boolean (value, xcamel_message_info_get_dirty (mi));
                return;
 
        case PROP_FOLDER_FLAGGED:
-               xcamel_message_info_set_folder_flagged (mi, g_value_get_boolean (value));
+               g_value_set_boolean (value, xcamel_message_info_get_folder_flagged (mi));
+               return;
+
+       case PROP_LOADING:
+               g_value_set_boolean (value, xcamel_message_info_get_loading (mi));
                return;
 
        case PROP_UID:
@@ -343,6 +561,8 @@ xcamel_message_info_class_init (xCamelMessageInfoClass *class)
        g_type_class_add_private (class, sizeof (xCamelMessageInfoPrivate));
 
        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;
@@ -425,6 +645,24 @@ xcamel_message_info_class_init (xCamelMessageInfoClass *class)
                        G_PARAM_READWRITE));
 
        /**
+        * xCamelMessageInfo:loading
+        *
+        * Flag, whether the info is currently loading. It is used to avoid
+        * unnecessary 'folder-flagged' and 'dirty' flags changes.
+        *
+        * Since: 3.24
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_LOADING,
+               g_param_spec_boolean (
+                       "loading",
+                       "Loading",
+                       NULL,
+                       FALSE,
+                       G_PARAM_READWRITE));
+
+       /**
         * xCamelMessageInfo:flags
         *
         * Bit-or of #CamelMessageFlags.
@@ -756,6 +994,96 @@ xcamel_message_info_clone (const xCamelMessageInfo *mi,
 }
 
 /**
+ * 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_message_info_util_bdata_get_number() and
+ * camel_message_info_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 (xCamelMessageInfo *mi,
+                        const CamelMIRecord *record,
+                        /* const */ gchar **bdata_ptr)
+{
+       xCamelMessageInfoClass *klass;
+       gboolean success;
+
+       g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       klass = XCAMEL_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));
+       xcamel_message_info_property_lock (mi);
+       xcamel_message_info_set_loading (mi, TRUE);
+
+       success = klass->load (mi, record, bdata_ptr);
+
+       if (success)
+               xcamel_message_info_set_dirty (mi, FALSE);
+
+       xcamel_message_info_set_loading (mi, FALSE);
+       xcamel_message_info_property_unlock (mi);
+       g_object_thaw_notify (G_OBJECT (mi));
+
+       return success;
+}
+
+/**
+ * camel_message_info_save:
+ * @mi: a #xCamelMessageInfo
+ * @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_message_info_util_bdata_put_number() and
+ * camel_message_info_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 xCamelMessageInfo *mi,
+                        CamelMIRecord *record,
+                        GString *bdata_str)
+{
+       xCamelMessageInfoClass *klass;
+       gboolean success;
+
+       g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_str != NULL, FALSE);
+
+       klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->save != NULL, FALSE);
+
+       xcamel_message_info_property_lock (mi);
+
+       success = klass->save (mi, record, bdata_str);
+
+       xcamel_message_info_property_unlock (mi);
+
+       return success;
+}
+
+/**
  * xcamel_message_info_ref_summary:
  * @mi: a #xCamelMessageInfo
  *
@@ -885,16 +1213,18 @@ void
 xcamel_message_info_set_dirty (const xCamelMessageInfo *mi,
                               gboolean dirty)
 {
-       gboolean changed;
+       gboolean changed, loading;
+
        g_return_if_fail (XCAMEL_IS_MESSAGE_INFO (mi));
 
        xcamel_message_info_property_lock (mi);
        changed = (!mi->priv->dirty) != (!dirty);
        if (changed)
                mi->priv->dirty = dirty;
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "dirty");
 
                if (dirty) {
@@ -906,7 +1236,6 @@ xcamel_message_info_set_dirty (const xCamelMessageInfo *mi,
 
                        g_clear_object (&summary);
                }
-
        }
 }
 
@@ -964,6 +1293,58 @@ xcamel_message_info_set_folder_flagged (xCamelMessageInfo *mi,
 }
 
 /**
+ * xcamel_message_info_get_loading:
+ * @mi: a #CamelMessageInfo
+ *
+ * Returns: Whether the @mi is loading, 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.
+ *
+ * Since: 3.24
+ **/
+gboolean
+xcamel_message_info_get_loading (const xCamelMessageInfo *mi)
+{
+       gboolean result;
+
+       g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
+
+       xcamel_message_info_property_lock (mi);
+       result = mi->priv->loading;
+       xcamel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
+ * xcamel_message_info_set_loading:
+ * @mi: a #CamelMessageInfo
+ * @loading: a loading state to set
+ *
+ * Marks the @mi as loading, 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.
+ *
+ * Since: 3.24
+ **/
+void
+xcamel_message_info_set_loading (const xCamelMessageInfo *mi,
+                               gboolean loading)
+{
+       gboolean changed;
+       g_return_if_fail (XCAMEL_IS_MESSAGE_INFO (mi));
+
+       xcamel_message_info_property_lock (mi);
+       changed = (!mi->priv->loading) != (!loading);
+       if (changed)
+               mi->priv->loading = loading;
+       xcamel_message_info_property_unlock (mi);
+
+       if (changed)
+               g_object_notify (G_OBJECT (mi), "loading");
+}
+
+/**
  * xcamel_message_info_get_uid:
  * @mi: a #CamelMessageInfo
  *
@@ -1019,8 +1400,8 @@ xcamel_message_info_pooldup_uid (const xCamelMessageInfo *mi)
  * @uid: a UID to set
  *
  * Changes UID of the @mi to @uid. If it changes, the 'dirty' flag
- * of the @mi is set too. This change does not influence the 'folder-flagged'
- * flag.
+ * of the @mi is set too, unless the @mi is loading. This change
+ * does not influence the 'folder-flagged' flag.
  *
  * Returns: Whether the UID changed.
  *
@@ -1030,7 +1411,7 @@ gboolean
 xcamel_message_info_set_uid (xCamelMessageInfo *mi,
                             const gchar *uid)
 {
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1040,9 +1421,10 @@ xcamel_message_info_set_uid (xCamelMessageInfo *mi,
                camel_pstring_free (mi->priv->uid);
                mi->priv->uid = camel_pstring_strdup (uid);
        }
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "uid");
                xcamel_message_info_set_dirty (mi, TRUE);
        }
@@ -1086,8 +1468,8 @@ xcamel_message_info_get_flags (const xCamelMessageInfo *mi)
  * Change the state of the flags on the @mi.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is also emitted folder's "changed" signal
- * for this @mi, if necessary.
+ * set automatically, unless the @mi is loading. There is also emitted
+ * folder's "changed" signal for this @mi, if necessary.
  *
  * Returns: Whether the flags changed.
  *
@@ -1099,7 +1481,7 @@ xcamel_message_info_set_flags (xCamelMessageInfo *mi,
                               guint32 set)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1109,9 +1491,10 @@ xcamel_message_info_set_flags (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_flags (mi, mask, set);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "flags");
                xcamel_message_info_set_dirty (mi, TRUE);
 
@@ -1166,8 +1549,8 @@ xcamel_message_info_get_user_flag (const xCamelMessageInfo *mi,
  * 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. There is also emitted folder's "changed" signal
- * for this @mi, if necessary.
+ * set automatically, unless the @mi is loading. There is also emitted
+ * folder's "changed" signal for this @mi, if necessary.
  *
  * Returns: Whether the message info changed.
  *
@@ -1179,7 +1562,7 @@ xcamel_message_info_set_user_flag (xCamelMessageInfo *mi,
                                   gboolean state)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
        g_return_val_if_fail (name != NULL, FALSE);
@@ -1190,9 +1573,10 @@ xcamel_message_info_set_user_flag (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_user_flag (mi, name, state);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "user-flags");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1204,6 +1588,34 @@ xcamel_message_info_set_user_flag (xCamelMessageInfo *mi,
 }
 
 /**
+ * xcamel_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 *
+xcamel_message_info_get_user_flags (const xCamelMessageInfo *mi)
+{
+       xCamelMessageInfoClass *klass;
+       const CamelNamedFlags *result;
+
+       g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_user_flags != NULL, NULL);
+
+       xcamel_message_info_property_lock (mi);
+       result = klass->get_user_flags (mi);
+       xcamel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
  * xcamel_message_info_dup_user_flags:
  * @mi: a #CamelMessageInfo
  *
@@ -1242,8 +1654,8 @@ xcamel_message_info_dup_user_flags (const xCamelMessageInfo *mi)
  * 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. There is also emitted folder's "changed" signal
- * for this @mi, if necessary.
+ * set automatically, unless the @mi is loading. 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.
@@ -1257,7 +1669,7 @@ xcamel_message_info_take_user_flags (xCamelMessageInfo *mi,
                                     CamelNamedFlags *user_flags)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1267,9 +1679,10 @@ xcamel_message_info_take_user_flags (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->take_user_flags (mi, user_flags);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "user-flags");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1345,8 +1758,8 @@ xcamel_message_info_dup_user_tag (const xCamelMessageInfo *mi,
  * 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. There is also emitted folder's "changed" signal
- * for this @mi, if necessary.
+ * set automatically, unless the @mi is loading. There is also emitted
+ * folder's "changed" signal for this @mi, if necessary.
  *
  * Returns: Whether the @mi changed.
  *
@@ -1358,7 +1771,7 @@ xcamel_message_info_set_user_tag (xCamelMessageInfo *mi,
                                  const gchar *value)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
        g_return_val_if_fail (name != NULL, FALSE);
@@ -1369,9 +1782,10 @@ xcamel_message_info_set_user_tag (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_user_tag (mi, name, value);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "user-tags");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1383,10 +1797,38 @@ xcamel_message_info_set_user_tag (xCamelMessageInfo *mi,
 }
 
 /**
+ * xcamel_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 *
+xcamel_message_info_get_user_tags (const xCamelMessageInfo *mi)
+{
+       xCamelMessageInfoClass *klass;
+       const CamelNameValueArray *result;
+
+       g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), NULL);
+
+       klass = XCAMEL_MESSAGE_INFO_GET_CLASS (mi);
+       g_return_val_if_fail (klass != NULL, NULL);
+       g_return_val_if_fail (klass->get_user_tags != NULL, NULL);
+
+       xcamel_message_info_property_lock (mi);
+       result = klass->get_user_tags (mi);
+       xcamel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+/**
  * xcamel_message_info_dup_user_tags:
  * @mi: a #CamelMessageInfo
  *
- * Returns: (transfer full): a newly allocated #CamelNameValueArray containing all set
+ * 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
@@ -1420,8 +1862,8 @@ xcamel_message_info_dup_user_tags (const xCamelMessageInfo *mi)
  * 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. There is also emitted folder's "changed" signal
- * for this @mi, if necessary.
+ * set automatically, unless the @mi is loading. 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.
@@ -1435,7 +1877,7 @@ xcamel_message_info_take_user_tags (xCamelMessageInfo *mi,
                                    CamelNameValueArray *user_tags)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1445,9 +1887,10 @@ xcamel_message_info_take_user_tags (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->take_user_tags (mi, user_tags);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "user-tags");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1497,8 +1940,8 @@ xcamel_message_info_get_subject (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -1509,7 +1952,7 @@ xcamel_message_info_set_subject (xCamelMessageInfo *mi,
                                const gchar *subject)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1519,9 +1962,10 @@ xcamel_message_info_set_subject (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_subject (mi, subject);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "subject");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1569,8 +2013,8 @@ xcamel_message_info_get_preview (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -1581,7 +2025,7 @@ xcamel_message_info_set_preview (xCamelMessageInfo *mi,
                                const gchar *preview)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1591,9 +2035,10 @@ xcamel_message_info_set_preview (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_preview (mi, preview);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "preview");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1641,8 +2086,8 @@ xcamel_message_info_get_from (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -1653,7 +2098,7 @@ xcamel_message_info_set_from (xCamelMessageInfo *mi,
                             const gchar *from)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1663,9 +2108,10 @@ xcamel_message_info_set_from (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_from (mi, from);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "from");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1713,8 +2159,8 @@ xcamel_message_info_get_to (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -1725,7 +2171,7 @@ xcamel_message_info_set_to (xCamelMessageInfo *mi,
                           const gchar *to)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1735,9 +2181,10 @@ xcamel_message_info_set_to (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_to (mi, to);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "to");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1785,8 +2232,8 @@ xcamel_message_info_get_cc (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -1797,7 +2244,7 @@ xcamel_message_info_set_cc (xCamelMessageInfo *mi,
                           const gchar *cc)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1807,9 +2254,10 @@ xcamel_message_info_set_cc (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_cc (mi, cc);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "cc");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1857,8 +2305,8 @@ xcamel_message_info_get_mlist (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -1869,7 +2317,7 @@ xcamel_message_info_set_mlist (xCamelMessageInfo *mi,
                              const gchar *mlist)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1879,9 +2327,10 @@ xcamel_message_info_set_mlist (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_mlist (mi, mlist);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "mlist");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -1929,8 +2378,8 @@ xcamel_message_info_get_size (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -1941,7 +2390,7 @@ xcamel_message_info_set_size (xCamelMessageInfo *mi,
                             guint32 size)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -1951,9 +2400,10 @@ xcamel_message_info_set_size (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_size (mi, size);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "size");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -2001,8 +2451,8 @@ xcamel_message_info_get_date_sent (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -2013,7 +2463,7 @@ xcamel_message_info_set_date_sent (xCamelMessageInfo *mi,
                                  gint64 date_sent)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -2023,9 +2473,10 @@ xcamel_message_info_set_date_sent (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_date_sent (mi, date_sent);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "date-sent");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -2073,8 +2524,8 @@ xcamel_message_info_get_date_received (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -2085,7 +2536,7 @@ xcamel_message_info_set_date_received (xCamelMessageInfo *mi,
                                      gint64 date_received)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -2095,9 +2546,10 @@ xcamel_message_info_set_date_received (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_date_received (mi, date_received);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "date-received");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -2149,8 +2601,8 @@ xcamel_message_info_get_message_id (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. There is not emitted
+ * folder's "changed" signal for this @mi.
  *
  * Returns: Whether the value changed.
  *
@@ -2161,7 +2613,7 @@ xcamel_message_info_set_message_id (xCamelMessageInfo *mi,
                                   guint64 message_id)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -2171,9 +2623,10 @@ xcamel_message_info_set_message_id (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->set_message_id (mi, message_id);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "message-id");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -2267,8 +2720,8 @@ xcamel_message_info_dup_references (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. 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.
@@ -2282,7 +2735,7 @@ xcamel_message_info_take_references (xCamelMessageInfo *mi,
                                    GArray *references)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -2292,9 +2745,10 @@ xcamel_message_info_take_references (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->take_references (mi, references);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "references");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -2375,8 +2829,8 @@ xcamel_message_info_dup_headers (const xCamelMessageInfo *mi)
  * change in the associated message.
  *
  * If the @mi changed, the 'dirty' flag and the 'folder-flagged' flag are
- * set automatically. There is not emitted folder's "changed" signal
- * for this @mi.
+ * set automatically, unless the @mi is loading. 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.
@@ -2390,7 +2844,7 @@ xcamel_message_info_take_headers (xCamelMessageInfo *mi,
                                 CamelNameValueArray *headers)
 {
        xCamelMessageInfoClass *klass;
-       gboolean changed;
+       gboolean changed, loading;
 
        g_return_val_if_fail (XCAMEL_IS_MESSAGE_INFO (mi), FALSE);
 
@@ -2400,9 +2854,10 @@ xcamel_message_info_take_headers (xCamelMessageInfo *mi,
 
        xcamel_message_info_property_lock (mi);
        changed = klass->take_headers (mi, headers);
+       loading = mi->priv->loading;
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !loading) {
                g_object_notify (G_OBJECT (mi), "headers");
                xcamel_message_info_set_dirty (mi, TRUE);
                xcamel_message_info_set_folder_flagged (mi, TRUE);
@@ -2410,3 +2865,151 @@ xcamel_message_info_take_headers (xCamelMessageInfo *mi,
 
        return changed;
 }
+
+/**
+ * camel_message_info_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_message_info_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_message_info_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_message_info_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_message_info_util_bdata_get_number().
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_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_message_info_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_message_info_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_message_info_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_message_info_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_message_info_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_message_info_util_bdata_get_string().
+ *
+ * The strings are encoded as "length-value", quotes for clarity only.
+ *
+ * Since: 3.24
+ **/
+void
+camel_message_info_util_bdata_put_string (GString *bdata_str,
+                                         const gchar *value)
+{
+       g_return_if_fail (bdata_str != NULL);
+       g_return_if_fail (value != NULL);
+
+       camel_message_info_util_bdata_put_number (bdata_str, strlen (value));
+
+       g_string_append_printf (bdata_str, "-%s", value);
+}
diff --git a/camel/camel-message-info.h b/camel/camel-message-info.h
index 6c4b163..ef73a6f 100644
--- a/camel/camel-message-info.h
+++ b/camel/camel-message-info.h
@@ -49,6 +49,7 @@ G_BEGIN_DECLS
 
 /* Forward declarations */
 struct _CamelFolderSummary;
+struct _CamelMIRecord;
 
 /* A summary messageid is a 64 bit identifier (partial md5 hash) */
 typedef struct _CamelSummaryMessageID {
@@ -106,9 +107,15 @@ struct _xCamelMessageInfoClass {
 
        xCamelMessageInfo *     (* clone)       (const xCamelMessageInfo *mi,
                                                 struct _CamelFolderSummary *assign_summary);
+       gboolean                (* load)        (xCamelMessageInfo *mi,
+                                                const struct _CamelMIRecord *record,
+                                                /* const */ gchar **bdata_ptr);
+       gboolean                (* save)        (const xCamelMessageInfo *mi,
+                                                struct _CamelMIRecord *record,
+                                                GString *bdata_str);
        guint32                 (* get_flags)   (const xCamelMessageInfo *mi);
        gboolean                (* set_flags)   (xCamelMessageInfo *mi,
-                                                CamelMessageFlags flags,
+                                                CamelMessageFlags mask,
                                                 guint32 set);
        gboolean                (* get_user_flag)
                                                (const xCamelMessageInfo *mi,
@@ -117,6 +124,8 @@ struct _xCamelMessageInfoClass {
                                                (xCamelMessageInfo *mi,
                                                 const gchar *name,
                                                 gboolean state);
+       const CamelNamedFlags * (* get_user_flags)
+                                               (const xCamelMessageInfo *mi);
        CamelNamedFlags *       (* dup_user_flags)
                                                (const xCamelMessageInfo *mi);
        gboolean                (* take_user_flags)
@@ -127,6 +136,9 @@ struct _xCamelMessageInfoClass {
        gboolean                (* set_user_tag)(xCamelMessageInfo *mi,
                                                 const gchar *name,
                                                 const gchar *value);
+       const CamelNameValueArray *
+                               (* get_user_tags)
+                                               (const xCamelMessageInfo *mi);
        CamelNameValueArray *   (* dup_user_tags)
                                                (const xCamelMessageInfo *mi);
        gboolean                (* take_user_tags)
@@ -188,6 +200,12 @@ xCamelMessageInfo *
 xCamelMessageInfo *
                xcamel_message_info_clone       (const xCamelMessageInfo *mi,
                                                 struct _CamelFolderSummary *assign_summary);
+gboolean       camel_message_info_load         (xCamelMessageInfo *mi,
+                                                const struct _CamelMIRecord *record,
+                                                /* const */ gchar **bdata_ptr);
+gboolean       camel_message_info_save         (const xCamelMessageInfo *mi,
+                                                struct _CamelMIRecord *record,
+                                                GString *bdata_str);
 struct _CamelFolderSummary *
                xcamel_message_info_ref_summary (const xCamelMessageInfo *mi);
 void           xcamel_message_info_property_lock
@@ -202,6 +220,9 @@ gboolean    xcamel_message_info_get_folder_flagged
 gboolean       xcamel_message_info_set_folder_flagged
                                                (xCamelMessageInfo *mi,
                                                 gboolean folder_flagged);
+gboolean       xcamel_message_info_get_loading (const xCamelMessageInfo *mi);
+void           xcamel_message_info_set_loading (const xCamelMessageInfo *mi,
+                                                gboolean loading);
 const gchar *  xcamel_message_info_get_uid     (const xCamelMessageInfo *mi);
 const gchar *  xcamel_message_info_pooldup_uid (const xCamelMessageInfo *mi);
 gboolean       xcamel_message_info_set_uid     (xCamelMessageInfo *mi,
@@ -217,6 +238,9 @@ gboolean    xcamel_message_info_set_user_flag
                                                (xCamelMessageInfo *mi,
                                                 const gchar *name,
                                                 gboolean state);
+const CamelNamedFlags *
+               xcamel_message_info_get_user_flags
+                                               (const xCamelMessageInfo *mi);
 CamelNamedFlags *
                xcamel_message_info_dup_user_flags
                                                (const xCamelMessageInfo *mi);
@@ -231,6 +255,9 @@ gchar *             xcamel_message_info_dup_user_tag        (const xCamelMessageInfo *mi,
 gboolean       xcamel_message_info_set_user_tag        (xCamelMessageInfo *mi,
                                                 const gchar *name,
                                                 const gchar *value);
+const CamelNameValueArray *
+               xcamel_message_info_get_user_tags
+                                               (const xCamelMessageInfo *mi);
 CamelNameValueArray *
                xcamel_message_info_dup_user_tags
                                                (const xCamelMessageInfo *mi);
@@ -287,6 +314,19 @@ CamelNameValueArray *
 gboolean       xcamel_message_info_take_headers        (xCamelMessageInfo *mi,
                                                CamelNameValueArray *headers);
 
+/* Utility functions */
+gint64         camel_message_info_util_bdata_get_number
+                                               (/* const */ gchar **bdata_ptr,
+                                                gint64 default_value);
+void           camel_message_info_util_bdata_put_number
+                                               (GString *bdata_str,
+                                                gint64 value);
+gchar *                camel_message_info_util_bdata_get_string
+                                               (/* const */ gchar **bdata_ptr,
+                                                const gchar *default_value);
+void           camel_message_info_util_bdata_put_string
+                                               (GString *bdata_str,
+                                                const gchar *value);
 G_END_DECLS
 
 #endif /* XCAMEL_MESSAGE_INFO_H */
diff --git a/camel/camel-vee-message-info.c b/camel/camel-vee-message-info.c
index 8c52b94..d604416 100644
--- a/camel/camel-vee-message-info.c
+++ b/camel/camel-vee-message-info.c
@@ -125,6 +125,12 @@ vee_message_info_set_user_flag (xCamelMessageInfo *mi,
        vee_call_from_parent_mi (FALSE, gboolean, xcamel_message_info_set_user_flag, (orig_mi, name, state));
 }
 
+static const CamelNamedFlags *
+vee_message_info_get_user_flags (const xCamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const CamelNamedFlags *, xcamel_message_info_get_user_flags, 
(orig_mi));
+}
+
 static CamelNamedFlags *
 vee_message_info_dup_user_flags (const xCamelMessageInfo *mi)
 {
@@ -159,6 +165,12 @@ vee_message_info_dup_user_tags (const xCamelMessageInfo *mi)
        vee_call_from_parent_mi (NULL, CamelNameValueArray *, xcamel_message_info_dup_user_tags, (orig_mi));
 }
 
+static const CamelNameValueArray *
+vee_message_info_get_user_tags (const xCamelMessageInfo *mi)
+{
+       vee_call_from_parent_mi (NULL, const CamelNameValueArray *, xcamel_message_info_get_user_tags, 
(orig_mi));
+}
+
 static gboolean
 vee_message_info_take_user_tags (xCamelMessageInfo *mi,
                                 CamelNameValueArray *user_tags)
@@ -349,10 +361,12 @@ xcamel_vee_message_info_class_init (xCamelVeeMessageInfoClass *class)
        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;
diff --git a/camel/providers/imapx/camel-imapx-message-info.c 
b/camel/providers/imapx/camel-imapx-message-info.c
index c000f14..609b83f 100644
--- a/camel/providers/imapx/camel-imapx-message-info.c
+++ b/camel/providers/imapx/camel-imapx-message-info.c
@@ -67,6 +67,31 @@ imapx_message_info_clone (const xCamelMessageInfo *mi,
        return result;
 }
 
+static gboolean
+imapx_message_info_load (xCamelMessageInfo *mi,
+                        const CamelMIRecord *record,
+                        /* const */ gchar **bdata_ptr)
+{
+       xCamelIMAPXMessageInfo *imi;
+
+       g_return_val_if_fail (XCAMEL_IS_IMAPX_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       if (!XCAMEL_MESSAGE_INFO_CLASS (xcamel_imapx_message_info_parent_class)->load ||
+           !XCAMEL_MESSAGE_INFO_CLASS (xcamel_imapx_message_info_parent_class)->load (mi, record, bdata_ptr))
+               return FALSE;
+
+       imi = XCAMEL_IMAPX_MESSAGE_INFO (mi);
+
+       /* Reset server-side information, which is not saved into the summary anyway. */
+       xcamel_imapx_message_info_set_server_flags (imi, 0);
+       xcamel_imapx_message_info_take_server_user_flags (imi, NULL);
+       xcamel_imapx_message_info_take_server_user_tags (imi, NULL);
+
+       return TRUE;
+}
+
 static void
 imapx_message_info_set_property (GObject *object,
                                 guint property_id,
@@ -142,6 +167,7 @@ xcamel_imapx_message_info_class_init (xCamelIMAPXMessageInfoClass *class)
 
        mi_class = XCAMEL_MESSAGE_INFO_CLASS (class);
        mi_class->clone = imapx_message_info_clone;
+       mi_class->load = imapx_message_info_load;
 
        object_class = G_OBJECT_CLASS (class);
        object_class->set_property = imapx_message_info_set_property;
@@ -244,7 +270,7 @@ xcamel_imapx_message_info_set_server_flags (xCamelIMAPXMessageInfo *imi,
 
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !xcamel_message_info_get_loading (mi)) {
                g_object_notify (G_OBJECT (imi), "server-flags");
                xcamel_message_info_set_dirty (mi, TRUE);
        }
@@ -310,7 +336,7 @@ xcamel_imapx_message_info_take_server_user_flags (xCamelIMAPXMessageInfo *imi,
 
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !xcamel_message_info_get_loading (mi)) {
                g_object_notify (G_OBJECT (imi), "server-user-flags");
                xcamel_message_info_set_dirty (mi, TRUE);
        }
@@ -376,7 +402,7 @@ xcamel_imapx_message_info_take_server_user_tags (xCamelIMAPXMessageInfo *imi,
 
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !xcamel_message_info_get_loading (mi)) {
                g_object_notify (G_OBJECT (imi), "server-user-tags");
                xcamel_message_info_set_dirty (mi, TRUE);
        }
diff --git a/camel/providers/local/camel-maildir-message-info.c 
b/camel/providers/local/camel-maildir-message-info.c
index d833f41..84badca 100644
--- a/camel/providers/local/camel-maildir-message-info.c
+++ b/camel/providers/local/camel-maildir-message-info.c
@@ -66,6 +66,28 @@ maildir_message_info_clone (const xCamelMessageInfo *mi,
        return result;
 }
 
+static gboolean
+maildir_message_info_load (xCamelMessageInfo *mi,
+                          const CamelMIRecord *record,
+                          /* const */ gchar **bdata_ptr)
+{
+       xCamelMaildirMessageInfo *mmi;
+
+       g_return_val_if_fail (XCAMEL_IS_MAILDIR_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       if (!XCAMEL_MESSAGE_INFO_CLASS (xcamel_maildir_message_info_parent_class)->load ||
+           !XCAMEL_MESSAGE_INFO_CLASS (xcamel_maildir_message_info_parent_class)->load (mi, record, 
bdata_ptr))
+               return FALSE;
+
+       mmi = XCAMEL_MAILDIR_MESSAGE_INFO (mi);
+
+       xcamel_maildir_message_info_take_filename (mmi, camel_maildir_summary_info_to_name (mmi));
+
+       return TRUE;
+}
+
 static void
 maildir_message_info_set_property (GObject *object,
                                 guint property_id,
@@ -122,6 +144,7 @@ xcamel_maildir_message_info_class_init (xCamelMaildirMessageInfoClass *class)
 
        mi_class = XCAMEL_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;
@@ -190,6 +213,15 @@ gboolean
 xcamel_maildir_message_info_set_filename (xCamelMaildirMessageInfo *mmi,
                                          const gchar *filename)
 {
+       g_return_val_if_fail (XCAMEL_IS_MAILDIR_MESSAGE_INFO (mmi), FALSE);
+
+       return xcamel_maildir_message_info_take_filename (mmi, g_strdup (filename));
+}
+
+gboolean
+xcamel_maildir_message_info_take_filename (xCamelMaildirMessageInfo *mmi,
+                                         gchar *filename)
+{
        xCamelMessageInfo *mi;
        gboolean changed;
 
@@ -203,12 +235,14 @@ xcamel_maildir_message_info_set_filename (xCamelMaildirMessageInfo *mmi,
 
        if (changed) {
                g_free (mmi->priv->filename);
-               mmi->priv->filename = g_strdup (filename);
+               mmi->priv->filename = filename;
+       } else if (filename != mmi->priv->filename) {
+               g_free (filename);
        }
 
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !xcamel_message_info_get_loading (mi)) {
                g_object_notify (G_OBJECT (mmi), "filename");
                xcamel_message_info_set_dirty (mi, TRUE);
        }
diff --git a/camel/providers/local/camel-maildir-message-info.h 
b/camel/providers/local/camel-maildir-message-info.h
index efba5b0..bd1840a 100644
--- a/camel/providers/local/camel-maildir-message-info.h
+++ b/camel/providers/local/camel-maildir-message-info.h
@@ -65,6 +65,9 @@ gchar *               xcamel_maildir_message_info_dup_filename
 gboolean       xcamel_maildir_message_info_set_filename
                                                        (xCamelMaildirMessageInfo *mmi,
                                                         const gchar *filename);
+gboolean       xcamel_maildir_message_info_take_filename
+                                                       (xCamelMaildirMessageInfo *mmi,
+                                                        gchar *filename);
 
 G_END_DECLS
 
diff --git a/camel/providers/local/camel-mbox-message-info.c b/camel/providers/local/camel-mbox-message-info.c
index be330b9..38ed6a0 100644
--- a/camel/providers/local/camel-mbox-message-info.c
+++ b/camel/providers/local/camel-mbox-message-info.c
@@ -61,11 +61,60 @@ mbox_message_info_clone (const xCamelMessageInfo *mi,
        return result;
 }
 
+static gboolean
+mbox_message_info_load (xCamelMessageInfo *mi,
+                       const CamelMIRecord *record,
+                       /* const */ gchar **bdata_ptr)
+{
+       xCamelMboxMessageInfo *mmi;
+       gint64 offset;
+
+       g_return_val_if_fail (XCAMEL_IS_MBOX_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_ptr != NULL, FALSE);
+
+       if (!XCAMEL_MESSAGE_INFO_CLASS (xcamel_mbox_message_info_parent_class)->load ||
+           !XCAMEL_MESSAGE_INFO_CLASS (xcamel_mbox_message_info_parent_class)->load (mi, record, bdata_ptr))
+               return FALSE;
+
+       mmi = XCAMEL_MBOX_MESSAGE_INFO (mi);
+
+       offset = camel_message_info_util_bdata_get_number (bdata_ptr, -1);
+       if (offset < 0)
+               return FALSE;
+
+       xcamel_mbox_message_info_set_offset (mmi, offset);
+
+       return TRUE;
+}
+
+static gboolean
+mbox_message_info_save (const xCamelMessageInfo *mi,
+                       CamelMIRecord *record,
+                       GString *bdata_str)
+{
+       xCamelMboxMessageInfo *mmi;
+
+       g_return_val_if_fail (XCAMEL_IS_MBOX_MESSAGE_INFO (mi), FALSE);
+       g_return_val_if_fail (record != NULL, FALSE);
+       g_return_val_if_fail (bdata_str != NULL, FALSE);
+
+       if (!XCAMEL_MESSAGE_INFO_CLASS (xcamel_mbox_message_info_parent_class)->save ||
+           !XCAMEL_MESSAGE_INFO_CLASS (xcamel_mbox_message_info_parent_class)->save (mi, record, bdata_str))
+               return FALSE;
+
+       mmi = XCAMEL_MBOX_MESSAGE_INFO (mi);
+
+       camel_message_info_util_bdata_put_number (bdata_str, xcamel_mbox_message_info_get_offset (mmi));
+
+       return TRUE;
+}
+
 static void
 mbox_message_info_set_property (GObject *object,
-                                guint property_id,
-                                const GValue *value,
-                                GParamSpec *pspec)
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
 {
        xCamelMboxMessageInfo *mmi = XCAMEL_MBOX_MESSAGE_INFO (object);
 
@@ -80,9 +129,9 @@ mbox_message_info_set_property (GObject *object,
 
 static void
 mbox_message_info_get_property (GObject *object,
-                                guint property_id,
-                                GValue *value,
-                                GParamSpec *pspec)
+                               guint property_id,
+                               GValue *value,
+                               GParamSpec *pspec)
 {
        xCamelMboxMessageInfo *mmi = XCAMEL_MBOX_MESSAGE_INFO (object);
 
@@ -105,6 +154,8 @@ xcamel_mbox_message_info_class_init (xCamelMboxMessageInfoClass *class)
 
        mi_class = XCAMEL_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;
 
        object_class = G_OBJECT_CLASS (class);
        object_class->set_property = mbox_message_info_set_property;
@@ -153,7 +204,7 @@ xcamel_mbox_message_info_get_offset (const xCamelMboxMessageInfo *mmi)
 
 gboolean
 xcamel_mbox_message_info_set_offset (xCamelMboxMessageInfo *mmi,
-                                    goffset offset)
+                                   goffset offset)
 {
        xCamelMessageInfo *mi;
        gboolean changed;
@@ -171,7 +222,7 @@ xcamel_mbox_message_info_set_offset (xCamelMboxMessageInfo *mmi,
 
        xcamel_message_info_property_unlock (mi);
 
-       if (changed) {
+       if (changed && !xcamel_message_info_get_loading (mi)) {
                g_object_notify (G_OBJECT (mmi), "offset");
                xcamel_message_info_set_dirty (mi, TRUE);
        }


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