[evolution-ews/gnome-3-38] I#132 - Server-side deleted calendar does not disappear



commit fc09ba4a3c340102785578c9b5ac2edd4970e5d6
Author: Milan Crha <mcrha redhat com>
Date:   Fri Nov 6 11:23:04 2020 +0100

    I#132 - Server-side deleted calendar does not disappear
    
    Closes https://gitlab.gnome.org/GNOME/evolution-ews/-/issues/132

 src/EWS/common/e-ews-folder.c        |   1 +
 src/EWS/common/e-source-ews-folder.c |  88 +++++++++++++++--
 src/EWS/common/e-source-ews-folder.h |   4 +
 src/EWS/registry/e-ews-backend.c     | 181 ++++++++++++++++++++++++++---------
 4 files changed, 225 insertions(+), 49 deletions(-)
---
diff --git a/src/EWS/common/e-ews-folder.c b/src/EWS/common/e-ews-folder.c
index 45bb0d5a..6ae7c496 100644
--- a/src/EWS/common/e-ews-folder.c
+++ b/src/EWS/common/e-ews-folder.c
@@ -752,6 +752,7 @@ e_ews_folder_utils_populate_esource (ESource *source,
                        folder_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
                        e_source_ews_folder_set_id (folder_ext, folder_id->id);
                        e_source_ews_folder_set_change_key (folder_ext, NULL);
+                       e_source_ews_folder_set_name (folder_ext, e_ews_folder_get_name (folder));
                        e_source_ews_folder_set_foreign (folder_ext, e_ews_folder_get_foreign (folder));
                        e_source_ews_folder_set_foreign_subfolders (folder_ext, (flags & 
E_EWS_ESOURCE_FLAG_INCLUDE_SUBFOLDERS) != 0);
                        e_source_ews_folder_set_foreign_mail (folder_ext, e_ews_folder_get_foreign_mail 
(folder));
diff --git a/src/EWS/common/e-source-ews-folder.c b/src/EWS/common/e-source-ews-folder.c
index c8b88903..c0ae0827 100644
--- a/src/EWS/common/e-source-ews-folder.c
+++ b/src/EWS/common/e-source-ews-folder.c
@@ -15,6 +15,7 @@
 struct _ESourceEwsFolderPrivate {
        gchar *change_key;
        gchar *id;
+       gchar *name;
        gboolean foreign;
        gboolean foreign_subfolders;
        gchar *foreign_mail;
@@ -34,6 +35,7 @@ enum {
        PROP_FOREIGN_MAIL,
        PROP_FREEBUSY_WEEKS_BEFORE,
        PROP_FREEBUSY_WEEKS_AFTER,
+       PROP_NAME,
        PROP_PUBLIC,
        PROP_USE_PRIMARY_ADDRESS,
        PROP_FETCH_GAL_PHOTOS
@@ -93,6 +95,12 @@ source_ews_folder_set_property (GObject *object,
                                g_value_get_uint (value));
                        return;
 
+               case PROP_NAME:
+                       e_source_ews_folder_set_name (
+                               E_SOURCE_EWS_FOLDER (object),
+                               g_value_get_string (value));
+                       return;
+
                case PROP_PUBLIC:
                        e_source_ews_folder_set_public (
                                E_SOURCE_EWS_FOLDER (object),
@@ -171,6 +179,13 @@ source_ews_folder_get_property (GObject *object,
                                E_SOURCE_EWS_FOLDER (object)));
                        return;
 
+               case PROP_NAME:
+                       g_value_take_string (
+                               value,
+                               e_source_ews_folder_dup_name (
+                               E_SOURCE_EWS_FOLDER (object)));
+                       return;
+
                case PROP_PUBLIC:
                        g_value_set_boolean (
                                value,
@@ -205,6 +220,7 @@ source_ews_folder_finalize (GObject *object)
 
        g_free (priv->change_key);
        g_free (priv->id);
+       g_free (priv->name);
        g_free (priv->foreign_mail);
 
        /* Chain up to parent's finalize() method. */
@@ -319,6 +335,19 @@ e_source_ews_folder_class_init (ESourceEwsFolderClass *class)
                        G_PARAM_STATIC_STRINGS |
                        E_SOURCE_PARAM_SETTING));
 
+       g_object_class_install_property (
+               object_class,
+               PROP_NAME,
+               g_param_spec_string (
+                       "name",
+                       "Name",
+                       "The server-side folder name",
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS |
+                       E_SOURCE_PARAM_SETTING));
+
        g_object_class_install_property (
                object_class,
                PROP_PUBLIC,
@@ -407,13 +436,13 @@ e_source_ews_folder_set_change_key (ESourceEwsFolder *extension,
 
        e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
 
-       if (g_strcmp0 (extension->priv->change_key, change_key) == 0) {
+       if (e_util_strcmp0 (extension->priv->change_key, change_key) == 0) {
                e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
                return;
        }
 
        g_free (extension->priv->change_key);
-       extension->priv->change_key = g_strdup (change_key);
+       extension->priv->change_key = e_util_strdup_strip (change_key);
 
        e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
 
@@ -454,13 +483,13 @@ e_source_ews_folder_set_id (ESourceEwsFolder *extension,
 
        e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
 
-       if (g_strcmp0 (extension->priv->id, id) == 0) {
+       if (e_util_strcmp0 (extension->priv->id, id) == 0) {
                e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
                return;
        }
 
        g_free (extension->priv->id);
-       extension->priv->id = g_strdup (id);
+       extension->priv->id = e_util_strdup_strip (id);
 
        e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
 
@@ -485,6 +514,53 @@ e_source_ews_folder_dup_folder_id (ESourceEwsFolder *extension)
        return folder_id;
 }
 
+const gchar *
+e_source_ews_folder_get_name (ESourceEwsFolder *extension)
+{
+       g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), NULL);
+
+       return extension->priv->name;
+}
+
+gchar *
+e_source_ews_folder_dup_name (ESourceEwsFolder *extension)
+{
+       const gchar *protected;
+       gchar *duplicate;
+
+       g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), NULL);
+
+       e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
+
+       protected = e_source_ews_folder_get_name (extension);
+       duplicate = g_strdup (protected);
+
+       e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+
+       return duplicate;
+}
+
+void
+e_source_ews_folder_set_name (ESourceEwsFolder *extension,
+                             const gchar *name)
+{
+       g_return_if_fail (E_IS_SOURCE_EWS_FOLDER (extension));
+
+       e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
+
+       if (e_util_strcmp0 (extension->priv->name, name) == 0) {
+               e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+               return;
+       }
+
+       g_free (extension->priv->name);
+       extension->priv->name = e_util_strdup_strip (name);
+
+       e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+
+       g_object_notify (G_OBJECT (extension), "name");
+}
+
 gboolean
 e_source_ews_folder_get_foreign (ESourceEwsFolder *extension)
 {
@@ -563,13 +639,13 @@ e_source_ews_folder_set_foreign_mail (ESourceEwsFolder *extension,
 
        e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
 
-       if (g_strcmp0 (extension->priv->foreign_mail, foreign_mail) == 0) {
+       if (e_util_strcmp0 (extension->priv->foreign_mail, foreign_mail) == 0) {
                e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
                return;
        }
 
        g_free (extension->priv->foreign_mail);
-       extension->priv->foreign_mail = g_strdup (foreign_mail);
+       extension->priv->foreign_mail = e_util_strdup_strip (foreign_mail);
 
        e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
 
diff --git a/src/EWS/common/e-source-ews-folder.h b/src/EWS/common/e-source-ews-folder.h
index 984b5e57..525e9ac1 100644
--- a/src/EWS/common/e-source-ews-folder.h
+++ b/src/EWS/common/e-source-ews-folder.h
@@ -60,6 +60,10 @@ const gchar *        e_source_ews_folder_get_id      (ESourceEwsFolder *extension);
 gchar *                e_source_ews_folder_dup_id      (ESourceEwsFolder *extension);
 void           e_source_ews_folder_set_id      (ESourceEwsFolder *extension,
                                                 const gchar *id);
+const gchar *  e_source_ews_folder_get_name    (ESourceEwsFolder *extension);
+gchar *                e_source_ews_folder_dup_name    (ESourceEwsFolder *extension);
+void           e_source_ews_folder_set_name    (ESourceEwsFolder *extension,
+                                                const gchar *name);
 
 EwsFolderId *  e_source_ews_folder_dup_folder_id
                                                (ESourceEwsFolder *extension);
diff --git a/src/EWS/registry/e-ews-backend.c b/src/EWS/registry/e-ews-backend.c
index c01e3172..b9915a9e 100644
--- a/src/EWS/registry/e-ews-backend.c
+++ b/src/EWS/registry/e-ews-backend.c
@@ -20,6 +20,7 @@
 typedef struct _SyncFoldersClosure SyncFoldersClosure;
 
 struct _EEwsBackendPrivate {
+       gchar *deleted_items_folder_id;
        /* Folder ID -> ESource */
        GHashTable *folders;
        GMutex folders_lock;
@@ -71,26 +72,9 @@ sync_folders_closure_free (SyncFoldersClosure *closure)
        g_slice_free (SyncFoldersClosure, closure);
 }
 
-static gboolean
-ews_backend_folders_contains (EEwsBackend *backend,
-                              const gchar *folder_id)
-{
-       gboolean contains;
-
-       g_return_val_if_fail (folder_id != NULL, FALSE);
-
-       g_mutex_lock (&backend->priv->folders_lock);
-
-       contains = g_hash_table_contains (backend->priv->folders, folder_id);
-
-       g_mutex_unlock (&backend->priv->folders_lock);
-
-       return contains;
-}
-
 static void
 ews_backend_folders_insert (EEwsBackend *backend,
-                            const gchar *folder_id,
+                            gchar *folder_id, /* assumes ownership */
                             ESource *source)
 {
        g_return_if_fail (folder_id != NULL);
@@ -100,7 +84,7 @@ ews_backend_folders_insert (EEwsBackend *backend,
 
        g_hash_table_insert (
                backend->priv->folders,
-               g_strdup (folder_id),
+               folder_id,
                g_object_ref (source));
 
        g_mutex_unlock (&backend->priv->folders_lock);
@@ -290,6 +274,7 @@ ews_backend_new_child (EEwsBackend *backend,
                E_SOURCE_EWS_FOLDER (extension), fid->id);
        e_source_ews_folder_set_change_key (
                E_SOURCE_EWS_FOLDER (extension), fid->change_key);
+       e_source_ews_folder_set_name (E_SOURCE_EWS_FOLDER (extension), e_ews_folder_get_name (folder));
 
        extension_name = E_SOURCE_EXTENSION_OFFLINE;
        extension = e_source_get_extension (source, extension_name);
@@ -334,6 +319,26 @@ ews_backend_new_address_book (EEwsBackend *backend,
        return ews_backend_new_child (backend, folder);
 }
 
+static void
+ews_backend_update_folder_name (ESource *source,
+                               EEwsFolder *folder)
+{
+       if (folder && source && e_source_has_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER)) {
+               ESourceEwsFolder *folder_extension;
+
+               folder_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
+
+               /* The user did not change the folder name (old sources have stored NULL), but it changed on 
the server */
+               if ((!e_source_ews_folder_get_name (folder_extension) ||
+                   g_strcmp0 (e_source_ews_folder_get_name (folder_extension), e_source_get_display_name 
(source)) == 0) &&
+                   g_strcmp0 (e_source_get_display_name (source), e_ews_folder_get_name (folder)) != 0) {
+                       e_source_set_display_name (source, e_ews_folder_get_name (folder));
+               }
+
+               e_source_ews_folder_set_name (folder_extension, e_ews_folder_get_name (folder));
+       }
+}
+
 static void
 ews_backend_sync_created_folders (EEwsBackend *backend,
                                  GSList *list,
@@ -348,15 +353,25 @@ ews_backend_sync_created_folders (EEwsBackend *backend,
 
        for (link = list; link != NULL; link = g_slist_next (link)) {
                EEwsFolder *folder = E_EWS_FOLDER (link->data);
-               const EwsFolderId *fid;
-               ESource *source = NULL;
+               const EwsFolderId *fid, *parent_fid;
+               ESource *source;
 
-               /* If we already know about this folder, skip it. */
                fid = e_ews_folder_get_id (folder);
                if (!fid || !fid->id)
-                       continue;  /* not a valid ID anyway */
-               if (ews_backend_folders_contains (backend, fid->id)) {
+                       continue;
+
+               /* Skip those under 'Deleted Items' */
+               parent_fid = e_ews_folder_get_parent_id (folder);
+               if (parent_fid && parent_fid->id && g_strcmp0 (parent_fid->id, 
backend->priv->deleted_items_folder_id) == 0)
+                       continue;
+
+               source = ews_backend_folders_lookup (backend, fid->id);
+
+               /* If we already know about this folder, skip it. */
+               if (source) {
+                       ews_backend_update_folder_name (source, folder);
                        g_hash_table_remove (old_sources, fid->id);
+                       g_clear_object (&source);
                        continue;
                }
 
@@ -393,6 +408,27 @@ ews_backend_sync_created_folders (EEwsBackend *backend,
        g_object_unref (server);
 }
 
+static void
+ews_backend_delete_folder (EEwsBackend *backend,
+                          const gchar *folder_id,
+                          GHashTable *old_sources)
+{
+       ESource *source = NULL;
+
+       if (folder_id) {
+               source = ews_backend_folders_lookup (backend, folder_id);
+               g_hash_table_remove (old_sources, folder_id);
+       }
+
+       if (source) {
+               /* This will trigger a "child-removed" signal and
+                * our handler will remove the hash table entry. */
+               e_source_remove_sync (source, NULL, NULL);
+
+               g_object_unref (source);
+       }
+}
+
 static void
 ews_backend_sync_deleted_folders (EEwsBackend *backend,
                                  GSList *list,
@@ -402,21 +438,44 @@ ews_backend_sync_deleted_folders (EEwsBackend *backend,
 
        for (link = list; link != NULL; link = g_slist_next (link)) {
                const gchar *folder_id = link->data;
-               ESource *source = NULL;
 
-               if (folder_id) {
-                       source = ews_backend_folders_lookup (backend, folder_id);
-                       g_hash_table_remove (old_sources, folder_id);
-               }
+               ews_backend_delete_folder (backend, folder_id, old_sources);
+       }
+}
+
+static void
+ews_backend_sync_updated_folders (EEwsBackend *backend,
+                                 GSList *list,
+                                 GHashTable *old_sources)
+{
+       GSList *link;
 
-               if (source == NULL)
+       for (link = list; link != NULL; link = g_slist_next (link)) {
+               EEwsFolder *folder = link->data;
+               const EwsFolderId *id, *parent_id;
+
+               if (!folder)
                        continue;
 
-               /* This will trigger a "child-removed" signal and
-                * our handler will remove the hash table entry. */
-               e_source_remove_sync (source, NULL, NULL);
+               id = e_ews_folder_get_id (folder);
+               parent_id = e_ews_folder_get_parent_id (folder);
 
-               g_object_unref (source);
+               if (id && parent_id) {
+                       /* Deleted calendars are under 'Deleted Items', even they are not visible in the OWA 
*/
+                       if (backend->priv->deleted_items_folder_id &&
+                           g_strcmp0 (parent_id->id, backend->priv->deleted_items_folder_id) == 0) {
+                               ews_backend_delete_folder (backend, id->id, old_sources);
+                       } else {
+                               ESource *source;
+
+                               source = ews_backend_folders_lookup (backend, id->id);
+
+                               if (source) {
+                                       ews_backend_update_folder_name (source, folder);
+                                       g_object_unref (source);
+                               }
+                       }
+               }
        }
 }
 
@@ -518,6 +577,7 @@ ews_backend_add_gal_source (EEwsBackend *backend)
                extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
                folder_extension = e_source_get_extension (source, extension_name);
                e_source_ews_folder_set_id (folder_extension, oal_id);
+               e_source_ews_folder_set_name (folder_extension, display_name);
 
                extension_name = E_SOURCE_EXTENSION_OFFLINE;
                offline_extension = e_source_get_extension (source, extension_name);
@@ -602,12 +662,9 @@ ews_backend_sync_folders_idle_cb (gpointer user_data)
 {
        SyncFoldersClosure *closure = user_data;
 
-       /* FIXME Handle updated folders. */
-
-       ews_backend_sync_deleted_folders (
-               closure->backend, closure->folders_deleted, closure->old_sources);
-       ews_backend_sync_created_folders (
-               closure->backend, closure->folders_created, closure->old_sources);
+       ews_backend_sync_deleted_folders (closure->backend, closure->folders_deleted, closure->old_sources);
+       ews_backend_sync_updated_folders (closure->backend, closure->folders_updated, closure->old_sources);
+       ews_backend_sync_created_folders (closure->backend, closure->folders_created, closure->old_sources);
 
        add_remote_sources (closure->backend, closure->old_sources);
 
@@ -645,6 +702,7 @@ ews_backend_finalize (GObject *object)
 
        priv = E_EWS_BACKEND_GET_PRIVATE (object);
 
+       g_free (priv->deleted_items_folder_id);
        g_hash_table_destroy (priv->folders);
        g_mutex_clear (&priv->folders_lock);
 
@@ -865,7 +923,6 @@ ews_backend_child_added (ECollectionBackend *backend,
                        ews_backend_folders_insert (
                                E_EWS_BACKEND (backend),
                                folder_id, child_source);
-                       g_free (folder_id);
                }
        }
 
@@ -967,8 +1024,6 @@ ews_backend_create_resource_sync (ECollectionBackend *backend,
                        folder_name, folder_type,
                        &out_folder_id, cancellable, error);
 
-               g_free (folder_name);
-
                /* Sanity check */
                g_warn_if_fail (
                        (success && out_folder_id != NULL) ||
@@ -984,9 +1039,12 @@ ews_backend_create_resource_sync (ECollectionBackend *backend,
                                extension, out_folder_id->id);
                        e_source_ews_folder_set_change_key (
                                extension, out_folder_id->change_key);
+                       e_source_ews_folder_set_name (extension, folder_name);
 
                        e_ews_folder_id_free (out_folder_id);
                }
+
+               g_free (folder_name);
        }
 
        if (success) {
@@ -1485,6 +1543,43 @@ e_ews_backend_sync_folders_sync (EEwsBackend *backend,
 
        g_mutex_lock (&backend->priv->sync_state_lock);
        old_sync_state = g_strdup (backend->priv->sync_state);
+
+       if (!backend->priv->deleted_items_folder_id) {
+               EwsFolderId fid;
+               GSList in_lst, *folders = NULL;
+
+               memset (&fid, 0, sizeof (EwsFolderId));
+               fid.id = (gchar *) "deleteditems";
+               fid.is_distinguished_id = TRUE;
+
+               memset (&in_lst, 0, sizeof (GSList));
+               in_lst.data = &fid;
+
+               g_mutex_unlock (&backend->priv->sync_state_lock);
+
+               if (e_ews_connection_get_folder_sync (connection, EWS_PRIORITY_MEDIUM, "IdOnly", NULL, 
&in_lst, &folders, cancellable, NULL)) {
+                       EEwsFolder *deleteditems = folders ? folders->data : NULL;
+
+                       g_mutex_lock (&backend->priv->sync_state_lock);
+
+                       if (deleteditems) {
+                               const EwsFolderId *id = e_ews_folder_get_id (deleteditems);
+
+                               if (id && id->id && *id->id) {
+                                       /* In case multiple threads fight on the authenticate at the same
+                                          time and one might eventually set the value before the lock
+                                          was re-acquired. */
+                                       g_free (backend->priv->deleted_items_folder_id);
+                                       backend->priv->deleted_items_folder_id = g_strdup (id->id);
+                               }
+                       }
+
+                       g_slist_free_full (folders, g_object_unref);
+               } else {
+                       g_mutex_lock (&backend->priv->sync_state_lock);
+               }
+       }
+
        g_mutex_unlock (&backend->priv->sync_state_lock);
 
        success = e_ews_connection_sync_folder_hierarchy_sync (connection, EWS_PRIORITY_MEDIUM, 
old_sync_state,


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