[evolution-data-server] I#51 - [Gmail] Change from OAuth2 to other authentication doesn't stick



commit 32d89b16591465a09028994ed4b93a4de4493255
Author: Milan Crha <mcrha redhat com>
Date:   Thu Nov 1 18:34:05 2018 +0100

    I#51 - [Gmail] Change from OAuth2 to other authentication doesn't stick
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/issues/51

 src/libebackend/e-collection-backend.c             | 65 ++++++++++++++++++
 src/libebackend/e-collection-backend.h             |  3 +
 src/modules/google-backend/module-google-backend.c | 76 +++++++++++++++++-----
 3 files changed, 127 insertions(+), 17 deletions(-)
---
diff --git a/src/libebackend/e-collection-backend.c b/src/libebackend/e-collection-backend.c
index d9ed7d43f..335fc773e 100644
--- a/src/libebackend/e-collection-backend.c
+++ b/src/libebackend/e-collection-backend.c
@@ -71,6 +71,7 @@ struct _ECollectionBackendPrivate {
        /* Resource ID -> ESource */
        GHashTable *unclaimed_resources;
        GMutex unclaimed_resources_lock;
+       GHashTable *new_sources; /* ESource::uid ~> NULL, uses the unclaimed_resources_lock */
 
        gulong source_added_handler_id;
        gulong source_removed_handler_id;
@@ -342,6 +343,13 @@ collection_backend_claim_resource (ECollectionBackend *backend,
                GFile *file = collection_backend_new_user_file (backend);
                source = collection_backend_new_source (backend, file, error);
                g_object_unref (file);
+
+               if (source) {
+                       if (!backend->priv->new_sources)
+                               backend->priv->new_sources = g_hash_table_new_full (g_str_hash, g_str_equal, 
g_free, NULL);
+
+                       g_hash_table_insert (backend->priv->new_sources, e_source_dup_uid (source), NULL);
+               }
        }
 
        g_mutex_unlock (&backend->priv->unclaimed_resources_lock);
@@ -547,6 +555,21 @@ collection_backend_source_enabled_cb (ESource *source,
        g_object_notify (collection, "mail-enabled");
 }
 
+static void
+collection_backend_forget_new_sources (ECollectionBackend *backend)
+{
+       g_return_if_fail (E_IS_COLLECTION_BACKEND (backend));
+
+       g_mutex_lock (&backend->priv->unclaimed_resources_lock);
+
+       if (backend->priv->new_sources) {
+               g_hash_table_destroy (backend->priv->new_sources);
+               backend->priv->new_sources = NULL;
+       }
+
+       g_mutex_unlock (&backend->priv->unclaimed_resources_lock);
+}
+
 static gboolean
 collection_backend_populate_idle_cb (gpointer user_data)
 {
@@ -561,6 +584,10 @@ collection_backend_populate_idle_cb (gpointer user_data)
        g_return_val_if_fail (class != NULL, FALSE);
        g_return_val_if_fail (class->populate != NULL, FALSE);
 
+       /* Any new sources found during the last populate() are not
+          considered new anymore. */
+       collection_backend_forget_new_sources (backend);
+
        class->populate (backend);
 
        return FALSE;
@@ -773,6 +800,8 @@ collection_backend_dispose (GObject *object)
 
        g_mutex_lock (&priv->unclaimed_resources_lock);
        g_hash_table_remove_all (priv->unclaimed_resources);
+       if (priv->new_sources)
+               g_hash_table_remove_all (priv->new_sources);
        g_mutex_unlock (&priv->unclaimed_resources_lock);
 
        /* Chain up to parent's dispose() method. */
@@ -792,6 +821,8 @@ collection_backend_finalize (GObject *object)
        g_mutex_clear (&priv->property_lock);
 
        g_hash_table_destroy (priv->unclaimed_resources);
+       if (priv->new_sources)
+               g_hash_table_destroy (priv->new_sources);
        g_mutex_clear (&priv->unclaimed_resources_lock);
 
        g_weak_ref_clear (&priv->server);
@@ -1201,6 +1232,7 @@ e_collection_backend_init (ECollectionBackend *backend)
        g_mutex_init (&backend->priv->children_lock);
        g_mutex_init (&backend->priv->property_lock);
        backend->priv->unclaimed_resources = unclaimed_resources;
+       backend->priv->new_sources = NULL;
        g_mutex_init (&backend->priv->unclaimed_resources_lock);
        g_weak_ref_init (&backend->priv->server, NULL);
 }
@@ -1256,6 +1288,39 @@ e_collection_backend_new_child (ECollectionBackend *backend,
        return child_source;
 }
 
+/**
+ * e_collection_backend_is_new_source:
+ * @backend: an #ECollectionBackend
+ * @source: a child #ESource
+ *
+ * Returns whether the @source is a newly created child or not. New sources
+ * are remembered between two populate calls only.
+ *
+ * Returns: %TRUE, when the @source is a new child; %FALSE when
+ *    it had been known before.
+ *
+ * Since: 3.32
+ **/
+gboolean
+e_collection_backend_is_new_source (ECollectionBackend *backend,
+                                   ESource *source)
+{
+       gboolean is_new;
+
+       g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (e_source_get_uid (source) != NULL, FALSE);
+
+       g_mutex_lock (&backend->priv->unclaimed_resources_lock);
+
+       is_new = backend->priv->new_sources &&
+               g_hash_table_contains (backend->priv->new_sources, e_source_get_uid (source));
+
+       g_mutex_unlock (&backend->priv->unclaimed_resources_lock);
+
+       return is_new;
+}
+
 /**
  * e_collection_backend_ref_proxy_resolver:
  * @backend: an #ECollectionBackend
diff --git a/src/libebackend/e-collection-backend.h b/src/libebackend/e-collection-backend.h
index 014232e42..695358d51 100644
--- a/src/libebackend/e-collection-backend.h
+++ b/src/libebackend/e-collection-backend.h
@@ -115,6 +115,9 @@ struct _ECollectionBackendClass {
 GType          e_collection_backend_get_type   (void) G_GNUC_CONST;
 ESource *      e_collection_backend_new_child  (ECollectionBackend *backend,
                                                 const gchar *resource_id);
+gboolean       e_collection_backend_is_new_source
+                                               (ECollectionBackend *backend,
+                                                ESource *source);
 GProxyResolver *
                e_collection_backend_ref_proxy_resolver
                                                (ECollectionBackend *backend);
diff --git a/src/modules/google-backend/module-google-backend.c 
b/src/modules/google-backend/module-google-backend.c
index c5527e3af..29586337f 100644
--- a/src/modules/google-backend/module-google-backend.c
+++ b/src/modules/google-backend/module-google-backend.c
@@ -151,28 +151,65 @@ host_ends_with (const gchar *host,
 }
 
 static gboolean
-google_backend_is_google_host (ESourceAuthentication *auth_extension)
+google_backend_is_google_host (ESourceAuthentication *auth_extension,
+                              gboolean *out_requires_oauth2)
 {
        gboolean is_google;
+       gboolean requires_oauth2;
        gchar *host;
 
        g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (auth_extension), FALSE);
 
        host = e_source_authentication_dup_host (auth_extension);
 
-       is_google = host && (
+       requires_oauth2 = host && host_ends_with (host, "googleusercontent.com");
+
+       is_google = requires_oauth2 || (host && (
                host_ends_with (host, "gmail.com") ||
                host_ends_with (host, "googlemail.com") ||
-               host_ends_with (host, "google.com") ||
-               host_ends_with (host, "googleusercontent.com"));
+               host_ends_with (host, "google.com")));
 
        g_free (host);
 
+       if (out_requires_oauth2)
+               *out_requires_oauth2 = requires_oauth2;
+
        return is_google;
 }
 
+static gboolean
+google_backend_is_oauth2 (const gchar *method)
+{
+       return g_strcmp0 (method, GOOGLE_OAUTH2_METHOD) == 0 ||
+               g_strcmp0 (method, "OAuth2") == 0 ||
+               g_strcmp0 (method, "XOAUTH2") == 0;
+}
+
+static gboolean
+google_backend_can_change_auth_method (ESourceAuthentication *auth_extension,
+                                      const gchar *new_method)
+{
+       gchar *cur_method;
+       gboolean can_change;
+
+       g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (auth_extension), FALSE);
+
+       if (!new_method)
+               return FALSE;
+
+       cur_method = e_source_authentication_dup_method (auth_extension);
+
+       /* Only when turning off OAuth2 */
+       can_change = google_backend_is_oauth2 (cur_method) && !google_backend_is_oauth2 (new_method);
+
+       g_free (cur_method);
+
+       return can_change;
+}
+
 static void
-google_backend_mail_update_auth_method (ESource *child_source,
+google_backend_mail_update_auth_method (ECollectionBackend *collection_backend,
+                                       ESource *child_source,
                                        ESource *master_source)
 {
        ESourceAuthentication *auth_extension;
@@ -182,7 +219,7 @@ google_backend_mail_update_auth_method (ESource *child_source,
 
        auth_extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION);
 
-       if (!google_backend_is_google_host (auth_extension))
+       if (!google_backend_is_google_host (auth_extension, NULL))
                return;
 
        oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (child_source));
@@ -201,7 +238,8 @@ google_backend_mail_update_auth_method (ESource *child_source,
                method = NULL;
        }
 
-       if (method)
+       if (method && (e_collection_backend_is_new_source (collection_backend, child_source) ||
+           google_backend_can_change_auth_method (auth_extension, method)))
                e_source_authentication_set_method (auth_extension, method);
 
        g_clear_object (&oauth2_support);
@@ -212,21 +250,22 @@ google_backend_mail_update_auth_method_cb (ESource *child_source,
                                           GParamSpec *param,
                                           EBackend *backend)
 {
-       google_backend_mail_update_auth_method (child_source, e_backend_get_source (backend));
+       google_backend_mail_update_auth_method (E_COLLECTION_BACKEND (backend), child_source, 
e_backend_get_source (backend));
 }
 
 static void
-google_backend_calendar_update_auth_method (ESource *child_source,
+google_backend_calendar_update_auth_method (ECollectionBackend *collection_backend,
+                                           ESource *child_source,
                                            ESource *master_source)
 {
        EOAuth2Support *oauth2_support;
        ESourceAuthentication *auth_extension;
        const gchar *method;
-       gboolean can_use_google_auth;
+       gboolean can_use_google_auth, requires_oauth2 = FALSE;
 
        auth_extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION);
 
-       if (!google_backend_is_google_host (auth_extension))
+       if (!google_backend_is_google_host (auth_extension, &requires_oauth2))
                return;
 
        oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (child_source));
@@ -245,7 +284,10 @@ google_backend_calendar_update_auth_method (ESource *child_source,
                method = "plain/password";
        }
 
-       e_source_authentication_set_method (auth_extension, method);
+       if (requires_oauth2 ||
+           e_collection_backend_is_new_source (collection_backend, child_source) ||
+           google_backend_can_change_auth_method (auth_extension, method))
+               e_source_authentication_set_method (auth_extension, method);
 
        g_clear_object (&oauth2_support);
 }
@@ -255,7 +297,7 @@ google_backend_calendar_update_auth_method_cb (ESource *child_source,
                                               GParamSpec *param,
                                               EBackend *backend)
 {
-       google_backend_calendar_update_auth_method (child_source, e_backend_get_source (backend));
+       google_backend_calendar_update_auth_method (E_COLLECTION_BACKEND (backend), child_source, 
e_backend_get_source (backend));
 }
 
 static void
@@ -269,7 +311,7 @@ google_backend_contacts_update_auth_method (ESource *child_source,
 
        extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION);
 
-       if (!google_backend_is_google_host (extension))
+       if (!google_backend_is_google_host (extension, NULL))
                return;
 
        oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (child_source));
@@ -476,7 +518,7 @@ google_backend_authenticate_sync (EBackend *backend,
        /* When the WebDAV extension is created, the auth method can be reset, thus ensure
           it's there before setting correct authentication method on the master source. */
        (void) e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-       google_backend_calendar_update_auth_method (source, NULL);
+       google_backend_calendar_update_auth_method (collection, source, NULL);
 
        if (goa_extension) {
                calendar_url = e_source_goa_get_calendar_url (goa_extension);
@@ -751,7 +793,7 @@ google_backend_child_added (ECollectionBackend *backend,
 
                if (e_source_has_extension (child_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT) ||
                    e_source_has_extension (child_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
-                       google_backend_mail_update_auth_method (child_source, collection_source);
+                       google_backend_mail_update_auth_method (backend, child_source, collection_source);
                        g_signal_connect (
                                child_source, "notify::oauth2-support",
                                G_CALLBACK (google_backend_mail_update_auth_method_cb),
@@ -780,7 +822,7 @@ google_backend_child_added (ECollectionBackend *backend,
                        g_free (today);
                }
 
-               google_backend_calendar_update_auth_method (child_source, collection_source);
+               google_backend_calendar_update_auth_method (backend, child_source, collection_source);
                g_signal_connect (
                        child_source, "notify::oauth2-support",
                        G_CALLBACK (google_backend_calendar_update_auth_method_cb),


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