[evolution-mapi] Derive from EBookMetaBackend and ECalMetaBackend



commit 8041b56dad48a4de55b5386ef25381b4256544a6
Author: Milan Crha <mcrha redhat com>
Date:   Mon May 29 19:02:03 2017 +0200

    Derive from EBookMetaBackend and ECalMetaBackend

 src/addressbook/e-book-backend-mapi-contacts.c | 1088 +-------
 src/addressbook/e-book-backend-mapi-contacts.h |    9 +-
 src/addressbook/e-book-backend-mapi-gal.c      |  322 +--
 src/addressbook/e-book-backend-mapi-gal.h      |   10 +-
 src/addressbook/e-book-backend-mapi.c          | 2129 +++++--------
 src/addressbook/e-book-backend-mapi.h          |  103 +-
 src/calendar/e-cal-backend-mapi.c              | 3900 +++++++-----------------
 src/calendar/e-cal-backend-mapi.h              |    4 +-
 src/libexchangemapi/CMakeLists.txt             |    2 -
 src/libexchangemapi/e-mapi-cal-utils.c         |   57 +-
 src/libexchangemapi/e-mapi-cal-utils.h         |    1 -
 src/libexchangemapi/e-mapi-mail-utils.c        |    2 +-
 src/libexchangemapi/e-mapi-operation-queue.c   |  337 --
 src/libexchangemapi/e-mapi-operation-queue.h   |   72 -
 src/libexchangemapi/e-mapi-utils.c             |    2 +-
 15 files changed, 1897 insertions(+), 6141 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-mapi-contacts.c b/src/addressbook/e-book-backend-mapi-contacts.c
index b1a07f6..8f5a443 100644
--- a/src/addressbook/e-book-backend-mapi-contacts.c
+++ b/src/addressbook/e-book-backend-mapi-contacts.c
@@ -23,1104 +23,30 @@
 
 #include "evolution-mapi-config.h"
 
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <glib/gi18n-lib.h>
-
-#include <sys/time.h>
-
-#include <libedataserver/libedataserver.h>
-#include <libedata-book/libedata-book.h>
-#include <libebook/libebook.h>
-#include <camel/camel.h>
-
 #include "e-book-backend-mapi-contacts.h"
-#include "e-source-mapi-folder.h"
 
 G_DEFINE_TYPE (EBookBackendMAPIContacts, e_book_backend_mapi_contacts, E_TYPE_BOOK_BACKEND_MAPI)
 
 struct _EBookBackendMAPIContactsPrivate
 {
-       mapi_id_t fid;
-       gboolean is_public_folder;
-       gchar *foreign_username; /* NULL, if not a foreign folder */
+       gint32 unused;
 };
 
-static gboolean
-ebbm_contacts_open_folder (EBookBackendMAPIContacts *ebmac,
-                          EMapiConnection *conn,
-                          mapi_object_t *obj_folder,
-                          GCancellable *cancellable,
-                          GError **perror)
-{
-       gboolean res;
-
-       g_return_val_if_fail (ebmac != NULL, FALSE);
-       g_return_val_if_fail (ebmac->priv != NULL, FALSE);
-       g_return_val_if_fail (conn != NULL, FALSE);
-       g_return_val_if_fail (obj_folder != NULL, FALSE);
-
-       if (ebmac->priv->foreign_username)
-               res = e_mapi_connection_open_foreign_folder (conn, ebmac->priv->foreign_username, 
ebmac->priv->fid, obj_folder, cancellable, perror);
-       else if (ebmac->priv->is_public_folder)
-               res = e_mapi_connection_open_public_folder (conn, ebmac->priv->fid, obj_folder, cancellable, 
perror);
-       else
-               res = e_mapi_connection_open_personal_folder (conn, ebmac->priv->fid, obj_folder, 
cancellable, perror);
-
-       return res;
-}
-
-typedef struct {
-       EContact *contact;
-       EBookBackendSqliteDB *db;
-} EMapiCreateitemData;
-
-static gboolean
-ebbm_contact_to_object (EMapiConnection *conn,
-                       TALLOC_CTX *mem_ctx,
-                       EMapiObject **pobject, /* out */
-                       gpointer user_data,
-                       GCancellable *cancellable,
-                       GError **perror)
-{
-       EMapiCreateitemData *mcd = user_data;
-       const gchar *uid = NULL;
-       EContact *old_contact = NULL;
-       gboolean res;
-       GError *error = NULL;
-
-       g_return_val_if_fail (mcd != NULL, FALSE);
-       g_return_val_if_fail (mcd->contact != NULL, FALSE);
-       g_return_val_if_fail (mcd->db != NULL, FALSE);
-       g_return_val_if_fail (conn != NULL, FALSE);
-       g_return_val_if_fail (mem_ctx != NULL, FALSE);
-       g_return_val_if_fail (pobject != NULL, FALSE);
-
-       uid = e_contact_get_const (mcd->contact, E_CONTACT_UID);
-       if (uid)
-               old_contact = e_book_backend_sqlitedb_get_contact (mcd->db, EMA_EBB_CACHE_FOLDERID, uid, 
NULL, NULL, &error);
-
-       if (error) {
-               old_contact = NULL;
-               g_clear_error (&error);
-       }
-
-       res = e_mapi_book_utils_contact_to_object (mcd->contact, old_contact, pobject, mem_ctx, cancellable, 
perror);
-
-       if (old_contact)
-               g_object_unref (old_contact);
-
-       return res;
-}
-
-struct TransferContactData
-{
-       EBookBackendMAPI *ebma;
-       EContact *contact; /* out */
-};
-
-static gboolean
-transfer_contact_cb (EMapiConnection *conn,
-                    TALLOC_CTX *mem_ctx,
-                    /* const */ EMapiObject *object,
-                    guint32 obj_index,
-                    guint32 obj_total,
-                    gpointer user_data,
-                    GCancellable *cancellable,
-                    GError **perror)
-{
-       struct TransferContactData *tc = user_data;
-
-       g_return_val_if_fail (tc != NULL, FALSE);
-       g_return_val_if_fail (tc->ebma != NULL, FALSE);
-       g_return_val_if_fail (object != NULL, FALSE);
-
-       tc->contact = e_mapi_book_utils_contact_from_object (conn, object, e_book_backend_mapi_get_book_uid 
(tc->ebma));
-       if (tc->contact)
-               return e_book_backend_mapi_notify_contact_update (tc->ebma, NULL, tc->contact, obj_index, 
obj_total, FALSE, NULL);
-
-       return TRUE;
-}
-
-static gboolean
-gather_contact_mids_cb (EMapiConnection *conn,
-                       TALLOC_CTX *mem_ctx,
-                       const ListObjectsData *object_data,
-                       guint32 obj_index,
-                       guint32 obj_total,
-                       gpointer user_data,
-                       GCancellable *cancellable,
-                       GError **perror)
-{
-       GSList **pmids = user_data;
-       mapi_id_t *pmid;
-
-       g_return_val_if_fail (object_data != NULL, FALSE);
-       g_return_val_if_fail (pmids != NULL, FALSE);
-
-       pmid = g_new0 (mapi_id_t, 1);
-       *pmid = object_data->mid;
-
-       *pmids = g_slist_prepend (*pmids, pmid);
-
-       return TRUE;
-}
-
-struct TransferContactsData
-{
-       EBookBackendMAPI *ebma;
-       EDataBookView *book_view;
-       gpointer notify_contact_data;
-       GSList **cards;
-};
-
-static gboolean
-transfer_contacts_cb (EMapiConnection *conn,
-                     TALLOC_CTX *mem_ctx,
-                     /* const */ EMapiObject *object,
-                     guint32 obj_index,
-                     guint32 obj_total,
-                     gpointer user_data,
-                     GCancellable *cancellable,
-                     GError **perror)
-{
-       struct TransferContactsData *tcd = user_data;
-       EContact *contact;
-
-       g_return_val_if_fail (tcd != NULL, FALSE);
-       g_return_val_if_fail (object != NULL, FALSE);
-       g_return_val_if_fail (tcd->ebma != NULL, FALSE);
-
-       contact = e_mapi_book_utils_contact_from_object (conn, object, e_book_backend_mapi_get_book_uid 
(tcd->ebma));
-       if (contact) {
-               if (tcd->cards)
-                       *tcd->cards = g_slist_prepend (*tcd->cards, e_vcard_to_string (E_VCARD (contact), 
EVC_FORMAT_VCARD_30));
-
-               if (!e_book_backend_mapi_notify_contact_update (tcd->ebma, tcd->book_view, contact, 
obj_index, obj_total, FALSE, tcd->notify_contact_data)) {
-                       g_object_unref (contact);
-                       return FALSE;
-               }
-
-               g_object_unref (contact);
-       } else {
-               g_debug ("%s: [%d/%d] Failed to transform to contact", G_STRFUNC, obj_index, obj_total);
-       }
-
-       return TRUE;
-}
-
-static gboolean
-gather_known_uids_cb (EMapiConnection *conn,
-                     TALLOC_CTX *mem_ctx,
-                     const ListObjectsData *object_data,
-                     guint32 obj_index,
-                     guint32 obj_total,
-                     gpointer user_data,
-                     GCancellable *cancellable,
-                     GError **perror)
-{
-       struct ListKnownUidsData *lku = user_data;
-       gchar *suid;
-
-       g_return_val_if_fail (lku != NULL, FALSE);
-       g_return_val_if_fail (lku->uid_to_rev != NULL, FALSE);
-
-       suid = e_mapi_util_mapi_id_to_string (object_data->mid);
-       if (suid) {
-               g_hash_table_insert (lku->uid_to_rev, suid, e_mapi_book_utils_timet_to_string 
(object_data->last_modified));
-               if (lku->latest_last_modify < object_data->last_modified)
-                       lku->latest_last_modify = object_data->last_modified;
-       }
-
-       return TRUE;
-}
-
-static void
-ebbmc_server_notification_cb (EMapiConnection *conn,
-                             guint event_mask,
-                             gpointer event_data,
-                             gpointer user_data)
-{
-       EBookBackendMAPI *ebma = user_data;
-       EBookBackendMAPIContactsPrivate *priv;
-       mapi_id_t update_folder1 = 0, update_folder2 = 0;
-
-       g_return_if_fail (ebma != NULL);
-
-       switch (event_mask) {
-       case fnevNewMail:
-       case fnevNewMail | fnevMbit: {
-               struct NewMailNotification *newmail = event_data;
-
-               if (newmail)
-                       update_folder1 = newmail->FID;
-               } break;
-       case fnevObjectCreated:
-       case fnevMbit | fnevObjectCreated: {
-               struct MessageCreatedNotification *msgcreated = event_data;
-
-               if (msgcreated)
-                       update_folder1 = msgcreated->FID;
-               } break;
-       case fnevObjectModified:
-       case fnevMbit | fnevObjectModified: {
-               struct MessageModifiedNotification *msgmodified = event_data;
-
-               if (msgmodified)
-                       update_folder1 = msgmodified->FID;
-               } break;
-       case fnevObjectDeleted:
-       case fnevMbit | fnevObjectDeleted: {
-               struct MessageDeletedNotification *msgdeleted = event_data;
-
-               if (msgdeleted)
-                       update_folder1 = msgdeleted->FID;
-               } break;
-       case fnevObjectMoved:
-       case fnevMbit | fnevObjectMoved: {
-               struct MessageMoveCopyNotification *msgmoved = event_data;
-
-               if (msgmoved) {
-                       update_folder1 = msgmoved->OldFID;
-                       update_folder2 = msgmoved->FID;
-               }
-               } break;
-       case fnevObjectCopied:
-       case fnevMbit | fnevObjectCopied: {
-               struct MessageMoveCopyNotification *msgcopied = event_data;
-
-               if (msgcopied) {
-                       update_folder1 = msgcopied->OldFID;
-                       update_folder2 = msgcopied->FID;
-               }
-               } break;
-       default:
-               break;
-       }
-
-       priv = ((EBookBackendMAPIContacts *) ebma)->priv;
-       if ((priv->fid == update_folder1 || priv->fid == update_folder2) &&
-           e_book_backend_mapi_is_marked_for_offline (ebma))
-               e_book_backend_mapi_refresh_cache (ebma);
-}
-
-static void
-ebbm_contacts_open (EBookBackendMAPI *ebma, GCancellable *cancellable, gboolean only_if_exists, GError 
**perror)
-{
-       ESource *source = e_backend_get_source (E_BACKEND (ebma));
-       ESourceMapiFolder *ext_mapi_folder;
-       EBookBackendMAPIContactsPrivate *priv = ((EBookBackendMAPIContacts *) ebma)->priv;
-       GError *err = NULL;
-
-       if (e_book_backend_is_opened (E_BOOK_BACKEND (ebma))) {
-               if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_open)
-                       E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_open (ebma, 
cancellable, only_if_exists, perror);
-               return;
-       }
-
-       ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
-
-       priv->fid = e_source_mapi_folder_get_id (ext_mapi_folder);
-       priv->is_public_folder = e_source_mapi_folder_is_public (ext_mapi_folder);
-       priv->foreign_username = e_source_mapi_folder_dup_foreign_username (ext_mapi_folder);
-
-       if (priv->foreign_username && !*priv->foreign_username) {
-               g_free (priv->foreign_username);
-               priv->foreign_username = NULL;
-       }
-
-       /* Chain up to parent's op_load_source() method. */
-       if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_open)
-               E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_open (ebma, 
cancellable, only_if_exists, &err);
-
-       if (err)
-               g_propagate_error (perror, err);
-}
-
 static void
-ebbm_contacts_connection_status_changed (EBookBackendMAPI *ebma, gboolean is_online)
+e_book_backend_mapi_contacts_init (EBookBackendMAPIContacts *bbmcontacts)
 {
-       ESource *source;
-       ESourceMapiFolder *ext_mapi_folder;
-
-       e_book_backend_set_writable (E_BOOK_BACKEND (ebma), is_online);
-
-       if (!is_online)
-               return;
-
-       source = e_backend_get_source (E_BACKEND (ebma));
-       ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
-
-       if (e_source_mapi_folder_get_server_notification (ext_mapi_folder)) {
-               EMapiConnection *conn;
-               mapi_object_t obj_folder;
-               gboolean status;
-               GError *mapi_error = NULL;
-
-               e_book_backend_mapi_lock_connection (ebma);
-
-               conn = e_book_backend_mapi_get_connection (ebma, NULL, NULL);
-               if (!conn) {
-                       e_book_backend_mapi_unlock_connection (ebma);
-                       return;
-               }
-
-               status = ebbm_contacts_open_folder (E_BOOK_BACKEND_MAPI_CONTACTS (ebma), conn, &obj_folder, 
NULL, &mapi_error);
-
-               if (status) {
-                       e_mapi_connection_enable_notifications (conn, &obj_folder,
-                               fnevObjectCreated | fnevObjectModified | fnevObjectDeleted | fnevObjectMoved 
| fnevObjectCopied,
-                               NULL, &mapi_error);
+       bbmcontacts->priv = G_TYPE_INSTANCE_GET_PRIVATE (bbmcontacts, E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, 
EBookBackendMAPIContactsPrivate);
 
-                       e_mapi_connection_close_folder (conn, &obj_folder, NULL, &mapi_error);
-               }
-
-               e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-               g_clear_error (&mapi_error);
-
-               g_signal_connect (conn, "server-notification", G_CALLBACK (ebbmc_server_notification_cb), 
ebma);
-
-               e_book_backend_mapi_unlock_connection (ebma);
-       }
-}
-
-static void
-ebbm_contacts_remove (EBookBackendMAPI *ebma, GCancellable *cancellable, GError **error)
-{
-       EBookBackendMAPIContactsPrivate *priv;
-       GError *mapi_error = NULL;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), 
E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       priv = E_BOOK_BACKEND_MAPI_CONTACTS (ebma)->priv;
-       e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_remove)
-               E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_remove (ebma, 
cancellable, &mapi_error);
-
-       if (mapi_error) {
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
-               g_error_free (mapi_error);
-               return;
-       }
-
-       if (!priv->is_public_folder && !priv->foreign_username) {
-               EMapiConnection *conn;
-
-               e_book_backend_mapi_lock_connection (ebma);
-
-               conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-               if (!conn) {
-                       if (!mapi_error)
-                               g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-                       else
-                               mapi_error_to_edb_error (error, mapi_error, 
E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
-                       g_clear_error (&mapi_error);
-               } else {
-                       mapi_object_t *obj_store = NULL;
-
-                       if (e_mapi_connection_peek_store (conn, priv->foreign_username ? FALSE : 
priv->is_public_folder, priv->foreign_username, &obj_store, cancellable, &mapi_error))
-                               e_mapi_connection_remove_folder (conn, obj_store, priv->fid, cancellable, 
&mapi_error);
-
-                       if (mapi_error) {
-                               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, 
_("Failed to remove public folder"));
-                               e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-                               g_error_free (mapi_error);
-                       }
-               }
-
-               e_book_backend_mapi_unlock_connection (ebma);
-       }
-}
-
-static void
-ebbm_contacts_create_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, 
GSList **added_contacts, GError **error)
-{
-       EBookBackendMAPIContacts *ebmac;
-       EBookBackendMAPIContactsPrivate *priv;
-       EMapiConnection *conn;
-       EMapiCreateitemData mcd;
-       GError *mapi_error = NULL;
-       mapi_id_t mid = 0;
-       mapi_object_t obj_folder;
-       gboolean status;
-       gchar *id;
-       EContact *contact;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), 
E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (vcards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (added_contacts != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
-       e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       priv = ebmac->priv;
-       e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       if (vcards->next) {
-               g_propagate_error (error, EDB_ERROR_EX (NOT_SUPPORTED, _("The backend does not support bulk 
additions")));
-               return;
-       }
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       contact = e_contact_new_from_vcard (vcards->data);
-       if (!contact) {
-               g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               e_book_backend_mapi_unlock_connection (ebma);
-               return;
-       }
-
-       e_book_backend_mapi_get_db (ebma, &mcd.db);
-       mcd.contact = contact;
-
-       status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);
-
-       if (status) {
-               e_mapi_connection_create_object (conn, &obj_folder, E_MAPI_CREATE_FLAG_NONE,
-                                                ebbm_contact_to_object, &mcd,
-                                                &mid, cancellable, &mapi_error);
-               e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-       }
-
-       e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-       e_book_backend_mapi_unlock_connection (ebma);
-
-       if (!mid) {
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to 
create item on a server"));
-
-               if (mapi_error)
-                       g_error_free (mapi_error);
-
-               g_object_unref (contact);
-               return;
-       }
-
-       id = e_mapi_util_mapi_id_to_string (mid);
-
-       /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
-       e_contact_set (contact, E_CONTACT_UID, id);
-       e_contact_set (contact, E_CONTACT_BOOK_UID, e_book_backend_mapi_get_book_uid (ebma));
-
-       g_free (id);
-
-       *added_contacts = g_slist_append (NULL, contact);
-}
-
-static void
-ebbm_contacts_remove_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *id_list, 
GSList **removed_ids, GError **error)
-{
-       EBookBackendMAPIContacts *ebmac;
-       EBookBackendMAPIContactsPrivate *priv;
-       EMapiConnection *conn;
-       GError *mapi_error = NULL;
-       GSList *to_remove;
-       const GSList *l;
-       mapi_object_t obj_folder;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), 
E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (id_list != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (removed_ids != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
-       e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       priv = ebmac->priv;
-       e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       to_remove = NULL;
-       for (l = id_list; l; l = l->next) {
-               const gchar *uid = l->data;
-               mapi_id_t *pmid = g_new0 (mapi_id_t, 1);
-
-               if (e_mapi_util_mapi_id_from_string (uid, pmid)) {
-                       to_remove = g_slist_prepend (to_remove, pmid);
-
-                       *removed_ids = g_slist_prepend (*removed_ids, g_strdup (uid));
-               } else {
-                       g_debug ("%s: Failed to decode MID from '%s'", G_STRFUNC, uid);
-                       g_free (pmid);
-               }
-       }
-
-       if (ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error)) {
-               e_mapi_connection_remove_items (conn, &obj_folder, to_remove, cancellable, &mapi_error);
-               e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-       }
-
-       e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-       e_book_backend_mapi_unlock_connection (ebma);
-
-       if (mapi_error) {
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
-
-               g_error_free (mapi_error);
-
-               g_slist_foreach (*removed_ids, (GFunc) g_free, NULL);
-               g_slist_free (*removed_ids);
-               *removed_ids = NULL;
-       }
-
-       g_slist_foreach (to_remove, (GFunc) g_free, NULL);
-       g_slist_free (to_remove);
-}
-
-static void
-ebbm_contacts_modify_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, 
GSList **modified_contacts, GError **error)
-{
-       EBookBackendMAPIContacts *ebmac;
-       EBookBackendMAPIContactsPrivate *priv;
-       EMapiConnection *conn;
-       EMapiCreateitemData mcd;
-       EContact *contact;
-       GError *mapi_error = NULL;
-       mapi_id_t mid;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), 
E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (vcards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (modified_contacts != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
-       e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       priv = ebmac->priv;
-       e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       if (vcards->next != NULL) {
-               g_propagate_error (error, EDB_ERROR_EX (NOT_SUPPORTED, _("The backend does not support bulk 
modifications")));
-               return;
-       }
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       contact = e_contact_new_from_vcard (vcards->data);
-       if (!contact) {
-               g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               e_book_backend_mapi_unlock_connection (ebma);
-               return;
-       }
-
-       e_book_backend_mapi_get_db (ebma, &mcd.db);
-       mcd.contact = contact;
-
-       if (e_mapi_util_mapi_id_from_string (e_contact_get_const (contact, E_CONTACT_UID), &mid)) {
-               mapi_object_t obj_folder;
-               gboolean status;
-
-               status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);
-
-               if (status) {
-                       status = e_mapi_connection_modify_object (conn, &obj_folder, mid,
-                                                                 ebbm_contact_to_object, &mcd,
-                                                                 cancellable, &mapi_error);
-
-                       e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-               }
-
-               e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-               if (!status) {
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed 
to modify item on a server"));
-                       if (mapi_error)
-                               g_error_free (mapi_error);
-
-                       g_object_unref (contact);
-               } else {
-                       *modified_contacts = g_slist_append (NULL, contact);
-               }
-       } else {
-               g_debug ("%s: Failed to decode MID from '%s'", G_STRFUNC, (const gchar *) e_contact_get_const 
(contact, E_CONTACT_UID));
-       }
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static void
-ebbm_contacts_get_contact (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *id, gchar 
**vcard, GError **error)
-{
-       EBookBackendMAPIContacts *ebmac;
-       EBookBackendMAPIContactsPrivate *priv;
-       EMapiConnection *conn;
-       mapi_id_t mid;
-       mapi_object_t obj_folder;
-       struct TransferContactData tc = { 0 };
-       gboolean status, has_obj_folder;
-       GError *mapi_error = NULL;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), 
E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (id != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (vcard != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
-       e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       priv = ebmac->priv;
-       e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact)
-               E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact (ebma, 
cancellable, id, vcard, &mapi_error);
-
-       if (mapi_error) {
-               g_propagate_error (error, mapi_error);
-               return;
-       }
-
-       /* found in a cache */
-       if (*vcard)
-               return;
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);
-       has_obj_folder = status;
-
-       if (status) {
-               status = e_mapi_util_mapi_id_from_string (id, &mid);
-               if (!status) {
-                       g_debug ("%s: Failed to decode MID from '%s'", G_STRFUNC, id);
-               }
-       }
-
-       if (status) {
-               tc.ebma = ebma;
-               tc.contact = NULL;
-
-               e_mapi_connection_transfer_object (conn, &obj_folder, mid, transfer_contact_cb, &tc, 
cancellable, &mapi_error);
-       }
-
-       if (has_obj_folder)
-               e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-
-       if (tc.contact) {
-               *vcard =  e_vcard_to_string (E_VCARD (tc.contact), EVC_FORMAT_VCARD_30);
-               g_object_unref (tc.contact);
-       } else {
-               e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-
-               if (!mapi_error || mapi_error->code == MAPI_E_NOT_FOUND) {
-                       g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND));
-               } else {
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND, 
NULL);
-               }
-
-               if (mapi_error)
-                       g_error_free (mapi_error);
-       }
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static void
-ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *query, 
GSList **vCards, GError **error)
-{
-       EBookBackendMAPIContacts *ebmac;
-       EBookBackendMAPIContactsPrivate *priv;
-       EMapiConnection *conn;
-       GError *mapi_error = NULL;
-       gboolean status;
-       mapi_object_t obj_folder;
-       GSList *mids = NULL;
-       struct TransferContactsData tcd = { 0 };
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), 
E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (query != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (vCards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
-       e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       priv = ebmac->priv;
-       e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact_list)
-               E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact_list 
(ebma, cancellable, query, vCards, &mapi_error);
-
-       if (mapi_error) {
-               g_propagate_error (error, mapi_error);
-               return;
-       }
-
-       /* found some in cache, thus use them */
-       if (*vCards)
-               return;
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       tcd.ebma = ebma;
-       tcd.cards = vCards;
-
-       status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);
-
-       if (status) {
-               status = e_mapi_connection_list_objects (conn, &obj_folder,
-                                                        e_mapi_book_utils_build_sexp_restriction, (gpointer) 
query,
-                                                        gather_contact_mids_cb, &mids,
-                                                        cancellable, &mapi_error);
-
-               if (mids)
-                       status = e_mapi_connection_transfer_objects (conn, &obj_folder, mids, 
transfer_contacts_cb, &tcd, cancellable, &mapi_error);
-
-               e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-
-               g_slist_free_full (mids, g_free);
-       }
-
-       e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-
-       if (!status) {
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to 
fetch items from a server"));
-               if (mapi_error)
-                       g_error_free (mapi_error);
-       }
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static gchar *
-ebbm_contacts_get_status_message (EBookBackendMAPI *ebma, gint index, gint total)
-{
-       if (index <= 0)
-               return NULL;
-
-       if (total <= 0)
-               return g_strdup_printf (
-                       /* Translators : This is used to cache the downloaded contacts from a server.
-                          %d is an index of the contact. */
-                       _("Caching contact %d"), index);
-
-       return g_strdup_printf (
-               /* Translators : This is used to cache the downloaded contacts from a server.
-                  The first %d is an index of the contact,
-                  the second %d is total count of conacts on the server. */
-               _("Caching contact %d/%d"), index, total);
-}
-
-static void
-ebbm_contacts_get_contacts_count (EBookBackendMAPI *ebma,
-                                 guint32 *obj_total,
-                                 GCancellable *cancellable,
-                                 GError **error)
-{
-       EBookBackendMAPIContacts *ebmac;
-       EMapiConnection *conn;
-       gboolean status;
-       mapi_object_t obj_folder;
-       GError *mapi_error = NULL;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (obj_total != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
-       e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (ebmac->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);
-
-       if (status) {
-               struct FolderBasicPropertiesData fbp = { 0 };
-
-               status = e_mapi_connection_get_folder_properties (conn, &obj_folder, NULL, NULL,
-                       e_mapi_utils_get_folder_basic_properties_cb, &fbp,
-                       cancellable, &mapi_error);
-               if (status)
-                       *obj_total = fbp.obj_total;
-               
-               e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-       }
-
-       e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-
-       if (mapi_error) {
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to 
count server contacts"));
-               g_error_free (mapi_error);
-       }
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static void
-ebbm_contacts_list_known_uids (EBookBackendMAPI *ebma,
-                              BuildRestrictionsCB build_rs_cb,
-                              gpointer build_rs_cb_data,
-                              struct ListKnownUidsData *lku,
-                              GCancellable *cancellable,
-                              GError **error)
-{
-       EBookBackendMAPIContacts *ebmac;
-       EMapiConnection *conn;
-       gboolean status;
-       mapi_object_t obj_folder;
-       GError *mapi_error = NULL;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), 
E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (lku != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (lku->uid_to_rev != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
-       e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (ebmac->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);
-
-       if (status) {
-               status = e_mapi_connection_list_objects (conn, &obj_folder, build_rs_cb, build_rs_cb_data,
-                                                        gather_known_uids_cb, lku,
-                                                        cancellable, &mapi_error);
-
-               e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-       }
-
-       e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-
-       if (mapi_error) {
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to list 
items from a server"));
-               g_error_free (mapi_error);
-       }
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static void
-ebbm_contacts_transfer_contacts (EBookBackendMAPI *ebma,
-                                const GSList *uids,
-                                EDataBookView *book_view,
-                                gpointer notify_contact_data,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-       EBookBackendMAPIContacts *ebmac;
-       EBookBackendMAPIContactsPrivate *priv;
-       EMapiConnection *conn;
-       struct TransferContactsData tcd = { 0 };
-       mapi_object_t obj_folder;
-       gboolean status;
-       GError *mapi_error = NULL;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), 
E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
-       e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       priv = ebmac->priv;
-       e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       tcd.ebma = ebma;
-       tcd.book_view = book_view;
-       tcd.notify_contact_data = notify_contact_data;
-
-       status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);
-
-       if (status) {
-               GSList *mids = NULL;
-               const GSList *iter;
-
-               for (iter = uids; iter; iter = iter->next) {
-                       const gchar *uid_str = iter->data;
-                       mapi_id_t mid, *pmid;
-
-                       if (!uid_str || !e_mapi_util_mapi_id_from_string (uid_str, &mid))
-                               continue;
-
-                       pmid = g_new0 (mapi_id_t, 1);
-                       *pmid = mid;
-
-                       mids = g_slist_prepend (mids, pmid);
-               }
-
-               if (mids)
-                       status = e_mapi_connection_transfer_objects (conn, &obj_folder, mids, 
transfer_contacts_cb, &tcd, cancellable, &mapi_error);
-
-               e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-
-               g_slist_free_full (mids, g_free);
-       }
-
-       e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-
-       if (!status) {
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to 
transfer contacts from a server"));
-
-               if (mapi_error)
-                       g_error_free (mapi_error);
-       }
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static void
-e_book_backend_mapi_contacts_init (EBookBackendMAPIContacts *backend)
-{
-       backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, 
EBookBackendMAPIContactsPrivate);
-
-       backend->priv->foreign_username = NULL;
-}
-
-static void
-ebbm_contacts_finalize (GObject *object)
-{
-       EBookBackendMAPIContactsPrivate *priv;
-
-       priv = E_BOOK_BACKEND_MAPI_CONTACTS (object)->priv;
-
-       g_free (priv->foreign_username);
-       priv->foreign_username = NULL;
-
-       G_OBJECT_CLASS (e_book_backend_mapi_contacts_parent_class)->finalize (object);
+       e_book_backend_mapi_set_is_gal (E_BOOK_BACKEND_MAPI (bbmcontacts), FALSE);
 }
 
 static void
 e_book_backend_mapi_contacts_class_init (EBookBackendMAPIContactsClass *klass)
 {
-       EBookBackendMAPIClass *parent_class;
-       GObjectClass *object_class;
+       EBookMetaBackendClass *meta_backend_class;
 
        g_type_class_add_private (klass, sizeof (EBookBackendMAPIContactsPrivate));
 
-       object_class = G_OBJECT_CLASS (klass);
-       object_class->finalize = ebbm_contacts_finalize;
-
-       parent_class = E_BOOK_BACKEND_MAPI_CLASS (klass);
-
-       /* Set the virtual methods. */
-       parent_class->op_open                           = ebbm_contacts_open;
-       parent_class->op_remove                         = ebbm_contacts_remove;
-       parent_class->op_create_contacts                = ebbm_contacts_create_contacts;
-       parent_class->op_remove_contacts                = ebbm_contacts_remove_contacts;
-       parent_class->op_modify_contacts                = ebbm_contacts_modify_contacts;
-       parent_class->op_get_contact                    = ebbm_contacts_get_contact;
-       parent_class->op_get_contact_list               = ebbm_contacts_get_contact_list;
-
-       parent_class->op_connection_status_changed      = ebbm_contacts_connection_status_changed;
-       parent_class->op_get_status_message             = ebbm_contacts_get_status_message;
-       parent_class->op_get_contacts_count             = ebbm_contacts_get_contacts_count;
-       parent_class->op_list_known_uids                = ebbm_contacts_list_known_uids;
-       parent_class->op_transfer_contacts              = ebbm_contacts_transfer_contacts;
-}
-
-EBookBackend *
-e_book_backend_mapi_contacts_new (void)
-{
-       return g_object_new (E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, NULL);
+       meta_backend_class = E_BOOK_META_BACKEND_CLASS (klass);
+       meta_backend_class->backend_factory_type_name = "EBookBackendMapiContactsFactory";
 }
diff --git a/src/addressbook/e-book-backend-mapi-contacts.h b/src/addressbook/e-book-backend-mapi-contacts.h
index c09723c..1cc4769 100644
--- a/src/addressbook/e-book-backend-mapi-contacts.h
+++ b/src/addressbook/e-book-backend-mapi-contacts.h
@@ -21,8 +21,8 @@
  *
  */
 
-#ifndef __E_BOOK_BACKEND_MAPI_CONTACTS_H__
-#define __E_BOOK_BACKEND_MAPI_CONTACTS_H__
+#ifndef E_BOOK_BACKEND_MAPI_CONTACTS_H
+#define E_BOOK_BACKEND_MAPI_CONTACTS_H
 
 #include "e-book-backend-mapi.h"
 
@@ -39,7 +39,7 @@ typedef struct _EBookBackendMAPIContactsPrivate EBookBackendMAPIContactsPrivate;
 
 typedef struct
 {
-       EBookBackendMAPI                 parent_object;
+       EBookBackendMAPI parent_object;
        EBookBackendMAPIContactsPrivate *priv;
 } EBookBackendMAPIContacts;
 
@@ -48,9 +48,8 @@ typedef struct
        EBookBackendMAPIClass parent_class;
 } EBookBackendMAPIContactsClass;
 
-EBookBackend *e_book_backend_mapi_contacts_new      (void);
 GType         e_book_backend_mapi_contacts_get_type (void);
 
 G_END_DECLS
 
-#endif /* __E_BOOK_BACKEND_MAPI_CONTACTS_H__ */
+#endif /* E_BOOK_BACKEND_MAPI_CONTACTS_H */
diff --git a/src/addressbook/e-book-backend-mapi-gal.c b/src/addressbook/e-book-backend-mapi-gal.c
index e189599..5204cf2 100644
--- a/src/addressbook/e-book-backend-mapi-gal.c
+++ b/src/addressbook/e-book-backend-mapi-gal.c
@@ -1,5 +1,8 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
@@ -16,341 +19,34 @@
  *
  * Authors:
  *    Bharath Acharya <abharath novell com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #include "evolution-mapi-config.h"
 
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <glib/gi18n-lib.h>
-
-#include <sys/time.h>
-
-#include <libedataserver/libedataserver.h>
-#include <libedata-book/libedata-book.h>
-#include <libebook/libebook.h>
-
 #include "e-book-backend-mapi-gal.h"
-#include "e-source-mapi-folder.h"
-
-/* default value for "partial-count", upper bound of objects to download during partial search */
-#define DEFAULT_PARTIAL_COUNT 50
 
 G_DEFINE_TYPE (EBookBackendMAPIGAL, e_book_backend_mapi_gal, E_TYPE_BOOK_BACKEND_MAPI)
 
 struct _EBookBackendMAPIGALPrivate
 {
-       /* nothing to store locally at the moment,
-          but keep it ready for any later need */
-
        gint32 unused;
 };
 
-struct TransferGalData
-{
-       EBookBackendMAPI *ebma;
-       EDataBookView *book_view;
-       gpointer notify_contact_data;
-};
-
-static gboolean
-transfer_gal_cb (EMapiConnection *conn,
-                TALLOC_CTX *mem_ctx,
-                /* const */ EMapiObject *object,
-                guint32 obj_index,
-                guint32 obj_total,
-                gpointer user_data,
-                GCancellable *cancellable,
-                GError **perror)
-{
-       struct TransferGalData *tg = user_data;
-       EContact *contact;
-
-       g_return_val_if_fail (conn != NULL, FALSE);
-       g_return_val_if_fail (object != NULL, FALSE);
-       g_return_val_if_fail (tg != NULL, FALSE);
-
-       contact = e_mapi_book_utils_contact_from_object (conn, object, e_book_backend_mapi_get_book_uid 
(tg->ebma));
-       if (!contact) {
-               /* this is GAL, just ignore them */
-               return TRUE;
-       }
-
-       if (!e_book_backend_mapi_notify_contact_update (tg->ebma, tg->book_view, contact, obj_index, 
obj_total, FALSE, tg->notify_contact_data)) {
-               g_object_unref (contact);
-               return FALSE;
-       }
-
-       g_object_unref (contact);
-
-       return TRUE;
-}
-
-static gboolean
-list_gal_uids_cb (EMapiConnection *conn,
-                 TALLOC_CTX *mem_ctx,
-                 const ListObjectsData *object_data,
-                 guint32 obj_index,
-                 guint32 obj_total,
-                 gpointer user_data,
-                 GCancellable *cancellable,
-                 GError **perror)
-{
-       gchar *uid;
-       struct ListKnownUidsData *lku = user_data;
-
-       g_return_val_if_fail (conn != NULL, FALSE);
-       g_return_val_if_fail (object_data != NULL, FALSE);
-       g_return_val_if_fail (lku != NULL, FALSE);
-
-       uid = e_mapi_util_mapi_id_to_string (object_data->mid);
-       if (uid) {
-               if (lku->latest_last_modify < object_data->last_modified)
-                       lku->latest_last_modify = object_data->last_modified;
-
-               g_hash_table_insert (lku->uid_to_rev, uid, e_mapi_book_utils_timet_to_string 
(object_data->last_modified));
-       }
-
-       return TRUE;
-}
-
-static void
-ebbm_gal_create_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, GSList 
**added_contacts, GError **error)
-{
-       g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
-}
-
-static void
-ebbm_gal_remove_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *ids, GSList 
**removed_ids, GError **error)
-{
-       g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
-}
-
 static void
-ebbm_gal_modify_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, GSList 
**modified_contacts, GError **error)
-{
-       g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
-}
-
-static gchar *
-ebbm_gal_get_status_message (EBookBackendMAPI *ebma, gint index, gint total)
+e_book_backend_mapi_gal_init (EBookBackendMAPIGAL *bbmgal)
 {
-       if (index <= 0)
-               return NULL;
-
-       if (total <= 0)
-               return g_strdup_printf (
-                       /* Translators : This is used to cache the downloaded contacts from GAL.
-                          %d is an index of the GAL entry. */
-                       _("Caching GAL contact %d"), index);
+       bbmgal->priv = G_TYPE_INSTANCE_GET_PRIVATE (bbmgal, E_TYPE_BOOK_BACKEND_MAPI_GAL, 
EBookBackendMAPIGALPrivate);
 
-       return g_strdup_printf (
-               /* Translators : This is used to cache the downloaded contacts from GAL.
-                  The first %d is an index of the GAL entry,
-                  the second %d is total count of entries in GAL. */
-               _("Caching GAL contact %d/%d"), index, total);
-}
-
-static void
-ebbm_gal_transfer_contacts (EBookBackendMAPI *ebma,
-                           const GSList *uids,
-                           EDataBookView *book_view,
-                           gpointer notify_contact_data,
-                           GCancellable *cancellable,
-                           GError **error)
-{
-       GError *mapi_error = NULL;
-       struct TransferGalData tg = { 0 };
-       EMapiConnection *conn;
-       ESource *source;
-       ESourceMapiFolder *ext_mapi_folder;
-       GSList *get_mids = NULL;
-       const GSList *iter;
-       gint partial_count = -1;
-       gboolean status;
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       source = e_backend_get_source (E_BACKEND (ebma));
-       ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
-
-       if (ext_mapi_folder &&
-           !e_book_backend_mapi_is_marked_for_offline (ebma) &&
-           e_source_mapi_folder_get_allow_partial (ext_mapi_folder)) {
-               partial_count = e_source_mapi_folder_get_partial_count (ext_mapi_folder);
-
-               if (partial_count <= 0)
-                       partial_count = DEFAULT_PARTIAL_COUNT;
-       }
-
-       for (iter = uids; iter && (partial_count == -1 || partial_count > 0); iter = iter->next) {
-               mapi_id_t *pmid, mid;
-
-               if (e_mapi_util_mapi_id_from_string  (iter->data, &mid)) {
-                       pmid = g_new0 (mapi_id_t, 1);
-                       *pmid = mid;
-
-                       get_mids = g_slist_prepend (get_mids, pmid);
-
-                       if (partial_count > 0)
-                               partial_count--;
-               }
-       }
-
-       tg.ebma = ebma;
-       tg.book_view = book_view;
-       tg.notify_contact_data = notify_contact_data;
-
-       status = e_mapi_connection_transfer_gal_objects (conn, get_mids, NULL, NULL, transfer_gal_cb, &tg, 
cancellable, &mapi_error);
-
-       if (mapi_error) {
-               e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to 
fetch GAL entries"));
-               g_error_free (mapi_error);
-       } else if (!status) {
-               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
-       }
-
-       g_slist_free_full (get_mids, g_free);
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static void
-ebbm_gal_get_contacts_count (EBookBackendMAPI *ebma,
-                            guint32 *obj_total,
-                            GCancellable *cancellable,
-                            GError **error)
-{
-       EMapiConnection *conn;
-       GError *mapi_error = NULL;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (obj_total != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       if (!e_mapi_connection_count_gal_objects (conn, obj_total, cancellable, &mapi_error))
-               *obj_total = -1;
-
-       e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-       if (mapi_error) {
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
-               g_clear_error (&mapi_error);
-       }
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static void
-ebbm_gal_list_known_uids (EBookBackendMAPI *ebma,
-                         BuildRestrictionsCB build_rs_cb,
-                         gpointer build_rs_cb_data,
-                         struct ListKnownUidsData *lku,
-                         GCancellable *cancellable,
-                         GError **error)
-{
-       EMapiConnection *conn;
-       GError *mapi_error = NULL;
-
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (lku != NULL);
-       g_return_if_fail (lku->uid_to_rev != NULL);
-
-       e_book_backend_mapi_lock_connection (ebma);
-
-       conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
-       if (!conn) {
-               e_book_backend_mapi_unlock_connection (ebma);
-
-               if (!mapi_error)
-                       g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               else
-                       mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, 
NULL);
-               g_clear_error (&mapi_error);
-
-               return;
-       }
-
-       e_mapi_connection_list_gal_objects (conn, build_rs_cb, build_rs_cb_data, list_gal_uids_cb, lku, 
cancellable, &mapi_error);
-
-       if (mapi_error) {
-               e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
-               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to 
fetch GAL entries"));
-               g_error_free (mapi_error);
-       }
-
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static void
-e_book_backend_mapi_gal_init (EBookBackendMAPIGAL *backend)
-{
-       backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_MAPI_GAL, 
EBookBackendMAPIGALPrivate);
+       e_book_backend_mapi_set_is_gal (E_BOOK_BACKEND_MAPI (bbmgal), TRUE);
 }
 
 static void
 e_book_backend_mapi_gal_class_init (EBookBackendMAPIGALClass *klass)
 {
-       EBookBackendMAPIClass *parent_class;
+       EBookMetaBackendClass *meta_backend_class;
 
        g_type_class_add_private (klass, sizeof (EBookBackendMAPIGALPrivate));
 
-       parent_class = E_BOOK_BACKEND_MAPI_CLASS (klass);
-
-       /* Set the virtual methods. */
-       parent_class->op_create_contacts        = ebbm_gal_create_contacts;
-       parent_class->op_remove_contacts        = ebbm_gal_remove_contacts;
-       parent_class->op_modify_contacts        = ebbm_gal_modify_contacts;
-
-       parent_class->op_get_status_message     = ebbm_gal_get_status_message;
-       parent_class->op_get_contacts_count     = ebbm_gal_get_contacts_count;
-       parent_class->op_list_known_uids        = ebbm_gal_list_known_uids;
-       parent_class->op_transfer_contacts      = ebbm_gal_transfer_contacts;
-}
-
-/**
- * e_book_backend_mapi_gal_new:
- */
-EBookBackend *
-e_book_backend_mapi_gal_new (void)
-{
-       EBookBackendMAPIGAL *backend;
-
-       backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPI_GAL, NULL);
-
-       return E_BOOK_BACKEND (backend);
+       meta_backend_class = E_BOOK_META_BACKEND_CLASS (klass);
+       meta_backend_class->backend_factory_type_name = "EBookBackendMapiGalFactory";
 }
diff --git a/src/addressbook/e-book-backend-mapi-gal.h b/src/addressbook/e-book-backend-mapi-gal.h
index e9f1e82..fdec7dc 100644
--- a/src/addressbook/e-book-backend-mapi-gal.h
+++ b/src/addressbook/e-book-backend-mapi-gal.h
@@ -21,8 +21,8 @@
  *
  */
 
-#ifndef __E_BOOK_BACKEND_MAPI_GAL_H__
-#define __E_BOOK_BACKEND_MAPI_GAL_H__
+#ifndef E_BOOK_BACKEND_MAPI_GAL_H
+#define E_BOOK_BACKEND_MAPI_GAL_H
 
 #include "e-book-backend-mapi.h"
 
@@ -37,7 +37,7 @@ G_BEGIN_DECLS
 typedef struct _EBookBackendMAPIGALPrivate EBookBackendMAPIGALPrivate;
 
 typedef struct {
-       EBookBackendMAPI            parent_object;
+       EBookBackendMAPI parent_object;
        EBookBackendMAPIGALPrivate *priv;
 } EBookBackendMAPIGAL;
 
@@ -45,10 +45,8 @@ typedef struct {
        EBookBackendMAPIClass parent_class;
 } EBookBackendMAPIGALClass;
 
-EBookBackend *e_book_backend_mapi_gal_new      (void);
 GType         e_book_backend_mapi_gal_get_type (void);
 
 G_END_DECLS
 
-#endif /* __E_BOOK_BACKEND_MAPI_GAL_H__ */
-
+#endif /* E_BOOK_BACKEND_MAPI_GAL_H */
diff --git a/src/addressbook/e-book-backend-mapi.c b/src/addressbook/e-book-backend-mapi.c
index 355bae8..22bdd32 100644
--- a/src/addressbook/e-book-backend-mapi.c
+++ b/src/addressbook/e-book-backend-mapi.c
@@ -1,5 +1,8 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
@@ -16,9 +19,6 @@
  *
  * Authors:
  *    Srinivasa Ragavan <sragavan novell com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #include "evolution-mapi-config.h"
@@ -33,41 +33,85 @@
 #include <libedataserver/libedataserver.h>
 #include <camel/camel.h>
 
-#include <e-mapi-operation-queue.h>
-
 #include "e-mapi-utils.h"
 #include "e-mapi-defs.h"
+#include "e-source-mapi-folder.h"
 
 #include "e-book-backend-mapi.h"
 
-G_DEFINE_TYPE (EBookBackendMAPI, e_book_backend_mapi, E_TYPE_BOOK_BACKEND)
+/* default value for "partial-count", upper bound of objects to download during partial search */
+#define DEFAULT_PARTIAL_COUNT 50
+
+#define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
+#define EDB_ERROR_EX(_code, _msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg)
 
 struct _EBookBackendMAPIPrivate
 {
-       EMapiOperationQueue *op_queue;
-
        GRecMutex conn_lock;
        EMapiConnection *conn;
-       gchar *book_uid;
 
-       GThread *update_cache_thread;
-       GCancellable *update_cache;
-       time_t last_update_cache;
+       gboolean is_gal;
+};
 
-       EBookBackendSqliteDB *db;
+G_DEFINE_TYPE (EBookBackendMAPI, e_book_backend_mapi, E_TYPE_BOOK_META_BACKEND)
 
-       glong last_db_commit_time; /* when committed changes to db */
+static void
+ebb_mapi_error_to_edb_error (GError **perror,
+                            const GError *mapi_error,
+                            EDataBookStatus code,
+                            const gchar *context)
+{
+       gchar *err_msg = NULL;
 
-       guint32 last_server_contact_count;
-       time_t last_modify_time;
-       gboolean server_dirty;
+       if (!perror)
+               return;
 
-       GHashTable *running_views; /* EDataBookView => GCancellable */
-       GMutex running_views_lock;
-};
+       if (g_error_matches (mapi_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_propagate_error (perror, g_error_copy (mapi_error));
+               return;
+       }
+
+       if (code == E_DATA_BOOK_STATUS_OTHER_ERROR && mapi_error && mapi_error->domain == E_MAPI_ERROR) {
+               /* Change error to more accurate only with OTHER_ERROR */
+               switch (mapi_error->code) {
+               case MAPI_E_PASSWORD_CHANGE_REQUIRED:
+               case MAPI_E_PASSWORD_EXPIRED:
+                       code = E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED;
+                       break;
+               case ecRpcFailed:
+                       code = E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (context)
+               err_msg = g_strconcat (context, mapi_error ? ": " : NULL, mapi_error ? mapi_error->message : 
NULL, NULL);
+
+       g_propagate_error (perror, e_data_book_create_error (code, err_msg ? err_msg : mapi_error ? 
mapi_error->message : _("Unknown error")));
+
+       g_free (err_msg);
+}
+
+static void
+ebb_mapi_lock_connection (EBookBackendMAPI *bbmapi)
+{
+       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
+
+       g_rec_mutex_lock (&bbmapi->priv->conn_lock);
+}
+
+static void
+ebb_mapi_unlock_connection (EBookBackendMAPI *bbmapi)
+{
+       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
+
+       g_rec_mutex_unlock (&bbmapi->priv->conn_lock);
+}
 
 static CamelMapiSettings *
-ebbm_get_collection_settings (EBookBackendMAPI *ebbm)
+ebb_mapi_get_collection_settings (EBookBackendMAPI *ebbm)
 {
        ESource *source;
        ESource *collection;
@@ -95,1217 +139,922 @@ ebbm_get_collection_settings (EBookBackendMAPI *ebbm)
        return CAMEL_MAPI_SETTINGS (settings);
 }
 
-static glong
-get_current_time_ms (void)
+static gboolean
+ebb_mapi_contacts_open_folder (EBookBackendMAPI *bbmapi,
+                              mapi_object_t *out_obj_folder,
+                              GCancellable *cancellable,
+                              GError **error)
 {
-       GTimeVal tv;
-
-       g_get_current_time (&tv);
+       ESource *source;
+       ESourceMapiFolder *ext_mapi_folder;
+       mapi_id_t fid;
+       gchar *foreign_username;
+       gboolean success;
 
-       return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
+       g_return_val_if_fail (bbmapi->priv->conn != NULL, FALSE);
+       g_return_val_if_fail (out_obj_folder != NULL, FALSE);
 
-static EDataBookView *
-ebbm_pick_book_view (EBookBackendMAPI *ebma)
-{
-       EDataBookView *pick = NULL;
-       GList *list;
+       source = e_backend_get_source (E_BACKEND (bbmapi));
+       ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 
-       list = e_book_backend_list_views (E_BOOK_BACKEND (ebma));
+       fid = e_source_mapi_folder_get_id (ext_mapi_folder);
+       foreign_username = e_source_mapi_folder_dup_foreign_username (ext_mapi_folder);
 
-       if (list != NULL) {
-               /* Note we return a new reference. */
-               pick = g_object_ref (list->data);
-       }
+       if (foreign_username && *foreign_username)
+               success = e_mapi_connection_open_foreign_folder (bbmapi->priv->conn, foreign_username, fid, 
out_obj_folder, cancellable, error);
+       else if (e_source_mapi_folder_is_public (ext_mapi_folder))
+               success = e_mapi_connection_open_public_folder (bbmapi->priv->conn, fid, out_obj_folder, 
cancellable, error);
+       else
+               success = e_mapi_connection_open_personal_folder (bbmapi->priv->conn, fid, out_obj_folder, 
cancellable, error);
 
-       g_list_free_full (list, g_object_unref);
+       g_free (foreign_username);
 
-       return pick;
+       return success;
 }
 
 static void
-complete_views (EBookBackendMAPI *ebma)
+ebb_mapi_maybe_disconnect (EBookBackendMAPI *bbmapi,
+                          const GError *mapi_error)
 {
-       GList *list, *link;
-
-       list = e_book_backend_list_views (E_BOOK_BACKEND (ebma));
-
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               EDataBookView *view = E_DATA_BOOK_VIEW (link->data);
+       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
 
-               if (e_book_backend_mapi_book_view_is_running (ebma, view))
-                       e_book_backend_mapi_update_view_by_cache (ebma, view, NULL);
+       /* no error or already disconnected */
+       if (!mapi_error || !bbmapi->priv->conn)
+               return;
 
-               e_data_book_view_notify_complete (view, NULL);
+       if (g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed) ||
+           g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_CALL_FAILED)) {
+               e_mapi_connection_disconnect (bbmapi->priv->conn,
+                       !g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed),
+                       NULL, NULL);
+               g_clear_object (&bbmapi->priv->conn);
        }
-
-       g_list_free_full (list, g_object_unref);
 }
 
-static void
-ebbm_notify_connection_status (EBookBackendMAPI *ebma, gboolean is_online)
+static gboolean
+ebb_mapi_is_marked_for_offline (EBookBackendMAPI *bbmapi)
 {
-       EBookBackendMAPIClass *ebmac;
+       ESource *source;
+       ESourceOffline *offline_extension;
+
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
 
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+       source = e_backend_get_source (E_BACKEND (bbmapi));
 
-       ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
-       g_return_if_fail (ebmac != NULL);
+       offline_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_OFFLINE);
 
-       if (ebmac->op_connection_status_changed)
-               ebmac->op_connection_status_changed (ebma, is_online);
+       return e_source_offline_get_stay_synchronized (offline_extension);
 }
 
 static void
-ebbm_transfer_contacts (EBookBackendMAPI *ebma,
-                       const GSList *uids,
-                       EDataBookView *book_view,
-                       GCancellable *cancellable,
-                       GError **error)
+ebb_mapi_server_notification_cb (EMapiConnection *conn,
+                                guint event_mask,
+                                gpointer event_data,
+                                gpointer user_data)
 {
-       EBookBackendMAPIClass *ebmac;
-       glong last_notification = 0;
-
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (ebma->priv != NULL);
-       g_return_if_fail (ebma->priv->conn != NULL);
-
-       ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
-       g_return_if_fail (ebmac != NULL);
-       g_return_if_fail (ebmac->op_transfer_contacts != NULL);
+       EBookBackendMAPI *bbmapi = user_data;
+       mapi_id_t update_folder1 = 0, update_folder2 = 0;
+
+       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
+
+       switch (event_mask) {
+       case fnevNewMail:
+       case fnevNewMail | fnevMbit: {
+               struct NewMailNotification *newmail = event_data;
+
+               if (newmail)
+                       update_folder1 = newmail->FID;
+               } break;
+       case fnevObjectCreated:
+       case fnevMbit | fnevObjectCreated: {
+               struct MessageCreatedNotification *msgcreated = event_data;
+
+               if (msgcreated)
+                       update_folder1 = msgcreated->FID;
+               } break;
+       case fnevObjectModified:
+       case fnevMbit | fnevObjectModified: {
+               struct MessageModifiedNotification *msgmodified = event_data;
+
+               if (msgmodified)
+                       update_folder1 = msgmodified->FID;
+               } break;
+       case fnevObjectDeleted:
+       case fnevMbit | fnevObjectDeleted: {
+               struct MessageDeletedNotification *msgdeleted = event_data;
+
+               if (msgdeleted)
+                       update_folder1 = msgdeleted->FID;
+               } break;
+       case fnevObjectMoved:
+       case fnevMbit | fnevObjectMoved: {
+               struct MessageMoveCopyNotification *msgmoved = event_data;
+
+               if (msgmoved) {
+                       update_folder1 = msgmoved->OldFID;
+                       update_folder2 = msgmoved->FID;
+               }
+               } break;
+       case fnevObjectCopied:
+       case fnevMbit | fnevObjectCopied: {
+               struct MessageMoveCopyNotification *msgcopied = event_data;
+
+               if (msgcopied) {
+                       update_folder1 = msgcopied->OldFID;
+                       update_folder2 = msgcopied->FID;
+               }
+               } break;
+       default:
+               break;
+       }
 
-       e_book_backend_sqlitedb_lock_updates (ebma->priv->db, NULL);
-       ebma->priv->last_db_commit_time = get_current_time_ms ();
+       if (update_folder1 || update_folder2) {
+               ESource *source;
+               ESourceMapiFolder *ext_mapi_folder;
 
-       ebmac->op_transfer_contacts (ebma, uids, book_view, &last_notification, cancellable, error);
+               source = e_backend_get_source (E_BACKEND (bbmapi));
+               ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 
-       e_book_backend_sqlitedb_unlock_updates (ebma->priv->db, TRUE, NULL);
+               if (update_folder1 == e_source_mapi_folder_get_id (ext_mapi_folder) ||
+                   update_folder2 == e_source_mapi_folder_get_id (ext_mapi_folder)) {
+                       e_book_meta_backend_schedule_refresh (E_BOOK_META_BACKEND (bbmapi));
+               }
+       }
 }
 
 static gboolean
-unref_backend_idle_cb (gpointer data)
+ebb_mapi_connect_sync (EBookMetaBackend *meta_backend,
+                      const ENamedParameters *credentials,
+                      ESourceAuthenticationResult *out_auth_result,
+                      gchar **out_certificate_pem,
+                      GTlsCertificateFlags *out_certificate_errors,
+                      GCancellable *cancellable,
+                      GError **error)
 {
-       EBookBackendMAPI *ebma = data;
-
-       g_return_val_if_fail (ebma != NULL, FALSE);
-
-       g_object_unref (ebma);
-
-       return FALSE;
-}
-
-static gpointer
-ebbm_update_cache_cb (gpointer data)
-{
-       EBookBackendMAPI *ebma = (EBookBackendMAPI *) data;
-       EBookBackendMAPIPrivate *priv;
-       EBookBackendMAPIClass *ebmac;
-       guint32 server_stored_contacts = 0;
-       time_t restr_tt = 0;
-       gboolean partial_update = FALSE;
-       GCancellable *cancellable;
-       GError *error = NULL;
+       EBookBackendMAPI *bbmapi;
+       EMapiConnection *old_conn;
+       CamelMapiSettings *settings;
+       ESource *source;
+       ESourceMapiFolder *ext_mapi_folder;
+       GError *mapi_error = NULL;
 
-       g_return_val_if_fail (ebma != NULL, NULL);
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (out_auth_result != NULL, FALSE);
 
-       priv = ebma->priv;
-       g_return_val_if_fail (priv != NULL, NULL);
-       g_return_val_if_fail (priv->db != NULL, NULL);
-       g_return_val_if_fail (priv->conn != NULL, NULL);
+       bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
 
-       ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
-       g_return_val_if_fail (ebmac != NULL, NULL);
+       ebb_mapi_lock_connection (bbmapi);
 
-       cancellable = priv->update_cache;
-       g_cancellable_reset (cancellable);
+       if (bbmapi->priv->conn &&
+           e_mapi_connection_connected (bbmapi->priv->conn)) {
+               ebb_mapi_unlock_connection (bbmapi);
+               return TRUE;
+       }
 
-       do {
-               GHashTable *local_known_uids, *server_known_uids;
+       settings = ebb_mapi_get_collection_settings (bbmapi);
+       source = e_backend_get_source (E_BACKEND (bbmapi));
+       ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 
-               priv->server_dirty = FALSE;
+       old_conn = bbmapi->priv->conn;
 
-               local_known_uids = e_book_backend_sqlitedb_get_uids_and_rev (priv->db, 
EMA_EBB_CACHE_FOLDERID, &error);
-               server_known_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+       bbmapi->priv->conn = e_mapi_connection_new (
+               e_book_backend_get_registry (E_BOOK_BACKEND (bbmapi)),
+               camel_mapi_settings_get_profile (settings),
+               credentials, cancellable, &mapi_error);
 
-               if (!error && !g_cancellable_is_cancelled (cancellable) && ebmac->op_get_contacts_count) {
-                       ebmac->op_get_contacts_count (ebma, &server_stored_contacts, cancellable, &error);
-               }
+       if (!bbmapi->priv->conn) {
+               bbmapi->priv->conn = e_mapi_connection_find (camel_mapi_settings_get_profile (settings));
+               if (bbmapi->priv->conn && !e_mapi_connection_connected (bbmapi->priv->conn))
+                       e_mapi_connection_reconnect (bbmapi->priv->conn, credentials, cancellable, 
&mapi_error);
+       }
 
-               if (!error && !g_cancellable_is_cancelled (cancellable) && ebmac->op_list_known_uids) {
-                       struct ListKnownUidsData lku;
+       if (old_conn)
+               g_signal_handlers_disconnect_by_func (old_conn, G_CALLBACK (ebb_mapi_server_notification_cb), 
bbmapi);
 
-                       restr_tt = priv->last_modify_time && server_stored_contacts == g_hash_table_size 
(local_known_uids) ? priv->last_modify_time + 1 : 0;
-                       partial_update = restr_tt > 0;
+       g_clear_object (&old_conn);
 
-                       lku.uid_to_rev = server_known_uids;
-                       lku.latest_last_modify = priv->last_modify_time;
+       if (!bbmapi->priv->conn || mapi_error) {
+               gboolean is_network_error = mapi_error && mapi_error->domain != E_MAPI_ERROR;
 
-                       ebmac->op_list_known_uids (ebma, partial_update ? 
e_mapi_utils_build_last_modify_restriction : NULL, &restr_tt, &lku, cancellable, &error);
+               g_clear_object (&bbmapi->priv->conn);
+               ebb_mapi_unlock_connection (bbmapi);
 
-                       restr_tt = lku.latest_last_modify;
-               }
+               if (is_network_error)
+                       ebb_mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
 
-               if (!error && !g_cancellable_is_cancelled (cancellable) && ebmac->op_transfer_contacts && 
local_known_uids) {
-                       GSList *uids = NULL;
-                       GHashTableIter iter;
-                       gpointer key, value;
+               g_clear_error (&mapi_error);
 
-                       g_hash_table_iter_init (&iter, server_known_uids);
-                       while (g_hash_table_iter_next (&iter, &key, &value)) {
-                               const gchar *uid = key, *rev = value, *local_rev;
+               *out_auth_result = is_network_error ? E_SOURCE_AUTHENTICATION_ERROR : 
E_SOURCE_AUTHENTICATION_REJECTED;
 
-                               local_rev = g_hash_table_lookup (local_known_uids, uid);
-                               if (g_strcmp0 (local_rev, rev) != 0) {
-                                       uids = g_slist_prepend (uids, (gpointer) uid);
-                               }
+               return FALSE;
+       }
 
-                               g_hash_table_remove (local_known_uids, uid);
-                       }
+       if (!e_book_backend_mapi_get_is_gal (bbmapi) &&
+           e_source_mapi_folder_get_server_notification (ext_mapi_folder)) {
+               mapi_object_t obj_folder;
+               GError *mapi_error = NULL;
 
-                       if (uids)
-                               ebbm_transfer_contacts (ebma, uids, NULL, cancellable, &error);
+               g_signal_connect (bbmapi->priv->conn, "server-notification", G_CALLBACK 
(ebb_mapi_server_notification_cb), bbmapi);
 
-                       if (!error && !g_cancellable_is_cancelled (cancellable) && !partial_update) {
-                               e_book_backend_sqlitedb_lock_updates (priv->db, NULL);
+               if (ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error)) {
+                       e_mapi_connection_enable_notifications (bbmapi->priv->conn, &obj_folder,
+                               fnevObjectCreated | fnevObjectModified | fnevObjectDeleted | fnevObjectMoved 
| fnevObjectCopied,
+                               cancellable, &mapi_error);
 
-                               g_hash_table_iter_init (&iter, local_known_uids);
-                               while (g_hash_table_iter_next (&iter, &key, &value)) {
-                                       const gchar *uid = key;
+                       e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, 
&mapi_error);
+               }
 
-                                       if (!uid)
-                                               continue;
+               if (mapi_error) {
+                       ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
+                       g_clear_error (&mapi_error);
+               }
+       }
 
-                                       e_book_backend_mapi_notify_contact_removed (ebma, uid);
-                               }
+       ebb_mapi_unlock_connection (bbmapi);
 
-                               e_book_backend_sqlitedb_unlock_updates (priv->db, TRUE, NULL);
-                       }
+       *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
 
-                       priv->last_server_contact_count = server_stored_contacts;
-                       priv->last_modify_time = restr_tt;
+       return TRUE;
+}
 
-                       /* has borrowed data from server_known_uids */
-                       g_slist_free (uids);
-               }
+static gboolean
+ebb_mapi_disconnect_sync (EBookMetaBackend *meta_backend,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+       EBookBackendMAPI *bbmapi;
+       gboolean success = TRUE;
 
-               priv->last_update_cache = time(NULL);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
 
-               g_hash_table_destroy (server_known_uids);
-               if (local_known_uids)
-                       g_hash_table_destroy (local_known_uids);
-       } while (!error && priv->server_dirty && !g_cancellable_is_cancelled (cancellable));
+       bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
 
-       g_clear_error (&error);
+       ebb_mapi_lock_connection (bbmapi);
 
-       complete_views (ebma);
+       if (bbmapi->priv->conn) {
+               g_signal_handlers_disconnect_by_func (bbmapi->priv->conn, G_CALLBACK 
(ebb_mapi_server_notification_cb), bbmapi);
 
-       /* indicate the thread is not running */
-       g_cancellable_cancel (priv->update_cache);
+               success = e_mapi_connection_disconnect (bbmapi->priv->conn, FALSE, cancellable, error);
+               g_clear_object (&bbmapi->priv->conn);
+       }
 
-       /* May unref it out of the thread, in case it's the last reference to it */
-       g_idle_add (unref_backend_idle_cb, ebma);
+       ebb_mapi_unlock_connection (bbmapi);
 
-       return NULL;
+       return success;
 }
 
-static void
-ebbm_maybe_invoke_cache_update (EBookBackendMAPI *ebma)
-{
-       EBookBackendMAPIPrivate *priv;
-
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (ebma->priv != NULL);
+typedef struct _LoadMultipleData {
+       gboolean is_gal;
+       gchar *book_uid;
+       GSList **out_contacts; /* EContact * */
+} LoadMultipleData;
 
-       priv = ebma->priv;
+static gboolean
+transfer_contacts_cb (EMapiConnection *conn,
+                     TALLOC_CTX *mem_ctx,
+                     /* const */ EMapiObject *object,
+                     guint32 obj_index,
+                     guint32 obj_total,
+                     gpointer user_data,
+                     GCancellable *cancellable,
+                     GError **perror)
+{
+       LoadMultipleData *lmd = user_data;
+       EContact *contact;
 
-       if (priv->update_cache_thread) {
-               if (!g_cancellable_is_cancelled (priv->update_cache))
-                       return;
+       g_return_val_if_fail (conn != NULL, FALSE);
+       g_return_val_if_fail (object != NULL, FALSE);
+       g_return_val_if_fail (lmd != NULL, FALSE);
 
-               g_thread_join (priv->update_cache_thread);
-               priv->update_cache_thread = NULL;
+       contact = e_mapi_book_utils_contact_from_object (conn, object, lmd->book_uid);
+       if (!contact) {
+               /* being it GAL, just ignore failures */
+               return lmd->is_gal;
        }
 
-       /* do not update more often than each 10 minutes */
-       if (time (NULL) - priv->last_update_cache >= 60 * 10) {
-               g_object_ref (ebma);
+       *lmd->out_contacts = g_slist_prepend (*lmd->out_contacts, contact);
 
-               g_cancellable_reset (priv->update_cache);
-               priv->server_dirty = FALSE;
-               priv->update_cache_thread = g_thread_new (NULL, ebbm_update_cache_cb, ebma);
-               if (!priv->update_cache_thread)
-                       g_object_unref (ebma);
-       }
+       return TRUE;
 }
 
-static ESourceAuthenticationResult
-ebbm_connect_user (EBookBackendMAPI *ebma,
-                  const ENamedParameters *credentials,
-                  gboolean update_connection_status,
-                  GCancellable *cancellable,
-                  GError **error)
+static gboolean
+ebb_mapi_load_multiple_sync (EBookBackendMAPI *bbmapi,
+                            const GSList *uids, /* gchar * */
+                            GSList **out_contacts, /* EContact * */
+                            GCancellable *cancellable,
+                            GError **error)
 {
-       EBookBackendMAPIPrivate *priv = ebma->priv;
-       EMapiConnection *old_conn;
-       CamelMapiSettings *settings;
+       LoadMultipleData lmd;
+       const gchar *error_text;
+       gint partial_count = -1;
+       GSList *mids = NULL, *link;
        ESource *source;
+       gboolean success;
        GError *mapi_error = NULL;
 
-       settings = ebbm_get_collection_settings (ebma);
-       source = e_backend_get_source (E_BACKEND (ebma));
-
-       if (!e_backend_get_online (E_BACKEND (ebma))) {
-               ebbm_notify_connection_status (ebma, FALSE);
-       } else {
-               if (priv->update_cache_thread) {
-                       g_cancellable_cancel (priv->update_cache);
-                       g_thread_join (priv->update_cache_thread);
-                       priv->update_cache_thread = NULL;
-               }
-
-               e_book_backend_mapi_lock_connection (ebma);
-               if (update_connection_status)
-                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
-
-               if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
-                       if (update_connection_status)
-                               e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
-                       e_book_backend_mapi_unlock_connection (ebma);
-                       return E_SOURCE_AUTHENTICATION_ERROR;
-               }
-
-               old_conn = priv->conn;
-               priv->conn = NULL;
-
-               priv->conn = e_mapi_connection_new (
-                       e_book_backend_get_registry (E_BOOK_BACKEND (ebma)),
-                       camel_mapi_settings_get_profile (settings),
-                       credentials, cancellable, &mapi_error);
-               if (!priv->conn) {
-                       priv->conn = e_mapi_connection_find (camel_mapi_settings_get_profile (settings));
-                       if (priv->conn && !e_mapi_connection_connected (priv->conn))
-                               e_mapi_connection_reconnect (priv->conn, credentials, cancellable, 
&mapi_error);
-               }
-
-               if (old_conn)
-                       g_object_unref (old_conn);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
+       g_return_val_if_fail (uids != NULL, FALSE);
+       g_return_val_if_fail (out_contacts != NULL, FALSE);
 
-               if (!priv->conn || mapi_error) {
-                       gboolean is_network_error = mapi_error && mapi_error->domain != E_MAPI_ERROR;
+       source = e_backend_get_source (E_BACKEND (bbmapi));
 
-                       if (priv->conn) {
-                               g_object_unref (priv->conn);
-                               priv->conn = NULL;
-                       }
-
-                       if (is_network_error)
-                               mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, 
NULL);
-                       if (update_connection_status)
-                               e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
-                       e_book_backend_mapi_unlock_connection (ebma);
-
-                       if (mapi_error)
-                               g_error_free (mapi_error);
-
-                       ebbm_notify_connection_status (ebma, FALSE);
+       if (e_book_backend_mapi_get_is_gal (bbmapi) &&
+           !ebb_mapi_is_marked_for_offline (bbmapi)) {
+               ESourceMapiFolder *ext_mapi_folder;
 
-                       return is_network_error ? E_SOURCE_AUTHENTICATION_ERROR : 
E_SOURCE_AUTHENTICATION_REJECTED;
-               }
-
-               if (update_connection_status)
-                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
-               e_book_backend_mapi_unlock_connection (ebma);
+               ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
+               if (e_source_mapi_folder_get_allow_partial (ext_mapi_folder)) {
+                       partial_count = e_source_mapi_folder_get_partial_count (ext_mapi_folder);
 
-               ebbm_notify_connection_status (ebma, TRUE);
-
-               if (!g_cancellable_is_cancelled (cancellable) && e_book_backend_mapi_is_marked_for_offline 
(ebma)) {
-                       ebbm_maybe_invoke_cache_update (ebma);
+                       if (partial_count <= 0)
+                               partial_count = DEFAULT_PARTIAL_COUNT;
                }
        }
 
-       return E_SOURCE_AUTHENTICATION_ACCEPTED;
-}
+       for (link = (GSList *) uids; link && (partial_count == -1 || partial_count > 0); link = g_slist_next 
(link)) {
+               mapi_id_t *pmid, mid;
 
-/* connection lock should be already held when calling this function */
-gboolean
-e_book_backend_mapi_ensure_connected (EBookBackendMAPI *ebma,
-                                     GCancellable *cancellable, 
-                                     GError **error)
-{
-       CamelMapiSettings *settings;
-       GError *local_error = NULL;
+               if (e_mapi_util_mapi_id_from_string  (link->data, &mid)) {
+                       pmid = g_new0 (mapi_id_t, 1);
+                       *pmid = mid;
 
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
+                       mids = g_slist_prepend (mids, pmid);
 
-       if (ebma->priv->conn && e_mapi_connection_connected (ebma->priv->conn))
-               return TRUE;
-
-       settings = ebbm_get_collection_settings (ebma);
-
-       if (!camel_mapi_settings_get_kerberos (settings) ||
-           ebbm_connect_user (ebma, NULL, TRUE, cancellable, &local_error) != 
E_SOURCE_AUTHENTICATION_ACCEPTED) {
-               e_backend_credentials_required_sync (E_BACKEND (ebma),
-                       E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL,
-                       cancellable, &local_error);
+                       if (partial_count > 0)
+                               partial_count--;
+               }
        }
 
-       if (!local_error)
-               return TRUE;
-
-       g_propagate_error (error, local_error);
-
-       return FALSE;
-}
-
-/* connection lock should be already held when calling this function */
-void
-e_book_backend_mapi_maybe_disconnect (EBookBackendMAPI *ebma,
-                                     const GError *mapi_error)
-{
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
-
-       /* no error or already disconnected */
-       if (!mapi_error || !ebma->priv->conn)
-               return;
+       lmd.is_gal = e_book_backend_mapi_get_is_gal (bbmapi);
+       lmd.book_uid = e_source_dup_uid (source);
+       lmd.out_contacts = out_contacts;
 
-       if (g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed) ||
-           g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_CALL_FAILED)) {
-               e_mapi_connection_disconnect (ebma->priv->conn,
-                       !g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed),
-                       NULL, NULL);
-               g_object_unref (ebma->priv->conn);
-               ebma->priv->conn = NULL;
-       }
-}
+       ebb_mapi_lock_connection (bbmapi);
 
-static void
-ebbm_open (EBookBackendMAPI *ebma,
-          GCancellable *cancellable,
-          gboolean only_if_exists,
-          GError **perror)
-{
-       EBookBackendMAPIPrivate *priv = ebma->priv;
-       ESource *source = e_backend_get_source (E_BACKEND (ebma));
-       const gchar *cache_dir;
-       GError *error = NULL;
+       if (e_book_backend_mapi_get_is_gal (bbmapi)) {
+               error_text = _("Failed to fetch GAL entries");
 
-       if (e_book_backend_is_opened (E_BOOK_BACKEND (ebma)))
-               return;
+               success = e_mapi_connection_transfer_gal_objects (bbmapi->priv->conn, mids, NULL, NULL, 
transfer_contacts_cb, &lmd, cancellable, &mapi_error);
+       } else {
+               mapi_object_t obj_folder;
 
-       if (priv->book_uid)
-               g_free (priv->book_uid);
-       priv->book_uid = e_source_dup_uid (source);
+               error_text = _("Failed to transfer contacts from a server");
 
-       cache_dir = e_book_backend_get_cache_dir (E_BOOK_BACKEND (ebma));
+               success = ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error);
 
-       if (priv->db)
-               g_object_unref (priv->db);
-       priv->db = e_book_backend_sqlitedb_new (cache_dir,
-                                               EMA_EBB_CACHE_PROFILEID,
-                                               EMA_EBB_CACHE_FOLDERID,
-                                               EMA_EBB_CACHE_FOLDERID,
-                                               TRUE, &error);
+               if (success) {
+                       success = e_mapi_connection_transfer_objects (bbmapi->priv->conn, &obj_folder, mids, 
transfer_contacts_cb, &lmd, cancellable, &mapi_error);
 
-       if (error) {
-               g_propagate_error (perror, error);
-               return;
+                       e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, 
&mapi_error);
+               }
        }
 
-       e_book_backend_set_writable (E_BOOK_BACKEND (ebma), FALSE);
-
-       ebbm_notify_connection_status (ebma, e_backend_get_online (E_BACKEND (ebma)));
+       if (mapi_error) {
+               ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
+               ebb_mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, error_text);
+               g_error_free (mapi_error);
 
-       /* Either we are in Online mode or this is marked for offline */
-       if (!e_backend_get_online (E_BACKEND (ebma)) &&
-           !e_book_backend_mapi_is_marked_for_offline (ebma)) {
-               g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
-               return;
-       }
-
-       /* Once aunthentication in address book works this can be removed */
-       if (!e_backend_get_online (E_BACKEND (ebma))) {
-               e_backend_set_online (E_BACKEND (ebma), FALSE);
-               return;
+               success = FALSE;
        }
 
-       e_backend_set_online (E_BACKEND (ebma), TRUE);
+       ebb_mapi_unlock_connection (bbmapi);
 
-       e_book_backend_mapi_ensure_connected (ebma, cancellable, &error);
+       g_slist_free_full (mids, g_free);
+       g_free (lmd.book_uid);
 
-       if (error)
-               g_propagate_error (perror, error);
+       return success;
 }
 
-static ESourceAuthenticationResult
-ebbm_authenticate_sync (EBackend *backend,
-                       const ENamedParameters *credentials,
-                       gchar **out_certificate_pem,
-                       GTlsCertificateFlags *out_certificate_errors,
-                       GCancellable *cancellable,
-                       GError **error)
-{
-       return ebbm_connect_user (E_BOOK_BACKEND_MAPI (backend), credentials, FALSE, cancellable, error);
-}
-
-static void
-ebbm_remove (EBookBackendMAPI *ebma, GCancellable *cancellable, GError **error)
+static gboolean
+ebb_mapi_preload_infos_sync (EBookBackendMAPI *bbmapi,
+                            GSList *created_objects,
+                            GSList *modified_objects,
+                            GCancellable *cancellable,
+                            GError **error)
 {
-       EBookBackendMAPIPrivate *priv;
-
-       e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
-       e_mapi_return_data_book_error_if_fail (ebma->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+       GHashTable *infos;
+       GSList *uids = NULL, *link;
+       gboolean success = TRUE;
 
-       priv = ebma->priv;
-
-       if (!priv->book_uid)
-               return;
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
 
-       e_book_backend_mapi_lock_connection (ebma);
+       infos = g_hash_table_new (g_str_hash, g_str_equal);
 
-       if (!priv->db) {
-               const gchar *cache_dir = e_book_backend_get_cache_dir (E_BOOK_BACKEND (ebma));
+       for (link = created_objects; link; link = g_slist_next (link)) {
+               EBookMetaBackendInfo *nfo = link->data;
 
-               /* pity, but it's required to be removed completely */
-               priv->db = e_book_backend_sqlitedb_new (cache_dir,
-                                                       EMA_EBB_CACHE_PROFILEID,
-                                                       EMA_EBB_CACHE_FOLDERID,
-                                                       EMA_EBB_CACHE_FOLDERID,
-                                                       TRUE, NULL);
+               if (nfo && nfo->uid) {
+                       uids = g_slist_prepend (uids, nfo->uid);
+                       g_hash_table_insert (infos, nfo->uid, nfo);
+               }
        }
 
-       if (priv->db) {
-               e_book_backend_sqlitedb_remove (priv->db, NULL);
-               g_object_unref (priv->db);
-               priv->db = NULL;
-       }
+       for (link = modified_objects; link; link = g_slist_next (link)) {
+               EBookMetaBackendInfo *nfo = link->data;
 
-       e_book_backend_mapi_unlock_connection (ebma);
-}
-
-static gchar *
-ebbm_get_backend_property (EBookBackend *backend,
-                           const gchar *prop_name)
-{
-       EBookBackendMAPI *ebma;
-
-       g_return_val_if_fail (prop_name != NULL, NULL);
-
-       ebma = E_BOOK_BACKEND_MAPI (backend);
-
-       if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
-               if (e_book_backend_mapi_is_marked_for_offline (ebma))
-                       return g_strdup ("net,bulk-removes,contact-lists,do-initial-query");
-               else
-                       return g_strdup ("net,bulk-removes,contact-lists");
-       } else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
-               return g_strdup (e_contact_field_name (E_CONTACT_FILE_AS));
-       } else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
-               GSList *fields;
-               gchar *prop_value;
-
-               fields = e_mapi_book_utils_get_supported_contact_fields ();
-               prop_value = e_data_book_string_slist_to_comma_string (fields);
-               g_slist_free (fields);
-
-               return prop_value;
+               if (nfo && nfo->uid) {
+                       uids = g_slist_prepend (uids, nfo->uid);
+                       g_hash_table_insert (infos, nfo->uid, nfo);
+               }
        }
 
-       /* Chain up to parent's get_backend_property() method. */
-       return E_BOOK_BACKEND_CLASS (e_book_backend_mapi_parent_class)->
-               get_backend_property (backend, prop_name);
-}
-
-static void
-ebbm_notify_online_cb (EBookBackend *backend, GParamSpec *pspec)
-{
-       EBookBackendMAPI *ebma = E_BOOK_BACKEND_MAPI (backend);
-       EBookBackendMAPIPrivate *priv = ebma->priv;
-       gboolean online;
+       uids = g_slist_reverse (uids);
+       if (uids) {
+               GSList *contacts = NULL;
 
-       online = e_backend_get_online (E_BACKEND (backend));
+               success = ebb_mapi_load_multiple_sync (bbmapi, uids, &contacts, cancellable, error);
+               if (success) {
+                       for (link = contacts; link; link = g_slist_next (link)) {
+                               EContact *contact = link->data;
 
-       if (e_book_backend_is_opened (backend)) {
-               e_book_backend_mapi_lock_connection (ebma);
+                               if (contact) {
+                                       EBookMetaBackendInfo *nfo = g_hash_table_lookup (infos, 
e_contact_get_const (contact, E_CONTACT_UID));
 
-               if (!online) {
-                       e_book_backend_set_writable (backend, FALSE);
-                       ebbm_notify_connection_status (ebma, FALSE);
-
-                       if (priv->conn) {
-                               e_mapi_utils_unref_in_thread (G_OBJECT (priv->conn));
-                               priv->conn = NULL;
+                                       if (nfo && !nfo->object)
+                                               nfo->object = e_vcard_to_string (E_VCARD (contact), 
EVC_FORMAT_VCARD_30);
+                               }
                        }
-               } else {
-                       ebbm_notify_connection_status (ebma, TRUE);
                }
 
-               e_book_backend_mapi_unlock_connection (ebma);
+               g_slist_free_full (contacts, g_object_unref);
        }
-}
-
-static void
-ebbm_get_contact (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *id, gchar **vcard, GError 
**error)
-{
-       EBookBackendMAPIPrivate *priv;
-       gchar *contact;
 
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (vcard != NULL);
+       g_hash_table_destroy (infos);
+       g_slist_free (uids);
 
-       priv = ebma->priv;
-       g_return_if_fail (priv != NULL);
-
-       if (!priv->db) {
-               g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               return;
-       }
-
-       contact = e_book_backend_sqlitedb_get_vcard_string (priv->db,
-                                                           EMA_EBB_CACHE_FOLDERID,
-                                                           id, NULL, NULL, error);
-       if (contact)
-               *vcard = contact;
-       else
-               g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND));
+       return success;
 }
 
-static void
-ebbm_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *query, GSList 
**vCards, GError **error)
+static gboolean
+ebb_mapi_get_changes_sync (EBookMetaBackend *meta_backend,
+                          const gchar *last_sync_tag,
+                          gboolean is_repeat,
+                          gchar **out_new_sync_tag,
+                          gboolean *out_repeat,
+                          GSList **out_created_objects,
+                          GSList **out_modified_objects,
+                          GSList **out_removed_objects,
+                          GCancellable *cancellable,
+                          GError **error)
 {
-       EBookBackendMAPIPrivate *priv;
-       GSList *hits, *l;
-       GError *err = NULL;
-
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (query != NULL);
-       g_return_if_fail (vCards != NULL);
+       EBookBackendMAPI *bbmapi;
 
-       priv = ebma->priv;
-       g_return_if_fail (priv != NULL);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (out_created_objects != NULL, FALSE);
+       g_return_val_if_fail (out_modified_objects != NULL, FALSE);
 
-       if (!priv->db) {
-               g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-               return;
+       /* Chain up to parent's method */
+       if (!E_BOOK_META_BACKEND_CLASS (e_book_backend_mapi_parent_class)->get_changes_sync (meta_backend,
+               last_sync_tag, is_repeat, out_new_sync_tag, out_repeat, out_created_objects,
+               out_modified_objects, out_removed_objects, cancellable, error)) {
+               return FALSE;
        }
 
-       hits = e_book_backend_sqlitedb_search (priv->db, EMA_EBB_CACHE_FOLDERID,
-                                              query, NULL, NULL, NULL, &err);
+       bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
 
-       for (l = hits; !err && l; l = l->next) {
-               EbSdbSearchData *sdata = (EbSdbSearchData *) l->data;
-               gchar *vcard = sdata->vcard;
+       /* Preload some of the contacts in chunk, to speed-up things;
+          ignore errors, to not break whole update process. */
+       ebb_mapi_preload_infos_sync (bbmapi, *out_created_objects, *out_modified_objects, cancellable, NULL);
 
-               if (!err && vcard)
-                       *vCards = g_slist_prepend (*vCards, g_strdup (vcard));
-
-               e_book_backend_sqlitedb_search_data_free (sdata);
-       }
-
-       if (err)
-               g_propagate_error (error, err);
-
-       g_slist_free (hits);
+       return TRUE;
 }
 
-struct BookViewThreadData
-{
-       EBookBackendMAPI *ebma;
-       EDataBookView *book_view;
-       GCancellable *cancellable;
-};
-
-static gpointer
-ebbm_book_view_thread (gpointer data)
+static gboolean
+ebb_mapi_list_existing_uids_cb (EMapiConnection *conn,
+                               TALLOC_CTX *mem_ctx,
+                               const ListObjectsData *object_data,
+                               guint32 obj_index,
+                               guint32 obj_total,
+                               gpointer user_data,
+                               GCancellable *cancellable,
+                               GError **perror)
 {
-       struct BookViewThreadData *bvtd = data;
-       EBookBackendMAPIPrivate *priv;
-       EBookBackendMAPIClass *ebmac;
-       GError *error = NULL;
-
-       g_return_val_if_fail (bvtd != NULL, NULL);
-       g_return_val_if_fail (bvtd->ebma != NULL, NULL);
-       g_return_val_if_fail (bvtd->book_view != NULL, NULL);
-
-       ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (bvtd->ebma);
-       g_return_val_if_fail (ebmac != NULL, NULL);
-
-       priv = bvtd->ebma->priv;
-
-       e_data_book_view_notify_progress (bvtd->book_view, -1, _("Searching"));
-
-       if (!error && priv && priv->conn && (!priv->update_cache_thread || g_cancellable_is_cancelled 
(priv->update_cache))
-           && e_book_backend_mapi_book_view_is_running (bvtd->ebma, bvtd->book_view)) {
-               EBookBackendMAPIClass *ebmac;
+       GSList **out_existing_objects = user_data;
+       gchar *uid;
 
-               ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (bvtd->ebma);
-               if (ebmac && ebmac->op_book_view_thread)
-                       ebmac->op_book_view_thread (bvtd->ebma, bvtd->book_view, priv->update_cache, &error);
+       g_return_val_if_fail (conn != NULL, FALSE);
+       g_return_val_if_fail (object_data != NULL, FALSE);
+       g_return_val_if_fail (out_existing_objects != NULL, FALSE);
 
-               if (e_book_backend_mapi_is_marked_for_offline (bvtd->ebma)) {
-                       e_book_backend_mapi_update_view_by_cache (bvtd->ebma, bvtd->book_view, &error);
+       uid = e_mapi_util_mapi_id_to_string (object_data->mid);
+       if (uid) {
+               gchar *rev;
 
-                       ebbm_maybe_invoke_cache_update (bvtd->ebma);
+               rev = e_mapi_book_utils_timet_to_string (object_data->last_modified);
 
-                       e_book_backend_mapi_update_view_by_cache (bvtd->ebma, bvtd->book_view, &error);
-               } else if (ebmac && ebmac->op_list_known_uids && ebmac->op_transfer_contacts) {
-                       EBookBackendSExp *sexp;
-                       const gchar *query;
+               *out_existing_objects = g_slist_prepend (*out_existing_objects,
+                       e_book_meta_backend_info_new (uid, rev, NULL, NULL));
 
-                       sexp = e_data_book_view_get_sexp (bvtd->book_view);
-                       query = e_book_backend_sexp_text (sexp);
+               g_free (uid);
+               g_free (rev);
+       }
 
-                       /* search only if not searching for everything */
-                       if (query && *query && g_ascii_strcasecmp (query, "(contains 
\"x-evolution-any-field\" \"\")") != 0) {
-                               struct ListKnownUidsData lku = { 0 };
-                               GHashTable *local_known_uids, *server_known_uids;
+       return TRUE;
+}
 
-                               e_book_backend_mapi_update_view_by_cache (bvtd->ebma, bvtd->book_view, 
&error);
+static gboolean
+ebb_mapi_list_existing_with_restrictions_sync (EBookMetaBackend *meta_backend,
+                                              BuildRestrictionsCB build_rs_cb,
+                                              gpointer build_rs_cb_data,
+                                              gchar **out_new_sync_tag,
+                                              GSList **out_existing_objects, /* EBookMetaBackendInfo * */
+                                              GCancellable *cancellable,
+                                              GError **error)
+{
+       EBookBackendMAPI *bbmapi;
+       const gchar *error_text;
+       gboolean success;
+       GError *mapi_error = NULL;
 
-                               local_known_uids = e_book_backend_sqlitedb_get_uids_and_rev (priv->db, 
EMA_EBB_CACHE_FOLDERID, &error);
-                               server_known_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
g_free);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (out_existing_objects, FALSE);
 
-                               lku.uid_to_rev = server_known_uids;
-                               lku.latest_last_modify = 0;
+       *out_existing_objects = NULL;
 
-                               ebmac->op_list_known_uids (bvtd->ebma, 
e_mapi_book_utils_build_sexp_restriction, (gpointer) query, &lku, bvtd->cancellable, &error);
+       bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
 
-                               if (!g_cancellable_is_cancelled (bvtd->cancellable)) {
-                                       GSList *uids = NULL;
-                                       GHashTableIter iter;
-                                       gpointer key, value;
+       ebb_mapi_lock_connection (bbmapi);
 
-                                       g_hash_table_iter_init (&iter, server_known_uids);
-                                       while (g_hash_table_iter_next (&iter, &key, &value)) {
-                                               const gchar *uid = key, *rev = value, *local_rev;
+       if (e_book_backend_mapi_get_is_gal (bbmapi)) {
+               error_text = _("Failed to fetch GAL entries");
 
-                                               local_rev = g_hash_table_lookup (local_known_uids, uid);
-                                               if (g_strcmp0 (local_rev, rev) != 0) {
-                                                       uids = g_slist_prepend (uids, (gpointer) uid);
-                                               }
+               success = e_mapi_connection_list_gal_objects (bbmapi->priv->conn, NULL, NULL,
+                       ebb_mapi_list_existing_uids_cb, out_existing_objects, cancellable, &mapi_error);
+       } else {
+               mapi_object_t obj_folder;
 
-                                               g_hash_table_remove (local_known_uids, uid);
-                                       }
+               error_text = _("Failed to list items from a server");
 
-                                       if (uids) {
-                                               ebbm_transfer_contacts (bvtd->ebma, uids, NULL, 
bvtd->cancellable, &error);
-                                               e_book_backend_mapi_update_view_by_cache (bvtd->ebma, 
bvtd->book_view, &error);
-                                       }
+               success = ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error);
+               if (success) {
+                       success = e_mapi_connection_list_objects (bbmapi->priv->conn, &obj_folder, NULL, NULL,
+                               ebb_mapi_list_existing_uids_cb, out_existing_objects, cancellable, 
&mapi_error);
 
-                                       /* has borrowed data from server_known_uids */
-                                       g_slist_free (uids);
-                               }
-
-                               g_hash_table_destroy (server_known_uids);
-                               if (local_known_uids)
-                                       g_hash_table_destroy (local_known_uids);
-                       }
+                       e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, 
&mapi_error);
                }
        }
 
-       if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-               g_clear_error (&error);
+       if (mapi_error) {
+               ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
+               ebb_mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, error_text);
+               g_error_free (mapi_error);
 
-       /* do not stop book view when filling cache */
-       if (e_book_backend_mapi_book_view_is_running (bvtd->ebma, bvtd->book_view)
-           && (!priv->update_cache_thread || g_cancellable_is_cancelled (priv->update_cache)))
-               e_data_book_view_notify_complete (bvtd->book_view, error);
-
-       if (error)
-               g_error_free (error);
+               success = FALSE;
+       }
 
-       if (bvtd->cancellable)
-               g_object_unref (bvtd->cancellable);
-       g_object_unref (bvtd->book_view);
-       /* May unref it out of the thread, in case it's the last reference to it */
-       g_idle_add (unref_backend_idle_cb, bvtd->ebma);
-       g_free (bvtd);
+       ebb_mapi_unlock_connection (bbmapi);
 
-       return NULL;
+       return success;
 }
 
-/* Async OP functions, data structures and so on */
-
-typedef enum {
-       OP_OPEN,
-
-       OP_CREATE_CONTACTS,
-       OP_REMOVE_CONTACTS,
-       OP_MODIFY_CONTACTS,
-       OP_GET_CONTACT,
-       OP_GET_CONTACT_LIST,
-       OP_START_BOOK_VIEW,
-       OP_STOP_BOOK_VIEW
-} OperationType;
-
-typedef struct {
-       OperationType ot;
-
-       EDataBook *book;
-       guint32 opid;
-       GCancellable *cancellable;
-} OperationBase;
 
-typedef struct {
-       OperationBase base;
-
-       gboolean only_if_exists;
-} OperationOpen;
-
-typedef struct {
-       OperationBase base;
-
-       gchar *str;
-} OperationStr;
-
-typedef struct {
-       OperationBase base;
-
-       GSList *str_slist;
-} OperationStrSlist;
-
-typedef struct {
-       OperationBase base;
+static gboolean
+ebb_mapi_list_existing_sync (EBookMetaBackend *meta_backend,
+                            gchar **out_new_sync_tag,
+                            GSList **out_existing_objects,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
 
-       EDataBookView *book_view;
-} OperationBookView;
+       return ebb_mapi_list_existing_with_restrictions_sync (meta_backend, NULL, NULL,
+               out_new_sync_tag, out_existing_objects, cancellable, error);
+}
 
-static void
-ebbm_operation_cb (OperationBase *op, gboolean cancelled, EBookBackend *backend)
+static gboolean
+ebb_mapi_load_contact_sync (EBookMetaBackend *meta_backend,
+                             const gchar *uid,
+                             const gchar *extra,
+                             EContact **out_contact,
+                             gchar **out_extra,
+                             GCancellable *cancellable,
+                             GError **error)
 {
-       EBookBackendMAPI *ebma;
-       EBookBackendMAPIClass *ebmac;
-       GError *error = NULL;
+       EBookBackendMAPI *bbmapi;
+       GSList *uids, *contacts = NULL;
+       gboolean success;
 
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-       g_return_if_fail (op != NULL);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
+       g_return_val_if_fail (out_contact != NULL, FALSE);
 
-       ebma = E_BOOK_BACKEND_MAPI (backend);
-       g_return_if_fail (ebma != NULL);
+       *out_contact = NULL;
 
-       ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
-       g_return_if_fail (ebmac != NULL);
+       bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
 
-       cancelled = cancelled || (op->cancellable && g_cancellable_is_cancelled (op->cancellable));
+       uids = g_slist_prepend (NULL, (gpointer) uid);
 
-       switch (op->ot) {
-       case OP_OPEN: {
-               OperationOpen *opo = (OperationOpen *) op;
+       success = ebb_mapi_load_multiple_sync (bbmapi, uids, &contacts, cancellable, error);
 
-               if (!cancelled) {
-                       if (ebmac->op_open)
-                               ebmac->op_open (ebma, op->cancellable, opo->only_if_exists, &error);
-                       else
-                               error = EDB_ERROR (NOT_SUPPORTED);
+       ebb_mapi_unlock_connection (bbmapi);
 
-                       e_data_book_respond_open (op->book, op->opid, error);
-               }
-       } break;
-       case OP_CREATE_CONTACTS: {
-               OperationStrSlist *ops = (OperationStrSlist *) op;
+       if (success && contacts) {
+               *out_contact = g_object_ref (contacts->data);
+       }
 
-               if (!cancelled) {
-                       GSList *added_contacts = NULL;
+       g_slist_free_full (contacts, g_object_unref);
+       g_slist_free (uids);
 
-                       if (ebmac->op_create_contacts)
-                               ebmac->op_create_contacts (ebma, op->cancellable, ops->str_slist, 
&added_contacts, &error);
-                       else
-                               error = EDB_ERROR (NOT_SUPPORTED);
+       return success;
+}
 
-                       if (added_contacts && !error) {
-                               const GSList *l;
+typedef struct _SaveContactData {
+       EBookBackendMAPI *bbmapi;
+       EContact *contact;
+} SaveContactData;
 
-                               e_book_backend_sqlitedb_lock_updates (ebma->priv->db, NULL);
+static gboolean
+ebb_mapi_create_object_cb (EMapiConnection *conn,
+                          TALLOC_CTX *mem_ctx,
+                          EMapiObject **pobject, /* out */
+                          gpointer user_data,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       SaveContactData *scd = user_data;
+       const gchar *uid = NULL;
+       EContact *old_contact = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (scd != NULL, FALSE);
+       g_return_val_if_fail (scd->bbmapi != NULL, FALSE);
+       g_return_val_if_fail (scd->contact != NULL, FALSE);
+       g_return_val_if_fail (conn != NULL, FALSE);
+       g_return_val_if_fail (mem_ctx != NULL, FALSE);
+       g_return_val_if_fail (pobject != NULL, FALSE);
+
+       uid = e_contact_get_const (scd->contact, E_CONTACT_UID);
+       if (uid) {
+               EBookCache *book_cache;
+
+               book_cache = e_book_meta_backend_ref_cache (E_BOOK_META_BACKEND (scd->bbmapi));
+               if (book_cache &&
+                   !e_book_cache_get_contact (book_cache, uid, FALSE, &old_contact, cancellable, NULL)) {
+                       old_contact = NULL;
+               }
 
-                               for (l = added_contacts; l; l = l->next) {
-                                       e_book_backend_mapi_notify_contact_update (ebma, NULL, E_CONTACT 
(l->data), -1, -1, TRUE, NULL);
-                               }
+               g_clear_object (&book_cache);
+       }
 
-                               e_book_backend_sqlitedb_unlock_updates (ebma->priv->db, TRUE, NULL);
-                       }
+       success = e_mapi_book_utils_contact_to_object (scd->contact, old_contact, pobject, mem_ctx, 
cancellable, error);
 
-                       e_data_book_respond_create_contacts (op->book, op->opid, error, added_contacts);
+       g_clear_object (&old_contact);
 
-                       g_slist_free_full (added_contacts, g_object_unref);
-               }
+       return success;
+}
 
-               g_slist_free_full (ops->str_slist, g_free);
-       } break;
-       case OP_REMOVE_CONTACTS: {
-               OperationStrSlist *ops = (OperationStrSlist *) op;
+static gboolean
+ebb_mapi_save_contact_sync (EBookMetaBackend *meta_backend,
+                           gboolean overwrite_existing,
+                           EConflictResolution conflict_resolution,
+                           /* const */ EContact *contact,
+                           const gchar *extra,
+                           gchar **out_new_uid,
+                           gchar **out_new_extra,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       EBookBackendMAPI *bbmapi;
+       mapi_object_t obj_folder;
+       mapi_id_t mid = 0;
+       gboolean success;
+       GError *mapi_error = NULL;
 
-               if (!cancelled) {
-                       GSList *removed_ids = NULL;
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
+       g_return_val_if_fail (out_new_uid != NULL, FALSE);
 
-                       if (ebmac->op_remove_contacts)
-                               ebmac->op_remove_contacts (ebma, op->cancellable, ops->str_slist, 
&removed_ids, &error);
-                       else
-                               error = EDB_ERROR (NOT_SUPPORTED);
+       *out_new_uid = NULL;
 
-                       if (!error) {
-                               GSList *r;
+       bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
 
-                               e_book_backend_sqlitedb_lock_updates (ebma->priv->db, NULL);
+       if (e_book_backend_mapi_get_is_gal (bbmapi)) {
+               g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
+               return FALSE;
+       }
 
-                               for (r = removed_ids; r; r = r->next) {
-                                       const gchar *uid = r->data;
+       ebb_mapi_lock_connection (bbmapi);
 
-                                       if (uid)
-                                               e_book_backend_mapi_notify_contact_removed (ebma, uid);
-                               }
+       success = ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error);
+       if (success) {
+               SaveContactData scd;
 
-                               e_book_backend_sqlitedb_unlock_updates (ebma->priv->db, TRUE, NULL);
-                       }
+               scd.bbmapi = bbmapi;
+               scd.contact = contact;
 
-                       e_data_book_respond_remove_contacts (op->book, op->opid, error, removed_ids);
+               if (overwrite_existing) {
+                       success = e_mapi_util_mapi_id_from_string (e_contact_get_const (contact, 
E_CONTACT_UID), &mid) &&
+                               e_mapi_connection_modify_object (bbmapi->priv->conn, &obj_folder, mid,
+                                       ebb_mapi_create_object_cb, &scd, cancellable, &mapi_error);
 
-                       g_slist_foreach (removed_ids, (GFunc) g_free, NULL);
-                       g_slist_free (removed_ids);
+               } else {
+                       success = e_mapi_connection_create_object (bbmapi->priv->conn, &obj_folder, 
E_MAPI_CREATE_FLAG_NONE,
+                               ebb_mapi_create_object_cb, &scd, &mid, cancellable, &mapi_error);
                }
 
-               g_slist_free_full (ops->str_slist, g_free);
-       } break;
-       case OP_MODIFY_CONTACTS: {
-               OperationStrSlist *ops = (OperationStrSlist *) op;
-
-               if (!cancelled) {
-                       GSList *modified_contacts = NULL;
-
-                       if (ebmac->op_modify_contacts)
-                               ebmac->op_modify_contacts (ebma, op->cancellable, ops->str_slist, 
&modified_contacts, &error);
-                       else
-                               error = EDB_ERROR (NOT_SUPPORTED);
+               e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
+       }
 
-                       if (modified_contacts && !error) {
-                               const GSList *l;
+       if (mapi_error || !mid) {
+               ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
+               ebb_mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR,
+                       overwrite_existing ? _("Failed to modify item on a server") : _("Failed to create 
item on a server"));
+               g_clear_error (&mapi_error);
 
-                               e_book_backend_sqlitedb_lock_updates (ebma->priv->db, NULL);
+               success = FALSE;
+       }
 
-                               for (l = modified_contacts; l; l = l->next) {
-                                       e_book_backend_mapi_notify_contact_update (ebma, NULL, E_CONTACT 
(l->data), -1, -1, TRUE, NULL);
-                               }
+       ebb_mapi_unlock_connection (bbmapi);
 
-                               e_book_backend_sqlitedb_unlock_updates (ebma->priv->db, TRUE, NULL);
-                       }
+       if (success)
+               *out_new_uid = e_mapi_util_mapi_id_to_string (mid);
 
-                       e_data_book_respond_modify_contacts (op->book, op->opid, error, modified_contacts);
+       return success;
+}
 
-                       g_slist_free_full (modified_contacts, g_object_unref);
-               }
+static gboolean
+ebb_mapi_remove_contact_sync (EBookMetaBackend *meta_backend,
+                             EConflictResolution conflict_resolution,
+                             const gchar *uid,
+                             const gchar *extra,
+                             const gchar *object,
+                             GCancellable *cancellable,
+                             GError **error)
+{
+       EBookBackendMAPI *bbmapi;
+       mapi_id_t mid = 0;
+       gboolean success = TRUE;
+       GError *mapi_error = NULL;
 
-               g_slist_free_full (ops->str_slist, g_free);
-       } break;
-       case OP_GET_CONTACT: {
-               OperationStr *ops = (OperationStr *) op;
-               const gchar *id = ops->str;
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
 
-               if (!cancelled) {
-                       gchar *vcard = NULL;
+       bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
 
-                       if (ebmac->op_get_contact)
-                               ebmac->op_get_contact (ebma, op->cancellable, id, &vcard, &error);
-                       else
-                               error = EDB_ERROR (NOT_SUPPORTED);
+       if (e_book_backend_mapi_get_is_gal (bbmapi)) {
+               g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
+               return FALSE;
+       }
 
-                       e_data_book_respond_get_contact (op->book, op->opid, error, vcard);
+       if (e_mapi_util_mapi_id_from_string (uid, &mid)) {
+               mapi_object_t obj_folder;
 
-                       g_free (vcard);
-               }
+               ebb_mapi_lock_connection (bbmapi);
 
-               g_free (ops->str);
-       } break;
-       case OP_GET_CONTACT_LIST: {
-               OperationStr *ops = (OperationStr *) op;
-               const gchar *query = ops->str;
+               success = ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error);
+               if (success) {
+                       GSList *mids;
 
-               if (!cancelled) {
-                       GSList *vCards = NULL;
+                       mids = g_slist_prepend (NULL, &mid);
 
-                       if (ebmac->op_get_contact_list)
-                               ebmac->op_get_contact_list (ebma, op->cancellable, query, &vCards, &error);
-                       else
-                               error = EDB_ERROR (NOT_SUPPORTED);
+                       success = e_mapi_connection_remove_items (bbmapi->priv->conn, &obj_folder, mids, 
cancellable, &mapi_error);
 
-                       e_data_book_respond_get_contact_list (op->book, op->opid, error, vCards);
+                       e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, 
&mapi_error);
 
-                       g_slist_foreach (vCards, (GFunc) g_free, NULL);
-                       g_slist_free (vCards);
+                       g_slist_free (mids);
                }
 
-               g_free (ops->str);
-       } break;
-       case OP_START_BOOK_VIEW: {
-               OperationBookView *opbv = (OperationBookView *) op;
+               ebb_mapi_unlock_connection (bbmapi);
+       }
 
-               if (!cancelled && e_book_backend_mapi_book_view_is_running (ebma, opbv->book_view)) {
-                       GThread *thread;
-                       GError *err = NULL;
-                       struct BookViewThreadData *bvtd = g_new0 (struct BookViewThreadData, 1);
+       if (mapi_error || !mid) {
+               ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
+               ebb_mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to 
remove item from a server"));
+               g_clear_error (&mapi_error);
 
-                       g_mutex_lock (&ebma->priv->running_views_lock);
+               success = FALSE;
+       }
 
-                       bvtd->ebma = g_object_ref (ebma);
-                       bvtd->book_view = g_object_ref (opbv->book_view);
-                       bvtd->cancellable = g_hash_table_lookup (ebma->priv->running_views, bvtd->book_view);
+       return success;
+}
 
-                       if (bvtd->cancellable)
-                               g_object_ref (bvtd->cancellable);
+static gboolean
+ebb_mapi_update_cache_for_expression (EBookBackendMAPI *bbmapi,
+                                     const gchar *expr,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+       EBookMetaBackend *meta_backend;
+       GSList *found_infos = NULL;
+       gboolean success = TRUE;
 
-                       g_mutex_unlock (&ebma->priv->running_views_lock);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
 
-                       thread = g_thread_try_new (NULL, ebbm_book_view_thread, bvtd, &err);
+       meta_backend = E_BOOK_META_BACKEND (bbmapi);
 
-                       if (err) {
-                               error = EDB_ERROR_EX (OTHER_ERROR, err->message);
-                               e_data_book_view_notify_complete (opbv->book_view, error);
-                               g_error_free (error);
-                               g_error_free (err);
-                       }
+       ebb_mapi_lock_connection (bbmapi);
 
-                       if (thread)
-                               g_thread_unref (thread);
-               }
+       /* Search only if not searching for everything */
+       if (expr && *expr && g_ascii_strcasecmp (expr, "(contains \"x-evolution-any-field\" \"\")") != 0) {
+               success = e_book_meta_backend_ensure_connected_sync (meta_backend, cancellable, error) &&
+                       ebb_mapi_list_existing_with_restrictions_sync (meta_backend,
+                               e_mapi_book_utils_build_sexp_restriction, (gpointer) expr,
+                               NULL, &found_infos, cancellable, error);
+
+               if (success) {
+                       GSList *created_objects = NULL, *modified_objects = NULL;
 
-               g_object_unref (opbv->book_view);
-       } break;
-       case OP_STOP_BOOK_VIEW: {
-               OperationBookView *opbv = (OperationBookView *) op;
+                       success = e_book_meta_backend_split_changes_sync (meta_backend, found_infos, 
&created_objects,
+                               &modified_objects, NULL, cancellable, error);
+                       if (success)
+                               success = ebb_mapi_preload_infos_sync (bbmapi, created_objects, 
modified_objects, cancellable, error);
+                       if (success)
+                               success = e_book_meta_backend_process_changes_sync (meta_backend, 
created_objects,
+                                       modified_objects, NULL, cancellable, error);
 
-               if (!cancelled) {
-                       e_data_book_view_notify_complete (opbv->book_view, NULL);
+                       g_slist_free_full (created_objects, e_book_meta_backend_info_free);
+                       g_slist_free_full (modified_objects, e_book_meta_backend_info_free);
                }
 
-               g_object_unref (opbv->book_view);
-       } break;
+               g_slist_free_full (found_infos, e_book_meta_backend_info_free);
        }
 
-       if (op->cancellable)
-               g_object_unref (op->cancellable);
-       if (op->book)
-               g_object_unref (op->book);
-       g_free (op);
+       ebb_mapi_unlock_connection (bbmapi);
 
-       /* for cases when this is the last reference */
-       e_mapi_utils_unref_in_thread (G_OBJECT (backend));
+       return success;
 }
 
-static void
-str_op_abstract (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const 
gchar *str, OperationType ot)
-{
-       OperationStr *op;
-       EBookBackendMAPI *ebbm;
-       EBookBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
-
-       ebbm = E_BOOK_BACKEND_MAPI (backend);
-       priv = ebbm->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (ebbm);
-       if (book)
-               g_object_ref (book);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationStr, 1);
-       op->base.ot = ot;
-       op->base.book = book;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->str = g_strdup (str);
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-static void
-str_slist_op_abstract (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, 
const GSList *str_slist, OperationType ot)
+static gboolean
+ebb_mapi_search_sync (EBookMetaBackend *meta_backend,
+                     const gchar *expr,
+                     gboolean meta_contact,
+                     GSList **out_contacts,
+                     GCancellable *cancellable,
+                     GError **error)
 {
-       OperationStrSlist *op;
-       EBookBackendMAPI *ebbm;
-       EBookBackendMAPIPrivate *priv;
-       GSList *l;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
-       g_return_if_fail (str_slist != NULL);
-
-       ebbm = E_BOOK_BACKEND_MAPI (backend);
-       priv = ebbm->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (ebbm);
-       if (book)
-               g_object_ref (book);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationStrSlist, 1);
-       op->base.ot = ot;
-       op->base.book = book;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->str_slist = g_slist_copy ((GSList *) str_slist);
-
-       for (l = op->str_slist; l; l = l->next) {
-               l->data = g_strdup (l->data);
-       }
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
 
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
+       /* Ignore errors, just try its best */
+       ebb_mapi_update_cache_for_expression (E_BOOK_BACKEND_MAPI (meta_backend), expr, cancellable, NULL);
 
-#define STR_OP_DEF(_func, _ot)                                                 \
-static void                                                                    \
-_func (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *str)    
  \
-{                                                                              \
-       str_op_abstract (backend, book, opid, cancellable, str, _ot);           \
+       /* Chain up to parent's method */
+       return E_BOOK_META_BACKEND_CLASS (e_book_backend_mapi_parent_class)->search_sync (meta_backend, expr, 
meta_contact,
+               out_contacts, cancellable, error);
 }
 
-#define STR_SLIST_OP_DEF(_func, _ot)                                                   \
-static void                                                                            \
-_func (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList 
*str_slist)       \
-{                                                                                      \
-       str_slist_op_abstract (backend, book, opid, cancellable, str_slist, _ot);       \
-}
+static gboolean
+ebb_mapi_search_uids_sync (EBookMetaBackend *meta_backend,
+                          const gchar *expr,
+                          GSList **out_uids,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
 
-STR_SLIST_OP_DEF (ebbm_op_create_contacts, OP_CREATE_CONTACTS)
-STR_SLIST_OP_DEF (ebbm_op_modify_contacts, OP_MODIFY_CONTACTS)
-STR_SLIST_OP_DEF (ebbm_op_remove_contacts, OP_REMOVE_CONTACTS)
-STR_OP_DEF  (ebbm_op_get_contact, OP_GET_CONTACT)
-STR_OP_DEF  (ebbm_op_get_contact_list, OP_GET_CONTACT_LIST)
+       /* Ignore errors, just try its best */
+       ebb_mapi_update_cache_for_expression (E_BOOK_BACKEND_MAPI (meta_backend), expr, cancellable, NULL);
 
-static void
-ebbm_op_open (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, gboolean 
only_if_exists)
-{
-       OperationOpen *op;
-       EBookBackendMAPI *ebbm;
-       EBookBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
-
-       ebbm = E_BOOK_BACKEND_MAPI (backend);
-       priv = ebbm->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (ebbm);
-       if (book)
-               g_object_ref (book);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationOpen, 1);
-       op->base.ot = OP_OPEN;
-       op->base.book = book;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->only_if_exists = only_if_exists;
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
+       /* Chain up to parent's method */
+       return E_BOOK_META_BACKEND_CLASS (e_book_backend_mapi_parent_class)->search_uids_sync (meta_backend, 
expr,
+               out_uids, cancellable, error);
 }
 
-static void
-ebbm_op_start_view (EBookBackend *backend, EDataBookView *book_view)
+static gchar *
+ebb_mapi_get_backend_property (EBookBackend *backend,
+                              const gchar *prop_name)
 {
-       OperationBookView *op;
-       EBookBackendMAPI *ebbm;
-       EBookBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
-       g_return_if_fail (book_view != NULL);
-
-       ebbm = E_BOOK_BACKEND_MAPI (backend);
-       priv = ebbm->priv;
-       g_return_if_fail (priv != NULL);
+       EBookBackendMAPI *bbmapi;
 
-       g_object_ref (ebbm);
+       g_return_val_if_fail (prop_name != NULL, NULL);
 
-       op = g_new0 (OperationBookView, 1);
-       op->base.ot = OP_START_BOOK_VIEW;
-       op->base.book = NULL;
-       op->base.opid = 0;
-       op->book_view = g_object_ref (book_view);
+       bbmapi = E_BOOK_BACKEND_MAPI (backend);
 
-       g_mutex_lock (&priv->running_views_lock);
-       g_hash_table_insert (priv->running_views, book_view, g_cancellable_new ());
-       g_mutex_unlock (&priv->running_views_lock);
+       if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+               return g_strjoin (",",
+                       "net",
+                       "contact-lists",
+                       e_book_meta_backend_get_capabilities (E_BOOK_META_BACKEND (backend)),
+                       ebb_mapi_is_marked_for_offline (bbmapi) ? "do-initial-query" : NULL,
+                       NULL);
+       } else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
+               return g_strdup (e_contact_field_name (E_CONTACT_FILE_AS));
+       } else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
+               GSList *fields;
+               gchar *prop_value;
 
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
+               fields = e_mapi_book_utils_get_supported_contact_fields ();
+               prop_value = e_data_book_string_slist_to_comma_string (fields);
+               g_slist_free (fields);
 
-static void
-ebbm_op_stop_view (EBookBackend *backend, EDataBookView *book_view)
-{
-       OperationBookView *op;
-       EBookBackendMAPI *ebbm;
-       EBookBackendMAPIPrivate *priv;
-       GCancellable *cancellable;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
-       g_return_if_fail (book_view != NULL);
-
-       ebbm = E_BOOK_BACKEND_MAPI (backend);
-       priv = ebbm->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (ebbm);
-
-       op = g_new0 (OperationBookView, 1);
-       op->base.ot = OP_STOP_BOOK_VIEW;
-       op->base.book = NULL;
-       op->base.opid = 0;
-       op->book_view = g_object_ref (book_view);
-
-       g_mutex_lock (&priv->running_views_lock);
-       cancellable = g_hash_table_lookup (priv->running_views, book_view);
-       if (cancellable)
-               g_cancellable_cancel (cancellable);
-       g_hash_table_remove (priv->running_views, book_view);
-       g_mutex_unlock (&priv->running_views_lock);
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
+               return prop_value;
+       }
 
-static void
-e_book_backend_mapi_init (EBookBackendMAPI *ebma)
-{
-       ebma->priv = G_TYPE_INSTANCE_GET_PRIVATE (ebma, E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIPrivate);
-
-       ebma->priv->op_queue = e_mapi_operation_queue_new ((EMapiOperationQueueFunc) ebbm_operation_cb, ebma);
-       ebma->priv->running_views = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
g_object_unref);
-       g_mutex_init (&ebma->priv->running_views_lock);
-       g_rec_mutex_init (&ebma->priv->conn_lock);
-
-       ebma->priv->update_cache = g_cancellable_new ();
-       ebma->priv->update_cache_thread = NULL;
-       ebma->priv->last_update_cache = 0;
-       ebma->priv->last_server_contact_count = 0;
-       ebma->priv->last_modify_time = 0;
-       ebma->priv->server_dirty = FALSE;
-       ebma->priv->last_db_commit_time = 0;
-
-       g_signal_connect (
-               ebma, "notify::online",
-               G_CALLBACK (ebbm_notify_online_cb), NULL);
+       /* Chain up to parent's method */
+       return E_BOOK_BACKEND_CLASS (e_book_backend_mapi_parent_class)->get_backend_property (backend, 
prop_name);
 }
 
 static gboolean
-ebbm_get_destination_address (EBackend *backend,
-                             gchar **host,
-                             guint16 *port)
+ebb_mapi_get_destination_address (EBackend *backend,
+                                 gchar **host,
+                                 guint16 *port)
 {
        ESourceRegistry *registry;
        ESource *source;
        gboolean result = FALSE;
 
-       g_return_val_if_fail (port != NULL, FALSE);
        g_return_val_if_fail (host != NULL, FALSE);
+       g_return_val_if_fail (port != NULL, FALSE);
 
        registry = e_book_backend_get_registry (E_BOOK_BACKEND (backend));
        source = e_backend_get_source (backend);
@@ -1340,403 +1089,97 @@ ebbm_get_destination_address (EBackend *backend,
 }
 
 static void
-ebbm_constructed (GObject *object)
+ebb_mapi_constructed (GObject *object)
 {
+       EBookBackendMAPI *bbmapi = E_BOOK_BACKEND_MAPI (object);
+
+       /* Chaing up to parent's method */
        G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->constructed (object);
 
        /* Reset the connectable, it steals data from Authentication extension,
           where is written no address */
        e_backend_set_connectable (E_BACKEND (object), NULL);
-}
-
-static void
-ebbm_dispose (GObject *object)
-{
-       EBookBackendMAPI *ebma = E_BOOK_BACKEND_MAPI (object);
-       EBookBackendMAPIPrivate *priv = ebma->priv;
-
-       if (priv) {
-               if (priv->update_cache_thread) {
-                       g_cancellable_cancel (priv->update_cache);
-                       g_thread_join (priv->update_cache_thread);
-                       priv->update_cache_thread = NULL;
-               }
-
-               #define FREE(x) if (x) { g_free (x); x = NULL; }
-               #define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
-
-               e_book_backend_mapi_lock_connection (ebma);
-               UNREF (priv->conn);
-               e_book_backend_mapi_unlock_connection (ebma);
-               UNREF (priv->op_queue);
-               UNREF (priv->db);
-               UNREF (priv->update_cache);
-
-               FREE (priv->book_uid);
-
-               g_hash_table_destroy (priv->running_views);
-               g_mutex_clear (&priv->running_views_lock);
-               g_rec_mutex_clear (&priv->conn_lock);
 
-               #undef UNREF
-               #undef FREE
-
-               ebma->priv = NULL;
-       }
-
-       /* Chain up to parent's dispose() method. */
-       if (G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose)
-               G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose (object);
+       e_book_backend_set_writable (E_BOOK_BACKEND (bbmapi), !e_book_backend_mapi_get_is_gal (bbmapi));
 }
 
 static void
-e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
+ebb_mapi_dispose (GObject *object)
 {
-       GObjectClass  *object_class = G_OBJECT_CLASS (klass);
-       EBackendClass *backend_class = E_BACKEND_CLASS (klass);
-       EBookBackendClass *book_backend_class = E_BOOK_BACKEND_CLASS (klass);
+       EBookBackendMAPI *bbmapi = E_BOOK_BACKEND_MAPI (object);
 
-       g_type_class_add_private (klass, sizeof (EBookBackendMAPIPrivate));
+       g_clear_object (&bbmapi->priv->conn);
 
-       object_class->constructed               = ebbm_constructed;
-       object_class->dispose                   = ebbm_dispose;
-
-       backend_class->get_destination_address  = ebbm_get_destination_address;
-       backend_class->authenticate_sync        = ebbm_authenticate_sync;
-
-       book_backend_class->open                = ebbm_op_open;
-       book_backend_class->create_contacts     = ebbm_op_create_contacts;
-       book_backend_class->remove_contacts     = ebbm_op_remove_contacts;
-       book_backend_class->modify_contacts     = ebbm_op_modify_contacts;
-       book_backend_class->get_contact         = ebbm_op_get_contact;
-       book_backend_class->get_contact_list    = ebbm_op_get_contact_list;
-       book_backend_class->start_view          = ebbm_op_start_view;
-       book_backend_class->stop_view           = ebbm_op_stop_view;
-       book_backend_class->get_backend_property= ebbm_get_backend_property;
-
-       klass->op_open                          = ebbm_open;
-       klass->op_remove                        = ebbm_remove;
-       klass->op_get_contact                   = ebbm_get_contact;
-       klass->op_get_contact_list              = ebbm_get_contact_list;
-
-       klass->op_connection_status_changed     = NULL;
-       klass->op_get_status_message            = NULL;
-       klass->op_book_view_thread              = NULL;
-       klass->op_get_contacts_count            = NULL;
-       klass->op_list_known_uids               = NULL;
-       klass->op_transfer_contacts             = NULL;
+       /* Chain up to parent's method */
+       G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose (object);
 }
 
-const gchar *
-e_book_backend_mapi_get_book_uid (EBookBackendMAPI *ebma)
-{
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
-       g_return_val_if_fail (ebma->priv != NULL, NULL);
-
-       return ebma->priv->book_uid;
-}
-
-void
-e_book_backend_mapi_lock_connection (EBookBackendMAPI *ebma)
-{
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
-       g_return_if_fail (ebma->priv != NULL);
-
-       g_rec_mutex_lock (&ebma->priv->conn_lock);
-}
-
-void
-e_book_backend_mapi_unlock_connection (EBookBackendMAPI *ebma)
-{
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
-       g_return_if_fail (ebma->priv != NULL);
-
-       g_rec_mutex_unlock (&ebma->priv->conn_lock);
-}
-
-EMapiConnection *
-e_book_backend_mapi_get_connection (EBookBackendMAPI *ebma,
-                                   GCancellable *cancellable,
-                                   GError **perror)
+static void
+ebb_mapi_finalize (GObject *object)
 {
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
-       g_return_val_if_fail (ebma->priv != NULL, NULL);
-
-       if (ebma->priv->conn)
-               return ebma->priv->conn;
-
-       if (!e_backend_get_online (E_BACKEND (ebma)))
-               return NULL;
-
-       if (!e_book_backend_mapi_ensure_connected (ebma, cancellable, perror))
-               return NULL;
+       EBookBackendMAPI *bbmapi = E_BOOK_BACKEND_MAPI (object);
 
-       return ebma->priv->conn;
-}
-
-void
-e_book_backend_mapi_get_db (EBookBackendMAPI *ebma, EBookBackendSqliteDB **db)
-{
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
-       g_return_if_fail (ebma->priv != NULL);
+       g_rec_mutex_clear (&bbmapi->priv->conn_lock);
 
-       if (db)
-               *db = ebma->priv->db;
+       /* Chain up to parent's method */
+       G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->finalize (object);
 }
 
-gboolean
-e_book_backend_mapi_book_view_is_running (EBookBackendMAPI *ebma, EDataBookView *book_view)
+static void
+e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
 {
-       gboolean res;
-
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
-       g_return_val_if_fail (ebma->priv != NULL, FALSE);
+       GObjectClass *object_class;
+       EBackendClass *backend_class;
+       EBookBackendClass *book_backend_class;
+       EBookMetaBackendClass *meta_backend_class;
 
-       g_mutex_lock (&ebma->priv->running_views_lock);
-       res = g_hash_table_lookup (ebma->priv->running_views, book_view) != NULL;
-       g_mutex_unlock (&ebma->priv->running_views_lock);
+       g_type_class_add_private (klass, sizeof (EBookBackendMAPIPrivate));
 
-       return res;
+       meta_backend_class = E_BOOK_META_BACKEND_CLASS (klass);
+       meta_backend_class->backend_module_filename = "libebookbackendmapi.so";
+       meta_backend_class->connect_sync = ebb_mapi_connect_sync;
+       meta_backend_class->disconnect_sync = ebb_mapi_disconnect_sync;
+       meta_backend_class->get_changes_sync = ebb_mapi_get_changes_sync;
+       meta_backend_class->list_existing_sync = ebb_mapi_list_existing_sync;
+       meta_backend_class->load_contact_sync = ebb_mapi_load_contact_sync;
+       meta_backend_class->save_contact_sync = ebb_mapi_save_contact_sync;
+       meta_backend_class->remove_contact_sync = ebb_mapi_remove_contact_sync;
+       meta_backend_class->search_sync = ebb_mapi_search_sync;
+       meta_backend_class->search_uids_sync = ebb_mapi_search_uids_sync;
+
+       book_backend_class = E_BOOK_BACKEND_CLASS (klass);
+       book_backend_class->get_backend_property = ebb_mapi_get_backend_property;
+
+       backend_class = E_BACKEND_CLASS (klass);
+       backend_class->get_destination_address = ebb_mapi_get_destination_address;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->constructed = ebb_mapi_constructed;
+       object_class->dispose = ebb_mapi_dispose;
+       object_class->finalize = ebb_mapi_finalize;
 }
 
-gboolean
-e_book_backend_mapi_is_marked_for_offline (EBookBackendMAPI *ebma)
+static void
+e_book_backend_mapi_init (EBookBackendMAPI *bbmapi)
 {
-       ESource *source;
-       ESourceOffline *offline_extension;
-
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
-       g_return_val_if_fail (ebma->priv != NULL, FALSE);
+       bbmapi->priv = G_TYPE_INSTANCE_GET_PRIVATE (bbmapi, E_TYPE_BOOK_BACKEND_MAPI, 
EBookBackendMAPIPrivate);
 
-       source = e_backend_get_source (E_BACKEND (ebma));
-
-       offline_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_OFFLINE);
-
-       return e_source_offline_get_stay_synchronized (offline_extension);
+       g_rec_mutex_init (&bbmapi->priv->conn_lock);
 }
 
 void
-e_book_backend_mapi_update_view_by_cache (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error)
+e_book_backend_mapi_set_is_gal (EBookBackendMAPI *bbmapi,
+                               gboolean is_gal)
 {
-       gint i = 0;
-       const gchar *query = NULL;
-       EBookBackendSExp *sexp;
-       EBookBackendSqliteDB *db = NULL;
-       GSList *hits, *l;
-
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
-       g_return_if_fail (book_view != NULL);
-       g_return_if_fail (E_IS_DATA_BOOK_VIEW (book_view));
-
-       sexp = e_data_book_view_get_sexp (book_view);
-       query = e_book_backend_sexp_text (sexp);
-
-       e_book_backend_mapi_get_db (ebma, &db);
-
-       g_return_if_fail (db != NULL);
-
-       hits = e_book_backend_sqlitedb_search (db, EMA_EBB_CACHE_FOLDERID,
-                                              query, NULL, NULL, NULL, error);
+       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
 
-       for (l = hits; (!error || !*error) && l; l = l->next) {
-               EbSdbSearchData *sdata = (EbSdbSearchData *) l->data;
-               gchar *vcard = sdata->vcard;
-
-               if (((i++) % 10) == 0 && !e_book_backend_mapi_book_view_is_running (ebma, book_view))
-                       break;
-
-               if (vcard) {
-                       EContact *contact = e_contact_new_from_vcard (vcard);
-                       e_data_book_view_notify_update (book_view, contact);
-                       g_object_unref (contact);
-               }
-       }
-
-       if (hits) {
-               g_slist_foreach (hits, (GFunc) e_book_backend_sqlitedb_search_data_free, NULL);
-               g_slist_free (hits);
-       }
+       bbmapi->priv->is_gal = is_gal;
 }
 
-/* called from op_transfer_contacts - book_view and notify_contact_data are taken from there;
-   notify_contact_data is a pointer to glong last_notification, if not NULL;
-   returns whether can continue with fetching */
 gboolean
-e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma,
-                                          EDataBookView *pbook_view,
-                                          EContact *contact,
-                                          gint index,
-                                          gint total,
-                                          gboolean cache_is_locked,
-                                          gpointer notify_contact_data)
-{
-       EBookBackendMAPIPrivate *priv;
-       glong *last_notification = notify_contact_data;
-       EDataBookView *book_view = pbook_view;
-       glong current_time;
-       GError *error = NULL;
-
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
-       g_return_val_if_fail (ebma->priv, FALSE);
-       g_return_val_if_fail (contact != NULL, FALSE);
-
-       priv = ebma->priv;
-       g_return_val_if_fail (priv != NULL, FALSE);
-
-       current_time = get_current_time_ms ();
-
-       /* report progres to any book_view, if not passed in;
-          it can happen when cache is filling and the book view started later */
-       if (!book_view)
-               book_view = ebbm_pick_book_view (ebma);
-       else
-               g_object_ref (book_view);
-
-       if (book_view) {
-               if (!e_book_backend_mapi_book_view_is_running (ebma, book_view)) {
-                       g_object_unref (book_view);
-                       return FALSE;
-               }
-
-               if (index > 0 && last_notification && current_time - *last_notification > 333) {
-                       gchar *status_msg = NULL;
-                       EBookBackendMAPIClass *ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
-
-                       if (ebmac->op_get_status_message)
-                               status_msg = ebmac->op_get_status_message (ebma, index, total);
-
-                       if (status_msg)
-                               e_data_book_view_notify_progress (book_view, -1, status_msg);
-
-                       g_free (status_msg);
-
-                       *last_notification = current_time;
-               }
-
-               g_object_unref (book_view);
-       }
-
-       if (!pbook_view && g_cancellable_is_cancelled (priv->update_cache))
-               return FALSE;
-
-       e_book_backend_sqlitedb_new_contact (priv->db,
-                                            EMA_EBB_CACHE_FOLDERID, contact,
-                                            TRUE, &error);
-
-       /* commit not often than each minute, also to not lose data already transferred */
-       if (cache_is_locked && current_time - priv->last_db_commit_time >= 60000) {
-               e_book_backend_sqlitedb_unlock_updates (priv->db, TRUE, NULL);
-               e_book_backend_sqlitedb_lock_updates (priv->db, NULL);
-
-               priv->last_db_commit_time = current_time;
-       }
-
-       if (!error) {
-               e_book_backend_notify_update (E_BOOK_BACKEND (ebma), contact);
-               return TRUE;
-       }
-
-       g_error_free (error);
-
-       return FALSE;
-}
-
-void
-e_book_backend_mapi_notify_contact_removed (EBookBackendMAPI *ebma, const gchar *uid)
-{
-       EBookBackendMAPIPrivate *priv;
-       GError *error = NULL;
-       gboolean ret;
-
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
-       g_return_if_fail (ebma->priv);
-       g_return_if_fail (uid != NULL);
-
-       priv = ebma->priv;
-       g_return_if_fail (priv != NULL);
-
-       ret = e_book_backend_sqlitedb_remove_contact (priv->db,
-                                                     EMA_EBB_CACHE_FOLDERID,
-                                                     uid, &error);
-       if (ret && !error)
-               e_book_backend_notify_remove (E_BOOK_BACKEND (ebma), uid);
-
-       if (error)
-               g_error_free (error);
-}
-
-void
-e_book_backend_mapi_cache_set (EBookBackendMAPI *ebma, const gchar *key, const gchar *value)
+e_book_backend_mapi_get_is_gal (EBookBackendMAPI *bbmapi)
 {
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
-       g_return_if_fail (ebma->priv != NULL);
-       g_return_if_fail (ebma->priv->db != NULL);
-       g_return_if_fail (key != NULL);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
 
-       e_book_backend_sqlitedb_set_key_value (ebma->priv->db, EMA_EBB_CACHE_FOLDERID, key, value, NULL);
-}
-
-gchar *
-e_book_backend_mapi_cache_get (EBookBackendMAPI *ebma, const gchar *key)
-{
-       g_return_val_if_fail (ebma != NULL, NULL);
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
-       g_return_val_if_fail (ebma->priv != NULL, NULL);
-       g_return_val_if_fail (ebma->priv->db != NULL, NULL);
-       g_return_val_if_fail (key != NULL, NULL);
-
-       return e_book_backend_sqlitedb_get_key_value (ebma->priv->db, EMA_EBB_CACHE_FOLDERID, key, NULL);
-}
-
-void
-e_book_backend_mapi_refresh_cache (EBookBackendMAPI *ebma)
-{
-       g_return_if_fail (ebma != NULL);
-       g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
-
-       ebma->priv->last_update_cache = 0;
-       ebma->priv->last_modify_time = 0;
-       ebma->priv->server_dirty = TRUE;
-
-       ebbm_maybe_invoke_cache_update (ebma);
-}
-
-/* utility functions/macros */
-
-void
-mapi_error_to_edb_error (GError **perror, const GError *mapi_error, EDataBookStatus code, const gchar 
*context)
-{
-       gchar *err_msg = NULL;
-
-       if (!perror)
-               return;
-
-       if (g_error_matches (mapi_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-               g_propagate_error (perror, g_error_copy (mapi_error));
-               return;
-       }
-
-       if (code == E_DATA_BOOK_STATUS_OTHER_ERROR && mapi_error && mapi_error->domain == E_MAPI_ERROR) {
-               /* Change error to more accurate only with OTHER_ERROR */
-               switch (mapi_error->code) {
-               case MAPI_E_PASSWORD_CHANGE_REQUIRED:
-               case MAPI_E_PASSWORD_EXPIRED:
-                       code = E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED;
-                       break;
-               case ecRpcFailed:
-                       code = E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       if (context)
-               err_msg = g_strconcat (context, mapi_error ? ": " : NULL, mapi_error ? mapi_error->message : 
NULL, NULL);
-
-       g_propagate_error (perror, e_data_book_create_error (code, err_msg ? err_msg : mapi_error ? 
mapi_error->message : _("Unknown error")));
-
-       g_free (err_msg);
+       return bbmapi->priv->is_gal;
 }
diff --git a/src/addressbook/e-book-backend-mapi.h b/src/addressbook/e-book-backend-mapi.h
index 5751e32..b5848d8 100644
--- a/src/addressbook/e-book-backend-mapi.h
+++ b/src/addressbook/e-book-backend-mapi.h
@@ -18,8 +18,8 @@
  *
  */
 
-#ifndef __E_BOOK_BACKEND_MAPI_H__
-#define __E_BOOK_BACKEND_MAPI_H__
+#ifndef E_BOOK_BACKEND_MAPI_H
+#define E_BOOK_BACKEND_MAPI_H
 
 #include <glib.h>
 #include <gio/gio.h>
@@ -44,106 +44,21 @@ typedef struct _EBookBackendMAPIPrivate EBookBackendMAPIPrivate;
 
 typedef struct
 {
-       EBookBackend             parent_object;
+       EBookMetaBackend parent_object;
        EBookBackendMAPIPrivate *priv;
 } EBookBackendMAPI;
 
-struct ListKnownUidsData
-{
-       GHashTable *uid_to_rev;
-       time_t latest_last_modify;
-};
-
 typedef struct
 {
-       EBookBackendClass parent_class;
-
-       void (*op_open) (EBookBackendMAPI *ebma, GCancellable *cancellable, gboolean only_if_exists, GError 
**error);
-       void (*op_remove) (EBookBackendMAPI *ebma, GCancellable *cancellable, GError **error);
-
-       void (*op_create_contacts) (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, 
GSList **added_contacts, GError **error);
-       void (*op_remove_contacts) (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *id_list, 
GSList **removed_ids, GError **error);
-       void (*op_modify_contacts) (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, 
GSList **modified_contacts, GError **error);
-       void (*op_get_contact) (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *id, gchar 
**vcard, GError **error);
-       void (*op_get_contact_list) (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *query, 
GSList **vCards, GError **error);
-
-       /* called when online state changes on the backend */
-       void (*op_connection_status_changed) (EBookBackendMAPI *ebma, gboolean is_online);
-
-       /* returns a status message for a progress of fetching entries "index/total";
-          returned string is freed by g_free() */
-       gchar * (*op_get_status_message) (EBookBackendMAPI *ebma, gint index, gint total);
-
-       /* function called for each new book_view, in a separate thread;
-          this function is optional, contacts from cache are always processed
-          before this function call */
-       void (*op_book_view_thread) (EBookBackendMAPI *ebma, EDataBookView *book_view, GCancellable 
*cancellable, GError **error);
-
-       /* gets current count of contacts in the folder corresponding to the backend */
-       void (*op_get_contacts_count) (EBookBackendMAPI *ebma, guint32 *obj_total, GCancellable *cancellable, 
GError **error);
-
-       /* function to fetch list of known uids (strings) on the server;
-          it's used to synchronize local cache with available items;
-          uids has the uid key, as a newly allocated string;
-          value is a revision (REV) field value as newly allocated string */
-       void (*op_list_known_uids) (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb, gpointer 
build_rs_cb_data, struct ListKnownUidsData *lku, GCancellable *cancellable, GError **error);
-
-       /* function called to populate cache or similar operations;
-          book_view can be NULL, call e_book_backend_mapi_notify_contact_update for each
-          transferred contact with this book_view and notify_contact_data */
-       void (*op_transfer_contacts) (EBookBackendMAPI *ebma, const GSList *uids, EDataBookView *book_view, 
gpointer notify_contact_data, GCancellable *cancellable, GError **error);
+       EBookMetaBackendClass parent_class;
 } EBookBackendMAPIClass;
 
-GType e_book_backend_mapi_get_type (void);
-
-const gchar *          e_book_backend_mapi_get_book_uid (EBookBackendMAPI *ebma);
-void                   e_book_backend_mapi_lock_connection             (EBookBackendMAPI *ebma);
-void                   e_book_backend_mapi_unlock_connection           (EBookBackendMAPI *ebma);
-EMapiConnection *      e_book_backend_mapi_get_connection              (EBookBackendMAPI *ebma,
-                                                                        GCancellable *cancellable,
-                                                                        GError **perror);
-gboolean               e_book_backend_mapi_ensure_connected            (EBookBackendMAPI *ebma,
-                                                                        GCancellable *cancellable, 
-                                                                        GError **error);
-void                   e_book_backend_mapi_maybe_disconnect            (EBookBackendMAPI *ebma,
-                                                                        const GError *mapi_error);
-void                   e_book_backend_mapi_get_db                      (EBookBackendMAPI *ebma,
-                                                                        EBookBackendSqliteDB **db);
-gboolean               e_book_backend_mapi_book_view_is_running        (EBookBackendMAPI *ebma,
-                                                                        EDataBookView *book_view);
-void                   e_book_backend_mapi_update_view_by_cache        (EBookBackendMAPI *ebma,
-                                                                        EDataBookView *book_view,
-                                                                        GError **error);
-gboolean               e_book_backend_mapi_is_marked_for_offline       (EBookBackendMAPI *ebma);
-gboolean               e_book_backend_mapi_notify_contact_update       (EBookBackendMAPI *ebma,
-                                                                        EDataBookView *book_view,
-                                                                        EContact *contact,
-                                                                        gint index,
-                                                                        gint total,
-                                                                        gboolean cache_is_locked,
-                                                                        gpointer notify_contact_data);
-void                   e_book_backend_mapi_notify_contact_removed      (EBookBackendMAPI *ebma,
-                                                                        const gchar *uid);
-void                   e_book_backend_mapi_cache_set                   (EBookBackendMAPI *ebma,
-                                                                        const gchar *key,
-                                                                        const gchar *value);
-gchar *                        e_book_backend_mapi_cache_get                   (EBookBackendMAPI *ebma,
-                                                                        const gchar *key);
-void                   e_book_backend_mapi_refresh_cache               (EBookBackendMAPI *ebma);
-
-/* utility functions/macros */
-
-#define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
-#define EDB_ERROR_EX(_code, _msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg)
-
-void mapi_error_to_edb_error (GError **perror, const GError *mapi_error, EDataBookStatus code, const gchar 
*context);
+GType          e_book_backend_mapi_get_type    (void);
 
-/* The EBookBackendSqliteDB functions allow for a single all-caches database,
- * which is a feature we do not use, and instead have per-folder databases.
- * Therefore we have a couple arbitrary constants... */
-#define EMA_EBB_CACHE_PROFILEID        "EMA_PROFILE"
-#define EMA_EBB_CACHE_FOLDERID "EMA_FOLDER"
+void           e_book_backend_mapi_set_is_gal  (EBookBackendMAPI *bbmapi,
+                                                gboolean is_gal);
+gboolean       e_book_backend_mapi_get_is_gal  (EBookBackendMAPI *bbmapi);
 
 G_END_DECLS
 
-#endif /* __E_BOOK_BACKEND_MAPI_H__ */
+#endif /* E_BOOK_BACKEND_MAPI_H */
diff --git a/src/calendar/e-cal-backend-mapi.c b/src/calendar/e-cal-backend-mapi.c
index d3142b1..aced948 100644
--- a/src/calendar/e-cal-backend-mapi.c
+++ b/src/calendar/e-cal-backend-mapi.c
@@ -1,5 +1,8 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
@@ -16,9 +19,6 @@
  *
  * Authors:
  *    Suman Manjunath <msuman novell com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #include "evolution-mapi-config.h"
@@ -31,11 +31,10 @@
 #include <libedata-cal/libedata-cal.h>
 #include <libedataserver/libedataserver.h>
 
-#include <e-mapi-connection.h>
-#include <e-mapi-cal-utils.h>
-#include <e-mapi-utils.h>
-#include <e-mapi-operation-queue.h>
-#include <e-source-mapi-folder.h>
+#include "e-mapi-connection.h"
+#include "e-mapi-cal-utils.h"
+#include "e-mapi-utils.h"
+#include "e-source-mapi-folder.h"
 
 #include "e-cal-backend-mapi.h"
 
@@ -54,107 +53,21 @@
 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
 #define EDC_ERROR_EX(_code, _msg) e_data_cal_create_error (_code, _msg)
 
-G_DEFINE_TYPE (ECalBackendMAPI, e_cal_backend_mapi, E_TYPE_CAL_BACKEND)
-
-typedef struct {
-       GCond cond;
-       GMutex mutex;
-       gboolean exit;
-} SyncDelta;
+G_DEFINE_TYPE (ECalBackendMAPI, e_cal_backend_mapi, E_TYPE_CAL_META_BACKEND)
 
-/* Private part of the CalBackendMAPI structure */
 struct _ECalBackendMAPIPrivate {
-       EMapiOperationQueue *op_queue;
-
-       mapi_id_t               fid;
-       gboolean is_public_folder;
-       gchar *foreign_username;
+       GRecMutex conn_lock;
        EMapiConnection *conn;
-
-       /* A mutex to control access to the private structure */
-       GMutex                  mutex;
-       ECalBackendStore        *store;
-       gboolean                read_only;
-       gchar                   *uri;
-       GMutex                  updating_mutex;
-       GMutex                  is_updating_mutex;
-       gboolean                is_updating;
-
-       /* timeout handler for syncing sendoptions */
-       guint                   sendoptions_sync_timeout;
-
-       /* used exclusively for delta fetching */
-       guint                   timeout_id;
-       GThread                 *dthread;
-       SyncDelta               *dlock;
-
-       time_t last_refresh;
-       gint last_obj_total;
-       GCancellable *cancellable;
 };
 
-static CamelMapiSettings *
-ecbm_get_collection_settings (ECalBackendMAPI *ecbm)
-{
-       ESource *source;
-       ESource *collection;
-       ESourceCamel *extension;
-       ESourceRegistry *registry;
-       CamelSettings *settings;
-       const gchar *extension_name;
-
-       source = e_backend_get_source (E_BACKEND (ecbm));
-       registry = e_cal_backend_get_registry (E_CAL_BACKEND (ecbm));
-
-       extension_name = e_source_camel_get_extension_name ("mapi");
-       e_source_camel_generate_subtype ("mapi", CAMEL_TYPE_MAPI_SETTINGS);
-
-       /* The collection settings live in our parent data source. */
-       collection = e_source_registry_find_extension (
-               registry, source, extension_name);
-       g_return_val_if_fail (collection != NULL, NULL);
-
-       extension = e_source_get_extension (collection, extension_name);
-       settings = e_source_camel_get_settings (extension);
-
-       g_object_unref (collection);
-
-       return CAMEL_MAPI_SETTINGS (settings);
-}
-
-static gboolean
-ecbm_open_folder (ECalBackendMAPI *ecbm,
-                 EMapiConnection *conn,
-                 mapi_object_t *obj_folder,
-                 GCancellable *cancellable,
-                 GError **perror)
-{
-       gboolean res;
-
-       g_return_val_if_fail (ecbm != NULL, FALSE);
-       g_return_val_if_fail (ecbm->priv != NULL, FALSE);
-       g_return_val_if_fail (conn != NULL, FALSE);
-       g_return_val_if_fail (obj_folder != NULL, FALSE);
-
-       if (ecbm->priv->foreign_username)
-               res = e_mapi_connection_open_foreign_folder (conn, ecbm->priv->foreign_username, 
ecbm->priv->fid, obj_folder, cancellable, perror);
-       else if (ecbm->priv->is_public_folder)
-               res = e_mapi_connection_open_public_folder (conn, ecbm->priv->fid, obj_folder, cancellable, 
perror);
-       else
-               res = e_mapi_connection_open_personal_folder (conn, ecbm->priv->fid, obj_folder, cancellable, 
perror);
-
-       return res;
-}
-
-static EMapiConnection *e_cal_backend_mapi_get_connection      (ECalBackendMAPI *cbma, GCancellable 
*cancellable, GError **perror);
-static void            e_cal_backend_mapi_maybe_disconnect     (ECalBackendMAPI *cbma, const GError 
*mapi_error);
-
-#define CACHE_REFRESH_INTERVAL 600000
-
-static GMutex auth_mutex;
+static gchar * ecb_mapi_dup_component_revision_cb      (ECalCache *cal_cache,
+                                                        icalcomponent *icalcomp);
 
 static void
-mapi_error_to_edc_error (GError **perror, const GError *mapi_error, EDataCalCallStatus code, const gchar 
*context)
+ecb_mapi_error_to_edc_error (GError **perror,
+                            const GError *mapi_error,
+                            EDataCalCallStatus code,
+                            const gchar *context)
 {
        gchar *err_msg = NULL;
 
@@ -189,917 +102,498 @@ mapi_error_to_edc_error (GError **perror, const GError *mapi_error, EDataCalCall
        g_free (err_msg);
 }
 
-/* **** UTILITY FUNCTIONS **** */
-
 static void
-get_comp_mid (icalcomponent *icalcomp, mapi_id_t *mid)
+ecb_mapi_lock_connection (ECalBackendMAPI *cbmapi)
 {
-       gchar *x_mid;
-
-       g_return_if_fail (icalcomp != NULL);
-       g_return_if_fail (mid != NULL);
-
-       x_mid = e_mapi_cal_utils_get_icomp_x_prop (icalcomp, "X-EVOLUTION-MAPI-MID");
-       if (x_mid) {
-               e_mapi_util_mapi_id_from_string (x_mid, mid);
-               g_free (x_mid);
-       } else {
-               e_mapi_util_mapi_id_from_string (icalcomponent_get_uid (icalcomp), mid);
-       }
-}
-
-static ESource *
-ecbm_find_identity_source (ECalBackendMAPI *cbmapi)
-{
-       ESourceRegistry *registry;
-       GList *all_sources, *my_sources, *iter;
-       CamelMapiSettings *settings;
-       ESource *res = NULL;
-
-       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), NULL);
-
-       settings = ecbm_get_collection_settings (cbmapi);
-       g_return_val_if_fail (settings != NULL, NULL);
-
-       registry = e_cal_backend_get_registry (E_CAL_BACKEND (cbmapi));
-       all_sources = e_source_registry_list_sources (registry, NULL);
-       my_sources = e_mapi_utils_filter_sources_for_profile (all_sources,
-               camel_mapi_settings_get_profile (settings));
-       g_list_free_full (all_sources, g_object_unref);
-
-       for (iter = my_sources; iter; iter = iter->next) {
-               ESource *source = iter->data;
-
-               if (!source)
-                       continue;
-
-               if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_IDENTITY)) {
-                       res = g_object_ref (source);
-                       break;
-               }
-       }
-
-       g_list_free_full (my_sources, g_object_unref);
-
-       return res;
-}
-
-static const gchar *
-ecbm_get_owner_name (ECalBackendMAPI *cbmapi)
-{
-       ESource *identity_source;
-       ESourceMailIdentity *identity_ext;
-       const gchar *res = NULL;
-
-       identity_source = ecbm_find_identity_source (cbmapi);
-       if (!identity_source)
-               return NULL;
-
-       identity_ext = e_source_get_extension (identity_source, E_SOURCE_EXTENSION_MAIL_IDENTITY);
-       if (identity_ext)
-               res = e_source_mail_identity_get_name (identity_ext);
-
-       g_object_unref (identity_source);
-
-       return res;
-}
-
-static const gchar *
-ecbm_get_owner_email (ECalBackendMAPI *cbmapi)
-{
-       ESource *identity_source;
-       ESourceMailIdentity *identity_ext;
-       const gchar *res = NULL;
-
-       identity_source = ecbm_find_identity_source (cbmapi);
-       if (!identity_source)
-               return NULL;
-
-       identity_ext = e_source_get_extension (identity_source, E_SOURCE_EXTENSION_MAIL_IDENTITY);
-       if (identity_ext)
-               res = e_source_mail_identity_get_address (identity_ext);
-
-       g_object_unref (identity_source);
+       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi));
 
-       return res;
+       g_rec_mutex_lock (&cbmapi->priv->conn_lock);
 }
 
-static const gchar *
-ecbm_get_user_name (ECalBackendMAPI *cbmapi)
+static void
+ecb_mapi_unlock_connection (ECalBackendMAPI *cbmapi)
 {
-       return ecbm_get_owner_name (cbmapi);
-}
+       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi));
 
-static const gchar *
-ecbm_get_user_email (ECalBackendMAPI *cbmapi)
-{
-       return ecbm_get_owner_email (cbmapi);
+       g_rec_mutex_unlock (&cbmapi->priv->conn_lock);
 }
 
-static gchar *
-ecbm_get_backend_property (ECalBackend *backend,
-                           const gchar *prop_name)
+static CamelMapiSettings *
+ecb_mapi_get_collection_settings (ECalBackendMAPI *cbmapi)
 {
-       g_return_val_if_fail (prop_name != NULL, NULL);
-
-       if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
-               return g_strjoin (
-                       ",",
-                       CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT,
-                       CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS,
-                       CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS,
-                       CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS,
-                       CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY,
-                       CAL_STATIC_CAPABILITY_REMOVE_ALARMS,
-                       CAL_STATIC_CAPABILITY_NO_THISANDFUTURE,
-                       CAL_STATIC_CAPABILITY_NO_THISANDPRIOR,
-                       CAL_STATIC_CAPABILITY_CREATE_MESSAGES,
-                       CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK,
-                       CAL_STATIC_CAPABILITY_NO_CONV_TO_RECUR,
-                       CAL_STATIC_CAPABILITY_HAS_UNACCEPTED_MEETING,
-                       CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED,
-                       CAL_STATIC_CAPABILITY_NO_MEMO_START_DATE,
-                       CAL_STATIC_CAPABILITY_TASK_DATE_ONLY,
-                       NULL);
-       } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
-               ECalBackendMAPI *cbmapi;
-
-               cbmapi = E_CAL_BACKEND_MAPI (backend);
-
-               return g_strdup (ecbm_get_user_email (cbmapi));
-       } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
-               /* We don't support email alarms. This should not have been called. */
-               return NULL;
-       } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
-               ECalComponent *comp;
-               gchar *prop_value;
+       ESource *source;
+       ESource *collection;
+       ESourceCamel *extension;
+       ESourceRegistry *registry;
+       CamelSettings *settings;
+       const gchar *extension_name;
 
-               comp = e_cal_component_new ();
+       source = e_backend_get_source (E_BACKEND (cbmapi));
+       registry = e_cal_backend_get_registry (E_CAL_BACKEND (cbmapi));
 
-               switch (e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
-               case ICAL_VEVENT_COMPONENT:
-                       e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
-                       break;
-               case ICAL_VTODO_COMPONENT:
-                       e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
-                       break;
-               case ICAL_VJOURNAL_COMPONENT:
-                       e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
-                       break;
-               default:
-                       g_object_unref (comp);
-                       return NULL;
-               }
+       extension_name = e_source_camel_get_extension_name ("mapi");
+       e_source_camel_generate_subtype ("mapi", CAMEL_TYPE_MAPI_SETTINGS);
 
-               prop_value = e_cal_component_get_as_string (comp);
+       /* The collection settings live in our parent data source. */
+       collection = e_source_registry_find_extension (registry, source, extension_name);
+       g_return_val_if_fail (collection != NULL, NULL);
 
-               g_object_unref (comp);
+       extension = e_source_get_extension (collection, extension_name);
+       settings = e_source_camel_get_settings (extension);
 
-               return prop_value;
-       }
+       g_object_unref (collection);
 
-       /* Chain up to parent's get_backend_property() method. */
-       return E_CAL_BACKEND_CLASS (e_cal_backend_mapi_parent_class)->
-               get_backend_property (backend, prop_name);
+       return CAMEL_MAPI_SETTINGS (settings);
 }
 
-static void
-ecbm_refresh (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
+static gboolean
+ecb_mapi_open_folder (ECalBackendMAPI *cbmapi,
+                     mapi_object_t *out_obj_folder,
+                     GCancellable *cancellable,
+                     GError **error)
 {
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
+       ESource *source;
+       ESourceMapiFolder *ext_mapi_folder;
+       mapi_id_t fid;
+       gchar *foreign_username;
+       gboolean success;
 
-       if (priv && priv->dlock)
-               g_cond_signal (&priv->dlock->cond);
-}
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), FALSE);
+       g_return_val_if_fail (cbmapi->priv->conn != NULL, FALSE);
+       g_return_val_if_fail (out_obj_folder != NULL, FALSE);
 
-#if 0
-static const gchar *
-get_element_type (icalcomponent_kind kind)
-{
+       source = e_backend_get_source (E_BACKEND (cbmapi));
+       ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 
-       const gchar *type = "";
+       fid = e_source_mapi_folder_get_id (ext_mapi_folder);
+       foreign_username = e_source_mapi_folder_dup_foreign_username (ext_mapi_folder);
 
-       if (kind == ICAL_VEVENT_COMPONENT)
-               type = "Appointment";
-       else if (kind == ICAL_VTODO_COMPONENT)
-               type = "Task";
-       else if (kind == ICAL_VJOURNAL_COMPONENT)
-               type = "Note";
+       if (foreign_username && *foreign_username)
+               success = e_mapi_connection_open_foreign_folder (cbmapi->priv->conn, foreign_username, fid, 
out_obj_folder, cancellable, error);
+       else if (e_source_mapi_folder_is_public (ext_mapi_folder))
+               success = e_mapi_connection_open_public_folder (cbmapi->priv->conn, fid, out_obj_folder, 
cancellable, error);
+       else
+               success = e_mapi_connection_open_personal_folder (cbmapi->priv->conn, fid, out_obj_folder, 
cancellable, error);
 
-       return type;
+       g_free (foreign_username);
 
+       return success;
 }
-#endif
 
 static void
-notify_view_progress (ECalBackendMAPI *cbmapi, guint index, guint total)
+ecb_mapi_maybe_disconnect (ECalBackendMAPI *cbmapi,
+                          const GError *mapi_error)
 {
-       GList *list, *link;
-       gchar *progress_string;
-       gint percent = -1;
-
-       if (total > 0)
-               percent = index * 100 / total;
-
-       if (percent > 100)
-               percent = 99;
-
-       /* To translators: This message is displayed on the status bar when calendar/tasks/memo items are 
being fetched from the server. */
-       progress_string = g_strdup_printf (_("Loading items in folder %s"),
-                               e_source_get_display_name (e_backend_get_source (E_BACKEND (cbmapi))));
-
-       list = e_cal_backend_list_views (E_CAL_BACKEND (cbmapi));
-
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               EDataCalView *view = E_DATA_CAL_VIEW (link->data);
-
-               if (e_data_cal_view_is_completed (view))
-                       continue;
+       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi));
 
-               if (e_data_cal_view_is_stopped (view))
-                       continue;
+       /* no error or already disconnected */
+       if (!mapi_error || !cbmapi->priv->conn)
+               return;
 
-               e_data_cal_view_notify_progress (view, percent, progress_string);
+       if (g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed) ||
+           g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_CALL_FAILED)) {
+               e_mapi_connection_disconnect (cbmapi->priv->conn,
+                       !g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed),
+                       NULL, NULL);
+               g_clear_object (&cbmapi->priv->conn);
        }
-
-       g_list_free_full (list, g_object_unref);
-
-       g_free (progress_string);
 }
 
 static void
-notify_view_completed (ECalBackendMAPI *cbmapi)
+ecb_mapi_get_comp_mid (icalcomponent *icalcomp,
+                      mapi_id_t *mid)
 {
-       GList *list, *link;
-
-       list = e_cal_backend_list_views (E_CAL_BACKEND (cbmapi));
-
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               EDataCalView *view = E_DATA_CAL_VIEW (link->data);
-
-               if (e_data_cal_view_is_completed (view))
-                       continue;
+       gchar *x_mid;
 
-               if (e_data_cal_view_is_stopped (view))
-                       continue;
+       g_return_if_fail (icalcomp != NULL);
+       g_return_if_fail (mid != NULL);
 
-               e_data_cal_view_notify_complete (view, NULL);
+       x_mid = e_mapi_cal_utils_get_icomp_x_prop (icalcomp, "X-EVOLUTION-MAPI-MID");
+       if (x_mid) {
+               e_mapi_util_mapi_id_from_string (x_mid, mid);
+               g_free (x_mid);
+       } else {
+               e_mapi_util_mapi_id_from_string (icalcomponent_get_uid (icalcomp), mid);
        }
-
-       g_list_free_full (list, g_object_unref);
 }
 
-static icaltimezone *
-resolve_tzid (const char *tzid, gpointer user_data)
-{
-       ETimezoneCache *timezone_cache;
-
-       timezone_cache = E_TIMEZONE_CACHE (user_data);
-
-       return e_timezone_cache_get_timezone (timezone_cache, tzid);
-}
-
-static void
-put_component_to_store (ECalBackendMAPI *cbmapi,
-                       ECalComponent *comp)
-{
-       time_t time_start, time_end;
-       ECalBackendMAPIPrivate *priv;
-
-       priv = cbmapi->priv;
-
-       e_cal_util_get_component_occur_times (comp, &time_start, &time_end,
-                                               resolve_tzid, cbmapi, icaltimezone_get_utc_timezone (),
-                                               e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi)));
-
-       e_cal_backend_store_put_component_with_time_range (priv->store, comp, time_start, time_end);
-}
-
-#define notify_error(_mmapi_backend, _merror, _mformat)                                        \
-       G_STMT_START {                                                                  \
-               notify_error_ex (_mmapi_backend,                                        \
-                                &(_merror),                                            \
-                                _mformat,                                              \
-                                (_merror) ? (_merror)->message : _("Unknown error"));  \
-       } G_STMT_END
-
-static void notify_error_ex (ECalBackendMAPI *mapi_backend, GError **perror, const gchar *format, ...) 
G_GNUC_PRINTF (3, 4);
-
-static void
-notify_error_ex (ECalBackendMAPI *mapi_backend, GError **perror, const gchar *format, ...)
+static gboolean
+ecb_mapi_capture_req_props (EMapiConnection *conn,
+                           TALLOC_CTX *mem_ctx,
+                           /* const */ EMapiObject *object,
+                           guint32 obj_index,
+                           guint32 obj_total,
+                           gpointer user_data,
+                           GCancellable *cancellable,
+                           GError **perror)
 {
-       gchar *msg;
-       va_list args;
+       struct cal_cbdata *cbdata = user_data;
+       const uint32_t *ui32;
 
-       g_return_if_fail (mapi_backend != NULL);
-       g_return_if_fail (format != NULL);
+       g_return_val_if_fail (object != NULL, FALSE);
+       g_return_val_if_fail (cbdata != NULL, FALSE);
 
-       if (perror && (
-           g_error_matches (*perror, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
-           g_error_matches (*perror, E_MAPI_ERROR, MAPI_E_USER_CANCEL)))
-               return;
+       ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagOwnerAppointmentId);
+       if (ui32)
+               cbdata->appt_id = *ui32;
+       ui32 = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentSequence);
+       if (ui32)
+               cbdata->appt_seq = *ui32;
 
-       va_start (args, format);
-       msg = g_strdup_vprintf (format, args);
-       va_end (args);
+       cbdata->cleanglobalid = e_mapi_util_copy_sbinary_short (e_mapi_util_find_array_propval 
(&object->properties, PidLidCleanGlobalObjectId));
+       cbdata->globalid = e_mapi_util_copy_sbinary_short (e_mapi_util_find_array_propval 
(&object->properties, PidLidGlobalObjectId));
 
-       e_cal_backend_notify_error (E_CAL_BACKEND (mapi_backend), msg);
-       g_free (msg);
+       cbdata->username = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSentRepresentingName));
+       cbdata->useridtype = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSentRepresentingAddressType));
+       cbdata->userid = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSentRepresentingEmailAddress));
 
-       if (perror)
-               e_cal_backend_mapi_maybe_disconnect (mapi_backend, *perror);
-       g_clear_error (perror);
-}
+       cbdata->ownername = g_strdup (e_mapi_util_find_array_propval (&object->properties, PidTagSenderName));
+       cbdata->owneridtype = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSenderAddressType));
+       cbdata->ownerid = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSenderEmailAddress));
 
-static void
-free_component_slist (gpointer ptr)
-{
-       g_slist_free_full (ptr, g_object_unref);
+       return TRUE;
 }
 
-static void
-drop_removed_comps_cb (gpointer pmid, gpointer slist, gpointer pcbmapi)
+static gboolean
+ecb_mapi_list_for_one_mid_cb (EMapiConnection *conn,
+                             TALLOC_CTX *mem_ctx,
+                             const ListObjectsData *object_data,
+                             guint32 obj_index,
+                             guint32 obj_total,
+                             gpointer user_data,
+                             GCancellable *cancellable,
+                             GError **perror)
 {
-       ECalBackendMAPI *cbmapi = pcbmapi;
-       ECalBackend *backend;
-       GSList *iter;
-
-       g_return_if_fail (pcbmapi != NULL);
-
-       backend = E_CAL_BACKEND (cbmapi);
-       g_return_if_fail (backend != NULL);
-
-       for (iter = slist; iter; iter = iter->next) {
-               ECalComponent *comp = iter->data;
-               ECalComponentId *id;
-
-               if (!comp) {
-                       g_debug ("%s: NULL component in list", G_STRFUNC);
-                       continue;
-               }
+       mapi_id_t *pmid = user_data;
 
-               id = e_cal_component_get_id (comp);
-               if (!id) {
-                       g_debug ("%s: Failed to get component's ID", G_STRFUNC);
-                       continue;
-               }
+       g_return_val_if_fail (pmid != NULL, FALSE);
+       g_return_val_if_fail (object_data != NULL, FALSE);
 
-               if (e_cal_backend_store_remove_component (cbmapi->priv->store, id->uid, id->rid)) {
-                       e_cal_backend_notify_component_removed (backend, id, comp, NULL);
-               }
+       *pmid = object_data->mid;
 
-               e_cal_component_free_id (id);
-       }
+       return TRUE;
 }
 
-struct ListCalendarObjectsData
-{
-       GSList *changed_mids;           /* newly allocated mapi_id_t *; these will be fetched again */
-       GHashTable *known_comps;        /* reffed ECalComponent-s from the cache; those left will be removed;
-                                          key is 'mapi_id_t *', the mid;
-                                          value is GSList of the component and its detached instances
-                                       */
-       time_t latest_modified;
-};
-
 static gboolean
-list_calendar_objects_cb (EMapiConnection *conn,
-                         TALLOC_CTX *mem_ctx,
-                         const ListObjectsData *object_data,
-                         guint32 obj_index,
-                         guint32 obj_total,
-                         gpointer user_data,
-                         GCancellable *cancellable,
-                         GError **perror)
+ecb_mapi_build_global_id_restriction (EMapiConnection *conn,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct mapi_SRestriction **restrictions,
+                                     gpointer user_data,
+                                     GCancellable *cancellable,
+                                     GError **perror)
 {
-       struct ListCalendarObjectsData *lco = user_data;
-       GSList *slist;
-       gboolean need_update = FALSE;
-
-       g_return_val_if_fail (object_data != NULL, FALSE);
-       g_return_val_if_fail (lco != NULL, FALSE);
+       ECalComponent *comp = user_data;
+       struct SBinary_short sb;
+       struct SPropValue sprop;
+       struct mapi_SRestriction *restriction;
+       gchar *propval;
 
-       if (object_data->msg_class &&
-           g_ascii_strcasecmp (object_data->msg_class, "IPM.Note") == 0) {
-               return TRUE;
-       }
+       g_return_val_if_fail (restrictions != NULL, FALSE);
+       g_return_val_if_fail (comp != NULL, FALSE);
 
-       if (lco->latest_modified < object_data->last_modified)
-               lco->latest_modified = object_data->last_modified;
+       restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
+       g_return_val_if_fail (restriction != NULL, FALSE);
 
-       slist = g_hash_table_lookup (lco->known_comps, &object_data->mid);
-       if (!slist) {
-               /* it's a new component on the server */
-               need_update = TRUE;
-       } else {
-               /* known component, which might change */
-               ECalComponent *comp = slist->data;
-               struct icaltimetype *last_mod = NULL;
+       restriction->rt = RES_PROPERTY;
+       restriction->res.resProperty.relop = RELOP_EQ;
+       restriction->res.resProperty.ulPropTag = PidLidGlobalObjectId;
 
-               /* pretty bad, but do not avoid fetching of other objects */
-               g_return_val_if_fail (comp != NULL, TRUE);
+       propval = e_mapi_cal_utils_get_icomp_x_prop (e_cal_component_get_icalcomponent (comp), 
"X-EVOLUTION-MAPI-GLOBALID");
+       if (propval && *propval) {
+               gsize len = 0;
 
-               e_cal_component_get_last_modified (comp, &last_mod);
+               sb.lpb = g_base64_decode (propval, &len);
+               sb.cb = len;
+       } else {
+               struct icaltimetype ical_creation_time = { 0 };
+               struct FILETIME creation_time = { 0 };
+               const gchar *uid;
 
-               if (!last_mod ||
-                   icaltime_compare (icaltime_from_timet_with_zone (object_data->last_modified, 0, 
icaltimezone_get_utc_timezone ()), *last_mod) != 0) {
-                       need_update = TRUE;
-               }
+               uid = icalcomponent_get_uid (e_cal_component_get_icalcomponent (comp));
 
-               if (last_mod)
-                       e_cal_component_free_icaltimetype (last_mod);
+               e_cal_component_get_dtstamp (comp, &ical_creation_time);
 
-               g_hash_table_remove (lco->known_comps, &object_data->mid);
+               e_mapi_util_time_t_to_filetime (icaltime_as_timet (ical_creation_time), &creation_time);
+               e_mapi_cal_util_generate_globalobjectid (FALSE, uid, NULL, ical_creation_time.year ? 
&creation_time : NULL, &sb);
        }
+       g_free (propval);
 
-       if (need_update) {
-               mapi_id_t *pmid;
-
-               pmid = g_new0 (mapi_id_t, 1);
-               *pmid = object_data->mid;
+       set_SPropValue_proptag (&sprop, PidLidGlobalObjectId, &sb);
+       cast_mapi_SPropValue (mem_ctx, &(restriction->res.resProperty.lpProp), &sprop);
 
-               lco->changed_mids = g_slist_prepend (lco->changed_mids, pmid);
-       }
+       *restrictions = restriction;
 
        return TRUE;
 }
 
 static gboolean
-transfer_calendar_objects_cb (EMapiConnection *conn,
-                             TALLOC_CTX *mem_ctx,
-                             /* const */ EMapiObject *object,
-                             guint32 obj_index,
-                             guint32 obj_total,
-                             gpointer user_data,
-                             GCancellable *cancellable,
-                             GError **perror)
-{
-       ECalBackendMAPI *cbmapi = user_data;
-       ECalBackend *backend;
-       ECalComponent *comp;
-       const mapi_id_t *pmid;
-       gchar *use_uid;
-       GSList *comps = NULL, *iter;
-
-       g_return_val_if_fail (cbmapi != NULL, FALSE);
-       g_return_val_if_fail (object != NULL, FALSE);
-
-       backend = E_CAL_BACKEND (cbmapi);
-       g_return_val_if_fail (backend != NULL, FALSE);
-
-       pmid = e_mapi_util_find_array_propval (&object->properties, PidTagMid);
-       if (pmid)
-               use_uid = e_mapi_util_mapi_id_to_string (*pmid);
-       else
-               use_uid = e_util_generate_uid ();
-
-       comp = e_mapi_cal_util_object_to_comp (conn, object,
-               e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi)), FALSE,
-               e_cal_backend_get_cache_dir (E_CAL_BACKEND (cbmapi)),
-               use_uid, &comps);
-
-       g_free (use_uid);
-
-       if (comp)
-               comps = g_slist_prepend (comps, comp);
-
-       for (iter = comps; iter; iter = iter->next) {
-               ECalComponentId *id;
-               ECalComponent *old_comp;
-
-               comp = iter->data;
-               if (!comp)
-                       continue;
-
-               e_cal_component_commit_sequence (comp);
-
-               id = e_cal_component_get_id (comp);
-               if (!id) {
-                       g_debug ("%s: Failed to get component's ID", G_STRFUNC);
-                       continue;
-               }
+ecb_mapi_build_global_id_or_mid_restriction_from_uid (EMapiConnection *conn,
+                                                     TALLOC_CTX *mem_ctx,
+                                                     struct mapi_SRestriction **restrictions,
+                                                     gpointer user_data,
+                                                     GCancellable *cancellable,
+                                                     GError **perror)
+{
+       const gchar *uid = user_data;
+       struct SPropValue sprop;
+       struct mapi_SRestriction *restriction;
+       mapi_id_t mid = 0;
 
-               old_comp = e_cal_backend_store_get_component (cbmapi->priv->store, id->uid, id->rid);
-               if (old_comp) {
-                       mapi_id_t old_mid, new_mid;
+       g_return_val_if_fail (restrictions != NULL, FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
 
-                       get_comp_mid (e_cal_component_get_icalcomponent (old_comp), &old_mid);
-                       get_comp_mid (e_cal_component_get_icalcomponent (comp), &new_mid);
+       restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
+       g_return_val_if_fail (restriction != NULL, FALSE);
 
-                       if (new_mid && old_mid && new_mid != old_mid) {
-                               use_uid = e_mapi_util_mapi_id_to_string (new_mid);
-                               e_cal_component_set_uid (comp, use_uid);
-                               g_free (use_uid);
+       restriction->rt = RES_PROPERTY;
+       restriction->res.resProperty.relop = RELOP_EQ;
 
-                               e_cal_component_free_id (id);
-                               id = e_cal_component_get_id (comp);
-                               if (!id) {
-                                       g_debug ("%s: Failed to re-get component's ID", G_STRFUNC);
-                                       continue;
-                               }
+       if (e_mapi_util_mapi_id_from_string (uid, &mid) && mid) {
+               restriction->res.resProperty.ulPropTag = PidTagMid;
 
-                               old_comp = e_cal_backend_store_get_component (cbmapi->priv->store, id->uid, 
id->rid);
-                       }
-               }
+               set_SPropValue_proptag (&sprop, PidTagMid, &mid);
+               cast_mapi_SPropValue (mem_ctx, &(restriction->res.resProperty.lpProp), &sprop);
+       } else {
+               struct SBinary_short sb;
+               gsize len = 0;
 
-               put_component_to_store (cbmapi, comp);
+               sb.lpb = g_base64_decode (uid, &len);
+               sb.cb = len;
 
-               if (old_comp) {
-                       e_cal_backend_notify_component_modified (backend, old_comp, comp);
-                       g_object_unref (old_comp);
-               } else {
-                       e_cal_backend_notify_component_created (E_CAL_BACKEND (cbmapi), comp);
-               }
+               restriction->res.resProperty.ulPropTag = PidLidGlobalObjectId;
 
-               e_cal_component_free_id (id);
+               set_SPropValue_proptag (&sprop, PidLidGlobalObjectId, &sb);
+               cast_mapi_SPropValue (mem_ctx, &(restriction->res.resProperty.lpProp), &sprop);
        }
 
-       g_slist_free_full (comps, g_object_unref);
-
-       notify_view_progress (cbmapi, obj_index, obj_total);
+       *restrictions = restriction;
 
        return TRUE;
 }
 
+/* should call free_server_data() before done with cbdata */
 static void
-copy_to_known_comps (gpointer key, gpointer value, gpointer user_data)
-{
-       mapi_id_t *pmid = key, *pmidcopy;
-       GSList *comps = value;
-       GHashTable *known_comps = user_data;
-
-       g_return_if_fail (pmid != NULL);
-       g_return_if_fail (known_comps != NULL);
-
-       pmidcopy = g_new0 (mapi_id_t, 1);
-       *pmidcopy = *pmid;
-
-       /* stealing 'comps' pointer here */
-       g_hash_table_insert (known_comps, pmidcopy, comps);
-}
-
-static gboolean
-update_local_cache (ECalBackendMAPI *cbmapi, GCancellable *cancellable)
+ecb_mapi_get_server_data (ECalBackendMAPI *cbmapi,
+                         ECalComponent *comp,
+                         struct cal_cbdata *cbdata,
+                         GCancellable *cancellable)
 {
-       ECalBackendMAPIPrivate *priv;
        EMapiConnection *conn;
-       struct ListCalendarObjectsData lco;
-       GSList *iter, *components;
+       icalcomponent *icalcomp;
+       mapi_id_t mid;
        mapi_object_t obj_folder;
-       gboolean success = FALSE;
        GError *mapi_error = NULL;
-       GHashTable *comps_by_mids;
-       gboolean partial_update;
-       struct FolderBasicPropertiesData fbp;
-
-       priv = cbmapi->priv;
-       if (!e_backend_get_online (E_BACKEND (cbmapi)))
-               return FALSE;
-
-       g_mutex_lock (&priv->is_updating_mutex);
-       priv->is_updating = TRUE;
-       g_mutex_unlock (&priv->is_updating_mutex);
-
-       g_mutex_lock (&priv->updating_mutex);
-
-       conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
-       if (!conn) {
-               g_clear_error (&mapi_error);
-               goto cleanup;
-       }
 
-       g_object_ref (conn);
+       icalcomp = e_cal_component_get_icalcomponent (comp);
+       ecb_mapi_get_comp_mid (icalcomp, &mid);
 
-       success = ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &mapi_error);
-       if (!success) {
-               notify_error (cbmapi, mapi_error, _("Failed to open folder: %s"));
+       conn = cbmapi->priv->conn;
+       if (!conn)
                goto cleanup;
-       }
 
-       success = e_mapi_connection_get_folder_properties (conn, &obj_folder, NULL, NULL,
-                                        e_mapi_utils_get_folder_basic_properties_cb, &fbp,
-                                        cancellable, &mapi_error);
-       if (!success) {
-               notify_error (cbmapi, mapi_error, _("Failed to get folder properties: %s"));
-               e_mapi_connection_close_folder (conn, &obj_folder, NULL, NULL);
+       if (!ecb_mapi_open_folder (cbmapi, &obj_folder, cancellable, &mapi_error))
                goto cleanup;
-       }
-
-       comps_by_mids = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, NULL);
-
-       components = e_cal_backend_store_get_components (priv->store);
-       for (iter = components; iter; iter = iter->next) {
-               ECalComponent *comp = iter->data;
-               mapi_id_t mid, *pmid;
-               GSList *comps;
-
-               if (!comp)
-                       continue;
-
-               get_comp_mid (e_cal_component_get_icalcomponent (comp), &mid);
-
-               pmid = g_new0 (mapi_id_t, 1);
-               *pmid = mid;
-
-               comps = g_slist_prepend (g_hash_table_lookup (comps_by_mids, pmid), comp);
-               g_hash_table_insert (comps_by_mids, pmid, comps);
-       }
-       /* doesn't call unref, because the hash table holds the components */
-       g_slist_free (components);
-
-       lco.changed_mids = NULL;
-       lco.known_comps = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, free_component_slist);
-       lco.latest_modified = priv->last_refresh;
-
-       g_hash_table_foreach (comps_by_mids, copy_to_known_comps, lco.known_comps);
-       g_hash_table_destroy (comps_by_mids);
-       comps_by_mids = NULL;
-
-       partial_update = priv->last_refresh > 0 && fbp.obj_total == priv->last_obj_total;
-       success = e_mapi_connection_list_objects (conn, &obj_folder,
-               partial_update ? e_mapi_utils_build_last_modify_restriction : NULL, &priv->last_refresh,
-               list_calendar_objects_cb, &lco,
-               cancellable, &mapi_error);
-       if (!success) {
-               notify_error (cbmapi, mapi_error, _("Failed to list objects: %s"));
-
-               e_mapi_connection_close_folder (conn, &obj_folder, NULL, NULL);
-
-               g_slist_free_full (lco.changed_mids, g_free);
-               g_hash_table_destroy (lco.known_comps);
-
-               goto cleanup;
-       }
-
-       e_cal_backend_store_freeze_changes (priv->store);
-
-       if (!partial_update)
-               g_hash_table_foreach (lco.known_comps, drop_removed_comps_cb, cbmapi);
-       g_hash_table_destroy (lco.known_comps);
-       lco.known_comps = NULL;
-
-       if (lco.changed_mids) {
-               success = e_mapi_connection_transfer_objects (conn, &obj_folder,
-                       lco.changed_mids,
-                       transfer_calendar_objects_cb, cbmapi,
-                       cancellable, &mapi_error);
-
-               e_cal_backend_store_thaw_changes (priv->store);
-
-               if (!success) {
-                       notify_error (cbmapi, mapi_error, _("Failed to transfer objects: %s"));
-
-                       e_mapi_connection_close_folder (conn, &obj_folder, NULL, NULL);
-
-                       g_slist_free_full (lco.changed_mids, g_free);
 
+       if (!e_mapi_connection_transfer_object (conn, &obj_folder, mid, ecb_mapi_capture_req_props, cbdata, 
cancellable, &mapi_error)) {
+               if (!g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NOT_FOUND)) {
+                       g_clear_error (&mapi_error);
+                       e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
                        goto cleanup;
                }
 
-               g_slist_free_full (lco.changed_mids, g_free);
-       } else {
-               e_cal_backend_store_thaw_changes (priv->store);
+               /* try to find by global-id, if not found by MID */
+               g_clear_error (&mapi_error);
        }
 
-       priv->last_obj_total = fbp.obj_total;
-       priv->last_refresh = lco.latest_modified;
-
-       success = e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-       if (!success) {
-               notify_error (cbmapi, mapi_error, _("Failed to close folder: %s"));
-
-               goto cleanup;
+       if (e_mapi_connection_list_objects (conn, &obj_folder,
+                                           ecb_mapi_build_global_id_restriction, comp,
+                                           ecb_mapi_list_for_one_mid_cb, &mid,
+                                           cancellable, &mapi_error)) {
+               e_mapi_connection_transfer_object (conn, &obj_folder, mid, ecb_mapi_capture_req_props, 
cbdata, cancellable, &mapi_error);
        }
 
- cleanup:
-       if (conn)
-               g_object_unref (conn);
-       g_mutex_unlock (&priv->updating_mutex);
-
-       g_mutex_lock (&priv->is_updating_mutex);
-       priv->is_updating = FALSE;
-       g_mutex_unlock (&priv->is_updating_mutex);
-
-       notify_view_completed (cbmapi);
+       e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 
-       return success;
+ cleanup:
+       ecb_mapi_maybe_disconnect (cbmapi, mapi_error);
+       g_clear_error (&mapi_error);
 }
 
+/* frees data members allocated in get_server_data(), not the cbdata itself */
 static void
-ecbm_get_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const 
gchar *rid, gchar **object, GError **error)
+ecb_mapi_free_server_data (struct cal_cbdata *cbdata)
 {
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       cbmapi = (ECalBackendMAPI *)(backend);
-       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
-       e_mapi_return_data_cal_error_if_fail (object != NULL, InvalidArg);
-
-       priv = cbmapi->priv;
-
-       g_mutex_lock (&priv->mutex);
-
-       if (rid && *rid) {
-               ECalComponent *comp;
-
-               /* search the object in the cache */
-               comp = e_cal_backend_store_get_component (priv->store, uid, rid);
-
-               if (!comp) {
-                       /* the object is not in the backend store, double check that it's
-                        * also not on the server to prevent for a race condition where we
-                        * might otherwise mistakenly generate a new UID */
-                       g_mutex_unlock (&priv->mutex);
-                       update_local_cache (cbmapi, cancellable);
-                       g_mutex_lock (&priv->mutex);
-                       comp = e_cal_backend_store_get_component (priv->store, uid, rid);
-               }
-
-               if (comp) {
-                       g_mutex_unlock (&priv->mutex);
-
-                       *object = e_cal_component_get_as_string (comp);
+       if (!cbdata)
+               return;
 
-                       g_object_unref (comp);
-               } else {
-                       g_mutex_unlock (&priv->mutex);
-               }
-       } else {
-               *object = e_cal_backend_store_get_components_by_uid_as_ical_string (priv->store, uid);
-               if (!*object && e_backend_get_online (E_BACKEND (backend))) {
-                       /* the object is not in the backend store, double check that it's
-                        * also not on the server to prevent for a race condition where we
-                        * might otherwise mistakenly generate a new UID */
-                       g_mutex_unlock (&priv->mutex);
-                       update_local_cache (cbmapi, cancellable);
-                       g_mutex_lock (&priv->mutex);
-
-                       *object = e_cal_backend_store_get_components_by_uid_as_ical_string (priv->store, uid);
-               }
+       #define do_free(_func, _val) _func (_val); _val = NULL
 
-               g_mutex_unlock (&priv->mutex);
-       }
+       do_free (e_mapi_util_free_sbinary_short, cbdata->cleanglobalid);
+       do_free (e_mapi_util_free_sbinary_short, cbdata->globalid);
+       do_free (g_free, cbdata->username);
+       do_free (g_free, cbdata->useridtype);
+       do_free (g_free, cbdata->userid);
+       do_free (g_free, cbdata->ownername);
+       do_free (g_free, cbdata->owneridtype);
+       do_free (g_free, cbdata->ownerid);
 
-       if (!*object)
-               g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+       #undef do_free
 }
 
-static void
-ecbm_get_object_list (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, 
GSList **objects, GError **perror)
-{
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       GSList *components, *l;
-       ECalBackendSExp *cbsexp;
-       gboolean search_needed = TRUE;
-       time_t occur_start = -1, occur_end = -1;
-       gboolean prunning_by_time;
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
+#define free_and_dupe_str(_des, _new) G_STMT_START {   \
+       g_free (_des);                                  \
+       _des = g_strdup (_new);                         \
+       } G_STMT_END
 
-       g_mutex_lock (&priv->mutex);
+static ESource *
+ecb_mapi_find_identity_source (ECalBackendMAPI *cbmapi)
+{
+       ESourceRegistry *registry;
+       GList *all_sources, *my_sources, *iter;
+       CamelMapiSettings *settings;
+       ESource *res = NULL;
 
-       if (g_str_equal (sexp, "#t"))
-               search_needed = FALSE;
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), NULL);
 
-       cbsexp = e_cal_backend_sexp_new (sexp);
+       settings = ecb_mapi_get_collection_settings (cbmapi);
+       g_return_val_if_fail (settings != NULL, NULL);
 
-       if (!cbsexp) {
-               g_mutex_unlock (&priv->mutex);
-               g_propagate_error (perror, EDC_ERROR (InvalidQuery));
-               return;
-       }
+       registry = e_cal_backend_get_registry (E_CAL_BACKEND (cbmapi));
+       all_sources = e_source_registry_list_sources (registry, NULL);
+       my_sources = e_mapi_utils_filter_sources_for_profile (all_sources,
+               camel_mapi_settings_get_profile (settings));
+       g_list_free_full (all_sources, g_object_unref);
 
-       *objects = NULL;
-       prunning_by_time = e_cal_backend_sexp_evaluate_occur_times(cbsexp, &occur_start, &occur_end);
+       for (iter = my_sources; iter; iter = iter->next) {
+               ESource *source = iter->data;
 
-       components = prunning_by_time ?
-               e_cal_backend_store_get_components_occuring_in_range (priv->store, occur_start, occur_end)
-               : e_cal_backend_store_get_components (priv->store);
+               if (!source)
+                       continue;
 
-       for (l = components; l != NULL; l = l->next) {
-               ECalComponent *comp = E_CAL_COMPONENT (l->data);
-               if (e_cal_backend_get_kind (E_CAL_BACKEND (backend)) ==
-                               icalcomponent_isa (e_cal_component_get_icalcomponent (comp))) {
-                       if ((!search_needed) ||
-                                       (e_cal_backend_sexp_match_comp (cbsexp, comp, E_TIMEZONE_CACHE 
(backend)))) {
-                               *objects = g_slist_append (*objects, e_cal_component_get_as_string (comp));
-                       }
+               if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_IDENTITY)) {
+                       res = g_object_ref (source);
+                       break;
                }
        }
 
-       g_slist_free_full (components, g_object_unref);
-       g_object_unref (cbsexp);
-       g_mutex_unlock (&priv->mutex);
-}
+       g_list_free_full (my_sources, g_object_unref);
 
-static void
-ecbm_get_attachment_uris (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, 
const gchar *rid, GSList **list, GError **perror)
-{
-       /* TODO implement the function */
-       g_propagate_error (perror, EDC_ERROR (NotSupported));
+       return res;
 }
 
-static guint
-get_cache_refresh_interval (void)
+static const gchar *
+ecb_mapi_get_owner_name (ECalBackendMAPI *cbmapi)
 {
-       guint time_interval;
-       const gchar *time_interval_string = NULL;
-
-       time_interval = CACHE_REFRESH_INTERVAL;
-       time_interval_string = g_getenv ("GETQM_TIME_INTERVAL");
-       if (time_interval_string) {
-               time_interval = g_ascii_strtod (time_interval_string, NULL);
-               time_interval *= (60*1000);
-       }
+       ESource *identity_source;
+       ESourceMailIdentity *identity_ext;
+       const gchar *res = NULL;
+
+       identity_source = ecb_mapi_find_identity_source (cbmapi);
+       if (!identity_source)
+               return NULL;
+
+       identity_ext = e_source_get_extension (identity_source, E_SOURCE_EXTENSION_MAIL_IDENTITY);
+       if (identity_ext)
+               res = e_source_mail_identity_get_name (identity_ext);
+
+       g_object_unref (identity_source);
 
-       return time_interval;
+       return res;
 }
 
-static gpointer
-delta_thread (gpointer data)
+static const gchar *
+ecb_mapi_get_owner_email (ECalBackendMAPI *cbmapi)
 {
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       GCancellable *cancellable;
-       gint64 end_time;
-
-       cbmapi = (ECalBackendMAPI *)(data);
-       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), NULL);
+       ESource *identity_source;
+       ESourceMailIdentity *identity_ext;
+       const gchar *res = NULL;
 
-       priv = cbmapi->priv;
-       cancellable = g_object_ref (priv->cancellable);
+       identity_source = ecb_mapi_find_identity_source (cbmapi);
+       if (!identity_source)
+               return NULL;
 
-       while (!g_cancellable_is_cancelled (cancellable)) {
-               update_local_cache (cbmapi, cancellable);
+       identity_ext = e_source_get_extension (identity_source, E_SOURCE_EXTENSION_MAIL_IDENTITY);
+       if (identity_ext)
+               res = e_source_mail_identity_get_address (identity_ext);
 
-               g_mutex_lock (&priv->dlock->mutex);
+       g_object_unref (identity_source);
 
-               if (priv->dlock->exit)
-                       break;
+       return res;
+}
 
-               end_time = g_get_monotonic_time () + get_cache_refresh_interval () * G_TIME_SPAN_SECOND;
-               g_cond_wait_until (&priv->dlock->cond, &priv->dlock->mutex, end_time);
+static gboolean
+ecb_mapi_modifier_is_organizer (ECalBackendMAPI *cbmapi,
+                               ECalComponent *comp)
+{
+       ECalComponentOrganizer org;
+       const gchar *ownerid, *orgid;
 
-               if (priv->dlock->exit)
-                       break;
+       if (!e_cal_component_has_organizer (comp))
+               return TRUE;
 
-               g_mutex_unlock (&priv->dlock->mutex);
-       }
+       e_cal_component_get_organizer (comp, &org);
+       if (!g_ascii_strncasecmp (org.value, "mailto:";, 7))
+               orgid = (org.value) + 7;
+       else
+               orgid = org.value;
 
-       g_object_unref (cancellable);
-       g_mutex_unlock (&priv->dlock->mutex);
-       priv->dthread = NULL;
+       ownerid = ecb_mapi_get_owner_email (cbmapi);
 
-       return NULL;
+       return g_ascii_strcasecmp (orgid, ownerid) == 0;
 }
 
-static void
-run_delta_thread (ECalBackendMAPI *cbmapi)
+static OlResponseStatus
+ecb_mapi_find_my_response (ECalBackendMAPI *cbmapi,
+                          ECalComponent *comp)
 {
-       ECalBackendMAPIPrivate *priv;
-       GError *error = NULL;
+       icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
+       icalproperty *attendee;
+       gchar *att = NULL;
+       OlResponseStatus val = olResponseTentative;
 
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi));
+       att = g_strdup_printf ("MAILTO:%s", ecb_mapi_get_owner_email (cbmapi));
 
-       priv = cbmapi->priv;
+       for (attendee = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+            attendee;
+            attendee = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) {
+               const gchar *value = icalproperty_get_attendee (attendee);
+               if (!g_ascii_strcasecmp (value, att)) {
+                       icalparameter *param = icalproperty_get_first_parameter (attendee, 
ICAL_PARTSTAT_PARAMETER);
 
-       /* If the thread is already running just return back */
-       if (priv->dthread) {
-               g_cond_signal (&priv->dlock->cond);
-               return;
-       }
+                       switch (icalparameter_get_partstat (param)) {
+                       case ICAL_PARTSTAT_ACCEPTED:
+                               val = olResponseAccepted;
+                               break;
+                       case ICAL_PARTSTAT_TENTATIVE:
+                               val = olResponseTentative;
+                               break;
+                       case ICAL_PARTSTAT_DECLINED:
+                               val = olResponseDeclined;
+                               break;
+                       default:
+                               val = olResponseTentative;
+                               break;
+                       }
 
-       if (!priv->dlock) {
-               priv->dlock = g_new0 (SyncDelta, 1);
-               g_mutex_init (&priv->dlock->mutex);
-               g_cond_init (&priv->dlock->cond);
+                       break;
+               }
        }
 
-       priv->dlock->exit = FALSE;
-       priv->dthread = g_thread_try_new (NULL, (GThreadFunc) delta_thread, cbmapi, &error);
-       if (!priv->dthread) {
-               g_warning (G_STRLOC ": %s", error ? error->message : "Unknown error");
-               g_clear_error (&error);
-       }
+       g_free (att);
+
+       return val;
 }
 
 static void
-ecbm_server_notification_cb (EMapiConnection *conn,
-                            guint event_mask,
-                            gpointer event_data,
-                            gpointer user_data)
+ecb_mapi_server_notification_cb (EMapiConnection *conn,
+                                guint event_mask,
+                                gpointer event_data,
+                                gpointer user_data)
 {
        ECalBackendMAPI *cbmapi = user_data;
-       ECalBackendMAPIPrivate *priv;
        mapi_id_t update_folder1 = 0, update_folder2 = 0;
 
-       g_return_if_fail (cbmapi != NULL);
+       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi));
 
        switch (event_mask) {
        case fnevNewMail:
@@ -1152,924 +646,815 @@ ecbm_server_notification_cb (EMapiConnection *conn,
                break;
        }
 
-       priv = cbmapi->priv;
-       if (priv->fid == update_folder1 || priv->fid == update_folder2)
-               run_delta_thread (cbmapi);
+       if (update_folder1 || update_folder2) {
+               ESource *source;
+               ESourceMapiFolder *ext_mapi_folder;
+
+               source = e_backend_get_source (E_BACKEND (cbmapi));
+               ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
+
+               if (update_folder1 == e_source_mapi_folder_get_id (ext_mapi_folder) ||
+                   update_folder2 == e_source_mapi_folder_get_id (ext_mapi_folder)) {
+                       e_cal_meta_backend_schedule_refresh (E_CAL_META_BACKEND (cbmapi));
+               }
+       }
 }
 
-static ESourceAuthenticationResult
-ecbm_connect_user (ECalBackend *backend,
-                  const ENamedParameters *credentials,
-                  gboolean update_connection_status,
-                  GCancellable *cancellable,
-                  GError **perror)
+static gboolean
+ecb_mapi_connect_sync (ECalMetaBackend *meta_backend,
+                      const ENamedParameters *credentials,
+                      ESourceAuthenticationResult *out_auth_result,
+                      gchar **out_certificate_pem,
+                      GTlsCertificateFlags *out_certificate_errors,
+                      GCancellable *cancellable,
+                      GError **error)
 {
        ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       CamelMapiSettings *settings;
        EMapiConnection *old_conn;
+       CamelMapiSettings *settings;
        ESource *source;
+       ESourceMapiFolder *ext_mapi_folder;
        GError *mapi_error = NULL;
 
-       g_mutex_lock (&auth_mutex);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (out_auth_result != NULL, FALSE);
 
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
+       cbmapi = E_CAL_BACKEND_MAPI (meta_backend);
+
+       ecb_mapi_lock_connection (cbmapi);
+
+       if (cbmapi->priv->conn &&
+           e_mapi_connection_connected (cbmapi->priv->conn)) {
+               ecb_mapi_unlock_connection (cbmapi);
+               return TRUE;
+       }
 
-       old_conn = priv->conn;
-       settings = ecbm_get_collection_settings (cbmapi);
+       settings = ecb_mapi_get_collection_settings (cbmapi);
        source = e_backend_get_source (E_BACKEND (cbmapi));
+       ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 
-       if (update_connection_status)
-               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
-
-       priv->conn = e_mapi_connection_new (
-               e_cal_backend_get_registry (backend),
-               camel_mapi_settings_get_profile (settings), credentials, cancellable, &mapi_error);
-       if (!priv->conn) {
-               priv->conn = e_mapi_connection_find (camel_mapi_settings_get_profile (settings));
-               if (priv->conn
-                   && !e_mapi_connection_connected (priv->conn)) {
-                       e_mapi_connection_reconnect (priv->conn, credentials, cancellable, &mapi_error);
-               }
+       old_conn = cbmapi->priv->conn;
+
+       cbmapi->priv->conn = e_mapi_connection_new (
+               e_cal_backend_get_registry (E_CAL_BACKEND (cbmapi)),
+               camel_mapi_settings_get_profile (settings),
+               credentials, cancellable, &mapi_error);
+
+       if (!cbmapi->priv->conn) {
+               cbmapi->priv->conn = e_mapi_connection_find (camel_mapi_settings_get_profile (settings));
+               if (cbmapi->priv->conn && !e_mapi_connection_connected (cbmapi->priv->conn))
+                       e_mapi_connection_reconnect (cbmapi->priv->conn, credentials, cancellable, 
&mapi_error);
        }
 
        if (old_conn)
-               g_object_unref (old_conn);
+               g_signal_handlers_disconnect_by_func (old_conn, G_CALLBACK (ecb_mapi_server_notification_cb), 
cbmapi);
 
-       if (priv->conn && e_mapi_connection_connected (priv->conn)) {
-               /* Success */
-               ESourceMapiFolder *ext_mapi_folder;
+       g_clear_object (&old_conn);
 
-               if (update_connection_status)
-                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+       if (!cbmapi->priv->conn || mapi_error) {
+               gboolean is_network_error = mapi_error && mapi_error->domain != E_MAPI_ERROR;
 
-               ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
-               if (ext_mapi_folder && e_source_mapi_folder_get_server_notification (ext_mapi_folder)) {
-                       mapi_object_t obj_folder;
-                       gboolean status;
+               g_clear_object (&cbmapi->priv->conn);
+               ecb_mapi_unlock_connection (cbmapi);
 
-                       status = ecbm_open_folder (cbmapi, priv->conn, &obj_folder, NULL, NULL);
-                       if (status) {
-                               e_mapi_connection_enable_notifications (priv->conn, &obj_folder,
-                                       fnevObjectCreated | fnevObjectModified | fnevObjectDeleted | 
fnevObjectMoved | fnevObjectCopied,
-                                       NULL, NULL);
+               if (is_network_error)
+                       ecb_mapi_error_to_edc_error (error, mapi_error, OtherError, NULL);
 
-                               e_mapi_connection_close_folder (priv->conn, &obj_folder, NULL, NULL);
-                       }
+               g_clear_error (&mapi_error);
 
-                       g_signal_connect (priv->conn, "server-notification", G_CALLBACK 
(ecbm_server_notification_cb), cbmapi);
-               }
-       } else {
-               gboolean is_network_error = mapi_error && mapi_error->domain != E_MAPI_ERROR;
+               *out_auth_result = is_network_error ? E_SOURCE_AUTHENTICATION_ERROR : 
E_SOURCE_AUTHENTICATION_REJECTED;
 
-               if (is_network_error) {
-                       if (update_connection_status)
-                               e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
-                       mapi_error_to_edc_error (perror, mapi_error, OtherError, NULL);
-               } else if (update_connection_status) {
-                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
-               }
-               if (mapi_error)
-                       g_error_free (mapi_error);
-               g_mutex_unlock (&auth_mutex);
-               return is_network_error ? E_SOURCE_AUTHENTICATION_ERROR : E_SOURCE_AUTHENTICATION_REJECTED;
+               return FALSE;
        }
 
-       if (mapi_error) {
-               /* do not set error when authentication was rejected */
-               g_error_free (mapi_error);
-               g_mutex_unlock (&auth_mutex);
-               return E_SOURCE_AUTHENTICATION_REJECTED;
-       }
+       if (e_source_mapi_folder_get_server_notification (ext_mapi_folder)) {
+               mapi_object_t obj_folder;
+               GError *mapi_error = NULL;
 
-       g_mutex_unlock (&auth_mutex);
+               g_signal_connect (cbmapi->priv->conn, "server-notification", G_CALLBACK 
(ecb_mapi_server_notification_cb), cbmapi);
 
-       if (!priv->fid) {
-               g_propagate_error (perror, EDC_ERROR_EX (OtherError, "No folder ID set"));
-               return E_SOURCE_AUTHENTICATION_ERROR;
-       }
+               if (ecb_mapi_open_folder (cbmapi, &obj_folder, cancellable, &mapi_error)) {
+                       e_mapi_connection_enable_notifications (cbmapi->priv->conn, &obj_folder,
+                               fnevObjectCreated | fnevObjectModified | fnevObjectDeleted | fnevObjectMoved 
| fnevObjectCopied,
+                               cancellable, &mapi_error);
+
+                       e_mapi_connection_close_folder (cbmapi->priv->conn, &obj_folder, cancellable, 
&mapi_error);
+               }
 
-       if (!priv->conn || !e_mapi_connection_connected (priv->conn)) {
-               /* do not set error when authentication was rejected */
-               return E_SOURCE_AUTHENTICATION_REJECTED;
+               if (mapi_error) {
+                       ecb_mapi_maybe_disconnect (cbmapi, mapi_error);
+                       g_clear_error (&mapi_error);
+               }
        }
 
-       /* We have established a connection */
-       if (priv->store && priv->fid) {
-               e_backend_set_online (E_BACKEND (cbmapi), TRUE);
+       ecb_mapi_unlock_connection (cbmapi);
 
-               run_delta_thread (cbmapi);
-       }
+       *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
 
-       return E_SOURCE_AUTHENTICATION_ACCEPTED;
+       return TRUE;
 }
 
 static gboolean
-e_cal_backend_mapi_ensure_connected (ECalBackendMAPI *cbma,
-                                    GCancellable *cancellable,
-                                    GError **perror)
+ecb_mapi_disconnect_sync (ECalMetaBackend *meta_backend,
+                         GCancellable *cancellable,
+                         GError **error)
 {
-       CamelMapiSettings *settings;
-       GError *local_error = NULL;
+       ECalBackendMAPI *cbmapi;
+       gboolean success = TRUE;
 
-       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbma), FALSE);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (meta_backend), FALSE);
 
-       if (cbma->priv->conn && e_mapi_connection_connected (cbma->priv->conn))
-               return TRUE;
+       cbmapi = E_CAL_BACKEND_MAPI (meta_backend);
 
-       settings = ecbm_get_collection_settings (cbma);
+       ecb_mapi_lock_connection (cbmapi);
 
-       if (!camel_mapi_settings_get_kerberos (settings) ||
-           ecbm_connect_user (E_CAL_BACKEND (cbma), NULL, TRUE, cancellable, &local_error) != 
E_SOURCE_AUTHENTICATION_ACCEPTED) {
-               e_backend_credentials_required_sync (E_BACKEND (cbma),
-                       E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL,
-                       cancellable, &local_error);
-       }
+       if (cbmapi->priv->conn) {
+               g_signal_handlers_disconnect_by_func (cbmapi->priv->conn, G_CALLBACK 
(ecb_mapi_server_notification_cb), cbmapi);
 
-       if (!local_error)
-               return TRUE;
+               success = e_mapi_connection_disconnect (cbmapi->priv->conn, FALSE, cancellable, error);
+               g_clear_object (&cbmapi->priv->conn);
+       }
 
-       g_propagate_error (perror, local_error);
+       ecb_mapi_unlock_connection (cbmapi);
 
-       return FALSE;
+       return success;
 }
 
-static void
-e_cal_backend_mapi_maybe_disconnect (ECalBackendMAPI *cbma,
-                                    const GError *mapi_error)
+typedef struct _LoadMultipleData {
+       ECalMetaBackend *meta_backend;
+       icalcomponent_kind kind;
+       GSList **out_components; /* icalcomponent * */
+} LoadMultipleData;
+
+static gboolean
+transfer_calendar_objects_cb (EMapiConnection *conn,
+                             TALLOC_CTX *mem_ctx,
+                             /* const */ EMapiObject *object,
+                             guint32 obj_index,
+                             guint32 obj_total,
+                             gpointer user_data,
+                             GCancellable *cancellable,
+                             GError **perror)
 {
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (cbma));
+       LoadMultipleData *lmd = user_data;
+       ECalComponent *comp;
+       const mapi_id_t *pmid;
+       gchar *use_uid;
+       GSList *instances = NULL;
 
-       /* no error or already disconnected */
-       if (!mapi_error || !cbma->priv->conn)
-               return;
+       g_return_val_if_fail (conn != NULL, FALSE);
+       g_return_val_if_fail (object != NULL, FALSE);
+       g_return_val_if_fail (lmd != NULL, FALSE);
 
-       if (g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed) ||
-           g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_CALL_FAILED)) {
-               e_mapi_connection_disconnect (cbma->priv->conn,
-                       !g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed),
-                       NULL, NULL);
-               g_object_unref (cbma->priv->conn);
-               cbma->priv->conn = NULL;
-       }
-}
+       pmid = e_mapi_util_find_array_propval (&object->properties, PidTagMid);
+       if (pmid)
+               use_uid = e_mapi_util_mapi_id_to_string (*pmid);
+       else
+               use_uid = e_util_generate_uid ();
 
-static EMapiConnection *
-e_cal_backend_mapi_get_connection (ECalBackendMAPI *cbma,
-                                  GCancellable *cancellable,
-                                  GError **perror)
-{
-       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbma), NULL);
-       g_return_val_if_fail (cbma->priv != NULL, NULL);
+       comp = e_mapi_cal_util_object_to_comp (conn, object,
+               lmd->kind, FALSE, use_uid, &instances);
 
-       if (cbma->priv->conn)
-               return cbma->priv->conn;
+       g_free (use_uid);
 
-       if (!e_backend_get_online (E_BACKEND (cbma)))
-               return NULL;
+       if (comp)
+               instances = g_slist_prepend (instances, comp);
 
-       if (!e_cal_backend_mapi_ensure_connected (cbma, cancellable, perror))
-               return NULL;
+       if (instances) {
+               icalcomponent *icomp;
 
-       return cbma->priv->conn;
+               icomp = e_cal_meta_backend_merge_instances (lmd->meta_backend, instances, FALSE);
+               if (icomp)
+                       *lmd->out_components = g_slist_prepend (*lmd->out_components, icomp);
+       }
+
+       g_slist_free_full (instances, g_object_unref);
+
+       return TRUE;
 }
 
-static void
-ecbm_open (ECalBackend *backend,
-          EDataCal *cal,
-          GCancellable *cancellable,
-          gboolean only_if_exists,
-          GError **perror)
-{
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       ESource *esource;
-       ESourceMapiFolder *ext_mapi_folder;
-       guint64 fid;
-       const gchar *cache_dir;
-       GError *error = NULL;
+static gboolean
+ecb_mapi_load_multiple_sync (ECalBackendMAPI *cbmapi,
+                            const GSList *uids, /* gchar * */
+                            GSList **out_components, /* icalcomponent * */
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       LoadMultipleData lmd;
+       GSList *mids = NULL, *link;
+       mapi_object_t obj_folder;
+       gboolean success;
+       GError *mapi_error = NULL;
 
-       if (e_cal_backend_is_opened (backend))
-               return /* Success */;
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), FALSE);
+       g_return_val_if_fail (uids != NULL, FALSE);
+       g_return_val_if_fail (out_components != NULL, FALSE);
 
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
+       for (link = (GSList *) uids; link; link = g_slist_next (link)) {
+               mapi_id_t *pmid, mid;
 
-       esource = e_backend_get_source (E_BACKEND (cbmapi));
-       ext_mapi_folder = e_source_get_extension (esource, E_SOURCE_EXTENSION_MAPI_FOLDER);
-       fid = e_source_mapi_folder_get_id (ext_mapi_folder);
-       if (!fid) {
-               g_propagate_error (perror, EDC_ERROR_EX (OtherError, "No folder ID set"));
-               return;
+               if (e_mapi_util_mapi_id_from_string  (link->data, &mid)) {
+                       pmid = g_new0 (mapi_id_t, 1);
+                       *pmid = mid;
+
+                       mids = g_slist_prepend (mids, pmid);
+               }
        }
 
-       g_mutex_lock (&priv->mutex);
+       ecb_mapi_lock_connection (cbmapi);
+
+       lmd.meta_backend = E_CAL_META_BACKEND (cbmapi);
+       lmd.kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+       lmd.out_components = out_components;
+
+       success = ecb_mapi_open_folder (cbmapi, &obj_folder, cancellable, &mapi_error);
 
-       cbmapi->priv->read_only = FALSE;
+       if (success) {
+               success = e_mapi_connection_transfer_objects (cbmapi->priv->conn, &obj_folder, mids,
+                       transfer_calendar_objects_cb, &lmd, cancellable, &mapi_error);
 
-       if (priv->store) {
-               g_object_unref (priv->store);
-               priv->store = NULL;
+               e_mapi_connection_close_folder (cbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
        }
 
-       /* Always create cache here */
-       cache_dir = e_cal_backend_get_cache_dir (backend);
-       priv->store = e_cal_backend_store_new (cache_dir, E_TIMEZONE_CACHE (backend));
+       if (mapi_error) {
+               ecb_mapi_maybe_disconnect (cbmapi, mapi_error);
+               ecb_mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to transfer objects 
from a server"));
+               g_error_free (mapi_error);
 
-       if (!priv->store) {
-               g_mutex_unlock (&priv->mutex);
-               g_propagate_error (perror, EDC_ERROR_EX (OtherError, _("Could not create cache file")));
-               return;
+               success = FALSE;
        }
 
-       e_cal_backend_store_load (priv->store);
+       ecb_mapi_unlock_connection (cbmapi);
 
-       g_free (priv->foreign_username);
+       g_slist_free_full (mids, g_free);
 
-       priv->fid = fid;
-       priv->is_public_folder = e_source_mapi_folder_is_public (ext_mapi_folder);
-       priv->foreign_username = e_source_mapi_folder_dup_foreign_username (ext_mapi_folder);
+       return success;
+}
 
-       if (priv->foreign_username && !*priv->foreign_username) {
-               g_free (priv->foreign_username);
-               priv->foreign_username = NULL;
-       }
+static gboolean
+ecb_mapi_preload_infos_sync (ECalBackendMAPI *cbmapi,
+                            GSList *created_objects,
+                            GSList *modified_objects,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       GHashTable *infos;
+       GSList *uids = NULL, *link;
+       gboolean success = TRUE;
 
-       /* Not for remote */
-       if (!e_backend_get_online (E_BACKEND (backend))) {
-               ESourceOffline *offline_extension;
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), FALSE);
 
-               cbmapi->priv->read_only = TRUE;
+       infos = g_hash_table_new (g_str_hash, g_str_equal);
 
-               offline_extension = e_source_get_extension (esource, E_SOURCE_EXTENSION_OFFLINE);
+       for (link = created_objects; link; link = g_slist_next (link)) {
+               ECalMetaBackendInfo *nfo = link->data;
 
-               if (!e_source_offline_get_stay_synchronized (offline_extension)) {
-                       g_mutex_unlock (&priv->mutex);
-                       g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
-                       return;
+               if (nfo && nfo->extra) {
+                       uids = g_slist_prepend (uids, nfo->extra);
+                       g_hash_table_insert (infos, nfo->extra, nfo);
+               } else if (nfo && nfo->uid) {
+                       uids = g_slist_prepend (uids, nfo->uid);
+                       g_hash_table_insert (infos, nfo->uid, nfo);
                }
-
-               g_mutex_unlock (&priv->mutex);
-               e_backend_set_online (E_BACKEND (backend), FALSE);
-               e_cal_backend_set_writable (backend, !priv->read_only);
-               return /* Success */;
        }
 
-       g_mutex_unlock (&priv->mutex);
+       for (link = modified_objects; link; link = g_slist_next (link)) {
+               ECalMetaBackendInfo *nfo = link->data;
 
-       e_backend_set_online (E_BACKEND (backend), TRUE);
-       e_cal_backend_set_writable (backend, !priv->read_only);
+               if (nfo && nfo->extra) {
+                       uids = g_slist_prepend (uids, nfo->extra);
+                       g_hash_table_insert (infos, nfo->extra, nfo);
+               } else if (nfo && nfo->uid) {
+                       uids = g_slist_prepend (uids, nfo->uid);
+                       g_hash_table_insert (infos, nfo->uid, nfo);
+               }
+       }
 
-       e_cal_backend_mapi_ensure_connected (cbmapi, cancellable, &error);
+       uids = g_slist_reverse (uids);
+       if (uids) {
+               GSList *components = NULL;
 
-       if (error)
-               g_propagate_error (perror, error);
-}
+               success = ecb_mapi_load_multiple_sync (cbmapi, uids, &components, cancellable, error);
+               if (success) {
+                       for (link = components; link; link = g_slist_next (link)) {
+                               icalcomponent *icomp = link->data;
 
+                               if (icomp) {
+                                       ECalMetaBackendInfo *nfo;
+                                       const gchar *uid = NULL;
+                                       gchar *xmid = NULL;
 
-static ESourceAuthenticationResult
-ecbm_authenticate_sync (EBackend *backend,
-                       const ENamedParameters *credentials,
-                       gchar **out_certificate_pem,
-                       GTlsCertificateFlags *out_certificate_errors,
-                       GCancellable *cancellable,
-                       GError **error)
-{
-       return ecbm_connect_user (E_CAL_BACKEND (backend), credentials, FALSE, cancellable, error);
-}
+                                       if (icalcomponent_isa (icomp) == ICAL_VCALENDAR_COMPONENT) {
+                                               icalcomponent *subcomp;
+                                               icalcomponent_kind kind;
 
-static gboolean
-ecbm_capture_req_props (EMapiConnection *conn,
-                       TALLOC_CTX *mem_ctx,
-                       /* const */ EMapiObject *object,
-                       guint32 obj_index,
-                       guint32 obj_total,
-                       gpointer user_data,
-                       GCancellable *cancellable,
-                       GError **perror)
-{
-       struct cal_cbdata *cbdata = user_data;
-       const uint32_t *ui32;
+                                               kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
 
-       g_return_val_if_fail (object != NULL, FALSE);
-       g_return_val_if_fail (cbdata != NULL, FALSE);
+                                               for (subcomp = icalcomponent_get_first_component (icomp, 
kind);
+                                                    subcomp && !uid;
+                                                    subcomp = icalcomponent_get_next_component (icomp, 
kind)) {
+                                                       uid = icalcomponent_get_uid (subcomp);
+                                                       xmid = e_mapi_cal_utils_get_icomp_x_prop (subcomp, 
"X-EVOLUTION-MAPI-MID");
+                                               }
+                                       } else {
+                                               uid = icalcomponent_get_uid (icomp);
+                                               xmid = e_mapi_cal_utils_get_icomp_x_prop (icomp, 
"X-EVOLUTION-MAPI-MID");
+                                       }
 
-       ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagOwnerAppointmentId);
-       if (ui32)
-               cbdata->appt_id = *ui32;
-       ui32 = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentSequence);
-       if (ui32)
-               cbdata->appt_seq = *ui32;
+                                       nfo = uid ? g_hash_table_lookup (infos, uid) : NULL;
+                                       if (!nfo && xmid)
+                                               nfo = g_hash_table_lookup (infos, xmid);
 
-       cbdata->cleanglobalid = e_mapi_util_copy_sbinary_short (e_mapi_util_find_array_propval 
(&object->properties, PidLidCleanGlobalObjectId));
-       cbdata->globalid = e_mapi_util_copy_sbinary_short (e_mapi_util_find_array_propval 
(&object->properties, PidLidGlobalObjectId));
+                                       if (nfo && !nfo->object)
+                                               nfo->object = icalcomponent_as_ical_string_r (icomp);
 
-       cbdata->username = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSentRepresentingName));
-       cbdata->useridtype = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSentRepresentingAddressType));
-       cbdata->userid = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSentRepresentingEmailAddress));
+                                       g_free (xmid);
+                               }
+                       }
+               }
 
-       cbdata->ownername = g_strdup (e_mapi_util_find_array_propval (&object->properties, PidTagSenderName));
-       cbdata->owneridtype = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSenderAddressType));
-       cbdata->ownerid = g_strdup (e_mapi_util_find_array_propval (&object->properties, 
PidTagSenderEmailAddress));
+               g_slist_free_full (components, (GDestroyNotify) icalcomponent_free);
+       }
 
-       return TRUE;
+       g_hash_table_destroy (infos);
+       g_slist_free (uids);
+
+       return success;
 }
 
 static gboolean
-ecbm_list_for_one_mid_cb (EMapiConnection *conn,
-                         TALLOC_CTX *mem_ctx,
-                         const ListObjectsData *object_data,
-                         guint32 obj_index,
-                         guint32 obj_total,
-                         gpointer user_data,
-                         GCancellable *cancellable,
-                         GError **perror)
+ecb_mapi_get_changes_sync (ECalMetaBackend *meta_backend,
+                          const gchar *last_sync_tag,
+                          gboolean is_repeat,
+                          gchar **out_new_sync_tag,
+                          gboolean *out_repeat,
+                          GSList **out_created_objects,
+                          GSList **out_modified_objects,
+                          GSList **out_removed_objects,
+                          GCancellable *cancellable,
+                          GError **error)
 {
-       mapi_id_t *pmid = user_data;
+       ECalBackendMAPI *cbmapi;
 
-       g_return_val_if_fail (pmid != NULL, FALSE);
-       g_return_val_if_fail (object_data != NULL, FALSE);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (out_created_objects != NULL, FALSE);
+       g_return_val_if_fail (out_modified_objects != NULL, FALSE);
 
-       *pmid = object_data->mid;
+       /* Chain up to parent's method */
+       if (!E_CAL_META_BACKEND_CLASS (e_cal_backend_mapi_parent_class)->get_changes_sync (meta_backend,
+               last_sync_tag, is_repeat, out_new_sync_tag, out_repeat, out_created_objects,
+               out_modified_objects, out_removed_objects, cancellable, error)) {
+               return FALSE;
+       }
+
+       cbmapi = E_CAL_BACKEND_MAPI (meta_backend);
+
+       /* Preload some of the components in chunk, to speed-up things;
+          ignore errors, to not break whole update process. */
+       ecb_mapi_preload_infos_sync (cbmapi, *out_created_objects, *out_modified_objects, cancellable, NULL);
 
        return TRUE;
 }
 
 static gboolean
-ecbm_build_global_id_restriction (EMapiConnection *conn,
-                                 TALLOC_CTX *mem_ctx,
-                                 struct mapi_SRestriction **restrictions,
-                                 gpointer user_data,
-                                 GCancellable *cancellable,
-                                 GError **perror)
-{
-       ECalComponent *comp = user_data;
-       struct SBinary_short sb;
-       struct SPropValue sprop;
-       struct mapi_SRestriction *restriction;
-       gchar *propval;
-
-       g_return_val_if_fail (restrictions != NULL, FALSE);
-       g_return_val_if_fail (comp != NULL, FALSE);
+ecb_mapi_list_existing_uids_cb (EMapiConnection *conn,
+                               TALLOC_CTX *mem_ctx,
+                               const ListObjectsData *object_data,
+                               guint32 obj_index,
+                               guint32 obj_total,
+                               gpointer user_data,
+                               GCancellable *cancellable,
+                               GError **perror)
+{
+       GSList **out_existing_objects = user_data;
+       gchar *uid;
 
-       restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
-       g_return_val_if_fail (restriction != NULL, FALSE);
+       g_return_val_if_fail (conn != NULL, FALSE);
+       g_return_val_if_fail (object_data != NULL, FALSE);
+       g_return_val_if_fail (out_existing_objects != NULL, FALSE);
 
-       restriction->rt = RES_PROPERTY;
-       restriction->res.resProperty.relop = RELOP_EQ;
-       restriction->res.resProperty.ulPropTag = PidLidGlobalObjectId;
+       uid = e_mapi_util_mapi_id_to_string (object_data->mid);
+       if (uid) {
+               struct icaltimetype itt;
+               gchar *rev;
 
-       propval = e_mapi_cal_utils_get_icomp_x_prop (e_cal_component_get_icalcomponent (comp), 
"X-EVOLUTION-MAPI-GLOBALID");
-       if (propval && *propval) {
-               gsize len = 0;
+               itt = icaltime_from_timet_with_zone (object_data->last_modified, 0, 
icaltimezone_get_utc_timezone ());
+               rev = icaltime_as_ical_string_r (itt);
 
-               sb.lpb = g_base64_decode (propval, &len);
-               sb.cb = len;
-       } else {
-               struct icaltimetype ical_creation_time = { 0 };
-               struct FILETIME creation_time = { 0 };
-               const gchar *uid;
+               *out_existing_objects = g_slist_prepend (*out_existing_objects,
+                       e_cal_meta_backend_info_new (uid, rev, NULL, uid));
 
-               uid = icalcomponent_get_uid (e_cal_component_get_icalcomponent (comp));
+               g_free (uid);
+               g_free (rev);
+       }
 
-               e_cal_component_get_dtstamp (comp, &ical_creation_time);
+       return TRUE;
+}
 
-               e_mapi_util_time_t_to_filetime (icaltime_as_timet (ical_creation_time), &creation_time);
-               e_mapi_cal_util_generate_globalobjectid (FALSE, uid, NULL, ical_creation_time.year ? 
&creation_time : NULL, &sb);
-       }
-       g_free (propval);
+static gboolean
+ecb_mapi_populate_mid_to_gid_cb (ECalCache *cal_cache,
+                                const gchar *uid,
+                                const gchar *rid,
+                                const gchar *revision,
+                                const gchar *object,
+                                const gchar *extra,
+                                EOfflineState offline_state,
+                                gpointer user_data)
+{
+       GHashTable *mid_to_gid = user_data;
 
-       set_SPropValue_proptag (&sprop, PidLidGlobalObjectId, &sb);
-       cast_mapi_SPropValue (mem_ctx, &(restriction->res.resProperty.lpProp), &sprop);
+       g_return_val_if_fail (mid_to_gid != NULL, FALSE);
 
-       *restrictions = restriction;
+       if (uid && *uid && extra && *extra && g_strcmp0 (uid, extra) != 0)
+               g_hash_table_insert (mid_to_gid, g_strdup (extra), g_strdup (uid));
 
        return TRUE;
 }
 
-/* should call free_server_data() before done with cbdata */
-static void
-get_server_data (ECalBackendMAPI *cbmapi,
-                ECalComponent *comp,
-                struct cal_cbdata *cbdata,
-                GCancellable *cancellable)
+static gboolean
+ecb_mapi_list_existing_sync (ECalMetaBackend *meta_backend,
+                            gchar **out_new_sync_tag,
+                            GSList **out_existing_objects,
+                            GCancellable *cancellable,
+                            GError **error)
 {
-       EMapiConnection *conn;
-       icalcomponent *icalcomp;
-       mapi_id_t mid;
+       ECalBackendMAPI *cbmapi;
        mapi_object_t obj_folder;
+       gboolean success;
        GError *mapi_error = NULL;
 
-       icalcomp = e_cal_component_get_icalcomponent (comp);
-       get_comp_mid (icalcomp, &mid);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (out_existing_objects, FALSE);
 
-       conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
-       if (!conn)
-               goto cleanup;
+       *out_existing_objects = NULL;
 
-       if (!ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &mapi_error))
-               goto cleanup;
+       cbmapi = E_CAL_BACKEND_MAPI (meta_backend);
 
-       if (!e_mapi_connection_transfer_object (conn, &obj_folder, mid, ecbm_capture_req_props, cbdata, 
cancellable, &mapi_error)) {
-               if (!g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NOT_FOUND)) {
-                       g_clear_error (&mapi_error);
-                       e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-                       goto cleanup;
-               }
+       ecb_mapi_lock_connection (cbmapi);
 
-               /* try to find by global-id, if not found by MID */
-               g_clear_error (&mapi_error);
+       success = ecb_mapi_open_folder (cbmapi, &obj_folder, cancellable, &mapi_error);
+       if (success) {
+               success = e_mapi_connection_list_objects (cbmapi->priv->conn, &obj_folder, NULL, NULL,
+                       ecb_mapi_list_existing_uids_cb, out_existing_objects, cancellable, &mapi_error);
+
+               e_mapi_connection_close_folder (cbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
        }
 
-       if (e_mapi_connection_list_objects (conn, &obj_folder,
-                                           ecbm_build_global_id_restriction, comp,
-                                           ecbm_list_for_one_mid_cb, &mid,
-                                           cancellable, &mapi_error)) {
-               e_mapi_connection_transfer_object (conn, &obj_folder, mid, ecbm_capture_req_props, cbdata, 
cancellable, &mapi_error);
+       if (mapi_error) {
+               ecb_mapi_maybe_disconnect (cbmapi, mapi_error);
+               ecb_mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to list items from a 
server"));
+               g_error_free (mapi_error);
+
+               success = FALSE;
        }
 
-       e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
+       ecb_mapi_unlock_connection (cbmapi);
 
- cleanup:
-       e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
-       g_clear_error (&mapi_error);
-}
+       /* Components with GlobalId has UID the GlobalId, all other have MessageID,
+          but here the 'nfo->uid' is MessageID */
+       if (success) {
+               ECalCache *cal_cache;
 
-/* frees data members allocated in get_server_data(), not the cbdata itself */
-static void
-free_server_data (struct cal_cbdata *cbdata)
-{
-       if (!cbdata)
-               return;
+               cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+               if (cal_cache) {
+                       GHashTable *mid_to_gid;
 
-       #define do_free(_func, _val) _func (_val); _val = NULL
+                       mid_to_gid = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
-       do_free (e_mapi_util_free_sbinary_short, cbdata->cleanglobalid);
-       do_free (e_mapi_util_free_sbinary_short, cbdata->globalid);
-       do_free (g_free, cbdata->username);
-       do_free (g_free, cbdata->useridtype);
-       do_free (g_free, cbdata->userid);
-       do_free (g_free, cbdata->ownername);
-       do_free (g_free, cbdata->owneridtype);
-       do_free (g_free, cbdata->ownerid);
+                       if (e_cal_cache_search_with_callback (cal_cache, NULL, 
ecb_mapi_populate_mid_to_gid_cb, mid_to_gid, cancellable, NULL) &&
+                           g_hash_table_size (mid_to_gid) > 0) {
+                               GSList *link;
 
-       #undef do_free
-}
+                               for (link = *out_existing_objects; link; link = g_slist_next (link)) {
+                                       ECalMetaBackendInfo *nfo = link->data;
 
-#define free_and_dupe_str(_des, _new) G_STMT_START {   \
-       g_free (_des);                                  \
-       _des = g_strdup (_new);                         \
-       } G_STMT_END
+                                       if (nfo && nfo->uid) {
+                                               const gchar *gid = g_hash_table_lookup (mid_to_gid, nfo->uid);
 
-static void
-ecbm_create_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, 
gchar **uid, ECalComponent **new_ecalcomp, GError **error)
-{
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       EMapiConnection *conn;
-       icalcomponent_kind kind;
-       icalcomponent *icalcomp;
-       ECalComponent *comp;
-       mapi_id_t mid = 0;
-       gchar *tmp = NULL;
-       struct icaltimetype current;
-       GError *mapi_error = NULL;
+                                               if (gid && *gid) {
+                                                       g_free (nfo->uid);
+                                                       nfo->uid = g_strdup (gid);
+                                               }
+                                       }
+                               }
+                       }
 
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
+                       g_hash_table_destroy (mid_to_gid);
+                       g_object_unref (cal_cache);
+               }
+       }
 
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+       return success;
+}
 
-       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
-       e_mapi_return_data_cal_error_if_fail (calobj != NULL, InvalidArg);
-       e_mapi_return_data_cal_error_if_fail (new_ecalcomp != NULL, InvalidArg);
+static gboolean
+ecb_mapi_load_component_sync (ECalMetaBackend *meta_backend,
+                             const gchar *uid,
+                             const gchar *extra,
+                             icalcomponent **out_component,
+                             gchar **out_extra,
+                             GCancellable *cancellable,
+                             GError **error)
+{
+       ECalBackendMAPI *cbmapi;
+       GSList *uids, *components = NULL;
+       gboolean success;
+       GError *local_error = NULL;
 
-       if (!e_backend_get_online (E_BACKEND (backend))) {
-               g_propagate_error (error, EDC_ERROR (RepositoryOffline));
-               return;
-       }
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
+       g_return_val_if_fail (out_component != NULL, FALSE);
 
-       /* check the component for validity */
-       icalcomp = icalparser_parse_string (calobj);
-       if (!icalcomp) {
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
+       *out_component = NULL;
 
-       if (kind != icalcomponent_isa (icalcomp)) {
-               icalcomponent_free (icalcomp);
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
+       cbmapi = E_CAL_BACKEND_MAPI (meta_backend);
 
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomp);
+       uids = g_slist_prepend (NULL, (gpointer) uid);
 
-       current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-       e_cal_component_set_created (comp, &current);
-       e_cal_component_set_last_modified (comp, &current);
+       ecb_mapi_lock_connection (cbmapi);
 
-       /* Check if object exists */
-       conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
-       if (conn) {
-               struct cal_cbdata cbdata = { 0 };
-               gboolean status;
+       success = ecb_mapi_load_multiple_sync (cbmapi, uids, &components, cancellable, &local_error);
+       if (!success) {
                mapi_object_t obj_folder;
-               gboolean has_attendees = e_cal_component_has_attendees (comp);
+               mapi_id_t mid = 0;
 
-               cbdata.kind = kind;
-               cbdata.username = g_strdup (ecbm_get_user_name (cbmapi));
-               cbdata.useridtype = (gchar *) "SMTP";
-               cbdata.userid = g_strdup (ecbm_get_user_email (cbmapi));
-               cbdata.ownername = g_strdup (ecbm_get_owner_name (cbmapi));
-               cbdata.owneridtype = (gchar *) "SMTP";
-               cbdata.ownerid = g_strdup (ecbm_get_owner_email (cbmapi));
-               cbdata.get_timezone = (icaltimezone * (*)(gpointer data, const gchar *tzid)) 
e_timezone_cache_get_timezone;
-               cbdata.get_tz_data = cbmapi;
+               /* Not downloaded in the local cache yet, try to find it. */
+               if (ecb_mapi_open_folder (cbmapi, &obj_folder, cancellable, NULL)) {
+                       if (e_mapi_connection_list_objects (cbmapi->priv->conn, &obj_folder,
+                               ecb_mapi_build_global_id_or_mid_restriction_from_uid, (gpointer) uid,
+                               ecb_mapi_list_for_one_mid_cb, &mid, cancellable, NULL) && mid) {
+                               LoadMultipleData lmd;
 
-               /* Create an appointment */
-               cbdata.comp = comp;
-               cbdata.is_modify = FALSE;
-               cbdata.msgflags = MSGFLAG_READ;
-               cbdata.meeting_type = has_attendees ? MEETING_OBJECT : NOT_A_MEETING;
-               cbdata.resp = has_attendees ? olResponseOrganized : olResponseNone;
-               cbdata.appt_id = e_mapi_cal_util_get_new_appt_id (conn, priv->fid);
-               cbdata.appt_seq = 0;
-               cbdata.globalid = NULL;
-               cbdata.cleanglobalid = NULL;
-
-               status = ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &mapi_error);
-               if (status) {
-                       e_mapi_connection_create_object (conn, &obj_folder, E_MAPI_CREATE_FLAG_NONE,
-                                                        e_mapi_cal_utils_comp_to_object, &cbdata,
-                                                        &mid, cancellable, &mapi_error);
+                               lmd.meta_backend = E_CAL_META_BACKEND (cbmapi);
+                               lmd.kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+                               lmd.out_components = &components;
 
-                       e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
-               }
+                               success = e_mapi_connection_transfer_object (cbmapi->priv->conn, &obj_folder, 
mid,
+                                       transfer_calendar_objects_cb, &lmd, cancellable, NULL);
 
-               g_free (cbdata.username);
-               g_free (cbdata.userid);
-               g_free (cbdata.ownername);
-               g_free (cbdata.ownerid);
+                               if (success)
+                                       g_clear_error (&local_error);
+                       }
 
-               if (!mid) {
-                       g_object_unref (comp);
-                       mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to create item on a 
server"));
-                       e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
-                       if (mapi_error)
-                               g_error_free (mapi_error);
-                       return;
+                       e_mapi_connection_close_folder (cbmapi->priv->conn, &obj_folder, cancellable, NULL);
                }
-
-               tmp = e_mapi_util_mapi_id_to_string (mid);
-               e_cal_component_set_uid (comp, tmp);
-               if (uid)
-                       *uid = tmp;
-               else
-                       g_free (tmp);
-
-               e_cal_component_commit_sequence (comp);
-               put_component_to_store (cbmapi, comp);
-               *new_ecalcomp = e_cal_component_clone (comp);
-               e_cal_backend_notify_component_created (E_CAL_BACKEND (cbmapi), *new_ecalcomp);
-       } else {
-               e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
-               if (!mapi_error)
-                       g_propagate_error (error, EDC_ERROR (RepositoryOffline));
-               else
-                       mapi_error_to_edc_error (error, mapi_error, RepositoryOffline, NULL);
-               g_clear_error (&mapi_error);
-               g_object_unref (comp);
-               return;
        }
 
-       run_delta_thread (cbmapi);
-
-       g_object_unref (comp);
-}
-
-static gboolean
-modifier_is_organizer (ECalBackendMAPI *cbmapi, ECalComponent *comp)
-{
-       ECalComponentOrganizer org;
-       const gchar *ownerid, *orgid;
-
-       if (!e_cal_component_has_organizer(comp))
-               return TRUE;
-
-       e_cal_component_get_organizer (comp, &org);
-       if (!g_ascii_strncasecmp (org.value, "mailto:";, 7))
-               orgid = (org.value) + 7;
-       else
-               orgid = org.value;
-       ownerid = ecbm_get_owner_email (cbmapi);
-
-       return (!g_ascii_strcasecmp(orgid, ownerid) ? TRUE : FALSE);
-}
+       ecb_mapi_unlock_connection (cbmapi);
 
-static OlResponseStatus
-get_trackstatus_from_partstat (icalparameter_partstat partstat)
-{
-       switch (partstat) {
-               case ICAL_PARTSTAT_ACCEPTED     : return olResponseAccepted;
-               case ICAL_PARTSTAT_TENTATIVE    : return olResponseTentative;
-               case ICAL_PARTSTAT_DECLINED     : return olResponseDeclined;
-               default                         : return olResponseTentative;
+       if (success && components) {
+               *out_component = components->data;
+               g_slist_free (components);
+       } else {
+               g_slist_free_full (components, (GDestroyNotify) icalcomponent_free);
        }
-}
 
-static OlResponseStatus
-find_my_response (ECalBackendMAPI *cbmapi, ECalComponent *comp)
-{
-       icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
-       icalproperty *attendee;
-       gchar *att = NULL;
-       OlResponseStatus val = olResponseTentative;
+       if (local_error)
+               g_propagate_error (error, local_error);
 
-       att = g_strdup_printf ("MAILTO:%s", ecbm_get_owner_email (cbmapi));
-       attendee = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
-       while (attendee) {
-               const gchar *value = icalproperty_get_attendee (attendee);
-               if (!g_ascii_strcasecmp (value, att)) {
-                       icalparameter *param = icalproperty_get_first_parameter (attendee, 
ICAL_PARTSTAT_PARAMETER);
-                       val = get_trackstatus_from_partstat (icalparameter_get_partstat(param));
-                       break;
-               }
-               attendee = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
-       }
-       g_free (att);
+       g_slist_free (uids);
 
-       return val;
+       return success;
 }
 
-static void
-ecbm_modify_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, 
ECalObjModType mod, ECalComponent **old_ecalcomp, ECalComponent **new_ecalcomp, GError **error)
+static gboolean
+ecb_mapi_save_component_sync (ECalMetaBackend *meta_backend,
+                             gboolean overwrite_existing,
+                             EConflictResolution conflict_resolution,
+                             const GSList *instances,
+                             const gchar *extra,
+                             gchar **out_new_uid,
+                             gchar **out_new_extra,
+                             GCancellable *cancellable,
+                             GError **error)
 {
        ECalBackendMAPI *cbmapi;
-        ECalBackendMAPIPrivate *priv;
-       EMapiConnection *conn;
-       icalcomponent_kind kind;
-       icalcomponent *icalcomp;
-       ECalComponent *comp, *cache_comp = NULL;
-       gboolean status;
-       mapi_id_t mid;
-       const gchar *uid = NULL, *rid = NULL;
-       struct cal_cbdata cbdata = { 0 };
-       gboolean no_increment = FALSE;
-       icalproperty *prop;
-       struct icaltimetype current;
+       ECalComponent *comp;
+       icalcomponent *icomp;
+       gboolean no_increment;
+       mapi_object_t obj_folder;
+       mapi_id_t mid = 0;
+       gboolean success;
        GError *mapi_error = NULL;
 
-       *old_ecalcomp = *new_ecalcomp = NULL;
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-
-       kind = e_cal_backend_get_kind (backend);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (instances != NULL, FALSE);
+       g_return_val_if_fail (out_new_uid != NULL, FALSE);
 
-       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
-       e_mapi_return_data_cal_error_if_fail (calobj != NULL, InvalidArg);
+       *out_new_uid = NULL;
 
-       if (!e_backend_get_online (E_BACKEND (backend))) {
-               g_propagate_error (error, EDC_ERROR (RepositoryOffline));
-               return;
+       if (instances->next ||
+           e_cal_component_is_instance (instances->data)) {
+               g_propagate_error (error, EDC_ERROR_EX (OtherError,
+                       _("Support for modifying single instances of a recurring appointment is not yet 
implemented. No change was made to the appointment on the server.")));
+               return FALSE;
        }
 
-       /* check the component for validity */
-       icalcomp = icalparser_parse_string (calobj);
-       if (!icalcomp) {
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
+       cbmapi = E_CAL_BACKEND_MAPI (meta_backend);
 
-       if (mod != E_CAL_OBJ_MOD_ALL && e_cal_util_component_is_instance (icalcomp)) {
-               icalcomponent_free (icalcomp);
-               g_propagate_error (error, EDC_ERROR_EX (OtherError, _("Support for modifying single instances 
of a recurring appointment is not yet implemented. No change was made to the appointment on the server.")));
-               return;
-       }
+       icomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (instances->data));
+       no_increment = e_cal_util_remove_x_property (icomp, "X-EVOLUTION-IS-REPLY");
 
-       prop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
-       while (prop) {
-               const gchar *name = icalproperty_get_x_name (prop);
-               if (!g_ascii_strcasecmp (name, "X-EVOLUTION-IS-REPLY")) {
-                       no_increment = TRUE;
-                       icalcomponent_remove_property (icalcomp, prop);
-               }
-               prop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
+       comp = e_cal_component_new_from_icalcomponent (icomp);
+       if (!comp) {
+               g_propagate_error (error, EDC_ERROR (InvalidObject));
+               return FALSE;
        }
 
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomp);
-
-       current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-       e_cal_component_set_last_modified (comp, &current);
+       ecb_mapi_lock_connection (cbmapi);
 
-       e_cal_component_get_uid (comp, &uid);
-       /* rid = e_cal_component_get_recurid_as_string (comp); */
-
-       cbdata.kind = kind;
-       cbdata.get_timezone = (icaltimezone * (*)(gpointer data, const gchar *tzid)) 
e_timezone_cache_get_timezone;
-       cbdata.get_tz_data = cbmapi;
-
-       conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
-
-       if (conn) {
+       success = ecb_mapi_open_folder (cbmapi, &obj_folder, cancellable, &mapi_error);
+       if (success) {
+               struct cal_cbdata cbdata = { 0 };
                gboolean has_attendees = e_cal_component_has_attendees (comp);
-               mapi_object_t obj_folder;
 
-               /* when online, send the item to the server */
-               /* check if the object exists */
-               cache_comp = e_cal_backend_store_get_component (priv->store, uid, rid);
-               if (!cache_comp) {
-                       update_local_cache (cbmapi, cancellable);
-                       cache_comp = e_cal_backend_store_get_component (priv->store, uid, rid);
-               }
+               cbdata.kind = e_cal_backend_get_kind (E_CAL_BACKEND (meta_backend));
+               cbdata.comp = comp;
+               cbdata.is_modify = overwrite_existing;
+               cbdata.msgflags = MSGFLAG_READ;
+               cbdata.get_timezone = (icaltimezone * (*)(gpointer data, const gchar *tzid)) 
e_timezone_cache_get_timezone;
+               cbdata.get_tz_data = cbmapi;
 
-               if (!cache_comp) {
-                       g_message ("CRITICAL : Could not find the object in cache");
-                       g_object_unref (comp);
-                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
-                       return;
-               }
+               if (overwrite_existing) {
+                       ecb_mapi_get_comp_mid (icomp, &mid);
+
+                       ecb_mapi_get_server_data (cbmapi, comp, &cbdata, cancellable);
+                       if (ecb_mapi_modifier_is_organizer (cbmapi, comp)) {
+                               cbdata.meeting_type = has_attendees ? MEETING_OBJECT : NOT_A_MEETING;
+                               cbdata.resp = has_attendees ? olResponseOrganized : olResponseNone;
+                               if (!no_increment)
+                                       cbdata.appt_seq += 1;
+                               free_and_dupe_str (cbdata.username, ecb_mapi_get_owner_name (cbmapi));
+                               free_and_dupe_str (cbdata.useridtype, "SMTP");
+                               free_and_dupe_str (cbdata.userid, ecb_mapi_get_owner_email (cbmapi));
+                               free_and_dupe_str (cbdata.ownername, ecb_mapi_get_owner_name (cbmapi));
+                               free_and_dupe_str (cbdata.owneridtype, "SMTP");
+                               free_and_dupe_str (cbdata.ownerid, ecb_mapi_get_owner_email (cbmapi));
+                       } else {
+                               cbdata.resp = has_attendees ? ecb_mapi_find_my_response (cbmapi, comp) : 
olResponseNone;
+                               cbdata.meeting_type = has_attendees ? MEETING_OBJECT_RCVD : NOT_A_MEETING;
+                       }
 
-               get_comp_mid (e_cal_component_get_icalcomponent (cache_comp), &mid);
+                       success = e_mapi_connection_modify_object (cbmapi->priv->conn, &obj_folder, mid,
+                                       e_mapi_cal_utils_comp_to_object, &cbdata, cancellable, &mapi_error);
 
-               cbdata.comp = comp;
-               cbdata.msgflags = MSGFLAG_READ;
-               cbdata.is_modify = TRUE;
+                       ecb_mapi_free_server_data (&cbdata);
+               } else {
+                       cbdata.username = g_strdup (ecb_mapi_get_owner_name (cbmapi));
+                       cbdata.useridtype = (gchar *) "SMTP";
+                       cbdata.userid = g_strdup (ecb_mapi_get_owner_email (cbmapi));
+                       cbdata.ownername = g_strdup (ecb_mapi_get_owner_name (cbmapi));
+                       cbdata.owneridtype = (gchar *) "SMTP";
+                       cbdata.ownerid = g_strdup (ecb_mapi_get_owner_email (cbmapi));
 
-               get_server_data (cbmapi, comp, &cbdata, cancellable);
-               if (modifier_is_organizer(cbmapi, comp)) {
                        cbdata.meeting_type = has_attendees ? MEETING_OBJECT : NOT_A_MEETING;
                        cbdata.resp = has_attendees ? olResponseOrganized : olResponseNone;
-                       if (!no_increment)
-                               cbdata.appt_seq += 1;
-                       free_and_dupe_str (cbdata.username, ecbm_get_user_name (cbmapi));
-                       free_and_dupe_str (cbdata.useridtype, "SMTP");
-                       free_and_dupe_str (cbdata.userid, ecbm_get_user_email (cbmapi));
-                       free_and_dupe_str (cbdata.ownername, ecbm_get_owner_name (cbmapi));
-                       free_and_dupe_str (cbdata.owneridtype, "SMTP");
-                       free_and_dupe_str (cbdata.ownerid, ecbm_get_owner_email (cbmapi));
-               } else {
-                       cbdata.resp = has_attendees ? find_my_response(cbmapi, comp) : olResponseNone;
-                       cbdata.meeting_type = has_attendees ? MEETING_OBJECT_RCVD : NOT_A_MEETING;
-               }
-
-               status = ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &mapi_error);
-               if (status) {
-                       status = e_mapi_connection_modify_object (conn, &obj_folder, mid, 
-                                                                 e_mapi_cal_utils_comp_to_object, &cbdata,
-                                                                 cancellable, &mapi_error);
+                       cbdata.appt_id = e_mapi_cal_util_get_new_appt_id (cbmapi->priv->conn, 
mapi_object_get_id (&obj_folder));
+                       cbdata.appt_seq = 0;
+                       cbdata.globalid = NULL;
+                       cbdata.cleanglobalid = NULL;
 
-                       status = e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error) 
&& status;
+                       success = e_mapi_connection_create_object (cbmapi->priv->conn, &obj_folder, 
E_MAPI_CREATE_FLAG_NONE,
+                               e_mapi_cal_utils_comp_to_object, &cbdata, &mid, cancellable, &mapi_error);
                }
 
-               free_server_data (&cbdata);
-               if (!status) {
-                       g_object_unref (comp);
-                       g_object_unref (cache_comp);
+               g_free (cbdata.username);
+               g_free (cbdata.userid);
+               g_free (cbdata.ownername);
+               g_free (cbdata.ownerid);
 
-                       mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to modify item on a 
server"));
-                       e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
-                       if (mapi_error)
-                               g_error_free (mapi_error);
-                       return;
-               }
-       } else {
-               g_object_unref (comp);
-               g_object_unref (cache_comp);
-               e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
-               if (!mapi_error)
-                       g_propagate_error (error, EDC_ERROR (RepositoryOffline));
-               else
-                       mapi_error_to_edc_error (error, mapi_error, RepositoryOffline, NULL);
+               e_mapi_connection_close_folder (cbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
+       }
+
+       if (mapi_error || !mid) {
+               ecb_mapi_maybe_disconnect (cbmapi, mapi_error);
+               ecb_mapi_error_to_edc_error (error, mapi_error, OtherError,
+                       overwrite_existing ? _("Failed to modify item on a server") : _("Failed to create 
item on a server"));
                g_clear_error (&mapi_error);
-               return;
+
+               success = FALSE;
        }
 
-       *old_ecalcomp = e_cal_component_clone (cache_comp);
-       *new_ecalcomp = e_cal_component_clone (comp);
+       ecb_mapi_unlock_connection (cbmapi);
 
-       put_component_to_store (cbmapi, comp);
-       e_cal_backend_notify_component_modified (E_CAL_BACKEND (cbmapi), *old_ecalcomp, *new_ecalcomp);
+       if (success)
+               *out_new_uid = e_mapi_util_mapi_id_to_string (mid);
 
        g_object_unref (comp);
-       g_object_unref (cache_comp);
+
+       return success;
 }
 
-static void
-ecbm_remove_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable,
-                                 const gchar *uid, const gchar *rid, ECalObjModType mod,
-                                 ECalComponent **old_ecalcomp, ECalComponent **new_ecalcomp, GError **error)
+static gboolean
+ecb_mapi_remove_component_sync (ECalMetaBackend *meta_backend,
+                               EConflictResolution conflict_resolution,
+                               const gchar *uid,
+                               const gchar *extra,
+                               const gchar *object,
+                               GCancellable *cancellable,
+                               GError **error)
 {
        ECalBackendMAPI *cbmapi;
-        ECalBackendMAPIPrivate *priv;
-       EMapiConnection *conn;
-       icalcomponent *icalcomp;
-       gchar *calobj = NULL;
-       mapi_id_t mid;
-       GError *err = NULL, *mapi_error = NULL;
-
-       *old_ecalcomp = *new_ecalcomp = NULL;
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
+       mapi_id_t mid = 0;
+       gboolean success = TRUE;
+       GError *mapi_error = NULL;
 
-       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (meta_backend), FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
 
-       if (!e_backend_get_online (E_BACKEND (backend))) {
-               g_propagate_error (error, EDC_ERROR (RepositoryOffline));
-               return;
-       }
+       cbmapi = E_CAL_BACKEND_MAPI (meta_backend);
 
-       /* when online, modify/delete the item from the server */
-       /* check if the object exists */
-       /* FIXME: we may have detached instances which need to be removed */
-       ecbm_get_object (backend, cal, NULL, uid, NULL, &calobj, &err);
-       if (err) {
-               g_propagate_error (error, err);
-               return;
-       }
+       if (object) {
+               icalcomponent *icomp;
 
-       /* check the component for validity */
-       icalcomp = icalparser_parse_string (calobj);
-       if (!icalcomp) {
-               g_free (calobj);
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
+               icomp = icalcomponent_new_from_string (object);
+               if (icomp) {
+                       ecb_mapi_get_comp_mid (icomp, &mid);
+                       icalcomponent_free (icomp);
+               }
        }
 
-       get_comp_mid (icalcomp, &mid);
-
-       conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
-
-       if (mod == E_CAL_OBJ_MOD_THIS && rid && *rid) {
-               gchar *new_calobj = NULL;
-               struct icaltimetype time_rid;
-
-               /*remove a single instance of a recurring event and modify */
-               time_rid = icaltime_from_string (rid);
-               e_cal_util_remove_instances (icalcomp, time_rid, mod);
-               new_calobj = icalcomponent_as_ical_string_r (icalcomp);
-               ecbm_modify_object (backend, cal, cancellable, new_calobj, E_CAL_OBJ_MOD_ALL, old_ecalcomp, 
new_ecalcomp, &err);
-               g_free (new_calobj);
-       } else if (conn) {
+       if (mid || e_mapi_util_mapi_id_from_string (uid, &mid)) {
                mapi_object_t obj_folder;
-               GSList *list=NULL, *l, *comp_list = e_cal_backend_store_get_components_by_uid (priv->store, 
uid);
-               GError *ri_error = NULL;
-               mapi_id_t *pmid = g_new (mapi_id_t, 1);
 
-               *pmid = mid;
-               list = g_slist_prepend (list, pmid);
+               ecb_mapi_lock_connection (cbmapi);
 
-               if (ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &ri_error)) {
-                       if (e_mapi_connection_remove_items (conn, &obj_folder, list, cancellable, &ri_error)) 
{
-                               for (l = comp_list; l; l = l->next) {
-                                       ECalComponent *comp = E_CAL_COMPONENT (l->data);
-                                       ECalComponentId *id = e_cal_component_get_id (comp);
+               success = ecb_mapi_open_folder (cbmapi, &obj_folder, cancellable, &mapi_error);
+               if (success) {
+                       GSList *mids;
 
-                                       e_cal_backend_store_remove_component (priv->store, id->uid, id->rid);
-                                       e_cal_backend_notify_component_removed (E_CAL_BACKEND (cbmapi), id, 
comp, NULL);
-                                       e_cal_component_free_id (id);
+                       mids = g_slist_prepend (NULL, &mid);
 
-                                       g_object_unref (comp);
-                               }
-                       }
+                       success = e_mapi_connection_remove_items (cbmapi->priv->conn, &obj_folder, mids, 
cancellable, &mapi_error);
 
-                       e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &ri_error);
+                       e_mapi_connection_close_folder (cbmapi->priv->conn, &obj_folder, cancellable, 
&mapi_error);
 
-                       *old_ecalcomp = e_cal_component_new_from_icalcomponent (icalparser_parse_string 
(calobj));
-                       *new_ecalcomp = NULL;
-                       err = NULL; /* Success */
-               } else {
-                       e_cal_backend_mapi_maybe_disconnect (cbmapi, ri_error);
-                       mapi_error_to_edc_error (&err, ri_error, OtherError, _("Cannot remove items from a 
server"));
+                       g_slist_free (mids);
                }
 
-               g_slist_free_full (list, g_free);
-               g_slist_free (comp_list);
-       } else {
-               e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
-               if (!mapi_error)
-                       g_propagate_error (&err, EDC_ERROR (RepositoryOffline));
-               else
-                       mapi_error_to_edc_error (&err, mapi_error, RepositoryOffline, NULL);
-               g_clear_error (&mapi_error);
+               ecb_mapi_unlock_connection (cbmapi);
        }
 
-       g_free (calobj);
+       if (mapi_error || !mid) {
+               ecb_mapi_maybe_disconnect (cbmapi, mapi_error);
+               ecb_mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to remove item from a 
server"));
+               g_clear_error (&mapi_error);
+
+               success = FALSE;
+       }
 
-       if (err)
-               g_propagate_error (error, err);
+       return success;
 }
 
-static void
-ecbm_discard_alarm (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const 
gchar *rid, const gchar *auid, GError **perror)
+static gchar *
+ecb_mapi_get_backend_property (ECalBackend *backend,
+                              const gchar *prop_name)
 {
-       g_propagate_error (perror, EDC_ERROR (NotSupported));
+       ECalBackendMAPI *cbmapi;
+
+       g_return_val_if_fail (prop_name != NULL, NULL);
+
+       cbmapi = E_CAL_BACKEND_MAPI (backend);
+
+       if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+               return g_strjoin (
+                       ",",
+                       CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT,
+                       CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS,
+                       CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS,
+                       CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS,
+                       CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY,
+                       CAL_STATIC_CAPABILITY_REMOVE_ALARMS,
+                       CAL_STATIC_CAPABILITY_NO_THISANDFUTURE,
+                       CAL_STATIC_CAPABILITY_NO_THISANDPRIOR,
+                       CAL_STATIC_CAPABILITY_CREATE_MESSAGES,
+                       CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK,
+                       CAL_STATIC_CAPABILITY_NO_CONV_TO_RECUR,
+                       CAL_STATIC_CAPABILITY_HAS_UNACCEPTED_MEETING,
+                       CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED,
+                       CAL_STATIC_CAPABILITY_NO_MEMO_START_DATE,
+                       CAL_STATIC_CAPABILITY_TASK_DATE_ONLY,
+                       e_cal_meta_backend_get_capabilities (E_CAL_META_BACKEND (backend)),
+                       NULL);
+       } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
+               return g_strdup (ecb_mapi_get_owner_email (cbmapi));
+       } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
+               /* We don't support email alarms. This should not have been called. */
+               return NULL;
+       }
+
+       /* Chain up to parent's method */
+       return E_CAL_BACKEND_CLASS (e_cal_backend_mapi_parent_class)->get_backend_property (backend, 
prop_name);
 }
 
 static void
-ecbm_send_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, 
GSList **users, gchar **modified_calobj, GError **error)
+ecb_mapi_send_objects_sync (ECalBackendSync *sync_backend,
+                           EDataCal *cal,
+                           GCancellable *cancellable,
+                           const gchar *calobj,
+                           GSList **users,
+                           gchar **modified_calobj,
+                           GError **error)
 {
        ECalBackendMAPI *cbmapi;
        EMapiConnection *conn;
@@ -2077,26 +1462,32 @@ ecbm_send_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellabl
        icalcomponent *icalcomp;
        GError *mapi_error = NULL;
 
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
+       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (sync_backend), InvalidArg);
+       e_mapi_return_data_cal_error_if_fail (calobj != NULL, InvalidArg);
 
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+       cbmapi = E_CAL_BACKEND_MAPI (sync_backend);
+       kind = e_cal_backend_get_kind (E_CAL_BACKEND (sync_backend));
 
-       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
-       e_mapi_return_data_cal_error_if_fail (calobj != NULL, InvalidArg);
+       ecb_mapi_lock_connection (cbmapi);
+
+       if (!e_cal_meta_backend_ensure_connected_sync (E_CAL_META_BACKEND (cbmapi), cancellable, &mapi_error) 
||
+           !cbmapi->priv->conn) {
+               ecb_mapi_unlock_connection (cbmapi);
 
-       conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
-       if (!conn) {
                if (!mapi_error)
                        g_propagate_error (error, EDC_ERROR (RepositoryOffline));
                else
-                       mapi_error_to_edc_error (error, mapi_error, RepositoryOffline, NULL);
+                       ecb_mapi_error_to_edc_error (error, mapi_error, RepositoryOffline, NULL);
                g_clear_error (&mapi_error);
                return;
        }
 
+       conn = cbmapi->priv->conn;
+
        /* check the component for validity */
        icalcomp = icalparser_parse_string (calobj);
        if (!icalcomp) {
+               ecb_mapi_unlock_connection (cbmapi);
                g_propagate_error (error, EDC_ERROR (InvalidObject));
                return;
        }
@@ -2106,8 +1497,11 @@ ecbm_send_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellabl
 
        if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
                icalproperty_method method = icalcomponent_get_method (icalcomp);
-               icalcomponent *subcomp = icalcomponent_get_first_component (icalcomp, kind);
-               while (subcomp) {
+               icalcomponent *subcomp;
+
+               for (subcomp = icalcomponent_get_first_component (icalcomp, kind);
+                    subcomp;
+                    subcomp = icalcomponent_get_next_component (icalcomp, kind)) {
                        ECalComponent *comp = e_cal_component_new ();
                        struct cal_cbdata cbdata = { 0 };
                        mapi_id_t mid = 0;
@@ -2127,32 +1521,32 @@ ecbm_send_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellabl
                        cbdata.msgflags = MSGFLAG_READ | MSGFLAG_SUBMIT | MSGFLAG_UNSENT;
 
                        switch (method) {
-                       case ICAL_METHOD_REQUEST :
+                       case ICAL_METHOD_REQUEST:
                                cbdata.meeting_type = MEETING_REQUEST;
                                cbdata.resp = olResponseNotResponded;
                                break;
-                       case ICAL_METHOD_CANCEL :
+                       case ICAL_METHOD_CANCEL:
                                cbdata.meeting_type = MEETING_CANCEL;
                                cbdata.resp = olResponseNotResponded;
                                break;
                        case ICAL_METHOD_REPLY:
-                       case ICAL_METHOD_RESPONSE :
+                       case ICAL_METHOD_RESPONSE:
                                cbdata.meeting_type = MEETING_RESPONSE;
-                               cbdata.resp = find_my_response (cbmapi, comp);
+                               cbdata.resp = ecb_mapi_find_my_response (cbmapi, comp);
                                break;
-                       default :
+                       default:
                                cbdata.meeting_type = NOT_A_MEETING;
                                cbdata.resp = olResponseNone;
                                break;
                        }
 
-                       get_server_data (cbmapi, comp, &cbdata, cancellable);
-                       free_and_dupe_str (cbdata.username, ecbm_get_user_name (cbmapi));
+                       ecb_mapi_get_server_data (cbmapi, comp, &cbdata, cancellable);
+                       free_and_dupe_str (cbdata.username, ecb_mapi_get_owner_name (cbmapi));
                        free_and_dupe_str (cbdata.useridtype, "SMTP");
-                       free_and_dupe_str (cbdata.userid, ecbm_get_user_email (cbmapi));
-                       free_and_dupe_str (cbdata.ownername, ecbm_get_owner_name (cbmapi));
+                       free_and_dupe_str (cbdata.userid, ecb_mapi_get_owner_email (cbmapi));
+                       free_and_dupe_str (cbdata.ownername, ecb_mapi_get_owner_name (cbmapi));
                        free_and_dupe_str (cbdata.owneridtype, "SMTP");
-                       free_and_dupe_str (cbdata.ownerid, ecbm_get_owner_email (cbmapi));
+                       free_and_dupe_str (cbdata.ownerid, ecb_mapi_get_owner_email (cbmapi));
                        cbdata.get_timezone = (icaltimezone * (*)(gpointer data, const gchar *tzid)) 
e_timezone_cache_get_timezone;
                        cbdata.get_tz_data = cbmapi;
 
@@ -2221,1174 +1615,42 @@ ecbm_send_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellabl
 
                        cbdata.globalid = NULL;
                        cbdata.cleanglobalid = NULL;
-                       free_server_data (&cbdata);
+                       ecb_mapi_free_server_data (&cbdata);
                        g_free (globalid.lpb);
                        g_free (cleanglobalid.lpb);
 
                        if (!mid) {
+                               ecb_mapi_unlock_connection (cbmapi);
                                g_object_unref (comp);
-                               mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to create 
item on a server"));
-                               e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
+                               ecb_mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to 
create item on a server"));
+                               ecb_mapi_maybe_disconnect (cbmapi, mapi_error);
                                if (mapi_error)
                                        g_error_free (mapi_error);
                                return;
                        }
 
                        g_object_unref (comp);
-
-                       subcomp = icalcomponent_get_next_component (icalcomp,
-                                                                   e_cal_backend_get_kind (E_CAL_BACKEND 
(backend)));
                }
        }
 
+       ecb_mapi_unlock_connection (cbmapi);
+
        *modified_calobj = g_strdup (calobj);
 
        icalcomponent_free (icalcomp);
 }
 
-static void
-ecbm_receive_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, 
GError **error)
-{
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       icalcomponent_kind kind;
-       icalcomponent *icalcomp;
-       GError *err = NULL;
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
-
-       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
-       e_mapi_return_data_cal_error_if_fail (calobj != NULL, InvalidArg);
-
-       if (!e_backend_get_online (E_BACKEND (backend))) {
-               g_propagate_error (error, EDC_ERROR (RepositoryOffline));
-               return;
-       }
-
-       /* check the component for validity */
-       icalcomp = icalparser_parse_string (calobj);
-       if (!icalcomp) {
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
-
-       if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
-               gboolean stop = FALSE;
-               icalproperty_method method = icalcomponent_get_method (icalcomp);
-               icalcomponent *subcomp = icalcomponent_get_first_component (icalcomp, kind);
-               while (subcomp && !stop) {
-                       ECalComponent *comp = e_cal_component_new ();
-                       ECalObjModType mod;
-                       gchar *rid = NULL;
-                       const gchar *uid;
-                       gchar *comp_str;
-                       ECalComponent *old_ecalcomp = NULL, *new_ecalcomp = NULL;
-
-                       e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
-                       mod = e_cal_component_is_instance (comp) ? E_CAL_OBJ_MOD_THIS : E_CAL_OBJ_MOD_ALL;
-
-                       e_cal_component_get_uid (comp, &uid);
-                       rid = e_cal_component_get_recurid_as_string (comp);
-
-                       switch (method) {
-                       case ICAL_METHOD_REQUEST :
-                               comp_str = NULL;
-                               ecbm_get_object (backend, cal, NULL, uid, NULL, &comp_str, &err);
-                               if (err) {
-                                       g_clear_error (&err);
-                                       comp_str = e_cal_component_get_as_string (comp);
-                                       ecbm_create_object (backend, cal, cancellable, comp_str, NULL, 
&new_ecalcomp, &err);
-                               } else {
-                                       g_free (comp_str);
-                                       comp_str = e_cal_component_get_as_string (comp);
-                                       ecbm_modify_object (backend, cal, cancellable, comp_str, mod, 
&old_ecalcomp, &new_ecalcomp, &err);
-                               }
-                               g_free (comp_str);
-
-                               if (err)
-                                       stop = TRUE;
-                               break;
-                       case ICAL_METHOD_CANCEL :
-                               ecbm_remove_object (backend, cal, cancellable, uid, rid, E_CAL_OBJ_MOD_THIS, 
&old_ecalcomp, &new_ecalcomp, &err);
-                               if (err)
-                                       stop = TRUE;
-                               break;
-                       case ICAL_METHOD_REPLY : {
-                               ECalComponent *cache_comp;
-
-                               g_mutex_lock (&priv->mutex);
-                               cache_comp = e_cal_backend_store_get_component (priv->store, uid, NULL);
-                               g_mutex_unlock (&priv->mutex);
-                               if (cache_comp) {
-                                       gboolean any_changed = FALSE;
-                                       GSList *reply_attendees = NULL, *ri, *cache_attendees = NULL, *ci;
-
-                                       e_cal_component_get_attendee_list (comp, &reply_attendees);
-                                       e_cal_component_get_attendee_list (cache_comp, &cache_attendees);
-
-                                       for (ri = reply_attendees; ri; ri = ri->next) {
-                                               ECalComponentAttendee *ra = ri->data;
-
-                                               if (!ra || !ra->value || !*ra->value)
-                                                       continue;
-
-                                               for (ci = cache_attendees; ci; ci = ci->next) {
-                                                       ECalComponentAttendee *ca = ci->data;
-
-                                                       if (!ca || !ca->value || !*ca->value || 
g_ascii_strcasecmp (ra->value, ca->value) != 0)
-                                                               continue;
-
-                                                       if (ca->status == ra->status)
-                                                               continue;
-
-                                                       ca->status = ra->status;
-                                                       any_changed = TRUE;
-                                               }
-                                       }
-
-                                       if (any_changed) {
-                                               old_ecalcomp = NULL;
-                                               new_ecalcomp = NULL;
-
-                                               e_cal_component_set_attendee_list (cache_comp, 
cache_attendees);
-
-                                               comp_str = e_cal_component_get_as_string (cache_comp);
-                                               ecbm_modify_object (backend, cal, cancellable, comp_str, mod, 
&old_ecalcomp, &new_ecalcomp, &err);
-
-                                               g_free (comp_str);
-                                       }
-
-                                       e_cal_component_free_attendee_list (reply_attendees);
-                                       e_cal_component_free_attendee_list (cache_attendees);
-
-                                       if (err)
-                                               stop = TRUE;
-
-                                       g_object_unref (cache_comp);
-                               }
-                               } break;
-                       default :
-                               break;
-                       }
-
-                       g_free (rid);
-                       g_object_unref (comp);
-
-                       if (old_ecalcomp)
-                               g_object_unref (old_ecalcomp);
-                       if (new_ecalcomp)
-                               g_object_unref (new_ecalcomp);
-
-                       subcomp = icalcomponent_get_next_component (icalcomp,
-                                                                   e_cal_backend_get_kind (E_CAL_BACKEND 
(backend)));
-               }
-       }
-
-       if (err)
-               g_propagate_error (error, err);
-}
-
-static void
-ecbm_get_timezone (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzid, gchar 
**object, GError **error)
-{
-       ETimezoneCache *timezone_cache;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       icaltimezone *zone = NULL;
-
-       cbmapi = (ECalBackendMAPI *) backend;
-       timezone_cache = E_TIMEZONE_CACHE (backend);
-
-       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
-       e_mapi_return_data_cal_error_if_fail (tzid != NULL, InvalidArg);
-
-       priv = cbmapi->priv;
-       e_mapi_return_data_cal_error_if_fail (priv != NULL, InvalidArg);
-
-       zone = e_timezone_cache_get_timezone (timezone_cache, tzid);
-
-       if (!zone) {
-               g_propagate_error (error, e_data_cal_create_error (ObjectNotFound, NULL));
-       } else {
-               icalcomponent *icalcomp;
-
-               icalcomp = icaltimezone_get_component (zone);
-
-               if (!icalcomp) {
-                       g_propagate_error (error, e_data_cal_create_error (InvalidObject, NULL));
-               } else {
-                       *object = icalcomponent_as_ical_string_r (icalcomp);
-               }
-       }
-}
-
-static void
-ecbm_add_timezone (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, 
GError **error)
-{
-       ECalBackendMAPI *cbmapi;
-       ETimezoneCache *timezone_cache;
-       icalcomponent *tz_comp;
-
-       cbmapi = (ECalBackendMAPI *) backend;
-       timezone_cache = E_TIMEZONE_CACHE (backend);
-
-       e_mapi_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
-       e_mapi_return_data_cal_error_if_fail (tzobj != NULL, InvalidArg);
-
-       tz_comp = icalparser_parse_string (tzobj);
-       if (!tz_comp) {
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
-
-       if (icalcomponent_isa (tz_comp) == ICAL_VTIMEZONE_COMPONENT) {
-               icaltimezone *zone;
-               zone = icaltimezone_new ();
-               icaltimezone_set_component (zone, tz_comp);
-               e_timezone_cache_add_timezone (timezone_cache, zone);
-               icaltimezone_free (zone, 1);
-       }
-}
-
-static void
-ecbm_get_free_busy (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, 
time_t start, time_t end, GSList **freebusy, GError **perror)
-{
-       ECalBackendMAPI *cbmapi;
-       EMapiConnection *conn;
-       GError *mapi_error = NULL;
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-
-       conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
-
-       if (!conn) {
-               if (!mapi_error)
-                       g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
-               else
-                       mapi_error_to_edc_error (perror, mapi_error, RepositoryOffline, NULL);
-               g_clear_error (&mapi_error);
-               return;
-       }
-
-       if (!e_mapi_cal_utils_get_free_busy_data (conn, users, start, end, freebusy, cancellable, 
&mapi_error)) {
-               mapi_error_to_edc_error (perror, mapi_error, OtherError, _("Failed to get Free/Busy data"));
-               e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
-
-               if (mapi_error)
-                       g_error_free (mapi_error);
-       }
-}
-
-/***** BACKEND CLASS FUNCTIONS *****/
-
-static void
-ecbm_start_view (ECalBackend *backend, EDataCalView *view)
-{
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       GSList *components, *l;
-       ECalBackendSExp *cbsexp;
-       const gchar *sexp;
-       gboolean search_needed = TRUE;
-       time_t occur_start = -1, occur_end = -1;
-       gboolean prunning_by_time;
-       GError *err = NULL;
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-
-       g_mutex_lock (&priv->mutex);
-
-       cbsexp = e_data_cal_view_get_sexp (view);
-
-       if (!cbsexp) {
-               g_mutex_unlock (&priv->mutex);
-
-               err = EDC_ERROR (InvalidQuery);
-               e_data_cal_view_notify_complete (view, err);
-               g_error_free (err);
-
-               return;
-       }
-
-       sexp = e_cal_backend_sexp_text (cbsexp);
-       if (!sexp || g_str_equal (sexp, "#t"))
-               search_needed = FALSE;
-
-       prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (cbsexp, &occur_start, &occur_end);
-
-       components = prunning_by_time ?
-               e_cal_backend_store_get_components_occuring_in_range (priv->store, occur_start, occur_end)
-               : e_cal_backend_store_get_components (priv->store);
-
-       for (l = components; l != NULL; l = l->next) {
-               ECalComponent *comp = E_CAL_COMPONENT (l->data);
-               if (e_cal_backend_get_kind (E_CAL_BACKEND (backend)) ==
-                               icalcomponent_isa (e_cal_component_get_icalcomponent (comp))) {
-                       if ((!search_needed) ||
-                                       (e_cal_backend_sexp_match_comp (cbsexp, comp, E_TIMEZONE_CACHE 
(backend)))) {
-                               e_data_cal_view_notify_components_added_1 (view, comp);
-                       }
-               }
-       }
-
-       g_slist_free_full (components, g_object_unref);
-       g_mutex_unlock (&priv->mutex);
-
-       g_mutex_lock (&priv->is_updating_mutex);
-       if (!priv->is_updating)
-               e_data_cal_view_notify_complete (view, NULL /* Success */);
-       g_mutex_unlock (&priv->is_updating_mutex);
-}
-
-static void
-ecbm_notify_online_cb (ECalBackend *backend, GParamSpec *pspec)
-{
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-       gboolean online;
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-
-       online = e_backend_get_online (E_BACKEND (backend));
-
-       g_mutex_lock (&priv->mutex);
-
-       if (online) {
-               priv->read_only = FALSE;
-       } else {
-               priv->read_only = TRUE;
-
-               e_mapi_utils_unref_in_thread (G_OBJECT (priv->conn));
-               priv->conn = NULL;
-       }
-
-       e_cal_backend_set_writable (backend, !priv->read_only);
-       g_mutex_unlock (&priv->mutex);
-}
-
-/* Async OP functions, data structures and so on */
-
-typedef enum {
-       OP_OPEN,
-       OP_REFRESH,
-       OP_CREATE_OBJECTS,
-       OP_MODIFY_OBJECTS,
-       OP_REMOVE_OBJECTS,
-       OP_DISCARD_ALARM,
-       OP_RECEIVE_OBJECTS,
-       OP_SEND_OBJECTS,
-       OP_GET_OBJECT,
-       OP_GET_ATTACHMENT_URIS,
-       OP_GET_OBJECT_LIST,
-       OP_GET_TIMEZONE,
-       OP_ADD_TIMEZONE,
-       OP_GET_FREE_BUSY,
-       OP_START_VIEW
-} OperationType;
-
-typedef struct {
-       OperationType ot;
-
-       EDataCal *cal;
-       guint32 opid;
-       GCancellable *cancellable;
-} OperationBase;
-
-typedef struct {
-       OperationBase base;
-
-       gboolean only_if_exists;
-} OperationOpen;
-
-typedef struct {
-       OperationBase base;
-
-       GSList *calobjs;
-} OperationCreate;
-
-typedef struct {
-       OperationBase base;
-
-       GSList *calobjs;
-       ECalObjModType mod;
-} OperationModify;
-
-typedef struct {
-       OperationBase base;
-
-       GSList *ids;
-       ECalObjModType mod;
-} OperationRemove;
-
-typedef struct {
-       OperationBase base;
-
-       gchar *str;
-} OperationStr;
-
-typedef struct {
-       OperationBase base;
-
-       gchar *str1;
-       gchar *str2;
-} OperationStr2;
-
-typedef struct {
-       OperationBase base;
-
-       gchar *uid;
-       gchar *rid;
-       gchar *auid;
-} OperationDiscardAlarm;
-
-typedef struct {
-       OperationBase base;
-
-       GSList *users;
-       time_t start;
-       time_t end;
-} OperationGetFreeBusy;
-
-typedef struct {
-       OperationBase base;
-
-       EDataCalView *view;
-} OperationStartView;
-
-static void
-ecbm_operation_cb (OperationBase *op, gboolean cancelled, ECalBackend *backend)
-{
-       GError *error = NULL;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND (backend));
-       g_return_if_fail (op != NULL);
-
-       cancelled = cancelled || (op->cancellable && g_cancellable_is_cancelled (op->cancellable));
-
-       switch (op->ot) {
-       case OP_OPEN: {
-               OperationOpen *opo = (OperationOpen *) op;
-
-               if (!cancelled) {
-                       ecbm_open (backend, op->cal, op->cancellable, opo->only_if_exists, &error);
-
-                       e_data_cal_respond_open (op->cal, op->opid, error);
-               }
-       } break;
-       case OP_REFRESH: {
-               if (!cancelled) {
-                       ecbm_refresh (backend, op->cal, op->cancellable, &error);
-
-                       e_data_cal_respond_refresh (op->cal, op->opid, error);
-               }
-       } break;
-       case OP_CREATE_OBJECTS: {
-               OperationCreate *opc = (OperationCreate *) op;
-
-               if (!cancelled) {
-                       GSList *iter;
-                       GSList *uids = NULL;
-                       GSList *new_components = NULL;
-
-                       for (iter = opc->calobjs; iter && !g_cancellable_is_cancelled (op->cancellable) && 
!error; iter = iter->next) {
-                               const gchar *calobj = iter->data;
-                               gchar *uid = NULL;
-                               ECalComponent *new_ecalcomp = NULL;
-
-                               ecbm_create_object (backend, op->cal, op->cancellable, calobj, &uid, 
&new_ecalcomp, &error);
-
-                               if (!error) {
-                                       uids = g_slist_prepend (uids, uid);
-                                       new_components = g_slist_prepend (new_components, new_ecalcomp);
-                               }
-                       }
-
-                       uids = g_slist_reverse (uids);
-                       new_components = g_slist_reverse (new_components);
-
-                       e_data_cal_respond_create_objects (op->cal, op->opid, error, uids, new_components);
-
-                       /* free memory */
-                       g_slist_free_full (uids, g_free);
-                       e_util_free_nullable_object_slist (new_components);
-               }
-
-               g_slist_free_full (opc->calobjs, g_free);
-       } break;
-       case OP_MODIFY_OBJECTS: {
-               OperationModify *opm = (OperationModify *) op;
-
-               if (!cancelled) {
-                       GSList *iter;
-                       GSList *new_components = NULL;
-                       GSList *old_components = NULL;
-
-                       for (iter = opm->calobjs; iter && !g_cancellable_is_cancelled (op->cancellable) && 
!error; iter = iter->next) {
-                               const gchar *calobj = iter->data;
-                               ECalComponent *old_ecalcomp = NULL, *new_ecalcomp = NULL;
-
-                               ecbm_modify_object (backend, op->cal, op->cancellable, calobj, opm->mod, 
&old_ecalcomp, &new_ecalcomp, &error);
-
-                               if (!error) {
-                                       if (!new_ecalcomp)
-                                               new_ecalcomp = e_cal_component_new_from_icalcomponent 
(icalparser_parse_string (calobj));
-
-                                       old_components = g_slist_prepend (old_components, old_ecalcomp);
-                                       new_components = g_slist_prepend (new_components, new_ecalcomp);
-                               }
-                       }
-
-                       old_components = g_slist_reverse (old_components);
-                       new_components = g_slist_reverse (new_components);
-
-                       e_data_cal_respond_modify_objects (op->cal, op->opid, error, old_components, 
new_components);
-
-                       e_util_free_nullable_object_slist (old_components);
-                       e_util_free_nullable_object_slist (new_components);
-               }
-
-               g_slist_free_full (opm->calobjs, g_free);
-       } break;
-       case OP_REMOVE_OBJECTS: {
-               OperationRemove *opr = (OperationRemove *) op;
-
-               if (!cancelled) {
-                       GSList *iter;
-                       GSList *ids = NULL;
-                       GSList *new_components = NULL;
-                       GSList *old_components = NULL;
-
-                       for (iter = opr->ids; iter && !g_cancellable_is_cancelled (op->cancellable) && 
!error; iter = iter->next) {
-                               const ECalComponentId *ecid = iter->data;
-                               ECalComponent *old_ecalcomp = NULL, *new_ecalcomp = NULL;
-
-                               if (!ecid)
-                                       continue;
-
-                               ecbm_remove_object (backend, op->cal, op->cancellable, ecid->uid, ecid->rid, 
opr->mod, &old_ecalcomp, &new_ecalcomp, &error);
-
-                               if (!error) {
-                                       ECalComponentId *id = g_new0 (ECalComponentId, 1);
-                                       id->uid = g_strdup (ecid->uid);
-
-                                       if (opr->mod == E_CAL_OBJ_MOD_THIS)
-                                               id->rid = g_strdup (ecid->rid);
-
-                                       ids = g_slist_prepend (ids, id);
-                               }
-                       }
-
-                       ids = g_slist_reverse (ids);
-                       old_components = g_slist_reverse (old_components);
-                       new_components = g_slist_reverse (new_components);
-
-                       e_data_cal_respond_remove_objects (op->cal, op->opid, error, ids, old_components, 
new_components);
-
-                       g_slist_free_full (ids, (GDestroyNotify) e_cal_component_free_id);
-                       e_util_free_nullable_object_slist (old_components);
-                       e_util_free_nullable_object_slist (new_components);
-               }
-
-               g_slist_free_full (opr->ids, (GDestroyNotify) e_cal_component_free_id);
-       } break;
-       case OP_DISCARD_ALARM: {
-               OperationDiscardAlarm *opda = (OperationDiscardAlarm *) op;
-
-               if (!cancelled) {
-                       ecbm_discard_alarm (backend, op->cal, op->cancellable, opda->uid, opda->rid, 
opda->auid, &error);
-
-                       e_data_cal_respond_discard_alarm (op->cal, op->opid, error);
-               }
-
-               g_free (opda->uid);
-               g_free (opda->rid);
-               g_free (opda->auid);
-       } break;
-       case OP_RECEIVE_OBJECTS: {
-               OperationStr *ops = (OperationStr *) op;
-               const gchar *calobj = ops->str;
-
-               if (!cancelled) {
-                       ecbm_receive_objects (backend, op->cal, op->cancellable, calobj, &error);
-
-                       e_data_cal_respond_receive_objects (op->cal, op->opid, error);
-               }
-
-               g_free (ops->str);
-       } break;
-       case OP_SEND_OBJECTS: {
-               OperationStr *ops = (OperationStr *) op;
-               const gchar *calobj = ops->str;
-
-               if (!cancelled) {
-                       GSList *users = NULL;
-                       gchar *modified_calobj = NULL;
-
-                       ecbm_send_objects (backend, op->cal, op->cancellable, calobj, &users, 
&modified_calobj, &error);
-
-                       e_data_cal_respond_send_objects (op->cal, op->opid, error, users, modified_calobj);
-
-                       g_slist_foreach (users, (GFunc) g_free, NULL);
-                       g_slist_free (users);
-                       g_free (modified_calobj);
-               }
-
-               g_free (ops->str);
-       } break;
-       case OP_GET_OBJECT: {
-               OperationStr2 *ops2 = (OperationStr2 *) op;
-               const gchar *uid = ops2->str1, *rid = ops2->str2;
-
-               if (!cancelled) {
-                       gchar *object = NULL;
-
-                       ecbm_get_object (backend, op->cal, op->cancellable, uid, rid, &object, &error);
-
-                       e_data_cal_respond_get_object (op->cal, op->opid, error, object);
-
-                       g_free (object);
-               }
-
-               g_free (ops2->str1);
-               g_free (ops2->str2);
-       } break;
-       case OP_GET_ATTACHMENT_URIS: {
-               OperationStr2 *ops2 = (OperationStr2 *) op;
-               const gchar *uid = ops2->str1, *rid = ops2->str2;
-
-               if (!cancelled) {
-                       GSList *list = NULL;
-
-                       ecbm_get_attachment_uris (backend, op->cal, op->cancellable, uid, rid, &list, &error);
-
-                       e_data_cal_respond_get_attachment_uris (op->cal, op->opid, error, list);
-
-                       g_slist_foreach (list, (GFunc) g_free, NULL);
-                       g_free (list);
-               }
-
-               g_free (ops2->str1);
-               g_free (ops2->str2);
-       } break;
-       case OP_GET_OBJECT_LIST: {
-               OperationStr *ops = (OperationStr *) op;
-               const gchar *sexp = ops->str;
-
-               if (!cancelled) {
-                       GSList *objects = NULL;
-
-                       ecbm_get_object_list (backend, op->cal, op->cancellable, sexp, &objects, &error);
-
-                       e_data_cal_respond_get_object_list (op->cal, op->opid, error, objects);
-
-                       g_slist_foreach (objects, (GFunc) g_free, NULL);
-                       g_slist_free (objects);
-               }
-
-               g_free (ops->str);
-       } break;
-       case OP_GET_TIMEZONE: {
-               OperationStr *ops = (OperationStr *) op;
-               const gchar *tzid = ops->str;
-
-               if (!cancelled) {
-                       gchar *object = NULL;
-
-                       ecbm_get_timezone (backend, op->cal, op->cancellable, tzid, &object, &error);
-
-                       if (!object && tzid) {
-                               /* fallback if tzid contains only the location of timezone */
-                               gint i, slashes = 0;
-
-                               for (i = 0; tzid [i]; i++) {
-                                       if (tzid [i] == '/')
-                                               slashes++;
-                               }
-
-                               if (slashes == 1) {
-                                       icalcomponent *icalcomp = NULL, *free_comp = NULL;
-
-                                       icaltimezone *zone = icaltimezone_get_builtin_timezone (tzid);
-                                       if (!zone) {
-                                               /* Try fetching the timezone from zone directory. There are 
some timezones like MST, US/Pacific etc. which do not appear in
-                                               zone.tab, so they will not be available in the libical 
builtin timezone */
-                                               icalcomp = free_comp = icaltzutil_fetch_timezone (tzid);
-                                       }
-
-                                       if (zone)
-                                               icalcomp = icaltimezone_get_component (zone);
-
-                                       if (icalcomp) {
-                                               icalcomponent *clone = icalcomponent_new_clone (icalcomp);
-                                               icalproperty *prop;
-
-                                               prop = icalcomponent_get_first_property (clone, 
ICAL_TZID_PROPERTY);
-                                               if (prop) {
-                                                       /* change tzid to our, because the component has the 
buildin tzid */
-                                                       icalproperty_set_tzid (prop, tzid);
-
-                                                       object = icalcomponent_as_ical_string_r (clone);
-                                                       g_clear_error (&error);
-                                               }
-                                               icalcomponent_free (clone);
-                                       }
-
-                                       if (free_comp)
-                                               icalcomponent_free (free_comp);
-                               }
-
-                               /* also cache this timezone to backend */
-                               if (object)
-                                       ecbm_add_timezone (backend, op->cal, op->cancellable, object, NULL);
-                       }
-
-                       e_data_cal_respond_get_timezone (op->cal, op->opid, error, object);
-
-                       g_free (object);
-               }
-
-               g_free (ops->str);
-       } break;
-       case OP_ADD_TIMEZONE: {
-               OperationStr *ops = (OperationStr *) op;
-               const gchar *tzobj = ops->str;
-
-               if (!cancelled) {
-                       ecbm_add_timezone (backend, op->cal, op->cancellable, tzobj, &error);
-
-                       e_data_cal_respond_add_timezone (op->cal, op->opid, error);
-               }
-
-               g_free (ops->str);
-       } break;
-       case OP_GET_FREE_BUSY: {
-               OperationGetFreeBusy *opgfb = (OperationGetFreeBusy *) op;
-
-               if (!cancelled) {
-                       GSList *freebusy = NULL;
-
-                       ecbm_get_free_busy (backend, op->cal, op->cancellable, opgfb->users, opgfb->start, 
opgfb->end, &freebusy, &error);
-
-                       if (freebusy)
-                               e_data_cal_report_free_busy_data (op->cal, freebusy);
-                       e_data_cal_respond_get_free_busy (op->cal, op->opid, error, freebusy);
-
-                       g_slist_foreach (freebusy, (GFunc) g_free, NULL);
-                       g_slist_free (freebusy);
-               }
-
-               g_slist_foreach (opgfb->users, (GFunc) g_free, NULL);
-               g_slist_free (opgfb->users);
-       } break;
-       case OP_START_VIEW: {
-               OperationStartView *opsv = (OperationStartView *) op;
-
-               if (!cancelled) {
-                       ecbm_start_view (backend, opsv->view);
-                       /* do not notify here, is should start its own thread */
-               }
-
-               g_object_unref (opsv->view);
-       } break;
-       }
-
-       if (op->cancellable)
-               g_object_unref (op->cancellable);
-       if (op->cal)
-               g_object_unref (op->cal);
-       g_free (op);
-
-       /* for cases when this is the last reference */
-       e_mapi_utils_unref_in_thread (G_OBJECT (backend));
-}
-
-static GSList *
-copy_string_slist (const GSList *lst)
-{
-       GSList *res, *l;
-
-       res = g_slist_copy ((GSList *) lst);
-       for (l = res; l; l = l->next) {
-               l->data = g_strdup (l->data);
-       }
-
-       return res;
-}
-
-static void
-base_op_abstract (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, 
OperationType ot)
-{
-       OperationBase *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationBase, 1);
-       op->ot = ot;
-       op->cal = cal;
-       op->opid = opid;
-       op->cancellable = cancellable;
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-static void
-str_op_abstract (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar 
*str, OperationType ot)
-{
-       OperationStr *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationStr, 1);
-       op->base.ot = ot;
-       op->base.cal = cal;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->str = g_strdup (str);
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-static void
-str2_op_abstract (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar 
*str1, const gchar *str2, OperationType ot)
-{
-       OperationStr2 *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationStr2, 1);
-       op->base.ot = ot;
-       op->base.cal = cal;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->str1 = g_strdup (str1);
-       op->str2 = g_strdup (str2);
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-#define BASE_OP_DEF(_func, _ot)                                                                              
  \
-static void                                                                                            \
-_func (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable)                   \
-{                                                                                                      \
-       base_op_abstract (backend, cal, opid, cancellable, _ot);                                        \
-}
-
-#define STR_OP_DEF(_func, _ot)                                                                         \
-static void                                                                                            \
-_func (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable * cancellable, const gchar *str)      
  \
-{                                                                                                      \
-       str_op_abstract (backend, cal, opid, cancellable, str, _ot);                                    \
-}
-
-#define STR2_OP_DEF(_func, _ot)                                                                        \
-static void                                                                                    \
-_func (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *str1, 
const gchar *str2)     \
-{                                                                                              \
-       str2_op_abstract (backend, cal, opid, cancellable, str1, str2, _ot);                    \
-}
-
-static void
-ecbm_op_open (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean 
only_if_exists)
-{
-       OperationOpen *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationOpen, 1);
-       op->base.ot = OP_OPEN;
-       op->base.cal = cal;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->only_if_exists = only_if_exists;
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-BASE_OP_DEF (ecbm_op_refresh, OP_REFRESH)
-
-static void
-ecbm_op_create_objects (ECalBackend *backend,
-                       EDataCal *cal,
-                       guint32 opid,
-                       GCancellable *cancellable,
-                       const GSList *calobjs)
-{
-       OperationCreate *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationCreate, 1);
-       op->base.ot = OP_CREATE_OBJECTS;
-       op->base.cal = cal;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->calobjs = g_slist_copy_deep ((GSList *) calobjs, (GCopyFunc) g_strdup, NULL);
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-static void
-ecbm_op_modify_objects (ECalBackend *backend,
-                       EDataCal *cal,
-                       guint32 opid,
-                       GCancellable *cancellable,
-                       const GSList *calobjs,
-                       ECalObjModType mod)
-{
-       OperationModify *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationModify, 1);
-       op->base.ot = OP_MODIFY_OBJECTS;
-       op->base.cal = cal;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->calobjs = g_slist_copy_deep ((GSList *) calobjs, (GCopyFunc) g_strdup, NULL);
-       op->mod = mod;
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-static void
-ecbm_op_remove_objects (ECalBackend *backend,
-                       EDataCal *cal,
-                       guint32 opid,
-                       GCancellable *cancellable,
-                       const GSList *ids,
-                       ECalObjModType mod)
-{
-       OperationRemove *op;
-       GSList *iter;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationRemove, 1);
-       op->base.ot = OP_REMOVE_OBJECTS;
-       op->base.cal = cal;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->ids = g_slist_copy ((GSList *) ids);
-       op->mod = mod;
-
-       for (iter = op->ids; iter; iter = iter->next) {
-               ECalComponentId *srcid = iter->data, *desid;
-
-               if (!srcid)
-                       continue;
-
-               desid = g_new0 (ECalComponentId, 1);
-               desid->uid = g_strdup (srcid->uid);
-               desid->rid = g_strdup (srcid->rid);
-
-               iter->data = desid;
-       }
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-static void
-ecbm_op_discard_alarm (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const 
gchar *uid, const gchar *rid, const gchar *auid)
-{
-       OperationDiscardAlarm *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationDiscardAlarm, 1);
-       op->base.ot = OP_DISCARD_ALARM;
-       op->base.cal = cal;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->uid = g_strdup (uid);
-       op->rid = g_strdup (rid);
-       op->auid = g_strdup (auid);
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-STR_OP_DEF  (ecbm_op_receive_objects, OP_RECEIVE_OBJECTS)
-STR_OP_DEF  (ecbm_op_send_objects, OP_SEND_OBJECTS)
-STR2_OP_DEF (ecbm_op_get_object, OP_GET_OBJECT)
-STR_OP_DEF  (ecbm_op_get_object_list, OP_GET_OBJECT_LIST)
-STR2_OP_DEF (ecbm_op_get_attachment_uris, OP_GET_ATTACHMENT_URIS)
-STR_OP_DEF  (ecbm_op_get_timezone, OP_GET_TIMEZONE)
-STR_OP_DEF  (ecbm_op_add_timezone, OP_ADD_TIMEZONE)
-
-static void
-ecbm_op_start_view (ECalBackend *backend, EDataCalView *view)
-{
-       OperationStartView *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-
-       op = g_new0 (OperationStartView, 1);
-       op->base.ot = OP_START_VIEW;
-       op->view = g_object_ref (view);
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
-static void
-ecbm_op_get_free_busy (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const 
GSList *users, time_t start, time_t end)
-{
-       OperationGetFreeBusy *op;
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (backend != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (backend));
-
-       cbmapi = E_CAL_BACKEND_MAPI (backend);
-       priv = cbmapi->priv;
-       g_return_if_fail (priv != NULL);
-
-       g_object_ref (cbmapi);
-       if (cal)
-               g_object_ref (cal);
-       if (cancellable)
-               g_object_ref (cancellable);
-
-       op = g_new0 (OperationGetFreeBusy, 1);
-       op->base.ot = OP_GET_FREE_BUSY;
-       op->base.cal = cal;
-       op->base.opid = opid;
-       op->base.cancellable = cancellable;
-       op->users = copy_string_slist (users);
-       op->start = start;
-       op->end = end;
-
-       e_mapi_operation_queue_push (priv->op_queue, op);
-}
-
 static gboolean
-ecbm_get_destination_address (EBackend *backend,
-                             gchar **host,
-                             guint16 *port)
+ecb_mapi_get_destination_address (EBackend *backend,
+                                 gchar **host,
+                                 guint16 *port)
 {
        ESourceRegistry *registry;
        ESource *source;
        gboolean result = FALSE;
 
-       g_return_val_if_fail (port != NULL, FALSE);
        g_return_val_if_fail (host != NULL, FALSE);
+       g_return_val_if_fail (port != NULL, FALSE);
 
        registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));
        source = e_backend_get_source (backend);
@@ -3422,172 +1684,108 @@ ecbm_get_destination_address (EBackend *backend,
        return result;
 }
 
-static void
-ecbm_constructed (GObject *object)
-{
-       G_OBJECT_CLASS (e_cal_backend_mapi_parent_class)->constructed (object);
-
-       /* Reset the connectable, it steals data from Authentication extension,
-          where is written no address */
-       e_backend_set_connectable (E_BACKEND (object), NULL);
-}
-
-static void
-ecbm_dispose (GObject *object)
+static gchar *
+ecb_mapi_dup_component_revision_cb (ECalCache *cal_cache,
+                                   icalcomponent *icalcomp)
 {
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
-
-       g_return_if_fail (object != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (object));
+       icalproperty *prop;
+       struct icaltimetype itt;
 
-       cbmapi = E_CAL_BACKEND_MAPI (object);
-       priv = cbmapi->priv;
+       g_return_val_if_fail (icalcomp != NULL, NULL);
 
-       if (priv && priv->op_queue)
-               e_mapi_operation_queue_cancel_all (priv->op_queue);
+       prop = icalcomponent_get_first_property (icalcomp, ICAL_LASTMODIFIED_PROPERTY);
+       if (!prop)
+               return NULL;
 
-       if (priv && priv->cancellable) {
-               g_cancellable_cancel (priv->cancellable);
-               g_object_unref (priv->cancellable);
-               priv->cancellable = NULL;
-       }
+       itt = icalproperty_get_lastmodified (prop);
 
-       if (G_OBJECT_CLASS (e_cal_backend_mapi_parent_class)->dispose)
-               (* G_OBJECT_CLASS (e_cal_backend_mapi_parent_class)->dispose) (object);
+       return icaltime_as_ical_string_r (itt);
 }
 
 static void
-ecbm_finalize (GObject *object)
+ecb_mapi_constructed (GObject *object)
 {
-       ECalBackendMAPI *cbmapi;
-       ECalBackendMAPIPrivate *priv;
+       ECalBackendMAPI *cbmapi = E_CAL_BACKEND_MAPI (object);
+       ECalCache *cal_cache;
 
-       g_return_if_fail (object != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_MAPI (object));
-
-       cbmapi = E_CAL_BACKEND_MAPI (object);
-       priv = cbmapi->priv;
-
-       /* Clean up */
-       if (priv->timeout_id) {
-               g_source_remove (priv->timeout_id);
-               priv->timeout_id = 0;
-       }
-
-       if (priv->dlock) {
-               g_mutex_lock (&priv->dlock->mutex);
-               priv->dlock->exit = TRUE;
-               g_mutex_unlock (&priv->dlock->mutex);
+       /* Chaing up to parent's method */
+       G_OBJECT_CLASS (e_cal_backend_mapi_parent_class)->constructed (object);
 
-               g_cond_signal (&priv->dlock->cond);
+       /* Reset the connectable, it steals data from Authentication extension,
+          where is written no address */
+       e_backend_set_connectable (E_BACKEND (object), NULL);
 
-               if (priv->dthread)
-                       g_thread_join (priv->dthread);
+       e_cal_backend_set_writable (E_CAL_BACKEND (cbmapi), TRUE);
 
-               g_mutex_clear (&priv->dlock->mutex);
-               g_cond_clear (&priv->dlock->cond);
-               g_free (priv->dlock);
-               priv->dthread = NULL;
-       }
+       cal_cache = e_cal_meta_backend_ref_cache (E_CAL_META_BACKEND (cbmapi));
 
-       if (priv->op_queue) {
-               g_object_unref (priv->op_queue);
-               priv->op_queue = NULL;
-       }
+       g_signal_connect (cal_cache, "dup-component-revision",
+               G_CALLBACK (ecb_mapi_dup_component_revision_cb), NULL);
 
-       g_mutex_clear (&priv->mutex);
-       g_mutex_clear (&priv->updating_mutex);
-       g_mutex_clear (&priv->is_updating_mutex);
+       g_clear_object (&cal_cache);
+}
 
-       if (priv->store) {
-               g_object_unref (priv->store);
-               priv->store = NULL;
-       }
+static void
+ecb_mapi_dispose (GObject *object)
+{
+       ECalBackendMAPI *cbmapi = E_CAL_BACKEND_MAPI (object);
 
-       if (priv->sendoptions_sync_timeout) {
-               g_source_remove (priv->sendoptions_sync_timeout);
-               priv->sendoptions_sync_timeout = 0;
-       }
+       g_clear_object (&cbmapi->priv->conn);
 
-       if (priv->foreign_username) {
-               g_free (priv->foreign_username);
-               priv->foreign_username = NULL;
-       }
+       /* Chain up to parent's method */
+       G_OBJECT_CLASS (e_cal_backend_mapi_parent_class)->dispose (object);
+}
 
-       if (priv->conn) {
-               g_object_unref (priv->conn);
-               priv->conn = NULL;
-       }
+static void
+ecb_mapi_finalize (GObject *object)
+{
+       ECalBackendMAPI *cbmapi = E_CAL_BACKEND_MAPI (object);
 
-       g_free (priv);
-       cbmapi->priv = NULL;
+       g_rec_mutex_clear (&cbmapi->priv->conn_lock);
 
-       if (G_OBJECT_CLASS (e_cal_backend_mapi_parent_class)->finalize)
-               (* G_OBJECT_CLASS (e_cal_backend_mapi_parent_class)->finalize) (object);
+       /* Chain up to parent's method */
+       G_OBJECT_CLASS (e_cal_backend_mapi_parent_class)->finalize (object);
 }
 
-/* MAPI CLASS INIT */
 static void
-e_cal_backend_mapi_class_init (ECalBackendMAPIClass *class)
+e_cal_backend_mapi_class_init (ECalBackendMAPIClass *klass)
 {
        GObjectClass *object_class;
        EBackendClass *backend_class;
        ECalBackendClass *cal_backend_class;
+       ECalBackendSyncClass *sync_backend_class;
+       ECalMetaBackendClass *meta_backend_class;
 
-       object_class = G_OBJECT_CLASS (class);
-       backend_class = E_BACKEND_CLASS (class);
-       cal_backend_class = E_CAL_BACKEND_CLASS (class);
-
-       object_class->constructed = ecbm_constructed;
-       object_class->dispose = ecbm_dispose;
-       object_class->finalize = ecbm_finalize;
-
-       backend_class->get_destination_address = ecbm_get_destination_address;
-       backend_class->authenticate_sync = ecbm_authenticate_sync;
-
-       /* functions done asynchronously */
-       cal_backend_class->get_backend_property = ecbm_get_backend_property;
-       cal_backend_class->open = ecbm_op_open;
-       cal_backend_class->refresh = ecbm_op_refresh;
-       cal_backend_class->get_object = ecbm_op_get_object;
-       cal_backend_class->get_object_list = ecbm_op_get_object_list;
-       cal_backend_class->get_attachment_uris = ecbm_op_get_attachment_uris;
-       cal_backend_class->create_objects = ecbm_op_create_objects;
-       cal_backend_class->modify_objects = ecbm_op_modify_objects;
-       cal_backend_class->remove_objects = ecbm_op_remove_objects;
-       cal_backend_class->discard_alarm = ecbm_op_discard_alarm;
-       cal_backend_class->receive_objects = ecbm_op_receive_objects;
-       cal_backend_class->send_objects = ecbm_op_send_objects;
-       cal_backend_class->get_timezone = ecbm_op_get_timezone;
-       cal_backend_class->add_timezone = ecbm_op_add_timezone;
-       cal_backend_class->get_free_busy = ecbm_op_get_free_busy;
-       cal_backend_class->start_view = ecbm_op_start_view;
-}
+       g_type_class_add_private (klass, sizeof (ECalBackendMAPIPrivate));
 
-static void
-e_cal_backend_mapi_init (ECalBackendMAPI *cbmapi)
-{
-       ECalBackendMAPIPrivate *priv;
+       meta_backend_class = E_CAL_META_BACKEND_CLASS (klass);
+       meta_backend_class->connect_sync = ecb_mapi_connect_sync;
+       meta_backend_class->disconnect_sync = ecb_mapi_disconnect_sync;
+       meta_backend_class->get_changes_sync = ecb_mapi_get_changes_sync;
+       meta_backend_class->list_existing_sync = ecb_mapi_list_existing_sync;
+       meta_backend_class->load_component_sync = ecb_mapi_load_component_sync;
+       meta_backend_class->save_component_sync = ecb_mapi_save_component_sync;
+       meta_backend_class->remove_component_sync = ecb_mapi_remove_component_sync;
 
-       priv = g_new0 (ECalBackendMAPIPrivate, 1);
+       cal_backend_class = E_CAL_BACKEND_CLASS (klass);
+       cal_backend_class->get_backend_property = ecb_mapi_get_backend_property;
 
-       priv->timeout_id = 0;
-       priv->sendoptions_sync_timeout = 0;
+       sync_backend_class = E_CAL_BACKEND_SYNC_CLASS (klass);
+       sync_backend_class->send_objects_sync = ecb_mapi_send_objects_sync;
 
-       /* create the mutex for thread safety */
-       g_mutex_init (&priv->mutex);
-       g_mutex_init (&priv->updating_mutex);
-       g_mutex_init (&priv->is_updating_mutex);
-       priv->is_updating = FALSE;
-       priv->op_queue = e_mapi_operation_queue_new ((EMapiOperationQueueFunc) ecbm_operation_cb, cbmapi);
-       priv->last_refresh = -1;
-       priv->last_obj_total = -1;
-       priv->cancellable = g_cancellable_new ();
+       backend_class = E_BACKEND_CLASS (klass);
+       backend_class->get_destination_address = ecb_mapi_get_destination_address;
 
-       cbmapi->priv = priv;
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->constructed = ecb_mapi_constructed;
+       object_class->dispose = ecb_mapi_dispose;
+       object_class->finalize = ecb_mapi_finalize;
+}
+
+static void
+e_cal_backend_mapi_init (ECalBackendMAPI *cbmapi)
+{
+       cbmapi->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbmapi, E_TYPE_CAL_BACKEND_MAPI, ECalBackendMAPIPrivate);
 
-       g_signal_connect (
-               cbmapi, "notify::online",
-               G_CALLBACK (ecbm_notify_online_cb), NULL);
+       g_rec_mutex_init (&cbmapi->priv->conn_lock);
 }
diff --git a/src/calendar/e-cal-backend-mapi.h b/src/calendar/e-cal-backend-mapi.h
index dc8689f..d0aab71 100644
--- a/src/calendar/e-cal-backend-mapi.h
+++ b/src/calendar/e-cal-backend-mapi.h
@@ -41,14 +41,14 @@ typedef struct _ECalBackendMAPIClass   ECalBackendMAPIClass;
 typedef struct _ECalBackendMAPIPrivate ECalBackendMAPIPrivate;
 
 struct _ECalBackendMAPI {
-       ECalBackend backend;
+       ECalMetaBackend parent_object;
 
        /* Private data */
        ECalBackendMAPIPrivate *priv;
 };
 
 struct _ECalBackendMAPIClass {
-       ECalBackendClass parent_class;
+       ECalMetaBackendClass parent_class;
 };
 
 GType  e_cal_backend_mapi_get_type(void);
diff --git a/src/libexchangemapi/CMakeLists.txt b/src/libexchangemapi/CMakeLists.txt
index d214c43..58a3a25 100644
--- a/src/libexchangemapi/CMakeLists.txt
+++ b/src/libexchangemapi/CMakeLists.txt
@@ -27,8 +27,6 @@ set(SOURCES
        e-mapi-cal-recur-utils.h
        e-mapi-mail-utils.c
        e-mapi-mail-utils.h
-       e-mapi-operation-queue.c
-       e-mapi-operation-queue.h
        e-source-mapi-folder.c
        e-source-mapi-folder.h
 )
diff --git a/src/libexchangemapi/e-mapi-cal-utils.c b/src/libexchangemapi/e-mapi-cal-utils.c
index 2b1bb53..475e065 100644
--- a/src/libexchangemapi/e-mapi-cal-utils.c
+++ b/src/libexchangemapi/e-mapi-cal-utils.c
@@ -760,28 +760,27 @@ populate_ical_attendees (EMapiConnection *conn,
 static void
 set_attachments_to_comp (EMapiConnection *conn,
                         EMapiAttachment *attachments,
-                        ECalComponent *comp,
-                        const gchar *local_store_path)
+                        ECalComponent *comp)
 {
-       GSList *comp_attach_list = NULL;
        EMapiAttachment *attach;
-       const gchar *uid;
+       icalcomponent *icalcomp;
 
        g_return_if_fail (comp != NULL);
-       g_return_if_fail (local_store_path != NULL);
 
        if (!attachments)
                return;
 
-       e_cal_component_get_uid (comp, &uid);
+       icalcomp = e_cal_component_get_icalcomponent (comp);
+       g_return_if_fail (icalcomp != NULL);
 
        for (attach = attachments; attach; attach = attach->next) {
                uint64_t data_cb = 0;
                const uint8_t *data_lpb = NULL;
                const gchar *filename;
-               const uint32_t *ui32;
-               gchar *path, *attach_uri;
-               GError *error = NULL;
+               icalattach *new_attach;
+               icalparameter *param;
+               gchar *base64;
+               icalproperty *prop;
 
                if (!e_mapi_attachment_get_bin_prop (attach, PidTagAttachDataBinary, &data_cb, &data_lpb)) {
                        g_debug ("%s: Skipping calendar attachment without data", G_STRFUNC);
@@ -792,31 +791,28 @@ set_attachments_to_comp (EMapiConnection *conn,
                if (!filename || !*filename)
                        filename = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachFilename);
 
-               ui32 = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachNumber);
-               path = e_filename_mkdir_encoded (local_store_path, uid, filename, ui32 ? *ui32 : 0);
+               base64 = g_base64_encode ((const guchar *) data_lpb, data_cb);
+               new_attach = icalattach_new_from_data (base64, NULL, NULL);
+               g_free (base64);
 
-               attach_uri = g_filename_to_uri (path, NULL, &error);
-               if (!attach_uri) {
-                       g_debug ("%s: Could not get attach_uri from '%s': %s", G_STRFUNC, path, error ? 
error->message : "Unknown error");
-                       g_clear_error (&error);
-                       g_free (path);
-                       continue;
-               }
+               prop = icalproperty_new_attach (new_attach);
+               icalattach_unref (new_attach);
 
-               if (!g_file_set_contents (path, (const gchar *) data_lpb, data_cb, &error)) {
-                       g_debug ("%s: Failed to write attachment content to '%s': %s", G_STRFUNC, path, error 
? error->message : "Unknown error");
-                       g_free (attach_uri);
-                       g_clear_error (&error);
-               } else {
-                       comp_attach_list = g_slist_append (comp_attach_list, attach_uri);
+               param = icalparameter_new_value (ICAL_VALUE_BINARY);
+               icalproperty_add_parameter (prop, param);
+
+               param = icalparameter_new_encoding (ICAL_ENCODING_BASE64);
+               icalproperty_add_parameter (prop, param);
+
+               if (filename && *filename) {
+                       param = icalparameter_new_filename (filename);
+                       icalproperty_add_parameter (prop, param);
                }
 
-               g_free (path);
+               icalcomponent_add_property (icalcomp, prop);
        }
 
-       e_cal_component_set_attachment_list (comp, comp_attach_list);
-
-       g_slist_free_full (comp_attach_list, g_free);
+       e_cal_component_rescan (comp);
 }
 
 ECalComponent *
@@ -824,7 +820,6 @@ e_mapi_cal_util_object_to_comp (EMapiConnection *conn,
                                EMapiObject *object,
                                icalcomponent_kind kind,
                                gboolean is_reply,
-                               const gchar *local_store_uri,
                                const gchar *use_uid,
                                GSList **detached_components)
 {
@@ -867,8 +862,6 @@ e_mapi_cal_util_object_to_comp (EMapiConnection *conn,
        }
 
        utc_zone = icaltimezone_get_utc_timezone ();
-       if (!local_store_uri)
-               local_store_uri = g_get_tmp_dir ();
 
        str = e_mapi_util_find_array_propval (&object->properties, PidTagSubject);
        str = str ? str : e_mapi_util_find_array_propval (&object->properties, PidTagNormalizedSubject);
@@ -1291,7 +1284,7 @@ e_mapi_cal_util_object_to_comp (EMapiConnection *conn,
                icalcomponent_add_property (ical_comp, prop);
        }
 
-       set_attachments_to_comp (conn, object->attachments, comp, local_store_uri);
+       set_attachments_to_comp (conn, object->attachments, comp);
 
        e_cal_component_rescan (comp);
 
diff --git a/src/libexchangemapi/e-mapi-cal-utils.h b/src/libexchangemapi/e-mapi-cal-utils.h
index 2c173fe..1af3db6 100644
--- a/src/libexchangemapi/e-mapi-cal-utils.h
+++ b/src/libexchangemapi/e-mapi-cal-utils.h
@@ -95,7 +95,6 @@ ECalComponent *       e_mapi_cal_util_object_to_comp                  (EMapiConnection 
*conn,
                                                                 EMapiObject *object,
                                                                 icalcomponent_kind kind,
                                                                 gboolean is_reply,
-                                                                const gchar *local_store_uri,
                                                                 const gchar *use_uid,
                                                                 GSList **detached_components);
 
diff --git a/src/libexchangemapi/e-mapi-mail-utils.c b/src/libexchangemapi/e-mapi-mail-utils.c
index db9b232..961f3e7 100644
--- a/src/libexchangemapi/e-mapi-mail-utils.c
+++ b/src/libexchangemapi/e-mapi-mail-utils.c
@@ -358,7 +358,7 @@ build_ical_string (EMapiConnection *conn,
        else
                use_uid = e_util_generate_uid ();
 
-       comp = e_mapi_cal_util_object_to_comp (conn, object, ical_kind, ical_method == ICAL_METHOD_REPLY, 
NULL, use_uid, &detached_components);
+       comp = e_mapi_cal_util_object_to_comp (conn, object, ical_kind, ical_method == ICAL_METHOD_REPLY, 
use_uid, &detached_components);
 
        g_free (use_uid);
 
diff --git a/src/libexchangemapi/e-mapi-utils.c b/src/libexchangemapi/e-mapi-utils.c
index 092cf79..859dad9 100644
--- a/src/libexchangemapi/e-mapi-utils.c
+++ b/src/libexchangemapi/e-mapi-utils.c
@@ -183,7 +183,7 @@ e_mapi_util_mapi_id_from_string (const gchar *str, mapi_id_t *id)
 {
        gint n = 0;
 
-       if (str && *str)
+       if (str && *str && strlen (str) <= 16)
                n = sscanf (str, "%016" G_GINT64_MODIFIER "X", id);
 
        return (n == 1);


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