[evolution-data-server] Bug 698726 - Handle goa-daemon crashes/restarts gracefully
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 698726 - Handle goa-daemon crashes/restarts gracefully
- Date: Sat, 27 Apr 2013 13:09:06 +0000 (UTC)
commit 725e976e67a62bf00820c70c47a3f439811d6c0d
Author: Matthew Barnes <mbarnes redhat com>
Date: Sat Apr 27 08:47:18 2013 -0400
Bug 698726 - Handle goa-daemon crashes/restarts gracefully
EGoaClient is an improved GoaClient that handles daemon crashes and
restarts gracefully so E-D-S accounts are not destroyed unnecessarily.
modules/gnome-online-accounts/Makefile.am | 2 +
modules/gnome-online-accounts/e-goa-client.c | 536 ++++++++++++++++++++
modules/gnome-online-accounts/e-goa-client.h | 93 ++++
.../module-gnome-online-accounts.c | 147 ++++--
4 files changed, 722 insertions(+), 56 deletions(-)
---
diff --git a/modules/gnome-online-accounts/Makefile.am b/modules/gnome-online-accounts/Makefile.am
index 547cc37..67448c3 100644
--- a/modules/gnome-online-accounts/Makefile.am
+++ b/modules/gnome-online-accounts/Makefile.am
@@ -14,6 +14,8 @@ module_gnome_online_accounts_la_CPPFLAGS = \
module_gnome_online_accounts_la_SOURCES = \
module-gnome-online-accounts.c \
+ e-goa-client.c \
+ e-goa-client.h \
e-goa-password-based.c \
e-goa-password-based.h \
goaewsclient.c \
diff --git a/modules/gnome-online-accounts/e-goa-client.c b/modules/gnome-online-accounts/e-goa-client.c
new file mode 100644
index 0000000..2575933
--- /dev/null
+++ b/modules/gnome-online-accounts/e-goa-client.c
@@ -0,0 +1,536 @@
+/*
+ * e-goa-client.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-goa-client.h"
+
+#define E_GOA_CLIENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_GOA_CLIENT, EGoaClientPrivate))
+
+struct _EGoaClientPrivate {
+ GDBusObjectManager *object_manager;
+ gulong object_added_handler_id;
+ gulong object_removed_handler_id;
+ gulong notify_name_owner_handler_id;
+
+ /* ID -> GoaObject */
+ GHashTable *orphans;
+ GMutex orphans_lock;
+};
+
+enum {
+ PROP_0,
+ PROP_OBJECT_MANAGER
+};
+
+enum {
+ ACCOUNT_ADDED,
+ ACCOUNT_REMOVED,
+ ACCOUNT_SWAPPED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+/* Forward Declarations */
+static void e_goa_client_interface_init
+ (GInitableIface *interface);
+
+/* By default, the GAsyncInitable interface calls GInitable.init()
+ * from a separate thread, so we only have to override GInitable. */
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (
+ EGoaClient,
+ e_goa_client,
+ G_TYPE_OBJECT,
+ 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (
+ G_TYPE_INITABLE,
+ e_goa_client_interface_init)
+ G_IMPLEMENT_INTERFACE_DYNAMIC (
+ G_TYPE_ASYNC_INITABLE,
+ NULL))
+
+static void
+e_goa_client_stash_orphan (EGoaClient *client,
+ GoaObject *goa_object)
+{
+ GoaAccount *goa_account;
+ const gchar *goa_account_id;
+
+ goa_account = goa_object_peek_account (goa_object);
+ g_return_if_fail (goa_account != NULL);
+
+ goa_account_id = goa_account_get_id (goa_account);
+ g_return_if_fail (goa_account_id != NULL);
+
+ g_print ("GOA: Stashing orphaned account '%s'\n", goa_account_id);
+
+ g_mutex_lock (&client->priv->orphans_lock);
+
+ g_hash_table_replace (
+ client->priv->orphans,
+ g_strdup (goa_account_id),
+ g_object_ref (goa_object));
+
+ g_mutex_unlock (&client->priv->orphans_lock);
+}
+
+static GoaObject *
+e_goa_client_claim_one_orphan (EGoaClient *client,
+ GoaObject *new_goa_object)
+{
+ GHashTable *orphans;
+ GoaAccount *goa_account;
+ GoaObject *old_goa_object;
+ const gchar *goa_account_id;
+
+ orphans = client->priv->orphans;
+
+ goa_account = goa_object_peek_account (new_goa_object);
+ g_return_val_if_fail (goa_account != NULL, NULL);
+
+ goa_account_id = goa_account_get_id (goa_account);
+ g_return_val_if_fail (goa_account_id != NULL, NULL);
+
+ g_print ("GOA: Claiming orphaned account '%s'\n", goa_account_id);
+
+ g_mutex_lock (&client->priv->orphans_lock);
+
+ old_goa_object = g_hash_table_lookup (orphans, goa_account_id);
+
+ if (old_goa_object != NULL) {
+ g_object_ref (old_goa_object);
+ g_hash_table_remove (orphans, goa_account_id);
+ }
+
+ g_mutex_unlock (&client->priv->orphans_lock);
+
+ return old_goa_object;
+}
+
+static GList *
+e_goa_client_claim_all_orphans (EGoaClient *client)
+{
+ GList *list;
+
+ g_mutex_lock (&client->priv->orphans_lock);
+
+ list = g_hash_table_get_values (client->priv->orphans);
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ g_hash_table_remove_all (client->priv->orphans);
+
+ g_mutex_unlock (&client->priv->orphans_lock);
+
+ if (list != NULL)
+ g_print ("GOA: Claiming orphaned account(s)\n");
+
+ return list;
+}
+
+static void
+e_goa_client_object_added_cb (GDBusObjectManager *manager,
+ GDBusObject *object,
+ EGoaClient *client)
+{
+ GoaObject *new_goa_object;
+ GoaObject *old_goa_object;
+
+ new_goa_object = GOA_OBJECT (object);
+
+ /* Only interested in objects with GoaAccount interfaces. */
+ if (goa_object_peek_account (new_goa_object) == NULL)
+ return;
+
+ old_goa_object =
+ e_goa_client_claim_one_orphan (client, new_goa_object);
+
+ if (old_goa_object != NULL) {
+ g_signal_emit (
+ client,
+ signals[ACCOUNT_SWAPPED], 0,
+ old_goa_object,
+ new_goa_object);
+ } else {
+ g_signal_emit (
+ client,
+ signals[ACCOUNT_ADDED], 0,
+ new_goa_object);
+ }
+
+ g_clear_object (&old_goa_object);
+}
+
+static void
+e_goa_client_object_removed_cb (GDBusObjectManager *manager,
+ GDBusObject *object,
+ EGoaClient *client)
+{
+ GoaObject *goa_object;
+ gchar *name_owner;
+
+ goa_object = GOA_OBJECT (object);
+
+ /* Only interested in objects with GoaAccount interfaces. */
+ if (goa_object_peek_account (goa_object) == NULL)
+ return;
+
+ name_owner = g_dbus_object_manager_client_get_name_owner (
+ G_DBUS_OBJECT_MANAGER_CLIENT (manager));
+
+ if (name_owner != NULL) {
+ g_signal_emit (
+ client,
+ signals[ACCOUNT_REMOVED], 0,
+ goa_object);
+ } else {
+ /* The goa-daemon went bye-bye. */
+ e_goa_client_stash_orphan (client, goa_object);
+ }
+
+ g_free (name_owner);
+}
+
+static void
+e_goa_client_notify_name_owner_cb (GDBusObjectManager *manager,
+ GParamSpec *pspec,
+ EGoaClient *client)
+{
+ gchar *name_owner;
+
+ name_owner = g_dbus_object_manager_client_get_name_owner (
+ G_DBUS_OBJECT_MANAGER_CLIENT (manager));
+
+ if (name_owner != NULL)
+ g_print ("GOA: 'org.gnome.OnlineAccounts' name appeared\n");
+ else
+ g_print ("GOA: 'org.gnome.OnlineAccounts' name vanished\n");
+
+ if (name_owner != NULL) {
+ GList *list, *link;
+
+ /* The goa-daemon (re)started. Any unclaimed accounts
+ * from the previous session were legitimately removed. */
+
+ list = e_goa_client_claim_all_orphans (client);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ g_signal_emit (
+ client,
+ signals[ACCOUNT_REMOVED], 0,
+ GOA_OBJECT (link->data));
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
+
+ g_free (name_owner);
+ }
+}
+
+static void
+e_goa_client_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_OBJECT_MANAGER:
+ g_value_take_object (
+ value,
+ e_goa_client_ref_object_manager (
+ E_GOA_CLIENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_goa_client_dispose (GObject *object)
+{
+ EGoaClientPrivate *priv;
+
+ priv = E_GOA_CLIENT_GET_PRIVATE (object);
+
+ if (priv->object_added_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->object_manager,
+ priv->object_added_handler_id);
+ priv->object_added_handler_id = 0;
+ }
+
+ if (priv->object_removed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->object_manager,
+ priv->object_removed_handler_id);
+ priv->object_removed_handler_id = 0;
+ }
+
+ if (priv->notify_name_owner_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->object_manager,
+ priv->notify_name_owner_handler_id);
+ priv->notify_name_owner_handler_id = 0;
+ }
+
+ g_clear_object (&priv->object_manager);
+
+ g_hash_table_remove_all (priv->orphans);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_goa_client_parent_class)->dispose (object);
+}
+
+static void
+e_goa_client_finalize (GObject *object)
+{
+ EGoaClientPrivate *priv;
+
+ priv = E_GOA_CLIENT_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->orphans);
+ g_mutex_clear (&priv->orphans_lock);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_goa_client_parent_class)->finalize (object);
+}
+
+static gboolean
+e_goa_client_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EGoaClientPrivate *priv;
+ gulong handler_id;
+
+ priv = E_GOA_CLIENT_GET_PRIVATE (initable);
+
+ priv->object_manager = goa_object_manager_client_new_for_bus_sync (
+ G_BUS_TYPE_SESSION,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ "org.gnome.OnlineAccounts",
+ "/org/gnome/OnlineAccounts",
+ cancellable, error);
+
+ if (priv->object_manager == NULL)
+ return FALSE;
+
+ handler_id = g_signal_connect (
+ priv->object_manager, "object-added",
+ G_CALLBACK (e_goa_client_object_added_cb),
+ E_GOA_CLIENT (initable));
+ priv->object_added_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ priv->object_manager, "object-removed",
+ G_CALLBACK (e_goa_client_object_removed_cb),
+ E_GOA_CLIENT (initable));
+ priv->object_removed_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ priv->object_manager, "notify::name-owner",
+ G_CALLBACK (e_goa_client_notify_name_owner_cb),
+ E_GOA_CLIENT (initable));
+ priv->notify_name_owner_handler_id = handler_id;
+
+ return TRUE;
+}
+
+static void
+e_goa_client_class_init (EGoaClientClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EGoaClientPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = e_goa_client_get_property;
+ object_class->dispose = e_goa_client_dispose;
+ object_class->finalize = e_goa_client_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_OBJECT_MANAGER,
+ g_param_spec_object (
+ "object-manager",
+ "Object Manager",
+ "The GDBusObjectManager used by the EGoaClient",
+ G_TYPE_DBUS_OBJECT_MANAGER,
+ G_PARAM_READABLE));
+
+ signals[ACCOUNT_ADDED] = g_signal_new (
+ "account-added",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EGoaClientClass, account_added),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ GOA_TYPE_OBJECT);
+
+ signals[ACCOUNT_REMOVED] = g_signal_new (
+ "account-removed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EGoaClientClass, account_removed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ GOA_TYPE_OBJECT);
+
+ signals[ACCOUNT_SWAPPED] = g_signal_new (
+ "account-swapped",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EGoaClientClass, account_swapped),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2,
+ GOA_TYPE_OBJECT,
+ GOA_TYPE_OBJECT);
+}
+
+static void
+e_goa_client_class_finalize (EGoaClientClass *class)
+{
+}
+
+static void
+e_goa_client_interface_init (GInitableIface *interface)
+{
+ interface->init = e_goa_client_initable_init;
+}
+
+static void
+e_goa_client_init (EGoaClient *client)
+{
+ client->priv = E_GOA_CLIENT_GET_PRIVATE (client);
+
+ client->priv->orphans = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+ g_mutex_init (&client->priv->orphans_lock);
+}
+
+void
+e_goa_client_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_goa_client_register_type (type_module);
+}
+
+void
+e_goa_client_new (GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_async_initable_new_async (
+ E_TYPE_GOA_CLIENT,
+ G_PRIORITY_DEFAULT, cancellable,
+ callback, user_data, NULL);
+}
+
+EGoaClient *
+e_goa_client_new_finish (GAsyncResult *result,
+ GError **error)
+{
+ GObject *source_object;
+ GObject *result_object;
+
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+ source_object = g_async_result_get_source_object (result);
+ g_return_val_if_fail (source_object != NULL, NULL);
+
+ result_object = g_async_initable_new_finish (
+ G_ASYNC_INITABLE (source_object), result, error);
+
+ g_object_unref (source_object);
+
+ if (result_object == NULL)
+ return NULL;
+
+ return E_GOA_CLIENT (result_object);
+}
+
+GDBusObjectManager *
+e_goa_client_ref_object_manager (EGoaClient *client)
+{
+ g_return_val_if_fail (E_IS_GOA_CLIENT (client), NULL);
+
+ return g_object_ref (client->priv->object_manager);
+}
+
+GList *
+e_goa_client_list_accounts (EGoaClient *client)
+{
+ GDBusObjectManager *object_manager;
+ GQueue queue = G_QUEUE_INIT;
+ GList *list, *link;
+
+ g_return_val_if_fail (E_IS_GOA_CLIENT (client), NULL);
+
+ object_manager = e_goa_client_ref_object_manager (client);
+ list = g_dbus_object_manager_get_objects (object_manager);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ GoaObject *goa_object = GOA_OBJECT (link->data);
+
+ if (goa_object_peek_account (goa_object) != NULL)
+ g_queue_push_tail (&queue, g_object_ref (goa_object));
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
+ g_object_unref (object_manager);
+
+ return g_queue_peek_head_link (&queue);
+}
+
+GoaObject *
+e_goa_client_lookup_by_id (EGoaClient *client,
+ const gchar *id)
+{
+ GList *list, *link;
+ GoaObject *match = NULL;
+
+ g_return_val_if_fail (E_IS_GOA_CLIENT (client), NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+
+ list = e_goa_client_list_accounts (client);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ GoaObject *goa_object = GOA_OBJECT (link->data);
+ GoaAccount *goa_account;
+ const gchar *goa_account_id;
+
+ goa_account = goa_object_peek_account (goa_object);
+ if (goa_account == NULL)
+ continue;
+
+ goa_account_id = goa_account_get_id (goa_account);
+ if (g_strcmp0 (goa_account_id, id) == 0) {
+ match = g_object_ref (goa_object);
+ break;
+ }
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
+
+ return match;
+}
+
diff --git a/modules/gnome-online-accounts/e-goa-client.h b/modules/gnome-online-accounts/e-goa-client.h
new file mode 100644
index 0000000..3ccc793
--- /dev/null
+++ b/modules/gnome-online-accounts/e-goa-client.h
@@ -0,0 +1,93 @@
+/*
+ * e-goa-client.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* This is an improved GoaClient. It handles goa-daemon crashes/restarts
+ * gracefully by emitting an "account-swapped" signal for each pair of old
+ * and new proxy objects for the same "online account" once the goa-daemon
+ * restarts. Contrast with GoaClient, which emits false "account-removed"
+ * and "account-added" signals and forces apps to distinguish them from an
+ * actual removal or addition of an "online account". */
+
+#ifndef E_GOA_CLIENT_H
+#define E_GOA_CLIENT_H
+
+/* XXX Yeah, yeah... */
+#define GOA_API_IS_SUBJECT_TO_CHANGE
+
+#include <goa/goa.h>
+
+/* Standard GObject macros */
+#define E_TYPE_GOA_CLIENT \
+ (e_goa_client_get_type ())
+#define E_GOA_CLIENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_GOA_CLIENT, EGoaClient))
+#define E_GOA_CLIENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_GOA_CLIENT, EGoaClientClass))
+#define E_IS_GOA_CLIENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_GOA_CLIENT))
+#define E_IS_GOA_CLIENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_GOA_CLIENT))
+#define E_GOA_CLIENT_CLASS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_GOA_CLIENT, EGoaClientClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EGoaClient EGoaClient;
+typedef struct _EGoaClientClass EGoaClientClass;
+typedef struct _EGoaClientPrivate EGoaClientPrivate;
+
+struct _EGoaClient {
+ GObject parent;
+ EGoaClientPrivate *priv;
+};
+
+struct _EGoaClientClass {
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*account_added) (EGoaClient *client,
+ GoaObject *object);
+ void (*account_removed) (EGoaClient *client,
+ GoaObject *object);
+ void (*account_swapped) (EGoaClient *client,
+ GoaObject *old_object,
+ GoaObject *new_object);
+};
+
+GType e_goa_client_get_type (void) G_GNUC_CONST;
+void e_goa_client_type_register (GTypeModule *type_module);
+void e_goa_client_new (GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+EGoaClient * e_goa_client_new_finish (GAsyncResult *result,
+ GError **error);
+GDBusObjectManager *
+ e_goa_client_ref_object_manager (EGoaClient *client);
+GList * e_goa_client_list_accounts (EGoaClient *client);
+GoaObject * e_goa_client_lookup_by_id (EGoaClient *client,
+ const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_GOA_CLIENT_H */
+
diff --git a/modules/gnome-online-accounts/module-gnome-online-accounts.c
b/modules/gnome-online-accounts/module-gnome-online-accounts.c
index c9ad646..66001ac 100644
--- a/modules/gnome-online-accounts/module-gnome-online-accounts.c
+++ b/modules/gnome-online-accounts/module-gnome-online-accounts.c
@@ -16,17 +16,14 @@
*
*/
-/* XXX Yeah, yeah... */
-#define GOA_API_IS_SUBJECT_TO_CHANGE
-
#include <config.h>
-#include <goa/goa.h>
#include <glib/gi18n-lib.h>
#include <libsoup/soup.h>
#include <libebackend/libebackend.h>
#include "goaewsclient.h"
+#include "e-goa-client.h"
#include "e-goa-password-based.h"
/* Standard GObject macros */
@@ -48,7 +45,11 @@ typedef struct _EGnomeOnlineAccountsClass EGnomeOnlineAccountsClass;
struct _EGnomeOnlineAccounts {
EExtension parent;
- GoaClient *goa_client;
+ EGoaClient *goa_client;
+ gulong account_added_handler_id;
+ gulong account_removed_handler_id;
+ gulong account_swapped_handler_id;
+
GCancellable *create_client;
/* GoaAccount ID -> ESource UID */
@@ -154,7 +155,6 @@ gnome_online_accounts_ref_account (EGnomeOnlineAccounts *extension,
{
ESourceRegistryServer *server;
GoaObject *match = NULL;
- GList *list, *iter;
const gchar *extension_name;
gchar *account_id = NULL;
@@ -173,35 +173,12 @@ gnome_online_accounts_ref_account (EGnomeOnlineAccounts *extension,
g_object_unref (source);
}
- if (account_id == NULL)
- return NULL;
-
- /* FIXME Use goa_client_lookup_by_id() once we require GOA 3.6. */
-
- list = goa_client_get_accounts (extension->goa_client);
-
- for (iter = list; iter != NULL; iter = g_list_next (iter)) {
- GoaObject *goa_object;
- GoaAccount *goa_account;
- const gchar *candidate_id;
-
- goa_object = GOA_OBJECT (iter->data);
- goa_account = goa_object_get_account (goa_object);
- candidate_id = goa_account_get_id (goa_account);
-
- if (g_strcmp0 (account_id, candidate_id) == 0)
- match = g_object_ref (goa_object);
-
- g_object_unref (goa_account);
-
- if (match != NULL)
- break;
+ if (account_id != NULL) {
+ match = e_goa_client_lookup_by_id (
+ extension->goa_client, account_id);
+ g_free (account_id);
}
- g_list_free_full (list, (GDestroyNotify) g_object_unref);
-
- g_free (account_id);
-
return match;
}
@@ -905,7 +882,7 @@ gnome_online_accounts_remove_collection (EGnomeOnlineAccounts *extension,
}
static void
-gnome_online_accounts_account_added_cb (GoaClient *goa_client,
+gnome_online_accounts_account_added_cb (EGoaClient *goa_client,
GoaObject *goa_object,
EGnomeOnlineAccounts *extension)
{
@@ -940,7 +917,7 @@ gnome_online_accounts_account_added_cb (GoaClient *goa_client,
}
static void
-gnome_online_accounts_account_removed_cb (GoaClient *goa_client,
+gnome_online_accounts_account_removed_cb (EGoaClient *goa_client,
GoaObject *goa_object,
EGnomeOnlineAccounts *extension)
{
@@ -969,6 +946,42 @@ gnome_online_accounts_account_removed_cb (GoaClient *goa_client,
g_object_unref (goa_account);
}
+static void
+gnome_online_accounts_account_swapped_cb (EGoaClient *goa_client,
+ GoaObject *old_goa_object,
+ GoaObject *new_goa_object,
+ EGnomeOnlineAccounts *extension)
+{
+ ESource *source = NULL;
+ ESourceRegistryServer *server;
+ GoaAccount *goa_account;
+ const gchar *account_id;
+ const gchar *source_uid;
+
+ /* The old GoaObject is about to be destroyed so we should
+ * not need to bother with undoing property bindings on it.
+ * Just set up new property bindings on the new GoaObject. */
+
+ server = gnome_online_accounts_get_server (extension);
+
+ goa_account = goa_object_get_account (new_goa_object);
+
+ account_id = goa_account_get_id (goa_account);
+ source_uid = g_hash_table_lookup (extension->goa_to_eds, account_id);
+
+ if (source_uid != NULL)
+ source = e_source_registry_server_ref_source (
+ server, source_uid);
+
+ if (source != NULL) {
+ gnome_online_accounts_config_sources (
+ extension, source, new_goa_object);
+ g_object_unref (source);
+ }
+
+ g_object_unref (goa_account);
+}
+
static gint
gnome_online_accounts_compare_id (GoaObject *goa_object,
const gchar *target_id)
@@ -1055,15 +1068,16 @@ gnome_online_accounts_create_client_cb (GObject *source_object,
gpointer user_data)
{
EGnomeOnlineAccounts *extension;
- GoaClient *goa_client;
+ EGoaClient *goa_client;
GList *list, *link;
+ gulong handler_id;
GError *error = NULL;
/* If we get back a G_IO_ERROR_CANCELLED then it means the
* EGnomeOnlineAccounts is already finalized, so be careful
- * not to touch it until after we have a valid GoaClient. */
+ * not to touch it until after we have a valid EGoaClient. */
- goa_client = goa_client_new_finish (result, &error);
+ goa_client = e_goa_client_new_finish (result, &error);
if (error != NULL) {
g_warn_if_fail (goa_client == NULL);
@@ -1074,7 +1088,7 @@ gnome_online_accounts_create_client_cb (GObject *source_object,
return;
}
- g_return_if_fail (GOA_IS_CLIENT (goa_client));
+ g_return_if_fail (E_IS_GOA_CLIENT (goa_client));
/* Should be safe to dereference the EGnomeOnlineAccounts now. */
@@ -1085,7 +1099,7 @@ gnome_online_accounts_create_client_cb (GObject *source_object,
g_object_unref (extension->create_client);
extension->create_client = NULL;
- list = goa_client_get_accounts (extension->goa_client);
+ list = e_goa_client_list_accounts (extension->goa_client);
/* This populates a hash table of GOA ID -> ESource UID strings by
* searching through available data sources for ones with a "GNOME
@@ -1104,14 +1118,23 @@ gnome_online_accounts_create_client_cb (GObject *source_object,
g_list_free_full (list, (GDestroyNotify) g_object_unref);
/* Listen for Online Account changes. */
- g_signal_connect (
+
+ handler_id = g_signal_connect (
extension->goa_client, "account-added",
G_CALLBACK (gnome_online_accounts_account_added_cb),
extension);
- g_signal_connect (
+ extension->account_added_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
extension->goa_client, "account-removed",
G_CALLBACK (gnome_online_accounts_account_removed_cb),
extension);
+ extension->account_removed_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ extension->goa_client, "account-swapped",
+ G_CALLBACK (gnome_online_accounts_account_swapped_cb),
+ extension);
}
static void
@@ -1124,7 +1147,7 @@ gnome_online_accounts_bus_acquired_cb (EDBusServer *server,
/* Note we don't reference the extension. If the
* extension gets destroyed before this completes
* we cancel the operation from dispose(). */
- goa_client_new (
+ e_goa_client_new (
extension->create_client,
gnome_online_accounts_create_client_cb,
extension);
@@ -1137,23 +1160,34 @@ gnome_online_accounts_dispose (GObject *object)
extension = E_GNOME_ONLINE_ACCOUNTS (object);
- if (extension->goa_client != NULL) {
- g_signal_handlers_disconnect_matched (
+ if (extension->account_added_handler_id > 0) {
+ g_signal_handler_disconnect (
extension->goa_client,
- G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL, object);
- g_object_unref (extension->goa_client);
- extension->goa_client = NULL;
+ extension->account_added_handler_id);
+ extension->account_added_handler_id = 0;
}
- /* This cancels goa_client_new() in case it still
- * hasn't completed. We're no longer interested. */
- if (extension->create_client != NULL) {
- g_cancellable_cancel (extension->create_client);
- g_object_unref (extension->create_client);
- extension->create_client = NULL;
+ if (extension->account_removed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ extension->goa_client,
+ extension->account_removed_handler_id);
+ extension->account_removed_handler_id = 0;
}
+ if (extension->account_swapped_handler_id > 0) {
+ g_signal_handler_disconnect (
+ extension->goa_client,
+ extension->account_swapped_handler_id);
+ extension->account_swapped_handler_id = 0;
+ }
+
+ /* This cancels e_goa_client_new() in case it still
+ * hasn't completed. We're no longer interested. */
+ g_cancellable_cancel (extension->create_client);
+
+ g_clear_object (&extension->goa_client);
+ g_clear_object (&extension->create_client);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_gnome_online_accounts_parent_class)->
dispose (object);
@@ -1277,7 +1311,7 @@ e_gnome_online_accounts_oauth2_support_init (EOAuth2SupportInterface *interface)
static void
e_gnome_online_accounts_init (EGnomeOnlineAccounts *extension)
{
- /* Used to cancel unfinished goa_client_new(). */
+ /* Used to cancel unfinished e_goa_client_new(). */
extension->create_client = g_cancellable_new ();
extension->goa_to_eds = g_hash_table_new_full (
@@ -1290,6 +1324,7 @@ e_gnome_online_accounts_init (EGnomeOnlineAccounts *extension)
G_MODULE_EXPORT void
e_module_load (GTypeModule *type_module)
{
+ e_goa_client_type_register (type_module);
e_goa_password_based_type_register (type_module);
e_gnome_online_accounts_register_type (type_module);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]