[evolution-ews/wip/mcrha/office365: 20/50] Add few more Camel stubs (copied from EWS and adapted)




commit d521dfe3dc51c5fadbd5fff7aa56a9172a661e5f
Author: Milan Crha <mcrha redhat com>
Date:   Thu Jun 18 16:13:00 2020 +0200

    Add few more Camel stubs (copied from EWS and adapted)

 src/Office365/camel/CMakeLists.txt              |   6 +
 src/Office365/camel/camel-o365-folder-summary.c | 317 +++++++++++++
 src/Office365/camel/camel-o365-folder-summary.h |  83 ++++
 src/Office365/camel/camel-o365-folder.c         | 571 ++++++++++++++++++++++++
 src/Office365/camel/camel-o365-folder.h         |  70 +++
 src/Office365/camel/camel-o365-message-info.c   | 420 +++++++++++++++++
 src/Office365/camel/camel-o365-message-info.h   |  81 ++++
 src/Office365/camel/camel-o365-store-summary.c  | 121 +++++
 src/Office365/camel/camel-o365-store-summary.h  |  12 +
 src/Office365/camel/camel-o365-store.c          | 178 +++++---
 src/Office365/camel/camel-o365-store.h          |  12 +
 11 files changed, 1800 insertions(+), 71 deletions(-)
---
diff --git a/src/Office365/camel/CMakeLists.txt b/src/Office365/camel/CMakeLists.txt
index 64167043..acdd56ec 100644
--- a/src/Office365/camel/CMakeLists.txt
+++ b/src/Office365/camel/CMakeLists.txt
@@ -7,6 +7,12 @@ set(DEPENDENCIES
 )
 
 set(SOURCES
+       camel-o365-folder.c
+       camel-o365-folder.h
+       camel-o365-folder-summary.c
+       camel-o365-folder-summary.h
+       camel-o365-message-info.c
+       camel-o365-message-info.h
        camel-o365-provider.c
        camel-o365-store.c
        camel-o365-store.h
diff --git a/src/Office365/camel/camel-o365-folder-summary.c b/src/Office365/camel/camel-o365-folder-summary.c
new file mode 100644
index 00000000..fe5f5fc3
--- /dev/null
+++ b/src/Office365/camel/camel-o365-folder-summary.c
@@ -0,0 +1,317 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-ews-config.h"
+
+#include <glib.h>
+
+#include "camel-o365-folder.h"
+
+#include "camel-o365-folder-summary.h"
+
+#define LOCK(_summary) g_mutex_lock (&_summary->priv->property_lock)
+#define UNLOCK(_summary) g_mutex_unlock (&_summary->priv->property_lock)
+
+struct _CamelO365FolderSummaryPrivate {
+       GMutex property_lock;
+       gchar *delta_link;
+       gint32 version;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (CamelO365FolderSummary, camel_o365_folder_summary, CAMEL_TYPE_FOLDER_SUMMARY)
+
+static gboolean
+o365_folder_summary_header_load (CamelFolderSummary *summary,
+                                CamelFIRecord *mir)
+{
+       CamelO365FolderSummary *o365_summary = CAMEL_O365_FOLDER_SUMMARY (summary);
+       const gchar *delta_link = NULL;
+       gchar *part;
+
+       if (!CAMEL_FOLDER_SUMMARY_CLASS (camel_o365_folder_summary_parent_class)->summary_header_load 
(summary, mir))
+               return FALSE;
+
+       o365_summary->priv->version = 0;
+
+       part = mir->bdata;
+
+       if (part)
+               o365_summary->priv->version = camel_util_bdata_get_number (&part, 0);
+
+       if (part && *part && part[1])
+               delta_link = part + 1;
+
+       /* Do not call camel_o365_folder_summary_set_sync_state() here,
+          to not mark the summary dirty after load. */
+       LOCK (o365_summary);
+
+       if (g_strcmp0 (o365_summary->priv->delta_link, delta_link) != 0) {
+               g_free (o365_summary->priv->delta_link);
+               o365_summary->priv->delta_link = g_strdup (delta_link);
+       }
+
+       UNLOCK (o365_summary);
+
+       return TRUE;
+}
+
+static CamelFIRecord *
+o365_folder_summary_header_save (CamelFolderSummary *summary,
+                                GError **error)
+{
+       CamelO365FolderSummary *o365_summary = CAMEL_O365_FOLDER_SUMMARY (summary);
+       CamelFIRecord *fir;
+       gchar *delta_link;
+
+       fir = CAMEL_FOLDER_SUMMARY_CLASS (camel_o365_folder_summary_parent_class)->summary_header_save 
(summary, error);
+
+       if (!fir)
+               return NULL;
+
+       delta_link = camel_o365_folder_summary_dup_delta_link (o365_summary);
+
+       fir->bdata = g_strdup_printf ("%d %s", CAMEL_O365_FOLDER_SUMMARY_VERSION, delta_link ? delta_link : 
"");
+
+       g_free (delta_link);
+
+       LOCK (o365_summary);
+
+       o365_summary->priv->version = CAMEL_O365_FOLDER_SUMMARY_VERSION;
+
+       UNLOCK (o365_summary);
+
+       return fir;
+}
+
+static void
+o365_folder_summary_finalize (GObject *object)
+{
+       CamelO365FolderSummary *o365_summary = CAMEL_O365_FOLDER_SUMMARY (object);
+
+       g_free (o365_summary->priv->delta_link);
+       g_mutex_clear (&o365_summary->priv->property_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_o365_folder_summary_parent_class)->finalize (object);
+}
+
+static void
+camel_o365_folder_summary_class_init (CamelO365FolderSummaryClass *class)
+{
+       CamelFolderSummaryClass *folder_summary_class;
+       GObjectClass *object_class;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->finalize = o365_folder_summary_finalize;
+
+       folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
+       folder_summary_class->message_info_type = CAMEL_TYPE_O365_MESSAGE_INFO;
+       folder_summary_class->summary_header_save = o365_folder_summary_header_save;
+       folder_summary_class->summary_header_load = o365_folder_summary_header_load;
+}
+
+static void
+camel_o365_folder_summary_init (CamelO365FolderSummary *o365_summary)
+{
+       o365_summary->priv = camel_o365_folder_summary_get_instance_private (o365_summary);
+
+       g_mutex_init (&o365_summary->priv->property_lock);
+}
+
+CamelFolderSummary *
+camel_o365_folder_summary_new (struct _CamelFolder *folder)
+{
+       CamelFolderSummary *summary;
+
+       summary = g_object_new (CAMEL_TYPE_O365_FOLDER_SUMMARY, "folder", folder, NULL);
+
+       camel_folder_summary_load (summary, NULL);
+
+       return summary;
+}
+
+gint
+camel_o365_folder_summary_get_version (CamelO365FolderSummary *o365_summary)
+{
+       gint version;
+
+       g_return_val_if_fail (CAMEL_IS_O365_FOLDER_SUMMARY (o365_summary), -1);
+
+       LOCK (o365_summary);
+
+       version = o365_summary->priv->version;
+
+       UNLOCK (o365_summary);
+
+       return version;
+}
+
+void
+camel_o365_folder_summary_set_delta_link (CamelO365FolderSummary *o365_summary,
+                                         const gchar *delta_link)
+{
+       gboolean changed = FALSE;
+
+       g_return_if_fail (CAMEL_IS_O365_FOLDER_SUMMARY (o365_summary));
+
+       LOCK (o365_summary);
+
+       if (g_strcmp0 (o365_summary->priv->delta_link, delta_link) != 0) {
+               gchar *dup = g_strdup (delta_link);
+
+               g_free (o365_summary->priv->delta_link);
+               o365_summary->priv->delta_link = dup;
+
+               changed = TRUE;
+       }
+
+       UNLOCK (o365_summary);
+
+       if (changed)
+               camel_folder_summary_touch (CAMEL_FOLDER_SUMMARY (o365_summary));
+}
+
+gchar *
+camel_o365_folder_summary_dup_delta_link (CamelO365FolderSummary *o365_summary)
+{
+       gchar *delta_link;
+
+       g_return_val_if_fail (CAMEL_IS_O365_FOLDER_SUMMARY (o365_summary), NULL);
+
+       LOCK (o365_summary);
+
+       delta_link = g_strdup (o365_summary->priv->delta_link);
+
+       UNLOCK (o365_summary);
+
+       return delta_link;
+}
+
+void
+camel_o365_folder_summary_clear (CamelFolderSummary *summary)
+{
+       CamelFolderChangeInfo *changes;
+       GPtrArray *known_uids;
+       gint i;
+
+       changes = camel_folder_change_info_new ();
+       known_uids = camel_folder_summary_get_array (summary);
+
+       for (i = 0; i < known_uids->len; i++) {
+               const gchar *uid = g_ptr_array_index (known_uids, i);
+
+               if (!uid)
+                       continue;
+
+               camel_folder_change_info_remove_uid (changes, uid);
+       }
+
+       camel_folder_summary_clear (summary, NULL);
+
+       if (camel_folder_change_info_changed (changes))
+               camel_folder_changed (camel_folder_summary_get_folder (summary), changes);
+       camel_folder_change_info_free (changes);
+       camel_folder_summary_free_array (known_uids);
+}
+
+static gboolean
+o365_folder_summary_update_user_flags (CamelMessageInfo *info,
+                                      const CamelNamedFlags *server_user_flags)
+{
+       gboolean changed = FALSE;
+       gboolean set_cal = FALSE, set_note = FALSE;
+
+       if (camel_message_info_get_user_flag (info, "$has_cal"))
+               set_cal = TRUE;
+       if (camel_message_info_get_user_flag (info, "$has_note"))
+               set_note = TRUE;
+
+       changed = camel_message_info_take_user_flags (info, camel_named_flags_copy (server_user_flags));
+
+       /* reset the flags as they were set in messageinfo before */
+       if (set_cal)
+               camel_message_info_set_user_flag (info, "$has_cal", TRUE);
+       if (set_note)
+               camel_message_info_set_user_flag (info, "$has_note", TRUE);
+
+       return changed;
+}
+
+gboolean
+camel_o365_folder_summary_update_message_info_flags (CamelFolderSummary *summary,
+                                                    CamelMessageInfo *info,
+                                                    guint32 server_flags,
+                                                    const CamelNamedFlags *server_user_flags)
+{
+       CamelO365MessageInfo *omi;
+       gboolean changed = FALSE;
+
+       g_return_val_if_fail (CAMEL_IS_O365_FOLDER_SUMMARY (summary), FALSE);
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (info), FALSE);
+
+       omi = CAMEL_O365_MESSAGE_INFO (info);
+
+       if (server_flags != camel_o365_message_info_get_server_flags (omi)) {
+               guint32 server_set, server_cleared;
+
+               server_set = server_flags & ~camel_o365_message_info_get_server_flags (omi);
+               server_cleared = camel_o365_message_info_get_server_flags (omi) & ~server_flags;
+
+               camel_message_info_set_flags (info, server_set | server_cleared, 
(camel_message_info_get_flags (info) | server_set) & ~server_cleared);
+               camel_o365_message_info_set_server_flags (omi, server_flags);
+               changed = TRUE;
+       }
+
+       if (server_user_flags && o365_folder_summary_update_user_flags (info, server_user_flags))
+               changed = TRUE;
+
+       return changed;
+}
+
+gboolean
+camel_o365_folder_summary_add_message (CamelFolderSummary *summary,
+                                      const gchar *uid,
+                                      const gchar *change_key,
+                                      CamelMessageInfo *info,
+                                      CamelMimeMessage *message)
+{
+       CamelMessageInfo *mi;
+
+       g_return_val_if_fail (uid != NULL, FALSE);
+       g_return_val_if_fail (info != NULL, FALSE);
+       g_return_val_if_fail (message != NULL, FALSE);
+
+       mi = camel_folder_summary_info_new_from_message (summary, message);
+       g_return_val_if_fail (mi != NULL, FALSE);
+
+       camel_message_info_set_abort_notifications (mi, TRUE);
+
+       camel_o365_message_info_set_change_key (CAMEL_O365_MESSAGE_INFO (mi), change_key);
+       camel_message_info_set_flags (mi, ~0, camel_message_info_get_flags (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_size (mi, camel_message_info_get_size (info));
+       camel_message_info_set_uid (mi, uid);
+
+       camel_message_info_set_abort_notifications (mi, FALSE);
+
+       camel_folder_summary_add (summary, mi, FALSE);
+
+       g_object_unref (mi);
+
+       return TRUE;
+}
diff --git a/src/Office365/camel/camel-o365-folder-summary.h b/src/Office365/camel/camel-o365-folder-summary.h
new file mode 100644
index 00000000..a8c79b59
--- /dev/null
+++ b/src/Office365/camel/camel-o365-folder-summary.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CAMEL_O365_FOLDER_SUMMARY_H
+#define CAMEL_O365_FOLDER_SUMMARY_H
+
+#include <camel/camel.h>
+
+#include "camel-o365-message-info.h"
+
+#define CAMEL_O365_FOLDER_SUMMARY_VERSION (1)
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_O365_FOLDER_SUMMARY \
+       (camel_o365_folder_summary_get_type ())
+#define CAMEL_O365_FOLDER_SUMMARY(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_O365_FOLDER_SUMMARY, CamelO365FolderSummary))
+#define CAMEL_O365_FOLDER_SUMMARY_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_O365_FOLDER_SUMMARY, CamelO365FolderSummaryClass))
+#define CAMEL_IS_O365_FOLDER_SUMMARY(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_O365_FOLDER_SUMMARY))
+#define CAMEL_IS_O365_FOLDER_SUMMARY_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_O365_FOLDER_SUMMARY))
+#define CAMEL_O365_FOLDER_SUMMARY_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_O365_FOLDER_SUMMARY, CamelO365FolderSummaryClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelO365FolderSummary CamelO365FolderSummary;
+typedef struct _CamelO365FolderSummaryClass CamelO365FolderSummaryClass;
+typedef struct _CamelO365FolderSummaryPrivate CamelO365FolderSummaryPrivate;
+
+struct _CamelO365FolderSummary {
+       CamelFolderSummary parent;
+       CamelO365FolderSummaryPrivate *priv;
+};
+
+struct _CamelO365FolderSummaryClass {
+       CamelFolderSummaryClass parent_class;
+};
+
+GType          camel_o365_folder_summary_get_type      (void);
+
+CamelFolderSummary *
+               camel_o365_folder_summary_new           (CamelFolder *folder);
+gint           camel_o365_folder_summary_get_version   (CamelO365FolderSummary *o365_summary);
+void           camel_o365_folder_summary_set_delta_link(CamelO365FolderSummary *o365_summary,
+                                                        const gchar *delta_link);
+gchar *                camel_o365_folder_summary_dup_delta_link(CamelO365FolderSummary *o365_summary);
+void           camel_o365_folder_summary_clear         (CamelFolderSummary *summary);
+gboolean       camel_o365_folder_summary_update_message_info_flags
+                                                       (CamelFolderSummary *summary,
+                                                        CamelMessageInfo *info,
+                                                        guint32 server_flags,
+                                                        const CamelNamedFlags *server_user_flags);
+gboolean       camel_o365_folder_summary_add_message   (CamelFolderSummary *summary,
+                                                        const gchar *uid,
+                                                        const gchar *change_key,
+                                                        CamelMessageInfo *info,
+                                                        CamelMimeMessage *message);
+
+G_END_DECLS
+
+#endif /* CAMEL_O365_FOLDER_SUMMARY_H */
diff --git a/src/Office365/camel/camel-o365-folder.c b/src/Office365/camel/camel-o365-folder.c
new file mode 100644
index 00000000..7d4f9e42
--- /dev/null
+++ b/src/Office365/camel/camel-o365-folder.c
@@ -0,0 +1,571 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-ews-config.h"
+
+#include <string.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "common/camel-o365-settings.h"
+#include "common/e-o365-connection.h"
+
+#include "camel-o365-folder-summary.h"
+#include "camel-o365-store.h"
+#include "camel-o365-store-summary.h"
+
+#include "camel-o365-folder.h"
+
+#define O365_LOCAL_CACHE_PATH "cur"
+
+#define LOCK_CACHE(_folder) g_rec_mutex_lock (&_folder->priv->cache_lock)
+#define UNLOCK_CACHE(_folder) g_rec_mutex_unlock (&_folder->priv->cache_lock)
+
+#define LOCK_SEARCH(_folder) g_mutex_lock (&_folder->priv->search_lock)
+#define UNLOCK_SEARCH(_folder) g_mutex_unlock (&_folder->priv->search_lock)
+
+struct _CamelO365FolderPrivate {
+       GRecMutex cache_lock;
+       CamelDataCache *cache;
+
+       GMutex search_lock;
+       CamelFolderSearch *search;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (CamelO365Folder, camel_o365_folder, CAMEL_TYPE_OFFLINE_FOLDER)
+
+static GChecksum *
+o365_folder_cache_new_checksum (const gchar *id)
+{
+       GChecksum *checksum;
+
+       g_return_val_if_fail (id != NULL, NULL);
+
+       /* No need to use SHA here, the string is short, will not collide with the others */
+       checksum = g_checksum_new (G_CHECKSUM_MD5);
+
+       g_checksum_update (checksum, (const guchar *) id, strlen (id));
+
+       return checksum;
+}
+
+static CamelStream *
+o365_folder_cache_add (CamelO365Folder *o365_folder,
+                      const gchar *id,
+                      GError **error)
+{
+       GIOStream *base_stream;
+       CamelStream *stream = NULL;
+       GChecksum *checksum;
+
+       checksum = o365_folder_cache_new_checksum (id);
+
+       LOCK_CACHE (o365_folder);
+       base_stream = camel_data_cache_add (o365_folder->priv->cache, O365_LOCAL_CACHE_PATH, 
g_checksum_get_string (checksum), error);
+       UNLOCK_CACHE (o365_folder);
+
+       g_checksum_free (checksum);
+
+       if (base_stream) {
+               stream = camel_stream_new (base_stream);
+               g_object_unref (base_stream);
+       }
+
+       return stream;
+}
+
+static gint
+o365_folder_cache_remove (CamelO365Folder *o365_folder,
+                         const gchar *id,
+                         GError **error)
+{
+       GChecksum *checksum;
+       gint ret;
+
+       checksum = o365_folder_cache_new_checksum (id);
+
+       LOCK_CACHE (o365_folder);
+       ret = camel_data_cache_remove (o365_folder->priv->cache, O365_LOCAL_CACHE_PATH, g_checksum_get_string 
(checksum), error);
+       UNLOCK_CACHE (o365_folder);
+
+       g_checksum_free (checksum);
+
+       return ret;
+}
+
+static CamelStream *
+o365_folder_cache_get (CamelO365Folder *o365_folder,
+                      const gchar *id,
+                      GError **error)
+{
+       GChecksum *checksum;
+       CamelStream *stream = NULL;
+       GIOStream *base_stream;
+
+       checksum = o365_folder_cache_new_checksum (id);
+
+       LOCK_CACHE (o365_folder);
+       base_stream = camel_data_cache_get (o365_folder->priv->cache, O365_LOCAL_CACHE_PATH, 
g_checksum_get_string (checksum), error);
+       UNLOCK_CACHE (o365_folder);
+
+       g_checksum_free (checksum);
+
+       if (base_stream) {
+               stream = camel_stream_new (base_stream);
+               g_object_unref (base_stream);
+       }
+
+       return stream;
+}
+
+static gchar *
+o365_folder_cache_dup_filename (CamelO365Folder *o365_folder,
+                               const gchar *id)
+{
+       GChecksum *checksum;
+       gchar *filename;
+
+       checksum = o365_folder_cache_new_checksum (id);
+
+       LOCK_CACHE (o365_folder);
+       filename = camel_data_cache_get_filename (o365_folder->priv->cache, O365_LOCAL_CACHE_PATH, 
g_checksum_get_string (checksum));
+       UNLOCK_CACHE (o365_folder);
+
+       g_checksum_free (checksum);
+
+       return filename;
+}
+
+static CamelMimeMessage *
+o365_folder_get_message_from_cache (CamelO365Folder *o365_folder,
+                                   const gchar *uid,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+       CamelStream *stream;
+       CamelMimeMessage *msg;
+
+       stream = o365_folder_cache_get (o365_folder, uid, error);
+
+       if (!stream)
+               return NULL;
+
+       msg = camel_mime_message_new ();
+
+       if (!camel_data_wrapper_construct_from_stream_sync (CAMEL_DATA_WRAPPER (msg), stream, cancellable, 
error))
+               g_clear_object (&msg);
+
+       g_object_unref (stream);
+
+       return msg;
+}
+
+static gchar *
+o365_folder_get_filename (CamelFolder *folder,
+                         const gchar *uid,
+                         GError **error)
+{
+       CamelO365Folder *o365_folder = CAMEL_O365_FOLDER (folder);
+
+       return o365_folder_cache_dup_filename (o365_folder, uid);
+}
+
+static void
+o365_folder_save_summary (CamelO365Folder *o365_folder)
+{
+       CamelFolderSummary *summary;
+
+       g_return_if_fail (CAMEL_IS_O365_FOLDER (o365_folder));
+
+       summary = camel_folder_get_folder_summary (CAMEL_FOLDER (o365_folder));
+
+       if (summary) {
+               GError *error = NULL;
+
+               if (!camel_folder_summary_save (summary, &error))
+                       g_warning ("%s: Failed to save summary: %s", G_STRFUNC, error ? error->message : 
"Unknown error");
+
+               g_clear_error (&error);
+       }
+}
+
+static guint32
+o365_folder_get_permanent_flags (CamelFolder *folder)
+{
+       return CAMEL_MESSAGE_ANSWERED |
+               CAMEL_MESSAGE_DELETED |
+               CAMEL_MESSAGE_DRAFT |
+               CAMEL_MESSAGE_FLAGGED |
+               CAMEL_MESSAGE_SEEN |
+               CAMEL_MESSAGE_FORWARDED |
+               CAMEL_MESSAGE_USER;
+}
+
+static CamelMimeMessage *
+o365_folder_get_message_cached (CamelFolder *folder,
+                               const gchar *message_uid,
+                               GCancellable *cancellable)
+{
+       return o365_folder_get_message_from_cache (CAMEL_O365_FOLDER (folder), message_uid, cancellable, 
NULL);
+}
+
+static void
+o365_folder_exec_search (CamelFolder *folder,
+                        const gchar *expression,
+                        GPtrArray *uids,
+                        GPtrArray **out_matches,
+                        guint32 *out_count,
+                        GCancellable *cancellable,
+                        GError **error)
+{
+       CamelO365Folder *o365_folder;
+
+       g_return_if_fail (CAMEL_IS_O365_FOLDER (folder));
+
+       o365_folder = CAMEL_O365_FOLDER (folder);
+
+       LOCK_SEARCH (o365_folder);
+
+       camel_folder_search_set_folder (o365_folder->priv->search, folder);
+
+       if (out_matches)
+               *out_matches = camel_folder_search_search (o365_folder->priv->search, expression, uids, 
cancellable, error);
+
+       if (out_count)
+               *out_count = camel_folder_search_count (o365_folder->priv->search, expression, cancellable, 
error);
+
+       UNLOCK_SEARCH (o365_folder);
+}
+
+static GPtrArray *
+o365_folder_search_by_expression (CamelFolder *folder,
+                                 const gchar *expression,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       GPtrArray *matches = NULL;
+
+       o365_folder_exec_search (folder, expression, NULL, &matches, NULL, cancellable, error);
+
+       return matches;
+}
+
+static guint32
+o365_folder_count_by_expression (CamelFolder *folder,
+                                const gchar *expression,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       guint32 count = 0;
+
+       o365_folder_exec_search (folder, expression, NULL, NULL, &count, cancellable, error);
+
+       return count;
+}
+
+static GPtrArray *
+o365_folder_search_by_uids (CamelFolder *folder,
+                           const gchar *expression,
+                           GPtrArray *uids,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       GPtrArray *matches = NULL;
+
+       if (uids->len == 0)
+               return g_ptr_array_new ();
+
+       o365_folder_exec_search (folder, expression, uids, &matches, NULL, cancellable, error);
+
+       return matches;
+}
+
+static void
+o365_folder_search_free (CamelFolder *folder,
+                        GPtrArray *uids)
+{
+       CamelO365Folder *o365_folder;
+
+       if (!uids)
+               return;
+
+       g_return_if_fail (CAMEL_IS_O365_FOLDER (folder));
+
+       o365_folder = CAMEL_O365_FOLDER (folder);
+
+       LOCK_SEARCH (o365_folder);
+
+       camel_folder_search_free_result (o365_folder->priv->search, uids);
+
+       UNLOCK_SEARCH (o365_folder);
+}
+
+static gint
+o365_folder_cmp_uids (CamelFolder *folder,
+                     const gchar *uid1,
+                     const gchar *uid2)
+{
+       g_return_val_if_fail (uid1 != NULL, 0);
+       g_return_val_if_fail (uid2 != NULL, 0);
+
+       return strcmp (uid1, uid2);
+}
+
+static void
+o365_folder_constructed (GObject *object)
+{
+       CamelSettings *settings;
+       CamelStore *parent_store;
+       CamelService *service;
+       CamelFolder *folder;
+       const gchar *full_name;
+       gchar *description;
+       gchar *user;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_o365_folder_parent_class)->constructed (object);
+
+       folder = CAMEL_FOLDER (object);
+       full_name = camel_folder_get_full_name (folder);
+       parent_store = camel_folder_get_parent_store (folder);
+
+       service = CAMEL_SERVICE (parent_store);
+
+       settings = camel_service_ref_settings (service);
+       user = camel_network_settings_dup_user (CAMEL_NETWORK_SETTINGS (settings));
+
+       g_object_unref (settings);
+
+       description = g_strdup_printf ("%s@Office365:%s", user, full_name);
+       camel_folder_set_description (folder, description);
+       g_free (description);
+
+       g_free (user);
+}
+
+static void
+o365_folder_dispose (GObject *object)
+{
+       CamelO365Folder *o365_folder = CAMEL_O365_FOLDER (object);
+       CamelFolderSummary *summary;
+
+       summary = camel_folder_get_folder_summary (CAMEL_FOLDER (o365_folder));
+
+       if (summary)
+               o365_folder_save_summary (o365_folder);
+
+       LOCK_CACHE (o365_folder);
+       g_clear_object (&o365_folder->priv->cache);
+       UNLOCK_CACHE (o365_folder);
+
+       LOCK_SEARCH (o365_folder);
+       g_clear_object (&o365_folder->priv->search);
+       UNLOCK_SEARCH (o365_folder);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_o365_folder_parent_class)->dispose (object);
+}
+
+static void
+o365_folder_finalize (GObject *object)
+{
+       CamelO365Folder *o365_folder = CAMEL_O365_FOLDER (object);
+
+       g_rec_mutex_clear (&o365_folder->priv->cache_lock);
+       g_mutex_clear (&o365_folder->priv->search_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_o365_folder_parent_class)->finalize (object);
+}
+
+static void
+camel_o365_folder_class_init (CamelO365FolderClass *klass)
+{
+       GObjectClass *object_class;
+       CamelFolderClass *folder_class;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->constructed = o365_folder_constructed;
+       object_class->dispose = o365_folder_dispose;
+       object_class->finalize = o365_folder_finalize;
+
+       folder_class = CAMEL_FOLDER_CLASS (klass);
+       folder_class->get_permanent_flags = o365_folder_get_permanent_flags;
+       folder_class->get_message_cached = o365_folder_get_message_cached;
+       folder_class->search_by_expression = o365_folder_search_by_expression;
+       folder_class->count_by_expression = o365_folder_count_by_expression;
+       folder_class->search_by_uids = o365_folder_search_by_uids;
+       folder_class->search_free = o365_folder_search_free;
+       folder_class->cmp_uids = o365_folder_cmp_uids;
+#if 0
+       folder_class->append_message_sync = o365_folder_append_message_sync;
+       folder_class->get_message_sync = o365_folder_get_message_sync;
+       folder_class->refresh_info_sync = o365_folder_refresh_info_sync;
+       folder_class->synchronize_sync = o365_folder_synchronize_sync;
+       folder_class->expunge_sync = o365_folder_expunge_sync;
+       folder_class->transfer_messages_to_sync = o365_folder_transfer_messages_to_sync;
+       folder_class->prepare_content_refresh = o365_folder_prepare_content_refresh;
+#endif
+       folder_class->get_filename = o365_folder_get_filename;
+}
+
+static void
+camel_o365_folder_init (CamelO365Folder *o365_folder)
+{
+       CamelFolder *folder = CAMEL_FOLDER (o365_folder);
+
+       o365_folder->priv = camel_o365_folder_get_instance_private (o365_folder);
+
+       g_rec_mutex_init (&o365_folder->priv->cache_lock);
+       g_mutex_init (&o365_folder->priv->search_lock);
+
+       camel_folder_set_flags (folder, CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY);
+       camel_folder_set_lock_async (folder, TRUE);
+}
+
+static gboolean
+o365_folder_has_inbox_type (CamelO365Store *o365_store,
+                           const gchar *full_name)
+{
+       CamelO365StoreSummary *summary;
+       guint32 flags;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE (o365_store), FALSE);
+       g_return_val_if_fail (full_name != NULL, FALSE);
+
+       summary = camel_o365_store_ref_store_summary (o365_store);
+
+       if (!summary)
+               return FALSE;
+
+       flags = camel_o365_store_summary_get_folder_flags_for_full_name (summary, full_name);
+
+       g_object_unref (summary);
+
+       return (flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX;
+}
+
+CamelFolder *
+camel_o365_folder_new (CamelStore *store,
+                      const gchar *display_name,
+                      const gchar *full_name,
+                      const gchar *folder_dir,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       CamelFolder *folder;
+       CamelFolderSummary *folder_summary;
+       CamelO365Folder *o365_folder;
+       CamelSettings *settings;
+       gboolean filter_inbox = FALSE;
+       gboolean filter_junk = FALSE;
+       gboolean filter_junk_inbox = FALSE;
+       gboolean offline_limit_by_age = FALSE;
+       CamelTimeUnit offline_limit_unit;
+       gint offline_limit_value = 0;
+       guint32 add_folder_flags = 0;
+       gchar *state_file;
+
+       folder = g_object_new (CAMEL_TYPE_O365_FOLDER,
+               "display_name", display_name,
+               "full-name", full_name,
+               "parent_store", store,
+               NULL);
+
+       o365_folder = CAMEL_O365_FOLDER (folder);
+
+       folder_summary = camel_o365_folder_summary_new (folder);
+
+       if (!folder_summary) {
+               g_object_unref (folder);
+               g_set_error (
+                       error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                       _("Could not load summary for %s"), full_name);
+               return NULL;
+       }
+
+       settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+
+       g_object_get (
+               settings,
+               "filter-inbox", &filter_inbox,
+               "filter-junk", &filter_junk,
+               "filter-junk-inbox", &filter_junk_inbox,
+               "limit-by-age", &offline_limit_by_age,
+               "limit-unit", &offline_limit_unit,
+               "limit-value", &offline_limit_value,
+               NULL);
+
+       g_clear_object (&settings);
+
+       camel_folder_take_folder_summary (folder, folder_summary);
+
+       /* set/load persistent state */
+       state_file = g_build_filename (folder_dir, "cmeta", NULL);
+       camel_object_set_state_filename (CAMEL_OBJECT (folder), state_file);
+       camel_object_state_read (CAMEL_OBJECT (folder));
+       g_free (state_file);
+
+       o365_folder->priv->cache = camel_data_cache_new (folder_dir, error);
+       if (!o365_folder->priv->cache) {
+               g_object_unref (folder);
+               return NULL;
+       }
+
+       if (camel_offline_folder_can_downsync (CAMEL_OFFLINE_FOLDER (folder))) {
+               time_t when = (time_t) 0;
+
+               if (offline_limit_by_age)
+                       when = camel_time_value_apply (when, offline_limit_unit, offline_limit_value);
+
+               if (when <= (time_t) 0)
+                       when = (time_t) -1;
+
+               /* Ensure cache will expire when set up, otherwise
+                * it causes redownload of messages too soon. */
+               camel_data_cache_set_expire_age (o365_folder->priv->cache, when);
+               camel_data_cache_set_expire_access (o365_folder->priv->cache, when);
+       } else {
+               /* Set cache expiration for one week. */
+               camel_data_cache_set_expire_age (o365_folder->priv->cache, 60 * 60 * 24 * 7);
+               camel_data_cache_set_expire_access (o365_folder->priv->cache, 60 * 60 * 24 * 7);
+       }
+
+       camel_binding_bind_property (store, "online",
+               o365_folder->priv->cache, "expire-enabled",
+               G_BINDING_SYNC_CREATE);
+
+       if (o365_folder_has_inbox_type (CAMEL_O365_STORE (store), full_name)) {
+               if (filter_inbox)
+                       add_folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+
+               if (filter_junk)
+                       add_folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
+       } else {
+               if (filter_junk && !filter_junk_inbox)
+                       add_folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
+       }
+
+       if (add_folder_flags)
+               camel_folder_set_flags (folder, camel_folder_get_flags (folder) | add_folder_flags);
+
+       camel_o365_store_connect_folder_summary (CAMEL_O365_STORE (store), folder_summary);
+
+       o365_folder->priv->search = camel_folder_search_new ();
+
+       return folder;
+}
diff --git a/src/Office365/camel/camel-o365-folder.h b/src/Office365/camel/camel-o365-folder.h
new file mode 100644
index 00000000..d189e72d
--- /dev/null
+++ b/src/Office365/camel/camel-o365-folder.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CAMEL_O365_FOLDER_H
+#define CAMEL_O365_FOLDER_H
+
+#include <camel/camel.h>
+
+#include "camel-o365-folder-summary.h"
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_O365_FOLDER \
+       (camel_o365_folder_get_type ())
+#define CAMEL_O365_FOLDER(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_O365_FOLDER, CamelO365Folder))
+#define CAMEL_O365_FOLDER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_O365_FOLDER, CamelO365FolderClass))
+#define CAMEL_IS_O365_FOLDER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_O365_FOLDER))
+#define CAMEL_IS_O365_FOLDER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_O365_FOLDER))
+#define CAMEL_O365_FOLDER_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_O365_FOLDER, CamelO365FolderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelO365Folder CamelO365Folder;
+typedef struct _CamelO365FolderClass CamelO365FolderClass;
+typedef struct _CamelO365FolderPrivate CamelO365FolderPrivate;
+
+struct _CamelO365Folder {
+       CamelOfflineFolder parent;
+       CamelO365FolderPrivate *priv;
+};
+
+struct _CamelO365FolderClass {
+       CamelOfflineFolderClass parent_class;
+};
+
+GType          camel_o365_folder_get_type      (void);
+
+CamelFolder *  camel_o365_folder_new           (CamelStore *store,
+                                                const gchar *display_name,
+                                                const gchar *full_name,
+                                                const gchar *folder_dir,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+G_END_DECLS
+
+#endif /* CAMEL_O365_FOLDER_H */
diff --git a/src/Office365/camel/camel-o365-message-info.c b/src/Office365/camel/camel-o365-message-info.c
new file mode 100644
index 00000000..9d738624
--- /dev/null
+++ b/src/Office365/camel/camel-o365-message-info.c
@@ -0,0 +1,420 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-ews-config.h"
+
+#include <stdio.h>
+
+#include "camel/camel.h"
+
+#include "camel-o365-message-info.h"
+
+struct _CamelO365MessageInfoPrivate {
+       guint32 server_flags;
+       gint32 item_type;
+       gchar *change_key;
+};
+
+enum {
+       PROP_0,
+       PROP_SERVER_FLAGS,
+       PROP_ITEM_TYPE,
+       PROP_CHANGE_KEY,
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (CamelO365MessageInfo, camel_o365_message_info, CAMEL_TYPE_MESSAGE_INFO_BASE)
+
+static CamelMessageInfo *
+o365_message_info_clone (const CamelMessageInfo *mi,
+                        CamelFolderSummary *assign_summary)
+{
+       CamelMessageInfo *result;
+
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (mi), NULL);
+
+       result = CAMEL_MESSAGE_INFO_CLASS (camel_o365_message_info_parent_class)->clone (mi, assign_summary);
+       if (!result)
+               return NULL;
+
+       if (CAMEL_IS_O365_MESSAGE_INFO (result)) {
+               CamelO365MessageInfo *omi, *omi_result;
+
+               omi = CAMEL_O365_MESSAGE_INFO (mi);
+               omi_result = CAMEL_O365_MESSAGE_INFO (result);
+
+               camel_o365_message_info_set_server_flags (omi_result, 
camel_o365_message_info_get_server_flags (omi));
+               camel_o365_message_info_set_item_type (omi_result, camel_o365_message_info_get_item_type 
(omi));
+               camel_o365_message_info_take_change_key (omi_result, camel_o365_message_info_dup_change_key 
(omi));
+       }
+
+       return result;
+}
+
+static gboolean
+o365_message_info_load (CamelMessageInfo *mi,
+                       const CamelMIRecord *record,
+                       /* const */ gchar **bdata_ptr)
+{
+       CamelO365MessageInfo *omi;
+
+       g_return_val_if_fail (CAMEL_IS_O365_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_o365_message_info_parent_class)->load ||
+           !CAMEL_MESSAGE_INFO_CLASS (camel_o365_message_info_parent_class)->load (mi, record, bdata_ptr))
+               return FALSE;
+
+       omi = CAMEL_O365_MESSAGE_INFO (mi);
+
+       if (*bdata_ptr) {
+               gchar **values;
+
+               values = g_strsplit (*bdata_ptr, " ", -1);
+
+               if (values && values[0] && values[1] && values[2]) {
+                       camel_o365_message_info_set_server_flags (omi, g_ascii_strtoll (values[0], NULL, 10));
+                       camel_o365_message_info_set_item_type (omi, g_ascii_strtoll (values[1], NULL, 10));
+                       camel_o365_message_info_set_change_key (omi, values[2]);
+               }
+
+               g_strfreev (values);
+       }
+
+       return TRUE;
+}
+
+static gboolean
+o365_message_info_save (const CamelMessageInfo *mi,
+                       CamelMIRecord *record,
+                       GString *bdata_str)
+{
+       CamelO365MessageInfo *omi;
+
+       g_return_val_if_fail (CAMEL_IS_O365_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_o365_message_info_parent_class)->save ||
+           !CAMEL_MESSAGE_INFO_CLASS (camel_o365_message_info_parent_class)->save (mi, record, bdata_str))
+               return FALSE;
+
+       omi = CAMEL_O365_MESSAGE_INFO (mi);
+
+       g_string_append_printf (bdata_str, "%u %d %s",
+               camel_o365_message_info_get_server_flags (omi),
+               camel_o365_message_info_get_item_type (omi),
+               camel_o365_message_info_get_change_key (omi));
+
+       return TRUE;
+}
+
+static void
+o365_message_info_set_property (GObject *object,
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+       CamelO365MessageInfo *omi = CAMEL_O365_MESSAGE_INFO (object);
+
+       switch (property_id) {
+       case PROP_SERVER_FLAGS:
+               camel_o365_message_info_set_server_flags (omi, g_value_get_uint (value));
+               return;
+
+       case PROP_ITEM_TYPE:
+               camel_o365_message_info_set_item_type (omi, g_value_get_int (value));
+               return;
+
+       case PROP_CHANGE_KEY:
+               camel_o365_message_info_set_change_key (omi, g_value_get_string (value));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+o365_message_info_get_property (GObject *object,
+                               guint property_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+       CamelO365MessageInfo *omi = CAMEL_O365_MESSAGE_INFO (object);
+
+       switch (property_id) {
+
+       case PROP_SERVER_FLAGS:
+               g_value_set_uint (value, camel_o365_message_info_get_server_flags (omi));
+               return;
+
+       case PROP_ITEM_TYPE:
+               g_value_set_int (value, camel_o365_message_info_get_item_type (omi));
+               return;
+
+       case PROP_CHANGE_KEY:
+               g_value_take_string (value, camel_o365_message_info_dup_change_key (omi));
+               return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+o365_message_info_dispose (GObject *object)
+{
+       CamelO365MessageInfo *omi = CAMEL_O365_MESSAGE_INFO (object);
+
+       g_free (omi->priv->change_key);
+       omi->priv->change_key = NULL;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_o365_message_info_parent_class)->dispose (object);
+}
+
+static void
+camel_o365_message_info_class_init (CamelO365MessageInfoClass *class)
+{
+       CamelMessageInfoClass *mi_class;
+       GObjectClass *object_class;
+
+       mi_class = CAMEL_MESSAGE_INFO_CLASS (class);
+       mi_class->clone = o365_message_info_clone;
+       mi_class->load = o365_message_info_load;
+       mi_class->save = o365_message_info_save;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = o365_message_info_set_property;
+       object_class->get_property = o365_message_info_get_property;
+       object_class->dispose = o365_message_info_dispose;
+
+       /*
+        * CamelO365MessageInfo:server-flags
+        *
+        * Last known server flags of the message.
+        */
+       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));
+
+       /*
+        * CamelO365MessageInfo:item-type
+        *
+        * Item type of the message.
+        */
+       g_object_class_install_property (
+               object_class,
+               PROP_ITEM_TYPE,
+               g_param_spec_int (
+                       "item-type",
+                       "Item Type",
+                       NULL,
+                       0, G_MAXINT32, 0,
+                       G_PARAM_READWRITE));
+
+       /*
+        * CamelO365MessageInfo:change-key
+        *
+        * Change key of the message on the server.
+        */
+       g_object_class_install_property (
+               object_class,
+               PROP_CHANGE_KEY,
+               g_param_spec_string (
+                       "change-key",
+                       "Change Key",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+}
+
+static void
+camel_o365_message_info_init (CamelO365MessageInfo *omi)
+{
+       omi->priv = camel_o365_message_info_get_instance_private (omi);
+}
+
+guint32
+camel_o365_message_info_get_server_flags (const CamelO365MessageInfo *omi)
+{
+       CamelMessageInfo *mi;
+       guint32 result;
+
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (omi), 0);
+
+       mi = CAMEL_MESSAGE_INFO (omi);
+
+       camel_message_info_property_lock (mi);
+       result = omi->priv->server_flags;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gboolean
+camel_o365_message_info_set_server_flags (CamelO365MessageInfo *omi,
+                                         guint32 server_flags)
+{
+       CamelMessageInfo *mi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (omi), FALSE);
+
+       mi = CAMEL_MESSAGE_INFO (omi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = omi->priv->server_flags != server_flags;
+
+       if (changed)
+               omi->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 (omi), "server-flags");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
+
+gint32
+camel_o365_message_info_get_item_type (const CamelO365MessageInfo *omi)
+{
+       CamelMessageInfo *mi;
+       gint32 result;
+
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (omi), 0);
+
+       mi = CAMEL_MESSAGE_INFO (omi);
+
+       camel_message_info_property_lock (mi);
+       result = omi->priv->item_type;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gboolean
+camel_o365_message_info_set_item_type (CamelO365MessageInfo *omi,
+                                      gint32 item_type)
+{
+       CamelMessageInfo *mi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (omi), FALSE);
+
+       mi = CAMEL_MESSAGE_INFO (omi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = omi->priv->item_type != item_type;
+
+       if (changed)
+               omi->priv->item_type = item_type;
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !camel_message_info_get_abort_notifications (mi)) {
+               g_object_notify (G_OBJECT (omi), "item-type");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
+
+const gchar *
+camel_o365_message_info_get_change_key (const CamelO365MessageInfo *omi)
+{
+       CamelMessageInfo *mi;
+       const gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (omi), NULL);
+
+       mi = CAMEL_MESSAGE_INFO (omi);
+
+       camel_message_info_property_lock (mi);
+       result = omi->priv->change_key;
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gchar *
+camel_o365_message_info_dup_change_key (const CamelO365MessageInfo *omi)
+{
+       CamelMessageInfo *mi;
+       gchar *result;
+
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (omi), NULL);
+
+       mi = CAMEL_MESSAGE_INFO (omi);
+
+       camel_message_info_property_lock (mi);
+       result = g_strdup (omi->priv->change_key);
+       camel_message_info_property_unlock (mi);
+
+       return result;
+}
+
+gboolean
+camel_o365_message_info_set_change_key (CamelO365MessageInfo *omi,
+                                       const gchar *change_key)
+{
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (omi), FALSE);
+
+       return camel_o365_message_info_take_change_key (omi, g_strdup (change_key));
+}
+
+gboolean
+camel_o365_message_info_take_change_key (CamelO365MessageInfo *omi,
+                                        gchar *change_key)
+{
+       CamelMessageInfo *mi;
+       gboolean changed;
+
+       g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (omi), FALSE);
+
+       mi = CAMEL_MESSAGE_INFO (omi);
+
+       camel_message_info_property_lock (mi);
+
+       changed = g_strcmp0 (omi->priv->change_key, change_key) != 0;
+
+       if (changed) {
+               g_free (omi->priv->change_key);
+               omi->priv->change_key = change_key;
+       } else if (change_key != omi->priv->change_key) {
+               g_free (change_key);
+       }
+
+       camel_message_info_property_unlock (mi);
+
+       if (changed && !camel_message_info_get_abort_notifications (mi)) {
+               g_object_notify (G_OBJECT (omi), "change-key");
+               camel_message_info_set_dirty (mi, TRUE);
+       }
+
+       return changed;
+}
diff --git a/src/Office365/camel/camel-o365-message-info.h b/src/Office365/camel/camel-o365-message-info.h
new file mode 100644
index 00000000..78f9ba8e
--- /dev/null
+++ b/src/Office365/camel/camel-o365-message-info.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CAMEL_O365_MESSAGE_INFO_H
+#define CAMEL_O365_MESSAGE_INFO_H
+
+#include <glib-object.h>
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_O365_MESSAGE_INFO \
+       (camel_o365_message_info_get_type ())
+#define CAMEL_O365_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_O365_MESSAGE_INFO, CamelO365MessageInfo))
+#define CAMEL_O365_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_O365_MESSAGE_INFO, CamelO365MessageInfoClass))
+#define CAMEL_IS_O365_MESSAGE_INFO(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_O365_MESSAGE_INFO))
+#define CAMEL_IS_O365_MESSAGE_INFO_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_O365_MESSAGE_INFO))
+#define CAMEL_O365_MESSAGE_INFO_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_O365_MESSAGE_INFO, CamelO365MessageInfoClass))
+
+G_BEGIN_DECLS
+
+/* extra summary flags*/
+enum {
+       CAMEL_O365_MESSAGE_MSGFLAG_RN_PENDING = CAMEL_MESSAGE_FOLDER_FLAGGED << 1
+};
+
+typedef struct _CamelO365MessageInfo CamelO365MessageInfo;
+typedef struct _CamelO365MessageInfoClass CamelO365MessageInfoClass;
+typedef struct _CamelO365MessageInfoPrivate CamelO365MessageInfoPrivate;
+
+struct _CamelO365MessageInfo {
+       CamelMessageInfoBase parent;
+       CamelO365MessageInfoPrivate *priv;
+};
+
+struct _CamelO365MessageInfoClass {
+       CamelMessageInfoBaseClass parent_class;
+};
+
+GType          camel_o365_message_info_get_type        (void);
+
+guint32                camel_o365_message_info_get_server_flags(const CamelO365MessageInfo *omi);
+gboolean       camel_o365_message_info_set_server_flags(CamelO365MessageInfo *omi,
+                                                        guint32 server_flags);
+gint32         camel_o365_message_info_get_item_type   (const CamelO365MessageInfo *omi);
+gboolean       camel_o365_message_info_set_item_type   (CamelO365MessageInfo *omi,
+                                                        gint32 item_type);
+const gchar *  camel_o365_message_info_get_change_key  (const CamelO365MessageInfo *omi);
+gchar *                camel_o365_message_info_dup_change_key  (const CamelO365MessageInfo *omi);
+gboolean       camel_o365_message_info_set_change_key  (CamelO365MessageInfo *omi,
+                                                        const gchar *change_key);
+gboolean       camel_o365_message_info_take_change_key (CamelO365MessageInfo *omi,
+                                                        gchar *change_key);
+
+G_END_DECLS
+
+#endif /* CAMEL_O365_MESSAGE_INFO_H */
diff --git a/src/Office365/camel/camel-o365-store-summary.c b/src/Office365/camel/camel-o365-store-summary.c
index 05ab38da..163d3a43 100644
--- a/src/Office365/camel/camel-o365-store-summary.c
+++ b/src/Office365/camel/camel-o365-store-summary.c
@@ -647,6 +647,57 @@ camel_o365_store_summary_dup_folder_full_name (CamelO365StoreSummary *store_summ
        return value;
 }
 
+gchar *
+camel_o365_store_summary_dup_folder_id_for_full_name (CamelO365StoreSummary *store_summary,
+                                                     const gchar *full_name)
+{
+       gchar *id;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE_SUMMARY (store_summary), NULL);
+       g_return_val_if_fail (full_name != NULL, NULL);
+
+       LOCK (store_summary);
+
+       id = g_strdup (g_hash_table_lookup (store_summary->priv->full_name_id_hash, full_name));
+
+       UNLOCK (store_summary);
+
+       return id;
+}
+
+gchar *
+camel_o365_store_summary_dup_folder_id_for_type (CamelO365StoreSummary *store_summary,
+                                                guint32 folder_type)
+{
+       GHashTableIter iter;
+       gpointer key;
+       gchar *id = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE_SUMMARY (store_summary), NULL);
+
+       folder_type = folder_type & CAMEL_FOLDER_TYPE_MASK;
+       g_return_val_if_fail (folder_type != 0, NULL);
+
+       LOCK (store_summary);
+
+       g_hash_table_iter_init (&iter, store_summary->priv->id_full_name_hash);
+
+       while (g_hash_table_iter_next (&iter, &key, NULL)) {
+               guint32 flags;
+
+               flags = camel_o365_store_summary_get_folder_flags (store_summary, key);
+
+               if ((flags & CAMEL_FOLDER_TYPE_MASK) == folder_type) {
+                       id = g_strdup (key);
+                       break;
+               }
+       }
+
+       UNLOCK (store_summary);
+
+       return id;
+}
+
 typedef struct _IdFullNameData {
        gchar *id;
        gchar *full_name;
@@ -955,6 +1006,28 @@ camel_o365_store_summary_get_folder_flags (CamelO365StoreSummary *store_summary,
        return value;
 }
 
+guint32
+camel_o365_store_summary_get_folder_flags_for_full_name (CamelO365StoreSummary *store_summary,
+                                                        const gchar *full_name)
+{
+       const gchar *id;
+       guint32 flags = 0;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE_SUMMARY (store_summary), 0);
+       g_return_val_if_fail (full_name != NULL, 0);
+
+       LOCK (store_summary);
+
+       id = g_hash_table_lookup (store_summary->priv->full_name_id_hash, full_name);
+
+       if (id)
+               flags = camel_o365_store_summary_get_folder_flags (store_summary, id);
+
+       UNLOCK (store_summary);
+
+       return flags;
+}
+
 EO365FolderKind
 camel_o365_store_summary_get_folder_kind (CamelO365StoreSummary *store_summary,
                                          const gchar *id)
@@ -1090,3 +1163,51 @@ camel_o365_store_summary_build_folder_info (CamelO365StoreSummary *store_summary
 
        return info;
 }
+
+static void
+o365_store_summary_folder_count_notify_cb (CamelFolderSummary *folder_summary,
+                                          GParamSpec *param,
+                                          CamelO365StoreSummary *store_summary)
+{
+       CamelFolder *folder;
+       gchar *folder_id;
+       gint count;
+
+       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (folder_summary));
+       g_return_if_fail (param != NULL);
+       g_return_if_fail (CAMEL_IS_O365_STORE_SUMMARY (store_summary));
+
+       folder = camel_folder_summary_get_folder (folder_summary);
+
+       if (!folder)
+               return;
+
+       folder_id = camel_o365_store_summary_dup_folder_id_for_full_name (store_summary, 
camel_folder_get_full_name (folder));
+
+       /* This can happen on folder delete/unsubscribe, after folder summary clear */
+       if (!folder_id)
+               return;
+
+       if (g_strcmp0 (g_param_spec_get_name (param), "saved-count") == 0) {
+               count = camel_folder_summary_get_saved_count (folder_summary);
+               camel_o365_store_summary_set_folder_total_count (store_summary, folder_id, count);
+       } else if (g_strcmp0 (g_param_spec_get_name (param), "unread-count") == 0) {
+               count = camel_folder_summary_get_unread_count (folder_summary);
+               camel_o365_store_summary_set_folder_unread_count (store_summary, folder_id, count);
+       } else {
+               g_warn_if_reached ();
+       }
+
+       g_free (folder_id);
+}
+
+void
+camel_o365_store_summary_connect_folder_summary (CamelO365StoreSummary *store_summary,
+                                                CamelFolderSummary *folder_summary)
+{
+       g_return_if_fail (CAMEL_IS_O365_STORE_SUMMARY (store_summary));
+       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (folder_summary));
+
+       g_signal_connect_object (folder_summary, "notify::saved-count", G_CALLBACK 
(o365_store_summary_folder_count_notify_cb), store_summary, 0);
+       g_signal_connect_object (folder_summary, "notify::unread-count", G_CALLBACK 
(o365_store_summary_folder_count_notify_cb), store_summary, 0);
+}
diff --git a/src/Office365/camel/camel-o365-store-summary.h b/src/Office365/camel/camel-o365-store-summary.h
index b07cc493..a83783e9 100644
--- a/src/Office365/camel/camel-o365-store-summary.h
+++ b/src/Office365/camel/camel-o365-store-summary.h
@@ -108,6 +108,12 @@ gboolean   camel_o365_store_summary_get_folder     (CamelO365StoreSummary *store_summa
 gchar *                camel_o365_store_summary_dup_folder_full_name
                                                        (CamelO365StoreSummary *store_summary,
                                                         const gchar *id);
+gchar *                camel_o365_store_summary_dup_folder_id_for_full_name
+                                                       (CamelO365StoreSummary *store_summary,
+                                                        const gchar *full_name);
+gchar *                camel_o365_store_summary_dup_folder_id_for_type
+                                                       (CamelO365StoreSummary *store_summary,
+                                                        guint32 folder_type); /* The CAMEL_FOLDER_TYPE_... 
of the CamelFolderInfoFlags */
 gboolean       camel_o365_store_summary_set_folder_display_name
                                                        (CamelO365StoreSummary *store_summary,
                                                         const gchar *id,
@@ -144,6 +150,9 @@ void                camel_o365_store_summary_set_folder_flags
 guint32                camel_o365_store_summary_get_folder_flags
                                                        (CamelO365StoreSummary *store_summary,
                                                         const gchar *id);
+guint32                camel_o365_store_summary_get_folder_flags_for_full_name
+                                                       (CamelO365StoreSummary *store_summary,
+                                                        const gchar *full_name);
 EO365FolderKind        camel_o365_store_summary_get_folder_kind(CamelO365StoreSummary *store_summary,
                                                         const gchar *id);
 gboolean       camel_o365_store_summary_get_folder_is_foreign
@@ -161,6 +170,9 @@ CamelFolderInfo *
                                                        (CamelO365StoreSummary *store_summary,
                                                         const gchar *top,
                                                         gboolean recursive);
+void           camel_o365_store_summary_connect_folder_summary
+                                                       (CamelO365StoreSummary *store_summary,
+                                                        CamelFolderSummary *folder_summary);
 G_END_DECLS
 
 #endif /* CAMEL_O365_STORE_SUMMARY_H */
diff --git a/src/Office365/camel/camel-o365-store.c b/src/Office365/camel/camel-o365-store.c
index 70d966b8..65596703 100644
--- a/src/Office365/camel/camel-o365-store.c
+++ b/src/Office365/camel/camel-o365-store.c
@@ -258,23 +258,6 @@ o365_store_read_default_folders (CamelO365Store *o365_store,
        return success;
 }
 
-static EO365Connection *
-o365_store_ref_connection (CamelO365Store *o365_store)
-{
-       EO365Connection *cnc = NULL;
-
-       g_return_val_if_fail (CAMEL_IS_O365_STORE (o365_store), NULL);
-
-       LOCK (o365_store);
-
-       if (o365_store->priv->cnc)
-               cnc = g_object_ref (o365_store->priv->cnc);
-
-       UNLOCK (o365_store);
-
-       return cnc;
-}
-
 static gboolean
 o365_store_connect_sync (CamelService *service,
                         GCancellable *cancellable,
@@ -292,7 +275,7 @@ o365_store_connect_sync (CamelService *service,
                return FALSE;
 
        o365_store = CAMEL_O365_STORE (service);
-       cnc = o365_store_ref_connection (o365_store);
+       cnc = camel_o365_store_ref_connection (o365_store);
 
        if (!cnc) {
                LOCK (o365_store);
@@ -328,7 +311,7 @@ o365_store_disconnect_sync (CamelService *service,
        EO365Connection *cnc;
        gboolean success = TRUE;
 
-       cnc = o365_store_ref_connection (o365_store);
+       cnc = camel_o365_store_ref_connection (o365_store);
 
        if (cnc) {
                success = e_o365_connection_disconnect_sync (cnc, cancellable, error);
@@ -354,7 +337,7 @@ o365_store_authenticate_sync (CamelService *service,
        EO365Connection *cnc;
 
        o365_store = CAMEL_O365_STORE (service);
-       cnc = o365_store_ref_connection (o365_store);
+       cnc = camel_o365_store_ref_connection (o365_store);
 
        if (!cnc)
                return CAMEL_AUTHENTICATION_ERROR;
@@ -381,48 +364,6 @@ o365_store_authenticate_sync (CamelService *service,
        return result;
 }
 
-gboolean
-camel_o365_store_connected (CamelO365Store *o365_store,
-                           GCancellable *cancellable,
-                           GError **error)
-{
-       if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (o365_store))) {
-               g_set_error (
-                       error, CAMEL_SERVICE_ERROR,
-                       CAMEL_SERVICE_ERROR_UNAVAILABLE,
-                       _("You must be working online to complete this operation"));
-               return FALSE;
-       }
-
-       if (!camel_service_connect_sync ((CamelService *) o365_store, cancellable, error))
-               return FALSE;
-
-       return TRUE;
-}
-
-void
-camel_o365_store_maybe_disconnect (CamelO365Store *store,
-                                  const GError *error)
-{
-       CamelService *service;
-
-       g_return_if_fail (store != NULL);
-
-       if (!error)
-               return;
-
-       service = CAMEL_SERVICE (store);
-
-       if (camel_service_get_connection_status (service) != CAMEL_SERVICE_CONNECTED)
-               return;
-
-#if 0
-       if (g_error_matches (error, O365_CONNECTION_ERROR, O365_CONNECTION_ERROR_NORESPONSE) ||
-           g_error_matches (error, O365_CONNECTION_ERROR, O365_CONNECTION_ERROR_AUTHENTICATION_FAILED))
-               camel_service_disconnect_sync (service, FALSE, NULL, NULL);
-#endif
-}
-
 static void
 o365_store_save_summary_locked (CamelO365StoreSummary *summary,
                                const gchar *where)
@@ -565,7 +506,7 @@ o365_get_folder_info_sync (CamelStore *store,
                if (refresh_online) {
                        EO365Connection *cnc;
 
-                       cnc = o365_store_ref_connection (o365_store);
+                       cnc = camel_o365_store_ref_connection (o365_store);
 
                        if (cnc) {
                                FoldersDeltaData fdd;
@@ -770,17 +711,17 @@ camel_o365_store_class_init (CamelO365StoreClass *class)
 
        store_class = CAMEL_STORE_CLASS (class);
 #if 0
-       store_class->get_folder_sync = o365_get_folder_sync;
-       store_class->create_folder_sync = o365_create_folder_sync;
-       store_class->delete_folder_sync = o365_delete_folder_sync;
-       store_class->rename_folder_sync = o365_rename_folder_sync;
+       store_class->get_folder_sync = o365_store_get_folder_sync;
+       store_class->create_folder_sync = o365_store_create_folder_sync;
+       store_class->delete_folder_sync = o365_store_delete_folder_sync;
+       store_class->rename_folder_sync = o365_store_rename_folder_sync;
 #endif
        store_class->get_folder_info_sync = o365_get_folder_info_sync;
 #if 0
-       store_class->initial_setup_sync = o365_initial_setup_sync;
-       store_class->get_trash_folder_sync = o365_get_trash_folder_sync;
-       store_class->get_junk_folder_sync = o365_get_junk_folder_sync;
-       store_class->can_refresh_folder = o365_can_refresh_folder;
+       store_class->initial_setup_sync = o365_store_initial_setup_sync;
+       store_class->get_trash_folder_sync = o365_store_get_trash_folder_sync;
+       store_class->get_junk_folder_sync = o365_store_get_junk_folder_sync;
+       store_class->can_refresh_folder = o365_store_can_refresh_folder;
 #endif
 }
 
@@ -810,3 +751,98 @@ camel_o365_store_init (CamelO365Store *o365_store)
        g_rec_mutex_init (&o365_store->priv->property_lock);
        o365_store->priv->default_folders = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 }
+
+CamelO365StoreSummary *
+camel_o365_store_ref_store_summary (CamelO365Store *store)
+{
+       CamelO365StoreSummary *summary;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE (store), NULL);
+
+       LOCK (store);
+
+       summary = store->priv->summary;
+
+       if (summary)
+               g_object_ref (summary);
+
+       UNLOCK (store);
+
+       return summary;
+}
+
+EO365Connection *
+camel_o365_store_ref_connection (CamelO365Store *o365_store)
+{
+       EO365Connection *cnc = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE (o365_store), NULL);
+
+       LOCK (o365_store);
+
+       if (o365_store->priv->cnc)
+               cnc = g_object_ref (o365_store->priv->cnc);
+
+       UNLOCK (o365_store);
+
+       return cnc;
+}
+
+gboolean
+camel_o365_store_connected (CamelO365Store *o365_store,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       g_return_val_if_fail (CAMEL_IS_O365_STORE (o365_store), FALSE);
+
+       if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (o365_store))) {
+               g_set_error (
+                       error, CAMEL_SERVICE_ERROR,
+                       CAMEL_SERVICE_ERROR_UNAVAILABLE,
+                       _("You must be working online to complete this operation"));
+               return FALSE;
+       }
+
+       if (!camel_service_connect_sync ((CamelService *) o365_store, cancellable, error))
+               return FALSE;
+
+       return TRUE;
+}
+
+void
+camel_o365_store_maybe_disconnect (CamelO365Store *store,
+                                  const GError *error)
+{
+       CamelService *service;
+
+       g_return_if_fail (CAMEL_IS_O365_STORE (store));
+
+       if (!error)
+               return;
+
+       service = CAMEL_SERVICE (store);
+
+       if (camel_service_get_connection_status (service) != CAMEL_SERVICE_CONNECTED)
+               return;
+
+#if 0
+       if (g_error_matches (error, O365_CONNECTION_ERROR, O365_CONNECTION_ERROR_NORESPONSE) ||
+           g_error_matches (error, O365_CONNECTION_ERROR, O365_CONNECTION_ERROR_AUTHENTICATION_FAILED))
+               camel_service_disconnect_sync (service, FALSE, NULL, NULL);
+#endif
+}
+
+void
+camel_o365_store_connect_folder_summary (CamelO365Store *store,
+                                        CamelFolderSummary *folder_summary)
+{
+       g_return_if_fail (CAMEL_IS_O365_STORE (store));
+       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (folder_summary));
+
+       LOCK (store);
+
+       if (store->priv->summary)
+               camel_o365_store_summary_connect_folder_summary (store->priv->summary, folder_summary);
+
+       UNLOCK (store);
+}
diff --git a/src/Office365/camel/camel-o365-store.h b/src/Office365/camel/camel-o365-store.h
index 1567d012..af42cd33 100644
--- a/src/Office365/camel/camel-o365-store.h
+++ b/src/Office365/camel/camel-o365-store.h
@@ -20,6 +20,9 @@
 
 #include <camel/camel.h>
 
+#include "common/e-o365-connection.h"
+#include "camel-o365-store-summary.h"
+
 /* Standard GObject macros */
 #define CAMEL_TYPE_O365_STORE \
        (camel_o365_store_get_type ())
@@ -55,12 +58,21 @@ struct _CamelO365StoreClass {
 };
 
 GType          camel_o365_store_get_type       (void);
+
+CamelO365StoreSummary *
+               camel_o365_store_ref_store_summary
+                                               (CamelO365Store *store);
+EO365Connection *
+               camel_o365_store_ref_connection (CamelO365Store *o365_store);
 gboolean       camel_o365_store_connected      (CamelO365Store *store,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           camel_o365_store_maybe_disconnect
                                                (CamelO365Store *store,
                                                 const GError *error);
+void           camel_o365_store_connect_folder_summary
+                                               (CamelO365Store *store,
+                                                CamelFolderSummary *folder_summary);
 
 G_END_DECLS
 


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