[evolution-data-server/f19] Add patch for Red Hat bug #956908 (GOA accounts forgotten on GOA crash)
Milan Crha
mcrha at fedoraproject.org
Thu May 2 08:42:03 UTC 2013
commit be1d08418382034b6a42f85a5c9535bbe5367c8c
Author: Milan Crha <mcrha at redhat.com>
Date: Thu May 2 10:41:49 2013 +0200
Add patch for Red Hat bug #956908 (GOA accounts forgotten on GOA crash)
evolution-data-server-3.8.1-goa-crash.patch | 983 +++++++++++++++++++++++++++
evolution-data-server.spec | 9 +-
2 files changed, 991 insertions(+), 1 deletions(-)
---
diff --git a/evolution-data-server-3.8.1-goa-crash.patch b/evolution-data-server-3.8.1-goa-crash.patch
new file mode 100644
index 0000000..25dbebc
--- /dev/null
+++ b/evolution-data-server-3.8.1-goa-crash.patch
@@ -0,0 +1,983 @@
+From 0e87aafea9a370b6f27ea720729dadb572b03d72 Mon Sep 17 00:00:00 2001
+From: Matthew Barnes <mbarnes at redhat.com>
+Date: Sat, 27 Apr 2013 12:47:18 +0000
+Subject: 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.
+
+(cherry picked from commit 725e976e67a62bf00820c70c47a3f439811d6c0d)
+---
+diff --git a/modules/gnome-online-accounts/Makefile.am b/modules/gnome-online-accounts/Makefile.am
+index 4be1ffa..6b2b129 100644
+--- a/modules/gnome-online-accounts/Makefile.am
++++ b/modules/gnome-online-accounts/Makefile.am
+@@ -19,6 +19,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 e6907f4..1143f67 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;
+ }
+
+@@ -925,7 +902,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)
+ {
+@@ -960,7 +937,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)
+ {
+@@ -989,6 +966,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)
+@@ -1075,15 +1088,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);
+@@ -1094,7 +1108,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. */
+
+@@ -1105,7 +1119,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
+@@ -1124,14 +1138,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
+@@ -1144,7 +1167,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);
+@@ -1157,23 +1180,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);
+@@ -1297,7 +1331,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 (
+@@ -1310,6 +1344,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);
+ }
+diff --git a/modules/gnome-online-accounts/e-goa-client.c b/modules/gnome-online-accounts/e-goa-client.c
+index 2575933..093ce07 100644
+--- a/modules/gnome-online-accounts/e-goa-client.c
++++ b/modules/gnome-online-accounts/e-goa-client.c
+@@ -48,8 +48,7 @@ enum {
+ static guint signals[LAST_SIGNAL];
+
+ /* Forward Declarations */
+-static void e_goa_client_interface_init
+- (GInitableIface *interface);
++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. */
+@@ -107,8 +106,6 @@ e_goa_client_claim_one_orphan (EGoaClient *client,
+ 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);
+@@ -120,6 +117,11 @@ e_goa_client_claim_one_orphan (EGoaClient *client,
+
+ g_mutex_unlock (&client->priv->orphans_lock);
+
++ if (old_goa_object != NULL)
++ g_print (
++ "GOA: Claiming orphaned account '%s'\n",
++ goa_account_id);
++
+ return old_goa_object;
+ }
+
+--
+cgit v0.9.1
diff --git a/evolution-data-server.spec b/evolution-data-server.spec
index ee8c195..7148e90 100644
--- a/evolution-data-server.spec
+++ b/evolution-data-server.spec
@@ -27,7 +27,7 @@
Name: evolution-data-server
Version: 3.8.1
-Release: 1%{?dist}
+Release: 2%{?dist}
Group: System Environment/Libraries
Summary: Backend data server for Evolution
License: LGPLv2+
@@ -43,6 +43,9 @@ Obsoletes: evolution-webcal < 2.24.0
# RH bug #243296
Patch01: evolution-data-server-1.11.5-fix-64bit-acinclude.patch
+# RH bug #956908
+Patch02: evolution-data-server-3.8.1-goa-crash.patch
+
### Build Dependencies ###
BuildRequires: libdb-devel
@@ -118,6 +121,7 @@ This package contains developer documentation for %{name}.
%setup -q
%patch01 -p1 -b .fix-64bit-acinclude
+%patch02 -p1 -b .goa-crash
mkdir -p krb5-fakeprefix/include
mkdir -p krb5-fakeprefix/lib
@@ -366,6 +370,9 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &>/dev/null || :
%{_datadir}/gtk-doc/html/libedataserver
%changelog
+* Thu May 02 2013 Milan Crha <mcrha at redhat.com> - 3.8.1-2
+- Add patch for Red Hat bug #956908 (GOA accounts forgotten on GOA crash)
+
* Sun Apr 14 2013 Matthew Barnes <mbarnes at redhat.com> - 3.8.1-1
- Update to 3.8.1
- Remove stuck message retrieval patch (fixed upstream).
More information about the scm-commits
mailing list