[evolution-ews] Derive from EBookMetaBackend and ECalMetaBackend



commit afeea7ba8a6eacdbe59cbfe9e3576bb1a1500cc8
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 7 14:56:36 2017 +0200

    Derive from EBookMetaBackend and ECalMetaBackend

 src/addressbook/e-book-backend-ews.c   | 4288 ++++++++---------------
 src/addressbook/e-book-backend-ews.h   |   13 +-
 src/calendar/e-cal-backend-ews-utils.c |   35 +-
 src/calendar/e-cal-backend-ews-utils.h |    1 -
 src/calendar/e-cal-backend-ews.c       | 6053 +++++++++++++-------------------
 src/calendar/e-cal-backend-ews.h       |   18 +-
 src/server/e-ews-connection.c          |   42 +-
 src/server/e-ews-connection.h          |    4 +-
 src/server/e-ews-item.h                |    5 +
 9 files changed, 4066 insertions(+), 6393 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-ews.c b/src/addressbook/e-book-backend-ews.c
index 7f0aab3..c37a79d 100644
--- a/src/addressbook/e-book-backend-ews.c
+++ b/src/addressbook/e-book-backend-ews.c
@@ -3,6 +3,7 @@
 /* e-book-backend-ews.c - Ews contact backend.
  *
  * 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 version 2 of the GNU Lesser General Public
@@ -50,97 +51,38 @@
 #include "ews-oab-decoder.h"
 #include "ews-oab-decompress.h"
 
-
-#define d(x) x
+#define d(x)
 
 #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)
 
-static gboolean
-ebews_fetch_items (EBookBackendEws *ebews,  GSList *items, GSList **contacts,
-                  GCancellable *cancellable, GError **error);
+#define EWS_MAX_FETCH_COUNT 500
 
-static void cursors_contact_added (EBookBackendEws *bf, EContact *contact);
-static void cursors_contact_removed (EBookBackendEws *bf, EContact *contact);
-static void cursors_recalculate (EBookBackendEws *bf);
+#define ELEMENT_TYPE_SIMPLE 0x01 /* simple string fields */
+#define ELEMENT_TYPE_COMPLEX 0x02 /* complex fields while require different get/set functions */
 
-typedef struct {
-       GCond cond;
-       GMutex mutex;
-       gboolean exit;
-} SyncDelta;
+/* passing field uris for PhysicalAddress, PhoneNumbers causes error, so we
+ * use Default view to fetch them. Thus the summary props just have attachments
+ * and some additional properties that are not return with Default view */
+#define CONTACT_ITEM_PROPS "item:Attachments item:HasAttachments item:Body contacts:Manager 
contacts:Department contacts:SpouseName contacts:AssistantName contacts:BusinessHomePage contacts:Birthday"
 
 struct _EBookBackendEwsPrivate {
-       gchar *base_directory;
+       GRecMutex cnc_lock;
        EEwsConnection *cnc;
-       gchar *folder_id;
-       gchar *oab_url;
-       gchar *folder_name;
-
-       EBookSqlite *summary;
 
-       gboolean is_writable;
-       gboolean marked_for_offline;
-       gboolean cache_ready;
+       gchar *folder_id;
        gboolean is_gal;
 
-       GHashTable *ops;
-
-       /* used for storing attachments */
-       gchar *attachment_dir;
-
-       GRecMutex rec_mutex;
-       GThread *dthread;
-       SyncDelta *dlock;
-
-       GCancellable *cancellable;
-
        guint subscription_key;
-       gboolean listen_notifications;
-
-       guint rev_counter;
-       gchar *locale;
-
-       GList *cursors;
-};
 
-/* using this for backward compatibility with E_DATA_BOOK_MODE */
-enum {
-       MODE_LOCAL,
-       MODE_REMOTE,
-       MODE_ANY
+       /* used for storing attachments */
+       gchar *attachments_dir;
 };
 
-#define EWS_MAX_FETCH_COUNT 500
-#define REFRESH_INTERVAL 21600
-
-#define ELEMENT_TYPE_SIMPLE 0x01 /* simple string fields */
-#define ELEMENT_TYPE_COMPLEX 0x02 /* complex fields while require different get/set functions */
-
-/* passing field uris for PhysicalAddress, PhoneNumbers causes error, so we use Default view to fetch them. 
Thus the summary props just have attachments  and 
- * some additional properties that are not return with Default view */
-#define CONTACT_ITEM_PROPS "item:Attachments item:HasAttachments item:Body contacts:Manager 
contacts:Department contacts:SpouseName contacts:AssistantName contacts:BusinessHomePage contacts:Birthday"
-
-/* NB: This is locked *outside* the EBookSqlite lock. Never lock it under e_book_sqlite_lock() */
-#define PRIV_LOCK(p)   (g_rec_mutex_lock (&(p)->rec_mutex))
-#define PRIV_UNLOCK(p) (g_rec_mutex_unlock (&(p)->rec_mutex))
-
-/* Forward Declarations */
-static void    e_book_backend_ews_initable_init
-                               (GInitableIface *iface);
-static gpointer ews_update_items_thread (gpointer data);
-
-
-G_DEFINE_TYPE_WITH_CODE (
-       EBookBackendEws,
-       e_book_backend_ews,
-       E_TYPE_BOOK_BACKEND,
-       G_IMPLEMENT_INTERFACE (
-               G_TYPE_INITABLE,
-               e_book_backend_ews_initable_init))
+G_DEFINE_TYPE (EBookBackendEws, e_book_backend_ews, E_TYPE_BOOK_META_BACKEND)
 
 static CamelEwsSettings *
-book_backend_ews_get_collection_settings (EBookBackendEws *backend)
+ebb_ews_get_collection_settings (EBookBackendEws *bbews)
 {
        ESource *source;
        ESource *collection;
@@ -149,15 +91,14 @@ book_backend_ews_get_collection_settings (EBookBackendEws *backend)
        CamelSettings *settings;
        const gchar *extension_name;
 
-       source = e_backend_get_source (E_BACKEND (backend));
-       registry = e_book_backend_get_registry (E_BOOK_BACKEND (backend));
+       source = e_backend_get_source (E_BACKEND (bbews));
+       registry = e_book_backend_get_registry (E_BOOK_BACKEND (bbews));
 
        extension_name = e_source_camel_get_extension_name ("ews");
        e_source_camel_generate_subtype ("ews", CAMEL_TYPE_EWS_SETTINGS);
 
        /* The collection settings live in our parent data source. */
-       collection = e_source_registry_find_extension (
-               registry, source, extension_name);
+       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);
@@ -169,13 +110,11 @@ book_backend_ews_get_collection_settings (EBookBackendEws *backend)
 }
 
 static void
-convert_error_to_edb_error (GError **perror)
+ebb_ews_convert_error_to_edb_error (GError **perror)
 {
        GError *error = NULL;
 
-       g_return_if_fail (perror != NULL);
-
-       if (!*perror || (*perror)->domain == E_DATA_BOOK_ERROR)
+       if (!perror || !*perror || (*perror)->domain == E_DATA_BOOK_ERROR)
                return;
 
        if ((*perror)->domain == EWS_CONNECTION_ERROR) {
@@ -194,72 +133,15 @@ convert_error_to_edb_error (GError **perror)
                        error = EDB_ERROR_EX (CONTACT_NOT_FOUND, (*perror)->message);
                        break;
                }
-       }
-
-       if (!error)
-               error = EDB_ERROR_EX (OTHER_ERROR, (*perror)->message);
-
-       g_error_free (*perror);
-       *perror = error;
-}
-
-static gboolean ebews_bump_revision (EBookBackendEws *ebews, GError **error)
-{
-       gboolean ret;
-       gchar *prop_value;
-       time_t t = time (NULL);
-
-       /* rev_counter is protected by the EBookSqlite lock. We only ever
-        * call ebews_bump_revision() under e_book_sqlite_lock() */
-       prop_value = g_strdup_printf ("%" G_GINT64_FORMAT "(%d)", (gint64) t, ++ebews->priv->rev_counter);
-
-       ret = e_book_sqlite_set_key_value (ebews->priv->summary, "revision",
-                                          prop_value, error);
-       if (ret)
-               e_book_backend_notify_property_changed (E_BOOK_BACKEND (ebews),
-                                                       BOOK_BACKEND_PROPERTY_REVISION,
-                                                       prop_value);
-       g_free (prop_value);
-
-       return ret;
-}
-
-
-static gboolean
-book_backend_ews_ensure_connected (EBookBackendEws *bbews,
-                                  GCancellable *cancellable,
-                                  GError **perror)
-{
-       CamelEwsSettings *ews_settings;
-       GError *local_error = NULL;
-
-       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (bbews), FALSE);
-
-       PRIV_LOCK (bbews->priv);
 
-       if (bbews->priv->cnc) {
-               PRIV_UNLOCK (bbews->priv);
-               return TRUE;
+               if (!error)
+                       error = EDB_ERROR_EX (OTHER_ERROR, (*perror)->message);
        }
 
-       PRIV_UNLOCK (bbews->priv);
-
-       ews_settings = book_backend_ews_get_collection_settings (bbews);
-
-       if (e_ews_connection_utils_get_without_password (ews_settings)) {
-               e_backend_schedule_authenticate (E_BACKEND (bbews), NULL);
-       } else {
-               e_backend_credentials_required_sync (E_BACKEND (bbews),
-                       E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL,
-                       cancellable, &local_error);
+       if (error) {
+               g_error_free (*perror);
+               *perror = error;
        }
-
-       if (!local_error)
-               return TRUE;
-
-       g_propagate_error (perror, local_error);
-
-       return FALSE;
 }
 
 static const struct phone_field_mapping {
@@ -287,7 +169,7 @@ static const struct phone_field_mapping {
 };
 
 static void
-ebews_populate_uid (EBookBackendEws *ebews,
+ebews_populate_uid (EBookBackendEws *bbews,
                    EContact *contact,
                     EEwsItem *item,
                    GCancellable *cancellable,
@@ -303,7 +185,7 @@ ebews_populate_uid (EBookBackendEws *ebews,
 }
 
 static void
-ebews_populate_full_name (EBookBackendEws *ebews,
+ebews_populate_full_name (EBookBackendEws *bbews,
                          EContact *contact,
                          EEwsItem *item,
                          GCancellable *cancellable,
@@ -317,7 +199,7 @@ ebews_populate_full_name (EBookBackendEws *ebews,
 }
 
 static void
-ebews_populate_nick_name (EBookBackendEws *ebews,
+ebews_populate_nick_name (EBookBackendEws *bbews,
                          EContact *contact,
                          EEwsItem *item,
                          GCancellable *cancellable,
@@ -331,7 +213,7 @@ ebews_populate_nick_name (EBookBackendEws *ebews,
 }
 
 static void
-ebews_populate_birth_date (EBookBackendEws *ebews,
+ebews_populate_birth_date (EBookBackendEws *bbews,
                           EContact *contact,
                           EEwsItem *item,
                           GCancellable *cancellable,
@@ -357,7 +239,7 @@ ebews_populate_birth_date (EBookBackendEws *ebews,
 }
 
 static void
-ebews_populate_anniversary (EBookBackendEws *ebews,
+ebews_populate_anniversary (EBookBackendEws *bbews,
                            EContact *contact,
                            EEwsItem *item,
                            GCancellable *cancellable,
@@ -383,7 +265,7 @@ ebews_populate_anniversary (EBookBackendEws *ebews,
 }
 
 static EContactPhoto *
-get_photo (EBookBackendEws *ebews,
+get_photo (EBookBackendEws *bbews,
           EEwsItem *item,
           GCancellable *cancellable,
           GError **error)
@@ -407,7 +289,7 @@ get_photo (EBookBackendEws *ebews,
 
        contact_item_ids = g_slist_prepend (contact_item_ids, g_strdup (id->id));
        if (!e_ews_connection_get_items_sync (
-                       ebews->priv->cnc,
+                       bbews->priv->cnc,
                        EWS_PRIORITY_MEDIUM,
                        contact_item_ids,
                        "IdOnly",
@@ -428,7 +310,7 @@ get_photo (EBookBackendEws *ebews,
 
        attachments_ids = g_slist_prepend (attachments_ids, g_strdup (contact_photo_id));
        if (!e_ews_connection_get_attachments_sync (
-               ebews->priv->cnc,
+               bbews->priv->cnc,
                EWS_PRIORITY_MEDIUM,
                NULL,
                attachments_ids,
@@ -459,7 +341,7 @@ exit:
 }
 
 static void
-ebews_populate_photo (EBookBackendEws *ebews,
+ebews_populate_photo (EBookBackendEws *bbews,
                      EContact *contact,
                      EEwsItem *item,
                      GCancellable *cancellable,
@@ -471,10 +353,10 @@ ebews_populate_photo (EBookBackendEws *ebews,
         * Support for ContactPhoto was added in Exchange 2010 SP2.
         * We don't want to try to set/get this property if we are running in older version of the server.
         */
-       if (!e_ews_connection_satisfies_server_version (ebews->priv->cnc, E_EWS_EXCHANGE_2010_SP2))
+       if (!e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010_SP2))
                return;
 
-       photo = get_photo (ebews, item, cancellable, error);
+       photo = get_photo (bbews, item, cancellable, error);
        if (!photo) {
                return;
        }
@@ -497,7 +379,7 @@ set_phone_number (EContact *contact,
 }
 
 static void
-ebews_populate_phone_numbers (EBookBackendEws *ebews,
+ebews_populate_phone_numbers (EBookBackendEws *bbews,
                              EContact *contact,
                              EEwsItem *item,
                              GCancellable *cancellable,
@@ -542,7 +424,7 @@ set_address (EContact *contact,
 }
 
 static void
-ebews_populate_address (EBookBackendEws *ebews,
+ebews_populate_address (EBookBackendEws *bbews,
                        EContact *contact,
                        EEwsItem *item,
                        GCancellable *cancellable,
@@ -555,7 +437,7 @@ ebews_populate_address (EBookBackendEws *ebews,
 }
 
 static void
-ebews_populate_ims (EBookBackendEws *ebews,
+ebews_populate_ims (EBookBackendEws *bbews,
                    EContact *contact,
                    EEwsItem *item,
                    GCancellable *cancellable,
@@ -566,7 +448,7 @@ ebews_populate_ims (EBookBackendEws *ebews,
 }
 
 static void
-ebews_populate_notes (EBookBackendEws *ebews,
+ebews_populate_notes (EBookBackendEws *bbews,
                      EContact *contact,
                      EEwsItem *item,
                      GCancellable *cancellable,
@@ -599,7 +481,7 @@ set_email_address (EContact *contact,
 }
 
 static void
-ebews_populate_emails_ex (EBookBackendEws *ebews,
+ebews_populate_emails_ex (EBookBackendEws *bbews,
                          EContact *contact,
                          EEwsItem *item,
                          gboolean require_smtp_prefix)
@@ -610,13 +492,13 @@ ebews_populate_emails_ex (EBookBackendEws *ebews,
 }
 
 static void
-ebews_populate_emails (EBookBackendEws *ebews,
+ebews_populate_emails (EBookBackendEws *bbews,
                       EContact *contact,
                       EEwsItem *item,
                       GCancellable *cancellable,
                       GError **errror)
 {
-       ebews_populate_emails_ex (ebews, contact, item, FALSE);
+       ebews_populate_emails_ex (bbews, contact, item, FALSE);
 }
 
 static void
@@ -844,15 +726,19 @@ convert_indexed_contact_property_to_updatexml (ESoapMessage *message,
 }
 
 static void
-ebews_set_full_name_changes (EBookBackendEws *ebews,
+ebews_set_full_name_changes (EBookBackendEws *bbews,
                             ESoapMessage *message,
                             EContact *new,
                             EContact *old,
+                            gchar **out_new_change_key,
                             GCancellable *cancellable,
                             GError **error)
 {
        EContactName *name, *old_name;
 
+       if (!message)
+               return;
+
        name = e_contact_get (new, E_CONTACT_NAME);
        old_name = e_contact_get (old, E_CONTACT_NAME);
        if (!old_name && !name)
@@ -878,35 +764,42 @@ ebews_set_full_name_changes (EBookBackendEws *ebews,
 }
 
 static void
-ebews_set_birth_date_changes (EBookBackendEws *ebews,
+ebews_set_birth_date_changes (EBookBackendEws *bbews,
                              ESoapMessage *message,
                              EContact *new,
                              EContact *old,
+                             gchar **out_new_change_key,
                              GCancellable *cancellable,
                              GError **error)
 {
        EContactDate *new_date, *old_date;
        gchar *birthday;
 
+       if (!message)
+               return;
+
        new_date = e_contact_get (new, E_CONTACT_BIRTH_DATE);
        old_date = e_contact_get (old, E_CONTACT_BIRTH_DATE);
 
-       if (e_contact_date_equal (new_date, old_date))
-               return;
+       if (!e_contact_date_equal (new_date, old_date)) {
+               birthday = g_strdup_printf (
+                       "%04d-%02d-%02dT00:00:00",
+                       new_date->year, new_date->month, new_date->day);
 
-       birthday = g_strdup_printf (
-               "%04d-%02d-%02dT00:00:00",
-               new_date->year, new_date->month, new_date->day);
+               convert_contact_property_to_updatexml (message, "Birthday", birthday, "contacts", NULL, NULL);
+               g_free (birthday);
+       }
 
-       convert_contact_property_to_updatexml (message, "Birthday", birthday, "contacts", NULL, NULL);
-       g_free (birthday);
+       e_contact_date_free (new_date);
+       e_contact_date_free (old_date);
 }
 
 static void
-ebews_set_anniversary_changes (EBookBackendEws *ebews,
+ebews_set_anniversary_changes (EBookBackendEws *bbews,
                               ESoapMessage *message,
                               EContact *new,
                               EContact *old,
+                              gchar **out_new_change_key,
                               GCancellable *cancellable,
                               GError **error)
 {
@@ -914,21 +807,27 @@ ebews_set_anniversary_changes (EBookBackendEws *ebews,
 }
 
 static void
-set_photo (EBookBackendEws *ebews,
+set_photo (EBookBackendEws *bbews,
+          const EwsId *item_id,
           EContact *contact,
           EContactPhoto *photo,
+          gchar **new_change_key,
           GCancellable *cancellable,
           GError **error)
 {
        EEwsAttachmentInfo *info;
-       EwsId *id;
+       EwsId *id = NULL;
        GSList *files = NULL;
        const guchar *data;
        gsize len;
 
-       id = g_new0 (EwsId, 1);
-       id->id = e_contact_get (contact, E_CONTACT_UID);
-       id->change_key = e_contact_get (contact, E_CONTACT_REV);
+       if (!item_id) {
+               id = g_new0 (EwsId, 1);
+               id->id = e_contact_get (contact, E_CONTACT_UID);
+               id->change_key = e_contact_get (contact, E_CONTACT_REV);
+
+               item_id = id;
+       }
 
        data = e_contact_photo_get_inlined (photo, &len);
 
@@ -940,81 +839,127 @@ set_photo (EBookBackendEws *ebews,
        files = g_slist_append (files, info);
 
        e_ews_connection_create_attachments_sync (
-                       ebews->priv->cnc,
+                       bbews->priv->cnc,
                        EWS_PRIORITY_MEDIUM,
-                       id,
+                       item_id,
                        files,
                        TRUE,
-                       NULL,
+                       new_change_key,
                        NULL,
                        cancellable,
                        error);
 
-       g_free (id->change_key);
-       g_free (id->id);
-       g_free (id);
+       if (id) {
+               g_free (id->change_key);
+               g_free (id->id);
+               g_free (id);
+       }
 
        g_slist_free_full (files, (GDestroyNotify) e_ews_attachment_info_free);
 }
 
 static gboolean
-photos_equal (EContactPhoto *old,
-               EContactPhoto *new)
+ebb_ews_photo_changed (EBookMetaBackend *meta_backend,
+                      EContact *old_contact,
+                      EContact *new_contact,
+                      GCancellable *cancellable)
 {
-       const guchar *old_content, *new_content;
-       gsize old_len, new_len;
+       EContact *old_contact_copy = NULL;
+       EContactPhoto *old_photo;
+       EContactPhoto *new_photo;
+       gboolean changed = FALSE;
 
-       if (!old && !new)
-               return TRUE;
+       old_photo = e_contact_get (old_contact, E_CONTACT_PHOTO);
+       new_photo = e_contact_get (new_contact, E_CONTACT_PHOTO);
 
-       if (!old || !new)
-               return FALSE;
+       if (!old_photo && new_photo)
+               changed = TRUE;
 
-       old_content = e_contact_photo_get_inlined (old, &old_len);
-       new_content = e_contact_photo_get_inlined (new, &new_len);
+       if (old_photo && !new_photo)
+               changed = TRUE;
 
-       if (old_len != new_len)
-               return FALSE;
+       /* old_photo comes from cache, thus it's always URI (to local file or elsewhere),
+          while the new_photo is to be saved, which is always inlined. */
+       if (!changed && old_photo && new_photo &&
+           old_photo->type == E_CONTACT_PHOTO_TYPE_URI &&
+           new_photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
+               e_contact_photo_free (old_photo);
+               old_photo = NULL;
 
-       if (memcmp (old_content, new_content, old_len) != 0)
-               return FALSE;
+               old_contact_copy = e_contact_duplicate (old_contact);
 
-       return TRUE;
+               if (e_book_meta_backend_inline_local_photos_sync (meta_backend, old_contact_copy, 
cancellable, NULL))
+                       old_photo = e_contact_get (old_contact_copy, E_CONTACT_PHOTO);
+       }
+
+       if (old_photo && new_photo &&
+           old_photo->type == E_CONTACT_PHOTO_TYPE_INLINED &&
+           new_photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
+               guchar *old_data;
+               guchar *new_data;
+               gsize old_length;
+               gsize new_length;
+
+               old_data = old_photo->data.inlined.data;
+               new_data = new_photo->data.inlined.data;
+
+               old_length = old_photo->data.inlined.length;
+               new_length = new_photo->data.inlined.length;
+
+               changed =
+                       (old_length != new_length) ||
+                       (memcmp (old_data, new_data, old_length) != 0);
+       }
+
+       e_contact_photo_free (old_photo);
+       e_contact_photo_free (new_photo);
+       g_clear_object (&old_contact_copy);
+
+       return changed;
 }
 
 static void
-ebews_set_photo_changes (EBookBackendEws *ebews,
+ebews_set_photo_changes (EBookBackendEws *bbews,
                         ESoapMessage *message,
                         EContact *new,
                         EContact *old,
+                        gchar **out_new_change_key,
                         GCancellable *cancellable,
                         GError **error)
 {
-       EContactPhoto *old_photo, *new_photo;
+       EContactPhoto *new_photo = NULL;
        EEwsAdditionalProps *add_props = NULL;
        GSList *contact_item_ids = NULL, *new_items = NULL, *attachments_ids = NULL;
-       gchar *id = e_contact_get (old, E_CONTACT_UID);
+       gchar *id = NULL;
        const gchar *contact_photo_id;
+       gchar *new_change_key = NULL;
 
        /*
         * Support for ContactPhoto was added in Exchange 2010 SP2.
         * We don't want to try to set/get this property if we are running in older version of the server.
         */
-       if (!e_ews_connection_satisfies_server_version (ebews->priv->cnc, E_EWS_EXCHANGE_2010_SP2))
+       if (!e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010_SP2)) {
+               return;
+       }
+
+       if (message) {
+               /* Photo changes can be done only in pre-flight stage,
+                  because it modifies ChangeKey */
                return;
+       }
 
-       old_photo = e_contact_get (old, E_CONTACT_PHOTO);
-       new_photo = e_contact_get (new, E_CONTACT_PHOTO);
+       if (!ebb_ews_photo_changed (E_BOOK_META_BACKEND (bbews), old, new, cancellable))
+               return;
 
-       if (photos_equal (old_photo, new_photo))
-               goto exit;
+       new_photo = e_contact_get (new, E_CONTACT_PHOTO);
+       id = e_contact_get (old, E_CONTACT_UID);
 
        add_props = e_ews_additional_props_new ();
        add_props->field_uri = g_strdup ("item:Attachments");
 
        contact_item_ids = g_slist_append (contact_item_ids, id);
        if (!e_ews_connection_get_items_sync (
-                       ebews->priv->cnc,
+                       bbews->priv->cnc,
                        EWS_PRIORITY_MEDIUM,
                        contact_item_ids,
                        "IdOnly",
@@ -1033,38 +978,68 @@ ebews_set_photo_changes (EBookBackendEws *ebews,
        if (contact_photo_id) {
                attachments_ids = g_slist_prepend (attachments_ids, g_strdup (contact_photo_id));
                if (!e_ews_connection_delete_attachments_sync (
-                                       ebews->priv->cnc,
+                                       bbews->priv->cnc,
                                        EWS_PRIORITY_MEDIUM,
                                        attachments_ids,
-                                       NULL,
+                                       &new_change_key,
                                        cancellable,
                                        error))
                        goto exit;
        }
 
-       if (new_photo)
-               set_photo (ebews, new, new_photo, cancellable, error);
+       if (new_photo) {
+               EwsId *item_id = NULL;
 
-exit:
+               if (new_change_key) {
+                       item_id = g_new0 (EwsId, 1);
+                       item_id->id = e_contact_get (new, E_CONTACT_UID);
+                       item_id->change_key = new_change_key;
+
+                       new_change_key = NULL;
+               }
+
+               set_photo (bbews, item_id, new, new_photo, &new_change_key, cancellable, error);
+
+               if (item_id) {
+                       if (!new_change_key) {
+                               new_change_key = item_id->change_key;
+                               item_id->change_key = NULL;
+                       }
+
+                       g_free (item_id->id);
+                       g_free (item_id->change_key);
+                       g_free (item_id);
+               }
+       }
+
+ exit:
        e_ews_additional_props_free (add_props);
-       e_contact_photo_free (old_photo);
        e_contact_photo_free (new_photo);
        g_slist_free_full (contact_item_ids, g_free);
        g_slist_free_full (new_items, g_object_unref);
        g_slist_free_full (attachments_ids, g_free);
+
+       if (new_change_key && out_new_change_key)
+               *out_new_change_key = new_change_key;
+       else
+               g_free (new_change_key);
 }
 
 static void
-ebews_set_phone_number_changes (EBookBackendEws *ebews,
+ebews_set_phone_number_changes (EBookBackendEws *bbews,
                                ESoapMessage *message,
                                EContact *new,
                                EContact *old,
+                               gchar **out_new_change_key,
                                GCancellable *cancellable,
                                GError **error)
 {
        gint i;
        gchar *new_value, *old_value;
 
+       if (!message)
+               return;
+
        for (i = 0; i < G_N_ELEMENTS (phone_field_map); i++) {
                new_value = e_contact_get (new, phone_field_map[i].field);
                old_value = e_contact_get (old, phone_field_map[i].field);
@@ -1149,23 +1124,28 @@ compare_address (ESoapMessage *message,
 }
 
 static void
-ebews_set_address_changes (EBookBackendEws *ebews,
+ebews_set_address_changes (EBookBackendEws *bbews,
                           ESoapMessage *message,
                           EContact *new,
                           EContact *old,
+                          gchar **out_new_change_key,
                           GCancellable *cancellable,
                           GError **error)
 {
+       if (!message)
+               return;
+
        compare_address (message, new, old, E_CONTACT_ADDRESS_WORK, "Business");
        compare_address (message, new, old, E_CONTACT_ADDRESS_HOME, "Home");
        compare_address (message, new, old, E_CONTACT_ADDRESS_OTHER, "Other");
 }
 
 static void
-ebews_set_im_changes (EBookBackendEws *ebews,
+ebews_set_im_changes (EBookBackendEws *bbews,
                      ESoapMessage *message,
                      EContact *new,
                      EContact *old,
+                     gchar **out_new_change_key,
                      GCancellable *cancellable,
                      GError **error)
 {
@@ -1173,15 +1153,19 @@ ebews_set_im_changes (EBookBackendEws *ebews,
 }
 
 static void
-ebews_set_notes_changes (EBookBackendEws *ebews,
+ebews_set_notes_changes (EBookBackendEws *bbews,
                         ESoapMessage *message,
                         EContact *new,
                         EContact *old,
+                        gchar **out_new_change_key,
                         GCancellable *cancellable,
                         GError **error)
 {
        gchar *old_notes, *new_notes;
 
+       if (!message)
+               return;
+
        old_notes = e_contact_get (old, E_CONTACT_NOTE);
        new_notes = e_contact_get (new, E_CONTACT_NOTE);
 
@@ -1195,15 +1179,19 @@ ebews_set_notes_changes (EBookBackendEws *ebews,
 }
 
 static void
-ebews_set_email_changes (EBookBackendEws *ebews,
+ebews_set_email_changes (EBookBackendEws *bbews,
                         ESoapMessage *message,
                         EContact *new,
                         EContact *old,
+                        gchar **out_new_change_key,
                         GCancellable *cancellable,
                         GError **error)
 {
        gchar *new_value, *old_value;
 
+       if (!message)
+               return;
+
        new_value = e_contact_get (new, E_CONTACT_EMAIL_1);
        old_value = e_contact_get (old, E_CONTACT_EMAIL_1);
        if (g_strcmp0 (new_value, old_value) != 0)
@@ -1227,7 +1215,7 @@ ebews_set_email_changes (EBookBackendEws *ebews,
 }
 
 static void
-ebews_populate_givenname (EBookBackendEws *ebews,
+ebews_populate_givenname (EBookBackendEws *bbews,
                          EContact *contact,
                          EEwsItem *item,
                          GCancellable *cancellable,
@@ -1248,10 +1236,11 @@ ebews_set_givenname (ESoapMessage *message,
 }
 
 static void
-ebews_set_givenname_changes (EBookBackendEws *ebews,
+ebews_set_givenname_changes (EBookBackendEws *bbews,
                             ESoapMessage *message,
                             EContact *new,
                             EContact *old,
+                            gchar **out_new_change_key,
                             GCancellable *cancellable,
                             GError **error)
 {
@@ -1264,9 +1253,9 @@ static const struct field_element_mapping {
        const gchar *element_name;
        /* set function for simple string type values */
        const gchar * (*get_simple_prop_func) (EEwsItem *item);
-       void (*populate_contact_func)(EBookBackendEws *ebews, EContact *contact, EEwsItem *item, GCancellable 
*cancellable, GError **error);
+       void (*populate_contact_func)(EBookBackendEws *bbews, EContact *contact, EEwsItem *item, GCancellable 
*cancellable, GError **error);
        void (*set_value_in_soap_message) (ESoapMessage *message, EContact *contact);
-       void (*set_changes) (EBookBackendEws *ebews, ESoapMessage *message, EContact *new, EContact *old, 
GCancellable *cancellable, GError **error);
+       void (*set_changes) (EBookBackendEws *bbews, ESoapMessage *message, EContact *new, EContact *old, 
gchar **out_new_change_key, GCancellable *cancellable, GError **error);
 
 } mappings[] = {
        /* The order should be maintained for create contacts to work */
@@ -1301,18 +1290,9 @@ static const struct field_element_mapping {
        { E_CONTACT_UID, ELEMENT_TYPE_COMPLEX, "ItemId", NULL,  ebews_populate_uid, ebews_set_item_id},
 };
 
-typedef struct {
-       EBookBackendEws *ebews;
-       EDataBook *book;
-       EContact *contact;
-       guint32 opid;
-       GCancellable *cancellable;
-       gboolean is_dl;
-} EwsCreateContact;
-
 static void
-ews_write_dl_members (ESoapMessage *msg,
-                     EContact *contact)
+ebb_ews_write_dl_members (ESoapMessage *msg,
+                         EContact *contact)
 {
        GSList *emails, *l;
 
@@ -1346,8 +1326,8 @@ ews_write_dl_members (ESoapMessage *msg,
 }
 
 static void
-convert_dl_to_xml (ESoapMessage *msg,
-                  gpointer user_data)
+ebb_ews_convert_dl_to_xml_cb (ESoapMessage *msg,
+                             gpointer user_data)
 {
        EContact *contact = user_data;
        EVCardAttribute *attribute;
@@ -1360,16 +1340,16 @@ convert_dl_to_xml (ESoapMessage *msg,
        values = e_vcard_attribute_get_values (attribute);
        e_ews_message_write_string_parameter (msg, "DisplayName", NULL, values->data);
 
-       ews_write_dl_members (msg, contact);
+       ebb_ews_write_dl_members (msg, contact);
 
        e_soap_message_end_element (msg); /* DistributionList */
 }
 
 static void
-convert_contact_to_xml (ESoapMessage *msg,
-                        gpointer user_data)
+ebb_ews_convert_contact_to_xml_cb (ESoapMessage *msg,
+                                  gpointer user_data)
 {
-       EContact *contact = (EContact *) user_data;
+       EContact *contact = user_data;
        gint i, element_type;
 
        /* Prepare Contact node in the SOAP message */
@@ -1393,950 +1373,531 @@ convert_contact_to_xml (ESoapMessage *msg,
                        mappings[i].set_value_in_soap_message (msg, contact);
        }
 
-       // end of "Contact"
+       /* end of "Contact" */
        e_soap_message_end_element (msg);
 }
 
+typedef struct _ConvertData {
+       EBookBackendEws *bbews;
+       GCancellable *cancellable;
+       GError **error;
+
+       EContact *old_contact;
+       EContact *new_contact;
+       gchar *change_key;
+} ConvertData;
+
 static void
-ews_create_contact_cb (GObject *object,
-                       GAsyncResult *res,
-                       gpointer user_data)
+ebb_ews_convert_dl_to_updatexml_cb (ESoapMessage *msg,
+                                   gpointer user_data)
 {
-       EEwsConnection *cnc = E_EWS_CONNECTION (object);
-       EwsCreateContact *create_contact = user_data;
-       EBookBackendEws *ebews = create_contact->ebews;
-       GError *error = NULL;
-       GSList *items = NULL;
-       const EwsId *item_id;
+       ConvertData *cd = user_data;
+       EContact *old_contact = cd->old_contact;
+       EContact *new_contact = cd->new_contact;
 
-       /* get a list of ids from server (single item) */
-       e_ews_connection_create_items_finish (cnc, res, &items, &error);
+       e_ews_message_start_item_change (msg, E_EWS_ITEMCHANGE_TYPE_ITEM,
+               e_contact_get_const (old_contact, E_CONTACT_UID),
+               cd->change_key ? cd->change_key : e_contact_get_const (old_contact, E_CONTACT_REV),
+               0);
+       e_ews_message_start_set_item_field (msg, "Members", "distributionlist", "DistributionList");
+       ebb_ews_write_dl_members (msg, new_contact);
+       e_ews_message_end_set_item_field (msg);
+       e_ews_message_end_item_change (msg);
+}
 
-       g_return_if_fail (ebews->priv->summary != NULL);
+static void
+ebb_ews_convert_contact_to_updatexml_cb (ESoapMessage *msg,
+                                        gpointer user_data)
+{
+       ConvertData *cd = user_data;
+       EContact *old_contact = cd->old_contact;
+       EContact *new_contact = cd->new_contact;
+       gchar *value = NULL, *old_value = NULL;
+       gint i, element_type;
 
-       if (error == NULL) {
-               EEwsItem *item = items->data;
-               EContactPhoto *photo;
-               EVCardAttribute *attr;
+       /* Pre-flight, to update the ChangeKey if needed */
+       for (i = 0; i < G_N_ELEMENTS (mappings); i++) {
+               element_type = mappings[i].element_type;
 
-               attr = e_vcard_attribute_new (NULL, "X-EWS-KIND");
-               e_vcard_add_attribute_with_value (
-                               E_VCARD (create_contact->contact),
-                               attr,
-                               create_contact->is_dl ? "DT_DISTLIST" : "DT_MAILUSER");
+               if (element_type == ELEMENT_TYPE_COMPLEX) {
+                       gchar *new_change_key = NULL;
 
-               /* set item id */
-               item_id = e_ews_item_get_id (item);
-
-               e_contact_set (create_contact->contact, E_CONTACT_UID, item_id->id);
-               e_contact_set (create_contact->contact, E_CONTACT_REV, item_id->change_key);
-               if (e_book_sqlite_lock (ebews->priv->summary, EBSQL_LOCK_WRITE, create_contact->cancellable, 
&error)) {
-                       if (e_book_sqlite_add_contact (ebews->priv->summary, create_contact->contact, NULL,
-                                                      TRUE, create_contact->cancellable, &error) &&
-                           ebews_bump_revision (ebews, &error))
-                               e_book_sqlite_unlock (ebews->priv->summary, EBSQL_UNLOCK_COMMIT, &error);
-                       else
-                               e_book_sqlite_unlock (ebews->priv->summary, EBSQL_UNLOCK_ROLLBACK, &error);
-               }
-               if (error == NULL) {
-                       GSList *contacts;
+                       if (mappings[i].field_id == E_CONTACT_UID)
+                               continue;
 
-                       contacts = g_slist_append (NULL, create_contact->contact);
-                       e_data_book_respond_create_contacts (create_contact->book, create_contact->opid, 
EDB_ERROR (SUCCESS), contacts);
-                       g_slist_free (contacts);
-                       cursors_contact_added (ebews, create_contact->contact);
-               }
+                       mappings[i].set_changes (cd->bbews, NULL, new_contact, old_contact, &new_change_key, 
cd->cancellable, cd->error);
 
-               /*
-                * Support for ContactPhoto was added in Exchange 2010 SP2.
-                * We don't want to try to set/get this property if we are running in older version of the 
server.
-                */
-               if (!e_ews_connection_satisfies_server_version (ebews->priv->cnc, E_EWS_EXCHANGE_2010_SP2)) {
-                       /*
-                        * The contact photo is basically an attachment with a special name.
-                        * Considering this, we only can set the contact photo after create the contact 
itself.
-                        * Then we are able to attach the picture to the "Contact Item".
-                        */
-                       photo = e_contact_get (create_contact->contact, E_CONTACT_PHOTO);
-                       if (photo) {
-                               set_photo (ebews, create_contact->contact, photo, 
create_contact->cancellable, &error);
-                               e_contact_photo_free (photo);
+                       if (new_change_key) {
+                               g_free (cd->change_key);
+                               cd->change_key = new_change_key;
                        }
                }
-
-               g_object_unref (item);
-               g_slist_free (items);
-       }
-
-       if (error) {
-               g_warning ("Error while Creating contact: %s", error->message);
-               e_data_book_respond_create_contacts (create_contact->book, create_contact->opid, EDB_ERROR_EX 
(OTHER_ERROR, error->message), NULL);
-       }
-
-       /* free memory allocated for create_contact & unref contained objects */
-       g_object_unref (create_contact->ebews);
-       g_object_unref (create_contact->contact);
-       g_object_unref (create_contact->cancellable);
-       g_free (create_contact);
-       g_clear_error (&error);
-}
-
-static void
-e_book_backend_ews_create_contacts (EBookBackend *backend,
-                                    EDataBook *book,
-                                    guint32 opid,
-                                    GCancellable *cancellable,
-                                    const GSList *vcards)
-{
-       EContact *contact = NULL;
-       EBookBackendEws *ebews;
-       EwsCreateContact *create_contact;
-       EwsFolderId *fid;
-       EBookBackendEwsPrivate *priv;
-       GError *error = NULL;
-       gboolean is_dl = FALSE;
-
-       if (vcards->next != NULL) {
-               e_data_book_respond_create_contacts (
-                       book, opid,
-                       EDB_ERROR_EX (NOT_SUPPORTED,
-                       _("The backend does not support bulk additions")),
-                       NULL);
-               return;
        }
 
-       ebews = E_BOOK_BACKEND_EWS (backend);
-       priv = ebews->priv;
+       e_ews_message_start_item_change (msg, E_EWS_ITEMCHANGE_TYPE_ITEM,
+               e_contact_get_const (old_contact, E_CONTACT_UID),
+               cd->change_key ? cd->change_key : e_contact_get_const (old_contact, E_CONTACT_REV),
+               0);
 
-       if (!e_backend_get_online (E_BACKEND (backend)) || !ebews->priv->cnc) {
-               if (!priv->is_writable) {
-                       e_data_book_respond_create_contacts (book, opid, EDB_ERROR (PERMISSION_DENIED), NULL);
-                       return;
-               }
-
-               e_data_book_respond_create_contacts (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
-               return;
-       }
+       /* Iterate for each field in contact */
 
-       if (!book_backend_ews_ensure_connected (ebews, cancellable, &error)) {
-               convert_error_to_edb_error (&error);
-               e_data_book_respond_create_contacts (book, opid, error, NULL);
-               return;
-       }
+       for (i = 0; i < G_N_ELEMENTS (mappings); i++) {
+               element_type = mappings[i].element_type;
+               if (element_type == ELEMENT_TYPE_SIMPLE)  {
+                       value =  e_contact_get (new_contact, mappings[i].field_id);
+                       old_value =  e_contact_get (old_contact, mappings[i].field_id);
+                       if (g_strcmp0 (value, old_value) != 0)
+                               convert_contact_property_to_updatexml (msg, mappings[i].element_name, value, 
"contacts", NULL, NULL);
+                       if (value)
+                               g_free (value);
+                       if (old_value)
+                               g_free (old_value);
+               } else if (element_type == ELEMENT_TYPE_COMPLEX) {
+                       gchar *new_change_key = NULL;
 
-       if (!ebews->priv->is_writable) {
-               e_data_book_respond_create_contacts (book, opid, EDB_ERROR (PERMISSION_DENIED), NULL);
-               return;
-       }
+                       if (mappings[i].field_id == E_CONTACT_UID)
+                               continue;
 
-       contact = e_contact_new_from_vcard (vcards->data);
+                       mappings[i].set_changes (cd->bbews, msg, new_contact, old_contact, &new_change_key, 
cd->cancellable, cd->error);
 
-       if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
-               if (!e_ews_connection_satisfies_server_version (ebews->priv->cnc, E_EWS_EXCHANGE_2010)) {
-                       g_object_unref (contact);
-                       e_data_book_respond_create_contacts (
-                               book,
-                               opid,
-                               EDB_ERROR_EX (
-                                       NOT_SUPPORTED,
-                                       _("Cannot save contact list, it’s only supported on EWS Server 2010 
or later")),
-                               NULL);
-                       return;
+                       if (new_change_key) {
+                               g_free (cd->change_key);
+                               cd->change_key = new_change_key;
+                       }
                }
-               is_dl = TRUE;
        }
 
-       create_contact = g_new0 (EwsCreateContact, 1);
-       create_contact->ebews = g_object_ref (ebews);
-       create_contact->book = g_object_ref (book);
-       create_contact->opid = opid;
-       create_contact->contact = g_object_ref (contact);
-       create_contact->cancellable = g_object_ref (cancellable);
-       create_contact->is_dl = is_dl;
-
-       fid = e_ews_folder_id_new (priv->folder_id, NULL, FALSE);
-
-       /* pass new contact component data to the exchange server and expect response in the callback */
-       e_ews_connection_create_items (
-               priv->cnc,
-               EWS_PRIORITY_MEDIUM, NULL,
-               NULL,
-               fid,
-               is_dl ? convert_dl_to_xml : convert_contact_to_xml,
-               contact,
-               cancellable,
-               ews_create_contact_cb,
-               create_contact);
-
-       e_ews_folder_id_free (fid);
+       e_ews_message_end_item_change (msg);
 }
 
-typedef struct {
-       EBookBackendEws *ebews;
-       EDataBook *book;
-       guint32 opid;
-       GSList *sl_ids;
-       GCancellable *cancellable;
-} EwsRemoveContact;
-
-static void
-ews_book_remove_contact_cb (GObject *object,
-                            GAsyncResult *res,
-                            gpointer user_data)
+static EContact *
+ebb_ews_item_to_contact (EBookBackendEws *bbews,
+                        EEwsItem *item,
+                        GCancellable *cancellable,
+                        GError **error)
 {
-       EwsRemoveContact *remove_contact = user_data;
-       EBookBackendEws *ebews = remove_contact->ebews;
-       EBookBackendEwsPrivate *priv = ebews->priv;
-       GSimpleAsyncResult *simple;
-       GSList *l, *contacts = NULL;
-       GError *error = NULL;
-
-       simple = G_SIMPLE_ASYNC_RESULT (res);
+       EContact *contact;
+       gint ii, element_type;
 
-       g_return_if_fail (priv->summary != NULL);
+       contact = e_contact_new ();
 
-       if (!g_simple_async_result_propagate_error (simple, &error) &&
-           e_book_sqlite_lock (priv->summary, EBSQL_LOCK_WRITE, remove_contact->cancellable, &error)) {
-               /* Wtf? Do we really have to fetch deleted contacts in full, just to tell the cursors? */
-               for (l = remove_contact->sl_ids; l != NULL; l = g_slist_next (l)) {
-                       EContact *contact = NULL;
-                       e_book_sqlite_get_contact (priv->summary, l->data, FALSE, &contact, NULL);
-                       if (contact)
-                               contacts = g_slist_prepend (contacts, contact);
-               }
-               if (e_book_sqlite_remove_contacts (priv->summary, remove_contact->sl_ids, 
remove_contact->cancellable, &error) &&
-                   ebews_bump_revision (ebews, &error))
-                       e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_COMMIT, &error);
-               else
-                       e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_ROLLBACK, NULL);
-       }
+       for (ii = 0; ii < G_N_ELEMENTS (mappings); ii++) {
+               element_type = mappings[ii].element_type;
 
-       if (error == NULL) {
-               e_data_book_respond_remove_contacts (remove_contact->book, remove_contact->opid, EDB_ERROR 
(SUCCESS),  remove_contact->sl_ids);
-               for (l = contacts; l != NULL; l = g_slist_next (l))
-                       cursors_contact_removed (ebews, E_CONTACT (l->data));
-       } else {
-               e_data_book_respond_remove_contacts (remove_contact->book, remove_contact->opid, EDB_ERROR_EX 
(OTHER_ERROR, error->message), NULL);
+               if (element_type == ELEMENT_TYPE_SIMPLE && !mappings[ii].populate_contact_func) {
+                       const gchar *val = mappings[ii].get_simple_prop_func (item);
 
-               g_warning ("\nError removing contact %s \n", error->message);
+                       if (val != NULL)
+                               e_contact_set (contact, mappings[ii].field_id, val);
+               } else {
+                       mappings[ii].populate_contact_func (bbews, contact, item, cancellable, error);
+               }
        }
 
-       g_slist_free_full (contacts, g_object_unref);
-       g_slist_free_full (remove_contact->sl_ids, g_free);
-       g_object_unref (remove_contact->ebews);
-       g_object_unref (remove_contact->book);
-       g_object_unref (remove_contact->cancellable);
-       g_free (remove_contact);
-       g_clear_error (&error);
+       return contact;
 }
 
 static void
-e_book_backend_ews_remove_contacts (EBookBackend *backend,
-                                    EDataBook *book,
-                                    guint32 opid,
-                                    GCancellable *cancellable,
-                                    const GSList *id_list)
+ebb_ews_items_to_contacts (EBookBackendEws *bbews,
+                          const GSList *new_items,
+                          GSList **contacts,
+                          GCancellable *cancellable,
+                          GError **error)
 {
-       EBookBackendEws *ebews;
-       EwsRemoveContact *remove_contact;
-       EBookBackendEwsPrivate *priv;
-       GSList *l, *copy = NULL;
-       GError *error = NULL;
+       GSList *link;
 
-       ebews = E_BOOK_BACKEND_EWS (backend);
-
-       priv = ebews->priv;
+       for (link = (GSList *) new_items; link; link = g_slist_next (link)) {
+               EContact *contact;
+               EEwsItem *item = link->data;
+               EVCardAttribute *attr;
 
-       if (!e_backend_get_online (E_BACKEND (backend)) || !ebews->priv->cnc) {
-               if (!priv->is_writable) {
-                       e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (PERMISSION_DENIED), NULL);
-                       return;
-               }
+               if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR)
+                       continue;
 
-               e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
-               return;
-       }
+               contact = ebb_ews_item_to_contact (bbews, item, cancellable, error);
 
-       if (!book_backend_ews_ensure_connected (ebews, cancellable, &error)) {
-               convert_error_to_edb_error (&error);
-               e_data_book_respond_remove_contacts (book, opid, error, NULL);
-               return;
-       }
+               attr = e_vcard_attribute_new (NULL, "X-EWS-KIND");
+               e_vcard_add_attribute_with_value (E_VCARD (contact), attr, "DT_MAILUSER");
 
-       if (!ebews->priv->is_writable) {
-               e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (PERMISSION_DENIED), NULL);
-               return;
+               *contacts = g_slist_prepend (*contacts, contact);
        }
-
-       for (l = (GSList *) id_list; l != NULL; l = g_slist_next (l))
-               copy = g_slist_prepend (copy, g_strdup ((gchar *) l->data));
-       copy = g_slist_reverse (copy);
-
-       remove_contact = g_new0 (EwsRemoveContact, 1);
-       remove_contact->ebews = g_object_ref (ebews);
-       remove_contact->book = g_object_ref (book);
-       remove_contact->opid = opid;
-       remove_contact->sl_ids = copy;
-       remove_contact->cancellable = g_object_ref(cancellable);
-
-       e_ews_connection_delete_items (
-               priv->cnc, EWS_PRIORITY_MEDIUM, (GSList *) id_list,
-               EWS_HARD_DELETE, 0 , FALSE,
-               cancellable,
-               ews_book_remove_contact_cb,
-               remove_contact);
 }
 
-typedef struct {
-       EBookBackendEws *ebews;
-       EDataBook *book;
-       EContact *new_contact;
-       EContact *old_contact;
-       guint32 opid;
-       GCancellable *cancellable;
-} EwsModifyContact;
-
-static void
-ews_modify_contact_cb (GObject *object,
-                       GAsyncResult *res,
-                       gpointer user_data)
+static gboolean
+ebb_ews_traverse_dl (EBookBackendEws *bbews,
+                    EContact **contact,
+                    GHashTable *items,
+                    GHashTable *values,
+                    EwsMailbox *mb,
+                    GCancellable *cancellable,
+                    GError **error)
 {
-       EEwsConnection *cnc = E_EWS_CONNECTION (object);
-       EwsModifyContact *modify_contact = user_data;
-       EBookBackendEws *ebews = modify_contact->ebews;
-       EBookBackendEwsPrivate *priv = ebews->priv;
-       GError *error = NULL;
-       GSList *items = NULL;
-       gchar *id;
-       const EwsId *item_id;
+       if (g_strcmp0 (mb->mailbox_type, "PrivateDL") == 0 ||
+           g_strcmp0 (mb->mailbox_type, "PublicDL") == 0) {
+               GSList *members = NULL, *l;
+               gboolean includes_last;
+               gboolean ret = FALSE;
+               const gchar *ident;
 
-       g_object_ref (modify_contact->new_contact);
-       g_object_ref (modify_contact->old_contact);
+               if (mb->item_id && mb->item_id->id)
+                       ident = mb->item_id->id;
+               else if (mb->email)
+                       ident = mb->email;
+               else
+                       return FALSE;
 
-       e_ews_connection_update_items_finish (cnc, res, &items, &error);
+               if (g_hash_table_lookup (items, ident) != NULL)
+                       return TRUE;
 
-       g_return_if_fail (priv->summary != NULL);
+               g_hash_table_insert (items, g_strdup (ident), GINT_TO_POINTER (1));
 
-       if (error == NULL) {
-               if (items != NULL) {
-                       EEwsItem *item = (EEwsItem *) items->data;
+               if (!e_ews_connection_expand_dl_sync (
+                       bbews->priv->cnc,
+                       EWS_PRIORITY_MEDIUM,
+                       mb,
+                       &members,
+                       &includes_last,
+                       cancellable,
+                       error))
+                       return FALSE;
 
-                       /* set item id */
-                       item_id = e_ews_item_get_id (item);
+               for (l = members; l; l = l->next) {
+                       ret = ebb_ews_traverse_dl (bbews, contact, items, values, l->data, cancellable, 
error);
+                       if (!ret)
+                               break;
+               }
 
-                       e_contact_set (modify_contact->new_contact, E_CONTACT_UID, item_id->id);
-                       e_contact_set (modify_contact->new_contact, E_CONTACT_REV, item_id->change_key);
+               g_slist_free_full (members, (GDestroyNotify) e_ews_mailbox_free);
+               return ret;
+       } else {
+               EVCardAttribute *attr;
+               CamelInternetAddress *addr;
+               gchar *value = NULL;
 
-                       g_object_unref (item);
-               }
+               if (mb->name == NULL && mb->email == NULL)
+                       return TRUE;
 
-               id = e_contact_get (modify_contact->old_contact, E_CONTACT_UID);
+               addr = camel_internet_address_new ();
+               attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
 
-               if (e_book_sqlite_lock (ebews->priv->summary, EBSQL_LOCK_WRITE, modify_contact->cancellable, 
&error)) {
-                       if (e_book_sqlite_remove_contact (ebews->priv->summary, id, 
modify_contact->cancellable, &error) &&
-                           e_book_sqlite_add_contact (ebews->priv->summary, modify_contact->new_contact, 
NULL,
-                                                      TRUE, modify_contact->cancellable, &error) &&
-                           ebews_bump_revision (ebews, &error))
-                               e_book_sqlite_unlock (ebews->priv->summary, EBSQL_UNLOCK_COMMIT, &error);
-                       else
-                               e_book_sqlite_unlock (ebews->priv->summary, EBSQL_UNLOCK_ROLLBACK, NULL);
-               }
+               camel_internet_address_add (addr, mb->name, mb->email ? mb->email : "");
+               value = camel_address_encode (CAMEL_ADDRESS (addr));
 
-               if (error == NULL) {
-                       GSList *new_contacts;
+               if (value && g_hash_table_lookup (values, value) == NULL) {
+                       e_vcard_attribute_add_value (attr, value);
+                       e_vcard_append_attribute (E_VCARD (*contact), attr);
 
-                       new_contacts = g_slist_append (NULL, modify_contact->new_contact);
-                       e_data_book_respond_modify_contacts (modify_contact->book, modify_contact->opid, 
EDB_ERROR (SUCCESS), new_contacts);
-                       g_slist_free (new_contacts);
-                       cursors_contact_removed (ebews, modify_contact->old_contact);
-                       cursors_contact_added (ebews, modify_contact->new_contact);
+                       g_hash_table_insert (values, g_strdup (value), GINT_TO_POINTER (1));
                }
 
-               g_slist_free (items);
-       }
-
-       if (error) {
-               g_warning ("Error while Modifying contact: %s", error->message);
+               g_object_unref (addr);
 
-               e_data_book_respond_modify_contacts (modify_contact->book, modify_contact->opid, EDB_ERROR_EX 
(OTHER_ERROR, error->message), NULL);
+               return TRUE;
        }
-
-       /* free memory allocated for create_contact & unref contained objects */
-       g_object_unref (modify_contact->ebews);
-       g_object_unref (modify_contact->new_contact);
-       g_object_unref (modify_contact->old_contact);
-       g_object_unref (modify_contact->cancellable);
-       g_free (modify_contact);
-       g_clear_error (&error);
 }
 
-static void
-convert_dl_to_updatexml (ESoapMessage *msg,
-                        gpointer user_data)
-{
-       EwsModifyContact *modify_contact = user_data;
-       EwsId *id;
-       EContact *old_contact = modify_contact->old_contact;
-       EContact *new_contact = modify_contact->new_contact;
-
-       id = g_new0 (EwsId, 1);
-       id->id = e_contact_get (old_contact, E_CONTACT_UID);
-       id->change_key = e_contact_get (old_contact, E_CONTACT_REV);
-
-       e_ews_message_start_item_change (msg, E_EWS_ITEMCHANGE_TYPE_ITEM, id->id, id->change_key, 0);
-       e_ews_message_start_set_item_field (msg, "Members", "distributionlist", "DistributionList");
-       ews_write_dl_members (msg, new_contact);
-       e_ews_message_end_set_item_field (msg);
-       e_ews_message_end_item_change (msg);
-}
-
-static void
-convert_contact_to_updatexml (ESoapMessage *msg,
-                              gpointer user_data)
+static EContact *
+ebb_ews_get_dl_info (EBookBackendEws *bbews,
+                    const EwsId *id,
+                    const gchar *d_name,
+                    GSList *members,
+                    GCancellable *cancellable,
+                    GError **error)
 {
-       EwsModifyContact *modify_contact = user_data;
-       EwsId *id;
-       EContact *old_contact = modify_contact->old_contact;
-       EContact *new_contact = modify_contact->new_contact;
-       gchar *value = NULL, *old_value = NULL;
-       gint i, element_type;
-       GError *error = NULL;
+       GHashTable *items, *values;
+       GSList *l;
+       EContact *contact;
 
-       id = g_new0 (EwsId, 1);
-       id->id = e_contact_get (old_contact, E_CONTACT_UID);
-       id->change_key = e_contact_get (old_contact, E_CONTACT_REV);
+       contact = e_contact_new ();
+       e_contact_set (contact, E_CONTACT_UID, id->id);
+       e_contact_set (contact, E_CONTACT_REV, id->change_key);
 
-       e_ews_message_start_item_change (
-               msg, E_EWS_ITEMCHANGE_TYPE_ITEM,
-               id->id, id->change_key, 0);
+       e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
+       e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
+       e_contact_set (contact, E_CONTACT_FULL_NAME, d_name);
 
-       /*Iterate for each field in contact*/
+       items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
-       for (i = 0; i < G_N_ELEMENTS (mappings); i++) {
-               element_type = mappings[i].element_type;
-               if (element_type == ELEMENT_TYPE_SIMPLE)  {
-                       value =  e_contact_get (new_contact, mappings[i].field_id);
-                       old_value =  e_contact_get (old_contact, mappings[i].field_id);
-                       if (g_strcmp0 (value, old_value) != 0)
-                               convert_contact_property_to_updatexml (msg, mappings[i].element_name, value, 
"contacts", NULL, NULL);
-                       if (value)
-                               g_free (value);
-                       if (old_value)
-                               g_free (old_value);
-               } else if (element_type == ELEMENT_TYPE_COMPLEX) {
-                       if (mappings[i].field_id == E_CONTACT_UID)
-                               continue;
-                       mappings[i].set_changes (
-                                       modify_contact->ebews, msg,
-                                       new_contact, old_contact,
-                                       modify_contact->cancellable,
-                                       &error);
-
-                       if (error != NULL) {
-                               e_data_book_respond_modify_contacts (
-                                               modify_contact->book,
-                                               modify_contact->opid,
-                                               EDB_ERROR_EX (OTHER_ERROR, error->message),
-                                               NULL);
-                               g_clear_error (&error);
-                       }
+       for (l = members; l != NULL; l = l->next) {
+               if (!ebb_ews_traverse_dl (bbews, &contact, items, values, l->data, cancellable, error)) {
+                       g_object_unref (contact);
+                       contact = NULL;
+                       goto exit;
                }
        }
 
-       e_ews_message_end_item_change (msg);
+ exit:
+       g_hash_table_destroy (items);
+       g_hash_table_destroy (values);
+
+       return contact;
 }
 
-static void
-e_book_backend_ews_modify_contacts (EBookBackend *backend,
-                                    EDataBook *book,
-                                    guint32 opid,
-                                    GCancellable *cancellable,
-                                    const GSList *vcards)
+static gboolean
+ebb_ews_get_dl_info_gal (EBookBackendEws *bbews,
+                        EContact *contact,
+                        EwsMailbox *mb,
+                        GCancellable *cancellable,
+                        GError **error)
 {
-       EContact *contact = NULL, *old_contact = NULL;
-       EwsModifyContact *modify_contact;
-       EBookBackendEws *ebews;
-       EwsId *id;
-       EBookBackendEwsPrivate *priv;
-       GError *error;
-       gboolean is_dl = FALSE;
-
-       if (vcards->next != NULL) {
-               e_data_book_respond_modify_contacts (book, opid,
-                       EDB_ERROR_EX (
-                       NOT_SUPPORTED,
-                       _("The backend does not support bulk modifications")),
-                       NULL);
-               return;
-       }
-
-       ebews = E_BOOK_BACKEND_EWS (backend);
-       priv = ebews->priv;
-
-       if (!e_backend_get_online (E_BACKEND (backend)) || !ebews->priv->cnc) {
-               if (!priv->is_writable) {
-                       e_data_book_respond_modify_contacts (book, opid, EDB_ERROR (PERMISSION_DENIED), NULL);
-                       return;
-               }
-
-               e_data_book_respond_modify_contacts (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
-               return;
-       }
-
-       if (!book_backend_ews_ensure_connected (ebews, cancellable, &error)) {
-               convert_error_to_edb_error (&error);
-               e_data_book_respond_modify_contacts (book, opid, error, NULL);
-               return;
-       }
-
-       if (!priv->is_writable) {
-               e_data_book_respond_modify_contacts (book, opid, EDB_ERROR (PERMISSION_DENIED), NULL);
-               return;
-       }
-
-       g_return_if_fail (priv->summary != NULL);
-
-       contact = e_contact_new_from_vcard (vcards->data);
-
-       if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
-               if (!e_ews_connection_satisfies_server_version (ebews->priv->cnc, E_EWS_EXCHANGE_2010)) {
-                       g_object_unref (contact);
-                       e_data_book_respond_create_contacts (
-                               book,
-                               opid,
-                               EDB_ERROR_EX (
-                                       NOT_SUPPORTED,
-                                       _("Cannot save contact list, it’s only supported on EWS Server 2010 
or later")),
-                               NULL);
-                       return;
-               }
-               is_dl = TRUE;
-       }
+       GHashTable *items, *values;
+       gboolean success;
 
-       /*get item id and change key from contact and fetch old contact and assign.*/
+       items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
-       id = g_new0 (EwsId, 1);
-       id->id = e_contact_get (contact, E_CONTACT_UID);
-       id->change_key = e_contact_get (contact, E_CONTACT_REV);
+       success = ebb_ews_traverse_dl (bbews, &contact, items, values, mb, cancellable, error);
 
-       if (e_book_sqlite_lock (priv->summary, EBSQL_LOCK_READ, cancellable, &error)) {
-               e_book_sqlite_get_contact (priv->summary, id->id, TRUE, &old_contact, &error);
-               e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_NONE, error ? NULL : &error);
+       if (success) {
+               e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
+               e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
        }
 
-       if (!old_contact) {
-               g_object_unref (contact);
-               g_clear_error (&error); // Shouldn't we be using this? NOT_SUPPORTED seems wrong
-               e_data_book_respond_modify_contacts (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
-               return;
-       }
+       g_hash_table_destroy (items);
+       g_hash_table_destroy (values);
 
-       /* TODO implement */
-       modify_contact = g_new0 (EwsModifyContact, 1);
-       modify_contact->ebews = g_object_ref (ebews);
-       modify_contact->book = g_object_ref (book);
-       modify_contact->opid = opid;
-       modify_contact->old_contact = g_object_ref (old_contact);
-       modify_contact->new_contact = g_object_ref (contact);
-       modify_contact->cancellable = g_object_ref (cancellable);
-
-       e_ews_connection_update_items (
-               priv->cnc,
-               EWS_PRIORITY_MEDIUM,
-               "AlwaysOverwrite",
-               "SendAndSaveCopy",
-               "SendToAllAndSaveCopy",
-               priv->folder_id,
-               is_dl ? convert_dl_to_updatexml : convert_contact_to_updatexml,
-               modify_contact,
-               cancellable,
-               ews_modify_contact_cb,
-               modify_contact);
+       return success;
 }
 
-static void
-e_book_backend_ews_get_contact (EBookBackend *backend,
-                                EDataBook *book,
-                                guint32 opid,
-                                GCancellable *cancellable,
-                                const gchar *id)
+static gboolean
+ebb_ews_contacts_append_dl (EBookBackendEws *bbews,
+                           const EwsId *id,
+                           const gchar *d_name,
+                           GSList *members,
+                           GSList **contacts,
+                           GCancellable *cancellable,
+                           GError **error)
 {
-       EBookBackendEws *ebews;
-       GError *error = NULL;
+       EContact *contact;
+       EVCardAttribute *attr;
 
-       ebews =  E_BOOK_BACKEND_EWS (backend);
+       contact = ebb_ews_get_dl_info (bbews, id, d_name, members, cancellable, error);
+       if (contact == NULL)
+               return FALSE;
 
-       if (!e_backend_get_online (E_BACKEND (backend)) || !ebews->priv->cnc) {
-               e_data_book_respond_get_contact (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
-               return;
-       }
+       attr = e_vcard_attribute_new (NULL, "X-EWS-KIND");
+       e_vcard_add_attribute_with_value (E_VCARD (contact), attr, "DT_DISTLIST");
 
-       if (!book_backend_ews_ensure_connected (ebews, cancellable, &error)) {
-               convert_error_to_edb_error (&error);
-               e_data_book_respond_get_contact (book, opid, error, NULL);
-               return;
-       }
+       *contacts = g_slist_prepend (*contacts, contact);
 
-       e_data_book_respond_get_contact (book, opid, EDB_ERROR (CONTACT_NOT_FOUND), "");
+       return TRUE;
 }
 
-static void
-e_book_backend_ews_get_contact_list (EBookBackend *backend,
-                                     EDataBook *book,
-                                     guint32 opid,
-                                     GCancellable *cancellable,
-                                     const gchar *query)
+static gboolean
+ebb_ews_fetch_items_sync (EBookBackendEws *bbews,
+                         const GSList *items, /* EEwsItem * */
+                         GSList **contacts,
+                         GCancellable *cancellable,
+                         GError **error)
 {
-       GSList *vcard_list = NULL;
-       GSList *list = NULL, *l;
-       GError *error = NULL;
-       EBookBackendEws *ebews;
-       EBookBackendEwsPrivate *priv;
-       gint populated = 0;
-
-       ebews = E_BOOK_BACKEND_EWS (backend);
-       priv = ebews->priv;
-
-       if (priv->summary)
-               e_book_sqlite_get_key_value_int (priv->summary, E_BOOK_SQL_IS_POPULATED_KEY, &populated, 
NULL);
-
-       if (!e_backend_get_online (E_BACKEND (backend)) || !ebews->priv->cnc) {
-               if (populated) {
-               search_db:
-                       if (e_book_sqlite_lock (priv->summary, EBSQL_LOCK_READ, cancellable, &error)) {
-                               e_book_sqlite_search (priv->summary, query, FALSE, &list, cancellable, 
&error);
-
-                               l = list;
-                               while (l) {
-                                       EbSqlSearchData *s_data = (EbSqlSearchData *) l->data;
+       GSList *contact_item_ids = NULL, *dl_ids = NULL, *link;
+       GSList *new_items = NULL;
+       gboolean ret = FALSE;
 
-                                       vcard_list = g_slist_append (vcard_list, g_strdup (s_data->vcard));
-                                       e_book_sqlite_search_data_free (s_data);
-                                       l = l->next;
-                               }
-                               e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_NONE, NULL);
-                       }
-                       convert_error_to_edb_error (&error);
-                       e_data_book_respond_get_contact_list (book, opid, error, vcard_list);
+       for (link = (GSList *) items; link; link = g_slist_next (link)) {
+               EEwsItem *item = link->data;
+               const EwsId *id = e_ews_item_get_id (item);
+               EEwsItemType type = e_ews_item_get_item_type (item);
 
-                       g_slist_free (list);
-                       g_slist_free_full (vcard_list, g_free);
-               } else {
-                       e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE), 
vcard_list);
+               if (type == E_EWS_ITEM_TYPE_CONTACT)
+                       contact_item_ids = g_slist_prepend (contact_item_ids, g_strdup (id->id));
+               else if (type == E_EWS_ITEM_TYPE_GROUP) {
+                       /* store a list of EwsMailBox's in case of distribution lists */
+                       dl_ids = g_slist_prepend (dl_ids, g_strdup (id->id));
                }
-
-               return;
-       }
-
-       if (!book_backend_ews_ensure_connected (ebews, cancellable, &error)) {
-               convert_error_to_edb_error (&error);
-               e_data_book_respond_get_contact_list (book, opid, error, NULL);
-               return;
        }
 
-       if (populated) {
-               goto search_db;
-
-       } else if (!priv->marked_for_offline) {
-               GSList *items = NULL;
-               EwsFolderId *fid = NULL;
-               gboolean includes_last_item;
-               gboolean any_applicable;
-
-               fid = g_new0 (EwsFolderId, 1);
-               fid->id = g_strdup (priv->folder_id);
-               fid->is_distinguished_id = FALSE;
-
-               any_applicable = e_ews_query_check_applicable (query, E_EWS_FOLDER_TYPE_CONTACTS);
-
-               e_ews_connection_find_folder_items_sync (
-                       priv->cnc, EWS_PRIORITY_MEDIUM,
-                       fid, "IdOnly", NULL, NULL, query, NULL,
-                       E_EWS_FOLDER_TYPE_CONTACTS,
-                       &includes_last_item,
-                       &items, any_applicable ? e_ews_query_to_restriction : NULL,
-                       cancellable, &error);
-
-               /*we have got Id for items lets fetch them using getitem operation*/
-               ebews_fetch_items (ebews, items, &list, cancellable, &error);
-
-               while (list) {
-                       gchar *vcard_string;
-
-                       l = list;
-                       list = list->next;
-
-                       vcard_string = e_vcard_to_string (E_VCARD (l->data), EVC_FORMAT_VCARD_30);
-
-                       g_object_unref (l->data);
-                       g_slist_free_1 (l);
+       /* TODO fetch attachments */
+       if (contact_item_ids) {
+               EEwsAdditionalProps *add_props;
+               add_props = e_ews_additional_props_new ();
+               add_props->field_uri = g_strdup (CONTACT_ITEM_PROPS);
 
-                       vcard_list = g_slist_append (vcard_list, vcard_string);
-               }
+               ret = e_ews_connection_get_items_sync (
+                       bbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+                       contact_item_ids, "Default", add_props,
+                       FALSE, NULL, E_EWS_BODY_TYPE_TEXT, &new_items, NULL, NULL,
+                       cancellable, error);
 
-               convert_error_to_edb_error (&error);
-               e_data_book_respond_get_contact_list (book, opid, error, vcard_list);
+               e_ews_additional_props_free (add_props);
 
-               e_ews_folder_id_free (fid);
-               g_slist_free_full (vcard_list, g_free);
-       } else {
-               e_data_book_respond_get_contact_list (book, opid, EDB_ERROR_EX (OTHER_ERROR, _("Wait till 
syncing is done")), vcard_list);
+               if (!ret)
+                       goto cleanup;
        }
-}
 
-typedef struct {
-       /* For future use */
-       gpointer restriction;
-
-       gboolean is_autocompletion;
-       gchar *auto_comp_str;
-} EBookBackendEwsSExpData;
+       if (new_items) {
+               ebb_ews_items_to_contacts (bbews, new_items, contacts, cancellable, error);
 
-static ESExpResult *
-func_not (ESExp *f,
-          gint argc,
-          ESExpResult **argv,
-          gpointer data)
-{
-       ESExpResult *r;
+               g_slist_free_full (new_items, g_object_unref);
+               new_items = NULL;
+       }
 
-       if (argc != 1 || argv[0]->type != ESEXP_RES_UNDEFINED) {
-               e_sexp_fatal_error (f, "parse error");
-               return NULL;
+       /* Get the display names of the distribution lists */
+       if (dl_ids) {
+               if (!e_ews_connection_get_items_sync (bbews->priv->cnc, EWS_PRIORITY_MEDIUM, dl_ids, 
"Default", NULL,
+                       FALSE, NULL, E_EWS_BODY_TYPE_TEXT, &new_items, NULL, NULL, cancellable, error))
+                       goto cleanup;
        }
 
-       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
-       r->value.boolean = FALSE;
+       for (link = new_items; link; link = g_slist_next (link)) {
+               EEwsItem *item = link->data;
+               const gchar *d_name;
+               const EwsId *id;
+               EwsMailbox *mb;
+               GSList *members = NULL;
+               gboolean includes_last;
 
-       return r;
-}
+               if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR)
+                       continue;
 
-static ESExpResult *
-func_and_or (ESExp *f,
-             gint argc,
-             ESExpResult **argv,
-             gpointer and)
-{
-       ESExpResult *r;
+               id = e_ews_item_get_id (item);
+               mb = g_new0 (EwsMailbox, 1);
+               mb->item_id = (EwsId *) id;
 
-       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
-       r->value.boolean = FALSE;
+               d_name = e_ews_item_get_subject (item);
+               if (!e_ews_connection_expand_dl_sync (
+                       bbews->priv->cnc, EWS_PRIORITY_MEDIUM, mb, &members,
+                       &includes_last, cancellable, error))
+                       goto cleanup;
 
-       return r;
-}
+               ret = ebb_ews_contacts_append_dl (bbews, id, d_name, members, contacts, cancellable, error);
 
-/* TODO implement */
-static ESExpResult *
-func_is (struct _ESExp *f,
-         gint argc,
-         struct _ESExpResult **argv,
-         gpointer data)
-{
-       ESExpResult *r;
+               g_free (mb);
+               g_slist_free_full (members, (GDestroyNotify) e_ews_mailbox_free);
 
-       if (argc != 2
-           && argv[0]->type != ESEXP_RES_STRING
-           && argv[1]->type != ESEXP_RES_STRING) {
-               e_sexp_fatal_error (f, "parse error");
-               return NULL;
+               if (!ret)
+                       goto cleanup;
        }
 
-       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
-       r->value.boolean = FALSE;
+ cleanup:
+       g_slist_free_full (new_items, g_object_unref);
+       g_slist_free_full (contact_item_ids, g_free);
+       g_slist_free_full (dl_ids, g_free);
 
-       return r;
+       return ret;
 }
 
-/* TODO implement */
-static ESExpResult *
-func_endswith (struct _ESExp *f,
-               gint argc,
-               struct _ESExpResult **argv,
-               gpointer data)
+static void
+ebb_ews_server_notification_cb (EBookBackendEws *bbews,
+                               const GSList *events,
+                               EEwsConnection *cnc)
 {
-       ESExpResult *r;
-
-       if (argc != 2
-           && argv[0]->type != ESEXP_RES_STRING
-           && argv[1]->type != ESEXP_RES_STRING) {
-               e_sexp_fatal_error (f, "parse error");
-               return NULL;
-       }
+       GSList *link;
+       gboolean update_folder = FALSE;
 
-       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
-       r->value.boolean = FALSE;
+       g_return_if_fail (E_IS_BOOK_BACKEND_EWS (bbews));
 
-       return r;
+       for (link = (GSList *) events; link && !update_folder; link = g_slist_next (link)) {
+               EEwsNotificationEvent *event = link->data;
 
-}
+               switch (event->type) {
+                       case E_EWS_NOTIFICATION_EVENT_CREATED:
+                       case E_EWS_NOTIFICATION_EVENT_DELETED:
+                       case E_EWS_NOTIFICATION_EVENT_MODIFIED:
+                               g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-/* TODO implement */
-static ESExpResult *
-func_contains (struct _ESExp *f,
-               gint argc,
-               struct _ESExpResult **argv,
-               gpointer data)
-{
-       ESExpResult *r;
-       EBookBackendEwsSExpData *sdata = data;
-       const gchar *propname, *str;
+                               if (g_strcmp0 (event->folder_id, bbews->priv->folder_id) == 0)
+                                       update_folder = TRUE;
 
-       if (argc != 2
-           && argv[0]->type != ESEXP_RES_STRING
-           && argv[1]->type != ESEXP_RES_STRING) {
-               e_sexp_fatal_error (f, "parse error");
-               return NULL;
-       }
+                               g_rec_mutex_unlock (&bbews->priv->cnc_lock);
+                               break;
+                       case E_EWS_NOTIFICATION_EVENT_MOVED:
+                       case E_EWS_NOTIFICATION_EVENT_COPIED:
+                               g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-       propname = argv[0]->value.string;
-       str = argv[1]->value.string;
+                               if (g_strcmp0 (event->folder_id, bbews->priv->folder_id) == 0 ||
+                                   g_strcmp0 (event->old_folder_id, bbews->priv->folder_id) == 0)
+                                       update_folder = TRUE;
 
-       if (!strcmp (propname, "full_name") || !strcmp (propname, "email")) {
-               if (!sdata->auto_comp_str) {
-                       sdata->auto_comp_str = g_strdup (str);
-                       sdata->is_autocompletion = TRUE;
+                               g_rec_mutex_unlock (&bbews->priv->cnc_lock);
+                               break;
+                       default:
+                               return;
                }
        }
 
-       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
-       r->value.boolean = FALSE;
-
-       return r;
-
+       if (update_folder)
+               e_book_meta_backend_schedule_refresh (E_BOOK_META_BACKEND (bbews));
 }
 
-/* We are just handling for autocompletion now. We need to support other fields after implementing
- * Restrictions and find_items request */
-static ESExpResult *
-func_beginswith (struct _ESExp *f,
-                 gint argc,
-                 struct _ESExpResult **argv,
-                 gpointer data)
+static void
+ebb_ews_unset_connection (EBookBackendEws *bbews)
 {
-       ESExpResult *r;
-       const gchar *propname, *str;
-       EBookBackendEwsSExpData *sdata = data;
+       g_return_if_fail (E_IS_BOOK_BACKEND_EWS (bbews));
 
-       if (argc != 2 ||
-           argv[0]->type != ESEXP_RES_STRING ||
-           argv[1]->type != ESEXP_RES_STRING) {
-               e_sexp_fatal_error (f, "parse error");
-               return NULL;
-       }
+       g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-       propname = argv[0]->value.string;
-       str = argv[1]->value.string;
+       if (bbews->priv->cnc) {
+               g_signal_handlers_disconnect_by_func (bbews->priv->cnc, ebb_ews_server_notification_cb, 
bbews);
 
-       if (!strcmp (propname, "full_name") || !strcmp (propname, "email")) {
-               if (!sdata->auto_comp_str) {
-                       sdata->auto_comp_str = g_strdup (str);
-                       sdata->is_autocompletion = TRUE;
+               if (bbews->priv->subscription_key != 0) {
+                       e_ews_connection_disable_notifications_sync (
+                               bbews->priv->cnc,
+                               bbews->priv->subscription_key);
+                       bbews->priv->subscription_key = 0;
                }
        }
 
-       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
-       r->value.boolean = FALSE;
-       return r;
+       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
 }
 
-static struct {
-       const gchar *name;
-       ESExpFunc *func;
-       guint flags;
-} symbols[] = {
-       { "and", func_and_or, 0 },
-       { "or", func_and_or, 0},
-       { "not", func_not, 0 },
-       { "contains", func_contains, 0},
-       { "is", func_is, 0},
-       { "beginswith", func_beginswith, 0},
-       { "endswith", func_endswith, 0},
-};
-
-/* FIXME  build a complete filter from the query that can be used by find_items */
-static gpointer
-e_book_backend_ews_build_restriction (const gchar *query,
-                                      gboolean *autocompletion,
-                                      gchar **auto_comp_str)
+static gint
+det_sort_func (gconstpointer _a,
+              gconstpointer _b)
 {
-       ESExpResult *r;
-       ESExp *sexp;
-       EBookBackendEwsSExpData *sdata;
-       gint i;
-
-       sexp = e_sexp_new ();
-       sdata = g_new0 (EBookBackendEwsSExpData, 1);
-       sdata->is_autocompletion = FALSE;
-
-       for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
-               e_sexp_add_function (
-                       sexp, 0, (gchar *) symbols[i].name,
-                       symbols[i].func,
-                       sdata);
-       }
-
-       e_sexp_input_text (sexp, query, strlen (query));
-       e_sexp_parse (sexp);
-
-       r = e_sexp_eval (sexp);
-       if (r) {
-               *autocompletion = sdata->is_autocompletion;
-               *auto_comp_str = sdata->auto_comp_str;
-       }
-
-       e_sexp_result_free (sexp, r);
-       g_object_unref (sexp);
-       g_free (sdata);
+       const EwsOALDetails *a = _a, *b = _b;
 
-       return NULL;
+       return a->seq - b->seq;
 }
 
-/************* GAL sync ***********************/
-
 static gchar *
-ews_download_gal_file (EBookBackendEws *cbews,
-                       EwsOALDetails *full,
-                       GCancellable *cancellable,
-                       GError **error)
+ebb_ews_download_gal_file (EBookBackendEws *bbews,
+                          EwsOALDetails *full,
+                          GCancellable *cancellable,
+                          GError **error)
 {
-       EBookBackendEwsPrivate *priv = cbews->priv;
        EEwsConnection *oab_cnc;
        gchar *full_url, *oab_url;
-       const gchar *cache_dir;
        gchar *download_path = NULL;
        gchar *password;
        CamelEwsSettings *ews_settings;
+       const gchar *cache_dir;
 
-       ews_settings = book_backend_ews_get_collection_settings (cbews);
+       ews_settings = ebb_ews_get_collection_settings (bbews);
 
        /* oab url with oab.xml removed from the suffix */
-       oab_url = g_strndup (priv->oab_url, strlen (priv->oab_url) - 7);
+       oab_url = camel_ews_settings_dup_oaburl (ews_settings);
+       if (!oab_url || !*oab_url) {
+               g_free (oab_url);
+               return NULL;
+       }
+
+       if (g_str_has_suffix (oab_url, "oab.xml"))
+               oab_url [strlen (oab_url) - 7] = '\0';
+
        full_url = g_strconcat (oab_url, full->filename, NULL);
-       cache_dir = e_book_backend_get_cache_dir (E_BOOK_BACKEND (cbews));
+       cache_dir = e_book_backend_get_cache_dir (E_BOOK_BACKEND (bbews));
        download_path = g_build_filename (cache_dir, full->filename, NULL);
 
        oab_cnc = e_ews_connection_new (full_url, ews_settings);
 
        e_binding_bind_property (
-               cbews, "proxy-resolver",
+               bbews, "proxy-resolver",
                oab_cnc, "proxy-resolver",
                G_BINDING_SYNC_CREATE);
 
-       password = e_ews_connection_dup_password (priv->cnc);
+       password = e_ews_connection_dup_password (bbews->priv->cnc);
        e_ews_connection_set_password (oab_cnc, password);
        g_free (password);
 
-       if (!e_ews_connection_download_oal_file_sync (oab_cnc, download_path,
-                                                     NULL, NULL,
-                                                     cancellable, error)) {
+       if (!e_ews_connection_download_oal_file_sync (oab_cnc, download_path, NULL, NULL, cancellable, 
error)) {
                g_free (download_path);
                download_path = NULL;
-               goto exit;
+       } else {
+               d (printf ("OAL file downloaded %s\n", download_path));
        }
 
-       d (g_print ("OAL file downloaded %s\n", download_path);)
-
- exit:
        g_object_unref (oab_cnc);
        g_free (oab_url);
        g_free (full_url);
@@ -2345,69 +1906,76 @@ ews_download_gal_file (EBookBackendEws *cbews,
 }
 
 static gchar *
-ews_download_full_gal (EBookBackendEws *cbews,
-                       EwsOALDetails *full,
-                       GCancellable *cancellable,
-                       GError **error)
+ebb_ews_download_full_gal (EBookBackendEws *bbews,
+                          EwsOALDetails *full,
+                          GCancellable *cancellable,
+                          GError **error)
 {
-       EBookBackendEwsPrivate *priv = cbews->priv;
+       ESource *source;
        const gchar *cache_dir;
        gchar *lzx_path, *oab_file, *oab_path;
 
-       lzx_path = ews_download_gal_file (cbews, full, cancellable, error);
+       lzx_path = ebb_ews_download_gal_file (bbews, full, cancellable, error);
        if (!lzx_path)
                return NULL;
 
-       cache_dir = e_book_backend_get_cache_dir (E_BOOK_BACKEND (cbews));
-       oab_file = g_strdup_printf ("%s-%d.oab", priv->folder_name, full->seq);
+       source = e_backend_get_source (E_BACKEND (bbews));
+       oab_file = g_strdup_printf ("%s-%d.oab", e_source_get_display_name (source), full->seq);
+       cache_dir = e_book_backend_get_cache_dir (E_BOOK_BACKEND (bbews));
        oab_path = g_build_filename (cache_dir, oab_file, NULL);
+
        if (!ews_oab_decompress_full (lzx_path, oab_path, error)) {
                g_free (oab_path);
                oab_path = NULL;
-               goto exit;
+       } else {
+               d (printf ("OAL file decompressed %s\n", oab_path));
        }
 
-       d (g_print ("OAL file decompressed %s \n", oab_path);)
-
-exit:
        if (lzx_path) {
                g_unlink (lzx_path);
                g_free (lzx_path);
        }
+
        g_free (oab_file);
+
        return oab_path;
 }
 
 static gchar *
-ews_download_gal (EBookBackendEws *cbews, EwsOALDetails *full, GSList *deltas, guint32 seq,
-                 GCancellable *cancellable, GError **error)
+ebb_ews_download_gal (EBookBackendEws *bbews,
+                     EBookCache *book_cache,
+                     EwsOALDetails *full,
+                     GSList *deltas,
+                     guint32 seq,
+                     GCancellable *cancellable,
+                     GError **error)
 {
 #ifdef WITH_MSPACK
-       EBookBackendEwsPrivate *priv = cbews->priv;
-       GSList *p;
-       gchar *thisoab = NULL;
-       const gchar *cache_dir;
+       GSList *link;
+       gchar *thisoab;
 
-       cache_dir = e_book_backend_get_cache_dir (E_BOOK_BACKEND (cbews));
-
-       if (!e_book_sqlite_get_key_value (priv->summary, "oab-filename", &thisoab, NULL)
-           || !thisoab)
+       thisoab = e_cache_dup_key (E_CACHE (book_cache), "oab-filename", NULL);
+       if (!thisoab)
                goto full;
 
-       for (p = deltas; p; p = p->next) {
-               EwsOALDetails *det = p->data;
-               GError *local_error = NULL;
+       for (link = deltas; link; link = g_slist_next (link)) {
+               EwsOALDetails *det = link->data;
+               ESource *source;
                gchar *oab_file, *lzx_path, *nextoab;
+               const gchar *cache_dir;
+               GError *local_error = NULL;
 
                seq++;
                if (det->seq != seq)
                        break;
 
-               lzx_path = ews_download_gal_file (cbews, det, cancellable, NULL);
+               lzx_path = ebb_ews_download_gal_file (bbews, det, cancellable, NULL);
                if (!lzx_path)
                        break;
 
-               oab_file = g_strdup_printf ("%s-%d.oab", priv->folder_name, seq);
+               source = e_backend_get_source (E_BACKEND (bbews));
+               oab_file = g_strdup_printf ("%s-%d.oab", e_source_get_display_name (source), seq);
+               cache_dir = e_book_backend_get_cache_dir (E_BOOK_BACKEND (bbews));
                nextoab = g_build_filename (cache_dir, oab_file, NULL);
                g_free (oab_file);
 
@@ -2426,13 +1994,12 @@ ews_download_gal (EBookBackendEws *cbews, EwsOALDetails *full, GSList *deltas, g
                /* For once we are *allowed* to use the error instead of having to
                 * check the return value of the function. It's our *own* error. */
                if (local_error) {
-                       d (g_print ("Failed to apply incremental patch: %s\n",
-                                   local_error->message));
+                       d (printf ("Failed to apply incremental patch: %s\n", local_error->message));
                        g_error_free (local_error);
                        break;
                }
 
-               d (g_print ("Created %s from delta\n", thisoab));
+               d (printf ("Created %s from delta\n", thisoab));
 
                if (seq == full->seq)
                        return thisoab;
@@ -2445,46 +2012,39 @@ ews_download_gal (EBookBackendEws *cbews, EwsOALDetails *full, GSList *deltas, g
  full:
 #endif /* WITH_MSPACK */
        d (printf ("Ewsgal: Downloading full gal \n"));
-       return ews_download_full_gal (cbews, full, cancellable, error);
+       return ebb_ews_download_full_gal (bbews, full, cancellable, error);
 }
 
-static gboolean
-ews_remove_old_gal_file (EBookBackendEws *cbews,
-                         GError **error)
+static void
+ebb_ews_remove_old_gal_file (EBookCache *book_cache)
 {
-       EBookBackendEwsPrivate *priv = cbews->priv;
-       gchar *filename = NULL;
+       gchar *filename;
 
-       if (!priv->summary)
-               return FALSE;
+       g_return_if_fail (E_IS_BOOK_CACHE (book_cache));
 
-       if (!e_book_sqlite_get_key_value (priv->summary, "oab-filename", &filename, error))
-               return FALSE;
+       filename = e_cache_dup_key (E_CACHE (book_cache), "oab-filename", NULL);
 
        if (filename)
                g_unlink (filename);
        g_free (filename);
-
-       return TRUE;
 }
 
 struct _db_data {
        GHashTable *uids;
        GHashTable *sha1s;
-       GSList *contact_collector;
-       GSList *sha1_collector;
-       guint collected_length;
-       EBookBackendEws *cbews;
-       GCancellable *cancellable;
        gint unchanged;
        gint changed;
        gint added;
        gint percent;
+       GSList *created_objects;
+       GSList *modified_objects;
 };
 
 static gboolean
-ews_gal_filter_contact (goffset offset, const gchar *sha1,
-                       gpointer user_data, GError **error)
+ebb_ews_gal_filter_contact (goffset offset,
+                           const gchar *sha1,
+                           gpointer user_data,
+                           GError **error)
 {
        struct _db_data *data = (struct _db_data *) user_data;
        gchar *uid;
@@ -2504,2050 +2064,1298 @@ ews_gal_filter_contact (goffset offset, const gchar *sha1,
 }
 
 static void
-ews_gal_store_contact (EContact *contact,
-                       goffset offset,
-                      const gchar *sha1,
-                       guint percent,
-                       gpointer user_data,
-                       GError **error)
+ebb_ews_gal_store_contact (EContact *contact,
+                          goffset offset,
+                          const gchar *sha1,
+                          guint percent,
+                          gpointer user_data,
+                          GError **error)
 {
        struct _db_data *data = (struct _db_data *) user_data;
-       EBookBackendEwsPrivate *priv = data->cbews->priv;
-
-       g_return_if_fail (priv->summary != NULL);
 
        if (contact) {
                const gchar *uid = e_contact_get_const (contact, E_CONTACT_UID);
-               if (g_hash_table_remove (data->uids, uid))
-                       data->changed++;
-               else
-                       data->added++;
+               EBookMetaBackendInfo *nfo;
 
-               data->contact_collector = g_slist_prepend (data->contact_collector, g_object_ref (contact));
-               data->sha1_collector = g_slist_prepend (data->sha1_collector, g_strdup (sha1));
-               data->collected_length += 1;
-       }
+               e_contact_set (contact, E_CONTACT_REV, sha1);
 
-       if (data->collected_length == 1000 || percent >= 100) {
-               GSList *l;
-
-               data->contact_collector = g_slist_reverse (data->contact_collector);
-               data->sha1_collector = g_slist_reverse (data->sha1_collector);
-               if (e_book_sqlite_lock (priv->summary, EBSQL_LOCK_WRITE, data->cancellable, error)) {
-                       if (e_book_sqlite_add_contacts (priv->summary, data->contact_collector, 
data->sha1_collector,
-                                                   TRUE, data->cancellable, error) &&
-                           ebews_bump_revision (data->cbews, error)) {
-                               if (e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_COMMIT, error)) {
-                                       for (l = data->contact_collector; l != NULL; l = g_slist_next (l)) {
-                                               e_book_backend_notify_update (E_BOOK_BACKEND (data->cbews), 
E_CONTACT (l->data));
-                                               cursors_contact_added (data->cbews, E_CONTACT (l->data));
-                                       }
-                               }
-                       } else
-                               e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_ROLLBACK, NULL);
-               }
+               nfo = e_book_meta_backend_info_new (uid, sha1, NULL, NULL);
+               nfo->object = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
 
-               g_slist_free_full (data->contact_collector, g_object_unref);
-               g_slist_free_full (data->sha1_collector, g_free);
-               data->contact_collector = NULL;
-               data->sha1_collector = NULL;
-               data->collected_length = 0;
+               if (g_hash_table_remove (data->uids, uid)) {
+                       data->changed++;
+                       data->modified_objects = g_slist_prepend (data->modified_objects, nfo);
+               } else {
+                       data->added++;
+                       data->created_objects = g_slist_prepend (data->created_objects, nfo);
+               }
        }
 
        if (data->percent != percent) {
-               gchar *status_message = NULL;
-               GList *list, *link;
-
                data->percent = percent;
 
-               d (g_print ("GAL processing contacts, %d%% complete (%d added, %d changed, %d unchanged\n",
-                           percent, data->added, data->changed, data->unchanged);)
-
-               status_message = g_strdup_printf (_("Processing contacts in %s %d%% completed... "),
-                                                 priv->folder_name, percent);
-               list = e_book_backend_list_views (E_BOOK_BACKEND (data->cbews));
-               for (link = list; link != NULL; link = g_list_next (link))
-                       e_data_book_view_notify_progress (E_DATA_BOOK_VIEW (link->data), -1, status_message);
-               g_list_free_full (list, g_object_unref);
-               g_free (status_message);
+               d (printf ("GAL processing contacts, %d%% complete (%d added, %d changed, %d unchanged\n",
+                          percent, data->added, data->changed, data->unchanged));
        }
 }
 
-static gint det_sort_func (gconstpointer _a, gconstpointer _b)
+static gboolean
+ebb_ews_gather_existing_uids_cb (EBookCache *book_cache,
+                                const gchar *uid,
+                                const gchar *revision,
+                                const gchar *object,
+                                const gchar *extra,
+                                EOfflineState offline_state,
+                                gpointer user_data)
 {
-       const EwsOALDetails *a = _a, *b = _b;
+       struct _db_data *data = user_data;
+       gchar *dup_uid, *dup_rev;
 
-       return a->seq - b->seq;
-}
+       g_return_val_if_fail (data != NULL, FALSE);
+       g_return_val_if_fail (data->uids != NULL, FALSE);
+       g_return_val_if_fail (data->sha1s != NULL, FALSE);
 
-static void append_to_list (gpointer key, gpointer val, gpointer user_data)
-{
-       GSList **list = user_data;
+       dup_uid = g_strdup (uid);
+       dup_rev = g_strdup (revision);
+
+       g_hash_table_insert (data->uids, dup_uid, dup_rev);
+       if (dup_rev)
+               g_hash_table_insert (data->sha1s, dup_rev, dup_uid);
 
-       *list = g_slist_prepend (*list, key);
+       return TRUE;
 }
 
 static gboolean
-ews_replace_gal_in_db (EBookBackendEws *cbews,
-                       const gchar *filename,
-                       GCancellable *cancellable,
-                       GError **error)
+ebb_ews_check_gal_changes (EBookBackendEws *bbews,
+                          EBookCache *book_cache,
+                          const gchar *filename,
+                          GSList **out_created_objects, /*EBookMetaBackendInfo * */
+                          GSList **out_modified_objects, /*EBookMetaBackendInfo * */
+                          GSList **out_removed_objects, /*EBookMetaBackendInfo * */
+                          GCancellable *cancellable,
+                          GError **error)
 {
-       EBookBackendEwsPrivate *priv = cbews->priv;
        EwsOabDecoder *eod;
-       gboolean ret = TRUE;
-       gint populated = 0;
-       GSList *stale_uids = NULL;
+       gboolean success = TRUE;
        struct _db_data data;
+#if d(1) + 0
        gint64 t1, t2;
+#endif
+       GError *local_error = NULL;
 
-       g_return_val_if_fail (priv->summary != NULL, FALSE);
-
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (bbews), FALSE);
+       g_return_val_if_fail (E_IS_BOOK_CACHE (book_cache), FALSE);
+       g_return_val_if_fail (filename != NULL, FALSE);
+       g_return_val_if_fail (out_created_objects != NULL, FALSE);
+       g_return_val_if_fail (out_modified_objects != NULL, FALSE);
+       g_return_val_if_fail (out_removed_objects != NULL, FALSE);
+
+       data.created_objects = NULL;
+       data.modified_objects = NULL;
        data.unchanged = data.changed = data.added = 0;
        data.percent = 0;
        data.uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
        data.sha1s = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
-       t1 = g_get_monotonic_time ();
-
-       e_book_sqlite_get_key_value_int (priv->summary, E_BOOK_SQL_IS_POPULATED_KEY, &populated, NULL);
-       if (populated) {
-               GSList *slist = NULL, *l;
-               if (e_book_sqlite_lock (priv->summary, EBSQL_LOCK_READ, cancellable, NULL)) {
-                       e_book_sqlite_search (priv->summary, NULL, TRUE, &slist, cancellable, NULL);
-                       e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_NONE, NULL);
-               }
+       d (t1 = g_get_monotonic_time ());
 
-               while (slist) {
-                       EbSqlSearchData *search_data = slist->data;
+       e_book_cache_search_with_callback (book_cache, NULL, ebb_ews_gather_existing_uids_cb, &data, 
cancellable, NULL);
 
-                       l = slist;
-                       slist = slist->next;
-                       g_slist_free_1 (l);
+       eod = ews_oab_decoder_new (filename, bbews->priv->attachments_dir, &local_error);
+       if (!local_error) {
+               GHashTableIter iter;
+               gpointer key;
 
-                       g_hash_table_insert (data.uids, search_data->uid, search_data->extra);
-                       if (search_data->extra)
-                               g_hash_table_insert (data.sha1s, search_data->extra, search_data->uid);
+               success = ews_oab_decoder_decode (eod, ebb_ews_gal_filter_contact, ebb_ews_gal_store_contact, 
&data, cancellable, &local_error);
 
-                       /* We steal these */
-                       search_data->extra = search_data->uid = NULL;
-                       e_book_sqlite_search_data_free (search_data);
-               }
-       }
+               if (success) {
+                       *out_created_objects = data.created_objects;
+                       *out_modified_objects = data.modified_objects;
+                       *out_removed_objects = NULL;
 
-       eod = ews_oab_decoder_new (filename, priv->attachment_dir, error);
-       if (*error)
-               return FALSE;
+                       g_hash_table_iter_init (&iter, data.uids);
+                       while (g_hash_table_iter_next (&iter, &key, NULL)) {
+                               const gchar *uid = key;
 
-       data.contact_collector = NULL;
-       data.sha1_collector = NULL;
-       data.collected_length = 0;
-       data.cbews = cbews;
-       data.cancellable = cancellable;
-
-       ret = ews_oab_decoder_decode (eod, ews_gal_filter_contact, ews_gal_store_contact, &data, cancellable, 
error);
-       /* Flush final entries if there are any */
-       if (data.contact_collector)
-               ews_gal_store_contact (NULL, 0, NULL, 100, &data, error);
-
-       /* Remove any items which were not present in the new OAB */
-       g_hash_table_foreach (data.uids, append_to_list, &stale_uids);
-       d (g_print ("GAL removing %d contacts\n", g_slist_length (stale_uids)));
-
-       /* Remove attachments. This will be easier once we add cursor support. */
-       // XXX: Tell cursors
-       if (!e_book_sqlite_lock (priv->summary, EBSQL_LOCK_WRITE, cancellable, error))
-               ret = FALSE;
-       else {
-               GSList *contacts = NULL, *l;
-               /* Wtf? Do we really have to fetch deleted contacts in full, just to tell the cursors? */
-               for (l = stale_uids; l != NULL; l = g_slist_next (l)) {
-                       EContact *contact = NULL;
-                       e_book_sqlite_get_contact (priv->summary, l->data, FALSE, &contact, NULL);
-                       if (contact)
-                               contacts = g_slist_prepend (contacts, contact);
-               }
-               if ((stale_uids && !e_book_sqlite_remove_contacts (priv->summary, stale_uids, cancellable, 
error)) ||
-                   !ebews_bump_revision (cbews, error) ||
-                   !e_book_sqlite_set_key_value_int (priv->summary, E_BOOK_SQL_IS_POPULATED_KEY, TRUE, 
error)) {
-                       ret = FALSE;
-                       e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_ROLLBACK, NULL);
+                               *out_removed_objects = g_slist_prepend (*out_removed_objects,
+                                       e_book_meta_backend_info_new (uid, NULL, NULL, NULL));
+                       }
                } else {
-                       ret = e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_COMMIT, error);
-                       if (ret)
-                               for (l = contacts; l != NULL; l = g_slist_next (l))
-                                       cursors_contact_removed (cbews, E_CONTACT (l->data));
+                       g_slist_free_full (data.created_objects, e_book_meta_backend_info_free);
+                       g_slist_free_full (data.modified_objects, e_book_meta_backend_info_free);
                }
-               g_slist_free_full (contacts, g_object_unref);
+       } else {
+               success = FALSE;
        }
 
-       t2 = g_get_monotonic_time ();
-       d (g_print("GAL update completed %ssuccessfully in %" G_GINT64_FORMAT " µs. Added: %d, Changed: %d, 
Unchanged %d, Removed: %d\n",
-                  ret ? "" : "un", (gint64) (t2 - t1),
-                  data.added, data.changed, data.unchanged, g_slist_length(stale_uids)));
+       d (t2 = g_get_monotonic_time ());
+       d (printf ("GAL update completed %ssuccessfully in %" G_GINT64_FORMAT " µs. Added: %d, Changed: %d, 
Unchanged %d, Removed: %d (%s)\n",
+                  success ? "" : "un", (gint64) (t2 - t1), data.added, data.changed, data.unchanged, 
g_hash_table_size (data.uids),
+                  local_error ? local_error->message : "no error"));
 
-       g_slist_free (stale_uids);
        g_hash_table_destroy (data.sha1s);
        g_hash_table_destroy (data.uids);
-       /* always notify views as complete, to not left anything behind,
-          if the decode was cancelled before full completion */
-       e_book_backend_notify_complete (E_BOOK_BACKEND (cbews));
-
-       return ret;
-}
-
-static gboolean
-ebews_start_gal_sync (gpointer data)
-{
-       EBookBackendEws *cbews;
-       EBookBackendEwsPrivate *priv;
-       EwsOALDetails *full = NULL;
-       GError *error = NULL;
-       EEwsConnection *oab_cnc;
-       GSList *full_l = NULL;
-       GSList *deltas = NULL;
-       gboolean ret = TRUE;
-       gint is_populated = 0;
-       gchar *uncompressed_filename = NULL;
-       gchar *password;
-       gchar *old_etag = NULL, *etag = NULL;
-       gchar *seq;
-       guint32 old_seq = 0;
-       guint32 delta_size = 0;
-       CamelEwsSettings *ews_settings;
-       GCancellable *cancellable;
-
-       cbews = (EBookBackendEws *) data;
-       ews_settings = book_backend_ews_get_collection_settings (cbews);
-       priv = cbews->priv;
-
-       g_return_val_if_fail (priv->summary != NULL, FALSE);
-
-       cancellable = g_object_ref (priv->cancellable);
-
-       oab_cnc = e_ews_connection_new (priv->oab_url, ews_settings);
-
-       e_binding_bind_property (
-               cbews, "proxy-resolver",
-               oab_cnc, "proxy-resolver",
-               G_BINDING_SYNC_CREATE);
-
-       password = e_ews_connection_dup_password (priv->cnc);
-       e_ews_connection_set_password (oab_cnc, password);
-       g_free (password);
-
-       d (printf ("Ewsgal: Fetching oal full details file \n");)
-
-       e_book_sqlite_get_key_value_int (priv->summary, E_BOOK_SQL_IS_POPULATED_KEY, &is_populated, NULL);
-       if (is_populated) {
-               gchar *tmp = NULL;
-               e_book_sqlite_get_key_value (
-                       priv->summary, "etag", &old_etag, NULL);
-               e_book_sqlite_get_key_value (
-                       priv->summary, "seq", &tmp, NULL);
-               if (tmp)
-                       old_seq = strtoul(tmp, NULL, 10);
-               else
-                       is_populated = FALSE;
-               g_free (tmp);
-       }
-
-       if (!e_ews_connection_get_oal_detail_sync (
-               oab_cnc, priv->folder_id, NULL, old_etag, &full_l, &etag,
-               cancellable, &error)) {
-               if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_MODIFIED)) {
-                       g_clear_error (&error);
-               } else {
-                       ret = FALSE;
-               }
-               goto exit;
-       }
-
-       g_warn_if_fail (priv->summary != NULL);
-       if (!priv->summary)
-               goto exit;
-
-       if (full_l == NULL)
-               goto exit;
 
-       while (full_l) {
-               EwsOALDetails *det = full_l->data;
-
-               /* Throw away anything older than we already have */
-               if (det->seq <= old_seq) {
-                       ews_oal_details_free (det);
-               } else if (!strcmp (det->type, "Full")) {
-                       if (full)
-                               ews_oal_details_free (full);
-                       full = det;
-               } else if (is_populated && !strcmp (det->type, "Diff")) {
-                       delta_size += det->size;
-                       deltas = g_slist_insert_sorted (deltas, det, det_sort_func);
-               } else {
-                       ews_oal_details_free (det);
-               }
-               full_l = g_slist_remove (full_l, det);
-       }
-
-       if (!full)
-               goto exit;
-
-       /* If the deltas would be bigger, just download the new full file */
-       if (delta_size > full->size) {
-               g_slist_free_full (deltas, (GDestroyNotify) ews_oal_details_free);
-               deltas = NULL;
-       }
-
-       uncompressed_filename = ews_download_gal (cbews, full, deltas, old_seq, cancellable, &error);
-       if (!uncompressed_filename) {
-               ret = FALSE;
-               goto exit;
-       }
-
-       d (printf ("Ewsgal: Removing old gal \n");)
-       /* remove old_gal_file */
-       ews_remove_old_gal_file (cbews, &error);
-
-       d (printf ("Ewsgal: Replacing old gal with new gal contents in db \n");)
-       ret = ews_replace_gal_in_db (cbews, uncompressed_filename, cancellable, &error);
-       if (!ret)
-               goto exit;
-
-       ret = e_book_sqlite_set_key_value (priv->summary, "etag", etag ? etag : "", NULL);
-       if (!ret)
-               goto exit;
-
-       if (e_book_sqlite_set_key_value (priv->summary, "oab-filename",
-                                        uncompressed_filename, NULL)) {
-               /* Don't let it get deleted */
-               g_free (uncompressed_filename);
-               uncompressed_filename = NULL;
-       }
-
-       seq = g_strdup_printf ("%"G_GUINT32_FORMAT, full->seq);
-       ret = e_book_sqlite_set_key_value (priv->summary, "seq", seq, &error);
-       g_free (seq);
-
-       if (!ret) {
-               gchar *db_filename = g_build_filename (
-                                                      e_book_backend_get_cache_dir (E_BOOK_BACKEND (cbews)),
-                                                      "contacts.dn", NULL);
-               g_object_unref (priv->summary);
-               priv->summary = NULL;
-               g_unlink (db_filename);
-               g_free (db_filename);
-               goto exit;
-       }
+       if (local_error)
+               g_propagate_error (error, local_error);
 
-       d (printf ("Ews gal: sync successful complete \n");)
+       return success;
+}
 
-exit:
-       g_clear_object (&cancellable);
+typedef struct {
+       /* For future use */
+       gpointer restriction;
 
-       if (error) {
-               g_warning ("Unable to update gal : %s \n", error->message);
-               g_clear_error (&error);
-       }
+       gboolean is_autocompletion;
+       gchar *auto_comp_str;
+} EBookBackendEwsSExpData;
 
-       g_free (old_etag);
-       g_free (etag);
+static ESExpResult *
+ebb_ews_func_not (ESExp *f,
+                 gint argc,
+                 ESExpResult **argv,
+                 gpointer data)
+{
+       ESExpResult *r;
 
-       /* preserve  the oab file once we are able to decode the differential updates */
-       if (uncompressed_filename) {
-               g_unlink (uncompressed_filename);
-               g_free (uncompressed_filename);
+       if (argc != 1 || argv[0]->type != ESEXP_RES_UNDEFINED) {
+               e_sexp_fatal_error (f, "parse error");
+               return NULL;
        }
 
-       if (full)
-               ews_oal_details_free (full);
-       if (deltas)
-               g_slist_free_full (deltas, (GDestroyNotify) ews_oal_details_free);
-       if (full_l)
-               g_slist_free_full (full_l, (GDestroyNotify) ews_oal_details_free);
+       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+       r->value.boolean = FALSE;
 
-       g_object_unref (oab_cnc);
-       return ret;
+       return r;
 }
 
-/********** GAL sync **************************/
-
-
-static EContact *
-ebews_get_contact_info (EBookBackendEws *ebews,
-                       EEwsItem *item,
-                       GCancellable *cancellable,
-                       GError **error)
+static ESExpResult *
+ebb_ews_func_and_or (ESExp *f,
+                    gint argc,
+                    ESExpResult **argv,
+                    gpointer and)
 {
-       EContact *contact;
-       gint i, element_type;
+       ESExpResult *r;
 
-       contact = e_contact_new ();
+       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+       r->value.boolean = FALSE;
 
-       for (i = 0; i < G_N_ELEMENTS (mappings); i++) {
-               element_type = mappings[i].element_type;
+       return r;
+}
 
-               if (element_type == ELEMENT_TYPE_SIMPLE && !mappings[i].populate_contact_func) {
-                       const gchar *val = mappings[i].get_simple_prop_func (item);
+/* TODO implement */
+static ESExpResult *
+ebb_ews_func_is (struct _ESExp *f,
+                gint argc,
+                struct _ESExpResult **argv,
+                gpointer data)
+{
+       ESExpResult *r;
 
-                       if (val != NULL)
-                               e_contact_set (contact, mappings[i].field_id, val);
-               } else {
-                       mappings[i].populate_contact_func (ebews, contact, item, cancellable, error);
-               }
+       if (argc != 2
+           && argv[0]->type != ESEXP_RES_STRING
+           && argv[1]->type != ESEXP_RES_STRING) {
+               e_sexp_fatal_error (f, "parse error");
+               return NULL;
        }
 
-       return contact;
+       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+       r->value.boolean = FALSE;
+
+       return r;
 }
 
-static void
-ebews_get_contacts_list (EBookBackendEws *ebews, GSList *new_items,
-                        GSList **contacts, GCancellable *cancellable,
-                        GError **error)
+/* TODO implement */
+static ESExpResult *
+ebb_ews_func_endswith (struct _ESExp *f,
+                      gint argc,
+                      struct _ESExpResult **argv,
+                      gpointer data)
 {
-       GSList *l;
-
-       for (l = new_items; l != NULL; l = g_slist_next (l)) {
-               EContact *contact;
-               EEwsItem *item = l->data;
-               EVCardAttribute *attr;
-
-               if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR) {
-                       g_object_unref (item);
-                       continue;
-               }
+       ESExpResult *r;
 
-               contact = ebews_get_contact_info (ebews, item, cancellable, error);
+       if (argc != 2
+           && argv[0]->type != ESEXP_RES_STRING
+           && argv[1]->type != ESEXP_RES_STRING) {
+               e_sexp_fatal_error (f, "parse error");
+               return NULL;
+       }
 
-               attr = e_vcard_attribute_new (NULL, "X-EWS-KIND");
-               e_vcard_add_attribute_with_value (E_VCARD (contact), attr, "DT_MAILUSER");
+       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+       r->value.boolean = FALSE;
 
-               *contacts = g_slist_prepend (*contacts, contact);
+       return r;
 
-               g_object_unref (item);
-       }
-       g_slist_free (new_items);
 }
 
-static gboolean
-ebews_traverse_dl (EBookBackendEws *ebews,
-                  EContact **contact,
-                  GHashTable *items,
-                  GHashTable *values,
-                  EwsMailbox *mb,
-                  GError **error)
+/* TODO implement */
+static ESExpResult *
+ebb_ews_func_contains (struct _ESExp *f,
+                      gint argc,
+                      struct _ESExpResult **argv,
+                      gpointer data)
 {
-       if (g_strcmp0 (mb->mailbox_type, "PrivateDL") == 0 ||
-           g_strcmp0 (mb->mailbox_type, "PublicDL") == 0) {
-               GSList *members = NULL, *l;
-               gboolean includes_last;
-               gboolean ret = FALSE;
-               const gchar *ident;
-
-               if (mb->item_id && mb->item_id->id)
-                       ident = mb->item_id->id;
-               else if (mb->email)
-                       ident = mb->email;
-               else
-                       return FALSE;
-
-               if (g_hash_table_lookup (items, ident) != NULL)
-                       return TRUE;
+       ESExpResult *r;
+       EBookBackendEwsSExpData *sdata = data;
+       const gchar *propname, *str;
 
-               g_hash_table_insert (items, g_strdup (ident), GINT_TO_POINTER (1));
+       if (argc != 2
+           && argv[0]->type != ESEXP_RES_STRING
+           && argv[1]->type != ESEXP_RES_STRING) {
+               e_sexp_fatal_error (f, "parse error");
+               return NULL;
+       }
 
-               if (!e_ews_connection_expand_dl_sync (
-                       ebews->priv->cnc,
-                       EWS_PRIORITY_MEDIUM,
-                       mb,
-                       &members,
-                       &includes_last,
-                       ebews->priv->cancellable,
-                       error))
-                       return FALSE;
+       propname = argv[0]->value.string;
+       str = argv[1]->value.string;
 
-               for (l = members; l; l = l->next) {
-                       ret = ebews_traverse_dl (ebews, contact, items, values, l->data, error);
-                       if (!ret)
-                               break;
+       if (!strcmp (propname, "full_name") || !strcmp (propname, "email")) {
+               if (!sdata->auto_comp_str) {
+                       sdata->auto_comp_str = g_strdup (str);
+                       sdata->is_autocompletion = TRUE;
                }
+       }
 
-               g_slist_free_full (members, (GDestroyNotify) e_ews_mailbox_free);
-               return ret;
-       } else {
-               EVCardAttribute *attr;
-               CamelInternetAddress *addr;
-               gchar *value = NULL;
-
-               if (mb->name == NULL && mb->email == NULL)
-                       return TRUE;
-
-               addr = camel_internet_address_new ();
-               attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
-
-               camel_internet_address_add (addr, mb->name, mb->email ? mb->email : "");
-               value = camel_address_encode (CAMEL_ADDRESS (addr));
-
-               if (value && g_hash_table_lookup (values, value) == NULL) {
-                       e_vcard_attribute_add_value (attr, value);
-                       e_vcard_append_attribute (E_VCARD (*contact), attr);
-
-                       g_hash_table_insert (values, g_strdup (value), GINT_TO_POINTER (1));
-               }
+       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+       r->value.boolean = FALSE;
 
-               g_object_unref (addr);
+       return r;
 
-               return TRUE;
-       }
 }
 
-static EContact *
-ebews_get_dl_info (EBookBackendEws *ebews,
-                  const EwsId *id,
-                  const gchar *d_name,
-                  GSList *members,
-                  GError **error)
+/* We are just handling for autocompletion now. We need to support other fields after implementing
+ * Restrictions and find_items request */
+static ESExpResult *
+ebb_ews_func_beginswith (struct _ESExp *f,
+                        gint argc,
+                        struct _ESExpResult **argv,
+                        gpointer data)
 {
-       GHashTable *items, *values;
-       GSList *l;
-       EContact *contact;
-
-       contact = e_contact_new ();
-       e_contact_set (contact, E_CONTACT_UID, id->id);
-       e_contact_set (contact, E_CONTACT_REV, id->change_key);
+       ESExpResult *r;
+       const gchar *propname, *str;
+       EBookBackendEwsSExpData *sdata = data;
 
-       e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
-       e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
-       e_contact_set (contact, E_CONTACT_FULL_NAME, d_name);
+       if (argc != 2 ||
+           argv[0]->type != ESEXP_RES_STRING ||
+           argv[1]->type != ESEXP_RES_STRING) {
+               e_sexp_fatal_error (f, "parse error");
+               return NULL;
+       }
 
-       items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-       values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       propname = argv[0]->value.string;
+       str = argv[1]->value.string;
 
-       for (l = members; l != NULL; l = l->next) {
-               if (!ebews_traverse_dl (ebews, &contact, items, values, l->data, error)) {
-                       g_object_unref (contact);
-                       contact = NULL;
-                       goto exit;
+       if (!strcmp (propname, "full_name") || !strcmp (propname, "email")) {
+               if (!sdata->auto_comp_str) {
+                       sdata->auto_comp_str = g_strdup (str);
+                       sdata->is_autocompletion = TRUE;
                }
        }
 
-exit:
-       g_hash_table_destroy (items);
-       g_hash_table_destroy (values);
-       return contact;
+       r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+       r->value.boolean = FALSE;
+       return r;
 }
 
+static struct {
+       const gchar *name;
+       ESExpFunc *func;
+       guint flags;
+} symbols[] = {
+       { "and", ebb_ews_func_and_or, 0 },
+       { "or", ebb_ews_func_and_or, 0},
+       { "not", ebb_ews_func_not, 0 },
+       { "contains", ebb_ews_func_contains, 0},
+       { "is", ebb_ews_func_is, 0},
+       { "beginswith", ebb_ews_func_beginswith, 0},
+       { "endswith", ebb_ews_func_endswith, 0},
+};
+
+/* FIXME  build a complete filter from the query that can be used by find_items */
 static gboolean
-ebews_get_dl_info_gal (EBookBackendEws *ebews,
-                      EContact *contact,
-                      EwsMailbox *mb,
-                      GError **error)
+ebb_ews_build_restriction (const gchar *query,
+                          gchar **auto_comp_str)
 {
-       GHashTable *items, *values;
-       gboolean success;
+       ESExpResult *r;
+       ESExp *sexp;
+       EBookBackendEwsSExpData *sdata;
+       gboolean autocompletion = FALSE;
+       gint i;
 
-       items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-       values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       *auto_comp_str = NULL;
 
-       success = ebews_traverse_dl (ebews, &contact, items, values, mb, error);
+       sexp = e_sexp_new ();
+       sdata = g_new0 (EBookBackendEwsSExpData, 1);
+       sdata->is_autocompletion = FALSE;
 
-       if (success) {
-               e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
-               e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
+       for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
+               e_sexp_add_function (
+                       sexp, 0, (gchar *) symbols[i].name,
+                       symbols[i].func,
+                       sdata);
        }
 
-       g_hash_table_destroy (items);
-       g_hash_table_destroy (values);
-
-       return success;
-}
-
-static gboolean
-ebews_contacts_append_dl (EBookBackendEws *ebews, const EwsId *id,
-                         const gchar *d_name,GSList *members,
-                         GSList **contacts, GError **error)
-{
-       EContact *contact;
-       EVCardAttribute *attr;
-
-       contact = ebews_get_dl_info (ebews, id, d_name, members, error);
-       if (contact == NULL)
-               return FALSE;
+       e_sexp_input_text (sexp, query, strlen (query));
+       e_sexp_parse (sexp);
 
-       attr = e_vcard_attribute_new (NULL, "X-EWS-KIND");
-       e_vcard_add_attribute_with_value (E_VCARD (contact), attr, "DT_DISTLIST");
+       r = e_sexp_eval (sexp);
+       if (r) {
+               autocompletion = sdata->is_autocompletion;
+               if (autocompletion)
+                       *auto_comp_str = sdata->auto_comp_str;
+               else
+                       g_free (sdata->auto_comp_str);
+       }
 
-       *contacts = g_slist_prepend (*contacts, contact);
+       e_sexp_result_free (sexp, r);
+       g_object_unref (sexp);
+       g_free (sdata);
 
-       return TRUE;
+       return autocompletion && *auto_comp_str;
 }
 
 static gboolean
-ebews_fetch_items (EBookBackendEws *ebews, GSList *items, GSList **contacts,
-                   GCancellable *cancellable, GError **error)
+ebb_ews_update_cache_for_expression (EBookBackendEws *bbews,
+                                    const gchar *expr,
+                                    GCancellable *cancellable,
+                                    GError **error)
 {
-       EBookBackendEwsPrivate *priv;
-       EEwsConnection *cnc;
-       GSList *l;
-       GSList *contact_item_ids = NULL, *dl_ids = NULL;
-       GSList *new_items = NULL;
-       gboolean ret = FALSE;
+       EBookMetaBackend *meta_backend;
+       CamelEwsSettings *ews_settings;
+       gboolean success = TRUE;
 
-       if (!book_backend_ews_ensure_connected (ebews, cancellable, error) || !ebews->priv->cnc) {
-               g_slist_free_full (items, g_object_unref);
-               return ret;
-       }
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (bbews), FALSE);
 
-       priv = ebews->priv;
-       cnc = priv->cnc;
+       /* Resolve names in GAL only for GAL */
+       if (!bbews->priv->is_gal)
+               return TRUE;
 
-       for (l = items; l != NULL; l = g_slist_next (l)) {
-               EEwsItem *item = (EEwsItem *) l->data;
-               const EwsId *id = e_ews_item_get_id (item);
-               EEwsItemType type = e_ews_item_get_item_type (item);
+       ews_settings = ebb_ews_get_collection_settings (bbews);
 
-               if (type == E_EWS_ITEM_TYPE_CONTACT)
-                       contact_item_ids = g_slist_prepend (contact_item_ids, g_strdup (id->id));
-               else if (type == E_EWS_ITEM_TYPE_GROUP) {
-                       /* store a list of EwsMailBox's in case of distribution lists */
-                       dl_ids = g_slist_prepend (dl_ids, g_strdup (id->id));
-               }
+       if (camel_ews_settings_get_oab_offline (ews_settings))
+               return TRUE;
 
-               g_object_unref (item);
-       }
-       g_slist_free (items);
+       meta_backend = E_BOOK_META_BACKEND (bbews);
 
-       /* TODO fetch attachments */
-       if (contact_item_ids) {
-               EEwsAdditionalProps *add_props;
-               add_props = e_ews_additional_props_new ();
-               add_props->field_uri = g_strdup (CONTACT_ITEM_PROPS);
+       g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-               ret = e_ews_connection_get_items_sync (
-                       cnc, EWS_PRIORITY_MEDIUM,
-                       contact_item_ids, "Default", add_props,
-                       FALSE, NULL, E_EWS_BODY_TYPE_TEXT, &new_items, NULL, NULL,
-                       cancellable, error);
+       /* Search only if not searching for everything */
+       if (expr && *expr && g_ascii_strcasecmp (expr, "(contains \"x-evolution-any-field\" \"\")") != 0) {
+               gchar *restriction_expr = NULL;
+               GSList *mailboxes = NULL, *contacts = NULL, *found_infos = NULL;
+               gboolean includes_last_item = TRUE;
 
-               e_ews_additional_props_free (add_props);
+               success = ebb_ews_build_restriction (expr, &restriction_expr) &&
+                       e_book_meta_backend_ensure_connected_sync (meta_backend, cancellable, error) &&
+                       e_ews_connection_resolve_names_sync (bbews->priv->cnc, EWS_PRIORITY_MEDIUM, 
restriction_expr,
+                               EWS_SEARCH_AD, NULL, TRUE, &mailboxes, &contacts, &includes_last_item, 
cancellable, error);
 
-               if (!ret)
-                       goto cleanup;
-       }
+               if (success) {
+                       GSList *mlink, *clink;
 
-       if (new_items)
-               ebews_get_contacts_list (ebews, new_items, contacts, cancellable, error);
-       new_items = NULL;
+                       for (mlink = mailboxes, clink = contacts; mlink; mlink = g_slist_next (mlink), clink 
= g_slist_next (clink)) {
+                               EwsMailbox *mb = mlink->data;
+                               EEwsItem *contact_item = clink ? clink->data : NULL;
+                               EBookMetaBackendInfo *nfo;
+                               EContact *contact = NULL;
+                               const gchar *str;
+                               gchar *fake_rev;
 
-       /* Get the display names of the distribution lists */
-       if (dl_ids)
-               if (!e_ews_connection_get_items_sync (
-                       cnc, EWS_PRIORITY_MEDIUM,
-                       dl_ids, "Default", NULL,
-                       FALSE, NULL, E_EWS_BODY_TYPE_TEXT, &new_items, NULL, NULL,
-                       cancellable, error))
-                       goto cleanup;
+                               if (g_strcmp0 (mb->mailbox_type, "PublicDL") == 0) {
+                                       contact = e_contact_new ();
 
-       for (l = new_items; l != NULL; l = g_slist_next (l)) {
-               EEwsItem *item = (EEwsItem *) l->data;
-               const gchar *d_name;
-               const EwsId *id;
-               EwsMailbox *mb;
-               GSList *members = NULL;
-               gboolean includes_last;
+                                       if (!ebb_ews_get_dl_info_gal (bbews, contact, mb, cancellable, NULL)) 
{
+                                               g_clear_object (&contact);
+                                       }
+                               }
 
-               if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR)
-                       continue;
+                               if (!contact && contact_item && e_ews_item_get_item_type (contact_item) == 
E_EWS_ITEM_TYPE_CONTACT)
+                                       contact = ebb_ews_item_to_contact (bbews, contact_item, cancellable, 
NULL);
 
-               id = e_ews_item_get_id (item);
-               mb = g_new0 (EwsMailbox, 1);
-               mb->item_id = (EwsId *) id;
+                               if (!contact)
+                                       contact = e_contact_new ();
 
-               d_name = e_ews_item_get_subject (item);
-               if (!e_ews_connection_expand_dl_sync (
-                       cnc, EWS_PRIORITY_MEDIUM, mb, &members,
-                       &includes_last, cancellable, error))
-                       goto cleanup;
+                               /* We do not get an id from the server, so just using email_id as uid for now 
*/
+                               e_contact_set (contact, E_CONTACT_UID, mb->email);
 
-               ret = ebews_contacts_append_dl (ebews, id, d_name, members, contacts, error);
+                               /* There is no ChangeKey provided either, thus make up some revision,
+                                  to have the contact always updated in the local cache. */
+                               fake_rev = e_util_generate_uid ();
 
-               g_free (mb);
-               g_slist_free_full (members, (GDestroyNotify) e_ews_mailbox_free);
+                               e_contact_set (contact, E_CONTACT_REV, fake_rev);
 
-               if (!ret)
-                       goto cleanup;
-       }
+                               g_free (fake_rev);
 
-cleanup:
-       g_slist_free_full (new_items, g_object_unref);
-       g_slist_free_full (dl_ids, g_free);
-       g_slist_free_full (contact_item_ids, g_free);
+                               str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
+                               if (!str || !*str)
+                                       e_contact_set (contact, E_CONTACT_FULL_NAME, mb->name);
 
-       return ret;
-}
+                               str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);
+                               if (!str || !*str || (contact_item && e_ews_item_get_item_type (contact_item) 
== E_EWS_ITEM_TYPE_CONTACT)) {
+                                       /* Cleanup first, then re-add only SMTP addresses */
+                                       e_contact_set (contact, E_CONTACT_EMAIL_1, NULL);
+                                       e_contact_set (contact, E_CONTACT_EMAIL_2, NULL);
+                                       e_contact_set (contact, E_CONTACT_EMAIL_3, NULL);
+                                       e_contact_set (contact, E_CONTACT_EMAIL_4, NULL);
+                                       e_contact_set (contact, E_CONTACT_EMAIL, NULL);
 
-static gboolean
-ebews_start_sync (gpointer data)
-{
-       EBookBackendEws *ebews;
-       EBookBackendEwsPrivate *priv;
-       GList *list, *link;
-       gchar *status_message = NULL;
-       GCancellable *cancellable;
-       GError *error = NULL;
+                                       ebews_populate_emails_ex (bbews, contact, contact_item, TRUE);
+                               }
 
-       ebews = (EBookBackendEws *) data;
-       priv = ebews->priv;
+                               str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);
+                               if (!str || !*str) {
+                                       e_contact_set (contact, E_CONTACT_EMAIL_1, mb->email);
+                               } else if (mb->email && (!mb->routing_type || g_ascii_strcasecmp 
(mb->routing_type, "SMTP") == 0)) {
+                                       EContactField fields[3] = { E_CONTACT_EMAIL_2, E_CONTACT_EMAIL_3, 
E_CONTACT_EMAIL_4 };
+                                       gchar *emails[3];
+                                       gint ii, ff = 0;
+
+                                       emails[0] = e_contact_get (contact, E_CONTACT_EMAIL_1);
+                                       emails[1] = e_contact_get (contact, E_CONTACT_EMAIL_2);
+                                       emails[2] = e_contact_get (contact, E_CONTACT_EMAIL_3);
+
+                                       /* Make the mailbox email the primary email and skip duplicates */
+                                       e_contact_set (contact, E_CONTACT_EMAIL_1, NULL);
+                                       e_contact_set (contact, E_CONTACT_EMAIL_2, NULL);
+                                       e_contact_set (contact, E_CONTACT_EMAIL_3, NULL);
+                                       e_contact_set (contact, E_CONTACT_EMAIL_4, NULL);
+                                       e_contact_set (contact, E_CONTACT_EMAIL, NULL);
+
+                                       e_contact_set (contact, E_CONTACT_EMAIL_1, mb->email);
+
+                                       for (ii = 0; ii < 3; ii++) {
+                                               if (emails[ii] && g_ascii_strcasecmp (emails[ii], mb->email) 
!= 0) {
+                                                       e_contact_set (contact, fields[ff], emails[ii]);
+                                                       ff++;
+                                               }
+
+                                               g_free (emails[ii]);
+                                       }
+                               }
 
-       g_return_val_if_fail (priv->summary != NULL, FALSE);
+                               nfo = e_book_meta_backend_info_new (e_contact_get_const (contact, 
E_CONTACT_UID),
+                                       e_contact_get_const (contact, E_CONTACT_REV), NULL, NULL);
+                               nfo->object = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
 
-       /* Not connected? Try again later */
-       if (!priv->cnc)
-               return TRUE;
+                               found_infos = g_slist_prepend (found_infos, nfo);
 
-       cancellable = g_object_ref (priv->cancellable);
+                               g_object_unref (contact);
+                       }
+               }
 
-       status_message = g_strdup (_("Syncing contacts..."));
-       list = e_book_backend_list_views (E_BOOK_BACKEND (ebews));
-       for (link = list; link != NULL; link = g_list_next (link))
-               e_data_book_view_notify_progress (E_DATA_BOOK_VIEW (link->data), -1, status_message);
-       g_list_free_full (list, g_object_unref);
-       g_free (status_message);
+               g_slist_free_full (mailboxes, (GDestroyNotify) e_ews_mailbox_free);
+               e_util_free_nullable_object_slist (contacts);
 
-       ews_update_items_thread (g_object_ref (ebews));
+               if (success) {
+                       GSList *created_objects = NULL, *modified_objects = NULL;
 
-       /* hide progress message when done */
-       list = e_book_backend_list_views (E_BOOK_BACKEND (ebews));
-       for (link = list; link != NULL; link = g_list_next (link))
-               e_data_book_view_notify_progress (E_DATA_BOOK_VIEW (link->data), -1, NULL);
-       g_list_free_full (list, g_object_unref);
+                       success = e_book_meta_backend_split_changes_sync (meta_backend, found_infos, 
&created_objects,
+                               &modified_objects, NULL, cancellable, error);
+                       if (success)
+                               success = e_book_meta_backend_process_changes_sync (meta_backend, 
created_objects,
+                                       modified_objects, NULL, cancellable, error);
 
-       g_clear_object (&cancellable);
+                       g_slist_free_full (created_objects, e_book_meta_backend_info_free);
+                       g_slist_free_full (modified_objects, e_book_meta_backend_info_free);
+               }
 
-       if (error) {
-               g_warning ("Error Syncing Contacts: Folder %s Error: %s", priv->folder_id, error->message);
-               g_clear_error (&error);
-               return FALSE;
+               g_slist_free_full (found_infos, e_book_meta_backend_info_free);
+               g_free (restriction_expr);
        }
 
-       return TRUE;
-}
-
-static gpointer
-delta_thread (gpointer data)
-{
-       EBookBackendEws *ebews = data;
-       EBookBackendEwsPrivate *priv = ebews->priv;
-       gint64 end_time;
-
-       g_mutex_lock (&priv->dlock->mutex);
-       g_object_ref (ebews);
-       g_mutex_unlock (&priv->dlock->mutex);
-
-       while (TRUE)    {
-               gboolean succeeded = TRUE;
-
-               if (!priv->is_gal)
-                       succeeded = ebews_start_sync (ebews);
-               else if (priv->summary && priv->marked_for_offline)
-                       succeeded = ebews_start_gal_sync (ebews);
+       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
 
-               g_mutex_lock (&priv->dlock->mutex);
+       ebb_ews_convert_error_to_edb_error (error);
 
-               /* in case this is the last reference, then this cannot join
-                  the itself thread in dispose */
-               e_ews_connection_utils_unref_in_thread (ebews);
-
-               if (!succeeded || priv->dlock->exit)
-                       break;
-
-               end_time = g_get_monotonic_time () + REFRESH_INTERVAL * G_TIME_SPAN_SECOND;
-               g_cond_wait_until (&priv->dlock->cond, &priv->dlock->mutex, end_time);
-
-               if (priv->dlock->exit)
-                       break;
-
-               g_object_ref (ebews);
-
-               g_mutex_unlock (&priv->dlock->mutex);
-       }
-
-       g_mutex_unlock (&priv->dlock->mutex);
-       priv->dthread = NULL;
-       return NULL;
+       return success;
 }
 
-static gboolean
-fetch_deltas (EBookBackendEws *ebews,
-             gboolean force_update)
+static GSList * /* the possibly modified 'in_items' */
+ebb_ews_verify_changes (EBookCache *book_cache,
+                       GSList *in_items, /* EEwsItem * */
+                       GCancellable *cancellable)
 {
-       EBookBackendEwsPrivate *priv = ebews->priv;
-       GError *error = NULL;
+       GSList *items = NULL, *link;
 
-       /* If the thread is already running just return back */
-       if (priv->dthread) {
-               if (force_update && priv->dlock) {
-                       g_mutex_lock (&priv->dlock->mutex);
-                       g_cond_signal (&priv->dlock->cond);
-                       g_mutex_unlock (&priv->dlock->mutex);
-               }
-
-               return FALSE;
-       }
-
-       if (!priv->dlock) {
-               priv->dlock = g_new0 (SyncDelta, 1);
-               g_mutex_init (&priv->dlock->mutex);
-               g_cond_init (&priv->dlock->cond);
-       }
+       g_return_val_if_fail (E_IS_BOOK_CACHE (book_cache), in_items);
 
-       priv->dlock->exit = FALSE;
-       priv->dthread = g_thread_try_new (NULL, (GThreadFunc) delta_thread, ebews, &error);
-       if (!priv->dthread) {
-               g_warning (G_STRLOC ": %s", error->message);
-               g_error_free (error);
-       }
-
-       return TRUE;
-}
+       for (link = in_items; link; link = g_slist_next (link)) {
+               EEwsItem *item = link->data;
+               const EwsId *id = e_ews_item_get_id (item);
+               EEwsItemType type = e_ews_item_get_item_type (item);
 
-static void
-ebews_start_refreshing (EBookBackendEws *ebews,
-                       gboolean force_update)
-{
-       EBookBackendEwsPrivate *priv;
+               if (!g_cancellable_is_cancelled (cancellable) && (
+                   type == E_EWS_ITEM_TYPE_CONTACT ||
+                   type == E_EWS_ITEM_TYPE_GROUP)) {
+                       EContact *existing = NULL;
 
-       priv = ebews->priv;
+                       if (e_book_cache_get_contact (book_cache, id->id, TRUE, &existing, cancellable, NULL) 
&&
+                           existing && g_strcmp0 (e_contact_get_const (existing, E_CONTACT_REV), 
id->change_key) == 0) {
+                               g_object_unref (item);
+                       } else {
+                               items = g_slist_prepend (items, item);
+                       }
 
-       PRIV_LOCK (priv);
+                       g_clear_object (&existing);
+               } else {
+                       items = g_slist_prepend (items, item);
+               }
+       }
 
-       if (e_backend_get_online (E_BACKEND (ebews)) &&
-           priv->cnc != NULL && priv->marked_for_offline)
-               fetch_deltas (ebews, force_update);
+       g_slist_free (in_items);
 
-       PRIV_UNLOCK (priv);
+       return items;
 }
 
-static gboolean
-fetch_from_offline (EBookBackendEws *ews,
-                   EDataBookView *book_view,
-                   const gchar *query,
-                   GCancellable *cancellable,
-                   GError **error)
+static GSList * /* EBookMetaBackendInfo */
+ebb_ews_contacts_to_infos (const GSList *contacts) /* EContact * */
 {
-       GSList *contacts = NULL, *l;
-       EBookBackendEwsPrivate *priv;
-
-       priv = ews->priv;
-
-       /* GAL with folder_id means offline GAL */
-       if (priv->is_gal && !priv->folder_id && !g_strcmp0 (query, "(contains \"x-evolution-any-field\" 
\"\")"))
-               return TRUE;
+       GSList *nfos = NULL, *link;
 
-       if (!e_book_sqlite_lock (priv->summary, EBSQL_LOCK_READ, cancellable, error))
-               return FALSE;
+       for (link = (GSList *) contacts; link; link = g_slist_next (link)) {
+               EContact *contact = link->data;
+               EBookMetaBackendInfo *nfo;
 
-       e_book_sqlite_search (priv->summary, query, FALSE, &contacts, cancellable, error);
-       e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_NONE, NULL);
-       for (l = contacts; l != NULL; l = g_slist_next (l)) {
-               EbSqlSearchData *s_data = (EbSqlSearchData *) l->data;
+               if (!E_IS_CONTACT (contact))
+                       continue;
 
-               e_data_book_view_notify_update_prefiltered_vcard (book_view, s_data->uid, s_data->vcard);
+               nfo = e_book_meta_backend_info_new (
+                       e_contact_get_const (contact, E_CONTACT_UID),
+                       e_contact_get_const (contact, E_CONTACT_REV),
+                       NULL, NULL);
+               nfo->object = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
 
-               e_book_sqlite_search_data_free (s_data);
+               nfos = g_slist_prepend (nfos, nfo);
        }
 
-       if (contacts)
-               g_slist_free (contacts);
-
-       return TRUE;
+       return nfos;
 }
 
-static void
-e_book_backend_ews_start_view (EBookBackend *backend,
-                               EDataBookView *book_view)
+static gboolean
+ebb_ews_connect_sync (EBookMetaBackend *meta_backend,
+                     const ENamedParameters *credentials,
+                     ESourceAuthenticationResult *out_auth_result,
+                     gchar **out_certificate_pem,
+                     GTlsCertificateFlags *out_certificate_errors,
+                     GCancellable *cancellable,
+                     GError **error)
 {
-       EBookBackendEws *ebews;
-       EBookBackendEwsPrivate *priv;
-       EBookBackendSExp *sexp;
-       const gchar *query;
-       gboolean is_autocompletion = FALSE;
-       gchar *auto_comp_str = NULL;
-       GCancellable *cancellable;
-       GSList *mailboxes = NULL, *l, *contacts = NULL, *c;
-       EwsFolderId *fid;
-       ESource *source;
-       ESourceEwsFolder *extension;
-       const gchar *extension_name;
-       GError *error = NULL;
-       gboolean includes_last_item;
-       gint is_populated = 0;
-
-       ebews = E_BOOK_BACKEND_EWS (backend);
-       priv = ebews->priv;
+       EBookBackendEws *bbews;
+       CamelEwsSettings *ews_settings;
+       gchar *hosturl;
+       gboolean success = FALSE;
 
-       sexp = e_data_book_view_get_sexp (book_view);
-       query = e_book_backend_sexp_text (sexp);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (meta_backend), FALSE);
+       g_return_val_if_fail (out_auth_result != NULL, FALSE);
 
-       source = e_backend_get_source (E_BACKEND (backend));
+       bbews = E_BOOK_BACKEND_EWS (meta_backend);
 
-       g_object_ref (book_view);
-       e_data_book_view_notify_progress (book_view, -1, _("Searching..."));
+       g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-       PRIV_LOCK (priv);
-       cancellable = g_cancellable_new ();
-       g_hash_table_insert (priv->ops, book_view, cancellable);
-       PRIV_UNLOCK (priv);
+       if (bbews->priv->cnc) {
+               g_rec_mutex_unlock (&bbews->priv->cnc_lock);
 
-       if (!e_backend_get_online (E_BACKEND (backend)) || !priv->cnc) {
-               if (priv->summary)
-                       e_book_sqlite_get_key_value_int (priv->summary, E_BOOK_SQL_IS_POPULATED_KEY, 
&is_populated, NULL);
-               if (is_populated) {
-                       fetch_from_offline (ebews, book_view, query, cancellable, &error);
-                       goto out;
-               }
+               *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
 
-               goto out;
+               return TRUE;
        }
 
-       g_return_if_fail (priv->cnc != NULL);
-
-       ebews_start_refreshing (ebews, FALSE);
-
-       if (priv->summary)
-               e_book_sqlite_get_key_value_int (priv->summary, E_BOOK_SQL_IS_POPULATED_KEY, &is_populated, 
NULL);
-       if (is_populated) {
-               fetch_from_offline (ebews, book_view, query, cancellable, &error);
-               goto out;
-       }
+       ews_settings = ebb_ews_get_collection_settings (bbews);
+       hosturl = camel_ews_settings_dup_hosturl (ews_settings);
 
-       e_book_backend_ews_build_restriction (query, &is_autocompletion, &auto_comp_str);
-       if (!is_autocompletion || !auto_comp_str) {
-               g_free (auto_comp_str);
-               goto out;
-       }
+       bbews->priv->cnc = e_ews_connection_new (hosturl, ews_settings);
 
-       extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
-       extension = e_source_get_extension (source, extension_name);
-
-       /* FIXME Need to convert the Ids from EwsLegacyId format to EwsId format using
-        * convert_id operation before using it as the schema has changed between Exchange
-        * 2007 and 2007_SP1 */
-       fid = g_new0 (EwsFolderId, 1);
-       fid->id = g_strdup (priv->folder_id);
-       fid->change_key = e_source_ews_folder_dup_change_key (extension);
-
-       /* We do not scan until we reach the last_item as it might be good enough to show first 100
-        * items during auto-completion. Change it if needed. TODO, Personal Address-book should start using
-        * find_items rather than resolve_names to support all queries */
-       e_ews_connection_resolve_names_sync (
-               priv->cnc, EWS_PRIORITY_MEDIUM, auto_comp_str,
-               EWS_SEARCH_AD, NULL, TRUE, &mailboxes, &contacts,
-               &includes_last_item, cancellable, &error);
-       g_free (auto_comp_str);
-       e_ews_folder_id_free (fid);
-       if (error != NULL) {
-               e_data_book_view_notify_complete (book_view, error);
-               g_object_unref (book_view);
-               g_clear_error (&error);
-               return;
-       }
+       e_binding_bind_property (
+               bbews, "proxy-resolver",
+               bbews->priv->cnc, "proxy-resolver",
+               G_BINDING_SYNC_CREATE);
 
-       for (l = mailboxes, c = contacts; l != NULL; l = g_slist_next (l), c = g_slist_next (c)) {
-               EwsMailbox *mb = l->data;
-               EEwsItem *contact_item = c ? c->data : NULL;
-               EContact *contact = NULL;
-               const gchar *str;
+       *out_auth_result = e_ews_connection_try_credentials_sync (bbews->priv->cnc, credentials, cancellable, 
error);
 
-               if (g_strcmp0 (mb->mailbox_type, "PublicDL") == 0) {
-                       contact = e_contact_new ();
+       if (*out_auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
+               ESource *source = e_backend_get_source (E_BACKEND (bbews));
+               ESourceEwsFolder *ews_folder;
+               gchar *gal_uid;
 
-                       if (!ebews_get_dl_info_gal (ebews, contact, mb, NULL)) {
-                               g_clear_object (&contact);
-                       }
-               }
+               ews_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
 
-               if (!contact && contact_item && e_ews_item_get_item_type (contact_item) == 
E_EWS_ITEM_TYPE_CONTACT)
-                       contact = ebews_get_contact_info (ebews, contact_item, cancellable, NULL);
+               g_free (bbews->priv->folder_id);
+               bbews->priv->folder_id = e_source_ews_folder_dup_id (ews_folder);
 
-               if (!contact)
-                       contact = e_contact_new ();
+               gal_uid = camel_ews_settings_dup_gal_uid (ews_settings);
+               bbews->priv->is_gal = g_strcmp0 (e_source_get_uid (source), gal_uid) == 0;
 
-               /* We do not get an id from the server, so just using email_id as uid for now */
-               e_contact_set (contact, E_CONTACT_UID, mb->email);
+               g_free (gal_uid);
 
-               str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
-               if (!str || !*str)
-                       e_contact_set (contact, E_CONTACT_FULL_NAME, mb->name);
+               g_signal_connect_swapped (bbews->priv->cnc, "server-notification",
+                       G_CALLBACK (ebb_ews_server_notification_cb), bbews);
 
-               str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);
-               if (!str || !*str || (contact_item && e_ews_item_get_item_type (contact_item) == 
E_EWS_ITEM_TYPE_CONTACT)) {
-                       /* Cleanup first, then re-add only SMTP addresses */
-                       e_contact_set (contact, E_CONTACT_EMAIL_1, NULL);
-                       e_contact_set (contact, E_CONTACT_EMAIL_2, NULL);
-                       e_contact_set (contact, E_CONTACT_EMAIL_3, NULL);
-                       e_contact_set (contact, E_CONTACT_EMAIL_4, NULL);
-                       e_contact_set (contact, E_CONTACT_EMAIL, NULL);
+               if (!bbews->priv->is_gal &&
+                   camel_ews_settings_get_listen_notifications (ews_settings) &&
+                   e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010_SP1)) {
+                       GSList *folders = NULL;
 
-                       ebews_populate_emails_ex (ebews, contact, contact_item, TRUE);
-               }
+                       folders = g_slist_prepend (folders, bbews->priv->folder_id);
 
-               str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);
-               if (!str || !*str) {
-                       e_contact_set (contact, E_CONTACT_EMAIL_1, mb->email);
-               } else if (mb->email && (!mb->routing_type || g_ascii_strcasecmp (mb->routing_type, "SMTP") 
== 0)) {
-                       EContactField fields[3] = { E_CONTACT_EMAIL_2, E_CONTACT_EMAIL_3, E_CONTACT_EMAIL_4 };
-                       gchar *emails[3];
-                       gint ii, ff = 0;
-
-                       emails[0] = e_contact_get (contact, E_CONTACT_EMAIL_1);
-                       emails[1] = e_contact_get (contact, E_CONTACT_EMAIL_2);
-                       emails[2] = e_contact_get (contact, E_CONTACT_EMAIL_3);
-
-                       /* Make the mailbox email the primary email and skip duplicates */
-                       e_contact_set (contact, E_CONTACT_EMAIL_1, NULL);
-                       e_contact_set (contact, E_CONTACT_EMAIL_2, NULL);
-                       e_contact_set (contact, E_CONTACT_EMAIL_3, NULL);
-                       e_contact_set (contact, E_CONTACT_EMAIL_4, NULL);
-                       e_contact_set (contact, E_CONTACT_EMAIL, NULL);
-
-                       e_contact_set (contact, E_CONTACT_EMAIL_1, mb->email);
-
-                       for (ii = 0; ii < 3; ii++) {
-                               if (emails[ii] && g_ascii_strcasecmp (emails[ii], mb->email) != 0) {
-                                       e_contact_set (contact, fields[ff], emails[ii]);
-                                       ff++;
-                               }
+                       e_ews_connection_enable_notifications_sync (bbews->priv->cnc,
+                               folders, &bbews->priv->subscription_key);
 
-                               g_free (emails[ii]);
-                       }
+                       g_slist_free (folders);
                }
 
-               e_data_book_view_notify_update (book_view, contact);
-
-               g_object_unref (contact);
+               e_book_backend_set_writable (E_BOOK_BACKEND (bbews), !bbews->priv->is_gal);
+               success = TRUE;
+       } else {
+               ebb_ews_convert_error_to_edb_error (error);
+               g_clear_object (&bbews->priv->cnc);
        }
 
-       g_slist_free_full (mailboxes, (GDestroyNotify) e_ews_mailbox_free);
-       e_util_free_nullable_object_slist (contacts);
- out:
-       e_data_book_view_notify_complete (book_view, error);
-       g_clear_error (&error);
-       PRIV_LOCK (priv);
-       g_hash_table_remove (priv->ops, book_view);
-       PRIV_UNLOCK (priv);
-       g_object_unref (cancellable);
-       g_object_unref (book_view);
-}
+       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
 
-static void
-e_book_backend_ews_stop_view (EBookBackend *backend,
-                              EDataBookView *book_view)
-{
-       EBookBackendEws *bews = E_BOOK_BACKEND_EWS (backend);
-       EBookBackendEwsPrivate *priv = bews->priv;
-       GCancellable *cancellable;
+       g_free (hosturl);
 
-       PRIV_LOCK (priv);
-       cancellable = g_hash_table_lookup (priv->ops, book_view);
-       if (cancellable)
-               g_cancellable_cancel (cancellable);
-       PRIV_UNLOCK (priv);
+       return success;
 }
 
 static gboolean
-book_backend_ews_initable_init (GInitable *initable,
-                               GCancellable *cancellable,
-                               GError **error)
+ebb_ews_disconnect_sync (EBookMetaBackend *meta_backend,
+                        GCancellable *cancellable,
+                        GError **error)
 {
-       EBookBackend *backend = E_BOOK_BACKEND (initable);
-       ESource *source = e_backend_get_source (E_BACKEND (backend));
-       EBookBackendEws *cbews;
-       EBookBackendEwsPrivate *priv;
-       CamelEwsSettings *settings;
-       ESourceExtension *extension;
-       const gchar *cache_dir;
-       const gchar *display_name;
-       const gchar *extension_name;
-       const gchar *gal_uid;
-       const gchar *uid;
-       gchar *db_filename;
-
-       cbews = E_BOOK_BACKEND_EWS (backend);
-       priv = cbews->priv;
-
-       if (priv->base_directory)
-               cache_dir = priv->base_directory;
-       else
-               cache_dir = e_book_backend_get_cache_dir (backend);
-       db_filename = g_build_filename (cache_dir, "contacts.db", NULL);
-       settings = book_backend_ews_get_collection_settings (cbews);
-
-       uid = e_source_get_uid (source);
-       gal_uid = camel_ews_settings_get_gal_uid (settings);
-       priv->is_gal = (g_strcmp0 (uid, gal_uid) == 0);
-
-       display_name = e_source_get_display_name (source);
-
-       extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
-       extension = e_source_get_extension (source, extension_name);
-
-       priv->folder_id = e_source_ews_folder_dup_id (
-               E_SOURCE_EWS_FOLDER (extension));
-
-       priv->summary = e_book_sqlite_new (db_filename, source, cancellable, error);
-       g_free (db_filename);
-       if (priv->summary == NULL) {
-               convert_error_to_edb_error (error);
-               return FALSE;
-       }
-
-       if (!e_book_sqlite_get_locale (priv->summary, &priv->locale, error)) {
-               convert_error_to_edb_error (error);
-                g_object_unref (priv->summary);
-                priv->summary = NULL;
-               return FALSE;
-       }
-
-       priv->marked_for_offline = FALSE;
-       priv->is_writable = FALSE;
+       EBookBackendEws *bbews;
 
-       extension_name = E_SOURCE_EXTENSION_OFFLINE;
-       extension = e_source_get_extension (source, extension_name);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (meta_backend), FALSE);
 
-       priv->marked_for_offline = e_source_offline_get_stay_synchronized (E_SOURCE_OFFLINE (extension));
+       bbews = E_BOOK_BACKEND_EWS (meta_backend);
 
-       if (priv->is_gal) {
-               priv->folder_name = g_strdup (display_name);
-               priv->oab_url = camel_ews_settings_dup_oaburl (settings);
-
-               /* setup stagging dir, remove any old files from there */
-               priv->attachment_dir = g_build_filename (
-                       cache_dir, "attachments", NULL);
-               g_mkdir_with_parents (priv->attachment_dir, 0777);
-
-               priv->marked_for_offline = camel_ews_settings_get_oab_offline (settings);
-       }
+       ebb_ews_unset_connection (bbews);
 
        return TRUE;
 }
 
-static void
-e_book_backend_ews_notify_online_cb (EBookBackend *backend,
-                                     GParamSpec *spec)
+static gboolean
+ebb_ews_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)
 {
-       EBookBackendEws *ebews;
-
-       ebews = E_BOOK_BACKEND_EWS (backend);
-
-       if (e_book_backend_is_opened (backend)) {
-               if (ebews->priv->cancellable) {
-                       g_cancellable_cancel (ebews->priv->cancellable);
-                       g_object_unref (ebews->priv->cancellable);
-                       ebews->priv->cancellable = NULL;
-               }
-
-               if (!e_backend_get_online (E_BACKEND (backend))) {
-                       e_book_backend_set_writable (backend, FALSE);
-                       if (ebews->priv->cnc) {
-                               g_object_unref (ebews->priv->cnc);
-                               ebews->priv->cnc = NULL;
-                       }
-               } else {
-                       ebews->priv->cancellable = g_cancellable_new ();
-                       ebews->priv->is_writable = !ebews->priv->is_gal;
-
-                       e_book_backend_set_writable (backend, ebews->priv->is_writable);
-
-                       e_backend_schedule_credentials_required (E_BACKEND (backend),
-                               E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL,
-                               ebews->priv->cancellable, G_STRFUNC);
-               }
-       }
-}
+       EBookBackendEws *bbews;
+       EBookCache *book_cache;
+       gboolean success = TRUE;
+       GError *local_error = NULL;
 
-static gchar *
-e_book_backend_ews_get_backend_property (EBookBackend *backend,
-                                         const gchar *prop_name)
-{
-       g_return_val_if_fail (prop_name != NULL, NULL);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (meta_backend), FALSE);
+       g_return_val_if_fail (out_new_sync_tag != NULL, FALSE);
+       g_return_val_if_fail (out_repeat != NULL, FALSE);
+       g_return_val_if_fail (out_created_objects != NULL, FALSE);
+       g_return_val_if_fail (out_modified_objects != NULL, FALSE);
+       g_return_val_if_fail (out_removed_objects != NULL, FALSE);
 
-       if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
-               EBookBackendEws *ebews;
+       *out_created_objects = NULL;
+       *out_modified_objects = NULL;
+       *out_removed_objects = NULL;
 
-               ebews = E_BOOK_BACKEND_EWS (backend);
-               g_return_val_if_fail (ebews != NULL, NULL);
+       bbews = E_BOOK_BACKEND_EWS (meta_backend);
 
-               /* GAL with folder_id is an offline GAL */
-               if (ebews->priv->is_gal && !ebews->priv->folder_id) {
-                       return g_strdup ("net,bulk-removes,contact-lists");
-               } else {
-                       /* do-initialy-query is enabled for system address book also, so that we get the
-                        * book_view, which is needed for displaying cache update progress.
-                        * and null query is handled for system address book.
-                        */
-                       return g_strdup ("net,bulk-removes,do-initial-query,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)) {
-               GString *buffer;
-               gchar *fields;
-               gint ii;
+       book_cache = e_book_meta_backend_ref_cache (meta_backend);
+       g_return_val_if_fail (E_IS_BOOK_CACHE (book_cache), FALSE);
 
-               buffer = g_string_sized_new (1024);
+       g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-               for (ii = 0; ii < G_N_ELEMENTS (mappings); ii++) {
-                       if (mappings[ii].element_type != ELEMENT_TYPE_SIMPLE)
-                               continue;
+       if (bbews->priv->is_gal) {
+               CamelEwsSettings *ews_settings;
+               gchar *oab_url;
 
-                       if (buffer->len > 0)
-                               g_string_append_c (buffer, ',');
-                       g_string_append (buffer, e_contact_field_name (mappings[ii].field_id));
-               }
+               ews_settings = ebb_ews_get_collection_settings (bbews);
+               oab_url = camel_ews_settings_dup_oaburl (ews_settings);
 
-               for (ii = 0; ii < G_N_ELEMENTS (phone_field_map); ii++) {
-                       if (buffer->len > 0)
-                               g_string_append_c (buffer, ',');
-                       g_string_append (buffer, e_contact_field_name (phone_field_map[ii].field));
-               }
+               if (oab_url && *oab_url &&
+                   camel_ews_settings_get_oab_offline (ews_settings)) {
+                       EEwsConnection *oab_cnc;
+                       GSList *full_l = NULL, *deltas = NULL, *link;
+                       EwsOALDetails *full = NULL;
+                       gchar *password, *etag = NULL;
+                       gint sequence;
 
-               fields = g_strjoin (
-                       ",",
-                       buffer->str,
-                       e_contact_field_name (E_CONTACT_FULL_NAME),
-                       e_contact_field_name (E_CONTACT_NICKNAME),
-                       e_contact_field_name (E_CONTACT_FAMILY_NAME),
-                       e_contact_field_name (E_CONTACT_EMAIL_1),
-                       e_contact_field_name (E_CONTACT_EMAIL_2),
-                       e_contact_field_name (E_CONTACT_EMAIL_3),
-                       e_contact_field_name (E_CONTACT_ADDRESS_WORK),
-                       e_contact_field_name (E_CONTACT_ADDRESS_HOME),
-                       e_contact_field_name (E_CONTACT_ADDRESS_OTHER),
-                       e_contact_field_name (E_CONTACT_BIRTH_DATE),
-                       e_contact_field_name (E_CONTACT_NOTE),
-                       e_contact_field_name (E_CONTACT_PHOTO),
-                       NULL);
+                       sequence = e_cache_get_key_int (E_CACHE (book_cache), "gal-sequence", NULL);
+                       if (sequence == -1)
+                               sequence = 0;
 
-               g_string_free (buffer, TRUE);
+                       oab_cnc = e_ews_connection_new (oab_url, ews_settings);
 
-               return fields;
-       } else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REVISION)) {
-               EBookBackendEws *ebews = E_BOOK_BACKEND_EWS (backend);
-               gchar *prop_value = NULL;
+                       e_binding_bind_property (
+                               bbews, "proxy-resolver",
+                               oab_cnc, "proxy-resolver",
+                               G_BINDING_SYNC_CREATE);
 
-               e_book_sqlite_get_key_value (ebews->priv->summary, "revision", &prop_value, NULL);
-               return prop_value;
-        }
+                       password = e_ews_connection_dup_password (bbews->priv->cnc);
+                       e_ews_connection_set_password (oab_cnc, password);
+                       e_util_safe_free_string (password);
 
-       /* Chain up to parent's get_backend_property() method. */
-       return E_BOOK_BACKEND_CLASS (e_book_backend_ews_parent_class)->
-               get_backend_property (backend, prop_name);
-}
+                       d (printf ("Ewsgal: Fetching oal full details file\n"));
+                       if (!e_ews_connection_get_oal_detail_sync (oab_cnc, bbews->priv->folder_id, NULL, 
last_sync_tag, &full_l, &etag, cancellable, &local_error)) {
+                               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_MODIFIED)) 
{
+                                       g_clear_error (&local_error);
+                               } else {
+                                       success = FALSE;
+                               }
+                       }
 
-static gpointer
-handle_notifications_thread (gpointer data)
-{
-       EBookBackendEws *ebews = data;
+                       if (success && full_l) {
+                               guint32 delta_size = 0;
+
+                               for (link = full_l; link; link = g_slist_next (link)) {
+                                       EwsOALDetails *det = full_l->data;
+
+                                       /* Throw away anything older than we already have */
+                                       if (det->seq <= sequence) {
+                                               ews_oal_details_free (det);
+                                       } else if (!g_strcmp0 (det->type, "Full")) {
+                                               if (full)
+                                                       ews_oal_details_free (full);
+                                               full = det;
+                                       } else if (sequence > 0 && !g_strcmp0 (det->type, "Diff")) {
+                                               delta_size += det->size;
+                                               deltas = g_slist_insert_sorted (deltas, det, det_sort_func);
+                                       } else {
+                                               ews_oal_details_free (det);
+                                       }
+                               }
 
-       PRIV_LOCK (ebews->priv);
-       if (ebews->priv->cnc == NULL)
-               goto exit;
+                               g_slist_free (full_l);
+                               full_l = NULL;
 
-       if (ebews->priv->listen_notifications) {
-               GSList *folders = NULL;
+                               /* If the deltas would be bigger, just download the new full file */
+                               if (full && delta_size > full->size) {
+                                       g_slist_free_full (deltas, (GDestroyNotify) ews_oal_details_free);
+                                       deltas = NULL;
+                               }
+                       }
 
-               if (ebews->priv->subscription_key != 0)
-                       goto exit;
+                       if (full) {
+                               gchar *uncompressed_filename;
 
-               folders = g_slist_prepend (folders, ebews->priv->folder_id);
+                               uncompressed_filename = ebb_ews_download_gal (bbews, book_cache, full, 
deltas, sequence, cancellable, &local_error);
+                               if (!uncompressed_filename) {
+                                       success = FALSE;
+                               } else {
+                                       d (printf ("Ewsgal: Removing old gal\n"));
+                                       /* remove old_gal_file */
+                                       ebb_ews_remove_old_gal_file (book_cache);
 
-               e_ews_connection_enable_notifications_sync (
-                               ebews->priv->cnc,
-                               folders,
-                               &ebews->priv->subscription_key);
+                                       d (printf ("Ewsgal: Check for changes in GAL\n"));
+                                       success = ebb_ews_check_gal_changes (bbews, book_cache, 
uncompressed_filename,
+                                               out_created_objects, out_modified_objects, 
out_removed_objects, cancellable, &local_error);
 
-               g_slist_free (folders);
-       } else {
-               if (ebews->priv->subscription_key == 0)
-                       goto exit;
+                                       if (success) {
+                                               if (e_cache_set_key (E_CACHE (book_cache), "oab-filename", 
uncompressed_filename, NULL)) {
+                                                       /* Don't let it get deleted */
+                                                       g_free (uncompressed_filename);
+                                                       uncompressed_filename = NULL;
+                                               }
 
-               e_ews_connection_disable_notifications_sync (
-                               ebews->priv->cnc,
-                               ebews->priv->subscription_key);
+                                               e_cache_set_key_int (E_CACHE (book_cache), "gal-sequence", 
full->seq, NULL);
 
-               ebews->priv->subscription_key = 0;
-       }
+                                               d (printf ("Ewsgal: sync successfully completed\n"));
+                                       }
 
-exit:
-       PRIV_UNLOCK (ebews->priv);
-       g_object_unref (ebews);
-       return NULL;
-}
+                                       ews_oal_details_free (full);
+                               }
 
-static void
-ebews_listen_notifications_cb (EBookBackendEws *ebews,
-                              GParamSpec *spec,
-                              CamelEwsSettings *ews_settings)
-{
-       GThread *thread;
+                               if (uncompressed_filename) {
+                                       /* preserve  the oab file once we are able to decode the differential 
updates */
+                                       g_unlink (uncompressed_filename);
+                                       g_free (uncompressed_filename);
+                               }
+                       }
 
-       PRIV_LOCK (ebews->priv);
-       if (ebews->priv->cnc == NULL) {
-               PRIV_UNLOCK (ebews->priv);
-               return;
-       }
+                       g_slist_free_full (full_l, (GDestroyNotify) ews_oal_details_free);
+                       g_slist_free_full (deltas, (GDestroyNotify) ews_oal_details_free);
+                       g_clear_object (&oab_cnc);
 
-       if (!e_ews_connection_satisfies_server_version (ebews->priv->cnc, E_EWS_EXCHANGE_2010_SP1)) {
-               PRIV_UNLOCK (ebews->priv);
-               return;
-       }
+                       if (success)
+                               *out_new_sync_tag = etag;
+                       else
+                               g_free (etag);
 
-       ebews->priv->listen_notifications = camel_ews_settings_get_listen_notifications (ews_settings);
-       PRIV_UNLOCK (ebews->priv);
+                       if (local_error) {
+                               g_prefix_error (&local_error, "%s", _("Failed to update GAL:"));
+                               g_propagate_error (error, local_error);
+                       }
+               }
 
-       thread = g_thread_new (NULL, handle_notifications_thread, g_object_ref (ebews));
-       g_thread_unref (thread);
-}
+               g_free (oab_url);
+       } else {
+               GSList *items_created = NULL, *items_modified = NULL, *items_deleted = NULL, *link;
+               gboolean includes_last_item = TRUE;
 
-static gpointer
-ews_update_items_thread (gpointer data)
-{
-       EBookBackendEws *ebews = data;
-       EBookBackendEwsPrivate *priv;
-       gchar *sync_state = NULL;
-       GError *error = NULL;
-       gboolean includes_last_item;
-       GSList *items_created = NULL;
-       GSList *items_updated = NULL;
-       GSList *items_deleted = NULL;
-       GSList *items_deleted_resync = NULL;
-       GSList *contacts_created = NULL;
-       GSList *contacts_updated = NULL;
-       GSList *l;
+               success = e_ews_connection_sync_folder_items_sync (bbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+                       last_sync_tag, bbews->priv->folder_id, "IdOnly", NULL, EWS_MAX_FETCH_COUNT,
+                       out_new_sync_tag, &includes_last_item, &items_created, &items_modified, 
&items_deleted,
+                       cancellable, &local_error);
 
-       priv = ebews->priv;
-
-       e_book_sqlite_get_key_value (priv->summary, E_BOOK_SQL_SYNC_DATA_KEY, &sync_state, NULL);
-       do {
-               gchar *old_sync_state = sync_state;
-
-               sync_state = NULL;
-               includes_last_item = TRUE;
-
-               e_ews_connection_sync_folder_items_sync (
-                               priv->cnc,
-                               EWS_PRIORITY_MEDIUM,
-                               old_sync_state,
-                               priv->folder_id,
-                               "IdOnly",
-                               NULL,
-                               EWS_MAX_FETCH_COUNT,
-                               &sync_state,
-                               &includes_last_item,
-                               &items_created,
-                               &items_updated,
-                               &items_deleted,
-                               priv->cancellable,
-                               &error);
-
-               g_free (old_sync_state);
-
-               if (error != NULL) {
-                       if (g_error_matches (error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_INVALIDSYNCSTATEDATA)) {
-                               g_clear_error (&error);
-
-                               if (!e_book_sqlite_search_uids (priv->summary, NULL, &items_deleted_resync,
-                                                               priv->cancellable, &error))
-                                       break;
-
-                               /* This should be the case anyway, but make sure */
-                               sync_state = NULL;
-
-                               /* Ensure we go round the loop again */
-                               includes_last_item = FALSE;
-                               continue;
-                       }
-                       /* Other error */
-                       break;
-               }
+               if (!success &&
+                   g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_INVALIDSYNCSTATEDATA)) {
+                       g_clear_error (&local_error);
 
-               if (items_created) {
-                       ebews_fetch_items (
-                                       ebews,
-                                       items_created, /* freed inside the function */
-                                       &contacts_created,
-                                       priv->cancellable,
-                                       &error);
-                       items_created = NULL;
-                       if (error != NULL)
-                               break;
-               }
+                       e_book_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
 
-               if (items_updated) {
-                       ebews_fetch_items (
-                                       ebews,
-                                       items_updated, /* freed inside the function */
-                                       &contacts_updated,
-                                       priv->cancellable,
-                                       &error);
-                       items_updated = NULL;
-                       if (error != NULL)
-                               break;
+                       success = e_ews_connection_sync_folder_items_sync (bbews->priv->cnc, 
EWS_PRIORITY_MEDIUM,
+                               NULL, bbews->priv->folder_id, "IdOnly", NULL, EWS_MAX_FETCH_COUNT,
+                               out_new_sync_tag, &includes_last_item, &items_created, &items_modified, 
&items_deleted,
+                               cancellable, &local_error);
                }
 
-               /* Network traffic is done, and database access starts here */
-               if (!e_book_sqlite_lock (priv->summary, EBSQL_LOCK_WRITE, priv->cancellable, &error))
-                       break;
+               if (success) {
+                       GSList *contacts_created = NULL, *contacts_modified = NULL;
 
-               if ((items_deleted_resync && !e_book_sqlite_remove_contacts (priv->summary, 
items_deleted_resync, priv->cancellable, &error)) ||
-                   (items_deleted && !e_book_sqlite_remove_contacts (priv->summary, items_deleted, 
priv->cancellable, &error)) ||
-                   (contacts_created && !e_book_sqlite_add_contacts (priv->summary, contacts_created, NULL, 
TRUE, priv->cancellable, &error)) ||
-                   (contacts_updated && !e_book_sqlite_add_contacts (priv->summary, contacts_updated, NULL, 
TRUE, priv->cancellable, &error)) ||
-                   !e_book_sqlite_set_key_value (priv->summary, E_BOOK_SQL_SYNC_DATA_KEY, sync_state, 
&error) ||
-                   (includes_last_item && !e_book_sqlite_set_key_value_int (priv->summary, 
E_BOOK_SQL_IS_POPULATED_KEY, TRUE, &error)) ||
-                   !ebews_bump_revision (ebews, &error)) {
-                       e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_ROLLBACK, NULL);
-                       break;
-               }
-               if (!e_book_sqlite_unlock (priv->summary, EBSQL_UNLOCK_COMMIT, &error))
-                       break;
+                       /* The sync state doesn't cover changes made by save_contact_sync(),
+                          thus verify the changes, instead of re-donwloading the contacts again */
+                       items_created = ebb_ews_verify_changes (book_cache, items_created, cancellable);
+                       items_modified = ebb_ews_verify_changes (book_cache, items_modified, cancellable);
 
-               while (items_deleted_resync || items_deleted) {
-                       if (items_deleted_resync) {
-                               l = items_deleted_resync;
-                               items_deleted_resync = l->next;
-                       } else {
-                               l = items_deleted;
-                               items_deleted = l->next;
+                       if (items_created) {
+                               success = ebb_ews_fetch_items_sync (bbews, items_created, &contacts_created, 
cancellable, error);
+                               if (success)
+                                       *out_created_objects = ebb_ews_contacts_to_infos (contacts_created);
                        }
 
-                       e_book_backend_notify_remove (E_BOOK_BACKEND (ebews), l->data);
-                       g_free (l->data);
-                       g_slist_free_1 (l);
-               }
-               while (contacts_created || contacts_updated) {
-                       if (contacts_created) {
-                               l = contacts_created;
-                               contacts_created = l->next;
-                       } else {
-                               l = contacts_updated;
-                               contacts_updated = l->next;
+                       if (items_modified) {
+                               success = ebb_ews_fetch_items_sync (bbews, items_modified, 
&contacts_modified, cancellable, error);
+                               if (success)
+                                       *out_modified_objects = ebb_ews_contacts_to_infos (contacts_modified);
                        }
-                       e_book_backend_notify_update (E_BOOK_BACKEND (ebews), l->data);
-                       g_object_unref (l->data);
-                       g_slist_free_1 (l);
-               }
-               cursors_recalculate (ebews);
 
-       } while (!includes_last_item);
+                       for (link = items_deleted; link; link = g_slist_next (link)) {
+                               const gchar *uid = link->data;
 
-       g_slist_free_full (items_created, g_object_unref);
-       g_slist_free_full (items_updated, g_object_unref);
-       g_slist_free_full (items_deleted, g_free);
-       g_slist_free_full (items_deleted_resync, g_free);
-       g_slist_free_full (contacts_created, g_object_unref);
-       g_slist_free_full (contacts_updated, g_object_unref);
-
-       if (error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_clear_error (&error);
-       }
-
-       g_free (sync_state);
-       g_object_unref (ebews);
+                               *out_removed_objects = g_slist_prepend (*out_removed_objects,
+                                       e_book_meta_backend_info_new (uid, NULL, NULL, NULL));
+                       }
 
-       return NULL;
-}
+                       g_slist_free_full (contacts_created, g_object_unref);
+                       g_slist_free_full (contacts_modified, g_object_unref);
 
-static void
-ebews_server_notification_cb (EBookBackendEws *ebews,
-                             GSList *events,
-                             EEwsConnection *cnc)
-{
-       GSList *l;
-       gboolean update_folder = FALSE;
+                       *out_repeat = !includes_last_item;
+               } else if (local_error) {
+                       g_propagate_error (error, local_error);
+               }
 
-       g_return_if_fail (ebews != NULL);
-       g_return_if_fail (ebews->priv != NULL);
+               g_slist_free_full (items_created, g_object_unref);
+               g_slist_free_full (items_modified, g_object_unref);
+               g_slist_free_full (items_deleted, g_free);
+       }
 
-       for (l = events; l != NULL; l = l->next) {
-               EEwsNotificationEvent *event = l->data;
+       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
 
-               switch (event->type) {
-                       case E_EWS_NOTIFICATION_EVENT_CREATED:
-                       case E_EWS_NOTIFICATION_EVENT_DELETED:
-                       case E_EWS_NOTIFICATION_EVENT_MODIFIED:
-                               PRIV_LOCK (ebews->priv);
-                               if (g_strcmp0 (event->folder_id, ebews->priv->folder_id) == 0)
-                                       update_folder = TRUE;
-                               PRIV_UNLOCK (ebews->priv);
-                               break;
-                       case E_EWS_NOTIFICATION_EVENT_MOVED:
-                       case E_EWS_NOTIFICATION_EVENT_COPIED:
-                               PRIV_LOCK (ebews->priv);
-                               if (g_strcmp0 (event->folder_id, ebews->priv->folder_id) == 0 ||
-                                   g_strcmp0 (event->old_folder_id, ebews->priv->folder_id) == 0)
-                                       update_folder = TRUE;
-                               PRIV_UNLOCK (ebews->priv);
-                               break;
-                       default:
-                               return;
-               }
-       }
+       ebb_ews_convert_error_to_edb_error (error);
 
-       if (update_folder) {
-               GThread *thread;
+       g_clear_object (&book_cache);
 
-               thread = g_thread_new (NULL, ews_update_items_thread, g_object_ref (ebews));
-               g_thread_unref (thread);
-       }
+       return success;
 }
 
 static gboolean
-e_book_backend_ews_open_sync (EBookBackend *backend,
-                             GCancellable *cancellable,
-                             GError **error)
+ebb_ews_load_contact_sync (EBookMetaBackend *meta_backend,
+                          const gchar *uid,
+                          const gchar *extra,
+                          EContact **out_contact,
+                          gchar **out_extra,
+                          GCancellable *cancellable,
+                          GError **error)
 {
-       CamelEwsSettings *ews_settings;
-       EBookBackendEws *ebews;
-       EBookBackendEwsPrivate * priv;
-       ESource *source;
-       gboolean need_to_authenticate;
-       gchar *revision = NULL;
-
-       ebews = E_BOOK_BACKEND_EWS (backend);
-       priv = ebews->priv;
-
-       if (priv->base_directory || e_book_backend_is_opened (backend))
-               return TRUE;
-
-       ews_settings = book_backend_ews_get_collection_settings (ebews);
-       source = e_backend_get_source (E_BACKEND (ebews));
+       EBookBackendEws *bbews;
+       GSList *ids, *items = NULL;
+       gboolean success;
 
-       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (meta_backend), FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
+       g_return_val_if_fail (out_contact, FALSE);
 
-       PRIV_LOCK (priv);
-       need_to_authenticate = priv->cnc == NULL && e_backend_is_destination_reachable (E_BACKEND (backend), 
cancellable, NULL);
+       bbews = E_BOOK_BACKEND_EWS (meta_backend);
 
-       PRIV_UNLOCK (priv);
+       g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-       e_book_sqlite_get_key_value (priv->summary, "revision", &revision, NULL);
-       if (revision) {
-               e_book_backend_notify_property_changed (backend,
-                                                       BOOK_BACKEND_PROPERTY_REVISION,
-                                                       revision);
-               g_free (revision);
-       }
+       ids = g_slist_prepend (NULL, (gpointer) uid);
 
-       if (!ebews->priv->is_gal) {
-               PRIV_LOCK (priv);
-               priv->listen_notifications = camel_ews_settings_get_listen_notifications (ews_settings);
+       success = e_ews_connection_get_items_sync (bbews->priv->cnc, EWS_PRIORITY_MEDIUM, ids, "IdOnly",
+               NULL, FALSE, NULL, E_EWS_BODY_TYPE_TEXT, &items, NULL, NULL, cancellable, error);
 
-               if (priv->listen_notifications)
-                       ebews_listen_notifications_cb (ebews, NULL, ews_settings);
+       g_slist_free (ids);
 
-               PRIV_UNLOCK (priv);
+       if (!items)
+               success = FALSE;
 
-               g_signal_connect_swapped (
-                       ews_settings,
-                       "notify::listen-notifications",
-                       G_CALLBACK (ebews_listen_notifications_cb),
-                       ebews);
-       }
+       if (success) {
+               GSList *contacts = NULL;
 
-       if (ebews->priv->cnc)
-               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
-       else
-               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+               success = ebb_ews_fetch_items_sync (bbews, items, &contacts, cancellable, error);
+               if (success && contacts)
+                       *out_contact = g_object_ref (contacts->data);
 
-       if (need_to_authenticate &&
-           !book_backend_ews_ensure_connected (ebews, cancellable, error)) {
-               convert_error_to_edb_error (error);
-               return FALSE;
+               g_slist_free_full (contacts, g_object_unref);
        }
 
-       return TRUE;
-}
+       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
 
-/**
- * e_book_backend_ews_new:
- */
-EBookBackend *
-e_book_backend_ews_new (void)
-{
-       EBookBackendEws *backend;
+       g_slist_free_full (items, g_object_unref);
 
-       backend = g_object_new (E_TYPE_BOOK_BACKEND_EWS, NULL);
+       ebb_ews_convert_error_to_edb_error (error);
 
-       return E_BOOK_BACKEND (backend);
+       return success;
 }
 
 static gboolean
-e_book_backend_ews_get_destination_address (EBackend *backend,
-                                           gchar **host,
-                                           guint16 *port)
+ebb_ews_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)
 {
-       CamelEwsSettings *ews_settings;
-       SoupURI *soup_uri;
-       gchar *host_url;
-       gboolean result = FALSE;
-
-       g_return_val_if_fail (port != NULL, FALSE);
-       g_return_val_if_fail (host != NULL, FALSE);
-
-       /* Sanity checking */
-       if (!e_book_backend_get_registry (E_BOOK_BACKEND (backend)) ||
-           !e_backend_get_source (backend))
-               return FALSE;
+       EBookBackendEws *bbews;
+       EwsFolderId *fid;
+       GSList *items = NULL;
+       gboolean is_dl = FALSE;
+       gboolean success;
 
-       ews_settings = book_backend_ews_get_collection_settings (E_BOOK_BACKEND_EWS (backend));
-       g_return_val_if_fail (ews_settings != NULL, FALSE);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (meta_backend), FALSE);
+       g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
+       g_return_val_if_fail (out_new_uid != NULL, FALSE);
+       g_return_val_if_fail (out_new_extra != NULL, FALSE);
 
-       host_url = camel_ews_settings_dup_hosturl (ews_settings);
-       g_return_val_if_fail (host_url != NULL, FALSE);
+       bbews = E_BOOK_BACKEND_EWS (meta_backend);
 
-       soup_uri = soup_uri_new (host_url);
-       if (soup_uri) {
-               *host = g_strdup (soup_uri_get_host (soup_uri));
-               *port = soup_uri_get_port (soup_uri);
+       g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-               result = *host && **host;
-               if (!result) {
-                       g_free (*host);
-                       *host = NULL;
+       if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
+               if (!e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010)) {
+                       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
+                       g_propagate_error (error, EDB_ERROR_EX (NOT_SUPPORTED,
+                               _("Cannot save contact list, it’s only supported on EWS Server 2010 or 
later")));
+                       return FALSE;
                }
 
-               soup_uri_free (soup_uri);
+               is_dl = TRUE;
        }
 
-       g_free (host_url);
+       fid = e_ews_folder_id_new (bbews->priv->folder_id, NULL, FALSE);
+       if (overwrite_existing) {
+               EBookCache *book_cache;
+               EContact *old_contact = NULL;
 
-       return result;
-}
+               book_cache = e_book_meta_backend_ref_cache (meta_backend);
 
-static void
-e_book_backend_ews_constructed (GObject *object)
-{
-       G_OBJECT_CLASS (e_book_backend_ews_parent_class)->constructed (object);
+               success = e_book_cache_get_contact (book_cache, e_contact_get_const (contact, E_CONTACT_UID), 
FALSE, &old_contact, cancellable, error);
+               if (success) {
+                       ConvertData cd;
+                       const gchar *conflict_res = "AlwaysOverwrite";
 
-       /* Reset the connectable, it steals data from Authentication extension,
-          where is written incorrect address */
-       e_backend_set_connectable (E_BACKEND (object), NULL);
-}
-
-static void
-e_book_backend_ews_dispose (GObject *object)
-{
-       EBookBackendEws *bews;
-       EBookBackendEwsPrivate *priv;
-       CamelEwsSettings *ews_settings;
-
-       bews = E_BOOK_BACKEND_EWS (object);
-       priv = bews->priv;
-
-       ews_settings = book_backend_ews_get_collection_settings (bews);
-       g_signal_handlers_disconnect_by_func (ews_settings, ebews_listen_notifications_cb, bews);
-
-       if (priv->cancellable)
-               g_cancellable_cancel (priv->cancellable);
-
-       if (priv->dlock) {
-               g_mutex_lock (&priv->dlock->mutex);
-               priv->dlock->exit = TRUE;
-               g_cond_signal (&priv->dlock->cond);
-               g_mutex_unlock (&priv->dlock->mutex);
-
-               if (priv->dthread)
-                       g_thread_join (priv->dthread);
-
-               g_mutex_clear (&priv->dlock->mutex);
-               g_cond_clear (&priv->dlock->cond);
-               g_free (priv->dlock);
-               priv->dthread = NULL;
-               priv->dlock = NULL;
-       }
-
-       if (priv->cancellable) {
-               g_object_unref (priv->cancellable);
-               priv->cancellable = NULL;
-       }
+                       cd.bbews = bbews;
+                       cd.cancellable = cancellable;
+                       cd.error = error;
+                       cd.old_contact = old_contact;
+                       cd.new_contact = contact;
+                       cd.change_key = NULL;
 
-       if (priv->cnc) {
-               g_signal_handlers_disconnect_by_func (priv->cnc, ebews_server_notification_cb, bews);
+                       if (conflict_resolution == E_CONFLICT_RESOLUTION_FAIL)
+                               conflict_res = "NeverOverwrite";
 
-               if (priv->listen_notifications) {
-                       if (priv->subscription_key != 0) {
-                               e_ews_connection_disable_notifications_sync (
-                                       priv->cnc,
-                                       priv->subscription_key);
-                               priv->subscription_key = 0;
-                       }
+                       success = e_ews_connection_update_items_sync (bbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+                               conflict_res, "SendAndSaveCopy", "SendToAllAndSaveCopy",
+                               bbews->priv->folder_id, is_dl ? ebb_ews_convert_dl_to_updatexml_cb : 
ebb_ews_convert_contact_to_updatexml_cb,
+                               &cd, &items, cancellable, error);
 
-                       priv->listen_notifications = FALSE;
+                       g_free (cd.change_key);
                }
 
-               g_clear_object (&priv->cnc);
+               g_clear_object (&old_contact);
+               g_clear_object (&book_cache);
+       } else {
+               success = e_ews_connection_create_items_sync (bbews->priv->cnc, EWS_PRIORITY_MEDIUM, NULL, 
NULL,
+                       fid, is_dl ? ebb_ews_convert_dl_to_xml_cb : ebb_ews_convert_contact_to_xml_cb, 
contact,
+                       &items, cancellable, error);
        }
 
-       if (priv->ops)
-               g_hash_table_destroy (priv->ops);
-
-       g_free (priv->folder_id);
-       priv->folder_id = NULL;
+       if (success && items) {
+               EEwsItem *item = items->data;
+               const EwsId *item_id;
 
-       g_free (priv->oab_url);
-       priv->oab_url = NULL;
+               item_id = e_ews_item_get_id (item);
+               *out_new_uid = g_strdup (item_id->id);
 
-       g_free (priv->folder_name);
-       priv->folder_name = NULL;
+               /*
+                * Support for ContactPhoto was added in Exchange 2010 SP2.
+                * We don't want to try to set/get this property if we are running in older version of the 
server.
+                */
+               if (!overwrite_existing &&
+                   e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010_SP2)) {
+                       EContactPhoto *photo;
 
-       g_free (priv->attachment_dir);
-       priv->attachment_dir = NULL;
+                       /*
+                        * The contact photo is basically an attachment with a special name.
+                        * Considering this, we only can set the contact photo after create the contact 
itself.
+                        * Then we are able to attach the picture to the "Contact Item".
+                        */
+                       photo = e_contact_get (contact, E_CONTACT_PHOTO);
+                       if (photo) {
+                               GError *local_error = NULL;
 
-       if (priv->summary) {
-               g_object_unref (priv->summary);
-               priv->summary = NULL;
-       }
+                               set_photo (bbews, item_id, contact, photo, NULL, cancellable, &local_error);
+                               e_contact_photo_free (photo);
 
-       if (priv->cursors) {
-               g_list_free_full (priv->cursors, g_object_unref);
-               priv->cursors = NULL;
+                               if (local_error) {
+                                       g_propagate_error (error, local_error);
+                                       g_prefix_error (error, "%s", _("Failed to set contact photo:"));
+                                       success = FALSE;
+                               }
+                       }
+               }
        }
 
-       g_free (priv->locale);
-       priv->locale = NULL;
-
-       g_free (priv->base_directory);
-       priv->base_directory = NULL;
-
-       G_OBJECT_CLASS (e_book_backend_ews_parent_class)->dispose (object);
-}
-
-static void
-e_book_backend_ews_finalize (GObject *object)
-{
-       EBookBackendEws *bews;
+       g_slist_free_full (items, g_object_unref);
+       e_ews_folder_id_free (fid);
 
-       bews = E_BOOK_BACKEND_EWS (object);
+       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
 
-       g_rec_mutex_clear (&bews->priv->rec_mutex);
+       ebb_ews_convert_error_to_edb_error (error);
 
-       G_OBJECT_CLASS (e_book_backend_ews_parent_class)->finalize (object);
+       return success;
 }
 
-static ESourceAuthenticationResult
-e_book_backend_ews_authenticate_sync (EBackend *backend,
-                                     const ENamedParameters *credentials,
-                                     gchar **out_certificate_pem,
-                                     GTlsCertificateFlags *out_certificate_errors,
-                                     GCancellable *cancellable,
-                                     GError **error)
+static gboolean
+ebb_ews_remove_contact_sync (EBookMetaBackend *meta_backend,
+                            EConflictResolution conflict_resolution,
+                            const gchar *uid,
+                            const gchar *extra,
+                            const gchar *object,
+                            GCancellable *cancellable,
+                            GError **error)
 {
-       EBookBackendEws *ews_backend;
-       EEwsConnection *connection;
-       ESourceAuthenticationResult result;
-       CamelEwsSettings *ews_settings;
-       gchar *hosturl;
-
-       ews_backend = E_BOOK_BACKEND_EWS (backend);
-       ews_settings = book_backend_ews_get_collection_settings (ews_backend);
-       hosturl = camel_ews_settings_dup_hosturl (ews_settings);
-
-       connection = e_ews_connection_new (hosturl, ews_settings);
-
-       e_binding_bind_property (
-               ews_backend, "proxy-resolver",
-               connection, "proxy-resolver",
-               G_BINDING_SYNC_CREATE);
-
-       result = e_ews_connection_try_credentials_sync (connection, credentials, cancellable, error);
-
-       if (result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
-
-               PRIV_LOCK (ews_backend->priv);
-
-               if (ews_backend->priv->cnc != NULL)
-                       g_object_unref (ews_backend->priv->cnc);
-               ews_backend->priv->cnc = g_object_ref (connection);
-               ews_backend->priv->is_writable = !ews_backend->priv->is_gal;
-
-               g_signal_connect_swapped (
-                       ews_backend->priv->cnc,
-                       "server-notification",
-                       G_CALLBACK (ebews_server_notification_cb),
-                       backend);
-
-               PRIV_UNLOCK (ews_backend->priv);
+       EBookBackendEws *bbews;
+       GSList *ids;
+       gboolean success;
 
-               e_backend_set_online (backend, TRUE);
-               ebews_start_refreshing (ews_backend, TRUE);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (meta_backend), FALSE);
 
-               if (!ews_backend->priv->is_gal)
-                       ebews_listen_notifications_cb (ews_backend, NULL, ews_settings);
-       } else {
-               ews_backend->priv->is_writable = FALSE;
-               e_backend_set_online (backend, FALSE);
-
-               if (e_ews_connection_utils_get_without_password (ews_settings) &&
-                          result == E_SOURCE_AUTHENTICATION_REJECTED &&
-                          !e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD)) {
-                       e_ews_connection_utils_force_off_ntlm_auth_check ();
-                       result = E_SOURCE_AUTHENTICATION_REQUIRED;
-               }
-       }
+       bbews = E_BOOK_BACKEND_EWS (meta_backend);
 
-       e_book_backend_set_writable (E_BOOK_BACKEND (backend), ews_backend->priv->is_writable);
+       g_rec_mutex_lock (&bbews->priv->cnc_lock);
 
-       g_object_unref (connection);
+       ids = g_slist_prepend (NULL, (gpointer) uid);
 
-       g_free (hosturl);
+       success = e_ews_connection_delete_items_sync (bbews->priv->cnc, EWS_PRIORITY_MEDIUM, ids, 
EWS_HARD_DELETE, 0, FALSE, cancellable, error);
 
-       return result;
-}
+       g_slist_free (ids);
 
+       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
 
-static void
-cursors_contact_added (EBookBackendEws *ebews,
-                       EContact *contact)
-{
-       GList *l;
+       ebb_ews_convert_error_to_edb_error (error);
 
-       for (l = ebews->priv->cursors; l; l = l->next) {
-               EDataBookCursor *cursor = l->data;
-
-               e_data_book_cursor_contact_added (cursor, contact);
-       }
-}
-
-static void
-cursors_contact_removed (EBookBackendEws *ebews,
-                         EContact *contact)
-{
-       GList *l;
-
-       for (l = ebews->priv->cursors; l; l = l->next) {
-               EDataBookCursor *cursor = l->data;
-
-               e_data_book_cursor_contact_removed (cursor, contact);
-       }
+       return success;
 }
 
-static void
-cursors_recalculate (EBookBackendEws *ebews)
+static gboolean
+ebb_ews_search_sync (EBookMetaBackend *meta_backend,
+                    const gchar *expr,
+                    gboolean meta_contact,
+                    GSList **out_contacts,
+                    GCancellable *cancellable,
+                    GError **error)
 {
-       GList *l;
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (meta_backend), FALSE);
 
-       for (l = ebews->priv->cursors; l; l = l->next) {
-               EDataBookCursor *cursor = l->data;
+       /* Ignore errors, just try its best */
+       ebb_ews_update_cache_for_expression (E_BOOK_BACKEND_EWS (meta_backend), expr, cancellable, NULL);
 
-               e_data_book_cursor_recalculate (cursor, NULL, NULL);
-       }
+       /* Chain up to parent's method */
+       return E_BOOK_META_BACKEND_CLASS (e_book_backend_ews_parent_class)->search_sync (meta_backend, expr, 
meta_contact,
+               out_contacts, cancellable, error);
 }
 
-static EDataBookCursor *
-e_book_backend_ews_create_cursor (EBookBackend *backend,
-                                 EContactField *sort_fields,
-                                 EBookCursorSortType *sort_types,
-                                 guint n_fields,
-                                 GError **error)
+static gboolean
+ebb_ews_search_uids_sync (EBookMetaBackend *meta_backend,
+                         const gchar *expr,
+                         GSList **out_uids,
+                         GCancellable *cancellable,
+                         GError **error)
 {
-       EBookBackendEws *ebews = E_BOOK_BACKEND_EWS (backend);
-       EDataBookCursor *cursor;
-
-       PRIV_LOCK (ebews->priv);
-
-       cursor = e_data_book_cursor_sqlite_new (
-               backend,
-               ebews->priv->summary,
-               "revision",
-               sort_fields,
-               sort_types,
-               n_fields,
-               error);
-
-       if (cursor != NULL) {
-               ebews->priv->cursors =
-                       g_list_prepend (ebews->priv->cursors, cursor);
-       }
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (meta_backend), FALSE);
 
-       PRIV_UNLOCK (ebews->priv);
+       /* Ignore errors, just try its best */
+       ebb_ews_update_cache_for_expression (E_BOOK_BACKEND_EWS (meta_backend), expr, cancellable, NULL);
 
-       return cursor;
+       /* Chain up to parent's method */
+       return E_BOOK_META_BACKEND_CLASS (e_book_backend_ews_parent_class)->search_uids_sync (meta_backend, 
expr,
+               out_uids, cancellable, error);
 }
 
-static gboolean
-e_book_backend_ews_delete_cursor (EBookBackend *backend,
-                                 EDataBookCursor *cursor,
-                                 GError **error)
+static gchar *
+ebb_ews_get_backend_property (EBookBackend *book_backend,
+                             const gchar *prop_name)
 {
-       EBookBackendEws *ebews = E_BOOK_BACKEND_EWS (backend);
-       GList *link;
+       EBookBackendEws *bbews;
 
-       PRIV_LOCK (ebews->priv);
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_EWS (book_backend), NULL);
+       g_return_val_if_fail (prop_name != NULL, NULL);
 
-       link = g_list_find (ebews->priv->cursors, cursor);
+       bbews = E_BOOK_BACKEND_EWS (book_backend);
 
-       if (link != NULL) {
-               ebews->priv->cursors = g_list_delete_link (ebews->priv->cursors, link);
-               g_object_unref (cursor);
-       } else {
-               g_set_error_literal (
-                       error,
-                       E_CLIENT_ERROR,
-                       E_CLIENT_ERROR_INVALID_ARG,
-                       _("Requested to delete an unrelated cursor"));
-       }
+       if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+               CamelEwsSettings *ews_settings;
 
-       PRIV_UNLOCK (ebews->priv);
+               ews_settings = ebb_ews_get_collection_settings (bbews);
 
-       return link != NULL;
-}
+               return g_strjoin (",",
+                       "net",
+                       "contact-lists",
+                       e_book_meta_backend_get_capabilities (E_BOOK_META_BACKEND (book_backend)),
+                       (!bbews->priv->is_gal || camel_ews_settings_get_oab_offline (ews_settings)) ? 
"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)) {
+               GString *buffer;
+               gchar *fields;
+               gint ii;
 
-static gboolean
-e_book_backend_ews_set_locale (EBookBackend *backend,
-                              const gchar *locale,
-                              GCancellable *cancellable,
-                              GError **error)
-{
-       EBookBackendEws *ebews = E_BOOK_BACKEND_EWS (backend);
-       gboolean success = FALSE;
-       GList *l;
+               buffer = g_string_sized_new (1024);
 
-       PRIV_LOCK (ebews->priv);
+               for (ii = 0; ii < G_N_ELEMENTS (mappings); ii++) {
+                       if (mappings[ii].element_type != ELEMENT_TYPE_SIMPLE)
+                               continue;
 
-       if (!e_book_sqlite_lock (ebews->priv->summary, EBSQL_LOCK_WRITE, cancellable, error)) {
-               PRIV_UNLOCK (ebews->priv);
-               return FALSE;
-       }
+                       if (buffer->len > 0)
+                               g_string_append_c (buffer, ',');
+                       g_string_append (buffer, e_contact_field_name (mappings[ii].field_id));
+               }
 
-       if (e_book_sqlite_set_locale (ebews->priv->summary, locale, cancellable, error) &&
-           ebews_bump_revision (ebews, error))
-               success = e_book_sqlite_unlock (ebews->priv->summary, EBSQL_UNLOCK_COMMIT, error);
-       else
-               e_book_sqlite_unlock (ebews->priv->summary, EBSQL_UNLOCK_ROLLBACK, NULL);
+               for (ii = 0; ii < G_N_ELEMENTS (phone_field_map); ii++) {
+                       if (buffer->len > 0)
+                               g_string_append_c (buffer, ',');
+                       g_string_append (buffer, e_contact_field_name (phone_field_map[ii].field));
+               }
 
-       if (success) {
-               g_free (ebews->priv->locale);
-               ebews->priv->locale = g_strdup (locale);
-       }
+               fields = g_strjoin (
+                       ",",
+                       buffer->str,
+                       e_contact_field_name (E_CONTACT_FULL_NAME),
+                       e_contact_field_name (E_CONTACT_NICKNAME),
+                       e_contact_field_name (E_CONTACT_FAMILY_NAME),
+                       e_contact_field_name (E_CONTACT_EMAIL_1),
+                       e_contact_field_name (E_CONTACT_EMAIL_2),
+                       e_contact_field_name (E_CONTACT_EMAIL_3),
+                       e_contact_field_name (E_CONTACT_ADDRESS_WORK),
+                       e_contact_field_name (E_CONTACT_ADDRESS_HOME),
+                       e_contact_field_name (E_CONTACT_ADDRESS_OTHER),
+                       e_contact_field_name (E_CONTACT_BIRTH_DATE),
+                       e_contact_field_name (E_CONTACT_NOTE),
+                       e_contact_field_name (E_CONTACT_PHOTO),
+                       NULL);
 
-       /* This must be done outside the EBookSqlite lock,
-        * as it may try to acquire the lock as well. */
-       for (l = ebews->priv->cursors; success && l; l = l->next) {
-               EDataBookCursor *cursor = l->data;
+               g_string_free (buffer, TRUE);
 
-               success = e_data_book_cursor_load_locale (
-                       cursor, NULL, cancellable, error);
+               return fields;
        }
 
-       PRIV_UNLOCK (ebews->priv);
-
-       return success;
+       /* Chain up to parent's method. */
+       return E_BOOK_BACKEND_CLASS (e_book_backend_ews_parent_class)->get_backend_property (book_backend, 
prop_name);
 }
 
-static gchar *
-e_book_backend_ews_dup_locale (EBookBackend *backend)
+static void
+e_book_backend_ews_constructed (GObject *object)
 {
-       EBookBackendEws *ebews = E_BOOK_BACKEND_EWS (backend);
-       EBookBackendEwsPrivate *priv = ebews->priv;
-       gchar *locale;
+       EBookBackendEws *bbews = E_BOOK_BACKEND_EWS (object);
+       EBookCache *book_cache;
+       gchar *cache_dirname;
 
-       PRIV_LOCK (ebews->priv);
-       locale = g_strdup (priv->locale);
-       PRIV_UNLOCK (ebews->priv);
-
-       return locale;
-}
-
-static EDataBookDirect *
-e_book_backend_ews_get_direct_book (EBookBackend *backend)
-{
-       EDataBookDirect *direct;
-       gchar *backend_path;
-       const gchar *dirname;
-       const gchar *modules_env = NULL;
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_book_backend_ews_parent_class)->constructed (object);
 
-       modules_env = g_getenv (EDS_ADDRESS_BOOK_MODULES);
+       book_cache = e_book_meta_backend_ref_cache (E_BOOK_META_BACKEND (bbews));
 
-       dirname = e_book_backend_get_cache_dir (backend);
+       cache_dirname = g_path_get_dirname (e_cache_get_filename (E_CACHE (book_cache)));
 
-       /* Support in-tree testing / relocated modules */
-       if (modules_env)
-               backend_path = g_build_filename (modules_env, "libebookbackendews.so", NULL);
-       else
-               backend_path = g_build_filename (BACKENDDIR, "libebookbackendews.so", NULL);
-       direct = e_data_book_direct_new (backend_path, "EBookBackendEwsFactory", dirname);
+       g_clear_object (&book_cache);
 
-       g_free (backend_path);
+       bbews->priv->attachments_dir = g_build_filename (cache_dirname, "attachments", NULL);
+       g_mkdir_with_parents (bbews->priv->attachments_dir, 0777);
 
-       return direct;
+       g_free (cache_dirname);
 }
 
 static void
-e_book_backend_ews_configure_direct (EBookBackend *backend,
-                                     const gchar  *config)
+e_book_backend_ews_dispose (GObject *object)
 {
-       EBookBackendEwsPrivate *priv;
+       EBookBackendEws *bbews = E_BOOK_BACKEND_EWS (object);
+
+       g_rec_mutex_lock (&bbews->priv->cnc_lock);
+
+       g_clear_object (&bbews->priv->cnc);
 
-       priv = E_BOOK_BACKEND_EWS (backend)->priv;
-       priv->base_directory = g_strdup (config);
+       g_rec_mutex_unlock (&bbews->priv->cnc_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_book_backend_ews_parent_class)->dispose (object);
 }
 
 static void
-e_book_backend_ews_class_init (EBookBackendEwsClass *klass)
+e_book_backend_ews_finalize (GObject *object)
 {
+       EBookBackendEws *bbews = E_BOOK_BACKEND_EWS (object);
 
-       GObjectClass  *object_class = G_OBJECT_CLASS (klass);
-       EBackendClass *backend_class;
-       EBookBackendClass *parent_class;
+       g_free (bbews->priv->folder_id);
+       g_free (bbews->priv->attachments_dir);
 
-       g_type_class_add_private (klass, sizeof (EBookBackendEwsPrivate));
+       g_rec_mutex_clear (&bbews->priv->cnc_lock);
 
-       backend_class = E_BACKEND_CLASS (klass);
-       parent_class = E_BOOK_BACKEND_CLASS (klass);
-
-       /* Set the virtual methods. */
-       parent_class->open_sync               = e_book_backend_ews_open_sync;
-       parent_class->get_backend_property    = e_book_backend_ews_get_backend_property;
-
-       parent_class->create_contacts         = e_book_backend_ews_create_contacts;
-       parent_class->remove_contacts         = e_book_backend_ews_remove_contacts;
-       parent_class->modify_contacts         = e_book_backend_ews_modify_contacts;
-       parent_class->get_contact             = e_book_backend_ews_get_contact;
-       parent_class->get_contact_list        = e_book_backend_ews_get_contact_list;
-       parent_class->start_view              = e_book_backend_ews_start_view;
-       parent_class->stop_view               = e_book_backend_ews_stop_view;
-       parent_class->create_cursor           = e_book_backend_ews_create_cursor;
-       parent_class->delete_cursor           = e_book_backend_ews_delete_cursor;
-       parent_class->set_locale              = e_book_backend_ews_set_locale;
-       parent_class->dup_locale              = e_book_backend_ews_dup_locale;
-       parent_class->get_direct_book         = e_book_backend_ews_get_direct_book;
-       parent_class->configure_direct        = e_book_backend_ews_configure_direct;
-
-       backend_class->get_destination_address = e_book_backend_ews_get_destination_address;
-       backend_class->authenticate_sync = e_book_backend_ews_authenticate_sync;
-
-       object_class->constructed             = e_book_backend_ews_constructed;
-       object_class->dispose                 = e_book_backend_ews_dispose;
-       object_class->finalize                = e_book_backend_ews_finalize;
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_book_backend_ews_parent_class)->finalize (object);
 }
 
 static void
-e_book_backend_ews_initable_init (GInitableIface *iface)
+e_book_backend_ews_init (EBookBackendEws *bbews)
 {
-       iface->init = book_backend_ews_initable_init;
+       bbews->priv = G_TYPE_INSTANCE_GET_PRIVATE (bbews, E_TYPE_BOOK_BACKEND_EWS, EBookBackendEwsPrivate);
+
+       g_rec_mutex_init (&bbews->priv->cnc_lock);
 }
 
 static void
-e_book_backend_ews_init (EBookBackendEws *backend)
+e_book_backend_ews_class_init (EBookBackendEwsClass *klass)
 {
-       backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_EWS, 
EBookBackendEwsPrivate);
-       backend->priv->ops = g_hash_table_new (NULL, NULL);
+       GObjectClass *object_class;
+       EBookBackendClass *book_backend_class;
+       EBookMetaBackendClass *book_meta_backend_class;
 
-       g_rec_mutex_init (&backend->priv->rec_mutex);
-       backend->priv->cancellable = g_cancellable_new ();
+       g_type_class_add_private (klass, sizeof (EBookBackendEwsPrivate));
 
-       g_signal_connect (
-               backend, "notify::online",
-               G_CALLBACK (e_book_backend_ews_notify_online_cb), NULL);
+       book_meta_backend_class = E_BOOK_META_BACKEND_CLASS (klass);
+       book_meta_backend_class->backend_module_filename = "libebookbackendews.so";
+       book_meta_backend_class->backend_factory_type_name = "EBookBackendEwsFactory";
+       book_meta_backend_class->connect_sync = ebb_ews_connect_sync;
+       book_meta_backend_class->disconnect_sync = ebb_ews_disconnect_sync;
+       book_meta_backend_class->get_changes_sync = ebb_ews_get_changes_sync;
+       book_meta_backend_class->load_contact_sync = ebb_ews_load_contact_sync;
+       book_meta_backend_class->save_contact_sync = ebb_ews_save_contact_sync;
+       book_meta_backend_class->remove_contact_sync = ebb_ews_remove_contact_sync;
+       book_meta_backend_class->search_sync = ebb_ews_search_sync;
+       book_meta_backend_class->search_uids_sync = ebb_ews_search_uids_sync;
+
+       book_backend_class = E_BOOK_BACKEND_CLASS (klass);
+       book_backend_class->get_backend_property = ebb_ews_get_backend_property;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->constructed = e_book_backend_ews_constructed;
+       object_class->dispose = e_book_backend_ews_dispose;
+       object_class->finalize = e_book_backend_ews_finalize;
 }
diff --git a/src/addressbook/e-book-backend-ews.h b/src/addressbook/e-book-backend-ews.h
index ba1133f..ea58685 100644
--- a/src/addressbook/e-book-backend-ews.h
+++ b/src/addressbook/e-book-backend-ews.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef __E_BOOK_BACKEND_EWS_H__
-#define __E_BOOK_BACKEND_EWS_H__
+#ifndef E_BOOK_BACKEND_EWS_H
+#define E_BOOK_BACKEND_EWS_H
 
 #include <libedata-book/libedata-book.h>
 
@@ -31,19 +31,18 @@
 #define E_IS_BOOK_BACKEND_EWS(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_EWS))
 #define E_IS_BOOK_BACKEND_EWS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_EWS))
 #define E_BOOK_BACKEND_EWS_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_EWS, 
EBookBackenEwsClass))
+
 typedef struct _EBookBackendEwsPrivate EBookBackendEwsPrivate;
 
 typedef struct {
-       EBookBackend         parent_object;
+       EBookMetaBackend parent_object;
        EBookBackendEwsPrivate *priv;
 } EBookBackendEws;
 
 typedef struct {
-       EBookBackendClass parent_class;
+       EBookMetaBackendClass parent_class;
 } EBookBackendEwsClass;
 
-EBookBackend *e_book_backend_ews_new      (void);
 GType       e_book_backend_ews_get_type (void);
 
-#endif /* __E_BOOK_BACKEND_EWS_H__ */
-
+#endif /* E_BOOK_BACKEND_EWS_H */
diff --git a/src/calendar/e-cal-backend-ews-utils.c b/src/calendar/e-cal-backend-ews-utils.c
index 7c37be2..d76e2cb 100644
--- a/src/calendar/e-cal-backend-ews-utils.c
+++ b/src/calendar/e-cal-backend-ews-utils.c
@@ -865,36 +865,6 @@ ewscal_set_reccurence_exceptions (ESoapMessage *msg,
        e_soap_message_end_element (msg); /* "DeletedOccurrences" */
 }
 
-void
-ewscal_get_attach_differences (const GSList *original,
-                               const GSList *modified,
-                               GSList **removed,
-                               GSList **added)
-{
-       gboolean flag;
-       GSList *i, *i_next, *j, *j_next, *original_copy, *modified_copy;
-       original_copy = g_slist_copy ((GSList *) original);
-       modified_copy = g_slist_copy ((GSList *) modified);
-
-       for (j = modified_copy; j; j = j_next) {
-               j_next = j->next;
-
-               for (i = original_copy, flag = FALSE; !flag && i; i = i_next) {
-                       i_next = i->next;
-
-                       if (g_strcmp0 (j->data, i->data) == 0) {
-                               /* Remove from the lists attachments that are on both */
-                               original_copy = g_slist_delete_link (original_copy, i);
-                               modified_copy = g_slist_delete_link (modified_copy, j);
-                               flag = TRUE;
-                       }
-               }
-       }
-
-       *removed = original_copy;
-       *added = modified_copy;
-}
-
 /*
  * get meeting organizer e-mail address
  */
@@ -1094,7 +1064,7 @@ convert_vevent_calcomp_to_xml (ESoapMessage *msg,
        const gchar *ical_location_start, *ical_location_end, *value;
        const gchar *msdn_location_start, *msdn_location_end;
 
-       e_cal_component_set_icalcomponent (comp, icalcomp);
+       e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
 
        /* FORMAT OF A SAMPLE SOAP MESSAGE: http://msdn.microsoft.com/en-us/library/aa564690.aspx */
 
@@ -1224,6 +1194,8 @@ convert_vevent_calcomp_to_xml (ESoapMessage *msg,
        }
 
        e_soap_message_end_element (msg); /* "CalendarItem" */
+
+       g_object_unref (comp);
 }
 
 static void
@@ -1898,6 +1870,7 @@ e_cal_backend_ews_rid_to_index (icaltimezone *timezone,
                g_propagate_error (
                        error, EDC_ERROR_EX (OtherError,
                        "Invalid occurrence ID"));
+               index = 0;
        }
 
        return index;
diff --git a/src/calendar/e-cal-backend-ews-utils.h b/src/calendar/e-cal-backend-ews-utils.h
index 0427a2f..521e0e8 100644
--- a/src/calendar/e-cal-backend-ews-utils.h
+++ b/src/calendar/e-cal-backend-ews-utils.h
@@ -61,7 +61,6 @@ void ewscal_set_timezone (ESoapMessage *msg, const gchar *name, EEwsCalendarTime
 void ewscal_set_meeting_timezone (ESoapMessage *msg, icaltimezone *icaltz);
 void ewscal_set_reccurence (ESoapMessage *msg, icalproperty *rrule, icaltimetype *dtstart);
 void ewscal_set_reccurence_exceptions (ESoapMessage *msg, icalcomponent *comp);
-void ewscal_get_attach_differences (const GSList *original, const GSList *modified, GSList **removed, GSList 
**added);
 gchar *e_ews_extract_attachment_id_from_uri (const gchar *uri);
 void ews_set_alarm (ESoapMessage *msg, ECalComponent *comp);
 gint ews_get_alarm (ECalComponent *comp);
diff --git a/src/calendar/e-cal-backend-ews.c b/src/calendar/e-cal-backend-ews.c
index b32837a..57495a6 100644
--- a/src/calendar/e-cal-backend-ews.c
+++ b/src/calendar/e-cal-backend-ews.c
@@ -1,7 +1,7 @@
 /* -*- 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 version 2 of the GNU Lesser General Public
@@ -63,37 +63,17 @@
 
 /* Private part of the CalBackendEws structure */
 struct _ECalBackendEwsPrivate {
-       /* Fields required for online server requests */
+       GRecMutex cnc_lock;
        EEwsConnection *cnc;
        gchar *folder_id;
-       gchar *user_email;
-       gchar *storage_path;
-
-       ECalBackendStore *store;
-       gboolean read_only;
-
-       /* A mutex to control access to the private structure for the following */
-       GRecMutex rec_mutex;
-       icaltimezone *default_zone;
-       guint refresh_timeout;
-       guint refreshing;
-       EFlag *refreshing_done;
-       GHashTable *item_id_hash;
-
-       GMutex cancellable_lock;
-       GCancellable *cancellable;
 
        guint subscription_key;
-       gboolean listen_notifications;
        gboolean is_freebusy_calendar;
-};
 
-#define PRIV_LOCK(p)   (g_rec_mutex_lock (&(p)->rec_mutex))
-#define PRIV_UNLOCK(p) (g_rec_mutex_unlock (&(p)->rec_mutex))
+       gchar *attachments_dir;
+};
 
-#define SYNC_KEY "sync-state"
 #define EWS_MAX_FETCH_COUNT 100
-#define REFRESH_INTERVAL 600
 
 #define GET_ITEMS_SYNC_PROPERTIES \
        "item:Attachments" \
@@ -116,7 +96,6 @@ struct _ECalBackendEwsPrivate {
        " calendar:StartTimeZone" \
        " calendar:EndTimeZone"
 
-
 #define e_data_cal_error_if_fail(expr, _code)                                  \
        G_STMT_START {                                                          \
                if (G_LIKELY (expr)) {                                          \
@@ -132,15 +111,10 @@ struct _ECalBackendEwsPrivate {
                }                                                               \
        } G_STMT_END
 
-/* Forward Declarations */
-static void ews_cal_component_get_item_id (ECalComponent *comp, gchar **itemid, gchar **changekey);
-static gboolean ews_start_sync (gpointer data);
-static gpointer ews_start_sync_thread (gpointer data);
-
-G_DEFINE_TYPE (ECalBackendEws, e_cal_backend_ews, E_TYPE_CAL_BACKEND)
+G_DEFINE_TYPE (ECalBackendEws, e_cal_backend_ews, E_TYPE_CAL_META_BACKEND)
 
 static CamelEwsSettings *
-cal_backend_ews_get_collection_settings (ECalBackendEws *backend)
+ecb_ews_get_collection_settings (ECalBackendEws *cbews)
 {
        ESource *source;
        ESource *collection;
@@ -149,8 +123,8 @@ cal_backend_ews_get_collection_settings (ECalBackendEws *backend)
        CamelSettings *settings;
        const gchar *extension_name;
 
-       source = e_backend_get_source (E_BACKEND (backend));
-       registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));
+       source = e_backend_get_source (E_BACKEND (cbews));
+       registry = e_cal_backend_get_registry (E_CAL_BACKEND (cbews));
 
        extension_name = e_source_camel_get_extension_name ("ews");
        e_source_camel_generate_subtype ("ews", CAMEL_TYPE_EWS_SETTINGS);
@@ -169,13 +143,11 @@ cal_backend_ews_get_collection_settings (ECalBackendEws *backend)
 }
 
 static void
-convert_error_to_edc_error (GError **perror)
+ecb_ews_convert_error_to_edc_error (GError **perror)
 {
        GError *error = NULL;
 
-       g_return_if_fail (perror != NULL);
-
-       if (!*perror || (*perror)->domain == E_DATA_CAL_ERROR)
+       if (!perror || !*perror || (*perror)->domain == E_DATA_CAL_ERROR)
                return;
 
        if ((*perror)->domain == EWS_CONNECTION_ERROR) {
@@ -194,1412 +166,1763 @@ convert_error_to_edc_error (GError **perror)
                        error = EDC_ERROR_EX (ObjectNotFound, (*perror)->message);
                        break;
                }
-       }
 
-       if (!error)
-               error = EDC_ERROR_EX (OtherError, (*perror)->message);
+               if (!error)
+                       error = EDC_ERROR_EX (OtherError, (*perror)->message);
+       }
 
-       g_error_free (*perror);
-       *perror = error;
+       if (error) {
+               g_error_free (*perror);
+               *perror = error;
+       }
 }
 
-static GCancellable *
-cal_backend_ews_ref_cancellable (ECalBackendEws *cbews)
+static void
+ecb_ews_server_notification_cb (ECalBackendEws *cbews,
+                               GSList *events,
+                               EEwsConnection *cnc)
 {
-       GCancellable *cancellable = NULL;
+       GSList *link;
+       gboolean update_folder = FALSE;
 
-       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cbews), NULL);
+       g_return_if_fail (cbews != NULL);
+       g_return_if_fail (cbews->priv != NULL);
 
-       g_mutex_lock (&cbews->priv->cancellable_lock);
-       if (cbews->priv->cancellable)
-               cancellable = g_object_ref (cbews->priv->cancellable);
-       g_mutex_unlock (&cbews->priv->cancellable_lock);
+       for (link = events; link && !update_folder; link = g_slist_next (link)) {
+               EEwsNotificationEvent *event = link->data;
+
+               switch (event->type) {
+                       case E_EWS_NOTIFICATION_EVENT_CREATED:
+                       case E_EWS_NOTIFICATION_EVENT_DELETED:
+                       case E_EWS_NOTIFICATION_EVENT_MODIFIED:
+                               g_rec_mutex_lock (&cbews->priv->cnc_lock);
+                               if (g_strcmp0 (event->folder_id, cbews->priv->folder_id) == 0)
+                                       update_folder = TRUE;
+                               g_rec_mutex_unlock (&cbews->priv->cnc_lock);
+                               break;
+                       case E_EWS_NOTIFICATION_EVENT_MOVED:
+                       case E_EWS_NOTIFICATION_EVENT_COPIED:
+                               g_rec_mutex_lock (&cbews->priv->cnc_lock);
+                               if (g_strcmp0 (event->folder_id, cbews->priv->folder_id) == 0 ||
+                                   g_strcmp0 (event->old_folder_id, cbews->priv->folder_id) == 0)
+                                       update_folder = TRUE;
+                               g_rec_mutex_unlock (&cbews->priv->cnc_lock);
+                               break;
+                       default:
+                               return;
+               }
+       }
 
-       return cancellable;
+       if (update_folder)
+               e_cal_meta_backend_schedule_refresh (E_CAL_META_BACKEND (cbews));
 }
 
 static void
-cal_backend_ews_set_cancellable (ECalBackendEws *cbews,
-                                GCancellable *cancellable)
+ecb_ews_unset_connection (ECalBackendEws *cbews)
 {
-       GCancellable *old_cancellable;
-
        g_return_if_fail (E_IS_CAL_BACKEND_EWS (cbews));
 
-       g_mutex_lock (&cbews->priv->cancellable_lock);
-       old_cancellable = cbews->priv->cancellable;
-       cbews->priv->cancellable = cancellable;
-       g_mutex_unlock (&cbews->priv->cancellable_lock);
+       g_rec_mutex_lock (&cbews->priv->cnc_lock);
+
+       if (cbews->priv->cnc) {
+               g_signal_handlers_disconnect_by_func (cbews->priv->cnc, ecb_ews_server_notification_cb, 
cbews);
 
-       if (old_cancellable) {
-               g_cancellable_cancel (old_cancellable);
-               g_object_unref (old_cancellable);
+               if (cbews->priv->subscription_key != 0) {
+                       e_ews_connection_disable_notifications_sync (
+                               cbews->priv->cnc,
+                               cbews->priv->subscription_key);
+                       cbews->priv->subscription_key = 0;
+               }
        }
+
+       g_rec_mutex_unlock (&cbews->priv->cnc_lock);
 }
 
-static void
-switch_offline (ECalBackendEws *cbews)
+static icaltimezone *
+ecb_ews_get_timezone (ETimezoneCache *timezone_cache,
+                     const gchar *msdn_tzid,
+                     const gchar *tzid,
+                     const gchar *evo_ews_tzid)
 {
-       ECalBackendEwsPrivate *priv;
+       icaltimezone *zone = NULL;
+       const gchar *evo_ews_msdn_tzid;
 
-       priv= cbews->priv;
-       priv->read_only = TRUE;
+       zone = e_timezone_cache_get_timezone (timezone_cache, tzid);
+       if (zone == NULL)
+               zone = icaltimezone_get_builtin_timezone (tzid);
 
-       if (priv->refresh_timeout) {
-               g_source_remove (priv->refresh_timeout);
-               priv->refresh_timeout = 0;
-       }
+       if (g_strcmp0 (tzid, evo_ews_tzid) == 0)
+               return zone;
 
-       cal_backend_ews_set_cancellable (cbews, NULL);
+       if (evo_ews_tzid != NULL) {
+               evo_ews_msdn_tzid = e_cal_backend_ews_tz_util_get_msdn_equivalent (evo_ews_tzid);
 
-       if (priv->cnc) {
-               g_object_unref (priv->cnc);
-               priv->cnc = NULL;
+               if (g_strcmp0 (msdn_tzid, evo_ews_msdn_tzid) == 0) {
+                       zone = e_timezone_cache_get_timezone (timezone_cache, evo_ews_tzid);
+                       if (zone == NULL)
+                               zone = icaltimezone_get_builtin_timezone (evo_ews_tzid);
+               }
        }
+
+       return zone;
 }
 
-static gboolean
-cal_backend_ews_ensure_connected (ECalBackendEws *cbews,
-                                 GCancellable *cancellable,
-                                 GError **perror)
+static icalparameter *
+ecb_ews_responsetype_to_partstat (const gchar *responsetype)
 {
+       icalparameter *param = NULL;
+
+       g_return_val_if_fail (responsetype != NULL, NULL);
+
+       if (g_ascii_strcasecmp (responsetype, "Organizer") == 0)
+               param = icalparameter_new_partstat (ICAL_PARTSTAT_ACCEPTED);
+       else if (g_ascii_strcasecmp (responsetype, "Tentative") == 0)
+               param = icalparameter_new_partstat (ICAL_PARTSTAT_TENTATIVE);
+       else if (g_ascii_strcasecmp (responsetype, "Accept") == 0)
+               param = icalparameter_new_partstat (ICAL_PARTSTAT_ACCEPTED);
+       else if (g_ascii_strcasecmp (responsetype, "Decline") == 0)
+               param = icalparameter_new_partstat (ICAL_PARTSTAT_DECLINED);
+       else if (g_ascii_strcasecmp (responsetype, "NoResponseReceived") == 0)
+               param = icalparameter_new_partstat (ICAL_PARTSTAT_NEEDSACTION);
+       else if (g_ascii_strcasecmp (responsetype, "Unknown") == 0)
+               param = icalparameter_new_partstat (ICAL_PARTSTAT_NONE);
+
+       if (!param)
+               param = icalparameter_new_partstat (ICAL_PARTSTAT_NONE);
+
+       return param;
+}
+
+static ECalComponent *
+ecb_ews_item_to_component_sync (ECalBackendEws *cbews,
+                               EEwsItem *item,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       ECalComponent *res_component = NULL;
+       ETimezoneCache *timezone_cache;
+       icalcomponent_kind kind;
+       EEwsItemType item_type;
+       icalcomponent *icalcomp, *vcomp;
+       icaltimezone *utc_zone = icaltimezone_get_utc_timezone ();
        CamelEwsSettings *ews_settings;
-       GError *local_error = NULL;
+       const gchar *mime_content;
 
-       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cbews), FALSE);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cbews), NULL);
+       g_return_val_if_fail (E_IS_EWS_ITEM (item), NULL);
 
-       PRIV_LOCK (cbews->priv);
+       timezone_cache = E_TIMEZONE_CACHE (cbews);
 
-       if (cbews->priv->cnc) {
-               PRIV_UNLOCK (cbews->priv);
-               return TRUE;
-       }
+       kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbews));
+       ews_settings = ecb_ews_get_collection_settings (cbews);
+
+       item_type = e_ews_item_get_item_type (item);
+       if (item_type == E_EWS_ITEM_TYPE_TASK || item_type == E_EWS_ITEM_TYPE_MEMO) {
+               icalproperty *icalprop;
+               icaltimetype due_date, start_date, complete_date, created;
+               icalproperty_status status  = ICAL_STATUS_NONE;
+               icalproperty_class class = ICAL_CLASS_NONE;
+               const gchar *ews_task_status, *sensitivity;
+               EwsImportance item_importance;
+               gint priority = 5;
+               gboolean has_this_date = FALSE;
+
+               vcomp = icalcomponent_new (ICAL_VCALENDAR_COMPONENT);
+               /*subject*/
+               icalcomp = icalcomponent_new (item_type == E_EWS_ITEM_TYPE_TASK ? ICAL_VTODO_COMPONENT : 
ICAL_VJOURNAL_COMPONENT);
+               icalprop = icalproperty_new_summary (e_ews_item_get_subject (item));
+               icalcomponent_add_property (icalcomp, icalprop);
+
+               /*date time created*/
+               created = icaltime_from_timet_with_zone (e_ews_item_get_date_created (item), 0, utc_zone);
+               icalprop = icalproperty_new_created (created);
+               icalcomponent_add_property (icalcomp, icalprop);
+
+               /*sensitivity*/
+               sensitivity = e_ews_item_get_sensitivity (item);
+               if (g_strcmp0 (sensitivity, "Normal") == 0)
+                       class = ICAL_CLASS_PUBLIC;
+               else if (g_strcmp0 (sensitivity, "Private") == 0)
+                       class = ICAL_CLASS_PRIVATE;
+               else if ((g_strcmp0 (sensitivity, "Confidential") == 0) ||
+                        (g_strcmp0 (sensitivity, "Personal") == 0))
+                       class = ICAL_CLASS_CONFIDENTIAL;
+               icalprop = icalproperty_new_class (class);
+               icalcomponent_add_property (icalcomp, icalprop);
+
+               /*description*/
+               icalprop = icalproperty_new_description (e_ews_item_get_body (item));
+               icalcomponent_add_property (icalcomp, icalprop);
+
+               /*task assaingments*/
+               if (e_ews_item_get_delegator (item) != NULL) {
+                       const gchar *task_owner = e_ews_item_get_delegator (item);
+                       GSList *mailboxes = NULL, *l;
+                       gboolean includes_last_item;
+                       gchar *mailtoname, *user_email;
+                       icalparameter *param;
+
+                       /*The task owner according to Exchange is current user, even that the task was 
assigned by
+                        *someone else. I'm making the current user attendee and task delegator will be a 
task organizer */
+
+                       user_email = camel_ews_settings_dup_email (ews_settings);
+                       mailtoname = g_strdup_printf ("mailto:%s";, user_email);
+                       icalprop = icalproperty_new_attendee (mailtoname);
+                       g_free (mailtoname);
+                       g_free (user_email);
+
+                       param = icalparameter_new_cn (e_ews_item_get_owner (item));
+                       icalproperty_add_parameter (icalprop, param);
+                       icalcomponent_add_property (icalcomp, icalprop);
+
+                       /* get delegator mail box*/
+                       e_ews_connection_resolve_names_sync (
+                               cbews->priv->cnc, EWS_PRIORITY_MEDIUM, task_owner,
+                               EWS_SEARCH_AD, NULL, FALSE, &mailboxes, NULL,
+                               &includes_last_item, cancellable, error);
+
+                       for (l = mailboxes; l != NULL; l = g_slist_next (l)) {
+                               EwsMailbox *mb = l->data;
+
+                               mailtoname = g_strdup_printf ("mailto:%s";, mb->email);
+                               icalprop = icalproperty_new_organizer (mailtoname);
+                               param = icalparameter_new_cn (mb->name);
+                               icalproperty_add_parameter (icalprop, param);
+                               icalcomponent_add_property (icalcomp, icalprop);
+
+                               g_free (mailtoname);
+                               e_ews_mailbox_free (mb);
+                       }
+                       g_slist_free (mailboxes);
+               }
+
+               if (item_type == E_EWS_ITEM_TYPE_TASK) {
+                       const gchar *percent_complete;
+
+                       /*start date*/
+                       has_this_date = FALSE;
+                       e_ews_item_task_has_start_date (item, &has_this_date);
+                       if (has_this_date) {
+                               start_date = icaltime_from_timet_with_zone (e_ews_item_get_start_date (item), 
0, utc_zone);
+                               start_date.is_date = 1;
+                               icalprop = icalproperty_new_dtstart (start_date);
+                               icalcomponent_add_property (icalcomp, icalprop);
+                       }
+
+                       /*status*/
+                       ews_task_status = e_ews_item_get_status (item);
+                       if (g_strcmp0 (ews_task_status, "NotStarted") != 0) {
+                               if (g_strcmp0 (ews_task_status, "Completed") == 0)
+                                       status = ICAL_STATUS_COMPLETED;
+                               else if (g_strcmp0 (ews_task_status, "InProgress") == 0)
+                                       status = ICAL_STATUS_INPROCESS;
+                               else if (g_strcmp0 (ews_task_status, "WaitingOnOthers") == 0)
+                                       status = ICAL_STATUS_NEEDSACTION;
+                               else if (g_strcmp0 (ews_task_status, "Deferred") == 0)
+                                       status = ICAL_STATUS_CANCELLED;
+                               icalprop = icalproperty_new_status (status);
+                               icalcomponent_add_property (icalcomp, icalprop);
+                       }
+
+                       /*precent complete*/
+                       percent_complete = e_ews_item_get_percent_complete (item);
+                       icalprop  = icalproperty_new_percentcomplete (atoi (percent_complete ? 
percent_complete : "0"));
+                       icalcomponent_add_property (icalcomp, icalprop);
 
-       PRIV_UNLOCK (cbews->priv);
+                       /*due date*/
+                       e_ews_item_task_has_due_date (item, &has_this_date);
+                       if (has_this_date) {
+                               due_date = icaltime_from_timet_with_zone (e_ews_item_get_due_date (item), 0, 
utc_zone);
+                               due_date.is_date = 1;
+                               icalprop = icalproperty_new_due (due_date);
+                               icalcomponent_add_property (icalcomp, icalprop);
+                       }
+
+                       /*complete date*/
+                       has_this_date = FALSE;
+                       e_ews_item_task_has_complete_date (item, &has_this_date);
+                       if (has_this_date) {
+                               complete_date = icaltime_from_timet_with_zone (e_ews_item_get_complete_date 
(item), 0, utc_zone);
+                               complete_date.is_date = 1;
+                               icalprop = icalproperty_new_completed (complete_date);
+                               icalcomponent_add_property (icalcomp, icalprop);
+                       }
 
-       ews_settings = cal_backend_ews_get_collection_settings (cbews);
+                       /*priority*/
+                       item_importance = e_ews_item_get_importance (item);
+                       if (item_importance == EWS_ITEM_HIGH)
+                               priority = 3;
+                       else if (item_importance == EWS_ITEM_LOW)
+                               priority = 7;
+                       icalprop = icalproperty_new_priority (priority);
+                       icalcomponent_add_property (icalcomp, icalprop);
+               }
 
-       if (e_ews_connection_utils_get_without_password (ews_settings)) {
-               e_backend_schedule_authenticate (E_BACKEND (cbews), NULL);
+               icalcomponent_add_component (vcomp, icalcomp);
        } else {
-               e_backend_credentials_required_sync (E_BACKEND (cbews),
-                       E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL,
-                       cancellable, &local_error);
-       }
+               struct icaltimetype dt;
+               const gchar *tzid;
+               gboolean timezone_set = FALSE;
 
-       if (!local_error)
-               return TRUE;
+               mime_content = e_ews_item_get_mime_content (item);
+               vcomp = icalparser_parse_string (mime_content);
 
-       g_propagate_error (perror, local_error);
+               if (!vcomp && mime_content) {
+                       const gchar *begin_vcalendar, *end_vcalendar;
 
-       return FALSE;
-}
+                       /* Workaround Exchange 2016 error, which returns invalid iCalendar object (without 
'END:VCALENDAR'),
+                          when the event has at least one detached instance. */
+                       begin_vcalendar = camel_strstrcase (mime_content, "BEGIN:VCALENDAR");
+                       end_vcalendar = camel_strstrcase (mime_content, "END:VCALENDAR");
 
-static void
-e_cal_backend_ews_add_timezone (ECalBackend *backend,
-                                EDataCal *cal,
-                                guint32 context,
-                                GCancellable *cancellable,
-                                const gchar *tzobj)
-{
-       ETimezoneCache *timezone_cache;
-       icalcomponent *tz_comp;
-       ECalBackendEws *cbews;
-       GError *error = NULL;
+                       /* If it exists, then it should be alone on a separate line */
+                       if (!(begin_vcalendar && (begin_vcalendar == mime_content || begin_vcalendar[-1] == 
'\n') &&
+                           (begin_vcalendar[15 /* strlen ("BEGIN:VCALENDAR") */] == '\r' || 
begin_vcalendar[15] == '\n')))
+                               begin_vcalendar = NULL;
 
-       cbews = (ECalBackendEws *) backend;
-       timezone_cache = E_TIMEZONE_CACHE (backend);
+                       /* If it exists, then it should be alone on a separate line and not at the very 
beginning of the mime_content */
+                       if (!(end_vcalendar && end_vcalendar > mime_content && end_vcalendar[-1] == '\n' &&
+                           (end_vcalendar[13 /* strlen ("END:VCALENDAR") */] == '\r' || end_vcalendar[13] == 
'\n' || end_vcalendar[13] == '\0')))
+                               end_vcalendar = NULL;
 
-       e_data_cal_error_if_fail (E_IS_CAL_BACKEND_EWS (cbews), InvalidArg);
-       e_data_cal_error_if_fail (tzobj != NULL, InvalidArg);
+                       if (begin_vcalendar && !end_vcalendar) {
+                               gchar *str;
 
-       tz_comp = icalparser_parse_string (tzobj);
-       if (!tz_comp) {
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
-       }
+                               str = g_strconcat (mime_content, "\r\n", "END:VCALENDAR", "\r\n", NULL);
+                               vcomp = icalparser_parse_string (str);
+                               g_free (str);
+                       }
+               }
 
-       if (icalcomponent_isa (tz_comp) == ICAL_VTIMEZONE_COMPONENT) {
-               icaltimezone *zone;
+               if (!vcomp) {
+                       g_warn_if_reached ();
+                       return NULL;
+               }
 
-               zone = icaltimezone_new ();
-               icaltimezone_set_component (zone, tz_comp);
-               e_timezone_cache_add_timezone (timezone_cache, zone);
-               icaltimezone_free (zone, 1);
-       }
+               tzid = e_ews_item_get_tzid (item);
+               if (tzid == NULL) {
+                       /*
+                        * When we are working with Exchange server 2010 or newer, we have to handle a few
+                        * things more than we do working old servers. These things are:
+                        * - MSDN timezone names:
+                        *   Used setting StartTimeZone and EndTimeZone. MSDN timezone names are not
+                        *   the same used in libical, so we need to have a table of equivalence to
+                        *   convert from one to another and avoid show the MSDN timezone name to the
+                        *   user and save it in the ETimezoneCache.
+                        * - EvoEWSStartTimeZone/EvoEWSEndTimeZone
+                        *   Used to keep track if the timezone shown to the user is the same one set
+                        *   by him/her. As we have a table of equivalence, sometimes the user sets a
+                        *   timezone but without EvoEWSStartTiemZone property, another timezone name,
+                        *   in the same offset, can be shown. And we want to avoid this.
+                        * - DTEND property:
+                        *   As we have to work with DTEND setting an event when using EWS server 2010 or
+                        *   newer, we have to care about set it properly here, instead of use the same
+                        *   as is used in DTSTART.
+                        */
+                       icaltimezone *start_zone, *end_zone;
+                       const gchar *start_tzid, *end_tzid;
+                       const gchar *ical_start_tzid, *ical_end_tzid;
+                       const gchar *evo_ews_start_tzid, *evo_ews_end_tzid;
 
-exit:
-       /*FIXME pass tzid here */
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_add_timezone (cal, context, error);
-}
+                       start_tzid = e_ews_item_get_start_tzid (item);
+                       end_tzid = e_ews_item_get_end_tzid (item);
 
-typedef enum {
-       E_EWS_ATTACHMENT_TYPE_NOTHING = 0,
-       E_EWS_ATTACHMENT_TYPE_CREATE,
-       E_EWS_ATTACHMENT_TYPE_UPDATE
-} EEwsAttachmentType;
-
-typedef struct {
-       ECalBackendEws *cbews; /* Create, Remove, Modify, FreeBusy, Attachments, DiscardAlarm */
-       GCancellable *cancellable;
-       ECalComponent *comp; /* Create, Remove, Modify, FreeBusy, Attachments */
-       ECalComponent *extra_comp; /* Modify, Attachments: used as old_comp. Remove: used as parent_comp */
-       EDataCal *cal; /* Create, Remove, Modify, FreeBusy, Attachments, DiscardAlarm */
-       GSList *users; /* FreeBusy */
-       gchar *item_id; /* Accept, Remove, Modify, Attachments, DiscardAlarm */
-       gchar *uid; /* Remove */
-       gchar *rid; /* Remove */
-       EEwsAttachmentType cb_type; /* Attachments */
-       ECalObjModType mod; /* Remove */
-       guint32 context; /* Create, Remove, Modify, FreeBusy, Attachments, DiscardAlarm */
-} EwsCalendarAsyncData;
+                       ical_start_tzid = e_cal_backend_ews_tz_util_get_ical_equivalent (start_tzid);
+                       ical_end_tzid = e_cal_backend_ews_tz_util_get_ical_equivalent (end_tzid);
 
-static void
-e_cal_backend_ews_async_data_free (EwsCalendarAsyncData *async_data)
-{
-       if (async_data != NULL) {
-               g_clear_object (&async_data->cbews);
-               g_clear_object (&async_data->cancellable);
-               g_clear_object (&async_data->comp);
-               g_clear_object (&async_data->extra_comp);
-               g_clear_object (&async_data->cal);
-
-               g_slist_free_full (async_data->users, g_free);
-               g_free (async_data->item_id);
-               g_free (async_data->uid);
-               g_free (async_data->rid);
-
-               g_free (async_data);
-       }
-}
+                       evo_ews_start_tzid = e_ews_item_get_iana_start_time_zone (item);
+                       evo_ews_end_tzid = e_ews_item_get_iana_end_time_zone (item);
 
-static void
-ews_cal_discard_alarm_cb (GObject *object,
-                          GAsyncResult *res,
-                          gpointer user_data)
-{
-       EEwsConnection *cnc = E_EWS_CONNECTION (object);
-       EwsCalendarAsyncData *edad = user_data;
-       GError *error = NULL;
+                       /*
+                        * We have a few timezones that don't have an equivalent MSDN timezone.
+                        * For those, we will get ical_start_tzid being NULL and then we need to use
+                        * start_tzid, which one has the libical's expected name.
+                        */
+                       start_zone = ecb_ews_get_timezone (
+                               timezone_cache,
+                               start_tzid,
+                               ical_start_tzid != NULL ? ical_start_tzid : start_tzid,
+                               evo_ews_start_tzid);
+                       end_zone = ecb_ews_get_timezone (
+                               timezone_cache,
+                               end_tzid,
+                               ical_end_tzid != NULL ? ical_end_tzid : end_tzid,
+                               evo_ews_end_tzid);
 
-       if (!e_ews_connection_update_items_finish (cnc, res, NULL, &error)) {
-               convert_error_to_edc_error (&error);
-       }
+                       if (start_zone != NULL) {
+                               icalcomp = icalcomponent_get_first_component (vcomp, kind);
 
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_discard_alarm (edad->cal, edad->context, error);
+                               dt = icalcomponent_get_dtstart (icalcomp);
+                               dt = icaltime_convert_to_zone (dt, start_zone);
+                               icalcomponent_set_dtstart (icalcomp, dt);
 
-       e_cal_backend_ews_async_data_free (edad);
-}
+                               timezone_set = TRUE;
+                               e_timezone_cache_add_timezone (timezone_cache, start_zone);
 
-static void
-e_cal_backend_ews_discard_alarm (ECalBackend *backend,
-                                 EDataCal *cal,
-                                 guint32 context,
-                                 GCancellable *cancellable,
-                                 const gchar *uid,
-                                 const gchar *rid,
-                                 const gchar *auid)
-{
-       ECalBackendEws *cbews = (ECalBackendEws *) backend;
-       ECalBackendEwsPrivate *priv;
-       EwsCalendarAsyncData *edad;
-       EwsCalendarConvertData convert_data = { 0 };
-       ECalComponent *comp;
-       GError *local_error = NULL;
+                               if (end_zone != NULL) {
+                                       dt = icalcomponent_get_dtend (icalcomp);
+                                       dt = icaltime_convert_to_zone (dt, end_zone);
+                                       icalcomponent_set_dtend (icalcomp, dt);
 
-       priv = cbews->priv;
+                                       e_timezone_cache_add_timezone (timezone_cache, end_zone);
+                               }
+                       }
 
-       PRIV_LOCK (priv);
+                       if (!timezone_set)
+                               tzid = start_tzid;
+               }
 
-       comp = e_cal_backend_store_get_component (priv->store, uid, NULL);
-       if (!comp) {
-               e_data_cal_respond_discard_alarm (
-                       cal, context,
-                       EDC_ERROR (ObjectNotFound));
-               PRIV_UNLOCK (priv);
-               return;
-       }
+               if (!timezone_set && tzid) {
+                       /*
+                        * When we are working with Exchange server older than 2010, we don't set different
+                        * DTSTART and DTEND properties in VTIMEZONE. The reason of that is we don't use
+                        * those properties settings/changing a meeting timezone.
+                        * So, for older servers, here, we only set the DTSTART and DTEND properties with
+                        * the same values.
+                        */
+                       icaltimezone *zone;
+                       gchar *new_tzid = NULL;
 
-       PRIV_UNLOCK (priv);
+                       icalcomp = icalcomponent_get_first_component (vcomp, kind);
 
-       if (!cbews->priv->cnc) {
-               e_data_cal_respond_discard_alarm (cal, context, EDC_ERROR (RepositoryOffline));
-               return;
-       }
+                       if (!icaltimezone_get_builtin_timezone (tzid) &&
+                           icalcomponent_get_uid (icalcomp)) {
+                               icalcomponent *vtimezone;
 
-       if (!cal_backend_ews_ensure_connected (cbews, cancellable, &local_error)) {
-               convert_error_to_edc_error (&local_error);
-               e_data_cal_respond_discard_alarm (cal, context, local_error);
-               return;
-       }
+                               /* Add the timezone */
+                               vtimezone = icalcomponent_get_first_component (vcomp, 
ICAL_VTIMEZONE_COMPONENT);
+                               if (vtimezone != NULL) {
+                                       icalproperty *prop;
 
-       /* FIXME: Can't there be multiple alarms for each event? Or does
-        * Exchange not support that? */
-       edad = g_new0 (EwsCalendarAsyncData, 1);
-       edad->cbews = g_object_ref (cbews);
-       edad->cancellable = cal_backend_ews_ref_cancellable (cbews);
-       edad->cal = g_object_ref (cal);
-       edad->context = context;
+                                       new_tzid = g_strconcat ("/evolution/ews/tzid/", icalcomponent_get_uid 
(icalcomp), NULL);
 
-       if (e_cal_component_has_recurrences (comp)) {
-               gint *index;
+                                       zone = icaltimezone_new ();
+                                       vtimezone = icalcomponent_new_clone (vtimezone);
+                                       prop = icalcomponent_get_first_property (vtimezone, 
ICAL_TZID_PROPERTY);
+                                       if (prop) {
+                                               icalproperty_set_tzid (prop, new_tzid);
 
-               convert_data.change_type = E_EWS_ITEMCHANGE_TYPE_OCCURRENCEITEM;
-               e_cal_component_get_sequence (comp, &index);
+                                               prop = icalcomponent_get_first_property (vtimezone, 
ICAL_LOCATION_PROPERTY);
+                                               if (!prop) {
+                                                       /* Use the original tzid as the timezone Location, to 
not expose
+                                                          evolution-ews TZID. */
+                                                       prop = icalproperty_new_location (tzid);
+                                                       icalcomponent_add_property (vtimezone, prop);
+                                               }
+                                       } else {
+                                               g_free (new_tzid);
+                                               new_tzid = NULL;
+                                       }
+                                       icaltimezone_set_component (zone, vtimezone);
+                                       e_timezone_cache_add_timezone (timezone_cache, zone);
+                                       icaltimezone_free (zone, TRUE);
+                               }
+                       }
 
-               if (index != NULL) {
-                       /*Microsoft is counting the occurrences starting from 1
-                        where EcalComponent is starting from zerro */
-                       convert_data.index = *index + 1;
-                       e_cal_component_free_sequence (index);
-               } else {
-                       convert_data.change_type = E_EWS_ITEMCHANGE_TYPE_ITEM;
-                       convert_data.index = -1;
+                       zone = e_timezone_cache_get_timezone (timezone_cache, new_tzid ? new_tzid : tzid);
+
+                       if (!zone && new_tzid)
+                               zone = e_timezone_cache_get_timezone (timezone_cache, tzid);
+
+                       if (zone == NULL)
+                               zone = icaltimezone_get_builtin_timezone (tzid);
+
+                       if (zone != NULL) {
+                               dt = icalcomponent_get_dtstart (icalcomp);
+                               dt = icaltime_convert_to_zone (dt, zone);
+                               icalcomponent_set_dtstart (icalcomp, dt);
+
+                               dt = icalcomponent_get_dtend (icalcomp);
+                               dt = icaltime_convert_to_zone (dt, zone);
+                               icalcomponent_set_dtend (icalcomp, dt);
+                       }
+
+                       g_free (new_tzid);
                }
-       } else {
-               convert_data.change_type = E_EWS_ITEMCHANGE_TYPE_ITEM;
-               convert_data.index = -1;
        }
 
-       ews_cal_component_get_item_id (comp, &convert_data.item_id, &convert_data.change_key);
+       /* Vevent or Vtodo */
+       icalcomp = icalcomponent_get_first_component (vcomp, kind);
+       if (icalcomp) {
+               icalproperty *icalprop, *freebusy;
+               const EwsId *item_id;
+               const GSList *l = NULL;
+               const gchar *uid = e_ews_item_get_uid (item);
+               gchar *user_email;
 
-       e_ews_connection_update_items (
-               priv->cnc, EWS_PRIORITY_MEDIUM,
-               "AlwaysOverwrite", NULL,
-               "SendToNone", NULL,
-               e_cal_backend_ews_clear_reminder_is_set,
-               &convert_data,
-               edad->cancellable,
-               ews_cal_discard_alarm_cb,
-               edad);
-}
+               item_id = e_ews_item_get_id (item);
+               user_email = camel_ews_settings_dup_email (ews_settings);
 
-static gchar *
-cal_backend_ews_get_builtin_zone_object (const gchar *tzid)
-{
-       icalcomponent *icalcomp = NULL, *free_comp = NULL;
-       icaltimezone *zone;
-       gchar *object = NULL;
+               /* Attendees */
+               for (l = e_ews_item_get_attendees (item); l != NULL; l = g_slist_next (l)) {
+                       icalparameter *param, *cu_type;
+                       gchar *mailtoname;
+                       const gchar *email = NULL;
+                       EwsAttendee *attendee = (EwsAttendee *) l->data;
 
-       zone = icaltimezone_get_builtin_timezone (tzid);
-       if (!zone) {
-               icalcomp = free_comp = icaltzutil_fetch_timezone (tzid);
-       }
+                       if (!attendee->mailbox)
+                               continue;
 
-       if (zone)
-               icalcomp = icaltimezone_get_component (zone);
+                       if (g_strcmp0 (attendee->mailbox->routing_type, "EX") == 0)
+                               email = e_ews_item_util_strip_ex_address (attendee->mailbox->email);
 
-       if (icalcomp) {
-               icalcomponent *clone = icalcomponent_new_clone (icalcomp);
-               icalproperty *prop;
+                       mailtoname = g_strdup_printf ("mailto:%s";, email ? email : attendee->mailbox->email);
+                       icalprop = icalproperty_new_attendee (mailtoname);
+                       g_free (mailtoname);
+
+                       param = icalparameter_new_cn (attendee->mailbox->name);
+                       icalproperty_add_parameter (icalprop, param);
 
-               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);
+                       if (g_ascii_strcasecmp (attendee->attendeetype, "Required") == 0) {
+                               param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT);
+                               cu_type = icalparameter_new_cutype (ICAL_CUTYPE_INDIVIDUAL);
+                       }
+                       else if (g_ascii_strcasecmp (attendee->attendeetype, "Resource") == 0) {
+                               param = icalparameter_new_role (ICAL_ROLE_NONPARTICIPANT);
+                               cu_type = icalparameter_new_cutype (ICAL_CUTYPE_RESOURCE);
+                       }
+                       else {
+                               param = icalparameter_new_role ( ICAL_ROLE_OPTPARTICIPANT);
+                               cu_type = icalparameter_new_cutype (ICAL_CUTYPE_INDIVIDUAL);
+                       }
+                       icalproperty_add_parameter (icalprop, cu_type);
+                       icalproperty_add_parameter (icalprop, param);
 
-                       object = icalcomponent_as_ical_string_r (clone);
+                       if (user_email && (email || attendee->mailbox->email) && 
e_ews_item_get_my_response_type (item) &&
+                           g_ascii_strcasecmp (email ? email : attendee->mailbox->email, user_email) == 0) {
+                               param = ecb_ews_responsetype_to_partstat (e_ews_item_get_my_response_type 
(item));
+                       } else {
+                               param = ecb_ews_responsetype_to_partstat (attendee->responsetype);
+                       }
+                       icalproperty_add_parameter (icalprop, param);
+
+                       icalcomponent_add_property (icalcomp, icalprop);
                }
-               icalcomponent_free (clone);
-       }
 
-       if (free_comp)
-               icalcomponent_free (free_comp);
+               g_free (user_email);
 
-       return object;
-}
+               /* Free/Busy */
+               freebusy = icalcomponent_get_first_property (icalcomp, ICAL_TRANSP_PROPERTY);
+               if (!freebusy && (e_ews_item_get_item_type (item) != E_EWS_ITEM_TYPE_TASK)) {
+                       /* Busy by default */
+                       freebusy = icalproperty_new_transp (ICAL_TRANSP_OPAQUE);
+                       icalcomponent_add_property (icalcomp, freebusy);
+               }
+               for (icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
+                    icalprop != NULL;
+                    icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
+                       if (g_strcmp0 (icalproperty_get_x_name (icalprop), "X-MICROSOFT-CDO-BUSYSTATUS") == 
0) {
+                               if (g_strcmp0 (icalproperty_get_value_as_string (icalprop), "BUSY") == 0) {
+                                       icalproperty_set_transp (freebusy, ICAL_TRANSP_OPAQUE);
+                               } else {
+                                       icalproperty_set_transp (freebusy, ICAL_TRANSP_TRANSPARENT);
+                               }
 
-static void
-e_cal_backend_ews_get_timezone (ECalBackend *backend,
-                                EDataCal *cal,
-                                guint32 context,
-                                GCancellable *cancellable,
-                                const gchar *tzid)
-{
-       ETimezoneCache *timezone_cache;
-       icalcomponent *icalcomp;
-       icaltimezone *zone;
-       gchar *object = NULL;
-       GError *error = NULL;
+                               break;
+                       }
+               }
 
-       timezone_cache = E_TIMEZONE_CACHE (backend);
+               /* AllDayEvent */
+               for (icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
+                    icalprop != NULL;
+                    icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
+                       if (g_strcmp0 (icalproperty_get_x_name (icalprop), "X-MICROSOFT-CDO-ALLDAYEVENT") == 
0) {
+                               if (g_strcmp0 (icalproperty_get_value_as_string (icalprop), "TRUE") == 0) {
+                                       struct icaltimetype dtend, dtstart;
+                                       dtstart = icalcomponent_get_dtstart (icalcomp);
+                                       dtstart.is_date = 1;
+                                       icalcomponent_set_dtstart (icalcomp, dtstart);
 
-       zone = e_timezone_cache_get_timezone (timezone_cache, tzid);
-       if (zone) {
-               icalcomp = icaltimezone_get_component (zone);
+                                       dtend = icalcomponent_get_dtend (icalcomp);
+                                       dtend.is_date = 1;
+                                       icalcomponent_set_dtend (icalcomp, dtend);
+                               }
+                               break;
+                       }
+               }
 
-               if (!icalcomp)
-                       g_propagate_error (&error, e_data_cal_create_error (InvalidObject, NULL));
-               else
-                       object = icalcomponent_as_ical_string_r (icalcomp);
-       } else {
-               /* TODO Implement in ECalBackend base class */
-               /* fallback if tzid contains only the location of timezone */
-               gint i, slashes = 0;
+               if (icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY)) {
+                       /* Exchange sets RRULE even on the children, which is broken */
+                       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY);
+                       if (icalprop) {
+                               icalcomponent_remove_property (icalcomp, icalprop);
+                               icalproperty_free (icalprop);
+                       }
+               }
 
-               for (i = 0; tzid[i]; i++) {
-                       if (tzid[i] == '/')
-                               slashes++;
+               /* Exchange sets an ORGANIZER on all events. RFC2445 says:
+                *
+                *   This property MUST NOT be specified in an iCalendar
+                *   object that specifies only a time zone definition or
+                *   that defines calendar entities that are not group
+                *   scheduled entities, but are entities only on a single
+                *   user's calendar.
+                */
+               if (!icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) {
+                       if ((icalprop = icalcomponent_get_first_property (icalcomp, 
ICAL_ORGANIZER_PROPERTY))) {
+                               icalcomponent_remove_property (icalcomp, icalprop);
+                               icalproperty_free (icalprop);
+                       }
                }
 
-               if (slashes == 1)
-                       object = cal_backend_ews_get_builtin_zone_object (tzid);
+               icalcomponent_set_uid (icalcomp, uid ? uid : item_id->id);
 
-               if (!object) {
-                       /* The timezone can be sometimes the Windows zone, try to convert it to libical */
-                       const gchar *ical_location = e_cal_backend_ews_tz_util_get_ical_equivalent (tzid);
-                       if (ical_location) {
-                               object = cal_backend_ews_get_builtin_zone_object (ical_location);
+               e_cal_util_set_x_property (icalcomp, "X-EVOLUTION-ITEMID", item_id->id);
+               e_cal_util_set_x_property (icalcomp, "X-EVOLUTION-CHANGEKEY", item_id->change_key);
+
+               res_component = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (icalcomp));
+
+               /* Categories */
+               e_cal_component_set_categories_list (res_component, (GSList *) e_ews_item_get_categories 
(item));
+
+               /*
+                * There is no API to set/get alarm description on the server side.
+                * However, for some reason, the alarm description has been set to "REMINDER"
+                * automatically (and with no i18n). Instead of show it to the user, let's
+                * set the summary as the alarm description.
+                */
+               if (e_cal_component_has_alarms (res_component)) {
+                       GList *alarm_uids, *l;
+
+                       alarm_uids = e_cal_component_get_alarm_uids (res_component);
+                       for (l = alarm_uids; l != NULL; l = l->next) {
+                               ECalComponentAlarm *alarm;
+                               ECalComponentText text;
+
+                               alarm = e_cal_component_get_alarm (res_component, l->data);
+                               e_cal_component_get_summary (res_component, &text);
+                               e_cal_component_alarm_set_description (alarm, &text);
+
+                               e_cal_component_alarm_free (alarm);
                        }
+                       cal_obj_uid_list_free (alarm_uids);
                }
        }
 
-       if (!object && !error)
-               g_propagate_error (&error, e_data_cal_create_error (ObjectNotFound, NULL));
+       icalcomponent_free (vcomp);
 
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_get_timezone (cal, context, error, object);
-       g_free (object);
+       if (res_component) {
+               const GSList *attachment_ids, *aid, *l;
+               const gchar *uid = NULL;
+               GSList *info_attachments = NULL, *uris = NULL;
+               gboolean has_attachment = FALSE;
+
+               e_ews_item_has_attachments (item, &has_attachment);
+               if (!has_attachment)
+                       return res_component;
+
+               e_cal_component_get_uid (res_component, &uid);
+
+               attachment_ids = e_ews_item_get_attachments_ids (item);
+
+               if (e_ews_connection_get_attachments_sync (
+                       cbews->priv->cnc,
+                       EWS_PRIORITY_MEDIUM,
+                       uid,
+                       attachment_ids,
+                       cbews->priv->attachments_dir,
+                       TRUE,
+                       &info_attachments,
+                       NULL, NULL,
+                       cancellable,
+                       NULL)) {
+                       icalcomponent *icalcomp;
+                       icalproperty *icalprop;
+                       icalparameter *icalparam;
 
-}
+                       for (l = info_attachments; l; l = l->next) {
+                               EEwsAttachmentInfo *info = l->data;
 
-/* changekey can be NULL if you don't want it. itemid cannot. */
-static void
-ews_cal_component_get_item_id (ECalComponent *comp,
-                               gchar **itemid,
-                               gchar **changekey)
-{
-       icalproperty *prop;
-       gchar *ck = NULL;
-       gchar *id = NULL;
+                               /* ignore non-uri attachments, because it's an exception */
+                               if (e_ews_attachment_info_get_type (info) == E_EWS_ATTACHMENT_INFO_TYPE_URI) {
+                                       const gchar *uri = e_ews_attachment_info_get_uri (info);
 
-       prop = icalcomponent_get_first_property (
-               e_cal_component_get_icalcomponent (comp),
-               ICAL_X_PROPERTY);
-       while (prop) {
-               const gchar *x_name, *x_val;
+                                       if (uri)
+                                               uris = g_slist_append (uris, g_strdup (uri));
+                               }
+                       }
 
-               x_name = icalproperty_get_x_name (prop);
-               x_val = icalproperty_get_x (prop);
-               if (!id && !g_ascii_strcasecmp (x_name, "X-EVOLUTION-ITEMID"))
-                       id = g_strdup (x_val);
-                else if (changekey && !ck && !g_ascii_strcasecmp (x_name, "X-EVOLUTION-CHANGEKEY"))
-                       ck = g_strdup (x_val);
+                       e_cal_component_set_attachment_list (res_component, uris);
 
-               prop = icalcomponent_get_next_property (
-                       e_cal_component_get_icalcomponent (comp),
-                       ICAL_X_PROPERTY);
+                       icalcomp = e_cal_component_get_icalcomponent (res_component);
+                       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_ATTACH_PROPERTY);
+                       for (aid = attachment_ids; aid && icalprop; aid = aid->next, icalprop = 
icalcomponent_get_next_property (icalcomp, ICAL_ATTACH_PROPERTY)) {
+                               icalparam = icalparameter_new_x (aid->data);
+                               icalparameter_set_xname (icalparam, "X-EWS-ATTACHMENTID");
+                               icalproperty_add_parameter (icalprop, icalparam);
+                       }
+
+                       g_slist_free_full (uris, g_free);
+                       g_slist_free_full (info_attachments, (GDestroyNotify) e_ews_attachment_info_free);
+               }
        }
 
-       *itemid = id;
-       if (changekey)
-               *changekey = ck;
+       return res_component;
 }
 
-/* changekey can be NULL if you don't want it. itemid cannot. */
-static void
-ews_cal_component_get_calendar_item_accept_id (ECalComponent *comp,
-                                               gchar **itemid,
-                                               gchar **changekey,
-                                              gchar **mail_id)
+static gboolean
+ecb_ews_get_items_sync (ECalBackendEws *cbews,
+                       const GSList *item_ids, /* gchar * */
+                       const gchar *default_props,
+                       const EEwsAdditionalProps *add_props,
+                       GSList **out_components, /* ECalComponent * */
+                       GCancellable *cancellable,
+                       GError **error)
 {
-       icalproperty *prop;
-       gchar *id_item = NULL;
-       gchar *id_accept = NULL;
-       gchar *ck = NULL;
+       GSList *items = NULL, *link;
+       gboolean success;
 
-       prop = icalcomponent_get_first_property (
-               e_cal_component_get_icalcomponent (comp),
-               ICAL_X_PROPERTY);
-       while (prop) {
-               const gchar *x_name, *x_val;
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cbews), FALSE);
+       g_return_val_if_fail (out_components != NULL, FALSE);
 
-               x_name = icalproperty_get_x_name (prop);
-               x_val = icalproperty_get_x (prop);
-               if (!id_item && g_ascii_strcasecmp (x_name, "X-EVOLUTION-ITEMID") == 0)
-                       id_item = g_strdup (x_val);
-               else if (!id_accept && g_ascii_strcasecmp (x_name, "X-EVOLUTION-ACCEPT-ID") == 0)
-                       id_accept = g_strdup (x_val);
-               else if (changekey && !ck && !g_ascii_strcasecmp (x_name, "X-EVOLUTION-CHANGEKEY"))
-                       ck = g_strdup (x_val);
+       success = e_ews_connection_get_items_sync (
+               cbews->priv->cnc,
+               EWS_PRIORITY_MEDIUM,
+               item_ids,
+               default_props,
+               add_props,
+               FALSE,
+               NULL,
+               E_EWS_BODY_TYPE_TEXT,
+               &items,
+               NULL, NULL,
+               cancellable,
+               error);
 
-               prop = icalcomponent_get_next_property (
-                       e_cal_component_get_icalcomponent (comp),
-                       ICAL_X_PROPERTY);
-       }
+       if (!success)
+               return FALSE;
 
-       if (!id_item)
-               id_item = g_strdup (id_accept);
+       /* fetch modified occurrences */
+       for (link = items; link; link = g_slist_next (link)) {
+               EEwsItem *item = link->data;
+               const GSList *modified_occurrences;
 
-       *itemid = id_item;
-       *mail_id = id_accept;
-       if (changekey)
-               *changekey = ck;
-}
+               if (!item || e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR)
+                       continue;
 
-static void
-add_comps_to_item_id_hash (ECalBackendEws *cbews)
-{
-       ECalBackendEwsPrivate *priv;
-       GSList *comps, *l;
+               modified_occurrences = e_ews_item_get_modified_occurrences (item);
+               if (modified_occurrences) {
+                       EEwsAdditionalProps *modified_add_props;
 
-       priv = cbews->priv;
+                       modified_add_props = e_ews_additional_props_new ();
+                       if (e_ews_connection_satisfies_server_version (cbews->priv->cnc, 
E_EWS_EXCHANGE_2010)) {
+                               EEwsExtendedFieldURI *ext_uri;
 
-       PRIV_LOCK (priv);
+                               modified_add_props->field_uri = g_strdup (GET_ITEMS_SYNC_PROPERTIES_2010);
 
-       comps = e_cal_backend_store_get_components (priv->store);
-       for (l = comps; l != NULL; l = g_slist_next (l)) {
-               ECalComponent *comp = (ECalComponent *) l->data;
-               gchar *item_id = NULL;
+                               ext_uri = e_ews_extended_field_uri_new ();
+                               ext_uri->distinguished_prop_set_id = g_strdup ("PublicStrings");
+                               ext_uri->prop_name = g_strdup ("EvolutionEWSStartTimeZone");
+                               ext_uri->prop_type = g_strdup ("String");
+                               modified_add_props->extended_furis = g_slist_append 
(modified_add_props->extended_furis, ext_uri);
 
-               ews_cal_component_get_item_id (comp, &item_id, NULL);
-               if (!item_id) {
-                       const gchar *uid;
+                               ext_uri = e_ews_extended_field_uri_new ();
+                               ext_uri->distinguished_prop_set_id = g_strdup ("PublicStrings");
+                               ext_uri->prop_name = g_strdup ("EvolutionEWSEndTimeZone");
+                               ext_uri->prop_type = g_strdup ("String");
+                               modified_add_props->extended_furis = g_slist_append 
(modified_add_props->extended_furis, ext_uri);
+                       } else {
+                               modified_add_props->field_uri = g_strdup (GET_ITEMS_SYNC_PROPERTIES_2007);
+                       }
+
+                       success = ecb_ews_get_items_sync (cbews, modified_occurrences, "IdOnly", 
modified_add_props, out_components, cancellable, error);
+
+                       e_ews_additional_props_free (modified_add_props);
+
+                       if (!success)
+                               goto exit;
+               }
+       }
 
-                       /* This should never happen, but sometimes when our
-                        * use of X- fields has changed it has triggered. Make
-                        * it cope, and not crash */
-                       e_cal_component_get_uid (comp, &uid);
-                       g_warning (
-                               "EWS calendar item %s had no EWS ItemID!",
-                               uid);
+       for (link = items; link; link = g_slist_next (link)) {
+               EEwsItem *item = link->data;
+
+               if (!item)
                        continue;
+
+               if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR) {
+                       g_propagate_error (error, g_error_copy (e_ews_item_get_error (item)));
+                       success = FALSE;
+                       break;
+               } else {
+                       ECalComponent *comp;
+
+                       comp = ecb_ews_item_to_component_sync (cbews, item, cancellable, error);
+                       if (!comp) {
+                               success = FALSE;
+                               break;
+                       }
+
+                       *out_components = g_slist_prepend (*out_components, comp);
                }
-               g_hash_table_insert (priv->item_id_hash, item_id, comp);
        }
 
-       PRIV_UNLOCK (priv);
+ exit:
+       g_slist_free_full (items, g_object_unref);
 
-       g_slist_free (comps);
+       return success;
 }
 
-static gpointer
-handle_notifications_thread (gpointer data)
+static gboolean
+ecb_ews_fetch_items_sync (ECalBackendEws *cbews,
+                         const GSList *items, /* EEwsItem * */
+                         GSList **out_components, /* ECalComponent * */
+                         GCancellable *cancellable,
+                         GError **error)
 {
-       ECalBackendEws *cbews = data;
+       GSList *event_ids = NULL, *task_memo_ids = NULL, *link;
+       gboolean success = TRUE;
 
-       PRIV_LOCK (cbews->priv);
+       for (link = (GSList *) items; link; link = g_slist_next (link)) {
+               EEwsItem *item = link->data;
+               const EwsId *id = e_ews_item_get_id (item);
+               EEwsItemType type = e_ews_item_get_item_type (item);
 
-       if (cbews->priv->cnc == NULL)
-               goto exit;
+               if (type == E_EWS_ITEM_TYPE_EVENT)
+                       event_ids = g_slist_prepend (event_ids, g_strdup (id->id));
+               else if (type == E_EWS_ITEM_TYPE_TASK || type == E_EWS_ITEM_TYPE_MEMO) {
+                       task_memo_ids = g_slist_prepend (task_memo_ids, g_strdup (id->id));
+               }
+       }
 
-       if (cbews->priv->listen_notifications) {
-               GSList *folders = NULL;
+       if (event_ids) {
+               EEwsAdditionalProps *add_props;
 
-               if (cbews->priv->subscription_key != 0)
-                       goto exit;
+               add_props = e_ews_additional_props_new ();
+               if (e_ews_connection_satisfies_server_version (cbews->priv->cnc, E_EWS_EXCHANGE_2010)) {
+                       EEwsExtendedFieldURI *ext_uri;
 
-               folders = g_slist_prepend (folders, cbews->priv->folder_id);
+                       add_props->field_uri = g_strdup (GET_ITEMS_SYNC_PROPERTIES_2010);
 
-               e_ews_connection_enable_notifications_sync (
-                               cbews->priv->cnc,
-                               folders,
-                               &cbews->priv->subscription_key);
+                       ext_uri = e_ews_extended_field_uri_new ();
+                       ext_uri->distinguished_prop_set_id = g_strdup ("PublicStrings");
+                       ext_uri->prop_name = g_strdup ("EvolutionEWSStartTimeZone");
+                       ext_uri->prop_type = g_strdup ("String");
+                       add_props->extended_furis = g_slist_append (add_props->extended_furis, ext_uri);
 
-               g_slist_free (folders);
-       } else {
-               if (cbews->priv->subscription_key == 0)
-                       goto exit;
+                       ext_uri = e_ews_extended_field_uri_new ();
+                       ext_uri->distinguished_prop_set_id = g_strdup ("PublicStrings");
+                       ext_uri->prop_name = g_strdup ("EvolutionEWSEndTimeZone");
+                       ext_uri->prop_type = g_strdup ("String");
+                       add_props->extended_furis = g_slist_append (add_props->extended_furis, ext_uri);
+               } else {
+                       add_props->field_uri = g_strdup (GET_ITEMS_SYNC_PROPERTIES_2007);
+               }
 
-               e_ews_connection_disable_notifications_sync (
-                               cbews->priv->cnc,
-                               cbews->priv->subscription_key);
+               success = ecb_ews_get_items_sync (cbews, event_ids, "IdOnly", add_props, out_components, 
cancellable, error);
 
-               cbews->priv->subscription_key = 0;
+               e_ews_additional_props_free (add_props);
        }
 
-exit:
-       PRIV_UNLOCK (cbews->priv);
-       g_object_unref (cbews);
-       return NULL;
+       if (task_memo_ids && success)
+               success = ecb_ews_get_items_sync (cbews, task_memo_ids, "AllProperties", NULL, 
out_components, cancellable, error);
+
+       g_slist_free_full (event_ids, g_free);
+       g_slist_free_full (task_memo_ids, g_free);
+
+       return success;
 }
 
-static void
-cbews_listen_notifications_cb (ECalBackendEws *cbews,
-                              GParamSpec *spec,
-                              CamelEwsSettings *ews_settings)
+static gboolean
+ecb_ews_freebusy_ecomp_changed (ECalComponent *ecomp,
+                               icalcomponent *vevent)
 {
-       GThread *thread;
+       icalcomponent *icomp;
+       gboolean changed = FALSE;
 
-       PRIV_LOCK (cbews->priv);
-       if (cbews->priv->cnc == NULL) {
-               PRIV_UNLOCK (cbews->priv);
-               return;
-       }
+       g_return_val_if_fail (vevent != NULL, FALSE);
 
-       if (!e_ews_connection_satisfies_server_version (cbews->priv->cnc, E_EWS_EXCHANGE_2010_SP1)) {
-               PRIV_UNLOCK (cbews->priv);
-               return;
-       }
+       if (!ecomp)
+               return TRUE;
 
-       cbews->priv->listen_notifications = !cbews->priv->is_freebusy_calendar && 
camel_ews_settings_get_listen_notifications (ews_settings);
-       PRIV_UNLOCK (cbews->priv);
+       icomp = e_cal_component_get_icalcomponent (ecomp);
+       if (!icomp)
+               return TRUE;
+
+       if (!changed)
+               changed = g_strcmp0 (icalcomponent_get_summary (icomp), icalcomponent_get_summary (vevent)) 
!= 0;
+       if (!changed)
+               changed = g_strcmp0 (icalcomponent_get_location (icomp), icalcomponent_get_location (vevent)) 
!= 0;
+       if (!changed)
+               changed = icaltime_compare (icalcomponent_get_dtstart (icomp), icalcomponent_get_dtstart 
(vevent)) != 0;
+       if (!changed)
+               changed = icaltime_compare (icalcomponent_get_dtend (icomp), icalcomponent_get_dtend 
(vevent)) != 0;
 
-       thread = g_thread_new (NULL, handle_notifications_thread, g_object_ref (cbews));
-       g_thread_unref (thread);
+       return changed;
 }
 
-static void
-cbews_server_notification_cb (ECalBackendEws *cbews,
-                             GSList *events,
-                             EEwsConnection *cnc)
+static GSList * /* the possibly modified 'in_items' */
+ecb_ews_verify_changes (ECalCache *cal_cache,
+                       icalcomponent_kind kind,
+                       GSList *in_items, /* EEwsItem * */
+                       GCancellable *cancellable)
 {
-       GSList *l;
-       gboolean update_folder = FALSE;
+       GSList *items = NULL, *link;
 
-       g_return_if_fail (cbews != NULL);
-       g_return_if_fail (cbews->priv != NULL);
+       g_return_val_if_fail (E_IS_CAL_CACHE (cal_cache), in_items);
 
-       for (l = events; l != NULL; l = l->next) {
-               EEwsNotificationEvent *event = l->data;
+       for (link = in_items; link; link = g_slist_next (link)) {
+               EEwsItem *item = link->data;
+               const EwsId *id = e_ews_item_get_id (item);
+               EEwsItemType type = e_ews_item_get_item_type (item);
 
-               switch (event->type) {
-                       case E_EWS_NOTIFICATION_EVENT_CREATED:
-                       case E_EWS_NOTIFICATION_EVENT_DELETED:
-                       case E_EWS_NOTIFICATION_EVENT_MODIFIED:
-                               PRIV_LOCK (cbews->priv);
-                               if (g_strcmp0 (event->folder_id, cbews->priv->folder_id) == 0)
-                                       update_folder = TRUE;
-                               PRIV_UNLOCK (cbews->priv);
-                               break;
-                       case E_EWS_NOTIFICATION_EVENT_MOVED:
-                       case E_EWS_NOTIFICATION_EVENT_COPIED:
-                               PRIV_LOCK (cbews->priv);
-                               if (g_strcmp0 (event->folder_id, cbews->priv->folder_id) == 0 ||
-                                   g_strcmp0 (event->old_folder_id, cbews->priv->folder_id) == 0)
-                                       update_folder = TRUE;
-                               PRIV_UNLOCK (cbews->priv);
-                               break;
-                       default:
-                               return;
+               if (!g_cancellable_is_cancelled (cancellable) && (
+                   (type == E_EWS_ITEM_TYPE_EVENT && kind == ICAL_VEVENT_COMPONENT) ||
+                   (type == E_EWS_ITEM_TYPE_MEMO && kind == ICAL_VJOURNAL_COMPONENT) ||
+                   (type == E_EWS_ITEM_TYPE_TASK && kind == ICAL_VTODO_COMPONENT) )) {
+                       ECalComponent *existing = NULL;
+
+                       if (e_cal_cache_get_component (cal_cache, id->id, NULL, &existing, cancellable, NULL) 
&&
+                           existing && g_strcmp0 (e_cal_util_get_x_property 
(e_cal_component_get_icalcomponent (existing),
+                           "X-EVOLUTION-CHANGEKEY"), id->change_key) == 0) {
+                               g_object_unref (item);
+                       } else {
+                               items = g_slist_prepend (items, item);
+                       }
+
+                       g_clear_object (&existing);
+               } else if (type == E_EWS_ITEM_TYPE_EVENT ||
+                          type == E_EWS_ITEM_TYPE_MEMO ||
+                          type == E_EWS_ITEM_TYPE_TASK) {
+                       g_object_unref (item);
+               } else {
+                       items = g_slist_prepend (items, item);
                }
        }
 
-       if (update_folder)
-               ews_start_sync (cbews);
+       g_slist_free (in_items);
+
+       return items;
 }
 
-static void
-e_cal_backend_ews_open (ECalBackend *backend,
-                        EDataCal *cal,
-                        guint32 opid,
-                        GCancellable *cancellable,
-                        gboolean only_if_exists)
+static GSList * /* ECalMetaBackendInfo */
+ecb_ews_components_to_infos (ECalMetaBackend *meta_backend,
+                            const GSList *components, /* ECalComponent * */
+                            icalcomponent_kind kind)
 {
-       CamelEwsSettings *ews_settings;
-       ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-       ESource *source;
-       const gchar *cache_dir;
-       gboolean need_to_authenticate;
-       gboolean ret = TRUE;
-       GError *error = NULL;
+       GSList *nfos = NULL, *link;
+       GHashTable *sorted_by_uids; /* gchar * ~> GSList { ECalComponent * } */
+       GHashTableIter iter;
+       gpointer key, value;
 
-       if (e_cal_backend_is_opened (backend))
-               return;
+       sorted_by_uids = g_hash_table_new (g_str_hash, g_str_equal);
 
-       cbews = (ECalBackendEws *) backend;
-       priv = cbews->priv;
+       for (link = (GSList *) components; link; link = g_slist_next (link)) {
+               ECalComponent *comp = link->data;
+               icalcomponent *icomp;
+               const gchar *uid;
+               GSList *instances;
 
-       cache_dir = e_cal_backend_get_cache_dir (backend);
-       source = e_backend_get_source (E_BACKEND (cbews));
-       ews_settings = cal_backend_ews_get_collection_settings (cbews);
+               if (!comp)
+                       continue;
 
-       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
+               icomp = e_cal_component_get_icalcomponent (comp);
+               uid = icalcomponent_get_uid (icomp);
 
-       PRIV_LOCK (priv);
+               if (!uid)
+                       continue;
 
-       if (!priv->store) {
-               ESourceEwsFolder *extension;
-               const gchar *extension_name;
+               instances = g_hash_table_lookup (sorted_by_uids, uid);
+               g_hash_table_insert (sorted_by_uids, (gpointer) uid, g_slist_prepend (instances, comp));
+       }
 
-               extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
-               extension = e_source_get_extension (source, extension_name);
-               priv->folder_id = e_source_ews_folder_dup_id (extension);
-               priv->is_freebusy_calendar = g_strcmp0 (priv->folder_id, "freebusy-calendar") == 0;
+       g_hash_table_iter_init (&iter, sorted_by_uids);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               const gchar *uid = key;
+               GSList *instances = value, *link;
+               icalcomponent *icomp, *merged;
+               ECalComponent *comp;
+               ECalMetaBackendInfo *nfo;
+               const gchar *revision, *itemid;
 
-               priv->storage_path = g_build_filename (cache_dir, priv->folder_id, NULL);
+               if (!uid || !instances) {
+                       g_slist_free (instances);
+                       continue;
+               }
 
-               priv->store = e_cal_backend_store_new (
-                       priv->storage_path,
-                       E_TIMEZONE_CACHE (backend));
-               e_cal_backend_store_load (priv->store);
-               add_comps_to_item_id_hash (cbews);
+               /* Try to find master object, to have seves marter's itemid in ECalMetaBackendInfo::extra,
+                  thus the re-load of the event is done for the whole series and not for a detached instance 
*/
+               comp = NULL;
+               for (link = instances; link && !comp; link = g_slist_next (link)) {
+                       comp = link->data;
 
-               if (priv->default_zone)
-                       e_cal_backend_store_set_default_timezone (
-                               priv->store, priv->default_zone);
-       }
+                       if (!comp)
+                               continue;
+
+                       if (e_cal_component_is_instance (comp))
+                               comp = NULL;
+               }
 
-       need_to_authenticate =
-               (priv->cnc == NULL) &&
-               (e_backend_is_destination_reachable (E_BACKEND (backend), cancellable, NULL));
+               if (!comp)
+                       comp = instances->data;
 
-       PRIV_UNLOCK (priv);
+               if (!comp) {
+                       g_slist_free (instances);
+                       continue;
+               }
 
-       if (cbews->priv->cnc)
-               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
-       else
-               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+               icomp = e_cal_component_get_icalcomponent (comp);
+               itemid = e_cal_util_get_x_property (icomp, "X-EVOLUTION-ITEMID");
+               revision = e_cal_util_get_x_property (icomp, "X-EVOLUTION-CHANGEKEY");
+               merged = e_cal_meta_backend_merge_instances (meta_backend, instances, FALSE);
 
-       if (need_to_authenticate)
-               ret = cal_backend_ews_ensure_connected (cbews, cancellable, &error);
+               if (!merged) {
+                       g_warn_if_fail (merged != NULL);
+                       g_slist_free (instances);
+                       continue;
+               }
 
-       if (ret) {
-               e_cal_backend_set_writable (backend, !priv->is_freebusy_calendar);
+               nfo = e_cal_meta_backend_info_new (uid, revision, NULL, itemid);
+               nfo->object = icalcomponent_as_ical_string_r (merged);
 
-               PRIV_LOCK (priv);
-               if (priv->cnc != NULL) {
-                       priv->listen_notifications = !priv->is_freebusy_calendar && 
camel_ews_settings_get_listen_notifications (ews_settings);
+               nfos = g_slist_prepend (nfos, nfo);
 
-                       if (priv->listen_notifications)
-                               cbews_listen_notifications_cb (cbews, NULL, ews_settings);
-               }
-               PRIV_UNLOCK (priv);
+               icalcomponent_free (merged);
+               g_slist_free (instances);
        }
 
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_open (cal, opid, error);
+       g_hash_table_destroy (sorted_by_uids);
 
-       g_signal_connect_swapped (
-               ews_settings,
-               "notify::listen-notifications",
-               G_CALLBACK (cbews_listen_notifications_cb),
-               cbews);
+       return nfos;
 }
 
 static void
-e_cal_backend_ews_get_object (ECalBackend *backend,
-                              EDataCal *cal,
-                              guint32 context,
-                              GCancellable *cancellable,
-                              const gchar *uid,
-                              const gchar *rid)
+ecb_ews_extract_item_id (ECalComponent *comp,
+                        gchar **out_id,
+                        gchar **out_change_key)
 {
-       ECalBackendEwsPrivate *priv;
-       ECalBackendEws *cbews = (ECalBackendEws *) backend;
-       gchar *object = NULL;
-       GError *error = NULL;
-
-       e_data_cal_error_if_fail (E_IS_CAL_BACKEND_EWS (cbews), InvalidArg);
+       icalcomponent *icalcomp;
 
-       priv = cbews->priv;
+       g_return_if_fail (E_IS_CAL_COMPONENT (comp));
 
-       PRIV_LOCK (priv);
+       icalcomp = e_cal_component_get_icalcomponent (comp);
+       g_return_if_fail (icalcomp != NULL);
 
-       if (e_backend_get_online (E_BACKEND (backend))) {
-               /* make sure any pending refreshing is done */
-               while (priv->refreshing) {
-                       PRIV_UNLOCK (priv);
-                       e_flag_wait (priv->refreshing_done);
-                       PRIV_LOCK (priv);
-               }
-       }
+       if (out_id)
+               *out_id = e_cal_util_dup_x_property (icalcomp, "X-EVOLUTION-ITEMID");
+       if (out_change_key)
+               *out_change_key = e_cal_util_dup_x_property (icalcomp, "X-EVOLUTION-CHANGEKEY");
+}
 
-       /* search the object in the cache */
-       if (rid && *rid) {
-               ECalComponent *comp;
+static gboolean
+ecb_ews_is_organizer (ECalBackendEws *cbews,
+                     ECalComponent *comp)
+{
+       ECalComponentOrganizer organizer;
+       gboolean is_organizer = FALSE;
 
-               comp = e_cal_backend_store_get_component (priv->store, uid, rid);
-               if (!comp && e_backend_get_online (E_BACKEND (backend))) {
-                       /* maybe a meeting invitation, for which the calendar item is not downloaded yet,
-                        * thus synchronize local cache first */
-                       ews_start_sync (cbews);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cbews), FALSE);
+       g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
 
-                       PRIV_UNLOCK (priv);
-                       e_flag_wait (priv->refreshing_done);
-                       PRIV_LOCK (priv);
+       if (!e_cal_component_has_organizer (comp))
+               return FALSE;
 
-                       comp = e_cal_backend_store_get_component (priv->store, uid, rid);
-               }
+       organizer.value = NULL;
 
-               if (comp) {
-                       object = e_cal_component_get_as_string (comp);
+       e_cal_component_get_organizer (comp, &organizer);
+       if (organizer.value) {
+               CamelEwsSettings *ews_settings;
+               const gchar *email = organizer.value;
+               gchar *user_email;
 
-                       g_object_unref (comp);
+               ews_settings = ecb_ews_get_collection_settings (cbews);
 
-                       if (!object)
-                               g_propagate_error (&error, EDC_ERROR (ObjectNotFound));
-               } else {
-                       g_propagate_error (&error, EDC_ERROR (ObjectNotFound));
-               }
-       } 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))) {
-                       /* maybe a meeting invitation, for which the calendar item is not downloaded yet,
-                        * thus synchronize local cache first */
-                       ews_start_sync (cbews);
+               user_email = camel_ews_settings_dup_email (ews_settings);
 
-                       PRIV_UNLOCK (priv);
-                       e_flag_wait (priv->refreshing_done);
-                       PRIV_LOCK (priv);
+               if (!g_ascii_strncasecmp (email, "mailto:";, 7))
+                       email += 7;
 
-                       object = e_cal_backend_store_get_components_by_uid_as_ical_string (priv->store, uid);
-               }
+               is_organizer = user_email && g_ascii_strcasecmp (email, user_email) == 0;
 
-               if (!object)
-                       g_propagate_error (&error, EDC_ERROR (ObjectNotFound));
+               g_free (user_email);
        }
 
-       PRIV_UNLOCK (priv);
-
- exit:
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_get_object (cal, context, error, object);
-       g_free (object);
+       return is_organizer;
 }
 
-static void
-cal_backend_ews_get_object_list (ECalBackend *backend,
-                                 const gchar *sexp,
-                                 GSList **objects,
-                                 GError **error)
+static gboolean
+ecb_ews_connect_sync (ECalMetaBackend *meta_backend,
+                     const ENamedParameters *credentials,
+                     ESourceAuthenticationResult *out_auth_result,
+                     gchar **out_certificate_pem,
+                     GTlsCertificateFlags *out_certificate_errors,
+                     GCancellable *cancellable,
+                     GError **error)
 {
        ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-       GSList *components, *l;
-       ECalBackendSExp *cbsexp;
-       gboolean search_needed = TRUE;
-       time_t occur_start = -1, occur_end = -1;
-       gboolean prunning_by_time;
-
-       cbews = E_CAL_BACKEND_EWS (backend);
-       priv = cbews->priv;
-
-       if (!strcmp (sexp, "#t"))
-               search_needed = FALSE;
-
-       cbsexp = e_cal_backend_sexp_new (sexp);
-       if (!cbsexp) {
-               g_propagate_error (error, EDC_ERROR (InvalidQuery));
-               return;
+       CamelEwsSettings *ews_settings;
+       gchar *hosturl;
+       gboolean success = FALSE;
+
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (meta_backend), FALSE);
+       g_return_val_if_fail (out_auth_result != NULL, FALSE);
+
+       cbews = E_CAL_BACKEND_EWS (meta_backend);
+
+       g_rec_mutex_lock (&cbews->priv->cnc_lock);
+
+       if (cbews->priv->cnc) {
+               g_rec_mutex_unlock (&cbews->priv->cnc_lock);
+
+               *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+               return TRUE;
        }
 
-       *objects = NULL;
+       ews_settings = ecb_ews_get_collection_settings (cbews);
+       hosturl = camel_ews_settings_dup_hosturl (ews_settings);
+
+       cbews->priv->cnc = e_ews_connection_new (hosturl, ews_settings);
 
-       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);
+       e_binding_bind_property (
+               cbews, "proxy-resolver",
+               cbews->priv->cnc, "proxy-resolver",
+               G_BINDING_SYNC_CREATE);
 
-       for (l = components; l != NULL; l = l->next) {
-               ECalComponent *comp = E_CAL_COMPONENT (l->data);
+       *out_auth_result = e_ews_connection_try_credentials_sync (cbews->priv->cnc, credentials, cancellable, 
error);
 
-               if (e_cal_backend_get_kind (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 (*out_auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
+               ESource *source = e_backend_get_source (E_BACKEND (cbews));
+               ESourceEwsFolder *ews_folder;
+
+               ews_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
+
+               g_free (cbews->priv->folder_id);
+               cbews->priv->folder_id = e_source_ews_folder_dup_id (ews_folder);
+               cbews->priv->is_freebusy_calendar = g_strcmp0 (cbews->priv->folder_id, "freebusy-calendar") 
== 0;
+
+               g_signal_connect_swapped (cbews->priv->cnc, "server-notification",
+                       G_CALLBACK (ecb_ews_server_notification_cb), cbews);
+
+               if (!cbews->priv->is_freebusy_calendar &&
+                   camel_ews_settings_get_listen_notifications (ews_settings) &&
+                   e_ews_connection_satisfies_server_version (cbews->priv->cnc, E_EWS_EXCHANGE_2010_SP1)) {
+                       GSList *folders = NULL;
+
+                       folders = g_slist_prepend (folders, cbews->priv->folder_id);
+
+                       e_ews_connection_enable_notifications_sync (cbews->priv->cnc,
+                               folders, &cbews->priv->subscription_key);
+
+                       g_slist_free (folders);
                }
+
+               e_cal_backend_set_writable (E_CAL_BACKEND (cbews), !cbews->priv->is_freebusy_calendar);
+               success = TRUE;
+       } else {
+               ecb_ews_convert_error_to_edc_error (error);
+               g_clear_object (&cbews->priv->cnc);
        }
 
-       g_object_unref (cbsexp);
-       g_slist_free_full (components, g_object_unref);
+       g_rec_mutex_unlock (&cbews->priv->cnc_lock);
+
+       g_free (hosturl);
+
+       return success;
 }
 
-static void
-e_cal_backend_ews_get_object_list (ECalBackend *backend,
-                                   EDataCal *cal,
-                                   guint32 context,
-                                   GCancellable *cancellable,
-                                   const gchar *sexp)
+static gboolean
+ecb_ews_disconnect_sync (ECalMetaBackend *meta_backend,
+                        GCancellable *cancellable,
+                        GError **error)
 {
-       GSList *objects = NULL, *l;
-       GError *error = NULL;
+       ECalBackendEws *cbews;
 
-       cal_backend_ews_get_object_list (backend, sexp, &objects, &error);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (meta_backend), FALSE);
 
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_get_object_list (cal, context, error, objects);
-       if (objects) {
-               for (l = objects; l != NULL; l = g_slist_next (l))
-                       g_free (l->data);
-               g_slist_free (objects);
-       }
+       cbews = E_CAL_BACKEND_EWS (meta_backend);
+
+       ecb_ews_unset_connection (cbews);
+
+       return TRUE;
 }
 
 static gboolean
-ews_cal_delete_comp (ECalBackendEws *cbews,
-                     ECalComponent *comp,
-                     const gchar *item_id)
+ecb_ews_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)
 {
-       ECalBackendEwsPrivate *priv = cbews->priv;
-       ECalComponentId *uid;
-       gboolean ret;
+       ECalBackendEws *cbews;
+       ECalCache *cal_cache;
+       gboolean success = TRUE;
+       GError *local_error = NULL;
 
-       uid = e_cal_component_get_id (comp);
-       ret = e_cal_backend_store_remove_component (priv->store, uid->uid, uid->rid);
-       if (!ret)
-               goto exit;
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (meta_backend), FALSE);
+       g_return_val_if_fail (out_new_sync_tag != NULL, FALSE);
+       g_return_val_if_fail (out_repeat != NULL, FALSE);
+       g_return_val_if_fail (out_created_objects != NULL, FALSE);
+       g_return_val_if_fail (out_modified_objects != NULL, FALSE);
+       g_return_val_if_fail (out_removed_objects != NULL, FALSE);
 
-       e_cal_backend_notify_component_removed (E_CAL_BACKEND (cbews), uid, comp, NULL);
+       *out_created_objects = NULL;
+       *out_modified_objects = NULL;
+       *out_removed_objects = NULL;
 
-       PRIV_LOCK (priv);
-       g_hash_table_remove (priv->item_id_hash, item_id);
-       PRIV_UNLOCK (priv);
+       cbews = E_CAL_BACKEND_EWS (meta_backend);
 
-exit:
-       e_cal_component_free_id (uid);
-       return ret;
-}
+       cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+       g_return_val_if_fail (E_IS_CAL_CACHE (cal_cache), FALSE);
 
-static void
-ews_cal_append_exdate (ECalBackendEws *cbews,
-                       ECalComponent *comp,
-                       const gchar *rid,
-                       ECalObjModType mod)
-{
-       ECalComponent *old_comp;
+       g_rec_mutex_lock (&cbews->priv->cnc_lock);
 
-       old_comp = e_cal_component_clone (comp);
-       e_cal_util_remove_instances (e_cal_component_get_icalcomponent (comp), icaltime_from_string (rid), 
mod);
+       if (cbews->priv->is_freebusy_calendar) {
+               ESourceEwsFolder *ews_folder;
+               EEWSFreeBusyData fbdata;
+               GSList *free_busy = NULL, *link;
+               gboolean success;
+               time_t today;
 
-       e_cal_backend_notify_component_modified (E_CAL_BACKEND (cbews), old_comp, comp);
+               ews_folder = e_source_get_extension (e_backend_get_source (E_BACKEND (cbews)), 
E_SOURCE_EXTENSION_EWS_FOLDER);
 
-       g_object_unref (old_comp);
-}
+               today = time_day_begin (time (NULL));
 
-static icaltimezone *
-e_cal_backend_ews_get_timezone_from_ical_component (ECalBackend *backend,
-                                                   icalcomponent *comp)
-{
-       ETimezoneCache *timezone_cache;
-       icalproperty *prop = NULL;
-       const gchar *tzid = NULL;
+               fbdata.period_start = time_add_week (today, -e_source_ews_folder_get_freebusy_weeks_before 
(ews_folder));
+               fbdata.period_end = time_day_end (time_add_week (today, 
e_source_ews_folder_get_freebusy_weeks_after (ews_folder)));
+               fbdata.user_mails = g_slist_prepend (NULL, e_source_ews_folder_dup_foreign_mail (ews_folder));
 
-       timezone_cache = E_TIMEZONE_CACHE (backend);
+               success = e_ews_connection_get_free_busy_sync (cbews->priv->cnc, G_PRIORITY_DEFAULT,
+                       e_ews_cal_utils_prepare_free_busy_request, &fbdata,
+                       &free_busy, cancellable, &local_error);
 
-       prop = icalcomponent_get_first_property (comp, ICAL_DTSTART_PROPERTY);
-       if (prop != NULL) {
-               icalparameter *param = NULL;
+               if (success) {
+                       icaltimezone *utc_zone = icaltimezone_get_utc_timezone ();
+                       GSList *comps = NULL;
+                       GHashTable *known;
+                       GHashTableIter iter;
+                       gpointer key;
 
-               param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
-               if (param != NULL) {
-                       tzid = icalparameter_get_tzid (param);
-               } else {
-                       struct icaltimetype dtstart;
+                       known = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 
-                       dtstart = icalproperty_get_dtstart (prop);
-                       if (dtstart.is_utc)
-                               tzid = "UTC";
-               }
-       }
+                       if (e_cal_cache_search_components (cal_cache, NULL, &comps, cancellable, NULL)) {
+                               for (link = comps; link; link = g_slist_next (link)) {
+                                       ECalComponent *comp = link->data;
+                                       icalcomponent *icomp;
+                                       const gchar *uid;
 
-       if (tzid != NULL)
-               return e_timezone_cache_get_timezone (timezone_cache, tzid);
+                                       if (!comp)
+                                               continue;
 
-       return NULL;
-}
+                                       icomp = e_cal_component_get_icalcomponent (comp);
+                                       if (!icomp)
+                                               continue;
 
-static void
-ews_cal_remove_object_cb (GObject *object,
-                          GAsyncResult *res,
-                          gpointer user_data)
-{
-       EwsCalendarAsyncData *remove_data = user_data;
-       GSimpleAsyncResult *simple;
-       GError *error = NULL;
+                                       uid = icalcomponent_get_uid (icomp);
 
-       simple = G_SIMPLE_ASYNC_RESULT (res);
+                                       if (uid && *uid)
+                                               g_hash_table_insert (known, g_strdup (uid), g_object_ref 
(comp));
+                               }
 
-       if (!g_simple_async_result_propagate_error (simple, &error) || error->code == 
EWS_CONNECTION_ERROR_ITEMNOTFOUND) {
-               /* remove detached instances first */
-               if (remove_data->mod == E_CAL_OBJ_MOD_ALL) {
-                       ECalBackendEws *cbews = remove_data->cbews;
-                       GSList *with_detached, *iter;
+                               g_slist_free_full (comps, g_object_unref);
+                       }
 
-                       with_detached = e_cal_backend_store_get_components_by_uid (cbews->priv->store, 
remove_data->uid);
-                       for (iter = with_detached; iter; iter = g_slist_next (iter)) {
-                               ECalComponent *comp;
-                               ECalComponentId *id;
+                       for (link = free_busy; link; link = g_slist_next (link)) {
+                               icalcomponent *fbcomp = link->data;
+                               icalproperty *fbprop;
+                               icalparameter *param;
+                               struct icalperiodtype fb;
+                               icalparameter_fbtype fbtype;
 
-                               comp = iter->data;
-                               id = e_cal_component_get_id (comp);
+                               if (!fbcomp || icalcomponent_isa (fbcomp) != ICAL_VFREEBUSY_COMPONENT)
+                                       continue;
 
-                               /* notify separately only detached instances - the master object will be 
removed below */
-                               if (id && id->rid && *id->rid &&
-                                   e_cal_backend_store_remove_component (cbews->priv->store, id->uid, 
id->rid)) {
-                                       gchar *item_id = NULL;
+                               for (fbprop = icalcomponent_get_first_property (fbcomp, 
ICAL_FREEBUSY_PROPERTY);
+                                    fbprop;
+                                    fbprop = icalcomponent_get_next_property (fbcomp, 
ICAL_FREEBUSY_PROPERTY)) {
+                                       ECalComponent *ecomp;
+                                       icalcomponent *vevent;
+                                       const gchar *id, *summary, *location;
 
-                                       e_cal_backend_notify_component_removed (E_CAL_BACKEND (cbews), id, 
comp, NULL);
+                                       param = icalproperty_get_first_parameter (fbprop, 
ICAL_FBTYPE_PARAMETER);
+                                       if (!param)
+                                               continue;
 
-                                       ews_cal_component_get_item_id (comp, &item_id, NULL);
-                                       if (item_id) {
-                                               PRIV_LOCK (cbews->priv);
-                                               g_hash_table_remove (cbews->priv->item_id_hash, item_id);
-                                               PRIV_UNLOCK (cbews->priv);
+                                       fbtype = icalparameter_get_fbtype (param);
 
-                                               g_free (item_id);
+                                       if (fbtype != ICAL_FBTYPE_FREE &&
+                                           fbtype != ICAL_FBTYPE_BUSY &&
+                                           fbtype != ICAL_FBTYPE_BUSYUNAVAILABLE &&
+                                           fbtype != ICAL_FBTYPE_BUSYTENTATIVE)
+                                               continue;
+
+                                       fb = icalproperty_get_freebusy (fbprop);
+                                       id = icalproperty_get_parameter_as_string (fbprop, "X-EWS-ID");
+                                       summary = icalproperty_get_parameter_as_string (fbprop, "X-SUMMARY");
+                                       location = icalproperty_get_parameter_as_string (fbprop, 
"X-LOCATION");
+
+                                       vevent = icalcomponent_new_vevent ();
+
+                                       if (id && *id) {
+                                               icalcomponent_set_uid (vevent, id);
+                                       } else {
+                                               gchar *uid;
+
+                                               uid = g_strdup_printf ("%s-%s-%d",
+                                                       icaltime_as_ical_string (fb.start),
+                                                       icaltime_as_ical_string (fb.end),
+                                                       (gint) fbtype);
+
+                                               icalcomponent_set_uid (vevent, uid);
+
+                                               g_free (uid);
+                                       }
+
+                                       fb.start.zone = utc_zone;
+                                       fb.start.is_utc = 1;
+                                       fb.end.zone = utc_zone;
+                                       fb.end.is_utc = 1;
+
+                                       icalcomponent_set_dtstart (vevent, fb.start);
+                                       icalcomponent_set_dtend (vevent, fb.end);
+
+                                       icalcomponent_add_property (vevent, icalproperty_new_created 
(icaltime_current_time_with_zone (utc_zone)));
+
+                                       if (fbtype == ICAL_FBTYPE_FREE) {
+                                               icalcomponent_set_summary (vevent, C_("FreeBusyType", 
"Free"));
+                                               icalcomponent_add_property (vevent, icalproperty_new_transp 
(ICAL_TRANSP_TRANSPARENT));
+                                       } else if (fbtype == ICAL_FBTYPE_BUSY) {
+                                               icalcomponent_set_summary (vevent, C_("FreeBusyType", 
"Busy"));
+                                       } else if (fbtype == ICAL_FBTYPE_BUSYUNAVAILABLE) {
+                                               icalcomponent_set_summary (vevent, C_("FreeBusyType", "Out of 
Office"));
+                                       } else if (fbtype == ICAL_FBTYPE_BUSYTENTATIVE) {
+                                               icalcomponent_set_summary (vevent, C_("FreeBusyType", 
"Tentative"));
+                                       }
+
+                                       if (summary && *summary)
+                                               icalcomponent_set_summary (vevent, summary);
+
+                                       if (location && *location)
+                                               icalcomponent_set_location (vevent, location);
+
+                                       ecomp = g_hash_table_lookup (known, icalcomponent_get_uid (vevent));
+                                       if (ecomp) {
+                                               g_object_ref (ecomp);
+
+                                               /* This dereferences the ecomp, thus the ref() call above to 
keep it alive */
+                                               g_hash_table_remove (known, icalcomponent_get_uid (vevent));
+
+                                               if (ecb_ews_freebusy_ecomp_changed (ecomp, vevent)) {
+                                                       ECalMetaBackendInfo *nfo;
+                                                       gchar *revision = e_util_generate_uid ();
+
+                                                       e_cal_util_set_x_property (vevent, 
"X-EVOLUTION-CHANGEKEY", revision);
+
+                                                       nfo = e_cal_meta_backend_info_new 
(icalcomponent_get_uid (vevent), NULL, NULL, NULL);
+                                                       nfo->revision = revision;
+                                                       nfo->object = icalcomponent_as_ical_string_r (vevent);
+
+                                                       *out_created_objects = g_slist_prepend 
(*out_created_objects, nfo);
+                                               } else {
+                                                       icalcomponent_free (vevent);
+                                               }
+
+                                               g_clear_object (&ecomp);
+                                       } else {
+                                               ECalMetaBackendInfo *nfo;
+                                               gchar *revision = e_util_generate_uid ();
+
+                                               e_cal_util_set_x_property (vevent, "X-EVOLUTION-CHANGEKEY", 
revision);
+
+                                               nfo = e_cal_meta_backend_info_new (icalcomponent_get_uid 
(vevent), NULL, NULL, NULL);
+                                               nfo->revision = revision;
+                                               nfo->object = icalcomponent_as_ical_string_r (vevent);
+
+                                               *out_modified_objects = g_slist_prepend 
(*out_modified_objects, nfo);
                                        }
                                }
+                       }
+
+                       g_hash_table_iter_init (&iter, known);
+                       while (g_hash_table_iter_next (&iter, &key, NULL)) {
+                               const gchar *uid = key;
 
-                               e_cal_component_free_id (id);
+                               *out_removed_objects = g_slist_prepend (*out_removed_objects,
+                                       e_cal_meta_backend_info_new (uid, NULL, NULL, NULL));
                        }
 
-                       g_slist_free_full (with_detached, g_object_unref);
+                       g_hash_table_destroy (known);
+               } else if (g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NOFREEBUSYACCESS)) {
+                       e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
+
+                       e_cal_backend_notify_error (E_CAL_BACKEND (cbews), local_error->message);
+                       g_clear_error (&local_error);
+               } else {
+                       g_propagate_error (error, local_error);
                }
 
-               /* FIXME: This is horrid. Will bite us when we start to delete
-                * more than one item at a time... */
-               if (remove_data->comp != NULL)
-                       ews_cal_delete_comp (remove_data->cbews, remove_data->comp, remove_data->item_id);
-               if (remove_data->extra_comp != NULL)
-                       ews_cal_append_exdate (
-                               remove_data->cbews, remove_data->extra_comp, remove_data->rid, 
remove_data->mod);
-       }
+               g_slist_free_full (free_busy, (GDestroyNotify) icalcomponent_free);
+               g_slist_free_full (fbdata.user_mails, g_free);
+       } else {
+               GSList *items_created = NULL, *items_modified = NULL, *items_deleted = NULL, *link;
+               EEwsAdditionalProps *add_props;
+               gboolean includes_last_item = TRUE;
 
-       convert_error_to_edc_error (&error);
+               add_props = e_ews_additional_props_new ();
+               add_props->field_uri = g_strdup ("item:ItemClass");
 
-       if (remove_data->context)
-               e_data_cal_respond_remove_objects (remove_data->cal, remove_data->context, error, NULL, NULL, 
NULL);
-       else if (error) {
-               g_warning ("Remove object error :  %s\n", error->message);
-               g_clear_error (&error);
-       }
+               success = e_ews_connection_sync_folder_items_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+                       last_sync_tag, cbews->priv->folder_id, "IdOnly", add_props, EWS_MAX_FETCH_COUNT,
+                       out_new_sync_tag, &includes_last_item, &items_created, &items_modified, 
&items_deleted,
+                       cancellable, &local_error);
 
-       e_cal_backend_ews_async_data_free (remove_data);
-}
+               if (!success &&
+                   g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_INVALIDSYNCSTATEDATA)) {
+                       g_clear_error (&local_error);
 
-static gboolean
-e_cal_backend_ews_is_organizer (ECalBackendEws *cbews,
-                               ECalComponent *instance_comp,
-                               ECalComponent *parent_comp)
-{
-       ECalComponent *comp;
-       gboolean is_organizer = FALSE;
+                       e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
 
-       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cbews), FALSE);
+                       success = e_ews_connection_sync_folder_items_sync (cbews->priv->cnc, 
EWS_PRIORITY_MEDIUM,
+                               NULL, cbews->priv->folder_id, "IdOnly", add_props, EWS_MAX_FETCH_COUNT,
+                               out_new_sync_tag, &includes_last_item, &items_created, &items_modified, 
&items_deleted,
+                               cancellable, &local_error);
+               }
 
-       comp = instance_comp ? instance_comp : parent_comp;
-       if (!comp)
-               return FALSE;
+               e_ews_additional_props_free (add_props);
+
+               if (success) {
+                       GSList *components_created = NULL, *components_modified = NULL;
+                       icalcomponent_kind kind;
+
+                       kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbews));
+
+                       /* The sync state doesn't cover changes made by save_component_sync(),
+                          thus verify the changes, instead of re-donwloading the component again */
+                       items_created = ecb_ews_verify_changes (cal_cache, kind, items_created, cancellable);
+                       items_modified = ecb_ews_verify_changes (cal_cache, kind, items_modified, 
cancellable);
+
+                       if (items_created) {
+                               success = ecb_ews_fetch_items_sync (cbews, items_created, 
&components_created, cancellable, error);
+                               if (success)
+                                       *out_created_objects = ecb_ews_components_to_infos (meta_backend, 
components_created, kind);
+                       }
+
+                       if (items_modified) {
+                               success = ecb_ews_fetch_items_sync (cbews, items_modified, 
&components_modified, cancellable, error);
+                               if (success)
+                                       *out_modified_objects = ecb_ews_components_to_infos (meta_backend, 
components_modified, kind);
+                       }
+
+                       for (link = items_deleted; link; link = g_slist_next (link)) {
+                               const gchar *item_id = link->data;
+                               GSList *ids = NULL, *ilink;
 
-       PRIV_LOCK (cbews->priv);
+                               if (!e_cal_cache_get_ids_with_extra (cal_cache, item_id, &ids, cancellable, 
NULL))
+                                       continue;
 
-       if (e_cal_component_has_organizer (comp)) {
-               ECalComponentOrganizer organizer;
+                               for (ilink = ids; ilink; ilink = g_slist_next (ilink)) {
+                                       ECalComponentId *id = ilink->data;
 
-               organizer.value = NULL;
+                                       /* Use the master object */
+                                       if (id && id->uid && *id->uid && (!id->rid || !*id->rid)) {
+                                               *out_removed_objects = g_slist_prepend (*out_removed_objects,
+                                                       e_cal_meta_backend_info_new (id->uid, NULL, NULL, 
NULL));
+                                               break;
+                                       }
+                               }
 
-               e_cal_component_get_organizer (comp, &organizer);
-               if (organizer.value) {
-                       const gchar *email = organizer.value;
+                               g_slist_free_full (ids, (GDestroyNotify) e_cal_component_free_id);
+                       }
 
-                       if (!g_ascii_strncasecmp (email, "mailto:";, 7))
-                               email += 7;
+                       g_slist_free_full (components_created, g_object_unref);
+                       g_slist_free_full (components_modified, g_object_unref);
 
-                       is_organizer = cbews->priv->user_email && g_ascii_strcasecmp (email, 
cbews->priv->user_email) == 0;
+                       *out_repeat = !includes_last_item;
+               } else if (local_error) {
+                       g_propagate_error (error, local_error);
                }
+
+               g_slist_free_full (items_created, g_object_unref);
+               g_slist_free_full (items_modified, g_object_unref);
+               g_slist_free_full (items_deleted, g_free);
        }
 
-       PRIV_UNLOCK (cbews->priv);
+       g_rec_mutex_unlock (&cbews->priv->cnc_lock);
 
-       return is_organizer;
+       ecb_ews_convert_error_to_edc_error (error);
+       g_clear_object (&cal_cache);
+
+       return success;
 }
 
-static void
-e_cal_backend_ews_remove_object (ECalBackend *backend,
-                                 EDataCal *cal,
-                                 guint32 context,
-                                 GCancellable *cancellable,
-                                 const gchar *uid,
-                                 const gchar *rid,
-                                 ECalObjModType mod)
+static gboolean
+ecb_ews_load_component_sync (ECalMetaBackend *meta_backend,
+                            const gchar *uid,
+                            const gchar *extra,
+                            icalcomponent **out_component,
+                            gchar **out_extra,
+                            GCancellable *cancellable,
+                            GError **error)
 {
-       EwsCalendarAsyncData *remove_data;
-       ECalBackendEws *cbews = (ECalBackendEws *) backend;
-       ECalBackendEwsPrivate *priv;
-       ECalComponent *comp = NULL, *parent = NULL;
-       GError *error = NULL;
-       EwsId item_id;
-       guint index = 0;
-
-       /* There are 3 scenarios where this function is called:
-        * 1. An item with no recurrence - rid is NULL. Nothing special here.
-        * 2. A modified occurrence of a recurring event - rid isnt NULL. The store will contain the object 
which will have to be removed from it.
-        * 3. A non modified occurrence of a recurring event - rid isnt NULL. The store will only have a 
reference to the master event.
-        *        This is actually an update event where an exception date will have to be appended to the 
master. 
-        */
-       e_data_cal_error_if_fail (E_IS_CAL_BACKEND_EWS (cbews), InvalidArg);
-
-       if (!cbews->priv->cnc) {
-               e_data_cal_respond_remove_objects (cal, context, EDC_ERROR (RepositoryOffline), NULL, NULL, 
NULL);
-               return;
-       }
+       ECalBackendEws *cbews;
+       GSList *ids, *items = NULL, *components = NULL;
+       gboolean success;
 
-       if (!cal_backend_ews_ensure_connected (cbews, cancellable, &error)) {
-               convert_error_to_edc_error (&error);
-               e_data_cal_respond_remove_objects (cal, context, error, NULL, NULL, NULL);
-               return;
-       }
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (meta_backend), FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
+       g_return_val_if_fail (out_component != NULL, FALSE);
+       g_return_val_if_fail (out_extra != NULL, FALSE);
 
-       priv = cbews->priv;
+       cbews = E_CAL_BACKEND_EWS (meta_backend);
 
-       PRIV_LOCK (priv);
+       g_rec_mutex_lock (&cbews->priv->cnc_lock);
 
-       comp = e_cal_backend_store_get_component (priv->store, uid, rid);
+       ids = g_slist_prepend (NULL, (gpointer) (extra && *extra ? extra : uid));
 
-       if (!rid || !*rid)
-               rid = NULL;
+       success = e_ews_connection_get_items_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM, ids, "IdOnly",
+               NULL, FALSE, NULL, E_EWS_BODY_TYPE_TEXT, &items, NULL, NULL, cancellable, error);
 
-       if (rid) {
-               parent = e_cal_backend_store_get_component (priv->store, uid, NULL);
-               if (!parent && !comp) {
-                       g_warning ("EEE Cant find master component with uid:%s\n", uid);
-                       g_propagate_error (&error, EDC_ERROR (ObjectNotFound));
-                       PRIV_UNLOCK (priv);
-                       goto exit;
-               }
-       }
-
-       if (!comp && !parent) {
-               g_warning ("EEE Cant find component with uid:%s & rid:%s\n", uid, rid);
-               g_propagate_error (&error, EDC_ERROR (ObjectNotFound));
-               PRIV_UNLOCK (priv);
-               goto exit;
-       }
+       g_slist_free (ids);
 
-       ews_cal_component_get_item_id ((comp ? comp : parent), &item_id.id, &item_id.change_key);
+       if (success && items) {
+               success = ecb_ews_fetch_items_sync (cbews, items, &components, cancellable, error);
 
-       PRIV_UNLOCK (priv);
+               if (components) {
+                       const EwsId *ews_id = e_ews_item_get_id (items->data);
 
-       if (!item_id.id) {
-               g_propagate_error (
-                       &error, EDC_ERROR_EX (OtherError,
-                       "Cannot determine EWS ItemId"));
-               goto exit;
-       }
+                       if (ews_id)
+                               *out_extra = g_strdup (ews_id->id);
 
-       if (parent && !comp) {
-               index = e_cal_backend_ews_rid_to_index (
-                       e_cal_backend_ews_get_timezone_from_ical_component (
-                               backend,
-                               e_cal_component_get_icalcomponent (parent)),
-                       rid,
-                       e_cal_component_get_icalcomponent (parent),
-                       &error);
-
-               if (error != NULL)
-                       goto exit;
-       }
+                       if (components->next) {
+                               GSList *link;
 
-       remove_data = g_new0 (EwsCalendarAsyncData, 1);
-       remove_data->cbews = g_object_ref (cbews);
-       remove_data->cancellable = cal_backend_ews_ref_cancellable (cbews);
-       remove_data->comp = comp != NULL ? g_object_ref (comp) : NULL;
-       remove_data->extra_comp = parent != NULL ? g_object_ref (parent) : NULL;
-       remove_data->cal = g_object_ref (cal);
-       remove_data->context = context;
-       remove_data->item_id = g_strdup (item_id.id);
-       remove_data->uid = g_strdup (uid);
-       remove_data->rid = (rid ? g_strdup (rid) : NULL);
-       remove_data->mod = mod;
-
-       e_ews_connection_delete_item (
-               priv->cnc, EWS_PRIORITY_MEDIUM, &item_id, index, EWS_HARD_DELETE,
-               e_cal_backend_ews_is_organizer (cbews, comp, parent) ? EWS_SEND_TO_ALL_AND_SAVE_COPY : 
EWS_SEND_TO_NONE,
-               EWS_ALL_OCCURRENCES, remove_data->cancellable,
-               ews_cal_remove_object_cb,
-               remove_data);
-
-       return;
-
-exit:
-       if (comp != NULL)
-               g_object_unref (comp);
+                               *out_component = icalcomponent_new_vcalendar ();
 
-       if (parent != NULL)
-               g_object_unref (parent);
+                               for (link = components; link; link = g_slist_next (link)) {
+                                       ECalComponent *comp = link->data;
 
-       convert_error_to_edc_error (&error);
+                                       if (!comp)
+                                               continue;
 
-       if (context)
-               e_data_cal_respond_remove_objects (cal, context, error, NULL, NULL, NULL);
-       else if (error != NULL) {
-               g_warning ("Remove object error :  %s\n", error->message);
-               g_clear_error (&error);
+                                       icalcomponent_add_component (*out_component,
+                                               icalcomponent_new_clone (e_cal_component_get_icalcomponent 
(comp)));
+                               }
+                       } else {
+                               *out_component = icalcomponent_new_clone (e_cal_component_get_icalcomponent 
(components->data));
+                       }
+               } else {
+                       success = FALSE;
+               }
        }
-}
 
-static void
-e_cal_backend_ews_remove_objects (ECalBackend *backend,
-                                  EDataCal *cal,
-                                  guint32 context,
-                                  GCancellable *cancellable,
-                                  const GSList *ids,
-                                  ECalObjModType mod)
-{
-       GError *error = NULL;
-       const ECalComponentId *id;
+       if (!components && e_cal_meta_backend_refresh_sync (meta_backend, cancellable, NULL)) {
+               ECalCache *cal_cache;
 
-       if (!ids) {
-               if (context) {
-                       g_propagate_error (&error, EDC_ERROR (InvalidArg));
-                       e_data_cal_respond_remove_objects (cal, context, error, NULL, NULL, NULL);
-               }
-               return;
-       }
+               cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+               if (cal_cache) {
+                       success = e_cal_cache_get_components_by_uid (cal_cache, uid, &components, 
cancellable, NULL);
+                       if (success) {
+                               *out_component = e_cal_meta_backend_merge_instances (meta_backend, 
components, FALSE);
 
-       if (ids->next) {
-               if (context) {
-                       g_propagate_error (&error, EDC_ERROR_EX (UnsupportedMethod, _("EWS does not support 
bulk removals")));
-                       e_data_cal_respond_remove_objects (cal, context, error, NULL, NULL, NULL);
-               }
-               return;
-       }
+                               if (!e_cal_cache_get_component_extra (cal_cache, uid, NULL, out_extra, 
cancellable, NULL))
+                                       *out_extra = NULL;
 
-       id = ids->data;
-       if (!id) {
-               if (context) {
-                       g_propagate_error (&error, EDC_ERROR (InvalidArg));
-                       e_data_cal_respond_remove_objects (cal, context, error, NULL, NULL, NULL);
+                               g_clear_error (error);
+                       }
+                       g_object_unref (cal_cache);
                }
-               return;
        }
 
-       e_cal_backend_ews_remove_object (backend, cal, context, cancellable, id->uid, id->rid, mod);
+       g_rec_mutex_unlock (&cbews->priv->cnc_lock);
+
+       ecb_ews_convert_error_to_edc_error (error);
+       g_slist_free_full (components, g_object_unref);
+       g_slist_free_full (items, g_object_unref);
+
+       return success;
 }
 
-static icaltimezone * resolve_tzid (const gchar *tzid, gpointer user_data);
-static void put_component_to_store (ECalBackendEws *cbews,ECalComponent *comp);
+/* Very simple and naive component comparator, to avoid
+   unnecessary uploads and changes on the server. */
+static gboolean
+ecb_ews_components_equal (ECalComponent *comp1,
+                         ECalComponent *comp2)
+{
+       icalcomponent *icomp1, *icomp2;
+       icalproperty *prop1;
+       GHashTable *processed_props;
+       gboolean equal = TRUE;
 
-static void
-e_cal_backend_ews_modify_object (ECalBackend *backend,
-                                 EDataCal *cal,
-                                 guint32 context,
-                                 GCancellable *cancellable,
-                                 const gchar *calobj,
-                                 ECalObjModType mod);
+       if (!comp1 && !comp2)
+               return TRUE;
+       else if (!comp1 || !comp2)
+               return FALSE;
 
-static void ews_cal_modify_object_cb (GObject *object,
-                                 GAsyncResult *res,
-                                 gpointer user_data);
+       icomp1 = e_cal_component_get_icalcomponent (comp1);
+       icomp2 = e_cal_component_get_icalcomponent (comp2);
 
-static void
-ews_create_attachments_cb (GObject *object,
-                                 GAsyncResult *res,
-                                 gpointer user_data)
-{
-       EEwsConnection *cnc = E_EWS_CONNECTION (object);
-       EwsCalendarAsyncData *create_data = user_data;
-       ECalBackendEwsPrivate *priv = create_data->cbews->priv;
-       gchar *change_key;
-       GSList *ids, *i;
-       GError *error = NULL;
-       icalproperty *icalprop;
-       icalcomponent *icalcomp;
-       icalparameter *icalparam;
-       const gchar *comp_uid;
+       if (!icomp1 || !icomp2)
+               return FALSE;
 
-       if (!e_ews_connection_create_attachments_finish (cnc, &change_key, &ids, res, &error)) {
-               g_warning ("Error while creating attachments: %s\n", error ? error->message : "Unknown 
error");
-               if (error != NULL)
-                       g_clear_error (&error);
+       if (g_strcmp0 (icalcomponent_get_uid (icomp1), icalcomponent_get_uid (icomp2)) != 0)
+               return FALSE;
 
-               e_cal_backend_ews_async_data_free (create_data);
+       if (icalcomponent_count_properties (icomp1, ICAL_ANY_PROPERTY) !=
+           icalcomponent_count_properties (icomp2, ICAL_ANY_PROPERTY))
+               return FALSE;
 
-               return;
-       }
+       processed_props = g_hash_table_new (g_direct_hash, g_direct_equal);
 
-       /* get exclusive access to the store */
-       e_cal_backend_store_freeze_changes (priv->store);
-
-       /* Update change key. id remains the same, but change key changed.*/
-       icalcomp = e_cal_component_get_icalcomponent (create_data->comp);
-       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
-       while (icalprop) {
-               const gchar *x_name;
-               x_name = icalproperty_get_x_name (icalprop);
-               if (!g_ascii_strcasecmp (x_name, "X-EVOLUTION-CHANGEKEY")) {
-                       icalproperty_set_value_from_string (icalprop, change_key, "NO");
-                       break;
-               }
-               icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
-       }
+       for (prop1 = icalcomponent_get_first_property (icomp1, ICAL_ANY_PROPERTY);
+            prop1 && equal;
+            prop1 = icalcomponent_get_next_property (icomp1, ICAL_ANY_PROPERTY)) {
+               icalproperty_kind kind = icalproperty_isa (prop1);
+               icalproperty *prop2;
 
-       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_ATTACH_PROPERTY);
-       i = ids;
-       for (; i && icalprop; i = i->next, icalprop = icalcomponent_get_next_property (icalcomp, 
ICAL_ATTACH_PROPERTY)) {
-               icalparam = icalparameter_new_x (i->data);
-               icalparameter_set_xname (icalparam, "X-EWS-ATTACHMENTID");
-               icalproperty_add_parameter (icalprop, icalparam);
-               g_free (i->data);
-       }
+               for (prop2 = icalcomponent_get_first_property (icomp2, kind);
+                    prop2;
+                    prop2 = icalcomponent_get_next_property (icomp2, kind)) {
+                       gchar *str1, *str2;
+                       gboolean same;
 
-       e_cal_component_commit_sequence (create_data->comp);
-       /* update changes and release access to the store */
-       e_cal_backend_store_thaw_changes (priv->store);
+                       if (g_hash_table_contains (processed_props, prop2))
+                               continue;
 
-       e_cal_component_get_uid (create_data->comp, &comp_uid);
-       if (create_data->cb_type == E_EWS_ATTACHMENT_TYPE_UPDATE) {
-               const gchar *send_meeting_invitations;
-               const gchar *send_or_save;
-               EwsCalendarAsyncData *modify_data;
-               EwsCalendarConvertData convert_data = { 0 };
+                       if (icalproperty_count_parameters (prop1) != icalproperty_count_parameters (prop2))
+                               continue;
 
-               modify_data = g_new0 (EwsCalendarAsyncData, 1);
-               modify_data->cbews = g_object_ref (create_data->cbews);
-               modify_data->cancellable = cal_backend_ews_ref_cancellable (create_data->cbews);
-               modify_data->comp = g_object_ref (create_data->comp);
-               modify_data->extra_comp = g_object_ref (create_data->extra_comp);
-               modify_data->cal = g_object_ref (create_data->cal);
-               modify_data->context = create_data->context;
-               modify_data->item_id = g_strdup (create_data->item_id);
-
-               convert_data.connection = create_data->cbews->priv->cnc;
-               convert_data.user_email = create_data->cbews->priv->user_email;
-               convert_data.comp = create_data->comp;
-               convert_data.old_comp = create_data->extra_comp;
-               convert_data.item_id = create_data->item_id;
-               convert_data.change_key = change_key;
-               convert_data.default_zone = create_data->cbews->priv->default_zone;
-
-               if (e_cal_component_has_attendees (create_data->comp)) {
-                       send_meeting_invitations = "SendToAllAndSaveCopy";
-                       send_or_save = "SendAndSaveCopy";
-               } else {
-                       /*In case of appointment we have to set SendMeetingInvites to SendToNone */
-                       send_meeting_invitations = "SendToNone";
-                       send_or_save = "SaveOnly";
-               }
+                       str1 = icalproperty_as_ical_string_r (prop1);
+                       str2 = icalproperty_as_ical_string_r (prop2);
 
-               e_ews_connection_update_items (
-                       priv->cnc, EWS_PRIORITY_MEDIUM,
-                       "AlwaysOverwrite",
-                       send_or_save,
-                       send_meeting_invitations,
-                       priv->folder_id,
-                       e_cal_backend_ews_convert_component_to_updatexml,
-                       &convert_data,
-                       modify_data->cancellable,
-                       ews_cal_modify_object_cb,
-                       modify_data);
-       } else {
-               if (create_data->cb_type == E_EWS_ATTACHMENT_TYPE_CREATE) {
-                       /*In case we have attendees we have to fake update items,
-                       * this is the only way to pass attachments in meeting invite mail*/
-                       if (e_cal_component_has_attendees (create_data->comp)) {
-                               icalcomponent *icalcomp = e_cal_component_get_icalcomponent 
(create_data->comp);
-                               e_cal_backend_ews_modify_object (
-                                       E_CAL_BACKEND (create_data->cbews),
-                                       create_data->cal,
-                                       0,
-                                       NULL,
-                                       icalcomponent_as_ical_string (icalcomp),
-                                       E_CAL_OBJ_MOD_ALL);
+                       same = g_strcmp0 (str1, str2) == 0;
+
+                       g_free (str1);
+                       g_free (str2);
+
+                       if (same) {
+                               g_hash_table_insert (processed_props, prop2, NULL);
+                               break;
                        }
                }
+
+               if (!prop2)
+                       equal = FALSE;
        }
 
-       e_cal_backend_ews_async_data_free (create_data);
-       g_slist_free (ids);
+       g_hash_table_destroy (processed_props);
+
+       return equal;
 }
 
+typedef struct _ChangeData {
+       ECalComponent *old_component;
+       ECalComponent *new_component;
+} ChangeData;
+
 static void
-ews_create_object_cb (GObject *object,
-                      GAsyncResult *res,
-                      gpointer user_data)
+change_data_free (gpointer ptr)
 {
-       EEwsConnection *cnc = E_EWS_CONNECTION (object);
-       EwsCalendarAsyncData *create_data = user_data;
-       ECalBackendEws *cbews = create_data->cbews;
-       ECalBackendEwsPrivate *priv = cbews->priv;
-       GError *error = NULL;
-       GSList *ids = NULL, *attachments = NULL, *i, *exceptions = NULL, *items_req = NULL, *items = NULL;
-       GSList *new_uids, *new_comps;
-       const gchar *comp_uid;
-       const EwsId *item_id;
-       icalproperty *icalprop;
-       icalcomponent *icalcomp;
-       guint n_attach;
-       EEwsItem *item;
-
-       /* get a list of ids from server (single item) */
-       if (!e_ews_connection_create_items_finish (cnc, res, &ids, &error)) {
-               if (error != NULL) {
-                       convert_error_to_edc_error (&error);
-                       e_data_cal_respond_create_objects (create_data->cal, create_data->context, error, 
NULL, NULL);
-               } else {
-                       e_data_cal_respond_create_objects (
-                                       create_data->cal, create_data->context, EDC_ERROR_EX (OtherError, 
_("Unknown error")), NULL, NULL);
-               }
-               return;
+       ChangeData *cd = ptr;
+
+       if (cd) {
+               g_clear_object (&cd->old_component);
+               g_clear_object (&cd->new_component);
+               g_free (cd);
        }
+}
 
-       item = (EEwsItem *) ids->data;
-       item_id = e_ews_item_get_id (item);
-       g_slist_free (ids);
+static void
+ecb_ews_filter_out_unchanged_instances (const GSList *to_save_instances,
+                                       const GSList *existing_instances,
+                                       GSList **out_changed_instances, /* ChangeData * */
+                                       GSList **out_removed_instances) /* ECalComponent * */
+{
+       GSList *link = NULL;
+       GHashTable *existing_hash;
+       GHashTableIter iter;
+       gpointer value;
 
-       if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_EVENT) {
-               EEwsAdditionalProps *add_props;
-               GCancellable *cancellable;
+       g_return_if_fail (to_save_instances != NULL);
+       g_return_if_fail (existing_instances != NULL);
+       g_return_if_fail (out_changed_instances != NULL);
+       g_return_if_fail (out_removed_instances != NULL);
 
-               add_props = e_ews_additional_props_new ();
-               add_props->field_uri = g_strdup ("calendar:UID");
+       *out_changed_instances = NULL;
+       *out_removed_instances = NULL;
 
-               cancellable = cal_backend_ews_ref_cancellable (cbews);
-               items = g_slist_append (items, item_id->id);
+       existing_hash = g_hash_table_new_full ((GHashFunc)e_cal_component_id_hash, (GEqualFunc) 
e_cal_component_id_equal,
+               (GDestroyNotify) e_cal_component_free_id, NULL);
 
-               /* get calender uid from server*/
-               e_ews_connection_get_items_sync (
-                       cnc, EWS_PRIORITY_MEDIUM,
-                       items,
-                       "IdOnly",
-                       add_props,
-                       FALSE, NULL, E_EWS_BODY_TYPE_TEXT,
-                       &items_req,
-                       NULL, NULL, cancellable, &error);
+       for (link = (GSList *) existing_instances; link; link = g_slist_next (link)) {
+               ECalComponent *comp = link->data;
+               ECalComponentId *id = NULL;
 
-               e_ews_additional_props_free (add_props);
-               g_clear_object (&cancellable);
-
-               if (!res && error != NULL) {
-                       if (items_req)
-                               g_slist_free_full (items_req, g_object_unref);
-                       convert_error_to_edc_error (&error);
-                       e_data_cal_respond_create_objects (create_data->cal, create_data->context, error, 
NULL, NULL);
-                       return;
-               }
+               id = e_cal_component_get_id (comp);
+               if (id)
+                       g_hash_table_insert (existing_hash, id, comp);
+       }
 
-               item = (EEwsItem *) items_req->data;
-               if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR) {
-                       error = g_error_copy (e_ews_item_get_error (item));
-                       g_slist_free_full (items_req, g_object_unref);
+       for (link = (GSList *) to_save_instances; link; link = g_slist_next (link)) {
+               ECalComponent *comp = link->data;
+               ECalComponentId *id = NULL;
+
+               id = e_cal_component_get_id (comp);
+               if (id) {
+                       ECalComponent *old_comp;
+
+                       old_comp = g_hash_table_lookup (existing_hash, id);
+
+                       if (!ecb_ews_components_equal (comp, old_comp)) {
+                               ChangeData *cd;
+
+                               cd = g_new0 (ChangeData, 1);
+                               cd->old_component = old_comp ? g_object_ref (old_comp) : NULL;
+                               cd->new_component = g_object_ref (comp);
+
+                               *out_changed_instances = g_slist_prepend (*out_changed_instances, cd);
+                       }
 
-                       convert_error_to_edc_error (&error);
-                       e_data_cal_respond_create_objects (create_data->cal, create_data->context, error, 
NULL, NULL);
-                       return;
+                       g_hash_table_remove (existing_hash, id);
+                       e_cal_component_free_id (id);
                }
+       }
 
-               item_id = e_ews_item_get_id (item);
+       g_hash_table_iter_init (&iter, existing_hash);
+       while (g_hash_table_iter_next (&iter, NULL, &value)) {
+               *out_removed_instances = g_slist_prepend (*out_removed_instances, g_object_ref (value));
+       }
 
-               g_slist_free (items);
-               g_slist_free (items_req);
+       g_hash_table_destroy (existing_hash);
+}
+
+static gboolean
+ecb_ews_extract_attachments (icalcomponent *icalcomp,
+                            GSList **out_attachments) /* EEwsAttachmentInfo * */
+{
+       icalproperty *prop;
+       GSList *props = NULL, *link;
+
+       g_return_val_if_fail (icalcomp != NULL, FALSE);
+       g_return_val_if_fail (out_attachments != NULL, FALSE);
+
+       *out_attachments = NULL;
+
+       for (prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTACH_PROPERTY);
+            prop;
+            prop = icalcomponent_get_next_property (icalcomp, ICAL_ATTACH_PROPERTY)) {
+               props = g_slist_prepend (props, prop);
        }
 
-       /* attachments */
-       n_attach = e_cal_component_get_num_attachments (create_data->comp);
-       if (n_attach > 0) {
-               GSList *info_attachments = NULL;
-               EwsCalendarAsyncData *attach_data = g_new0 (EwsCalendarAsyncData, 1);
+       for (link = props; link; link = g_slist_next (link)) {
+               EEwsAttachmentInfo *info;
+               icalattach *attach;
+               icalparameter *param;
+               const gchar *stored_filename;
 
-               attach_data->cbews = g_object_ref (create_data->cbews);
-               attach_data->cancellable = cal_backend_ews_ref_cancellable (create_data->cbews);
-               attach_data->comp = g_object_ref (create_data->comp);
-               attach_data->cal = g_object_ref (create_data->cal);
-               attach_data->context = create_data->context;
-               attach_data->cb_type = 1;
+               prop = link->data;
+               param = icalproperty_get_first_parameter (prop, ICAL_FILENAME_PARAMETER);
+               stored_filename = param ? icalparameter_get_filename (param) : NULL;
 
-               e_cal_component_get_attachment_list (create_data->comp, &attachments);
+               attach = icalproperty_get_attach (prop);
+               if (icalattach_get_is_url (attach)) {
+                       const gchar *uri;
 
-               for (i = attachments; i; i = i->next) {
-                       const gchar *uri = i->data;
-                       gchar *uri_filename;
-                       EEwsAttachmentInfo *info;
+                       uri = icalattach_get_url (attach);
 
                        if (!uri || !*uri)
                                continue;
@@ -1607,106 +1930,214 @@ ews_create_object_cb (GObject *object,
                        info = e_ews_attachment_info_new (E_EWS_ATTACHMENT_INFO_TYPE_URI);
 
                        e_ews_attachment_info_set_uri (info, uri);
+                       if (stored_filename && *stored_filename) {
+                               e_ews_attachment_info_set_prefer_filename (info, stored_filename);
+                       } else {
+                               gchar *uri_filename;
 
-                       uri_filename = g_filename_from_uri (uri, NULL, NULL);
-                       if (uri_filename && *uri_filename) {
-                               gchar *basename;
+                               uri_filename = g_filename_from_uri (uri, NULL, NULL);
+                               if (uri_filename && *uri_filename) {
+                                       gchar *basename;
 
-                               basename = g_path_get_basename (uri_filename);
-                               if (basename && *basename && basename[0] != '.' && basename[0] != 
G_DIR_SEPARATOR) {
-                                       const gchar *uid;
+                                       basename = g_path_get_basename (uri_filename);
+                                       if (basename && *basename && basename[0] != '.' && basename[0] != 
G_DIR_SEPARATOR) {
+                                               const gchar *uid;
 
-                                       e_cal_component_get_uid (create_data->comp, &uid);
+                                               uid = icalcomponent_get_uid (icalcomp);
 
-                                       if (uid && g_str_has_prefix (basename, uid) && basename[strlen (uid)] 
== '-') {
-                                               e_ews_attachment_info_set_prefer_filename (info, basename + 
strlen (uid) + 1);
+                                               if (uid && g_str_has_prefix (basename, uid) && 
basename[strlen (uid)] == '-') {
+                                                       e_ews_attachment_info_set_prefer_filename (info, 
basename + strlen (uid) + 1);
+                                               }
                                        }
+
+                                       g_free (basename);
                                }
 
-                               g_free (basename);
+                               g_free (uri_filename);
                        }
+               } else {
+                       gsize len = -1;
+                       guchar *decoded = NULL;
+                       const gchar *content;
 
-                       g_free (uri_filename);
+                       content = (const gchar *) icalattach_get_data (attach);
+                       decoded = g_base64_decode (content, &len);
 
-                       info_attachments = g_slist_append (info_attachments, info);
-               }
+                       info = e_ews_attachment_info_new (E_EWS_ATTACHMENT_INFO_TYPE_INLINED);
+                       e_ews_attachment_info_set_inlined_data (info, decoded, len);
 
-               e_ews_connection_create_attachments (
-                       cnc, EWS_PRIORITY_MEDIUM,
-                       item_id, info_attachments,
-                       FALSE, attach_data->cancellable,
-                       ews_create_attachments_cb,
-                       attach_data);
+                       if (stored_filename && *stored_filename)
+                               e_ews_attachment_info_set_prefer_filename (info, stored_filename);
 
-               g_slist_free_full (info_attachments, (GDestroyNotify) e_ews_attachment_info_free);
-               g_slist_free_full (attachments, g_free);
+                       g_free (decoded);
+               }
+
+               e_ews_attachment_info_set_id (info, icalproperty_get_parameter_as_string (prop, 
"X-EWS-ATTACHMENTID"));
+               *out_attachments = g_slist_prepend (*out_attachments, info);
        }
 
-       /* get exclusive access to the store */
-       e_cal_backend_store_freeze_changes (priv->store);
+       g_slist_free (props);
 
-       /* set a new ical property containing the change key we got from the exchange server for future use */
-       if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_EVENT)
-               e_cal_component_set_uid (create_data->comp, e_ews_item_get_uid (item));
-       else
-               e_cal_component_set_uid (create_data->comp, item_id->id);
+       return *out_attachments != NULL;
+}
 
-       icalprop = icalproperty_new_x (item_id->id);
-       icalproperty_set_x_name (icalprop, "X-EVOLUTION-ITEMID");
-       icalcomp = e_cal_component_get_icalcomponent (create_data->comp);
-       icalcomponent_add_property (icalcomp, icalprop);
+static icaltimezone *
+ecb_ews_get_timezone_from_ical_component (ECalBackendEws *cbews,
+                                         icalcomponent *icalcomp)
+{
+       ETimezoneCache *timezone_cache;
+       icalproperty *prop = NULL;
+       const gchar *tzid = NULL;
 
-       icalprop = icalproperty_new_x (item_id->change_key);
-       icalproperty_set_x_name (icalprop, "X-EVOLUTION-CHANGEKEY");
-       icalcomp = e_cal_component_get_icalcomponent (create_data->comp);
-       icalcomponent_add_property (icalcomp, icalprop);
+       timezone_cache = E_TIMEZONE_CACHE (cbews);
 
-       /* update component internal data */
-       e_cal_component_commit_sequence (create_data->comp);
-       put_component_to_store (create_data->cbews, create_data->comp);
+       prop = icalcomponent_get_first_property (icalcomp, ICAL_DTSTART_PROPERTY);
+       if (prop != NULL) {
+               icalparameter *param = NULL;
 
-       e_cal_component_get_uid (create_data->comp, &comp_uid);
+               param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
+               if (param) {
+                       tzid = icalparameter_get_tzid (param);
+               } else {
+                       struct icaltimetype dtstart;
 
-       new_uids = g_slist_append (NULL, (gpointer) comp_uid);
-       new_comps = g_slist_append (NULL, create_data->comp);
+                       dtstart = icalproperty_get_dtstart (prop);
+                       if (dtstart.is_utc)
+                               tzid = "UTC";
+               }
+       }
 
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_create_objects (create_data->cal, create_data->context, error, new_uids, 
new_comps);
-       error = NULL;
+       if (tzid)
+               return e_timezone_cache_get_timezone (timezone_cache, tzid);
 
-       g_slist_free (new_uids);
-       g_slist_free (new_comps);
+       return NULL;
+}
 
-       /* notify the backend and the application that a new object was created */
-       e_cal_backend_notify_component_created (E_CAL_BACKEND (create_data->cbews), create_data->comp);
+static gboolean
+ecb_ews_remove_item_sync (ECalBackendEws *cbews,
+                         ECalCache *cal_cache,
+                         const gchar *uid,
+                         const gchar *rid,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+       ECalComponent *comp = NULL, *parent = NULL;
+       EwsId item_id = { 0 };
+       gint index = 0;
+       gboolean success;
 
-       /* place new component in our cache */
-       PRIV_LOCK (priv);
-       g_hash_table_insert (priv->item_id_hash, g_strdup (item_id->id), g_object_ref (create_data->comp));
-       PRIV_UNLOCK (priv);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cbews), FALSE);
+       g_return_val_if_fail (E_IS_CAL_CACHE (cal_cache), FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
 
-       /* update changes and release access to the store */
-       e_cal_backend_store_thaw_changes (priv->store);
+       if (rid && !*rid)
+               rid = NULL;
 
-       /* Excluded occurrences */
-       g_clear_error (&error);
-       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY);
-       if (icalprop != NULL) {
-               icalprop = icalcomponent_get_first_property (icalcomp, ICAL_EXDATE_PROPERTY);
-               for (; icalprop; icalprop = icalcomponent_get_next_property (icalcomp, ICAL_EXDATE_PROPERTY)) 
{
-                       exceptions = g_slist_prepend (exceptions, g_strdup (icalproperty_get_value_as_string 
(icalprop)));
+       if (!e_cal_cache_get_component (cal_cache, uid, rid, &comp, cancellable, error) ||
+           (rid && !e_cal_cache_get_component (cal_cache, uid, NULL, &parent, cancellable, error))) {
+               if (!parent && !comp) {
+                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+                       return FALSE;
                }
+       }
+
+       ecb_ews_extract_item_id (comp ? comp : parent, &item_id.id, &item_id.change_key);
 
-               for (i = exceptions; i; i = i->next) {
-                       e_cal_backend_ews_remove_object (
-                               E_CAL_BACKEND (create_data->cbews), create_data->cal, 0, NULL,
-                               comp_uid, i->data, E_CAL_OBJ_MOD_THIS);
+       if (!item_id.id) {
+               g_propagate_error (error, EDC_ERROR_EX (OtherError, "Cannot determine EWS ItemId"));
+               success = FALSE;
+       } else {
+               if (parent && !comp) {
+                       index = e_cal_backend_ews_rid_to_index (
+                               ecb_ews_get_timezone_from_ical_component (cbews,
+                                       e_cal_component_get_icalcomponent (parent)),
+                               rid,
+                               e_cal_component_get_icalcomponent (parent),
+                               error);
+                       if (index == 0)
+                               success = FALSE;
                }
 
-               g_slist_free_full (exceptions, g_free);
+               success = success && e_ews_connection_delete_item_sync (cbews->priv->cnc, 
EWS_PRIORITY_MEDIUM, &item_id, index, EWS_HARD_DELETE,
+                       ecb_ews_is_organizer (cbews, comp) ? EWS_SEND_TO_ALL_AND_SAVE_COPY : EWS_SEND_TO_NONE,
+                       EWS_ALL_OCCURRENCES, cancellable, error);
        }
 
-       e_cal_backend_ews_async_data_free (create_data);
+       g_free (item_id.id);
+       g_free (item_id.change_key);
+
+       g_clear_object (&comp);
+       g_clear_object (&parent);
+
+       return success;
+}
+
+static void
+ecb_ews_get_attach_differences (ECalComponent *oldcomp,
+                               ECalComponent *newcomp,
+                               GSList **out_removed_attachment_ids, /* gchar * */
+                               GSList **out_added_attachments) /* EEwsAttachmentInfo * */
+{
+       GSList *old_attachments = NULL, *new_attachments = NULL, *link;
+
+       g_return_if_fail (out_removed_attachment_ids != NULL);
+       g_return_if_fail (out_added_attachments != NULL);
+
+       *out_removed_attachment_ids = NULL;
+       *out_added_attachments = NULL;
+
+       if (!ecb_ews_extract_attachments (e_cal_component_get_icalcomponent (oldcomp), &old_attachments))
+               old_attachments = NULL;
+
+       if (!ecb_ews_extract_attachments (e_cal_component_get_icalcomponent (newcomp), &new_attachments))
+               new_attachments = NULL;
+
+       for (link = old_attachments; link; link = g_slist_next (link)) {
+               EEwsAttachmentInfo *old_nfo = link->data;
+               GSList *nlink;
+
+               if (!old_nfo)
+                       continue;
+
+               for (nlink = new_attachments; nlink; nlink = g_slist_next (nlink)) {
+                       EEwsAttachmentInfo *new_nfo = nlink->data;
+                       gboolean same = FALSE;
+
+                       if (!new_nfo ||
+                           e_ews_attachment_info_get_type (old_nfo) != e_ews_attachment_info_get_type 
(new_nfo))
+                               continue;
+
+                       if (e_ews_attachment_info_get_type (old_nfo) == E_EWS_ATTACHMENT_INFO_TYPE_INLINED) {
+                               const gchar *old_data, *new_data;
+                               gsize old_len = -1, new_len = -1;
+
+                               old_data = e_ews_attachment_info_get_inlined_data (old_nfo, &old_len);
+                               new_data = e_ews_attachment_info_get_inlined_data (new_nfo, &new_len);
+
+                               same = old_len == new_len && (old_len == 0 ||
+                                       (old_len > 0 && old_data && new_data && memcmp (old_data, new_data, 
old_len) == 0));
+                       } else if (e_ews_attachment_info_get_type (old_nfo) == 
E_EWS_ATTACHMENT_INFO_TYPE_URI) {
+                               same = g_strcmp0 (e_ews_attachment_info_get_uri (old_nfo), 
e_ews_attachment_info_get_uri (new_nfo)) == 0;
+                       }
+
+                       if (same) {
+                               new_attachments = g_slist_remove (new_attachments, new_nfo);
+                               e_ews_attachment_info_free (new_nfo);
+                               break;
+                       }
+               }
+
+               if (!nlink) {
+                       /* Did not find in the new_attachments, thus it's removed */
+                       g_warn_if_fail (e_ews_attachment_info_get_id (old_nfo) != NULL);
+                       *out_removed_attachment_ids = g_slist_prepend (*out_removed_attachment_ids,
+                               g_strdup (e_ews_attachment_info_get_id (old_nfo)));
+               }
+       }
+
+       *out_added_attachments = new_attachments;
+
+       g_slist_free_full (old_attachments, (GDestroyNotify) e_ews_attachment_info_free);
 }
 
 struct TzidCbData {
@@ -1714,7 +2145,9 @@ struct TzidCbData {
        ECalBackendEws *cbews;
 };
 
-static void tzid_cb (icalparameter *param, gpointer data)
+static void
+tzid_cb (icalparameter *param,
+        gpointer data)
 {
        struct TzidCbData *cbd = data;
        const gchar *tzid;
@@ -1725,7 +2158,7 @@ static void tzid_cb (icalparameter *param, gpointer data)
        if (!tzid)
                return;
 
-       zone = resolve_tzid (tzid, cbd->cbews);
+       zone = e_timezone_cache_get_timezone (E_TIMEZONE_CACHE (cbd->cbews), tzid);
        if (!zone)
                return;
 
@@ -1737,8 +2170,8 @@ static void tzid_cb (icalparameter *param, gpointer data)
 }
 
 static void
-e_cal_backend_ews_pick_all_tzids_out (ECalBackendEws *cbews,
-                                     icalcomponent *icalcomp)
+ecb_ews_pick_all_tzids_out (ECalBackendEws *cbews,
+                           icalcomponent *icalcomp)
 {
 
        /* pick all the tzids out of the component and resolve
@@ -1747,500 +2180,646 @@ e_cal_backend_ews_pick_all_tzids_out (ECalBackendEws *cbews,
 
        cbd.cbews = cbews;
        cbd.comp = icalcomp;
+
        icalcomponent_foreach_tzid (icalcomp, tzid_cb, &cbd);
 }
 
-static void
-e_cal_backend_ews_create_objects (ECalBackend *backend,
-                                  EDataCal *cal,
-                                  guint32 context,
-                                  GCancellable *cancellable,
-                                  const GSList *calobjs)
+static gboolean
+ecb_ews_modify_item_sync (ECalBackendEws *cbews,
+                         icalcomponent *old_icalcomp,
+                         icalcomponent *new_icalcomp,
+                         GCancellable *cancellable,
+                         GError **error)
 {
-       EwsCalendarAsyncData *create_data;
-       EwsCalendarConvertData convert_data = { 0 };
-       EwsFolderId *fid;
-       ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-       icalcomponent_kind kind;
+       ECalComponent *comp = NULL, *oldcomp = NULL;
        icalcomponent *icalcomp;
-       ECalComponent *comp = NULL;
-       struct icaltimetype current;
-       GError *error = NULL;
-       const gchar *send_meeting_invitations, *calobj;
-
-       /* sanity check */
-       e_data_cal_error_if_fail (E_IS_CAL_BACKEND_EWS (backend), InvalidArg);
-       e_data_cal_error_if_fail (calobjs != NULL, InvalidArg);
-
-       if (calobjs->next) {
-               g_propagate_error (&error, EDC_ERROR_EX (UnsupportedMethod, _("EWS does not support bulk 
additions")));
-               goto exit;
-       }
-
-       calobj = calobjs->data;
-       e_data_cal_error_if_fail (calobj != NULL && *calobj != '\0', InvalidArg);
+       gchar *itemid = NULL, *changekey = NULL;
+       GSList *added_attachments = NULL, *removed_attachment_ids = NULL;
+       gboolean success = TRUE;
 
-       cbews = E_CAL_BACKEND_EWS (backend);
-       priv = cbews->priv;
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cbews), FALSE);
+       g_return_val_if_fail (new_icalcomp != NULL, FALSE);
 
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+       icalcomp = icalcomponent_new_clone (new_icalcomp);
 
-       /* make sure we're not offline */
-       if (!e_backend_get_online (E_BACKEND (backend)) || !cbews->priv->cnc) {
-               g_propagate_error (&error, EDC_ERROR (RepositoryOffline));
-               goto exit;
-       }
+       ecb_ews_pick_all_tzids_out (cbews, icalcomp);
 
-       if (!cal_backend_ews_ensure_connected (cbews, cancellable, &error)) {
-               goto exit;
+       comp = e_cal_component_new_from_icalcomponent (icalcomp);
+       if (!comp) {
+               g_propagate_error (error, EDC_ERROR (InvalidObject));
+               return FALSE;
        }
 
-       /* parse ical data */
-       comp = e_cal_component_new_from_string (calobj);
-       if (comp == NULL) {
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
+       ecb_ews_extract_item_id (comp, &itemid, &changekey);
+       if (!itemid) {
+               g_propagate_error (error, EDC_ERROR_EX (OtherError, "Cannot determine EWS ItemId"));
+               g_object_unref (comp);
+               return FALSE;
        }
-       icalcomp = e_cal_component_get_icalcomponent (comp);
 
-       /* make sure data was parsed properly */
-       if (!icalcomp) {
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
+       if (old_icalcomp) {
+               oldcomp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (old_icalcomp));
+       } else {
+               oldcomp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (new_icalcomp));
        }
 
-       /* make sure ical data we parse is actually an ical component */
-       if (kind != icalcomponent_isa (icalcomp)) {
-               icalcomponent_free (icalcomp);
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
-       }
+       ecb_ews_pick_all_tzids_out (cbews, e_cal_component_get_icalcomponent (oldcomp));
 
-       e_ews_clean_icalcomponent (icalcomp);
+       /* In case we have updated attachments we have to run update attachments
+        * before update items so attendees will receive mails with already updated attachments */
 
-       if (!e_ews_connection_satisfies_server_version (cbews->priv->cnc, E_EWS_EXCHANGE_2010))
-               e_cal_backend_ews_pick_all_tzids_out (cbews, icalcomp);
+       ecb_ews_get_attach_differences (oldcomp, comp, &removed_attachment_ids, &added_attachments);
 
-       /* prepare new calender component */
-       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);
+       /* preform sync delete attachemnt operation*/
+       if (removed_attachment_ids) {
+               g_free (changekey);
+               changekey = NULL;
 
-       create_data = g_new0 (EwsCalendarAsyncData, 1);
-       create_data->cbews = g_object_ref (cbews);
-       create_data->comp = g_object_ref (comp);
-       create_data->cal = g_object_ref (cal);
-       create_data->context = context;
+               success = e_ews_connection_delete_attachments_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+                       removed_attachment_ids, &changekey, cancellable, error);
 
-       convert_data.connection = cbews->priv->cnc;
-       convert_data.icalcomp = icalcomp;
-       convert_data.default_zone = cbews->priv->default_zone;
-
-       /*
-        * In case we are creating a meeting with attendees and attachments.
-        * We have to preform 3 steps in order to allow attendees to receive attachments in their invite 
mails.
-        * 1. create meeting and do not send invites
-        * 2. create attachments
-        * 3. dummy update meeting and send invites to all
-        */
-       if (e_cal_component_has_attendees (comp)) {
-               if (e_cal_component_has_attachments (comp))
-                       send_meeting_invitations = "SendToNone";
-               else
-                       send_meeting_invitations = "SendToAllAndSaveCopy";
-       } else {
-               /*In case of appointment we have to set SendMeetingInvites to SendToNone */
-               send_meeting_invitations = "SendToNone";
+               g_slist_free_full (removed_attachment_ids, g_free);
        }
 
-       fid = e_ews_folder_id_new (priv->folder_id, NULL, FALSE);
+       /* in case we have a new attachments add them before update */
+       if (added_attachments && success) {
+               EwsId item_id;
 
-       e_ews_connection_create_items (
-               priv->cnc,
-               EWS_PRIORITY_MEDIUM,
-               "SaveOnly",
-               send_meeting_invitations,
-               fid,
-               e_cal_backend_ews_convert_calcomp_to_xml,
-               &convert_data,
-               cancellable,
-               ews_create_object_cb,
-               create_data);
+               item_id.id = itemid;
+               item_id.change_key = changekey;
 
-       e_ews_folder_id_free (fid);
+               changekey = NULL;
 
-       return;
+               success = e_ews_connection_create_attachments_sync (
+                       cbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+                       &item_id, added_attachments,
+                       FALSE, &changekey, NULL, cancellable, error);
 
-exit:
-       if (comp != NULL)
-               g_object_unref (comp);
+               g_free (item_id.change_key);
+       }
 
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_create_objects (cal, context, error, NULL, NULL);
-}
+       if (success && old_icalcomp &&
+           icalcomponent_get_first_property (new_icalcomp, ICAL_RRULE_PROPERTY) &&
+           !icalcomponent_get_first_property (new_icalcomp, ICAL_RECURRENCEID_PROPERTY)) {
+               icalproperty *prop, *old_prop;
+               GSList *exceptions = NULL, *link;
+               EwsId item_id;
 
-static void
-ews_cal_modify_object_cb (GObject *object,
-                          GAsyncResult *res,
-                          gpointer user_data)
-{
-       EEwsConnection *cnc = E_EWS_CONNECTION (object);
-       EwsCalendarAsyncData *modify_data = user_data;
-       ECalBackendEws *cbews = modify_data->cbews;
-       ECalBackendEwsPrivate *priv = cbews->priv;
-       GError *error = NULL;
-       GSList *ids = NULL;
-       const EwsId *item_id;
-       icalproperty *icalprop = NULL;
-       icalcomponent *icalcomp;
-       ECalComponentId *id = NULL;
-       const gchar *x_name;
-
-       if (!e_ews_connection_update_items_finish (cnc, res, &ids, &error)) {
-               convert_error_to_edc_error (&error);
-               if (modify_data->context)
-                       e_data_cal_respond_modify_objects (modify_data->cal, modify_data->context, error, 
NULL, NULL);
-               else if (error != NULL) {
-                       g_warning ("Modify object error :  %s\n", error->message);
-                       g_clear_error (&error);
-               }
+               item_id.id = itemid;
+               item_id.change_key = changekey;
 
-               goto exit;
-       }
+               /* Excluded occurrences */
+               for (prop = icalcomponent_get_first_property (new_icalcomp, ICAL_EXDATE_PROPERTY);
+                    prop;
+                    prop = icalcomponent_get_next_property (new_icalcomp, ICAL_EXDATE_PROPERTY)) {
+                       const gchar *new_rid;
 
-       e_cal_backend_store_freeze_changes (priv->store);
+                       new_rid = icalproperty_get_value_as_string (prop);
 
-       item_id = e_ews_item_get_id ((EEwsItem *) ids->data);
+                       for (old_prop = icalcomponent_get_first_property (old_icalcomp, ICAL_EXDATE_PROPERTY);
+                            old_prop;
+                            old_prop = icalcomponent_get_next_property (old_icalcomp, ICAL_EXDATE_PROPERTY)) 
{
+                               if (g_strcmp0 (new_rid, icalproperty_get_value_as_string (old_prop)) == 0)
+                                       break;
+                       }
 
-       /* Update change key. id remains the same, but change key changed.*/
-       icalcomp = e_cal_component_get_icalcomponent (modify_data->comp);
-       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
-       while (icalprop) {
-               x_name = icalproperty_get_x_name (icalprop);
-               if (!g_ascii_strcasecmp (x_name, "X-EVOLUTION-CHANGEKEY")) {
-                       icalproperty_set_value_from_string (icalprop, item_id->change_key, "NO");
-                       break;
+                       if (!old_prop)
+                               exceptions = g_slist_prepend (exceptions, prop);
                }
-               icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
-       }
 
-       e_cal_component_commit_sequence (modify_data->comp);
-       id = e_cal_component_get_id (modify_data->comp);
-       e_cal_backend_store_remove_component (cbews->priv->store, id->uid, id->rid);
-       put_component_to_store (cbews, modify_data->comp);
+               exceptions = g_slist_reverse (exceptions);
 
-       if (modify_data->context) {
-               GSList *old_components, *new_components;
+               for (link = exceptions; link && success; link = g_slist_next (link)) {
+                       guint index;
 
-               e_cal_backend_notify_component_modified (E_CAL_BACKEND (cbews), modify_data->extra_comp, 
modify_data->comp);
+                       prop = link->data;
 
-               old_components = g_slist_append (NULL, modify_data->extra_comp);
-               new_components = g_slist_append (NULL, modify_data->comp);
+                       index = e_cal_backend_ews_rid_to_index (
+                               ecb_ews_get_timezone_from_ical_component (cbews, new_icalcomp),
+                               icalproperty_get_value_as_string (prop),
+                               new_icalcomp,
+                               error);
 
-               e_data_cal_respond_modify_objects (modify_data->cal, modify_data->context, NULL, 
old_components, new_components);
+                       if (index == 0) {
+                               success = FALSE;
+                       } else {
+                               success = e_ews_connection_delete_item_sync (cbews->priv->cnc, 
EWS_PRIORITY_MEDIUM, &item_id, index,
+                                       EWS_HARD_DELETE, EWS_SEND_TO_NONE, EWS_ALL_OCCURRENCES, cancellable, 
error);
+                       }
+               }
 
-               g_slist_free (old_components);
-               g_slist_free (new_components);
+               g_slist_free (exceptions);
        }
 
-       ews_start_sync (cbews);
-
-       PRIV_LOCK (priv);
-       g_hash_table_replace (priv->item_id_hash, g_strdup (modify_data->item_id), g_object_ref 
(modify_data->comp));
-       PRIV_UNLOCK (priv);
+       if (success) {
+               EwsCalendarConvertData convert_data = { 0 };
+               CamelEwsSettings *ews_settings;
+               const gchar *send_meeting_invitations;
+               const gchar *send_or_save;
 
-       e_cal_backend_store_thaw_changes (priv->store);
+               ews_settings = ecb_ews_get_collection_settings (cbews);
 
-       icalproperty_free (icalprop);
-       e_cal_component_free_id (id);
+               convert_data.connection = cbews->priv->cnc;
+               convert_data.user_email = camel_ews_settings_dup_email (ews_settings);
+               convert_data.comp = comp;
+               convert_data.old_comp = oldcomp;
+               convert_data.item_id = itemid;
+               convert_data.change_key = changekey;
+               convert_data.default_zone = icaltimezone_get_utc_timezone ();
 
-exit:
-       e_cal_backend_ews_async_data_free (modify_data);
-}
+               if (e_cal_component_has_attendees (comp)) {
+                       send_meeting_invitations = "SendToAllAndSaveCopy";
+                       send_or_save = "SendAndSaveCopy";
+               } else {
+                       /*In case of appointment we have to set SendMeetingInvites to SendToNone */
+                       send_meeting_invitations = "SendToNone";
+                       send_or_save = "SaveOnly";
+               }
 
-static void
-e_cal_backend_ews_modify_objects (ECalBackend *backend,
-                                  EDataCal *cal,
-                                  guint32 context,
-                                  GCancellable *cancellable,
-                                  const GSList *calobjs,
-                                  ECalObjModType mod)
-{
-       GError *error = NULL;
+               success = e_ews_connection_update_items_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+                       "AlwaysOverwrite", send_or_save, send_meeting_invitations, cbews->priv->folder_id,
+                       e_cal_backend_ews_convert_component_to_updatexml, &convert_data,
+                       NULL, cancellable, error);
 
-       if (!calobjs) {
-               if (context) {
-                       g_propagate_error (&error, EDC_ERROR (InvalidArg));
-                       e_data_cal_respond_modify_objects (cal, context, error, NULL, NULL);
-               }
-               return;
+               g_free (convert_data.user_email);
        }
 
-       if (calobjs->next) {
-               if (context) {
-                       g_propagate_error (&error, EDC_ERROR_EX (UnsupportedMethod, _("EWS does not support 
bulk modifications")));
-                       e_data_cal_respond_modify_objects (cal, context, error, NULL, NULL);
-               }
-               return;
-       }
+       g_slist_free_full (added_attachments, (GDestroyNotify) e_ews_attachment_info_free);
+       g_clear_object (&oldcomp);
+       g_clear_object (&comp);
+       g_free (changekey);
+       g_free (itemid);
 
-       e_cal_backend_ews_modify_object (backend, cal, context, cancellable, calobjs->data, mod);
+       return success;
 }
 
-static void
-e_cal_backend_ews_modify_object (ECalBackend *backend,
-                                 EDataCal *cal,
-                                 guint32 context,
-                                 GCancellable *cancellable,
-                                 const gchar *calobj,
-                                 ECalObjModType mod)
+static gboolean
+ecb_ews_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)
 {
-       EwsCalendarAsyncData *modify_data;
        ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-       icalcomponent_kind kind;
-       ECalComponent *comp = NULL, *oldcomp = NULL;
-       icalcomponent *icalcomp;
-       gchar *itemid = NULL, *changekey = NULL;
-       struct icaltimetype current;
-       GError *error = NULL;
-       GSList *original_attachments = NULL, *modified_attachments = NULL, *added_attachments = NULL, 
*removed_attachments = NULL, *removed_attachments_ids = NULL, *i;
-       EwsCalendarAsyncData *attach_data;
+       ECalCache *cal_cache;
+       ECalComponent *master = NULL;
+       EwsFolderId *fid;
+       GSList *link;
+       const gchar *uid = NULL;
+       gboolean success = TRUE;
 
-       e_data_cal_error_if_fail (E_IS_CAL_BACKEND_EWS (backend), InvalidArg);
-       e_data_cal_error_if_fail (calobj != NULL && *calobj != '\0', InvalidArg);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (meta_backend), FALSE);
 
-       cbews = E_CAL_BACKEND_EWS (backend);
-       priv = cbews->priv;
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+       cbews = E_CAL_BACKEND_EWS (meta_backend);
 
-       if (!e_backend_get_online (E_BACKEND (backend)) || !cbews->priv->cnc) {
-               g_propagate_error (&error, EDC_ERROR (RepositoryOffline));
-               goto exit;
-       }
+       for (link = (GSList *) instances; link && !master; link = g_slist_next (link)) {
+               master = link->data;
 
-       if (!cal_backend_ews_ensure_connected (cbews, cancellable, &error)) {
-               goto exit;
-       }
+               if (!master)
+                       continue;
 
-       icalcomp = icalparser_parse_string (calobj);
-       if (!icalcomp) {
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
+               if (e_cal_component_is_instance (master))
+                       master = NULL;
        }
-       if (kind != icalcomponent_isa (icalcomp)) {
-               icalcomponent_free (icalcomp);
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
+
+       if (!master) {
+               g_propagate_error (error, EDC_ERROR (InvalidObject));
+               return FALSE;
        }
 
-       e_cal_backend_ews_pick_all_tzids_out (cbews, icalcomp);
+       cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+       g_return_val_if_fail (cal_cache != NULL, 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);
+       g_rec_mutex_lock (&cbews->priv->cnc_lock);
 
-       ews_cal_component_get_item_id (comp, &itemid, &changekey);
-       if (!itemid) {
-               g_propagate_error (
-                       &error, EDC_ERROR_EX (OtherError,
-                       "Cannot determine EWS ItemId"));
-               goto exit;
-       }
+       e_cal_component_get_uid (master, &uid);
+       fid = e_ews_folder_id_new (cbews->priv->folder_id, NULL, FALSE);
 
-       PRIV_LOCK (priv);
-       oldcomp = g_hash_table_lookup (priv->item_id_hash, itemid);
-       if (!oldcomp) {
-               g_propagate_error (&error, EDC_ERROR (ObjectNotFound));
-               PRIV_UNLOCK (priv);
-               goto exit;
-       }
-       g_object_ref (oldcomp);
-       PRIV_UNLOCK (priv);
+       if (overwrite_existing) {
+               GSList *existing = NULL, *changed_instances = NULL, *removed_instances = NULL;
+
+               success = uid && e_cal_cache_get_components_by_uid (cal_cache, uid, &existing, cancellable, 
error) && existing;
 
-       e_cal_backend_ews_pick_all_tzids_out (cbews, e_cal_component_get_icalcomponent (oldcomp));
+               if (success)
+                       ecb_ews_filter_out_unchanged_instances (instances, existing, &changed_instances, 
&removed_instances);
 
-       /*In case we have updated attachments we have to run update attachments
-        *before update items so attendees will receive mails with already updated attachments */
+               if (success) {
+                       for (link = changed_instances; link && success; link = g_slist_next (link)) {
+                               ChangeData *cd = link->data;
 
-       e_cal_component_get_attachment_list (oldcomp, &original_attachments);
-       e_cal_component_get_attachment_list (comp, &modified_attachments);
+                               if (!cd)
+                                       continue;
 
-       ewscal_get_attach_differences (original_attachments, modified_attachments, &removed_attachments, 
&added_attachments);
-       g_slist_free (original_attachments);
-       g_slist_free (modified_attachments);
+                               success = ecb_ews_modify_item_sync (cbews,
+                                       e_cal_component_get_icalcomponent (cd->old_component ? 
cd->old_component : master),
+                                       e_cal_component_get_icalcomponent (cd->new_component),
+                                       cancellable, error);
+                       }
 
-       /* preform sync delete attachemnt operation*/
-       if (removed_attachments) {
-               icalproperty *icalprop;
-               GSList *items;
+                       for (link = removed_instances; link && success; link = g_slist_next (link)) {
+                               ECalComponent *comp = link->data;
+                               ECalComponentId *id = NULL;
 
-               /* convert attachment uri to attachment id, should have used a hash table somehow */
-               icalcomp = e_cal_component_get_icalcomponent (oldcomp);
-               icalprop = icalcomponent_get_first_property (icalcomp, ICAL_ATTACH_PROPERTY);
-               while (icalprop) {
-                       const gchar *attachment_url = icalproperty_get_value_as_string (icalprop);
+                               if (!comp)
+                                       continue;
 
-                       for (items = removed_attachments; items; items = items->next) {
-                               if (g_strcmp0 (attachment_url, items->data) == 0) {
-                                       break;
+                               id = e_cal_component_get_id (comp);
+
+                               if (id) {
+                                       success = ecb_ews_remove_item_sync (cbews, cal_cache, id->uid, 
id->rid, cancellable, error);
+                                       e_cal_component_free_id (id);
                                }
                        }
+               }
+
+               if (success)
+                       ecb_ews_extract_item_id (master, out_new_uid, NULL);
 
-                       /* not NULL means the attachment was found in removed attachments */
-                       if (items != NULL)
-                               removed_attachments_ids = g_slist_append (removed_attachments_ids, 
icalproperty_get_parameter_as_string_r (icalprop, "X-EWS-ATTACHMENTID"));
+               g_slist_free_full (existing, g_object_unref);
+               g_slist_free_full (changed_instances, change_data_free);
+               g_slist_free_full (removed_instances, g_object_unref);
+       } else {
+               EwsCalendarConvertData convert_data = { 0 };
+               EEwsItem *item = NULL;
+               const EwsId *ews_id = NULL;
+               const gchar *send_meeting_invitations;
+               icalcomponent *icalcomp;
+               icalproperty *prop;
+               GSList *items = NULL;
+
+               icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (master));
 
-                       icalprop = icalcomponent_get_next_property (icalcomp, ICAL_ATTACH_PROPERTY);
+               e_ews_clean_icalcomponent (icalcomp);
+
+               if (!e_ews_connection_satisfies_server_version (cbews->priv->cnc, E_EWS_EXCHANGE_2010))
+                       ecb_ews_pick_all_tzids_out (cbews, icalcomp);
+
+               /*
+                * In case we are creating a meeting with attendees and attachments.
+                * We have to preform 3 steps in order to allow attendees to receive attachments in their 
invite mails.
+                * 1. create meeting and do not send invites
+                * 2. create attachments
+                * 3. dummy update meeting and send invites to all
+                */
+               if (e_cal_component_has_attendees (master)) {
+                       if (e_cal_component_has_attachments (master))
+                               send_meeting_invitations = "SendToNone";
+                       else
+                               send_meeting_invitations = "SendToAllAndSaveCopy";
+               } else {
+                       /* In case of appointment we have to set SendMeetingInvites to SendToNone */
+                       send_meeting_invitations = "SendToNone";
                }
 
-               items = NULL;
+               convert_data.connection = cbews->priv->cnc;
+               convert_data.icalcomp = icalcomp;
+               convert_data.default_zone = icaltimezone_get_utc_timezone ();
+
+               success = e_ews_connection_create_items_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM, 
"SaveOnly", send_meeting_invitations,
+                       fid, e_cal_backend_ews_convert_calcomp_to_xml, &convert_data,
+                       &items, cancellable, error);
+
+               if (success && items) {
+                       item = items->data;
+                       if (item) {
+                               g_object_ref (item);
 
-               if (removed_attachments_ids) {
-                       if (e_ews_connection_delete_attachments_sync (
-                               priv->cnc, EWS_PRIORITY_MEDIUM,
-                               removed_attachments_ids, &items, cancellable, &error) && items)
-                               changekey = items->data;
+                               ews_id = e_ews_item_get_id (item);
+                       }
                }
 
-               g_slist_free_full (removed_attachments_ids, g_free);
-               g_slist_free (removed_attachments);
-       }
+               if (success && item && e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_EVENT) {
+                       EEwsAdditionalProps *add_props;
+                       GSList *items, *items_req = NULL;
 
-       /*in case we have a new attachmetns the update item will be preformed in ews_create_attachments_cb*/
-       if (added_attachments) {
-               const gchar *old_uid = NULL;
-               gint old_uid_len = 0;
-               GSList *info_attachments = NULL;
-               EwsId *item_id = g_new0 (EwsId, 1);
-               item_id->id = itemid;
-               item_id->change_key = changekey;
-               attach_data = g_new0 (EwsCalendarAsyncData, 1);
-
-               attach_data->cbews = g_object_ref (cbews);
-               attach_data->comp = g_object_ref (comp);
-               attach_data->cb_type = E_EWS_ATTACHMENT_TYPE_UPDATE;
-               attach_data->extra_comp = g_object_ref (oldcomp);
-               attach_data->cal = g_object_ref (cal);
-               attach_data->context = 0;
-               attach_data->item_id = itemid;
-
-               e_cal_component_get_uid (oldcomp, &old_uid);
-               if (old_uid)
-                       old_uid_len = strlen (old_uid);
-
-               for (i = added_attachments; i; i = i->next) {
-                       EEwsAttachmentInfo *info = e_ews_attachment_info_new (E_EWS_ATTACHMENT_INFO_TYPE_URI);
-
-                       e_ews_attachment_info_set_uri (info, i->data);
-
-                       if (old_uid) {
-                               gchar *filename = g_filename_from_uri (i->data, NULL, NULL);
-                               if (filename) {
-                                       const gchar *slash = strrchr (filename, G_DIR_SEPARATOR);
-                                       if (slash && g_str_has_prefix (slash + 1, old_uid) &&
-                                           slash[1 + old_uid_len] == '-') {
-                                               e_ews_attachment_info_set_prefer_filename (info, slash + 1 + 
old_uid_len + 1);
-                                       }
+                       add_props = e_ews_additional_props_new ();
+                       add_props->field_uri = g_strdup ("calendar:UID");
+
+                       items = g_slist_append (NULL, ews_id->id);
 
-                                       g_free (filename);
+                       /* get calender uid from server*/
+                       success = e_ews_connection_get_items_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+                               items, "IdOnly", add_props, FALSE, NULL, E_EWS_BODY_TYPE_TEXT,
+                               &items_req, NULL, NULL, cancellable, error) && items_req != NULL;
+
+                       e_ews_additional_props_free (add_props);
+
+                       if (success) {
+                               g_clear_object (&item);
+
+                               item = items_req->data;
+                               ews_id = NULL;
+
+                               if (e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR) {
+                                       g_propagate_error (error, g_error_copy (e_ews_item_get_error (item)));
+                                       item = NULL;
+                                       success = FALSE;
+                               } else {
+                                       item = g_object_ref (item);
+                                       ews_id = e_ews_item_get_id (item);
                                }
                        }
 
-                       info_attachments = g_slist_append (info_attachments, info);
+                       g_slist_free_full (items_req, g_object_unref);
+                       g_slist_free (items);
                }
 
-               if (context) {
-                       convert_error_to_edc_error (&error);
-                       e_data_cal_respond_modify_objects (cal, context, error, NULL, NULL);
+               /* attachments */
+               if (success && e_cal_component_has_attachments (master) > 0) {
+                       GSList *info_attachments = NULL;
+
+                       if (ecb_ews_extract_attachments (icalcomp, &info_attachments)) {
+                               GSList *ids = NULL;
+
+                               success = e_ews_connection_create_attachments_sync (cbews->priv->cnc, 
EWS_PRIORITY_MEDIUM,
+                                       ews_id, info_attachments, FALSE, NULL, &ids, cancellable, error);
+
+                               g_slist_free_full (info_attachments, (GDestroyNotify) 
e_ews_attachment_info_free);
+                               g_slist_free_full (ids, g_free);
+                       }
                }
 
-               e_ews_connection_create_attachments (
-                       priv->cnc, EWS_PRIORITY_MEDIUM,
-                       item_id, info_attachments,
-                       FALSE, cancellable,
-                       ews_create_attachments_cb,
-                       attach_data);
+               if (success && icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY)) {
+                       GSList *exceptions = NULL;
 
-               g_slist_free_full (info_attachments, (GDestroyNotify) e_ews_attachment_info_free);
-               g_slist_free (added_attachments);
-               g_free (item_id);
+                       /* Excluded occurrences */
+                       for (prop = icalcomponent_get_first_property (icalcomp, ICAL_EXDATE_PROPERTY);
+                            prop;
+                            prop = icalcomponent_get_next_property (icalcomp, ICAL_EXDATE_PROPERTY)) {
+                               exceptions = g_slist_prepend (exceptions, g_strdup 
(icalproperty_get_value_as_string (prop)));
+                       }
 
-       } else {
-               EwsCalendarConvertData convert_data = { 0 };
-               const gchar *send_meeting_invitations;
-               const gchar *send_or_save;
+                       for (link = exceptions; link && success; link = g_slist_next (link)) {
+                               success = ecb_ews_remove_item_sync (cbews, cal_cache, uid, link->data, 
cancellable, error);
+                       }
 
-               modify_data = g_new0 (EwsCalendarAsyncData, 1);
-               modify_data->cbews = g_object_ref (cbews);
-               modify_data->comp = g_object_ref (comp);
-               modify_data->extra_comp = g_object_ref (oldcomp);
-               modify_data->cal = g_object_ref (cal);
-               modify_data->context = context;
-               modify_data->item_id = itemid;
+                       g_slist_free_full (exceptions, g_free);
+               }
 
-               convert_data.connection = cbews->priv->cnc;
-               convert_data.user_email = cbews->priv->user_email;
-               convert_data.comp = comp;
-               convert_data.old_comp = oldcomp;
-               convert_data.item_id = itemid;
-               convert_data.change_key = changekey;
-               convert_data.default_zone = cbews->priv->default_zone;
+               if (success && e_cal_component_has_attendees (master) && e_cal_component_has_attachments 
(master)) {
+                       if (ews_id) {
+                               e_cal_util_set_x_property (icalcomp, "X-EVOLUTION-ITEMID", ews_id->id);
+                               e_cal_util_set_x_property (icalcomp, "X-EVOLUTION-CHANGEKEY", 
ews_id->change_key);
+                       }
 
-               if (e_cal_component_has_attendees (comp)) {
-                       send_meeting_invitations = "SendToAllAndSaveCopy";
-                       send_or_save = "SendAndSaveCopy";
-               } else {
-                       /*In case of appointment we have to set SendMeetingInvites to SendToNone */
-                       send_meeting_invitations = "SendToNone";
-                       send_or_save = "SaveOnly";
+                       /* In case we have attendees and atachemnts we have to fake update items,
+                        * this is the only way to pass attachments in meeting invite mail */
+                       success = ecb_ews_modify_item_sync (cbews, NULL, icalcomp, cancellable, error);
                }
 
-               e_ews_connection_update_items (
-                       priv->cnc, EWS_PRIORITY_MEDIUM,
-                       "AlwaysOverwrite",
-                       send_or_save,
-                       send_meeting_invitations,
-                       priv->folder_id,
-                       e_cal_backend_ews_convert_component_to_updatexml,
-                       &convert_data,
-                       cancellable,
-                       ews_cal_modify_object_cb,
-                       modify_data);
+               icalcomponent_free (icalcomp);
+               g_clear_object (&item);
+
+               for (link = (GSList *) instances; link && success; link = g_slist_next (link)) {
+                       ECalComponent *comp = link->data;
+
+                       if (comp == master)
+                               continue;
+
+                       icalcomp = e_cal_component_get_icalcomponent (comp);
+
+                       success = ecb_ews_modify_item_sync (cbews, NULL, icalcomp, cancellable, error);
+               }
+
+               if (success && items) {
+                       EEwsItem *item = items->data;
+                       const EwsId *item_id;
+
+                       item_id = e_ews_item_get_id (item);
+                       *out_new_uid = g_strdup (item_id->id);
+               }
+
+               g_slist_free_full (items, g_object_unref);
        }
 
-       g_clear_object (&oldcomp);
+       g_rec_mutex_unlock (&cbews->priv->cnc_lock);
 
-       return;
+       g_clear_object (&cal_cache);
+       e_ews_folder_id_free (fid);
 
-exit:
-       g_clear_object (&oldcomp);
-       g_clear_object (&comp);
+       ecb_ews_convert_error_to_edc_error (error);
+
+       return success;
+}
+
+static gboolean
+ecb_ews_remove_component_sync (ECalMetaBackend *meta_backend,
+                              EConflictResolution conflict_resolution,
+                              const gchar *uid,
+                              const gchar *extra,
+                              const gchar *object,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       ECalBackendEws *cbews;
+       ECalComponent *comp;
+       EwsId item_id;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (meta_backend), FALSE);
+       g_return_val_if_fail (object != NULL, FALSE);
+
+       cbews = E_CAL_BACKEND_EWS (meta_backend);
 
-       convert_error_to_edc_error (&error);
-       if (context)
-               e_data_cal_respond_modify_objects (cal, context, error, NULL, NULL);
-       else if (error) {
-               g_warning ("Modify object error :  %s\n", error->message);
-               g_clear_error (&error);
+       comp = e_cal_component_new_from_string (object);
+       if (!comp) {
+               g_propagate_error (error, EDC_ERROR (InvalidObject));
+               return FALSE;
        }
+
+       g_rec_mutex_lock (&cbews->priv->cnc_lock);
+
+       ecb_ews_extract_item_id (comp, &item_id.id, &item_id.change_key);
+
+       success = e_ews_connection_delete_item_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM, &item_id, 0, 
EWS_HARD_DELETE,
+               ecb_ews_is_organizer (cbews, comp) ? EWS_SEND_TO_ALL_AND_SAVE_COPY : EWS_SEND_TO_NONE,
+               EWS_ALL_OCCURRENCES, cancellable, error);
+
+       g_free (item_id.id);
+       g_free (item_id.change_key);
+
+       g_rec_mutex_unlock (&cbews->priv->cnc_lock);
+
+       ecb_ews_convert_error_to_edc_error (error);
+       g_object_unref (comp);
+
+       return success;
 }
 
 static void
-e_ews_receive_objects_no_exchange_mail (ECalBackendEws *cbews,
-                                        icalcomponent *subcomp,
-                                        GSList **ids,
-                                        GCancellable *cancellable,
-                                        GError **error)
+ecb_ews_discard_alarm_sync (ECalBackendSync *cal_backend_sync,
+                           EDataCal *cal,
+                           GCancellable *cancellable,
+                           const gchar *uid,
+                           const gchar *rid,
+                           const gchar *auid,
+                           GError **error)
+{
+       ECalBackendEws *cbews;
+       ECalCache *cal_cache;
+       ECalComponent *comp = NULL;
+       EwsCalendarConvertData convert_data = { 0 };
+
+       g_return_if_fail (E_IS_CAL_BACKEND_EWS (cal_backend_sync));
+
+       cbews = E_CAL_BACKEND_EWS (cal_backend_sync);
+
+       cal_cache = e_cal_meta_backend_ref_cache (E_CAL_META_BACKEND (cbews));
+       g_return_if_fail (cal_cache != NULL);
+
+       if (!e_cal_cache_get_component (cal_cache, uid, NULL, &comp, cancellable, NULL) || !comp) {
+               g_object_unref (cal_cache);
+               g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+               return;
+       }
+
+       g_object_unref (cal_cache);
+
+       if (!e_cal_meta_backend_ensure_connected_sync (E_CAL_META_BACKEND (cbews), cancellable, error)) {
+               g_clear_object (&comp);
+               return;
+       }
+
+       if (e_cal_component_has_recurrences (comp)) {
+               gint *index;
+
+               convert_data.change_type = E_EWS_ITEMCHANGE_TYPE_OCCURRENCEITEM;
+               e_cal_component_get_sequence (comp, &index);
+
+               if (index != NULL) {
+                       /*Microsoft is counting the occurrences starting from 1
+                        where EcalComponent is starting from zerro */
+                       convert_data.index = *index + 1;
+                       e_cal_component_free_sequence (index);
+               } else {
+                       convert_data.change_type = E_EWS_ITEMCHANGE_TYPE_ITEM;
+                       convert_data.index = -1;
+               }
+       } else {
+               convert_data.change_type = E_EWS_ITEMCHANGE_TYPE_ITEM;
+               convert_data.index = -1;
+       }
+
+       ecb_ews_extract_item_id (comp, &convert_data.item_id, &convert_data.change_key);
+
+       if (e_ews_connection_update_items_sync (
+               cbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+               "AlwaysOverwrite", NULL,
+               "SendToNone", NULL,
+               e_cal_backend_ews_clear_reminder_is_set,
+               &convert_data,
+               NULL,
+               cancellable,
+               error)) {
+               icalcomponent *icomp = e_cal_component_get_icalcomponent (comp);
+               GSList *modified_objects;
+
+               modified_objects = g_slist_prepend (NULL,
+                       e_cal_meta_backend_info_new (icalcomponent_get_uid (icomp), NULL, NULL,
+                               e_cal_util_get_x_property (icomp, "X-EVOLUTION-ITEMID")));
+
+               /* Refresh the local cache, to have up-to-date ChangeKey */
+               e_cal_meta_backend_process_changes_sync (E_CAL_META_BACKEND (cbews), NULL, modified_objects, 
NULL, cancellable, error);
+
+               g_slist_free_full (modified_objects, e_cal_meta_backend_info_free);
+       }
+
+       g_object_unref (comp);
+       g_free (convert_data.item_id);
+       g_free (convert_data.change_key);
+
+       ecb_ews_convert_error_to_edc_error (error);
+}
+
+static gboolean
+ecb_ews_send_cancellation_email_sync (ECalBackendEws *cbews,
+                                     CamelAddress *from,
+                                     CamelInternetAddress *recipient,
+                                     const gchar *subject,
+                                     const gchar *body,
+                                     const gchar *calobj,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+       CamelMimeMessage *message;
+       CamelContentType *mime_type;
+       CamelMultipart *multi;
+       CamelMimePart *text_part, *vcal_part;
+       gchar *ical_str;
+       icalcomponent *vcal, *vevent, *vtz;
+       icalproperty *prop;
+       icaltimezone *icaltz;
+       struct icaltimetype dt;
+       gboolean success;
+
+       vcal = icalcomponent_new (ICAL_VCALENDAR_COMPONENT);
+       icalcomponent_add_property (vcal, icalproperty_new_version ("2.0"));
+       icalcomponent_add_property (vcal, icalproperty_new_prodid ("-//Evolution EWS backend//EN"));
+       icalcomponent_add_property (vcal, icalproperty_new_method (ICAL_METHOD_CANCEL));
+       vevent = icalcomponent_new_from_string (calobj);
+       prop = icalcomponent_get_first_property (vevent, ICAL_STATUS_PROPERTY);
+       if (prop != NULL) icalcomponent_remove_property (vevent, prop);
+       icalcomponent_add_property (vevent, icalproperty_new_status (ICAL_STATUS_CANCELLED));
+       prop = icalcomponent_get_first_property (vevent, ICAL_METHOD_PROPERTY);
+       if (prop != NULL) icalcomponent_remove_property (vevent, prop);
+       dt = icalcomponent_get_dtstart (vevent);
+       icaltz = (icaltimezone *)
+               (dt.zone ? dt.zone : ecb_ews_get_timezone_from_ical_component (cbews, vevent));
+       vtz = icaltimezone_get_component (icaltz);
+       icalcomponent_add_component (vcal, icalcomponent_new_clone (vtz));
+       icalcomponent_add_component (vcal, vevent);
+       text_part = camel_mime_part_new ();
+       camel_mime_part_set_content (text_part, body, strlen (body), "text/plain");
+
+       vcal_part = camel_mime_part_new ();
+       mime_type = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (vcal_part));
+       camel_content_type_set_param (mime_type, "charset", "utf-8");
+       camel_content_type_set_param (mime_type, "method", "CANCEL");
+       ical_str = icalcomponent_as_ical_string_r ((icalcomponent *) vcal);
+       camel_mime_part_set_content (vcal_part, ical_str, strlen (ical_str), "text/calendar; method=CANCEL");
+       free (ical_str);
+
+       multi = camel_multipart_new ();
+       camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multi), "multipart/alternative");
+       camel_multipart_add_part (multi, text_part);
+       camel_multipart_set_boundary (multi, NULL);
+       camel_multipart_add_part (multi, vcal_part);
+       g_object_unref (text_part);
+       g_object_unref (vcal_part);
+
+       message = camel_mime_message_new ();
+       camel_mime_message_set_subject (message, subject);
+       camel_mime_message_set_from (message, CAMEL_INTERNET_ADDRESS (from));
+       camel_mime_message_set_recipients (message, CAMEL_RECIPIENT_TYPE_TO, recipient);
+
+       camel_medium_set_content ((CamelMedium *) message, (CamelDataWrapper *) multi);
+       g_object_unref (multi);
+
+       success = camel_ews_utils_create_mime_message (cbews->priv->cnc, "SendOnly", NULL, message, NULL, 
from, NULL, NULL, NULL, cancellable, error);
+
+       g_object_unref (message);
+       icalcomponent_free (vcal);
+
+       return success;
+}
+
+static void
+ecb_ews_receive_objects_no_exchange_mail (ECalBackendEws *cbews,
+                                         icalcomponent *subcomp,
+                                         GSList **ids,
+                                         GCancellable *cancellable,
+                                         GError **error)
 {
        EwsCalendarConvertData convert_data = { 0 };
        EwsFolderId *fid;
 
        convert_data.connection = cbews->priv->cnc;
        convert_data.icalcomp = subcomp;
-       convert_data.default_zone = cbews->priv->default_zone;
+       convert_data.default_zone = icaltimezone_get_utc_timezone ();
 
        fid = e_ews_folder_id_new (cbews->priv->folder_id, NULL, FALSE);
 
@@ -2331,9 +2910,9 @@ find_attendee_if_sentby (icalcomponent *ical_comp,
 }
 
 static const gchar *
-e_ews_get_current_user_meeting_reponse (ECalBackendEws *cbews,
-                                       icalcomponent *icalcomp,
-                                        const gchar *current_user_mail)
+ecb_ews_get_current_user_meeting_reponse (ECalBackendEws *cbews,
+                                         icalcomponent *icalcomp,
+                                         const gchar *current_user_mail)
 {
        icalproperty *attendee;
        const gchar *attendee_str = NULL, *attendee_mail = NULL;
@@ -2415,11 +2994,53 @@ e_ews_get_current_user_meeting_reponse (ECalBackendEws *cbews,
        return response;
 }
 
+/* changekey can be NULL if you don't want it. itemid cannot. */
 static void
-ews_cal_do_method_request_publish_reply (ECalBackendEws *cbews,
+ecb_ews_get_item_accept_id (ECalComponent *comp,
+                           gchar **itemid,
+                           gchar **changekey,
+                           gchar **mail_id)
+{
+       icalproperty *prop;
+       gchar *id_item = NULL;
+       gchar *id_accept = NULL;
+       gchar *ck = NULL;
+
+       prop = icalcomponent_get_first_property (
+               e_cal_component_get_icalcomponent (comp),
+               ICAL_X_PROPERTY);
+       while (prop) {
+               const gchar *x_name, *x_val;
+
+               x_name = icalproperty_get_x_name (prop);
+               x_val = icalproperty_get_x (prop);
+               if (!id_item && g_ascii_strcasecmp (x_name, "X-EVOLUTION-ITEMID") == 0)
+                       id_item = g_strdup (x_val);
+               else if (!id_accept && g_ascii_strcasecmp (x_name, "X-EVOLUTION-ACCEPT-ID") == 0)
+                       id_accept = g_strdup (x_val);
+               else if (changekey && !ck && !g_ascii_strcasecmp (x_name, "X-EVOLUTION-CHANGEKEY"))
+                       ck = g_strdup (x_val);
+
+               prop = icalcomponent_get_next_property (
+                       e_cal_component_get_icalcomponent (comp),
+                       ICAL_X_PROPERTY);
+       }
+
+       if (!id_item)
+               id_item = g_strdup (id_accept);
+
+       *itemid = id_item;
+       *mail_id = id_accept;
+       if (changekey)
+               *changekey = ck;
+}
+
+static gboolean
+ecb_ews_do_method_request_publish_reply (ECalBackendEws *cbews,
                                         ECalComponent *comp,
                                         icalcomponent *subcomp,
                                         const gchar *response_type,
+                                        const gchar *user_email,
                                         GCancellable *cancellable,
                                         GError **error)
 {
@@ -2433,19 +3054,19 @@ ews_cal_do_method_request_publish_reply (ECalBackendEws *cbews,
        if (!response_type &&
            e_cal_util_component_has_organizer (subcomp) &&
            e_cal_util_component_has_attendee (subcomp)) {
-               g_set_error (error, E_DATA_CAL_ERROR, UnknownUser, _("Cannot find user “%s” between 
attendees"), cbews->priv->user_email ? cbews->priv->user_email : "NULL");
-               return;
+               g_set_error (error, E_DATA_CAL_ERROR, UnknownUser, _("Cannot find user “%s” between 
attendees"), user_email ? user_email : "NULL");
+               return FALSE;
        }
 
        if (response_type && *response_type)
-               ews_cal_component_get_calendar_item_accept_id (comp, &item_id, &change_key, &mail_id);
+               ecb_ews_get_item_accept_id (comp, &item_id, &change_key, &mail_id);
        else
                response_type = NULL;
 
        while (pass < 2) {
                /*in case we do not have item id we will create item with mime content only*/
                if (!item_id || (response_type && g_ascii_strcasecmp (response_type, "NEEDS-ACTION") == 0)) {
-                       e_ews_receive_objects_no_exchange_mail (cbews, subcomp, &ids, cancellable, 
&local_error);
+                       ecb_ews_receive_objects_no_exchange_mail (cbews, subcomp, &ids, cancellable, 
&local_error);
                } else {
                        EwsCalendarConvertData convert_data = { 0 };
 
@@ -2575,301 +3196,182 @@ ews_cal_do_method_request_publish_reply (ECalBackendEws *cbews,
        g_free (mail_id);
        g_slist_free_full (ids, g_object_unref);
 
-       /*We have to run sync before any other operations */
-       ews_start_sync (cbews);
+       return !local_error;
 }
 
 static void
-e_cal_backend_ews_receive_objects (ECalBackend *backend,
-                                   EDataCal *cal,
-                                   guint32 context,
-                                   GCancellable *cancellable,
-                                   const gchar *calobj)
+ecb_ews_receive_objects_sync (ECalBackendSync *sync_backend,
+                             EDataCal *cal,
+                             GCancellable *cancellable,
+                             const gchar *calobj,
+                             GError **error)
 {
        ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-       icalcomponent_kind kind;
+       ECalBackend *cal_backend;
+       CamelEwsSettings *ews_settings;
        icalcomponent *icalcomp, *subcomp;
-       GError *error = NULL;
-       icalproperty_method method;
+       icalcomponent_kind kind;
+       gchar *user_email;
+       gboolean success = TRUE, do_refresh = FALSE;
 
-       cbews = E_CAL_BACKEND_EWS (backend);
-       priv = cbews->priv;
+       g_return_if_fail (E_IS_CAL_BACKEND_EWS (sync_backend));
 
-       /* make sure we're not offline */
-       if (!e_backend_get_online (E_BACKEND (backend)) || !cbews->priv->cnc) {
-               g_propagate_error (&error, EDC_ERROR (RepositoryOffline));
-               goto exit;
-       }
+       cbews = E_CAL_BACKEND_EWS (sync_backend);
 
-       if (!cal_backend_ews_ensure_connected (cbews, cancellable, &error)) {
-               goto exit;
-       }
+       if (!e_cal_meta_backend_ensure_connected_sync (E_CAL_META_BACKEND (cbews), cancellable, error))
+               return;
 
-       icalcomp = icalparser_parse_string (calobj);
+       icalcomp = calobj ? icalparser_parse_string (calobj) : NULL;
 
-       /* make sure data was parsed properly */
        if (!icalcomp) {
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
+               g_propagate_error (error, EDC_ERROR (InvalidObject));
+               return;
        }
 
-       /* make sure ical data we parse is actually an vcal component */
+       /* make sure ical data we parse is actually a vCalendar component */
        if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) {
                icalcomponent_free (icalcomp);
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
+               g_propagate_error (error, EDC_ERROR (InvalidObject));
+               return;
        }
 
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
-       method = icalcomponent_get_method (icalcomp);
-       subcomp = icalcomponent_get_first_component (icalcomp, kind);
-
-       while (subcomp) {
-               ECalComponent *comp = e_cal_component_new ();
-               const gchar *response_type;
+       cal_backend = E_CAL_BACKEND (cbews);
+       kind = e_cal_backend_get_kind (cal_backend);
 
-               /* duplicate the ical component */
-               e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
-
-               /*getting a data for meeting request response*/
-               response_type = e_ews_get_current_user_meeting_reponse (cbews,
-                       e_cal_component_get_icalcomponent (comp),
-                       priv->user_email);
-
-               switch (method) {
-                       case ICAL_METHOD_REQUEST:
-                       case ICAL_METHOD_PUBLISH:
-                       case ICAL_METHOD_REPLY:
-                               ews_cal_do_method_request_publish_reply (
-                                       cbews,
-                                       comp,
-                                       subcomp,
-                                       response_type,
-                                       cancellable,
-                                       &error);
-                               break;
-                       case ICAL_METHOD_CANCEL: {
-                               const gchar *uid = NULL;
-                               gchar *rid = NULL;
-                               ECalObjModType mod;
-
-                               e_cal_component_get_uid (comp, &uid);
-                               rid = e_cal_component_get_recurid_as_string (comp);
-                               mod = e_cal_component_is_instance (comp) ? E_CAL_OBJ_MOD_THIS : 
E_CAL_OBJ_MOD_ALL;
-
-                               e_cal_backend_ews_remove_object (backend, cal, 0, cancellable, uid, rid, mod);
-                               g_free (rid);
-                               break;
-                       }
-                       case ICAL_METHOD_COUNTER:
-                               /*
-                                * this is a new time proposal mail from one of the attendees
-                                * if we decline the proposal, nothing have to be done
-                                * if we accept it we will call to modify_object
-                                */
-                               if (g_strcmp0 (response_type, "ACCEPTED") == 0) {
-                                       gchar **split_subject;
-                                       icalproperty *summary;
-
-                                       /*
-                                        * we have to edit the meeting subject to remove exchange header
-                                        */
-                                       summary = icalcomponent_get_first_property (subcomp, 
ICAL_SUMMARY_PROPERTY);
-                                       split_subject =
-                                               g_strsplit (icalproperty_get_value_as_string (summary), ":", 
-1);
-                                       icalproperty_set_value_from_string (summary, split_subject[1] , "NO");
-                                       g_strfreev (split_subject);
-
-                                       e_cal_backend_ews_modify_object (backend, cal, 0, cancellable, 
icalcomponent_as_ical_string (subcomp), E_CAL_OBJ_MOD_ALL);
-                               }
-                               break;
-                       default:
-                               break;
-               }
+       ews_settings = ecb_ews_get_collection_settings (cbews);
+       user_email = camel_ews_settings_dup_email (ews_settings);
 
-               g_object_unref (comp);
-               subcomp = icalcomponent_get_next_component (icalcomp, kind);
-       }
+       switch (icalcomponent_get_method (icalcomp)) {
+       case ICAL_METHOD_REQUEST:
+       case ICAL_METHOD_PUBLISH:
+       case ICAL_METHOD_REPLY:
+               for (subcomp = icalcomponent_get_first_component (icalcomp, kind);
+                    subcomp && success;
+                    subcomp = icalcomponent_get_next_component (icalcomp, kind)) {
+                       ECalComponent *comp;
+                       const gchar *response_type;
 
-       icalcomponent_free (icalcomp);
+                       /* getting a data for meeting request response */
+                       response_type = ecb_ews_get_current_user_meeting_reponse (cbews, subcomp, user_email);
 
-exit:
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_receive_objects (cal, context, error);
-}
+                       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (subcomp));
 
-static const gchar *
-e_cal_get_meeting_cancellation_comment (ECalComponent *comp)
-{
-       icalproperty *prop;
-       prop = icalcomponent_get_first_property (
-               e_cal_component_get_icalcomponent (comp),
-               ICAL_X_PROPERTY);
-       while (prop) {
-               const gchar *x_name, *x_val;
-               x_name = icalproperty_get_x_name (prop);
-               x_val = icalproperty_get_x (prop);
-               if (!g_ascii_strcasecmp (x_name, "X-EVOLUTION-RETRACT-COMMENT"))
-                       return x_val;
+                       success = ecb_ews_do_method_request_publish_reply (cbews, comp, subcomp, 
response_type, user_email, cancellable, error);
 
-               prop = icalcomponent_get_next_property (
-                       e_cal_component_get_icalcomponent (comp),
-                       ICAL_X_PROPERTY);
-       }
+                       do_refresh = TRUE;
 
-       return NULL;
-}
-
-static void
-ewscal_send_cancellation_email (ECalBackend *backend,
-                                EEwsConnection *cnc,
-                                CamelAddress *from,
-                                CamelInternetAddress *recipient,
-                                const gchar *subject,
-                                const gchar *body,
-                                const gchar *calobj)
-{
-       CamelMimeMessage *message;
-       CamelContentType *mime_type;
-       GError *error = NULL;
-       CamelMultipart *multi;
-       CamelMimePart *text_part, *vcal_part;
-       gchar *ical_str;
-       icalcomponent *vcal, *vevent, *vtz;
-       icalproperty *prop;
-       icaltimezone *icaltz;
-       struct icaltimetype dt;
-
-       vcal = icalcomponent_new (ICAL_VCALENDAR_COMPONENT);
-       icalcomponent_add_property (vcal, icalproperty_new_version ("2.0"));
-       icalcomponent_add_property (vcal, icalproperty_new_prodid ("-//Evolution EWS backend//EN"));
-       icalcomponent_add_property (vcal, icalproperty_new_method (ICAL_METHOD_CANCEL));
-       vevent = icalcomponent_new_from_string (calobj);
-       prop = icalcomponent_get_first_property (vevent, ICAL_STATUS_PROPERTY);
-       if (prop != NULL) icalcomponent_remove_property (vevent, prop);
-       icalcomponent_add_property (vevent, icalproperty_new_status (ICAL_STATUS_CANCELLED));
-       prop = icalcomponent_get_first_property (vevent, ICAL_METHOD_PROPERTY);
-       if (prop != NULL) icalcomponent_remove_property (vevent, prop);
-       dt = icalcomponent_get_dtstart (vevent);
-       icaltz = (icaltimezone *)
-               (dt.zone ? dt.zone : e_cal_backend_ews_get_timezone_from_ical_component (backend, vevent));
-       vtz = icaltimezone_get_component (icaltz);
-       icalcomponent_add_component (vcal, icalcomponent_new_clone (vtz));
-       icalcomponent_add_component (vcal, vevent);
-       text_part = camel_mime_part_new ();
-       camel_mime_part_set_content (text_part, body, strlen (body), "text/plain");
-
-       vcal_part = camel_mime_part_new ();
-       mime_type = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (vcal_part));
-       camel_content_type_set_param (mime_type, "charset", "utf-8");
-       camel_content_type_set_param (mime_type, "method", "CANCEL");
-       ical_str = icalcomponent_as_ical_string_r ((icalcomponent *) vcal);
-       camel_mime_part_set_content (vcal_part, ical_str, strlen (ical_str), "text/calendar; method=CANCEL");
-       free (ical_str);
+                       g_object_unref (comp);
+               }
+               break;
+       case ICAL_METHOD_COUNTER:
+               /*
+                * this is a new time proposal mail from one of the attendees
+                * if we decline the proposal, nothing have to be done
+                * if we accept it we will call to modify_object
+                */
+               for (subcomp = icalcomponent_get_first_component (icalcomp, kind);
+                    subcomp && success;
+                    subcomp = icalcomponent_get_next_component (icalcomp, kind)) {
+                       const gchar *response_type;
 
-       multi = camel_multipart_new ();
-       camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multi), "multipart/alternative");
-       camel_multipart_add_part (multi, text_part);
-       camel_multipart_set_boundary (multi, NULL);
-       camel_multipart_add_part (multi, vcal_part);
-       g_object_unref (text_part);
-       g_object_unref (vcal_part);
+                       /* getting a data for meeting request response */
+                       response_type = ecb_ews_get_current_user_meeting_reponse (cbews, subcomp, user_email);
 
-       message = camel_mime_message_new ();
-       camel_mime_message_set_subject (message, subject);
-       camel_mime_message_set_from (message, CAMEL_INTERNET_ADDRESS (from));
-       camel_mime_message_set_recipients (message, CAMEL_RECIPIENT_TYPE_TO, recipient);
+                       if (g_strcmp0 (response_type, "ACCEPTED") == 0) {
+                               gchar **split_subject;
+                               icalproperty *summary;
 
-       camel_medium_set_content ((CamelMedium *) message, (CamelDataWrapper *) multi);
-       g_object_unref (multi);
+                               /* we have to edit the meeting subject to remove exchange header */
+                               summary = icalcomponent_get_first_property (subcomp, ICAL_SUMMARY_PROPERTY);
+                               split_subject =
+                                       g_strsplit (icalproperty_get_value_as_string (summary), ":", -1);
+                               icalproperty_set_value_from_string (summary, split_subject[1] , "NO");
+                               g_strfreev (split_subject);
 
-       camel_ews_utils_create_mime_message (cnc, "SendOnly", NULL, message, NULL, from, NULL, NULL, NULL, 
NULL, &error);
+                               success = ecb_ews_modify_item_sync (cbews, NULL, subcomp, cancellable, error);
 
-       if (error) {
-               g_warning ("Failed to send cancellation email: %s", error->message);
-               g_clear_error (&error);
+                               do_refresh = TRUE;
+                       }
+               }
+               break;
+       default:
+               break;
        }
 
-       g_object_unref (message);
-       icalcomponent_free (vcal);
+       icalcomponent_free (icalcomp);
+       g_free (user_email);
+
+       if (success && do_refresh)
+               e_cal_meta_backend_schedule_refresh (E_CAL_META_BACKEND (cbews));
 }
 
 static void
-e_cal_backend_ews_send_objects (ECalBackend *backend,
-                                EDataCal *cal,
-                                guint32 context,
-                                GCancellable *cancellable,
-                                const gchar *calobj)
+ecb_ews_send_objects_sync (ECalBackendSync *sync_backend,
+                          EDataCal *cal,
+                          GCancellable *cancellable,
+                          const gchar *calobj,
+                          GSList **users,
+                          gchar **modified_calobj,
+                          GError **error)
 {
        ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
        icalcomponent_kind kind;
        icalcomponent *icalcomp, *subcomp = NULL;
-       GError *error = NULL;
        gchar *subcalobj;
+       gboolean success = TRUE;
 
-       cbews = E_CAL_BACKEND_EWS (backend);
-       priv = cbews->priv;
+       g_return_if_fail (E_IS_CAL_BACKEND_EWS (sync_backend));
 
-       /* make sure we're not offline */
-       if (!e_backend_get_online (E_BACKEND (backend)) || !cbews->priv->cnc) {
-               g_propagate_error (&error, EDC_ERROR (RepositoryOffline));
-               goto exit;
-       }
+       cbews = E_CAL_BACKEND_EWS (sync_backend);
 
-       if (!cal_backend_ews_ensure_connected (cbews, cancellable, &error)) {
-               goto exit;
-       }
+       if (!e_cal_meta_backend_ensure_connected_sync (E_CAL_META_BACKEND (cbews), cancellable, error))
+               return;
 
-       icalcomp = icalparser_parse_string (calobj);
+       icalcomp = calobj ? icalparser_parse_string (calobj) : NULL;
 
        /* make sure data was parsed properly */
        if (!icalcomp) {
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
+               g_propagate_error (error, EDC_ERROR (InvalidObject));
+               return;
        }
+
        /* make sure ical data we parse is actually an vcal component */
        if ((icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) && (icalcomponent_isa (icalcomp) != 
ICAL_VEVENT_COMPONENT)) {
                icalcomponent_free (icalcomp);
-               g_propagate_error (&error, EDC_ERROR (InvalidObject));
-               goto exit;
+               g_propagate_error (error, EDC_ERROR (InvalidObject));
+               return;
        }
 
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+       kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbews));
 
        if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
-               kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+               kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbews));
                subcomp = icalcomponent_get_first_component (icalcomp, kind);
        }
        if (icalcomponent_isa (icalcomp) == ICAL_VEVENT_COMPONENT)
                subcomp = icalcomp;
-       while (subcomp) {
-               ECalComponent *comp = e_cal_component_new ();
+       while (subcomp && success) {
                const gchar *new_body_content = NULL, *subject = NULL, *org_email = NULL;
                const gchar *org = NULL, *attendee = NULL;
                icalproperty *prop, *org_prop = NULL;
                CamelInternetAddress *org_addr = camel_internet_address_new ();
 
-               e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
-
-               new_body_content = e_cal_get_meeting_cancellation_comment (comp);
+               new_body_content = e_cal_util_get_x_property (subcomp, "X-EVOLUTION-RETRACT-COMMENT");
                subject = icalproperty_get_value_as_string (icalcomponent_get_first_property (subcomp, 
ICAL_SUMMARY_PROPERTY));
 
                org_prop = icalcomponent_get_first_property (subcomp, ICAL_ORGANIZER_PROPERTY);
                org = icalproperty_get_organizer (org_prop);
                if (!g_ascii_strncasecmp (org, "MAILTO:", 7))
                        org_email = (org) + 7;
-                       else
-                               org_email = org;
+               else
+                       org_email = org;
 
                camel_internet_address_add (org_addr, icalproperty_get_parameter_as_string (org_prop, "CN"), 
org_email);
 
                /* iterate over every attendee property */
                for (prop = icalcomponent_get_first_property (subcomp, ICAL_ATTENDEE_PROPERTY);
-                       prop != NULL;
-                       prop = icalcomponent_get_next_property (subcomp, ICAL_ATTENDEE_PROPERTY)) {
-
+                    prop && success;
+                    prop = icalcomponent_get_next_property (subcomp, ICAL_ATTENDEE_PROPERTY)) {
                        CamelInternetAddress *attendee_addr = camel_internet_address_new ();
                        attendee = icalproperty_get_attendee (prop);
                        if (g_ascii_strcasecmp (org_email, attendee) == 0) continue;
@@ -2877,1579 +3379,103 @@ e_cal_backend_ews_send_objects (ECalBackend *backend,
 
                        subcalobj = icalcomponent_as_ical_string_r (subcomp);
                        camel_internet_address_add (attendee_addr, icalproperty_get_parameter_as_string 
(prop, "CN"), attendee);
-                       ewscal_send_cancellation_email (backend, priv->cnc, CAMEL_ADDRESS (org_addr), 
attendee_addr, subject, new_body_content, subcalobj);
+                       success = ecb_ews_send_cancellation_email_sync (cbews, CAMEL_ADDRESS (org_addr), 
attendee_addr,
+                               subject, new_body_content, subcalobj, cancellable, error);
                        g_object_unref (attendee_addr);
                        free (subcalobj);
                }
 
                g_object_unref (org_addr);
-               g_object_unref (comp);
                subcomp = icalcomponent_get_next_component (icalcomp, kind);
        }
 
        icalcomponent_free (icalcomp);
 
-exit:
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_send_objects (cal, context, error,  NULL, calobj);
-}
-
-/* TODO Do not replicate this in every backend */
-static icaltimezone *
-resolve_tzid (const gchar *tzid,
-              gpointer user_data)
-{
-       ETimezoneCache *timezone_cache;
-
-       timezone_cache = E_TIMEZONE_CACHE (user_data);
-
-       return e_timezone_cache_get_timezone (timezone_cache, tzid);
+       ecb_ews_convert_error_to_edc_error (error);
 }
 
 static void
-put_component_to_store (ECalBackendEws *cbews,
-                        ECalComponent *comp)
+ecb_ews_get_free_busy_sync (ECalBackendSync *sync_backend,
+                           EDataCal *cal,
+                           GCancellable *cancellable,
+                           const GSList *users,
+                           time_t start,
+                           time_t end,
+                           GSList **freebusyobjs,
+                           GError **error)
 {
-       time_t time_start, time_end;
-       ECalBackendEwsPrivate *priv;
-
-       priv = cbews->priv;
-
-       e_cal_util_get_component_occur_times (
-               comp, &time_start, &time_end,
-               resolve_tzid, cbews, priv->default_zone,
-               e_cal_backend_get_kind (E_CAL_BACKEND (cbews)));
-
-       e_cal_backend_store_put_component_with_time_range (priv->store, comp, time_start, time_end);
-}
-
-static void
-ews_get_attachments (ECalBackendEws *cbews,
-                     EEwsItem *item)
-{
-       gboolean has_attachment = FALSE;
-       const GSList *attachment_ids, *aid, *l;
-       const EwsId *item_id;
-       ECalComponent *comp;
-       const gchar *uid;
-       GSList *uris = NULL, *info_attachments = NULL;
-       GCancellable *cancellable;
+       ECalBackendEws *cbews;
+       EEWSFreeBusyData fbdata = { 0 };
+       GSList *freebusy = NULL;
+       gboolean success;
 
-       e_ews_item_has_attachments (item, &has_attachment);
-       if (!has_attachment)
-               return;
+       g_return_if_fail (E_IS_CAL_BACKEND_EWS (sync_backend));
+       g_return_if_fail (freebusyobjs != NULL);
 
-       item_id = e_ews_item_get_id (item);
-       g_return_if_fail (item_id != NULL);
+       cbews = E_CAL_BACKEND_EWS (sync_backend);
 
-       cancellable = cal_backend_ews_ref_cancellable (cbews);
+       *freebusyobjs = NULL;
 
-       PRIV_LOCK (cbews->priv);
-       comp = g_hash_table_lookup (cbews->priv->item_id_hash, item_id->id);
-       if (!comp) {
-               PRIV_UNLOCK (cbews->priv);
-               g_clear_object (&cancellable);
-               g_warning ("%s: Failed to get component from item_id_hash", G_STRFUNC);
+       if (!e_cal_meta_backend_ensure_connected_sync (E_CAL_META_BACKEND (cbews), cancellable, error))
                return;
-       }
-
-       e_cal_component_get_uid (comp, &uid);
-
-       attachment_ids = e_ews_item_get_attachments_ids (item);
-       if (e_ews_connection_get_attachments_sync (
-               cbews->priv->cnc,
-               EWS_PRIORITY_MEDIUM,
-               uid,
-               attachment_ids,
-               cbews->priv->storage_path,
-               TRUE,
-               &info_attachments,
-               NULL, NULL,
-               cancellable,
-               NULL)) {
-               icalcomponent *icalcomp;
-               icalproperty *icalprop;
-               icalparameter *icalparam;
-               ECalComponentId *id;
-               ECalComponent *cache_comp;
-
-               for (l = info_attachments; l; l = l->next) {
-                       EEwsAttachmentInfo *info = l->data;
-
-                       /* ignore non-uri attachments, because it's an exception */
-                       if (e_ews_attachment_info_get_type (info) == E_EWS_ATTACHMENT_INFO_TYPE_URI) {
-                               const gchar *uri = e_ews_attachment_info_get_uri (info);
-
-                               if (uri)
-                                       uris = g_slist_append (uris, g_strdup (uri));
-                       }
-               }
-
-               e_cal_component_set_attachment_list (comp, uris);
-
-               icalcomp = e_cal_component_get_icalcomponent (comp);
-               icalprop = icalcomponent_get_first_property (icalcomp, ICAL_ATTACH_PROPERTY);
-               for (aid = attachment_ids; aid && icalprop; aid = aid->next, icalprop = 
icalcomponent_get_next_property (icalcomp, ICAL_ATTACH_PROPERTY)) {
-                       icalparam = icalparameter_new_x (aid->data);
-                       icalparameter_set_xname (icalparam, "X-EWS-ATTACHMENTID");
-                       icalproperty_add_parameter (icalprop, icalparam);
-               }
-
-               id = e_cal_component_get_id (comp);
-               if (!id) {
-                       g_warn_if_reached ();
-               } else {
-                       cache_comp = e_cal_backend_store_get_component (cbews->priv->store, id->uid, id->rid);
-                       e_cal_component_free_id (id);
-
-                       put_component_to_store (cbews, comp);
-
-                       if (cache_comp)
-                               e_cal_backend_notify_component_modified (E_CAL_BACKEND (cbews), cache_comp, 
comp);
-               }
-
-               g_slist_free_full (uris, g_free);
-               g_slist_free_full (info_attachments, (GDestroyNotify) e_ews_attachment_info_free);
-       }
-
-       PRIV_UNLOCK (cbews->priv);
-
-       g_clear_object (&cancellable);
-}
-
-static icaltimezone *
-get_timezone (ETimezoneCache *timezone_cache,
-             const gchar *msdn_tzid,
-             const gchar *tzid,
-             const gchar *evo_ews_tzid)
-{
-       icaltimezone *zone = NULL;
-       const gchar *evo_ews_msdn_tzid;
-
-       zone = e_timezone_cache_get_timezone (timezone_cache, tzid);
-       if (zone == NULL)
-               zone = icaltimezone_get_builtin_timezone (tzid);
-
-       if (g_strcmp0 (tzid, evo_ews_tzid) == 0)
-               return zone;
-
-       if (evo_ews_tzid != NULL) {
-               evo_ews_msdn_tzid = e_cal_backend_ews_tz_util_get_msdn_equivalent (evo_ews_tzid);
-
-               if (g_strcmp0 (msdn_tzid, evo_ews_msdn_tzid) == 0) {
-                       zone = e_timezone_cache_get_timezone (timezone_cache, evo_ews_tzid);
-                       if (zone == NULL)
-                               zone = icaltimezone_get_builtin_timezone (evo_ews_tzid);
-               }
-       }
-
-       return zone;
-}
-
-static icalparameter *
-cal_backend_ews_responsetype_to_partstat (const gchar *responsetype)
-{
-       icalparameter *param = NULL;
-
-       g_return_val_if_fail (responsetype != NULL, NULL);
-
-       if (g_ascii_strcasecmp (responsetype, "Organizer") == 0)
-               param = icalparameter_new_partstat (ICAL_PARTSTAT_ACCEPTED);
-       else if (g_ascii_strcasecmp (responsetype, "Tentative") == 0)
-               param = icalparameter_new_partstat (ICAL_PARTSTAT_TENTATIVE);
-       else if (g_ascii_strcasecmp (responsetype, "Accept") == 0)
-               param = icalparameter_new_partstat (ICAL_PARTSTAT_ACCEPTED);
-       else if (g_ascii_strcasecmp (responsetype, "Decline") == 0)
-               param = icalparameter_new_partstat (ICAL_PARTSTAT_DECLINED);
-       else if (g_ascii_strcasecmp (responsetype, "NoResponseReceived") == 0)
-               param = icalparameter_new_partstat (ICAL_PARTSTAT_NEEDSACTION);
-       else if (g_ascii_strcasecmp (responsetype, "Unknown") == 0)
-               param = icalparameter_new_partstat (ICAL_PARTSTAT_NONE);
-
-       if (!param)
-               param = icalparameter_new_partstat (ICAL_PARTSTAT_NONE);
-
-       return param;
-}
-
-static void
-add_item_to_cache (ECalBackendEws *cbews,
-                   EEwsItem *item)
-{
-       ECalBackendEwsPrivate *priv;
-       ETimezoneCache *timezone_cache;
-       icalcomponent_kind kind;
-       EEwsItemType item_type;
-       icalcomponent *icalcomp, *vcomp;
-       const gchar *mime_content;
-
-       timezone_cache = E_TIMEZONE_CACHE (cbews);
-
-       kind = e_cal_backend_get_kind ((ECalBackend *) cbews);
-       priv = cbews->priv;
-
-       item_type = e_ews_item_get_item_type (item);
-       if (item_type == E_EWS_ITEM_TYPE_TASK || item_type == E_EWS_ITEM_TYPE_MEMO) {
-               icalproperty *icalprop;
-               icaltimetype due_date, start_date, complete_date, created;
-               icalproperty_status status  = ICAL_STATUS_NONE;
-               icalproperty_class class = ICAL_CLASS_NONE;
-               const gchar *ews_task_status, *sensitivity;
-               EwsImportance item_importance;
-               gint priority = 5;
-               gboolean has_this_date = FALSE;
-
-               vcomp = icalcomponent_new (ICAL_VCALENDAR_COMPONENT);
-               /*subject*/
-               icalcomp = icalcomponent_new (item_type == E_EWS_ITEM_TYPE_TASK ? ICAL_VTODO_COMPONENT : 
ICAL_VJOURNAL_COMPONENT);
-               icalprop = icalproperty_new_summary (e_ews_item_get_subject (item));
-               icalcomponent_add_property (icalcomp, icalprop);
-
-               /*date time created*/
-               created = icaltime_from_timet_with_zone (e_ews_item_get_date_created (item), 0, 
priv->default_zone);
-               icalprop = icalproperty_new_created (created);
-               icalcomponent_add_property (icalcomp, icalprop);
-
-               /*sensitivity*/
-               sensitivity = e_ews_item_get_sensitivity (item);
-               if (g_strcmp0 (sensitivity, "Normal") == 0)
-                       class = ICAL_CLASS_PUBLIC;
-               else if (g_strcmp0 (sensitivity, "Private") == 0)
-                       class = ICAL_CLASS_PRIVATE;
-               else if ((g_strcmp0 (sensitivity, "Confidential") == 0) ||
-                        (g_strcmp0 (sensitivity, "Personal") == 0))
-                       class = ICAL_CLASS_CONFIDENTIAL;
-               icalprop = icalproperty_new_class (class);
-               icalcomponent_add_property (icalcomp, icalprop);
-
-               /*description*/
-               icalprop = icalproperty_new_description (e_ews_item_get_body (item));
-               icalcomponent_add_property (icalcomp, icalprop);
-
-               /*task assaingments*/
-               if (e_ews_item_get_delegator (item) != NULL) {
-                       const gchar *task_owner = e_ews_item_get_delegator (item);
-                       GSList *mailboxes = NULL, *l;
-                       GCancellable *cancellable;
-                       GError *error = NULL;
-                       gboolean includes_last_item;
-                       gchar *mailtoname;
-                       icalparameter *param;
-
-                       /*The task owner according to Exchange is current user, even that the task was 
assigned by
-                        *someone else. I'm making the current user attendee and task delegator will be a 
task organizer */
-
-                       mailtoname = g_strdup_printf ("mailto:%s";, priv->user_email);
-                       icalprop = icalproperty_new_attendee (mailtoname);
-                       g_free (mailtoname);
-
-                       param = icalparameter_new_cn (e_ews_item_get_owner (item));
-                       icalproperty_add_parameter (icalprop, param);
-                       icalcomponent_add_property (icalcomp, icalprop);
-
-                       cancellable = cal_backend_ews_ref_cancellable (cbews);
-
-                       /* get delegator mail box*/
-                       e_ews_connection_resolve_names_sync (
-                               priv->cnc, EWS_PRIORITY_MEDIUM, task_owner,
-                               EWS_SEARCH_AD, NULL, FALSE, &mailboxes, NULL,
-                               &includes_last_item, cancellable, &error);
-
-                       for (l = mailboxes; l != NULL; l = g_slist_next (l)) {
-                               EwsMailbox *mb = l->data;
-
-                               mailtoname = g_strdup_printf ("mailto:%s";, mb->email);
-                               icalprop = icalproperty_new_organizer (mailtoname);
-                               param = icalparameter_new_cn (mb->name);
-                               icalproperty_add_parameter (icalprop, param);
-                               icalcomponent_add_property (icalcomp, icalprop);
-
-                               g_free (mailtoname);
-                               e_ews_mailbox_free (mb);
-                       }
-                       g_slist_free (mailboxes);
-                       g_clear_object (&cancellable);
-               }
-
-               if (item_type == E_EWS_ITEM_TYPE_TASK) {
-                       const gchar *percent_complete;
-
-                       /*start date*/
-                       has_this_date = FALSE;
-                       e_ews_item_task_has_start_date (item, &has_this_date);
-                       if (has_this_date) {
-                               start_date = icaltime_from_timet_with_zone (e_ews_item_get_start_date (item), 
0, priv->default_zone);
-                               start_date.is_date = 1;
-                               icalprop = icalproperty_new_dtstart (start_date);
-                               icalcomponent_add_property (icalcomp, icalprop);
-                       }
-
-                       /*status*/
-                       ews_task_status = e_ews_item_get_status (item);
-                       if (g_strcmp0 (ews_task_status, "NotStarted") != 0) {
-                               if (g_strcmp0 (ews_task_status, "Completed") == 0)
-                                       status = ICAL_STATUS_COMPLETED;
-                               else if (g_strcmp0 (ews_task_status, "InProgress") == 0)
-                                       status = ICAL_STATUS_INPROCESS;
-                               else if (g_strcmp0 (ews_task_status, "WaitingOnOthers") == 0)
-                                       status = ICAL_STATUS_NEEDSACTION;
-                               else if (g_strcmp0 (ews_task_status, "Deferred") == 0)
-                                       status = ICAL_STATUS_CANCELLED;
-                               icalprop = icalproperty_new_status (status);
-                               icalcomponent_add_property (icalcomp, icalprop);
-                       }
-
-                       /*precent complete*/
-                       percent_complete = e_ews_item_get_percent_complete (item);
-                       icalprop  = icalproperty_new_percentcomplete (atoi (percent_complete ? 
percent_complete : "0"));
-                       icalcomponent_add_property (icalcomp, icalprop);
-
-                       /*due date*/
-                       e_ews_item_task_has_due_date (item, &has_this_date);
-                       if (has_this_date) {
-                               due_date = icaltime_from_timet_with_zone (e_ews_item_get_due_date (item), 0, 
priv->default_zone);
-                               due_date.is_date = 1;
-                               icalprop = icalproperty_new_due (due_date);
-                               icalcomponent_add_property (icalcomp, icalprop);
-                       }
-
-                       /*complete date*/
-                       has_this_date = FALSE;
-                       e_ews_item_task_has_complete_date (item, &has_this_date);
-                       if (has_this_date) {
-                               complete_date = icaltime_from_timet_with_zone (e_ews_item_get_complete_date 
(item), 0, priv->default_zone);
-                               complete_date.is_date = 1;
-                               icalprop = icalproperty_new_completed (complete_date);
-                               icalcomponent_add_property (icalcomp, icalprop);
-                       }
-
-                       /*priority*/
-                       item_importance = e_ews_item_get_importance (item);
-                       if (item_importance == EWS_ITEM_HIGH)
-                               priority = 3;
-                       else if (item_importance == EWS_ITEM_LOW)
-                               priority = 7;
-                       icalprop = icalproperty_new_priority (priority);
-                       icalcomponent_add_property (icalcomp, icalprop);
-               }
-
-               icalcomponent_add_component (vcomp,icalcomp);
-       } else {
-               struct icaltimetype dt;
-               const gchar *tzid;
-               gboolean timezone_set = FALSE;
-
-               mime_content = e_ews_item_get_mime_content (item);
-               vcomp = icalparser_parse_string (mime_content);
-
-               if (!vcomp && mime_content) {
-                       const gchar *begin_vcalendar, *end_vcalendar;
-
-                       /* Workaround Exchange 2016 error, which returns invalid iCalendar object (without 
'END:VCALENDAR'),
-                          when the event has at least one detached instance. */
-                       begin_vcalendar = camel_strstrcase (mime_content, "BEGIN:VCALENDAR");
-                       end_vcalendar = camel_strstrcase (mime_content, "END:VCALENDAR");
-
-                       /* If it exists, then it should be alone on a separate line */
-                       if (!(begin_vcalendar && (begin_vcalendar == mime_content || begin_vcalendar[-1] == 
'\n') &&
-                           (begin_vcalendar[15 /* strlen ("BEGIN:VCALENDAR") */] == '\r' || 
begin_vcalendar[15] == '\n')))
-                               begin_vcalendar = NULL;
-
-                       /* If it exists, then it should be alone on a separate line and not at the very 
beginning of the mime_content */
-                       if (!(end_vcalendar && end_vcalendar > mime_content && end_vcalendar[-1] == '\n' &&
-                           (end_vcalendar[13 /* strlen ("END:VCALENDAR") */] == '\r' || end_vcalendar[13] == 
'\n' || end_vcalendar[13] == '\0')))
-                               end_vcalendar = NULL;
-
-                       if (begin_vcalendar && !end_vcalendar) {
-                               gchar *str;
-
-                               str = g_strconcat (mime_content, "\r\n", "END:VCALENDAR", "\r\n", NULL);
-                               vcomp = icalparser_parse_string (str);
-                               g_free (str);
-                       }
-               }
-
-               if (!vcomp) {
-                       g_warn_if_reached ();
-                       return;
-               }
-
-               tzid = e_ews_item_get_tzid (item);
-               if (tzid == NULL) {
-                       /*
-                        * When we are working with Exchange server 2010 or newer, we have to handle a few
-                        * things more than we do working old servers. These things are:
-                        * - MSDN timezone names:
-                        *   Used setting StartTimeZone and EndTimeZone. MSDN timezone names are not
-                        *   the same used in libical, so we need to have a table of equivalence to
-                        *   convert from one to another and avoid show the MSDN timezone name to the
-                        *   user and save it in the ETimezoneCache.
-                        * - EvoEWSStartTimeZone/EvoEWSEndTimeZone
-                        *   Used to keep track if the timezone shown to the user is the same one set
-                        *   by him/her. As we have a table of equivalence, sometimes the user sets a
-                        *   timezone but without EvoEWSStartTiemZone property, another timezone name,
-                        *   in the same offset, can be shown. And we want to avoid this.
-                        * - DTEND property:
-                        *   As we have to work with DTEND setting an event when using EWS server 2010 or
-                        *   newer, we have to care about set it properly here, instead of use the same
-                        *   as is used in DTSTART.
-                        */
-                       icaltimezone *start_zone, *end_zone;
-                       const gchar *start_tzid, *end_tzid;
-                       const gchar *ical_start_tzid, *ical_end_tzid;
-                       const gchar *evo_ews_start_tzid, *evo_ews_end_tzid;
-
-                       start_tzid = e_ews_item_get_start_tzid (item);
-                       end_tzid = e_ews_item_get_end_tzid (item);
-
-                       ical_start_tzid = e_cal_backend_ews_tz_util_get_ical_equivalent (start_tzid);
-                       ical_end_tzid = e_cal_backend_ews_tz_util_get_ical_equivalent (end_tzid);
-
-                       evo_ews_start_tzid = e_ews_item_get_iana_start_time_zone (item);
-                       evo_ews_end_tzid = e_ews_item_get_iana_end_time_zone (item);
-
-                       /*
-                        * We have a few timezones that don't have an equivalent MSDN timezone.
-                        * For those, we will get ical_start_tzid being NULL and then we need to use
-                        * start_tzid, which one has the libical's expected name.
-                        */
-                       start_zone = get_timezone (
-                               timezone_cache,
-                               start_tzid,
-                               ical_start_tzid != NULL ? ical_start_tzid : start_tzid,
-                               evo_ews_start_tzid);
-                       end_zone = get_timezone (
-                               timezone_cache,
-                               end_tzid,
-                               ical_end_tzid != NULL ? ical_end_tzid : end_tzid,
-                               evo_ews_end_tzid);
-
-                       if (start_zone != NULL) {
-                               icalcomp = icalcomponent_get_first_component (vcomp, kind);
-
-                               dt = icalcomponent_get_dtstart (icalcomp);
-                               dt = icaltime_convert_to_zone (dt, start_zone);
-                               icalcomponent_set_dtstart (icalcomp, dt);
-
-                               timezone_set = TRUE;
-                               e_timezone_cache_add_timezone (timezone_cache, start_zone);
-
-                               if (end_zone != NULL) {
-                                       dt = icalcomponent_get_dtend (icalcomp);
-                                       dt = icaltime_convert_to_zone (dt, end_zone);
-                                       icalcomponent_set_dtend (icalcomp, dt);
-
-                                       e_timezone_cache_add_timezone (timezone_cache, end_zone);
-                               }
-                       }
-
-                       if (!timezone_set)
-                               tzid = start_tzid;
-               }
-
-               if (!timezone_set && tzid) {
-                       /*
-                        * When we are working with Exchange server older than 2010, we don't set different
-                        * DTSTART and DTEND properties in VTIMEZONE. The reason of that is we don't use
-                        * those properties settings/changing a meeting timezone.
-                        * So, for older servers, here, we only set the DTSTART and DTEND properties with
-                        * the same values.
-                        */
-                       icaltimezone *zone;
-                       gchar *new_tzid = NULL;
-
-                       icalcomp = icalcomponent_get_first_component (vcomp, kind);
-
-                       if (!icaltimezone_get_builtin_timezone (tzid) &&
-                           icalcomponent_get_uid (icalcomp)) {
-                               icalcomponent *vtimezone;
-
-                               /* Add the timezone */
-                               vtimezone = icalcomponent_get_first_component (vcomp, 
ICAL_VTIMEZONE_COMPONENT);
-                               if (vtimezone != NULL) {
-                                       icalproperty *prop;
-
-                                       new_tzid = g_strconcat ("/evolution/ews/tzid/", icalcomponent_get_uid 
(icalcomp), NULL);
-
-                                       zone = icaltimezone_new ();
-                                       vtimezone = icalcomponent_new_clone (vtimezone);
-                                       prop = icalcomponent_get_first_property (vtimezone, 
ICAL_TZID_PROPERTY);
-                                       if (prop) {
-                                               icalproperty_set_tzid (prop, new_tzid);
-
-                                               prop = icalcomponent_get_first_property (vtimezone, 
ICAL_LOCATION_PROPERTY);
-                                               if (!prop) {
-                                                       /* Use the original tzid as the timezone Location, to 
not expose
-                                                          evolution-ews TZID. */
-                                                       prop = icalproperty_new_location (tzid);
-                                                       icalcomponent_add_property (vtimezone, prop);
-                                               }
-                                       } else {
-                                               g_free (new_tzid);
-                                               new_tzid = NULL;
-                                       }
-                                       icaltimezone_set_component (zone, vtimezone);
-                                       e_timezone_cache_add_timezone (timezone_cache, zone);
-                                       icaltimezone_free (zone, TRUE);
-                               }
-                       }
-
-                       zone = e_timezone_cache_get_timezone (timezone_cache, new_tzid ? new_tzid : tzid);
-
-                       if (!zone && new_tzid)
-                               zone = e_timezone_cache_get_timezone (timezone_cache, tzid);
-
-                       if (zone == NULL)
-                               zone = icaltimezone_get_builtin_timezone (tzid);
-
-                       if (zone != NULL) {
-                               dt = icalcomponent_get_dtstart (icalcomp);
-                               dt = icaltime_convert_to_zone (dt, zone);
-                               icalcomponent_set_dtstart (icalcomp, dt);
-
-                               dt = icalcomponent_get_dtend (icalcomp);
-                               dt = icaltime_convert_to_zone (dt, zone);
-                               icalcomponent_set_dtend (icalcomp, dt);
-                       }
-
-                       g_free (new_tzid);
-               }
-       }
-
-       /* Vevent or Vtodo */
-       icalcomp = icalcomponent_get_first_component (vcomp, kind);
-       if (icalcomp) {
-               ECalComponent *comp, *cache_comp = NULL;
-               icalproperty *icalprop, *freebusy;
-               const EwsId *item_id;
-               ECalComponentId *id;
-               const GSList *l = NULL;
-               const gchar *uid = e_ews_item_get_uid (item);
-
-               item_id = e_ews_item_get_id (item);
-
-               /* Attendees */
-               for (l = e_ews_item_get_attendees (item); l != NULL; l = g_slist_next (l)) {
-                       icalparameter *param, *cu_type;
-                       gchar *mailtoname;
-                       const gchar *email = NULL;
-                       EwsAttendee *attendee = (EwsAttendee *) l->data;
-
-                       if (!attendee->mailbox)
-                               continue;
-
-                       if (g_strcmp0 (attendee->mailbox->routing_type, "EX") == 0)
-                               email = e_ews_item_util_strip_ex_address (attendee->mailbox->email);
-
-                       mailtoname = g_strdup_printf ("mailto:%s";, email ? email : attendee->mailbox->email);
-                       icalprop = icalproperty_new_attendee (mailtoname);
-                       g_free (mailtoname);
-
-                       param = icalparameter_new_cn (attendee->mailbox->name);
-                       icalproperty_add_parameter (icalprop, param);
-
-                       if (g_ascii_strcasecmp (attendee->attendeetype, "Required") == 0) {
-                               param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT);
-                               cu_type = icalparameter_new_cutype (ICAL_CUTYPE_INDIVIDUAL);
-                       }
-                       else if (g_ascii_strcasecmp (attendee->attendeetype, "Resource") == 0) {
-                               param = icalparameter_new_role (ICAL_ROLE_NONPARTICIPANT);
-                               cu_type = icalparameter_new_cutype (ICAL_CUTYPE_RESOURCE);
-                       }
-                       else {
-                               param = icalparameter_new_role ( ICAL_ROLE_OPTPARTICIPANT);
-                               cu_type = icalparameter_new_cutype (ICAL_CUTYPE_INDIVIDUAL);
-                       }
-                       icalproperty_add_parameter (icalprop, cu_type);
-                       icalproperty_add_parameter (icalprop, param);
-
-                       if (cbews->priv->user_email && (email || attendee->mailbox->email) && 
e_ews_item_get_my_response_type (item) &&
-                           g_ascii_strcasecmp (email ? email : attendee->mailbox->email, 
cbews->priv->user_email) == 0) {
-                               param = cal_backend_ews_responsetype_to_partstat 
(e_ews_item_get_my_response_type (item));
-                       } else {
-                               param = cal_backend_ews_responsetype_to_partstat (attendee->responsetype);
-                       }
-                       icalproperty_add_parameter (icalprop, param);
-
-                       icalcomponent_add_property (icalcomp, icalprop);
-               }
-
-               /* Free/Busy */
-               freebusy = icalcomponent_get_first_property (icalcomp, ICAL_TRANSP_PROPERTY);
-               if (!freebusy && (e_ews_item_get_item_type (item) != E_EWS_ITEM_TYPE_TASK)) {
-                       /* Busy by default */
-                       freebusy = icalproperty_new_transp (ICAL_TRANSP_OPAQUE);
-                       icalcomponent_add_property (icalcomp, freebusy);
-               }
-               for (icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
-                       icalprop != NULL;
-                       icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
 
-                       if (g_strcmp0 (icalproperty_get_x_name (icalprop), "X-MICROSOFT-CDO-BUSYSTATUS") == 
0) {
-                               if (g_strcmp0 (icalproperty_get_value_as_string (icalprop), "BUSY") == 0) {
-                                       icalproperty_set_transp (freebusy, ICAL_TRANSP_OPAQUE);
-                               } else {
-                                       icalproperty_set_transp (freebusy, ICAL_TRANSP_TRANSPARENT);
-                               }
-
-                               break;
-                       }
-               }
-
-               /*AllDayEvent*/
-               for (icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
-                       icalprop != NULL;
-                       icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
-
-                       if (g_strcmp0 (icalproperty_get_x_name (icalprop), "X-MICROSOFT-CDO-ALLDAYEVENT") == 
0) {
-                               if (g_strcmp0 (icalproperty_get_value_as_string (icalprop), "TRUE") == 0) {
-                                       struct icaltimetype dtend, dtstart;
-                                       dtstart = icalcomponent_get_dtstart (icalcomp);
-                                       dtstart.is_date = 1;
-                                       icalcomponent_set_dtstart (icalcomp, dtstart);
-
-                                       dtend = icalcomponent_get_dtend (icalcomp);
-                                       dtend.is_date = 1;
-                                       icalcomponent_set_dtend (icalcomp, dtend);
-                               }
-                               break;
-                       }
-               }
-
-               if (icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY)) {
-                       /* Exchange sets RRULE even on the children, which is broken */
-                       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY);
-                       if (icalprop) {
-                               icalcomponent_remove_property (icalcomp, icalprop);
-                               icalproperty_free (icalprop);
-                       }
-               }
-
-               /* Exchange sets an ORGANIZER on all events. RFC2445 says:
-                *
-                *   This property MUST NOT be specified in an iCalendar
-                *   object that specifies only a time zone definition or
-                *   that defines calendar entities that are not group
-                *   scheduled entities, but are entities only on a single
-                *   user's calendar.
-                */
-               if (!icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) {
-                       if ((icalprop = icalcomponent_get_first_property (icalcomp, 
ICAL_ORGANIZER_PROPERTY))) {
-                               icalcomponent_remove_property (icalcomp, icalprop);
-                               icalproperty_free (icalprop);
-                       }
-               }
-
-               icalcomponent_set_uid (icalcomp,uid ? uid : item_id->id);
-
-               icalprop = icalproperty_new_x (item_id->id);
-               icalproperty_set_x_name (icalprop, "X-EVOLUTION-ITEMID");
-               icalcomponent_add_property (icalcomp, icalprop);
-
-               icalprop = icalproperty_new_x (item_id->change_key);
-               icalproperty_set_x_name (icalprop, "X-EVOLUTION-CHANGEKEY");
-               icalcomponent_add_property (icalcomp, icalprop);
-
-               comp = e_cal_component_new ();
-               e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
-
-               /* Categories */
-               e_cal_component_set_categories_list (comp, (GSList *) e_ews_item_get_categories (item));
-
-               /*
-                * There is no API to set/get alarm description on the server side.
-                * However, for some reason, the alarm description has been set to "REMINDER"
-                * automatically (and with no i18n). Instead of show it to the user, let's
-                * set the summary as the alarm description.
-                */
-               if (e_cal_component_has_alarms (comp)) {
-                       GList *alarm_uids, *l;
-
-                       alarm_uids = e_cal_component_get_alarm_uids (comp);
-                       for (l = alarm_uids; l != NULL; l = l->next) {
-                               ECalComponentAlarm *alarm;
-                               ECalComponentText text;
-
-                               alarm = e_cal_component_get_alarm (comp, l->data);
-                               e_cal_component_get_summary (comp, &text);
-                               e_cal_component_alarm_set_description (alarm, &text);
-
-                               e_cal_component_alarm_free (alarm);
-                       }
-                       cal_obj_uid_list_free (alarm_uids);
-               }
-
-               id = e_cal_component_get_id (comp);
-               cache_comp = e_cal_backend_store_get_component (priv->store, id->uid, id->rid);
-               e_cal_component_free_id (id);
-
-               put_component_to_store (cbews, comp);
-
-               if (!cache_comp) {
-                       e_cal_backend_notify_component_created (E_CAL_BACKEND (cbews), comp);
-               } else {
-                       e_cal_backend_notify_component_modified (E_CAL_BACKEND (cbews), cache_comp, comp);
-               }
-
-               PRIV_LOCK (priv);
-               g_hash_table_insert (priv->item_id_hash, g_strdup (item_id->id), g_object_ref (comp));
-               PRIV_UNLOCK (priv);
-
-               g_object_unref (comp);
-       }
-       icalcomponent_free (vcomp);
-}
-
-static void
-ews_refreshing_inc (ECalBackendEws *cbews)
-{
-       PRIV_LOCK (cbews->priv);
-       if (!cbews->priv->refreshing)
-               e_flag_clear (cbews->priv->refreshing_done);
-       cbews->priv->refreshing++;
-       PRIV_UNLOCK (cbews->priv);
-}
-
-static void
-ews_refreshing_dec (ECalBackendEws *cbews)
-{
-       PRIV_LOCK (cbews->priv);
-       if (!cbews->priv->refreshing) {
-               e_flag_set (cbews->priv->refreshing_done);
-               PRIV_UNLOCK (cbews->priv);
-
-               g_warning ("%s: Invalid call, currently not refreshing", G_STRFUNC);
+       /* EWS can support only 100 identities, which is the maximum number of identities that the Web 
service method can request
+        see http://msdn.microsoft.com / en - us / library / aa564001 % 28v = EXCHG.140 % 29.aspx */
+       if (g_slist_length ((GSList *) users) > 100) {
+               g_propagate_error (error, EDC_ERROR (SearchSizeLimitExceeded));
                return;
        }
-       cbews->priv->refreshing--;
-       if (!cbews->priv->refreshing) {
-               e_flag_set (cbews->priv->refreshing_done);
-       }
-       PRIV_UNLOCK (cbews->priv);
-}
-
-static gboolean
-ews_cal_sync_get_items_sync (ECalBackendEws *cbews,
-                             const GSList *item_ids,
-                             const gchar *default_props,
-                             const EEwsAdditionalProps *add_props)
-{
-       ECalBackendEwsPrivate *priv;
-       gboolean ret = FALSE;
-       GSList *items = NULL, *l;
-       GCancellable *cancellable;
-       GError *error = NULL;
-
-       priv = cbews->priv;
-
-       cancellable = cal_backend_ews_ref_cancellable (cbews);
-
-       e_ews_connection_get_items_sync (
-               priv->cnc,
-               EWS_PRIORITY_MEDIUM,
-               item_ids,
-               default_props,
-               add_props,
-               FALSE,
-               NULL,
-               E_EWS_BODY_TYPE_TEXT,
-               &items,
-               NULL, NULL,
-               cancellable,
-               &error);
-
-       g_clear_object (&cancellable);
-
-       if (error != NULL) {
-               g_debug ("%s: Unable to get items: %s", G_STRFUNC, error->message);
-               g_clear_error (&error);
-
-               goto exit;
-       }
-
-       /* fetch modified occurrences */
-       for (l = items; l != NULL; l = g_slist_next (l)) {
-               EEwsItem *item = l->data;
-               const GSList *modified_occurrences;
-
-               if (!item || e_ews_item_get_item_type (item) == E_EWS_ITEM_TYPE_ERROR)
-                       continue;
-
-               modified_occurrences = e_ews_item_get_modified_occurrences (item);
-               if (modified_occurrences) {
-                       EEwsAdditionalProps *modified_add_props;
-
-                       modified_add_props = e_ews_additional_props_new ();
-                       if (e_ews_connection_satisfies_server_version (priv->cnc, E_EWS_EXCHANGE_2010)) {
-                               EEwsExtendedFieldURI *ext_uri;
-
-                               modified_add_props->field_uri = g_strdup (GET_ITEMS_SYNC_PROPERTIES_2010);
-
-                               ext_uri = e_ews_extended_field_uri_new ();
-                               ext_uri->distinguished_prop_set_id = g_strdup ("PublicStrings");
-                               ext_uri->prop_name = g_strdup ("EvolutionEWSStartTimeZone");
-                               ext_uri->prop_type = g_strdup ("String");
-                               modified_add_props->extended_furis = g_slist_append 
(modified_add_props->extended_furis, ext_uri);
-
-                               ext_uri = e_ews_extended_field_uri_new ();
-                               ext_uri->distinguished_prop_set_id = g_strdup ("PublicStrings");
-                               ext_uri->prop_name = g_strdup ("EvolutionEWSEndTimeZone");
-                               ext_uri->prop_type = g_strdup ("String");
-                               modified_add_props->extended_furis = g_slist_append 
(modified_add_props->extended_furis, ext_uri);
-                       } else {
-                               modified_add_props->field_uri = g_strdup (GET_ITEMS_SYNC_PROPERTIES_2007);
-                       }
-
-                       ret = ews_cal_sync_get_items_sync (
-                               cbews, modified_occurrences,
-                               "IdOnly",
-                               modified_add_props);
-
-                       e_ews_additional_props_free (modified_add_props);
-
-                       if (!ret)
-                               goto exit;
-               }
-       }
-
-       e_cal_backend_store_freeze_changes (priv->store);
-       for (l = items; l != NULL; l = g_slist_next (l)) {
-               EEwsItem *item = (EEwsItem *) l->data;
-
-               if (!item)
-                       continue;
-
-               if (e_ews_item_get_item_type (item) != E_EWS_ITEM_TYPE_ERROR) {
-                       add_item_to_cache (cbews, item);
-                       ews_get_attachments (cbews, item);
-               }
-       }
-       e_cal_backend_store_thaw_changes (priv->store);
-       ret = TRUE;
-
-exit:
-       g_slist_free_full (items, g_object_unref);
-       return ret;
-}
-
-static gboolean
-cal_backend_ews_process_folder_items (ECalBackendEws *cbews,
-                                      const gchar *sync_state,
-                                      GSList *items_created,
-                                      GSList *items_updated,
-                                      GSList *items_deleted)
-{
-       ECalBackendEwsPrivate *priv;
-       GSList *l[2], *m, *cal_item_ids = NULL, *task_memo_item_ids = NULL;
-       gint i;
-       gboolean ret = FALSE;
-
-       priv = cbews->priv;
-
-       l[0] = items_created;
-       l[1] = items_updated;
-
-       for (i = 0; i < 2; i++) {
-               for (; l[i] != NULL; l[i] = g_slist_next (l[i])) {
-                       EEwsItem *item = (EEwsItem *) l[i]->data;
-                       EEwsItemType type = e_ews_item_get_item_type (item);
-                       const EwsId *id;
-
-                       id = e_ews_item_get_id (item);
-                       if (type == E_EWS_ITEM_TYPE_EVENT)
-                               cal_item_ids = g_slist_prepend (cal_item_ids, id->id);
-                       else if (type == E_EWS_ITEM_TYPE_TASK || type == E_EWS_ITEM_TYPE_MEMO)
-                               task_memo_item_ids = g_slist_prepend (task_memo_item_ids, id->id);
-               }
-       }
-
-       e_cal_backend_store_freeze_changes (priv->store);
-       for (m = items_deleted; m != NULL; m = g_slist_next (m)) {
-               gchar *item_id = (gchar *) m->data;
-               ECalComponent *comp;
-
-               PRIV_LOCK (priv);
-               comp = g_hash_table_lookup (priv->item_id_hash, item_id);
-               if (comp)
-                       g_object_ref (comp);
-               PRIV_UNLOCK (priv);
-
-               if (comp) {
-                       if (!ews_cal_delete_comp (cbews, comp, item_id)) {
-                               g_object_unref (comp);
-                               goto exit;
-                       }
-
-                       g_object_unref (comp);
-               }
-       }
-       e_cal_backend_store_thaw_changes (priv->store);
-
-
-       if (cal_item_ids) {
-               EEwsAdditionalProps *add_props;
-
-               add_props = e_ews_additional_props_new ();
-               if (e_ews_connection_satisfies_server_version (priv->cnc, E_EWS_EXCHANGE_2010)) {
-                       EEwsExtendedFieldURI *ext_uri;
-
-                       add_props->field_uri = g_strdup (GET_ITEMS_SYNC_PROPERTIES_2010);
-
-                       ext_uri = e_ews_extended_field_uri_new ();
-                       ext_uri->distinguished_prop_set_id = g_strdup ("PublicStrings");
-                       ext_uri->prop_name = g_strdup ("EvolutionEWSStartTimeZone");
-                       ext_uri->prop_type = g_strdup ("String");
-                       add_props->extended_furis = g_slist_append (add_props->extended_furis, ext_uri);
-
-                       ext_uri = e_ews_extended_field_uri_new ();
-                       ext_uri->distinguished_prop_set_id = g_strdup ("PublicStrings");
-                       ext_uri->prop_name = g_strdup ("EvolutionEWSEndTimeZone");
-                       ext_uri->prop_type = g_strdup ("String");
-                       add_props->extended_furis = g_slist_append (add_props->extended_furis, ext_uri);
-               } else {
-                       add_props->field_uri = g_strdup (GET_ITEMS_SYNC_PROPERTIES_2007);
-               }
-
-               ews_cal_sync_get_items_sync (
-                       cbews,
-                       cal_item_ids,
-                       "IdOnly",
-                       add_props);
-
-               e_ews_additional_props_free (add_props);
-       }
-
-       if (task_memo_item_ids) {
-               ews_cal_sync_get_items_sync (
-                       cbews,
-                       task_memo_item_ids,
-                       "AllProperties",
-                       NULL);
-       }
-       ret = TRUE;
-
-exit:
-       g_slist_free (cal_item_ids);
-       g_slist_free (task_memo_item_ids);
-       return ret;
-}
-
-static void
-cbews_forget_all_components (ECalBackendEws *cbews)
-{
-       ECalBackend *backend;
-       GSList *ids, *ii;
-
-       g_return_if_fail (E_IS_CAL_BACKEND_EWS (cbews));
-
-       backend = E_CAL_BACKEND (cbews);
-       g_return_if_fail (backend != NULL);
-
-       ids = e_cal_backend_store_get_component_ids (cbews->priv->store);
-       for (ii = ids; ii; ii = ii->next) {
-               ECalComponentId *id = ii->data;
-
-               if (!id)
-                       continue;
-
-               e_cal_backend_store_remove_component (cbews->priv->store, id->uid, id->rid);
-               e_cal_backend_notify_component_removed (backend, id, NULL, NULL);
-       }
-
-       g_slist_free_full (ids, (GDestroyNotify) e_cal_component_free_id);
-}
-
-static gboolean
-ews_freebusy_ecomp_changed (ECalComponent *ecomp,
-                           icalcomponent *vevent)
-{
-       icalcomponent *icomp;
-       gboolean changed = FALSE;
-
-       g_return_val_if_fail (vevent != NULL, FALSE);
-
-       if (!ecomp)
-               return TRUE;
-
-       icomp = e_cal_component_get_icalcomponent (ecomp);
-       if (!icomp)
-               return TRUE;
-
-       if (!changed)
-               changed = g_strcmp0 (icalcomponent_get_summary (icomp), icalcomponent_get_summary (vevent)) 
!= 0;
-       if (!changed)
-               changed = g_strcmp0 (icalcomponent_get_location (icomp), icalcomponent_get_location (vevent)) 
!= 0;
-       if (!changed)
-               changed = icaltime_compare (icalcomponent_get_dtstart (icomp), icalcomponent_get_dtstart 
(vevent)) != 0;
-       if (!changed)
-               changed = icaltime_compare (icalcomponent_get_dtend (icomp), icalcomponent_get_dtend 
(vevent)) != 0;
-
-       return changed;
-}
-
-static gpointer
-ews_start_sync_thread (gpointer data)
-{
-       ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-       GSList *items_created = NULL;
-       GSList *items_updated = NULL;
-       GSList *items_deleted = NULL;
-       gboolean includes_last_item;
-       gboolean ret;
-       gchar *old_sync_state = NULL;
-       gchar *new_sync_state = NULL;
-       GCancellable *cancellable;
-       GError *error = NULL;
-
-       cbews = (ECalBackendEws *) data;
-       priv = cbews->priv;
-
-       cancellable = cal_backend_ews_ref_cancellable (cbews);
-
-       if (priv->is_freebusy_calendar) {
-               ESourceEwsFolder *ews_folder;
-               EEWSFreeBusyData fbdata;
-               GSList *free_busy = NULL, *link;
-               gboolean success;
-               time_t today;
 
-               ews_folder = e_source_get_extension (e_backend_get_source (E_BACKEND (cbews)), 
E_SOURCE_EXTENSION_EWS_FOLDER);
-
-               today = time_day_begin (time (NULL));
-
-               fbdata.period_start = time_add_week (today, -e_source_ews_folder_get_freebusy_weeks_before 
(ews_folder));
-               fbdata.period_end = time_day_end (time_add_week (today, 
e_source_ews_folder_get_freebusy_weeks_after (ews_folder)));
-               fbdata.user_mails = g_slist_prepend (NULL, e_source_ews_folder_dup_foreign_mail (ews_folder));
-
-               success = e_ews_connection_get_free_busy_sync (priv->cnc, G_PRIORITY_DEFAULT,
-                       e_ews_cal_utils_prepare_free_busy_request, &fbdata,
-                       &free_busy, cancellable, &error);
-
-               if (success) {
-                       icaltimezone *utc_zone = icaltimezone_get_utc_timezone ();
-                       GSList *ids;
-                       GHashTable *known;
-                       GHashTableIter iter;
-                       gpointer key;
-
-                       known = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
-                       ids = e_cal_backend_store_get_component_ids (priv->store);
-                       for (link = ids; link; link = g_slist_next (link)) {
-                               ECalComponentId *id = link->data;
-
-                               if (id && id->uid && *id->uid)
-                                       g_hash_table_insert (known, g_strdup (id->uid), NULL);
-                       }
-                       g_slist_free_full (ids, (GDestroyNotify) e_cal_component_free_id);
-
-                       for (link = free_busy; link; link = g_slist_next (link)) {
-                               icalcomponent *fbcomp = link->data;
-                               icalproperty *fbprop;
-                               icalparameter *param;
-                               struct icalperiodtype fb;
-                               icalparameter_fbtype fbtype;
-
-                               if (!fbcomp || icalcomponent_isa (fbcomp) != ICAL_VFREEBUSY_COMPONENT)
-                                       continue;
-
-                               for (fbprop = icalcomponent_get_first_property (fbcomp, 
ICAL_FREEBUSY_PROPERTY);
-                                    fbprop;
-                                    fbprop = icalcomponent_get_next_property (fbcomp, 
ICAL_FREEBUSY_PROPERTY)) {
-                                       icalcomponent *vevent;
-                                       const gchar *id, *summary, *location;
-
-                                       param = icalproperty_get_first_parameter (fbprop, 
ICAL_FBTYPE_PARAMETER);
-                                       if (!param)
-                                               continue;
-
-                                       fbtype = icalparameter_get_fbtype (param);
-
-                                       if (fbtype != ICAL_FBTYPE_FREE &&
-                                           fbtype != ICAL_FBTYPE_BUSY &&
-                                           fbtype != ICAL_FBTYPE_BUSYUNAVAILABLE &&
-                                           fbtype != ICAL_FBTYPE_BUSYTENTATIVE)
-                                               continue;
-
-                                       fb = icalproperty_get_freebusy (fbprop);
-                                       id = icalproperty_get_parameter_as_string (fbprop, "X-EWS-ID");
-                                       summary = icalproperty_get_parameter_as_string (fbprop, "X-SUMMARY");
-                                       location = icalproperty_get_parameter_as_string (fbprop, 
"X-LOCATION");
-
-                                       vevent = icalcomponent_new_vevent ();
-
-                                       if (id && *id) {
-                                               icalcomponent_set_uid (vevent, id);
-                                       } else {
-                                               gchar *uid;
-
-                                               uid = g_strdup_printf ("%s-%s-%d",
-                                                       icaltime_as_ical_string (fb.start),
-                                                       icaltime_as_ical_string (fb.end),
-                                                       (gint) fbtype);
-
-                                               icalcomponent_set_uid (vevent, uid);
-
-                                               g_free (uid);
-                                       }
-
-                                       fb.start.zone = utc_zone;
-                                       fb.start.is_utc = 1;
-                                       fb.end.zone = utc_zone;
-                                       fb.end.is_utc = 1;
-
-                                       icalcomponent_set_dtstart (vevent, fb.start);
-                                       icalcomponent_set_dtend (vevent, fb.end);
-
-                                       icalcomponent_add_property (vevent, icalproperty_new_created 
(icaltime_current_time_with_zone (utc_zone)));
-
-                                       if (fbtype == ICAL_FBTYPE_FREE) {
-                                               icalcomponent_set_summary (vevent, C_("FreeBusyType", 
"Free"));
-                                               icalcomponent_add_property (vevent, icalproperty_new_transp 
(ICAL_TRANSP_TRANSPARENT));
-                                       } else if (fbtype == ICAL_FBTYPE_BUSY) {
-                                               icalcomponent_set_summary (vevent, C_("FreeBusyType", 
"Busy"));
-                                       } else if (fbtype == ICAL_FBTYPE_BUSYUNAVAILABLE) {
-                                               icalcomponent_set_summary (vevent, C_("FreeBusyType", "Out of 
Office"));
-                                       } else if (fbtype == ICAL_FBTYPE_BUSYTENTATIVE) {
-                                               icalcomponent_set_summary (vevent, C_("FreeBusyType", 
"Tentative"));
-                                       }
-
-                                       if (summary && *summary)
-                                               icalcomponent_set_summary (vevent, summary);
-
-                                       if (location && *location)
-                                               icalcomponent_set_location (vevent, location);
-
-                                       PRIV_LOCK (priv);
-                                       if (g_hash_table_remove (known, icalcomponent_get_uid (vevent))) {
-                                               ECalComponent *ecomp = g_hash_table_lookup 
(priv->item_id_hash, icalcomponent_get_uid (vevent));
-
-                                               g_object_ref (ecomp);
-
-                                               PRIV_UNLOCK (priv);
-
-                                               if (ews_freebusy_ecomp_changed (ecomp, vevent)) {
-                                                       ECalComponent *new_ecomp;
-                                                       gchar *uid = g_strdup (icalcomponent_get_uid 
(vevent));
-
-                                                       new_ecomp = e_cal_component_new_from_icalcomponent 
(vevent);
-                                                       if (new_ecomp) {
-                                                               PRIV_LOCK (priv);
-                                                               g_hash_table_insert (priv->item_id_hash, uid, 
g_object_ref (new_ecomp));
-                                                               PRIV_UNLOCK (priv);
-
-                                                               put_component_to_store (cbews, new_ecomp);
-                                                               e_cal_backend_notify_component_modified 
(E_CAL_BACKEND (cbews), ecomp, new_ecomp);
-
-                                                               g_object_unref (new_ecomp);
-                                                       } else {
-                                                               g_free (uid);
-                                                       }
-                                               } else {
-                                                       icalcomponent_free (vevent);
-                                               }
-
-                                               g_clear_object (&ecomp);
-                                       } else {
-                                               ECalComponent *ecomp;
-                                               gchar *uid = g_strdup (icalcomponent_get_uid (vevent));
-
-                                               ecomp = e_cal_component_new_from_icalcomponent (vevent);
-                                               if (ecomp)
-                                                       g_hash_table_insert (priv->item_id_hash, uid, 
g_object_ref (ecomp));
-                                               else
-                                                       g_free (uid);
-
-                                               PRIV_UNLOCK (priv);
-
-                                               if (ecomp) {
-                                                       put_component_to_store (cbews, ecomp);
-                                                       e_cal_backend_notify_component_created (E_CAL_BACKEND 
(cbews), ecomp);
-                                               }
-
-                                               g_clear_object (&ecomp);
-                                       }
-                               }
-                       }
+       fbdata.period_start = start;
+       fbdata.period_end = end;
+       fbdata.user_mails = (GSList *) users;
 
-                       g_hash_table_iter_init (&iter, known);
-                       while (g_hash_table_iter_next (&iter, &key, NULL)) {
-                               ECalComponentId id = { 0 };
+       success = e_ews_connection_get_free_busy_sync (cbews->priv->cnc, EWS_PRIORITY_MEDIUM,
+               e_ews_cal_utils_prepare_free_busy_request, &fbdata,
+               &freebusy, cancellable, error);
 
-                               id.uid = key;
-                               id.rid = NULL;
+       if (success) {
+               GSList *fblink, *ulink;
 
-                               if (e_cal_backend_store_remove_component (priv->store, id.uid, id.rid)) {
-                                       e_cal_backend_notify_component_removed (E_CAL_BACKEND (cbews), &id, 
NULL, NULL);
+               for (fblink = freebusy, ulink = (GSList *) users;
+                    fblink && ulink;
+                    fblink = g_slist_next (fblink), ulink = g_slist_next (ulink)) {
+                       icalcomponent *icalcomp = fblink->data;
+                       gchar *mailto;
 
-                                       PRIV_LOCK (priv);
-                                       g_hash_table_remove (priv->item_id_hash, id.uid);
-                                       PRIV_UNLOCK (priv);
-                               }
-                       }
+                       /* add attendee property */
+                       mailto = g_strconcat ("mailto:";, ulink->data, NULL);
+                       icalcomponent_add_property (icalcomp, icalproperty_new_attendee (mailto));
+                       g_free (mailto);
 
-                       g_hash_table_destroy (known);
-               } else if (g_error_matches (error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NOFREEBUSYACCESS)) {
-                       cbews_forget_all_components (cbews);
-                       e_cal_backend_notify_error (E_CAL_BACKEND (cbews), error->message);
-                       g_clear_error (&error);
+                       *freebusyobjs = g_slist_prepend (*freebusyobjs, icalcomponent_as_ical_string_r 
(icalcomp));
                }
 
-               g_slist_free_full (free_busy, (GDestroyNotify) icalcomponent_free);
-               g_slist_free_full (fbdata.user_mails, g_free);
-       } else {
-               old_sync_state = g_strdup (e_cal_backend_store_get_key_value (priv->store, SYNC_KEY));
-               do {
-                       EEwsAdditionalProps *add_props;
-                       GCancellable *cancellable;
-
-                       includes_last_item = TRUE;
-
-                       add_props = e_ews_additional_props_new ();
-                       add_props->field_uri = g_strdup ("item:ItemClass");
-
-                       cancellable = cal_backend_ews_ref_cancellable (cbews);
-
-                       ret = e_ews_connection_sync_folder_items_sync (
-                               priv->cnc,
-                               EWS_PRIORITY_MEDIUM,
-                               old_sync_state,
-                               priv->folder_id,
-                               "IdOnly",
-                               add_props,
-                               EWS_MAX_FETCH_COUNT,
-                               &new_sync_state,
-                               &includes_last_item,
-                               &items_created,
-                               &items_updated,
-                               &items_deleted,
-                               cancellable,
-                               &error);
-
-                       e_ews_additional_props_free (add_props);
-                       g_clear_object (&cancellable);
-                       g_free (old_sync_state);
-                       old_sync_state = NULL;
-
-                       if (!ret) {
-                               if (g_error_matches (error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_INVALIDSYNCSTATEDATA)) {
-                                       g_clear_error (&error);
-                                       e_cal_backend_store_put_key_value (priv->store, SYNC_KEY, NULL);
-                                       cbews_forget_all_components (cbews);
-
-                                       if (!e_ews_connection_sync_folder_items_sync (
-                                                               priv->cnc,
-                                                               EWS_PRIORITY_MEDIUM,
-                                                               NULL,
-                                                               priv->folder_id,
-                                                               "IdOnly",
-                                                               NULL,
-                                                               EWS_MAX_FETCH_COUNT,
-                                                               &new_sync_state,
-                                                               &includes_last_item,
-                                                               &items_created,
-                                                               &items_updated,
-                                                               &items_deleted,
-                                                               cancellable,
-                                                               &error)) {
-                                               if (!g_error_matches (
-                                                               error,
-                                                               EWS_CONNECTION_ERROR,
-                                                               EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED)) {
-                                                       e_cal_backend_set_writable (E_CAL_BACKEND (cbews), 
TRUE);
-                                                       break;
-                                               }
-                                       }
-                               } else {
-                                       break;
-                               }
-                       }
-
-                       ret = cal_backend_ews_process_folder_items (
-                                       cbews,
-                                       new_sync_state,
-                                       items_created,
-                                       items_updated,
-                                       items_deleted);
-
-                       if (!ret)
-                               break;
-
-                       g_slist_free_full (items_created, g_object_unref);
-                       g_slist_free_full (items_updated, g_object_unref);
-                       g_slist_free_full (items_deleted, g_free);
-                       items_created = NULL;
-                       items_updated = NULL;
-                       items_deleted = NULL;
-
-                       e_cal_backend_store_put_key_value (priv->store, SYNC_KEY, new_sync_state);
-
-                       old_sync_state = new_sync_state;
-                       new_sync_state = NULL;
-               } while (!includes_last_item);
+               *freebusyobjs = g_slist_reverse (*freebusyobjs);
        }
 
-       ews_refreshing_dec (cbews);
-
-       g_clear_object (&cancellable);
+       g_slist_free_full (freebusy, (GDestroyNotify) icalcomponent_free);
 
-       g_slist_free_full (items_created, g_object_unref);
-       g_slist_free_full (items_updated, g_object_unref);
-       g_slist_free_full (items_deleted, g_free);
-
-       if (error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_clear_error (&error);
-       }
-
-       g_free (new_sync_state);
-       g_free (old_sync_state);
-
-       g_object_unref (cbews);
-
-       return NULL;
+       ecb_ews_convert_error_to_edc_error (error);
 }
 
-static gboolean
-ews_start_sync (gpointer data)
-{
-       ECalBackendEws *cbews = data;
-       GThread *thread;
-
-       PRIV_LOCK (cbews->priv);
-       if (cbews->priv->refreshing) {
-               PRIV_UNLOCK (cbews->priv);
-               return TRUE;
-       }
-
-       ews_refreshing_inc (cbews);
-
-       if (!cbews->priv->cnc) {
-               ews_refreshing_dec (cbews);
-               PRIV_UNLOCK (cbews->priv);
-               return FALSE;
-       }
-       PRIV_UNLOCK (cbews->priv);
-
-       /* run the actual operation in thread,
-        * to not block main thread of the factory */
-       thread = g_thread_new (NULL, ews_start_sync_thread, g_object_ref (cbews));
-       g_thread_unref (thread);
-
-       return TRUE;
-}
-
-static void
-ews_cal_start_refreshing (ECalBackendEws *cbews)
-{
-       ECalBackendEwsPrivate *priv;
-
-       priv = cbews->priv;
-
-       PRIV_LOCK (priv);
-
-       if (!priv->refresh_timeout &&
-           e_backend_get_online (E_BACKEND (cbews)) &&
-           priv->cnc) {
-               ews_start_sync (cbews);
-               priv->refresh_timeout = e_named_timeout_add_seconds (
-                       REFRESH_INTERVAL, (GSourceFunc) ews_start_sync, cbews);
-       }
-
-       PRIV_UNLOCK (priv);
-}
-
-static void
-e_cal_backend_ews_start_query (ECalBackend *backend,
-                               EDataCalView *query)
-{
-       ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *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;
-
-       cbews = E_CAL_BACKEND_EWS (backend);
-       priv = cbews->priv;
-
-       ews_cal_start_refreshing (cbews);
-       cbsexp = e_data_cal_view_get_sexp (query);
-       if (!cbsexp) {
-               err = EDC_ERROR (InvalidQuery);
-               e_data_cal_view_notify_complete (query, err);
-               g_error_free (err);
-               return;
-       }
-
-       sexp = e_cal_backend_sexp_text (cbsexp);
-       if (!sexp || !strcmp (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 (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 (query, comp);
-                       }
-               }
-       }
-
-       g_slist_free_full (components, g_object_unref);
-       e_data_cal_view_notify_complete (query, NULL);
-}
-
-static void
-e_cal_backend_ews_refresh (ECalBackend *backend,
-                           EDataCal *cal,
-                           guint32 context,
-                           GCancellable *cancellable)
+static gchar *
+ecb_ews_get_backend_property (ECalBackend *cal_backend,
+                             const gchar *prop_name)
 {
        ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-       GError *error = NULL;
-
-       cbews = E_CAL_BACKEND_EWS (backend);
-       priv = cbews->priv;
-
-       /* make sure we're not offline */
-       if (!e_backend_get_online (E_BACKEND (backend))) {
-               g_propagate_error (&error, EDC_ERROR (RepositoryOffline));
-               goto exit;
-       }
-
-       PRIV_LOCK (priv);
-       ews_start_sync (cbews);
-       PRIV_UNLOCK (priv);
-
-exit:
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_refresh (cal, context, error);
-}
-
-static void
-ews_cal_get_free_busy_cb (GObject *obj,
-                          GAsyncResult *res,
-                          gpointer user_data)
-{
-       EEwsConnection *cnc = (EEwsConnection *) obj;
-       EwsCalendarAsyncData *free_busy_data = user_data;
-       GSList *free_busy_sl = NULL, *i;
-       GSList *free_busy = NULL, *j;
-       GError *error = NULL;
-
-       if (!e_ews_connection_get_free_busy_finish (cnc, res, &free_busy_sl, &error)) {
-               goto done;
-       }
-
-       for (i = free_busy_sl, j = free_busy_data->users; i && j; i = i->next, j = j->next) {
-               /* add attendee property */
-               icalcomponent_add_property ((icalcomponent *) i->data, icalproperty_new_attendee (j->data));
 
-               free_busy = g_slist_append (free_busy, icalcomponent_as_ical_string_r (i->data));
-       }
-       g_slist_free (free_busy_sl);
-
-done:
-       if (free_busy)
-               e_data_cal_report_free_busy_data (free_busy_data->cal, free_busy);
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_get_free_busy (free_busy_data->cal, free_busy_data->context, error, free_busy);
-
-       g_slist_free_full (free_busy, g_free);
-       e_cal_backend_ews_async_data_free (free_busy_data);
-}
-
-static void
-e_cal_backend_ews_get_free_busy (ECalBackend *backend,
-                                 EDataCal *cal,
-                                 guint32 context,
-                                 GCancellable *cancellable,
-                                 const GSList *users,
-                                 time_t start,
-                                 time_t end)
-{
-       ECalBackendEws *cbews = E_CAL_BACKEND_EWS (backend);
-       ECalBackendEwsPrivate *priv = cbews->priv;
-       GError *error = NULL;
-       EwsCalendarAsyncData *free_busy_data;
-       EEWSFreeBusyData fbdata = { 0 };
-       GSList *users_copy = NULL;
-
-       /* make sure we're not offline */
-       if (!e_backend_get_online (E_BACKEND (backend)) || !cbews->priv->cnc) {
-               g_propagate_error (&error, EDC_ERROR (RepositoryOffline));
-               goto exit;
-       }
-
-       if (!cal_backend_ews_ensure_connected (cbews, cancellable, &error)) {
-               goto exit;
-       }
-
-       /* EWS can support only 100 identities, which is the maximum number of identities that the Web 
service method can request
-        see http://msdn.microsoft.com / en - us / library / aa564001 % 28v = EXCHG.140 % 29.aspx */
-       if (g_slist_length ((GSList *) users) > 100)
-       {
-               g_propagate_error (&error, EDC_ERROR (SearchSizeLimitExceeded));
-               goto exit;
-       }
-
-       for (; users; users = users->next)
-           users_copy = g_slist_append (users_copy, g_strdup (users->data));
-
-       free_busy_data = g_new0 (EwsCalendarAsyncData, 1);
-       free_busy_data->cbews = g_object_ref (cbews);
-       free_busy_data->cal = g_object_ref (cal);
-       free_busy_data->context = context;
-       free_busy_data->users = users_copy;
-
-       fbdata.period_start = start;
-       fbdata.period_end = end;
-       fbdata.user_mails = users_copy;
-
-       e_ews_connection_get_free_busy (
-               priv->cnc,
-               EWS_PRIORITY_MEDIUM,
-               e_ews_cal_utils_prepare_free_busy_request,
-               &fbdata,
-               cancellable,
-               ews_cal_get_free_busy_cb,
-               free_busy_data);
-
-       return;
-
-exit:
-       convert_error_to_edc_error (&error);
-       e_data_cal_respond_get_free_busy (cal, context, error, NULL);
-
-}
-
-static gchar *
-e_cal_backend_ews_get_backend_property (ECalBackend *backend,
-                                        const gchar *prop_name)
-{
+       g_return_val_if_fail (E_IS_CAL_BACKEND_EWS (cal_backend), NULL);
        g_return_val_if_fail (prop_name != NULL, NULL);
 
+       cbews = E_CAL_BACKEND_EWS (cal_backend);
+
        if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
                return g_strjoin (
                        ",",
                        CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS,
                        CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY,
                        CAL_STATIC_CAPABILITY_REMOVE_ALARMS,
-                       CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED,
                        CAL_STATIC_CAPABILITY_NO_THISANDPRIOR,
                        CAL_STATIC_CAPABILITY_NO_THISANDFUTURE,
                        CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK,
@@ -4459,78 +3485,60 @@ e_cal_backend_ews_get_backend_property (ECalBackend *backend,
                        CAL_STATIC_CAPABILITY_NO_MEMO_START_DATE,
                        CAL_STATIC_CAPABILITY_ALL_DAY_EVENT_AS_TIME,
                        CAL_STATIC_CAPABILITY_TASK_DATE_ONLY,
+                       e_cal_meta_backend_get_capabilities (E_CAL_META_BACKEND (cbews)),
                        NULL);
        } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
                /* return email address of the person who opened the calendar */
-               ECalBackendEws *cbews;
+               CamelEwsSettings *ews_settings;
 
-               cbews = E_CAL_BACKEND_EWS (backend);
+               ews_settings = ecb_ews_get_collection_settings (cbews);
 
-               return g_strdup (cbews->priv->user_email);
+               return camel_ews_settings_dup_email (ews_settings);
        } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
                /* ews does not support email based alarms */
                return NULL;
-       } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
-               ECalComponent *comp;
-               gchar *prop_value;
-
-               comp = e_cal_component_new ();
-
-               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;
-               }
-
-               prop_value = e_cal_component_get_as_string (comp);
-
-               g_object_unref (comp);
-
-               return prop_value;
        }
 
-       /* Chain up to parent's get_backend_property() method. */
-       return E_CAL_BACKEND_CLASS (e_cal_backend_ews_parent_class)->
-               get_backend_property (backend, prop_name);
+       /* Chain up to parent's method. */
+       return E_CAL_BACKEND_CLASS (e_cal_backend_ews_parent_class)->get_backend_property (cal_backend, 
prop_name);
 }
 
 static void
-e_cal_backend_ews_notify_online_cb (EBackend *backend,
-                                    GParamSpec *spec)
+ecb_ews_get_timezone_sync (ECalBackendSync *sync_backend,
+                          EDataCal *cal,
+                          GCancellable *cancellable,
+                          const gchar *tzid,
+                          gchar **tzobject,
+                          GError **error)
 {
-       ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
+       GError *local_error = NULL;
 
-       cbews = E_CAL_BACKEND_EWS (backend);
-       priv = cbews->priv;
+       g_return_if_fail (E_IS_CAL_BACKEND_EWS (sync_backend));
+       g_return_if_fail (tzid != NULL);
+       g_return_if_fail (tzobject != NULL);
 
-       PRIV_LOCK (priv);
+       *tzobject = NULL;
 
-       if (e_backend_get_online (backend)) {
-               cal_backend_ews_set_cancellable (cbews, g_cancellable_new ());
-               priv->read_only = FALSE;
-       } else {
-               switch_offline (cbews);
-       }
+       E_CAL_BACKEND_SYNC_CLASS (e_cal_backend_ews_parent_class)->get_timezone_sync (sync_backend, cal, 
cancellable, tzid, tzobject, &local_error);
+
+       if (!*tzobject) {
+               /* The timezone can be sometimes the Windows zone, try to convert it to libical */
+               const gchar *ical_location = e_cal_backend_ews_tz_util_get_ical_equivalent (tzid);
 
-       e_cal_backend_set_writable (E_CAL_BACKEND (backend), !priv->read_only);
+               if (ical_location)
+                       E_CAL_BACKEND_SYNC_CLASS (e_cal_backend_ews_parent_class)->get_timezone_sync 
(sync_backend, cal, cancellable, ical_location, tzobject, NULL);
+       }
 
-       PRIV_UNLOCK (priv);
+       if (*tzobject)
+               g_clear_error (&local_error);
+       else if (local_error)
+               g_propagate_error (error, local_error);
 }
 
 static gboolean
-e_cal_backend_ews_get_destination_address (EBackend *backend,
-                                          gchar **host,
-                                          guint16 *port)
+ecb_ews_get_destination_address (EBackend *backend,
+                                gchar **host,
+                                guint16 *port)
 {
        CamelEwsSettings *ews_settings;
        SoupURI *soup_uri;
@@ -4545,7 +3553,7 @@ e_cal_backend_ews_get_destination_address (EBackend *backend,
            !e_backend_get_source (backend))
                return FALSE;
 
-       ews_settings = cal_backend_ews_get_collection_settings (E_CAL_BACKEND_EWS (backend));
+       ews_settings = ecb_ews_get_collection_settings (E_CAL_BACKEND_EWS (backend));
        g_return_val_if_fail (ews_settings != NULL, FALSE);
 
        host_url = camel_ews_settings_dup_hosturl (ews_settings);
@@ -4570,244 +3578,119 @@ e_cal_backend_ews_get_destination_address (EBackend *backend,
        return result;
 }
 
+static gchar *
+ecb_ews_dup_component_revision (ECalCache *cal_cache,
+                               icalcomponent *icalcomp,
+                               gpointer user_data)
+{
+       g_return_val_if_fail (icalcomp != NULL, NULL);
+
+       return e_cal_util_dup_x_property (icalcomp, "X-EVOLUTION-CHANGEKEY");
+}
+
 static void
-e_cal_backend_ews_constructed (GObject *object)
+ecb_ews_constructed (GObject *object)
 {
        ECalBackendEws *cbews = E_CAL_BACKEND_EWS (object);
-       CamelEwsSettings *ews_settings;
+       ECalCache *cal_cache;
+       gchar *cache_dirname;
 
+       /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_cal_backend_ews_parent_class)->constructed (object);
 
        /* Reset the connectable, it steals data from Authentication extension,
           where is written incorrect address */
        e_backend_set_connectable (E_BACKEND (object), NULL);
 
-       ews_settings = cal_backend_ews_get_collection_settings (cbews);
-       g_warn_if_fail (cbews->priv->user_email == NULL);
-       cbews->priv->user_email = camel_ews_settings_dup_email (ews_settings);
-}
-
-static void
-e_cal_backend_ews_dispose (GObject *object)
-{
-       ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-       CamelEwsSettings *ews_settings;
+       cal_cache = e_cal_meta_backend_ref_cache (E_CAL_META_BACKEND (cbews));
+       g_return_if_fail (cal_cache != NULL);
 
-       g_return_if_fail (object != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_EWS (object));
+       cache_dirname = g_path_get_dirname (e_cache_get_filename (E_CACHE (cal_cache)));
+       g_signal_connect (cal_cache, "dup-component-revision", G_CALLBACK (ecb_ews_dup_component_revision), 
NULL);
 
-       cbews = E_CAL_BACKEND_EWS (object);
-       priv = cbews->priv;
+       g_clear_object (&cal_cache);
 
-       ews_settings = cal_backend_ews_get_collection_settings (cbews);
-       g_signal_handlers_disconnect_by_func (ews_settings, cbews_listen_notifications_cb, cbews);
+       cbews->priv->attachments_dir = g_build_filename (cache_dirname, "attachments", NULL);
+       g_mkdir_with_parents (cbews->priv->attachments_dir, 0777);
 
-       if (priv->refresh_timeout) {
-               g_source_remove (priv->refresh_timeout);
-               priv->refresh_timeout = 0;
-       }
-
-       cal_backend_ews_set_cancellable (cbews, NULL);
+       g_free (cache_dirname);
+}
 
-       if (priv->cnc) {
-               g_signal_handlers_disconnect_by_func (priv->cnc, cbews_server_notification_cb, object);
+static void
+ecb_ews_dispose (GObject *object)
+{
+       ECalBackendEws *cbews = E_CAL_BACKEND_EWS (object);
 
-               if (priv->listen_notifications) {
-                       if (priv->subscription_key != 0) {
-                               e_ews_connection_disable_notifications_sync (
-                                       priv->cnc,
-                                       priv->subscription_key);
-                               priv->subscription_key = 0;
-                       }
+       g_rec_mutex_lock (&cbews->priv->cnc_lock);
 
-                       priv->listen_notifications = FALSE;
-               }
+       g_clear_object (&cbews->priv->cnc);
 
-               g_object_unref (priv->cnc);
-               priv->cnc = NULL;
-       }
+       g_rec_mutex_unlock (&cbews->priv->cnc_lock);
 
+       /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_cal_backend_ews_parent_class)->dispose (object);
 }
 
-/* Finalize handler for the file backend */
 static void
-e_cal_backend_ews_finalize (GObject *object)
+ecb_ews_finalize (GObject *object)
 {
-       ECalBackendEws *cbews;
-       ECalBackendEwsPrivate *priv;
-
-       g_return_if_fail (object != NULL);
-       g_return_if_fail (E_IS_CAL_BACKEND_EWS (object));
-
-       cbews = E_CAL_BACKEND_EWS (object);
-       priv = cbews->priv;
-
-       /* Clean up */
-       g_rec_mutex_clear (&priv->rec_mutex);
-       g_mutex_clear (&priv->cancellable_lock);
-
-       if (priv->store) {
-               g_object_unref (priv->store);
-               priv->store = NULL;
-       }
-
-       if (priv->folder_id) {
-               g_free (priv->folder_id);
-               priv->folder_id = NULL;
-       }
-
-       if (priv->user_email) {
-               g_free (priv->user_email);
-               priv->user_email = NULL;
-       }
-
-       if (priv->storage_path) {
-               g_free (priv->storage_path);
-               priv->storage_path = NULL;
-       }
-
-       if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
-               icaltimezone_free (priv->default_zone, 1);
-               priv->default_zone = NULL;
-       }
+       ECalBackendEws *cbews = E_CAL_BACKEND_EWS (object);
 
-       g_hash_table_destroy (priv->item_id_hash);
+       g_free (cbews->priv->folder_id);
+       g_free (cbews->priv->attachments_dir);
 
-       if (priv->refreshing_done) {
-               e_flag_free (priv->refreshing_done);
-               priv->refreshing_done = NULL;
-       }
+       g_rec_mutex_clear (&cbews->priv->cnc_lock);
 
        e_cal_backend_ews_unref_windows_zones ();
 
+       /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_cal_backend_ews_parent_class)->finalize (object);
 }
 
-static ESourceAuthenticationResult
-e_cal_backend_ews_authenticate_sync (EBackend *backend,
-                                    const ENamedParameters *credentials,
-                                    gchar **out_certificate_pem,
-                                    GTlsCertificateFlags *out_certificate_errors,
-                                    GCancellable *cancellable,
-                                    GError **error)
+static void
+e_cal_backend_ews_init (ECalBackendEws *cbews)
 {
-       ECalBackendEws *cal_backend;
-       EEwsConnection *connection;
-       ESourceAuthenticationResult result;
-       CamelEwsSettings *ews_settings;
-       gchar *hosturl;
-
-       cal_backend = E_CAL_BACKEND_EWS (backend);
-       ews_settings = cal_backend_ews_get_collection_settings (cal_backend);
-       hosturl = camel_ews_settings_dup_hosturl (ews_settings);
-
-       connection = e_ews_connection_new (hosturl, ews_settings);
-
-       e_binding_bind_property (
-               backend, "proxy-resolver",
-               connection, "proxy-resolver",
-               G_BINDING_SYNC_CREATE);
-
-       result = e_ews_connection_try_credentials_sync (connection, credentials, cancellable, error);
-
-       if (result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
-
-               PRIV_LOCK (cal_backend->priv);
-
-               g_free (cal_backend->priv->user_email);
-               cal_backend->priv->user_email = camel_ews_settings_dup_email (ews_settings);
-
-               if (cal_backend->priv->cnc != NULL)
-                       g_object_unref (cal_backend->priv->cnc);
-               cal_backend->priv->cnc = g_object_ref (connection);
-
-               g_signal_connect_swapped (
-                       cal_backend->priv->cnc,
-                       "server-notification",
-                       G_CALLBACK (cbews_server_notification_cb),
-                       backend);
-
-               PRIV_UNLOCK (cal_backend->priv);
-
-               ews_start_sync (cal_backend);
-               cbews_listen_notifications_cb (cal_backend, NULL, ews_settings);
-       } else if (e_ews_connection_utils_get_without_password (ews_settings) &&
-                  result == E_SOURCE_AUTHENTICATION_REJECTED &&
-                  !e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD)) {
-               e_ews_connection_utils_force_off_ntlm_auth_check ();
-               result = E_SOURCE_AUTHENTICATION_REQUIRED;
-       }
-
-       g_object_unref (connection);
+       cbews->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbews, E_TYPE_CAL_BACKEND_EWS, ECalBackendEwsPrivate);
 
-       g_free (hosturl);
+       g_rec_mutex_init (&cbews->priv->cnc_lock);
 
-       return result;
+       e_cal_backend_ews_populate_windows_zones ();
 }
 
 static void
-e_cal_backend_ews_class_init (ECalBackendEwsClass *class)
+e_cal_backend_ews_class_init (ECalBackendEwsClass *klass)
 {
        GObjectClass *object_class;
        EBackendClass *backend_class;
        ECalBackendClass *cal_backend_class;
-
-       g_type_class_add_private (class, sizeof (ECalBackendEwsPrivate));
-
-       object_class = G_OBJECT_CLASS (class);
-       backend_class = E_BACKEND_CLASS (class);
-       cal_backend_class = E_CAL_BACKEND_CLASS (class);
-
-       object_class->constructed = e_cal_backend_ews_constructed;
-       object_class->dispose = e_cal_backend_ews_dispose;
-       object_class->finalize = e_cal_backend_ews_finalize;
-
-       backend_class->get_destination_address = e_cal_backend_ews_get_destination_address;
-       backend_class->authenticate_sync = e_cal_backend_ews_authenticate_sync;
-
-       /* Property accessors */
-       cal_backend_class->get_backend_property = e_cal_backend_ews_get_backend_property;
-
-       cal_backend_class->start_view = e_cal_backend_ews_start_query;
-
-       /* Many of these can be moved to Base class */
-       cal_backend_class->add_timezone = e_cal_backend_ews_add_timezone;
-       cal_backend_class->get_timezone = e_cal_backend_ews_get_timezone;
-
-       cal_backend_class->open = e_cal_backend_ews_open;
-       cal_backend_class->refresh = e_cal_backend_ews_refresh;
-       cal_backend_class->get_object = e_cal_backend_ews_get_object;
-       cal_backend_class->get_object_list = e_cal_backend_ews_get_object_list;
-
-       cal_backend_class->discard_alarm = e_cal_backend_ews_discard_alarm;
-
-       cal_backend_class->create_objects = e_cal_backend_ews_create_objects;
-       cal_backend_class->modify_objects = e_cal_backend_ews_modify_objects;
-       cal_backend_class->remove_objects = e_cal_backend_ews_remove_objects;
-
-       cal_backend_class->receive_objects = e_cal_backend_ews_receive_objects;
-       cal_backend_class->send_objects = e_cal_backend_ews_send_objects;
-       cal_backend_class->get_free_busy = e_cal_backend_ews_get_free_busy;
-}
-
-static void
-e_cal_backend_ews_init (ECalBackendEws *cbews)
-{
-       cbews->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbews, E_TYPE_CAL_BACKEND_EWS, ECalBackendEwsPrivate);
-
-       /* create the mutex for thread safety */
-       g_rec_mutex_init (&cbews->priv->rec_mutex);
-       g_mutex_init (&cbews->priv->cancellable_lock);
-       cbews->priv->refreshing_done = e_flag_new ();
-       cbews->priv->item_id_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-       cbews->priv->default_zone = icaltimezone_get_utc_timezone ();
-       cbews->priv->cancellable = g_cancellable_new ();
-
-       g_signal_connect (
-               cbews, "notify::online",
-               G_CALLBACK (e_cal_backend_ews_notify_online_cb), NULL);
-
-       e_cal_backend_ews_populate_windows_zones ();
+       ECalBackendSyncClass *cal_backend_sync_class;
+       ECalMetaBackendClass *cal_meta_backend_class;
+
+       g_type_class_add_private (klass, sizeof (ECalBackendEwsPrivate));
+
+       cal_meta_backend_class = E_CAL_META_BACKEND_CLASS (klass);
+       cal_meta_backend_class->connect_sync = ecb_ews_connect_sync;
+       cal_meta_backend_class->disconnect_sync = ecb_ews_disconnect_sync;
+       cal_meta_backend_class->get_changes_sync = ecb_ews_get_changes_sync;
+       cal_meta_backend_class->load_component_sync = ecb_ews_load_component_sync;
+       cal_meta_backend_class->save_component_sync = ecb_ews_save_component_sync;
+       cal_meta_backend_class->remove_component_sync = ecb_ews_remove_component_sync;
+
+       cal_backend_sync_class = E_CAL_BACKEND_SYNC_CLASS (klass);
+       cal_backend_sync_class->discard_alarm_sync = ecb_ews_discard_alarm_sync;
+       cal_backend_sync_class->receive_objects_sync = ecb_ews_receive_objects_sync;
+       cal_backend_sync_class->send_objects_sync = ecb_ews_send_objects_sync;
+       cal_backend_sync_class->get_free_busy_sync = ecb_ews_get_free_busy_sync;
+       cal_backend_sync_class->get_timezone_sync = ecb_ews_get_timezone_sync;
+
+       cal_backend_class = E_CAL_BACKEND_CLASS (klass);
+       cal_backend_class->get_backend_property = ecb_ews_get_backend_property;
+
+       backend_class = E_BACKEND_CLASS (klass);
+       backend_class->get_destination_address = ecb_ews_get_destination_address;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->constructed = ecb_ews_constructed;
+       object_class->dispose = ecb_ews_dispose;
+       object_class->finalize = ecb_ews_finalize;
 }
diff --git a/src/calendar/e-cal-backend-ews.h b/src/calendar/e-cal-backend-ews.h
index 48480f3..4537eeb 100644
--- a/src/calendar/e-cal-backend-ews.h
+++ b/src/calendar/e-cal-backend-ews.h
@@ -35,31 +35,19 @@ G_BEGIN_DECLS
 
 typedef struct _ECalBackendEws        ECalBackendEws;
 typedef struct _ECalBackendEwsClass   ECalBackendEwsClass;
-
 typedef struct _ECalBackendEwsPrivate ECalBackendEwsPrivate;
 
 struct _ECalBackendEws {
-       ECalBackend backend;
-
-       /* Private data */
+       ECalMetaBackend parent_object;
        ECalBackendEwsPrivate *priv;
 };
 
 struct _ECalBackendEwsClass {
-       ECalBackendClass parent_class;
+       ECalMetaBackendClass parent_class;
 };
 
 GType   e_cal_backend_ews_get_type (void);
 
-const EEwsConnection *
-       e_cal_backend_ews_get_connection                (ECalBackendEws *cbews);
-
-const icaltimezone *
-       e_cal_backend_ews_get_default_zone              (ECalBackendEws *cbews);
-
-const gchar *
-       e_cal_backend_ews_get_user_email                (ECalBackendEws *cbews);
-
 G_END_DECLS
 
-#endif
+#endif /* E_CAL_BACKEND_EWS_H */
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index aa5f22e..48517ca 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -1973,6 +1973,7 @@ e_ews_attachment_info_free (EEwsAttachmentInfo *info)
        }
 
        g_free (info->prefer_filename);
+       g_free (info->id);
        g_free (info);
 }
 
@@ -2067,7 +2068,6 @@ e_ews_attachment_info_set_filename (EEwsAttachmentInfo *info,
        info->data.inlined.filename = g_strdup (filename);
 }
 
-
 const gchar *
 e_ews_attachment_info_get_uri (EEwsAttachmentInfo *info)
 {
@@ -2088,6 +2088,26 @@ e_ews_attachment_info_set_uri (EEwsAttachmentInfo *info,
        info->data.uri = g_strdup (uri);
 }
 
+const gchar *
+e_ews_attachment_info_get_id (EEwsAttachmentInfo *info)
+{
+       g_return_val_if_fail (info != NULL, NULL);
+
+       return info->id;
+}
+
+void
+e_ews_attachment_info_set_id (EEwsAttachmentInfo *info,
+                             const gchar *id)
+{
+       g_return_if_fail (info != NULL);
+
+       if (info->id != id) {
+               g_free (info->id);
+               info->id = g_strdup (id);
+       }
+}
+
 /* Connection APIS */
 
 /**
@@ -3478,13 +3498,13 @@ ews_soup_got_chunk (SoupMessage *msg,
                if (write (fd, (const gchar *) chunk->data, chunk->length) != chunk->length) {
                        g_set_error (
                                &data->error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_UNKNOWN,
-                               "Failed to write streaming data to file : %d ", errno);
+                               "Failed to write streaming data to file '%s': %s", data->cache_filename, 
g_strerror (errno));
                }
                close (fd);
        } else {
                g_set_error (
                        &data->error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_UNKNOWN,
-                       "Failed to open the cache file : %d ", errno);
+                       "Failed to open the cache file '%s': %s", data->cache_filename, g_strerror (errno));
        }
 }
 
@@ -6983,9 +7003,7 @@ ews_handle_root_item_id_param (ESoapParameter *subparam,
        if (attspara == NULL)
                return;
 
-       async_data->items = g_slist_append (
-               async_data->items,
-               e_soap_parameter_get_property (attspara, "RootItemChangeKey"));
+       async_data->sync_state = e_soap_parameter_get_property (attspara, "RootItemChangeKey");
 }
 
 static void
@@ -7085,7 +7103,7 @@ e_ews_connection_delete_attachments (EEwsConnection *cnc,
 gboolean
 e_ews_connection_delete_attachments_finish (EEwsConnection *cnc,
                                             GAsyncResult *result,
-                                           GSList **parents_ids,
+                                           gchar **new_change_key,
                                             GError **error)
 {
        GSimpleAsyncResult *simple;
@@ -7103,10 +7121,10 @@ e_ews_connection_delete_attachments_finish (EEwsConnection *cnc,
        if (g_simple_async_result_propagate_error (simple, error))
                return FALSE;
 
-       if (parents_ids)
-               *parents_ids = async_data->items;
+       if (new_change_key)
+               *new_change_key = async_data->sync_state;
        else
-               g_slist_free_full (async_data->items, g_free);
+               g_free (async_data->sync_state);
 
        return TRUE;
 }
@@ -7115,7 +7133,7 @@ gboolean
 e_ews_connection_delete_attachments_sync (EEwsConnection *cnc,
                                           gint pri,
                                           const GSList *attachments_ids,
-                                         GSList **parents_ids,
+                                         gchar **new_change_key,
                                           GCancellable *cancellable,
                                           GError **error)
 {
@@ -7134,7 +7152,7 @@ e_ews_connection_delete_attachments_sync (EEwsConnection *cnc,
        result = e_async_closure_wait (closure);
 
        ret = e_ews_connection_delete_attachments_finish (
-               cnc, result, parents_ids, error);
+               cnc, result, new_change_key, error);
 
        e_async_closure_free (closure);
 
diff --git a/src/server/e-ews-connection.h b/src/server/e-ews-connection.h
index 7d472dc..b596bc7 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -954,13 +954,13 @@ void              e_ews_connection_delete_attachments
 gboolean       e_ews_connection_delete_attachments_finish
                                                (EEwsConnection *cnc,
                                                 GAsyncResult *result,
-                                                GSList **parents_ids,
+                                                gchar **new_change_key,
                                                 GError **error);
 gboolean       e_ews_connection_delete_attachments_sync
                                                (EEwsConnection *cnc,
                                                 gint pri,
                                                 const GSList *attachments_ids,
-                                                GSList **parents_ids,
+                                                gchar **new_change_key,
                                                 GCancellable *cancellable,
                                                 GError **error);
 
diff --git a/src/server/e-ews-item.h b/src/server/e-ews-item.h
index 832057a..88a540e 100644
--- a/src/server/e-ews-item.h
+++ b/src/server/e-ews-item.h
@@ -129,6 +129,7 @@ typedef struct {
                gchar *uri;
        } data;
        gchar *prefer_filename;
+       gchar *id;
 } EEwsAttachmentInfo;
 
 typedef enum {
@@ -296,6 +297,10 @@ void               e_ews_attachment_info_set_filename
 const gchar *  e_ews_attachment_info_get_uri   (EEwsAttachmentInfo *info);
 void           e_ews_attachment_info_set_uri   (EEwsAttachmentInfo *info,
                                                 const gchar *uri);
+const gchar *  e_ews_attachment_info_get_id    (EEwsAttachmentInfo *info);
+void           e_ews_attachment_info_set_id    (EEwsAttachmentInfo *info,
+                                                const gchar *id);
+
 
 /* Contact fields */
 const gchar *  e_ews_item_get_fileas           (EEwsItem *item);


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