Blob Blame History Raw
From 6bb9425ba858b2e0ecb128af88e263e887efda0b Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 14:21:07 +0200
Subject: [PATCH 01/22] provider: Export ensure_builtins_loaded as internal API

... because we want to use it inside GoaDaemon also.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goabackend/goaprovider-priv.h |  2 ++
 src/goabackend/goaprovider.c      | 12 ++++++------
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/goabackend/goaprovider-priv.h b/src/goabackend/goaprovider-priv.h
index 540da2eee4a7..dfede1b2bb97 100644
--- a/src/goabackend/goaprovider-priv.h
+++ b/src/goabackend/goaprovider-priv.h
@@ -119,6 +119,8 @@ struct _GoaProviderClass
  */
 #define GOA_PROVIDER_FACTORY_EXTENSION_POINT_NAME "goa-backend-provider-factory"
 
+void goa_provider_ensure_builtins_loaded             (void);
+
 void goa_provider_ensure_extension_points_registered (void);
 
 G_END_DECLS
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index eb221196eddc..e6cac23d6adc 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -802,8 +802,8 @@ static struct
   { NULL, NULL }
 };
 
-static void
-ensure_builtins_loaded (void)
+void
+goa_provider_ensure_builtins_loaded (void)
 {
   static gsize once_init_value = 0;
 
@@ -892,7 +892,7 @@ goa_provider_get_for_provider_type (const gchar *provider_type)
 
   g_return_val_if_fail (provider_type != NULL, NULL);
 
-  ensure_builtins_loaded ();
+  goa_provider_ensure_builtins_loaded ();
 
   ret = NULL;
 
@@ -1048,7 +1048,7 @@ goa_provider_get_all (GAsyncReadyCallback callback,
   GetAllData *data;
   gint i;
 
-  ensure_builtins_loaded ();
+  goa_provider_ensure_builtins_loaded ();
 
   data = g_slice_new0 (GetAllData);
   data->result = g_simple_async_result_new (NULL, callback, user_data,
@@ -1063,8 +1063,8 @@ goa_provider_get_all (GAsyncReadyCallback callback,
     {
       GIOExtension *extension = l->data;
       /* The extensions are loaded in the reverse order we used in
-       * ensure_builtins_loaded, so we need to push extension if front of
-       * the already loaded ones. */
+       * goa_provider_ensure_builtins_loaded, so we need to push
+       * extension if front of the already loaded ones. */
       g_queue_push_head (&data->ret, g_object_new (g_io_extension_get_type (extension), NULL));
     }
 
-- 
2.5.5


From fed8f107d2d864596554f79137f78945bb0d8ade Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 14:55:40 +0200
Subject: [PATCH 02/22] daemon: Abstract the way we initialize the Kerberos
 provider

The Kerberos backend needs to perform some class-wide (ie. not
instance-specific) initialization when goa-daemon starts. This code is
embedded into the class' type registration code.

There is no reason to call out to the Kerberos provider explicitly by
creating a dummy instance. The provider class will perform all
necessary initialization at the time of extension registration. Merely
ensuring the extensions are registered is better because it makes the
backend implementation details more opaque.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/daemon/goadaemon.c               | 27 +++------------------------
 src/goabackend/goakerberosprovider.c |  1 +
 2 files changed, 4 insertions(+), 24 deletions(-)

diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index 213f154c12aa..05ccb04c9ba5 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -24,6 +24,7 @@
 
 #include "goadaemon.h"
 #include "goabackend/goabackend.h"
+#include "goabackend/goaprovider-priv.h"
 #include "goabackend/goautils.h"
 
 struct _GoaDaemon
@@ -200,26 +201,6 @@ on_network_monitor_network_changed (GoaDaemon *self, gboolean available)
   queue_check_credentials (self);
 }
 
-#ifdef GOA_KERBEROS_ENABLED
-static void
-activate_identity_service (GoaDaemon *self)
-{
-  GoaProvider *provider;
-
-  /* We activate the identity service implicitly by using the kerberos
-   * backend.  This way if the kerberos backend isn't enabled, we don't
-   * end up starting the identity service needlessly
-   */
-  provider = goa_provider_get_for_provider_type (GOA_KERBEROS_NAME);
-
-  if (provider != NULL)
-    {
-      g_debug ("activated kerberos provider");
-      g_object_unref (provider);
-    }
-}
-#endif
-
 static void
 goa_daemon_init (GoaDaemon *self)
 {
@@ -233,6 +214,8 @@ goa_daemon_init (GoaDaemon *self)
   goa_error_domain = GOA_ERROR;
   goa_error_domain; /* shut up -Wunused-but-set-variable */
 
+  goa_provider_ensure_builtins_loaded ();
+
   /* TODO: maybe nicer to pass in a GDBusConnection* construct property */
   self->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
 
@@ -279,10 +262,6 @@ goa_daemon_init (GoaDaemon *self)
   g_dbus_object_manager_server_set_connection (self->object_manager, self->connection);
 
   queue_check_credentials (self);
-
-#ifdef GOA_KERBEROS_ENABLED
-  activate_identity_service (self);
-#endif
 }
 
 static void
diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c
index a3a9bd9f5369..9d6ddd65f995 100644
--- a/src/goabackend/goakerberosprovider.c
+++ b/src/goabackend/goakerberosprovider.c
@@ -100,6 +100,7 @@ goa_kerberos_provider_module_init (void)
 {
   create_object_manager ();
   create_identity_manager ();
+  g_debug ("activated kerberos provider");
 }
 
 static const gchar *
-- 
2.5.5


From de14a8ff62c34c4b2e77d29705ba373442031c4e Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 16:25:44 +0200
Subject: [PATCH 03/22] identity: Minor clean up

There is no need to keep the GoaManager pointer as an instance
variable. We can just get it when adding the account. There are too
many manager-like variables flying around. This makes the code more
readable by keeping one of them closely tied to its context.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goaidentity/goaidentityservice.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c
index bb5d3a7dbe25..2eda31d56e74 100644
--- a/src/goaidentity/goaidentityservice.c
+++ b/src/goaidentity/goaidentityservice.c
@@ -51,7 +51,6 @@ struct _GoaIdentityServicePrivate
    * is in process, we should able to use direct calls.
    */
   GoaClient                *client;
-  GoaManager               *accounts_manager;
 };
 
 static void identity_service_manager_interface_init (GoaIdentityServiceManagerIface *interface);
@@ -883,6 +882,7 @@ add_temporary_account (GoaIdentityService *self,
   GSimpleAsyncResult *operation_result;
   GVariantBuilder     credentials;
   GVariantBuilder     details;
+  GoaManager         *manager;
   GoaObject *object;
 
   principal = goa_identity_get_identifier (identity);
@@ -927,7 +927,8 @@ add_temporary_account (GoaIdentityService *self,
                        g_strdup (principal),
                        g_object_ref (operation_result));
 
-  goa_manager_call_add_account (self->priv->accounts_manager,
+  manager = goa_client_get_manager (self->priv->client);
+  goa_manager_call_add_account (manager,
                                 "kerberos",
                                 principal,
                                 principal_for_display,
@@ -1700,8 +1701,6 @@ on_got_client (GoaClient          *client,
       goto out;
     }
 
-  self->priv->accounts_manager = goa_client_get_manager (client);
-
   self->priv->identity_manager = goa_kerberos_identity_manager_new (NULL, &error);
 
   if (self->priv->identity_manager == NULL)
-- 
2.5.5


From 860b8aee47db9e3558d78d69a17fe154e8e5145a Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 3 Jun 2016 17:36:42 +0200
Subject: [PATCH 04/22] telepathy: Simplify the code by re-using the existing
 GoaClient

https://bugzilla.gnome.org/show_bug.cgi?id=767299
---
 src/goabackend/goatelepathyprovider.c | 33 +++++----------------------------
 1 file changed, 5 insertions(+), 28 deletions(-)

diff --git a/src/goabackend/goatelepathyprovider.c b/src/goabackend/goatelepathyprovider.c
index a388b8a4e090..cb3c8dd02de6 100644
--- a/src/goabackend/goatelepathyprovider.c
+++ b/src/goabackend/goatelepathyprovider.c
@@ -326,7 +326,7 @@ check_existing_goa_accounts (AddAccountData *data)
   GList *l = NULL;
   gboolean found = FALSE;
 
-  if (data->tp_account == NULL || data->goa_client == NULL)
+  if (data->tp_account == NULL)
     return FALSE;
 
   goa_accounts = goa_client_get_accounts (data->goa_client);
@@ -365,31 +365,6 @@ goa_account_added_cb (GoaClient *client,
 }
 
 static void
-goa_client_new_cb (GObject      *object,
-                   GAsyncResult *result,
-                   gpointer      user_data)
-{
-  AddAccountData *data = user_data;
-
-  data->goa_client = goa_client_new_finish (result, &data->error);
-  if (data->goa_client == NULL)
-    {
-      g_set_error (&data->error,
-                   GOA_ERROR,
-                   GOA_ERROR_FAILED,
-                   _("Failed to initialize a GOA client"));
-      g_main_loop_quit (data->loop);
-      return;
-    }
-
-  if (!check_existing_goa_accounts (data))
-    {
-      data->goa_account_added_id = g_signal_connect (data->goa_client,
-          "account-added", G_CALLBACK (goa_account_added_cb), data);
-    }
-}
-
-static void
 account_widget_close_cb (TpawAccountWidget *widget,
                          GtkResponseType    response,
                          AddAccountData    *data)
@@ -432,7 +407,10 @@ add_account (GoaProvider  *provider,
   data.dialog = dialog;
   data.vbox = vbox;
 
-  goa_client_new (data.cancellable, goa_client_new_cb, &data);
+  data.goa_client = client;
+  data.goa_account_added_id = g_signal_connect (data.goa_client,
+      "account-added", G_CALLBACK (goa_account_added_cb), &data);
+
   wait_for_account_settings_ready (settings, data.loop);
 
   account_widget = tpaw_account_widget_new_for_protocol (settings,
@@ -488,7 +466,6 @@ out:
     g_signal_handler_disconnect (data.goa_client, data.goa_account_added_id);
 
   g_clear_pointer (&data.loop, g_main_loop_unref);
-  g_clear_object (&data.goa_client);
   g_clear_object (&data.tp_account);
 
   return data.ret;
-- 
2.5.5


From 31b1d426a4be084d433ddbf7c7b6fd3c47083ec4 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 3 Jun 2016 19:44:45 +0200
Subject: [PATCH 05/22] telepathy: Remove the unused GCancellable

https://bugzilla.gnome.org/show_bug.cgi?id=767299
---
 src/goabackend/goatelepathyprovider.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/src/goabackend/goatelepathyprovider.c b/src/goabackend/goatelepathyprovider.c
index cb3c8dd02de6..ff509cc501fe 100644
--- a/src/goabackend/goatelepathyprovider.c
+++ b/src/goabackend/goatelepathyprovider.c
@@ -269,7 +269,6 @@ get_provider_features (GoaProvider *provider)
 typedef struct
 {
   GMainLoop *loop;
-  GCancellable *cancellable;
   GoaObject *ret;
   GError *error;
 
@@ -400,7 +399,6 @@ add_account (GoaProvider  *provider,
     }
 
   memset (&data, 0, sizeof (AddAccountData));
-  data.cancellable = g_cancellable_new ();
   data.loop = g_main_loop_new (NULL, FALSE);
   data.error = NULL;
   data.provider = GOA_TELEPATHY_PROVIDER (provider);
@@ -444,7 +442,7 @@ add_account (GoaProvider  *provider,
       goto out;
     }
 
-  if (data.ret == NULL && !g_cancellable_is_cancelled (data.cancellable))
+  if (data.ret == NULL)
     {
       /* We wait for the account to be created */
       g_main_loop_run (data.loop);
@@ -456,12 +454,6 @@ out:
   else
     g_assert (data.ret != NULL);
 
-  if (data.cancellable != NULL)
-    {
-      g_cancellable_cancel (data.cancellable);
-      g_object_unref (data.cancellable);
-    }
-
   if (data.goa_account_added_id)
     g_signal_handler_disconnect (data.goa_client, data.goa_account_added_id);
 
-- 
2.5.5


From 723ba9e231f2799bc0e15339585640b64fab36bd Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 3 Jun 2016 20:56:36 +0200
Subject: [PATCH 06/22] telepathy: Fix a race between TpawAccountWidget and
 GoaTpAccountLinker

If TpawAccountWidget is used with a GtkDialog, the job completion
semantics are as follows:

 GtkDialog::response is emitted when the user clicks the Add button.
 However, at this point the operation has just begun - the TpAccount
 hasn't even been created. Once it is ready, TpawAccountWidget::close
 (and a second GtkDialog::response) will be emitted.

Apart from this, we need to track whether the corresponding GoaObject
has been created by GoaTpAccountLinker.

We were quitting our hand rolled GMainLoop immediately after the
TpAccount / GoaObject pair were created without having anything to
wait for the TpawAccountWidget::close emission. This is wrong because
TpawAccountWidget does some follow-up work on the TpAccount after its
creation. Therefore, we were terminating add_account while some
asynchronous TpawAccountWidget operations could still be running.

(Even though TpawAccountWidget holds a reference to itself during an
asynchronous operation, the destruction of the GtkDialog leads to
the widget being disposed.)

Therefore, we track both the TpawAccountWidget::close emission and the
GoaObject creation. We quit the GMainLoop only after both events have
occured.

https://bugzilla.gnome.org/show_bug.cgi?id=767299
---
 src/goabackend/goatelepathyprovider.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/src/goabackend/goatelepathyprovider.c b/src/goabackend/goatelepathyprovider.c
index ff509cc501fe..7873607c1382 100644
--- a/src/goabackend/goatelepathyprovider.c
+++ b/src/goabackend/goatelepathyprovider.c
@@ -275,6 +275,7 @@ typedef struct
   GoaTelepathyProvider *provider;
   GtkDialog *dialog;
   GtkBox *vbox;
+  gboolean close_received;
 
   TpAccount *tp_account;
 
@@ -282,6 +283,20 @@ typedef struct
   guint goa_account_added_id;
 } AddAccountData;
 
+static void
+quit_main_loop_if_finished (AddAccountData *data)
+{
+  if (data->ret != NULL && data->close_received)
+    g_main_loop_quit (data->loop);
+}
+
+static void
+run_main_loop_if_needed (AddAccountData *data)
+{
+  if (data->ret == NULL || !data->close_received)
+    g_main_loop_run (data->loop);
+}
+
 static gboolean
 check_goa_object_match (AddAccountData *data,
                         GoaObject      *goa_object)
@@ -311,7 +326,7 @@ check_goa_object_match (AddAccountData *data,
     {
       /* Found it! */
       data->ret = g_object_ref (goa_object);
-      g_main_loop_quit (data->loop);
+      quit_main_loop_if_finished (data);
       return TRUE;
     }
 
@@ -368,7 +383,8 @@ account_widget_close_cb (TpawAccountWidget *widget,
                          GtkResponseType    response,
                          AddAccountData    *data)
 {
-  gtk_dialog_response (data->dialog, response);
+  data->close_received = TRUE;
+  quit_main_loop_if_finished (data);
 }
 
 static GoaObject *
@@ -442,11 +458,8 @@ add_account (GoaProvider  *provider,
       goto out;
     }
 
-  if (data.ret == NULL)
-    {
-      /* We wait for the account to be created */
-      g_main_loop_run (data.loop);
-    }
+  /* We wait for the account to be created */
+  run_main_loop_if_needed (&data);
 
 out:
   if (data.error != NULL)
-- 
2.5.5


From 3ed23bf6d26799486bf28749b2505c5b8d27a442 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 19:50:08 +0200
Subject: [PATCH 07/22] daemon: Style fix

---
 src/daemon/goadaemon.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index 05ccb04c9ba5..c12030f2bbc2 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -778,6 +778,8 @@ goa_daemon_reload_configuration (GoaDaemon *self)
   g_list_free_full (key_files_to_free, (GDestroyNotify) g_key_file_free);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gchar *
 generate_new_id (GoaDaemon *self)
 {
-- 
2.5.5


From 8f57271140a7f7ee83b17bb88a4c0dd6fb70b214 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Mon, 11 May 2015 17:30:41 +0200
Subject: [PATCH 08/22] provider: Use the name 'self' to refer to the instance

---
 src/goabackend/goaprovider-priv.h |  24 +++---
 src/goabackend/goaprovider.c      | 174 +++++++++++++++++++-------------------
 src/goabackend/goaprovider.h      |  32 +++----
 3 files changed, 115 insertions(+), 115 deletions(-)

diff --git a/src/goabackend/goaprovider-priv.h b/src/goabackend/goaprovider-priv.h
index dfede1b2bb97..bd110f8562a2 100644
--- a/src/goabackend/goaprovider-priv.h
+++ b/src/goabackend/goaprovider-priv.h
@@ -1,6 +1,6 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /*
- * Copyright (C) 2013, 2014 Red Hat, Inc.
+ * Copyright (C) 2013, 2014, 2015 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -60,28 +60,28 @@ struct _GoaProviderClass
   GObjectClass parent_class;
 
   /* pure virtual */
-  const gchar *(*get_provider_type) (GoaProvider        *provider);
-  gchar       *(*get_provider_name) (GoaProvider        *provider,
+  const gchar *(*get_provider_type) (GoaProvider        *self);
+  gchar       *(*get_provider_name) (GoaProvider        *self,
                                      GoaObject          *object);
-  GIcon       *(*get_provider_icon) (GoaProvider        *provider,
+  GIcon       *(*get_provider_icon) (GoaProvider        *self,
                                      GoaObject          *object);
-  GoaObject   *(*add_account)       (GoaProvider        *provider,
+  GoaObject   *(*add_account)       (GoaProvider        *self,
                                      GoaClient          *client,
                                      GtkDialog          *dialog,
                                      GtkBox             *vbox,
                                      GError            **error);
-  gboolean     (*refresh_account)   (GoaProvider        *provider,
+  gboolean     (*refresh_account)   (GoaProvider        *self,
                                      GoaClient          *client,
                                      GoaObject          *object,
                                      GtkWindow          *parent,
                                      GError            **error);
-  void         (*show_account)      (GoaProvider         *provider,
+  void         (*show_account)      (GoaProvider         *self,
                                      GoaClient           *client,
                                      GoaObject           *object,
                                      GtkBox              *vbox,
                                      GtkGrid             *grid,
                                      GtkGrid             *dummy);
-  gboolean     (*build_object)      (GoaProvider        *provider,
+  gboolean     (*build_object)      (GoaProvider        *self,
                                      GoaObjectSkeleton  *object,
                                      GKeyFile           *key_file,
                                      const gchar        *group,
@@ -89,16 +89,16 @@ struct _GoaProviderClass
                                      gboolean            just_added,
                                      GError            **error);
   /* virtual but with default implementation */
-  gboolean (*ensure_credentials_sync) (GoaProvider         *provider,
+  gboolean (*ensure_credentials_sync) (GoaProvider         *self,
                                        GoaObject           *object,
                                        gint                *out_expires_in,
                                        GCancellable        *cancellable,
                                        GError             **error);
-  guint    (*get_credentials_generation) (GoaProvider   *provider);
+  guint    (*get_credentials_generation) (GoaProvider   *self);
 
   /* pure virtual */
-  GoaProviderGroup (*get_provider_group) (GoaProvider   *provider);
-  GoaProviderFeatures  (*get_provider_features)     (GoaProvider   *provider);
+  GoaProviderGroup (*get_provider_group) (GoaProvider   *self);
+  GoaProviderFeatures  (*get_provider_features)     (GoaProvider   *self);
 
   /*< private >*/
   /* Padding for future expansion */
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index e6cac23d6adc..d0825a26f291 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -1,6 +1,6 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /*
- * Copyright (C) 2011, 2012, 2013, 2014 Red Hat, Inc.
+ * Copyright (C) 2011, 2012, 2013, 2014, 2015 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -62,13 +62,13 @@ enum {
 
 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
 
-static gboolean goa_provider_ensure_credentials_sync_real (GoaProvider   *provider,
+static gboolean goa_provider_ensure_credentials_sync_real (GoaProvider   *self,
                                                            GoaObject     *object,
                                                            gint          *out_expires_in,
                                                            GCancellable  *cancellable,
                                                            GError       **error);
 
-static gboolean goa_provider_build_object_real (GoaProvider         *provider,
+static gboolean goa_provider_build_object_real (GoaProvider         *self,
                                                 GoaObjectSkeleton   *object,
                                                 GKeyFile            *key_file,
                                                 const gchar         *group,
@@ -76,9 +76,9 @@ static gboolean goa_provider_build_object_real (GoaProvider         *provider,
                                                 gboolean             just_added,
                                                 GError             **error);
 
-static guint goa_provider_get_credentials_generation_real (GoaProvider *provider);
+static guint goa_provider_get_credentials_generation_real (GoaProvider *self);
 
-static GIcon *goa_provider_get_provider_icon_default (GoaProvider *provider,
+static GIcon *goa_provider_get_provider_icon_default (GoaProvider *self,
                                                       GoaObject   *object);
 
 #define GOA_PROVIDER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOA_TYPE_PROVIDER, GoaProviderPrivate))
@@ -124,17 +124,17 @@ goa_provider_set_property (GObject *object,
 static void
 goa_provider_dispose (GObject *object)
 {
-  GoaProvider *provider = GOA_PROVIDER (object);
+  GoaProvider *self = GOA_PROVIDER (object);
 
-  g_clear_pointer (&provider->priv->preseed_data, g_variant_unref);
+  g_clear_pointer (&self->priv->preseed_data, g_variant_unref);
 
   G_OBJECT_CLASS (goa_provider_parent_class)->dispose (object);
 }
 
 static void
-goa_provider_init (GoaProvider *provider)
+goa_provider_init (GoaProvider *self)
 {
-  provider->priv = GOA_PROVIDER_GET_PRIVATE (provider);
+  self->priv = GOA_PROVIDER_GET_PRIVATE (self);
 }
 
 static void
@@ -198,28 +198,28 @@ goa_provider_class_init (GoaProviderClass *klass)
 
 /**
  * goa_provider_get_provider_type:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  *
- * Gets the type of @provider.
+ * Gets the type of @self.
  *
  * This is a pure virtual method - a subclass must provide an
  * implementation.
  *
- * Returns: (transfer none): A string owned by @provider, do not free.
+ * Returns: (transfer none): A string owned by @self, do not free.
  */
 const gchar *
-goa_provider_get_provider_type (GoaProvider *provider)
+goa_provider_get_provider_type (GoaProvider *self)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), NULL);
-  return GOA_PROVIDER_GET_CLASS (provider)->get_provider_type (provider);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), NULL);
+  return GOA_PROVIDER_GET_CLASS (self)->get_provider_type (self);
 }
 
 /**
  * goa_provider_get_provider_name:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @object: (allow-none): A #GoaObject for an account.
  *
- * Gets a name for @provider and @object that is suitable for display
+ * Gets a name for @self and @object that is suitable for display
  * in an user interface. The returned value may depend on @object (if
  * it's not %NULL) - for example, hosted accounts might return a
  * different name.
@@ -230,19 +230,19 @@ goa_provider_get_provider_type (GoaProvider *provider)
  * Returns: (transfer full): A string that should be freed with g_free().
  */
 gchar *
-goa_provider_get_provider_name (GoaProvider *provider,
+goa_provider_get_provider_name (GoaProvider *self,
                                 GoaObject   *object)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), NULL);
-  return GOA_PROVIDER_GET_CLASS (provider)->get_provider_name (provider, object);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), NULL);
+  return GOA_PROVIDER_GET_CLASS (self)->get_provider_name (self, object);
 }
 
 /**
  * goa_provider_get_provider_icon:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @object: A #GoaObject for an account.
  *
- * Gets an icon for @provider and @object that is suitable for display
+ * Gets an icon for @self and @object that is suitable for display
  * in an user interface. The returned value may depend on @object -
  * for example, hosted accounts might return a different icon.
  *
@@ -254,20 +254,20 @@ goa_provider_get_provider_name (GoaProvider *provider,
  * Returns: (transfer full): An icon that should be freed with g_object_unref().
  */
 GIcon *
-goa_provider_get_provider_icon (GoaProvider *provider,
+goa_provider_get_provider_icon (GoaProvider *self,
                                 GoaObject   *object)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), NULL);
-  return GOA_PROVIDER_GET_CLASS (provider)->get_provider_icon (provider, object);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), NULL);
+  return GOA_PROVIDER_GET_CLASS (self)->get_provider_icon (self, object);
 }
 
 static GIcon *
-goa_provider_get_provider_icon_default (GoaProvider *provider,
+goa_provider_get_provider_icon_default (GoaProvider *self,
                                         GoaObject   *object)
 {
   GIcon *ret;
   gchar *s;
-  s = g_strdup_printf ("goa-account-%s", goa_provider_get_provider_type (provider));
+  s = g_strdup_printf ("goa-account-%s", goa_provider_get_provider_type (self));
   ret = g_themed_icon_new_with_default_fallbacks (s);
   g_free (s);
   return ret;
@@ -275,9 +275,9 @@ goa_provider_get_provider_icon_default (GoaProvider *provider,
 
 /**
  * goa_provider_get_provider_group:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  *
- * Gets the group to which @provider belongs that is suitable for
+ * Gets the group to which @self belongs that is suitable for
  * organizing the providers while displaying them in an user
  * interface.
  *
@@ -291,15 +291,15 @@ goa_provider_get_provider_icon_default (GoaProvider *provider,
  * Deprecated: 3.10: Use goa_provider_get_provider_features() instead.
  */
 GoaProviderGroup
-goa_provider_get_provider_group (GoaProvider *provider)
+goa_provider_get_provider_group (GoaProvider *self)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), GOA_PROVIDER_GROUP_INVALID);
-  return GOA_PROVIDER_GET_CLASS (provider)->get_provider_group (provider);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), GOA_PROVIDER_GROUP_INVALID);
+  return GOA_PROVIDER_GET_CLASS (self)->get_provider_group (self);
 }
 
 /**
  * goa_provider_get_provider_features:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  *
  * Get the features bitmask (eg. %GOA_PROVIDER_FEATURE_CHAT|%GOA_PROVIDER_FEATURE_CONTACTS)
  * supported by the provider.
@@ -309,25 +309,25 @@ goa_provider_get_provider_group (GoaProvider *provider)
  * Since: 3.10
  */
 GoaProviderFeatures
-goa_provider_get_provider_features (GoaProvider *provider)
+goa_provider_get_provider_features (GoaProvider *self)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), GOA_PROVIDER_FEATURE_INVALID);
-  g_return_val_if_fail (GOA_PROVIDER_GET_CLASS (provider)->get_provider_features != NULL, GOA_PROVIDER_FEATURE_INVALID);
-  return GOA_PROVIDER_GET_CLASS (provider)->get_provider_features (provider);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), GOA_PROVIDER_FEATURE_INVALID);
+  g_return_val_if_fail (GOA_PROVIDER_GET_CLASS (self)->get_provider_features != NULL, GOA_PROVIDER_FEATURE_INVALID);
+  return GOA_PROVIDER_GET_CLASS (self)->get_provider_features (self);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
  * goa_provider_add_account:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @client: A #GoaClient.
  * @dialog: A #GtkDialog.
  * @vbox: A vertically oriented #GtkBox to put content in.
  * @error: Return location for error or %NULL.
  *
  * This method brings up the user interface necessary to create a new
- * account on @client of the type for @provider, interacts with the
+ * account on @client of the type for @self, interacts with the
  * user to get all information needed and creates the account.
  *
  * The passed in @dialog widget is guaranteed to be visible with @vbox
@@ -358,7 +358,7 @@ goa_provider_get_provider_features (GoaProvider *provider)
  *   with g_object_unref()) or %NULL if @error is set.
  */
 GoaObject *
-goa_provider_add_account (GoaProvider  *provider,
+goa_provider_add_account (GoaProvider  *self,
                           GoaClient    *client,
                           GtkDialog    *dialog,
                           GtkBox       *vbox,
@@ -366,12 +366,12 @@ goa_provider_add_account (GoaProvider  *provider,
 {
   GoaObject *ret;
 
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), NULL);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), NULL);
   g_return_val_if_fail (GOA_IS_CLIENT (client), NULL);
   g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-  ret = GOA_PROVIDER_GET_CLASS (provider)->add_account (provider, client, dialog, vbox, error);
+  ret = GOA_PROVIDER_GET_CLASS (self)->add_account (self, client, dialog, vbox, error);
 
   g_warn_if_fail ((ret == NULL && (error == NULL || *error != NULL)) || GOA_IS_OBJECT (ret));
 
@@ -382,7 +382,7 @@ goa_provider_add_account (GoaProvider  *provider,
 
 /**
  * goa_provider_refresh_account:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @client: A #GoaClient.
  * @object: A #GoaObject with a #GoaAccount interface.
  * @parent: (allow-none): Transient parent of dialogs or %NULL.
@@ -406,26 +406,26 @@ goa_provider_add_account (GoaProvider  *provider,
  * is set.
  */
 gboolean
-goa_provider_refresh_account (GoaProvider  *provider,
+goa_provider_refresh_account (GoaProvider  *self,
                               GoaClient    *client,
                               GoaObject    *object,
                               GtkWindow    *parent,
                               GError      **error)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), FALSE);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), FALSE);
   g_return_val_if_fail (GOA_IS_CLIENT (client), FALSE);
   g_return_val_if_fail (GOA_IS_OBJECT (object) && goa_object_peek_account (object) != NULL, FALSE);
   g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  return GOA_PROVIDER_GET_CLASS (provider)->refresh_account (provider, client, object, parent, error);
+  return GOA_PROVIDER_GET_CLASS (self)->refresh_account (self, client, object, parent, error);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
  * goa_provider_show_account:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @client: A #GoaClient.
  * @object: A #GoaObject with a #GoaAccount interface.
  * @vbox: A vertically oriented #GtkBox to put content in.
@@ -439,27 +439,27 @@ goa_provider_refresh_account (GoaProvider  *provider,
  * implementation.
  */
 void
-goa_provider_show_account (GoaProvider         *provider,
+goa_provider_show_account (GoaProvider         *self,
                            GoaClient           *client,
                            GoaObject           *object,
                            GtkBox              *vbox,
                            GtkGrid             *grid,
                            GtkGrid             *dummy)
 {
-  g_return_if_fail (GOA_IS_PROVIDER (provider));
+  g_return_if_fail (GOA_IS_PROVIDER (self));
   g_return_if_fail (GOA_IS_CLIENT (client));
   g_return_if_fail (GOA_IS_OBJECT (object) && goa_object_peek_account (object) != NULL);
   g_return_if_fail (GTK_IS_BOX (vbox));
   g_return_if_fail (GTK_IS_GRID (grid));
 
-  GOA_PROVIDER_GET_CLASS (provider)->show_account (provider, client, object, vbox, grid, dummy);
+  GOA_PROVIDER_GET_CLASS (self)->show_account (self, client, object, vbox, grid, dummy);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
  * goa_provider_build_object:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @object: The #GoaObjectSkeleton that is being built.
  * @key_file: The #GKeyFile with configuation data.
  * @group: The group in @key_file to get data from.
@@ -484,7 +484,7 @@ goa_provider_show_account (GoaProvider         *provider,
  * Returns: %TRUE if data was valid, %FALSE if @error is set.
  */
 gboolean
-goa_provider_build_object (GoaProvider         *provider,
+goa_provider_build_object (GoaProvider         *self,
                            GoaObjectSkeleton   *object,
                            GKeyFile            *key_file,
                            const gchar         *group,
@@ -492,19 +492,19 @@ goa_provider_build_object (GoaProvider         *provider,
                            gboolean             just_added,
                            GError             **error)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), FALSE);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), FALSE);
   g_return_val_if_fail (GOA_IS_OBJECT_SKELETON (object) && goa_object_peek_account (GOA_OBJECT (object)) != NULL, FALSE);
   g_return_val_if_fail (key_file != NULL, FALSE);
   g_return_val_if_fail (group != NULL, FALSE);
   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-  return GOA_PROVIDER_GET_CLASS (provider)->build_object (provider,
-                                                          object,
-                                                          key_file,
-                                                          group,
-                                                          connection,
-                                                          just_added,
-                                                          error);
+  return GOA_PROVIDER_GET_CLASS (self)->build_object (self,
+                                                      object,
+                                                      key_file,
+                                                      group,
+                                                      connection,
+                                                      just_added,
+                                                      error);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -553,7 +553,7 @@ ensure_credentials_in_thread_func (GSimpleAsyncResult *simple,
 
 /**
  * goa_provider_ensure_credentials:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @object: A #GoaObject with a #GoaAccount interface.
  * @cancellable: (allow-none): A #GCancellable or %NULL.
  * @callback: The function to call when the request is satisfied.
@@ -572,7 +572,7 @@ ensure_credentials_in_thread_func (GSimpleAsyncResult *simple,
  * another implementation.
  */
 void
-goa_provider_ensure_credentials (GoaProvider          *provider,
+goa_provider_ensure_credentials (GoaProvider          *self,
                                  GoaObject            *object,
                                  GCancellable         *cancellable,
                                  GAsyncReadyCallback   callback,
@@ -580,11 +580,11 @@ goa_provider_ensure_credentials (GoaProvider          *provider,
 {
   GSimpleAsyncResult *simple;
 
-  g_return_if_fail (GOA_IS_PROVIDER (provider));
+  g_return_if_fail (GOA_IS_PROVIDER (self));
   g_return_if_fail (GOA_IS_OBJECT (object));
   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
-  simple = g_simple_async_result_new (G_OBJECT (provider),
+  simple = g_simple_async_result_new (G_OBJECT (self),
                                       callback,
                                       user_data,
                                       goa_provider_ensure_credentials);
@@ -600,7 +600,7 @@ goa_provider_ensure_credentials (GoaProvider          *provider,
 
 /**
  * goa_provider_ensure_credentials_finish:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @out_expires_in: (out): Return location for how long the expired credentials are good for (0 if unknown) or %NULL.
  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to goa_provider_ensure_credentials().
  * @error: Return location for error or %NULL.
@@ -610,7 +610,7 @@ goa_provider_ensure_credentials (GoaProvider          *provider,
  * Returns: %TRUE if the credentials for the passed #GoaObject are valid, %FALSE if @error is set.
  */
 gboolean
-goa_provider_ensure_credentials_finish (GoaProvider  *provider,
+goa_provider_ensure_credentials_finish (GoaProvider  *self,
                                                 gint                *out_expires_in,
                                                 GAsyncResult        *res,
                                                 GError             **error)
@@ -621,7 +621,7 @@ goa_provider_ensure_credentials_finish (GoaProvider  *provider,
 
   ret = FALSE;
 
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), FALSE);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), FALSE);
   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
@@ -643,7 +643,7 @@ goa_provider_ensure_credentials_finish (GoaProvider  *provider,
 
 /**
  * goa_provider_ensure_credentials_sync:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  * @object: A #GoaObject with a #GoaAccount interface.
  * @out_expires_in: (out): Return location for how long the expired credentials are good for (0 if unknown) or %NULL.
  * @cancellable: (allow-none): A #GCancellable or %NULL.
@@ -655,22 +655,22 @@ goa_provider_ensure_credentials_finish (GoaProvider  *provider,
  * Returns: %TRUE if the credentials for the passed #GoaObject are valid, %FALSE if @error is set.
  */
 gboolean
-goa_provider_ensure_credentials_sync (GoaProvider     *provider,
+goa_provider_ensure_credentials_sync (GoaProvider     *self,
                                       GoaObject       *object,
                                       gint            *out_expires_in,
                                       GCancellable    *cancellable,
                                       GError         **error)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), FALSE);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), FALSE);
   g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-  return GOA_PROVIDER_GET_CLASS (provider)->ensure_credentials_sync (provider, object, out_expires_in, cancellable, error);
+  return GOA_PROVIDER_GET_CLASS (self)->ensure_credentials_sync (self, object, out_expires_in, cancellable, error);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 static gboolean
-goa_provider_ensure_credentials_sync_real (GoaProvider   *provider,
+goa_provider_ensure_credentials_sync_real (GoaProvider   *self,
                                            GoaObject     *object,
                                            gint          *out_expires_in,
                                            GCancellable  *cancellable,
@@ -680,12 +680,12 @@ goa_provider_ensure_credentials_sync_real (GoaProvider   *provider,
                GOA_ERROR,
                GOA_ERROR_NOT_SUPPORTED,
                _("ensure_credentials_sync is not implemented on type %s"),
-               g_type_name (G_TYPE_FROM_INSTANCE (provider)));
+               g_type_name (G_TYPE_FROM_INSTANCE (self)));
   return FALSE;
 }
 
 static gboolean
-goa_provider_build_object_real (GoaProvider         *provider,
+goa_provider_build_object_real (GoaProvider         *self,
                                 GoaObjectSkeleton   *object,
                                 GKeyFile            *key_file,
                                 const gchar         *group,
@@ -701,7 +701,7 @@ goa_provider_build_object_real (GoaProvider         *provider,
 
 /**
  * goa_provider_get_credentials_generation:
- * @provider: A #GoaProvider.
+ * @self: A #GoaProvider.
  *
  * Gets the generation of credentials being used for the provider.
  *
@@ -719,14 +719,14 @@ goa_provider_build_object_real (GoaProvider         *provider,
  * Returns: The current generation of credentials.
  */
 guint
-goa_provider_get_credentials_generation (GoaProvider *provider)
+goa_provider_get_credentials_generation (GoaProvider *self)
 {
-  g_return_val_if_fail (GOA_IS_PROVIDER (provider), 0);
-  return GOA_PROVIDER_GET_CLASS (provider)->get_credentials_generation (provider);
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), 0);
+  return GOA_PROVIDER_GET_CLASS (self)->get_credentials_generation (self);
 }
 
 static guint
-goa_provider_get_credentials_generation_real (GoaProvider *provider)
+goa_provider_get_credentials_generation_real (GoaProvider *self)
 {
   return 0;
 }
@@ -1122,7 +1122,7 @@ goa_provider_get_all_finish (GList        **out_providers,
 
 /**
  * goa_provider_set_preseed_data:
- * @provider: The #GoaProvider
+ * @self: The #GoaProvider
  * @preseed_data: A #GVariant of type a{sv}
  *
  * Sets the #GoaProvider:preseed-data property to feed any information already
@@ -1132,18 +1132,18 @@ goa_provider_get_all_finish (GList        **out_providers,
  * 'inline' use of the g_variant_new() family of functions.
  */
 void
-goa_provider_set_preseed_data (GoaProvider *provider,
+goa_provider_set_preseed_data (GoaProvider *self,
                                GVariant    *preseed_data)
 {
-  g_clear_pointer (&provider->priv->preseed_data, g_variant_unref);
+  g_clear_pointer (&self->priv->preseed_data, g_variant_unref);
   if (preseed_data != NULL)
-    provider->priv->preseed_data = g_variant_ref_sink (preseed_data);
-  g_object_notify (G_OBJECT (provider), "preseed-data");
+    self->priv->preseed_data = g_variant_ref_sink (preseed_data);
+  g_object_notify (G_OBJECT (self), "preseed-data");
 }
 
 /**
  * goa_provider_get_preseed_data:
- * @provider: The #GoaProvider
+ * @self: The #GoaProvider
  *
  * Gets the #GVariant set through the #GoaProvider:preseed-data property.
  *
@@ -1151,9 +1151,9 @@ goa_provider_set_preseed_data (GoaProvider *provider,
  *   the property is overridden or the provider freed.
  */
 GVariant *
-goa_provider_get_preseed_data (GoaProvider *provider)
+goa_provider_get_preseed_data (GoaProvider *self)
 {
-  return provider->priv->preseed_data;
+  return self->priv->preseed_data;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/goabackend/goaprovider.h b/src/goabackend/goaprovider.h
index d67c0c8742b6..3c18d92d0fdc 100644
--- a/src/goabackend/goaprovider.h
+++ b/src/goabackend/goaprovider.h
@@ -1,6 +1,6 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /*
- * Copyright (C) 2011, 2012 Red Hat, Inc.
+ * Copyright (C) 2011, 2012, 2015 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -39,55 +39,55 @@ typedef struct _GoaProviderClass GoaProviderClass;
 typedef struct _GoaProviderPrivate GoaProviderPrivate;
 
 GType        goa_provider_get_type                  (void) G_GNUC_CONST;
-const gchar *goa_provider_get_provider_type         (GoaProvider         *provider);
-gchar       *goa_provider_get_provider_name         (GoaProvider         *provider,
+const gchar *goa_provider_get_provider_type         (GoaProvider         *self);
+gchar       *goa_provider_get_provider_name         (GoaProvider         *self,
                                                      GoaObject           *object);
-GIcon       *goa_provider_get_provider_icon         (GoaProvider         *provider,
+GIcon       *goa_provider_get_provider_icon         (GoaProvider         *self,
                                                      GoaObject           *object);
 G_DEPRECATED_FOR(goa_provider_get_provider_features)
-GoaProviderGroup goa_provider_get_provider_group    (GoaProvider         *provider);
-GoaProviderFeatures goa_provider_get_provider_features (GoaProvider      *provider);
-void         goa_provider_set_preseed_data          (GoaProvider *provider,
+GoaProviderGroup goa_provider_get_provider_group    (GoaProvider         *self);
+GoaProviderFeatures goa_provider_get_provider_features (GoaProvider      *self);
+void         goa_provider_set_preseed_data          (GoaProvider *self,
                                                      GVariant    *preseed_data);
-GVariant    *goa_provider_get_preseed_data          (GoaProvider *provider);
-GoaObject   *goa_provider_add_account               (GoaProvider         *provider,
+GVariant    *goa_provider_get_preseed_data          (GoaProvider *self);
+GoaObject   *goa_provider_add_account               (GoaProvider         *self,
                                                      GoaClient           *client,
                                                      GtkDialog           *dialog,
                                                      GtkBox              *vbox,
                                                      GError             **error);
-gboolean     goa_provider_refresh_account           (GoaProvider         *provider,
+gboolean     goa_provider_refresh_account           (GoaProvider         *self,
                                                      GoaClient           *client,
                                                      GoaObject           *object,
                                                      GtkWindow           *parent,
                                                      GError             **error);
-void         goa_provider_show_account              (GoaProvider         *provider,
+void         goa_provider_show_account              (GoaProvider         *self,
                                                      GoaClient           *client,
                                                      GoaObject           *object,
                                                      GtkBox              *vbox,
                                                      GtkGrid             *grid,
                                                      GtkGrid             *dummy);
-gboolean     goa_provider_build_object              (GoaProvider         *provider,
+gboolean     goa_provider_build_object              (GoaProvider         *self,
                                                      GoaObjectSkeleton   *object,
                                                      GKeyFile            *key_file,
                                                      const gchar         *group,
                                                      GDBusConnection     *connection,
                                                      gboolean             just_added,
                                                      GError             **error);
-void         goa_provider_ensure_credentials        (GoaProvider         *provider,
+void         goa_provider_ensure_credentials        (GoaProvider         *self,
                                                      GoaObject           *object,
                                                      GCancellable        *cancellable,
                                                      GAsyncReadyCallback  callback,
                                                      gpointer             user_data);
-gboolean     goa_provider_ensure_credentials_finish (GoaProvider         *provider,
+gboolean     goa_provider_ensure_credentials_finish (GoaProvider         *self,
                                                      gint                *out_expires_in,
                                                      GAsyncResult        *res,
                                                      GError             **error);
-gboolean     goa_provider_ensure_credentials_sync   (GoaProvider         *provider,
+gboolean     goa_provider_ensure_credentials_sync   (GoaProvider         *self,
                                                      GoaObject           *object,
                                                      gint                *out_expires_in,
                                                      GCancellable        *cancellable,
                                                      GError             **error);
-guint        goa_provider_get_credentials_generation (GoaProvider        *provider);
+guint        goa_provider_get_credentials_generation (GoaProvider        *self);
 
 void          goa_provider_get_all                  (GAsyncReadyCallback  callback,
                                                      gpointer             user_data);
-- 
2.5.5


From 6fe5f6848883e8f147d34071d306887fd5b548d5 Mon Sep 17 00:00:00 2001
From: Christophe Fergeau <cfergeau@redhat.com>
Date: Thu, 30 Jul 2015 22:33:34 +0200
Subject: [PATCH 09/22] Reorder GoaProviderClass fields as it's private now

We can group all pure virtual functions together, and drop the structure
padding as GoaProvider is not publicly exposed anymore.

https://bugzilla.gnome.org/show_bug.cgi?id=752941
---
 src/goabackend/goaprovider-priv.h | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/src/goabackend/goaprovider-priv.h b/src/goabackend/goaprovider-priv.h
index bd110f8562a2..f887b53a7276 100644
--- a/src/goabackend/goaprovider-priv.h
+++ b/src/goabackend/goaprovider-priv.h
@@ -88,6 +88,9 @@ struct _GoaProviderClass
                                      GDBusConnection    *connection,
                                      gboolean            just_added,
                                      GError            **error);
+  GoaProviderGroup     (*get_provider_group)        (GoaProvider   *self);
+  GoaProviderFeatures  (*get_provider_features)     (GoaProvider   *self);
+
   /* virtual but with default implementation */
   gboolean (*ensure_credentials_sync) (GoaProvider         *self,
                                        GoaObject           *object,
@@ -95,14 +98,6 @@ struct _GoaProviderClass
                                        GCancellable        *cancellable,
                                        GError             **error);
   guint    (*get_credentials_generation) (GoaProvider   *self);
-
-  /* pure virtual */
-  GoaProviderGroup (*get_provider_group) (GoaProvider   *self);
-  GoaProviderFeatures  (*get_provider_features)     (GoaProvider   *self);
-
-  /*< private >*/
-  /* Padding for future expansion */
-  gpointer goa_reserved[31];
 };
 
 /**
-- 
2.5.5


From b858e2f79292cdd888b0357c5442096bacd84d89 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 17:12:38 +0200
Subject: [PATCH 10/22] provider: Re-order and re-align the GoaProviderClass
 members

We don't allow out-of-tree providers and GoaProviderClass is not part
of the exported ABI.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goabackend/goaprovider-priv.h | 72 +++++++++++++++++++--------------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/src/goabackend/goaprovider-priv.h b/src/goabackend/goaprovider-priv.h
index f887b53a7276..0dedfd1ce600 100644
--- a/src/goabackend/goaprovider-priv.h
+++ b/src/goabackend/goaprovider-priv.h
@@ -60,44 +60,44 @@ struct _GoaProviderClass
   GObjectClass parent_class;
 
   /* pure virtual */
-  const gchar *(*get_provider_type) (GoaProvider        *self);
-  gchar       *(*get_provider_name) (GoaProvider        *self,
-                                     GoaObject          *object);
-  GIcon       *(*get_provider_icon) (GoaProvider        *self,
-                                     GoaObject          *object);
-  GoaObject   *(*add_account)       (GoaProvider        *self,
-                                     GoaClient          *client,
-                                     GtkDialog          *dialog,
-                                     GtkBox             *vbox,
-                                     GError            **error);
-  gboolean     (*refresh_account)   (GoaProvider        *self,
-                                     GoaClient          *client,
-                                     GoaObject          *object,
-                                     GtkWindow          *parent,
-                                     GError            **error);
-  void         (*show_account)      (GoaProvider         *self,
-                                     GoaClient           *client,
-                                     GoaObject           *object,
-                                     GtkBox              *vbox,
-                                     GtkGrid             *grid,
-                                     GtkGrid             *dummy);
-  gboolean     (*build_object)      (GoaProvider        *self,
-                                     GoaObjectSkeleton  *object,
-                                     GKeyFile           *key_file,
-                                     const gchar        *group,
-                                     GDBusConnection    *connection,
-                                     gboolean            just_added,
-                                     GError            **error);
-  GoaProviderGroup     (*get_provider_group)        (GoaProvider   *self);
-  GoaProviderFeatures  (*get_provider_features)     (GoaProvider   *self);
+  GoaObject              *(*add_account)                  (GoaProvider            *self,
+                                                           GoaClient              *client,
+                                                           GtkDialog              *dialog,
+                                                           GtkBox                 *vbox,
+                                                           GError                **error);
+  GoaProviderFeatures     (*get_provider_features)        (GoaProvider            *self);
+  GoaProviderGroup        (*get_provider_group)           (GoaProvider            *self);
+  gchar                  *(*get_provider_name)            (GoaProvider            *self,
+                                                           GoaObject              *object);
+  const gchar            *(*get_provider_type)            (GoaProvider            *self);
+  gboolean                (*refresh_account)              (GoaProvider            *self,
+                                                           GoaClient              *client,
+                                                           GoaObject              *object,
+                                                           GtkWindow              *parent,
+                                                           GError                **error);
+  void                    (*show_account)                 (GoaProvider            *self,
+                                                           GoaClient              *client,
+                                                           GoaObject              *object,
+                                                           GtkBox                 *vbox,
+                                                           GtkGrid                *grid,
+                                                           GtkGrid                *dummy);
 
   /* virtual but with default implementation */
-  gboolean (*ensure_credentials_sync) (GoaProvider         *self,
-                                       GoaObject           *object,
-                                       gint                *out_expires_in,
-                                       GCancellable        *cancellable,
-                                       GError             **error);
-  guint    (*get_credentials_generation) (GoaProvider   *self);
+  gboolean                (*build_object)                 (GoaProvider            *self,
+                                                           GoaObjectSkeleton      *object,
+                                                           GKeyFile               *key_file,
+                                                           const gchar            *group,
+                                                           GDBusConnection        *connection,
+                                                           gboolean                just_added,
+                                                           GError                **error);
+  gboolean                (*ensure_credentials_sync)      (GoaProvider            *self,
+                                                           GoaObject              *object,
+                                                           gint                   *out_expires_in,
+                                                           GCancellable           *cancellable,
+                                                           GError                **error);
+  guint                   (*get_credentials_generation)   (GoaProvider            *self);
+  GIcon                  *(*get_provider_icon)            (GoaProvider            *self,
+                                                           GoaObject              *object);
 };
 
 /**
-- 
2.5.5


From 16a8abc3e657eabcebae6d04f5309bd6994d36e4 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 18:42:01 +0200
Subject: [PATCH 11/22] provider: Re-align the function prototypes

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goabackend/goaprovider-priv.h |   4 +-
 src/goabackend/goaprovider.h      | 130 +++++++++++++++++++++-----------------
 2 files changed, 75 insertions(+), 59 deletions(-)

diff --git a/src/goabackend/goaprovider-priv.h b/src/goabackend/goaprovider-priv.h
index 0dedfd1ce600..06bed8c0308e 100644
--- a/src/goabackend/goaprovider-priv.h
+++ b/src/goabackend/goaprovider-priv.h
@@ -114,9 +114,9 @@ struct _GoaProviderClass
  */
 #define GOA_PROVIDER_FACTORY_EXTENSION_POINT_NAME "goa-backend-provider-factory"
 
-void goa_provider_ensure_builtins_loaded             (void);
+void        goa_provider_ensure_builtins_loaded                (void);
 
-void goa_provider_ensure_extension_points_registered (void);
+void        goa_provider_ensure_extension_points_registered    (void);
 
 G_END_DECLS
 
diff --git a/src/goabackend/goaprovider.h b/src/goabackend/goaprovider.h
index 3c18d92d0fdc..1a59fbe80107 100644
--- a/src/goabackend/goaprovider.h
+++ b/src/goabackend/goaprovider.h
@@ -38,64 +38,80 @@ G_BEGIN_DECLS
 typedef struct _GoaProviderClass GoaProviderClass;
 typedef struct _GoaProviderPrivate GoaProviderPrivate;
 
-GType        goa_provider_get_type                  (void) G_GNUC_CONST;
-const gchar *goa_provider_get_provider_type         (GoaProvider         *self);
-gchar       *goa_provider_get_provider_name         (GoaProvider         *self,
-                                                     GoaObject           *object);
-GIcon       *goa_provider_get_provider_icon         (GoaProvider         *self,
-                                                     GoaObject           *object);
+GType                  goa_provider_get_type                     (void) G_GNUC_CONST;
+
+const gchar           *goa_provider_get_provider_type            (GoaProvider            *self);
+
+gchar                 *goa_provider_get_provider_name            (GoaProvider            *self,
+                                                                  GoaObject              *object);
+
+GIcon                 *goa_provider_get_provider_icon            (GoaProvider            *self,
+                                                                  GoaObject              *object);
+
 G_DEPRECATED_FOR(goa_provider_get_provider_features)
-GoaProviderGroup goa_provider_get_provider_group    (GoaProvider         *self);
-GoaProviderFeatures goa_provider_get_provider_features (GoaProvider      *self);
-void         goa_provider_set_preseed_data          (GoaProvider *self,
-                                                     GVariant    *preseed_data);
-GVariant    *goa_provider_get_preseed_data          (GoaProvider *self);
-GoaObject   *goa_provider_add_account               (GoaProvider         *self,
-                                                     GoaClient           *client,
-                                                     GtkDialog           *dialog,
-                                                     GtkBox              *vbox,
-                                                     GError             **error);
-gboolean     goa_provider_refresh_account           (GoaProvider         *self,
-                                                     GoaClient           *client,
-                                                     GoaObject           *object,
-                                                     GtkWindow           *parent,
-                                                     GError             **error);
-void         goa_provider_show_account              (GoaProvider         *self,
-                                                     GoaClient           *client,
-                                                     GoaObject           *object,
-                                                     GtkBox              *vbox,
-                                                     GtkGrid             *grid,
-                                                     GtkGrid             *dummy);
-gboolean     goa_provider_build_object              (GoaProvider         *self,
-                                                     GoaObjectSkeleton   *object,
-                                                     GKeyFile            *key_file,
-                                                     const gchar         *group,
-                                                     GDBusConnection     *connection,
-                                                     gboolean             just_added,
-                                                     GError             **error);
-void         goa_provider_ensure_credentials        (GoaProvider         *self,
-                                                     GoaObject           *object,
-                                                     GCancellable        *cancellable,
-                                                     GAsyncReadyCallback  callback,
-                                                     gpointer             user_data);
-gboolean     goa_provider_ensure_credentials_finish (GoaProvider         *self,
-                                                     gint                *out_expires_in,
-                                                     GAsyncResult        *res,
-                                                     GError             **error);
-gboolean     goa_provider_ensure_credentials_sync   (GoaProvider         *self,
-                                                     GoaObject           *object,
-                                                     gint                *out_expires_in,
-                                                     GCancellable        *cancellable,
-                                                     GError             **error);
-guint        goa_provider_get_credentials_generation (GoaProvider        *self);
-
-void          goa_provider_get_all                  (GAsyncReadyCallback  callback,
-                                                     gpointer             user_data);
-gboolean      goa_provider_get_all_finish           (GList              **out_providers,
-                                                     GAsyncResult        *result,
-                                                     GError             **error);
-
-GoaProvider  *goa_provider_get_for_provider_type (const gchar *provider_type);
+GoaProviderGroup       goa_provider_get_provider_group           (GoaProvider            *self);
+
+GoaProviderFeatures    goa_provider_get_provider_features        (GoaProvider            *self);
+
+void                   goa_provider_set_preseed_data             (GoaProvider            *self,
+                                                                  GVariant               *preseed_data);
+
+GVariant              *goa_provider_get_preseed_data             (GoaProvider            *self);
+
+GoaObject             *goa_provider_add_account                  (GoaProvider            *self,
+                                                                  GoaClient              *client,
+                                                                  GtkDialog              *dialog,
+                                                                  GtkBox                 *vbox,
+                                                                  GError                **error);
+
+gboolean               goa_provider_refresh_account              (GoaProvider            *self,
+                                                                  GoaClient              *client,
+                                                                  GoaObject              *object,
+                                                                  GtkWindow              *parent,
+                                                                  GError                **error);
+
+void                   goa_provider_show_account                 (GoaProvider            *self,
+                                                                  GoaClient              *client,
+                                                                  GoaObject              *object,
+                                                                  GtkBox                 *vbox,
+                                                                  GtkGrid                *grid,
+                                                                  GtkGrid                *dummy);
+
+gboolean               goa_provider_build_object                 (GoaProvider            *self,
+                                                                  GoaObjectSkeleton      *object,
+                                                                  GKeyFile               *key_file,
+                                                                  const gchar            *group,
+                                                                  GDBusConnection        *connection,
+                                                                  gboolean                just_added,
+                                                                  GError                **error);
+
+void                   goa_provider_ensure_credentials           (GoaProvider            *self,
+                                                                  GoaObject              *object,
+                                                                  GCancellable           *cancellable,
+                                                                  GAsyncReadyCallback     callback,
+                                                                  gpointer                user_data);
+
+gboolean               goa_provider_ensure_credentials_finish    (GoaProvider            *self,
+                                                                  gint                   *out_expires_in,
+                                                                  GAsyncResult           *res,
+                                                                  GError                **error);
+
+gboolean               goa_provider_ensure_credentials_sync      (GoaProvider            *self,
+                                                                  GoaObject              *object,
+                                                                  gint                   *out_expires_in,
+                                                                  GCancellable           *cancellable,
+                                                                  GError                **error);
+
+guint                  goa_provider_get_credentials_generation   (GoaProvider            *self);
+
+void                   goa_provider_get_all                      (GAsyncReadyCallback     callback,
+                                                                  gpointer                user_data);
+
+gboolean               goa_provider_get_all_finish               (GList                 **out_providers,
+                                                                  GAsyncResult           *result,
+                                                                  GError                **error);
+
+GoaProvider           *goa_provider_get_for_provider_type        (const gchar            *provider_type);
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-- 
2.5.5


From ff49fe3e5d7d03696edcb0e411ea167bccb8aa8b Mon Sep 17 00:00:00 2001
From: Christophe Fergeau <cfergeau@redhat.com>
Date: Sat, 2 May 2015 00:07:20 +0200
Subject: [PATCH 12/22] provider: Unify default vfunc name

The default vfunc implementations in GoaProvider are named _real except
for goa_provider_get_provider_icon_default().
This commit changes the "_default" suffix to "_real" for better
consistency.

https://bugzilla.gnome.org/show_bug.cgi?id=752941
---
 src/goabackend/goaprovider.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index d0825a26f291..3a2d61408357 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -78,8 +78,8 @@ static gboolean goa_provider_build_object_real (GoaProvider         *self,
 
 static guint goa_provider_get_credentials_generation_real (GoaProvider *self);
 
-static GIcon *goa_provider_get_provider_icon_default (GoaProvider *self,
-                                                      GoaObject   *object);
+static GIcon *goa_provider_get_provider_icon_real (GoaProvider *self,
+                                                   GoaObject   *object);
 
 #define GOA_PROVIDER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOA_TYPE_PROVIDER, GoaProviderPrivate))
 
@@ -151,7 +151,7 @@ goa_provider_class_init (GoaProviderClass *klass)
   klass->build_object = goa_provider_build_object_real;
   klass->ensure_credentials_sync = goa_provider_ensure_credentials_sync_real;
   klass->get_credentials_generation = goa_provider_get_credentials_generation_real;
-  klass->get_provider_icon = goa_provider_get_provider_icon_default;
+  klass->get_provider_icon = goa_provider_get_provider_icon_real;
 
 /**
  * GoaProvider:preseed-data
@@ -262,8 +262,8 @@ goa_provider_get_provider_icon (GoaProvider *self,
 }
 
 static GIcon *
-goa_provider_get_provider_icon_default (GoaProvider *self,
-                                        GoaObject   *object)
+goa_provider_get_provider_icon_real (GoaProvider *self,
+                                     GoaObject   *object)
 {
   GIcon *ret;
   gchar *s;
-- 
2.5.5


From 13d27c80e5883191984b719c69210411af423e9d Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 18:48:37 +0200
Subject: [PATCH 13/22] provider: Add a new vfunc for backend-specific work on
 account removal

Some GoaProvider sub-classes (eg., Kerberos and Telepathy) need to
perform some extra clean up when an account is removed. This virtual
method will let them hook into the account removal operation to do so.

The default implementation of this virtual method simply returns TRUE.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goabackend/goaprovider-priv.h | 18 ++++++++++
 src/goabackend/goaprovider.c      | 72 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+)

diff --git a/src/goabackend/goaprovider-priv.h b/src/goabackend/goaprovider-priv.h
index 06bed8c0308e..762989158807 100644
--- a/src/goabackend/goaprovider-priv.h
+++ b/src/goabackend/goaprovider-priv.h
@@ -98,6 +98,14 @@ struct _GoaProviderClass
   guint                   (*get_credentials_generation)   (GoaProvider            *self);
   GIcon                  *(*get_provider_icon)            (GoaProvider            *self,
                                                            GoaObject              *object);
+  void                    (*remove_account)               (GoaProvider            *self,
+                                                           GoaObject              *object,
+                                                           GCancellable           *cancellable,
+                                                           GAsyncReadyCallback     callback,
+                                                           gpointer                user_data);
+  gboolean                (*remove_account_finish)        (GoaProvider            *self,
+                                                           GAsyncResult           *res,
+                                                           GError                **error);
 };
 
 /**
@@ -118,6 +126,16 @@ void        goa_provider_ensure_builtins_loaded                (void);
 
 void        goa_provider_ensure_extension_points_registered    (void);
 
+void        goa_provider_remove_account                        (GoaProvider             *self,
+                                                                GoaObject               *object,
+                                                                GCancellable            *cancellable,
+                                                                GAsyncReadyCallback      callback,
+                                                                gpointer                 user_data);
+
+gboolean    goa_provider_remove_account_finish                 (GoaProvider             *self,
+                                                                GAsyncResult            *res,
+                                                                GError                 **error);
+
 G_END_DECLS
 
 #endif /* __GOA_PROVIDER_PRIV_H__ */
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index 3a2d61408357..174fe9ac67be 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -81,6 +81,16 @@ static guint goa_provider_get_credentials_generation_real (GoaProvider *self);
 static GIcon *goa_provider_get_provider_icon_real (GoaProvider *self,
                                                    GoaObject   *object);
 
+static void goa_provider_remove_account_real (GoaProvider          *self,
+                                              GoaObject            *object,
+                                              GCancellable         *cancellable,
+                                              GAsyncReadyCallback   callback,
+                                              gpointer              user_data);
+
+static gboolean goa_provider_remove_account_finish_real (GoaProvider   *self,
+                                                         GAsyncResult  *res,
+                                                         GError       **error);
+
 #define GOA_PROVIDER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOA_TYPE_PROVIDER, GoaProviderPrivate))
 
 G_DEFINE_ABSTRACT_TYPE (GoaProvider, goa_provider, G_TYPE_OBJECT);
@@ -152,6 +162,8 @@ goa_provider_class_init (GoaProviderClass *klass)
   klass->ensure_credentials_sync = goa_provider_ensure_credentials_sync_real;
   klass->get_credentials_generation = goa_provider_get_credentials_generation_real;
   klass->get_provider_icon = goa_provider_get_provider_icon_real;
+  klass->remove_account = goa_provider_remove_account_real;
+  klass->remove_account_finish = goa_provider_remove_account_finish_real;
 
 /**
  * GoaProvider:preseed-data
@@ -1120,6 +1132,66 @@ goa_provider_get_all_finish (GList        **out_providers,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+void
+goa_provider_remove_account (GoaProvider          *self,
+                             GoaObject            *object,
+                             GCancellable         *cancellable,
+                             GAsyncReadyCallback   callback,
+                             gpointer              user_data)
+{
+  g_return_if_fail (GOA_IS_PROVIDER (self));
+  g_return_if_fail (GOA_IS_OBJECT (object));
+  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+  GOA_PROVIDER_GET_CLASS (self)->remove_account (self, object, cancellable, callback, user_data);
+}
+
+gboolean
+goa_provider_remove_account_finish (GoaProvider   *self,
+                                    GAsyncResult  *res,
+                                    GError       **error)
+{
+  g_return_val_if_fail (GOA_IS_PROVIDER (self), FALSE);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  return GOA_PROVIDER_GET_CLASS (self)->remove_account_finish (self, res, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+goa_provider_remove_account_real (GoaProvider          *self,
+                                  GoaObject            *object,
+                                  GCancellable         *cancellable,
+                                  GAsyncReadyCallback   callback,
+                                  gpointer              user_data)
+{
+  GTask *task;
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, goa_provider_remove_account_real);
+  g_task_return_boolean (task, TRUE);
+  g_object_unref (task);
+}
+
+static gboolean
+goa_provider_remove_account_finish_real (GoaProvider   *self,
+                                         GAsyncResult  *res,
+                                         GError       **error)
+{
+  GTask *task;
+
+  g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
+  task = G_TASK (res);
+
+  g_warn_if_fail (g_task_get_source_tag (task) == goa_provider_remove_account_real);
+
+  return g_task_propagate_boolean (task, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /**
  * goa_provider_set_preseed_data:
  * @self: The #GoaProvider
-- 
2.5.5


From 74ab19f5f6dafe7240b570923e8f5d4e4d47e474 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 19:02:50 +0200
Subject: [PATCH 14/22] daemon: Rename EnsureData as ObjectInvocationData

... because we are also going to use it for Remove.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/daemon/goadaemon.c | 66 ++++++++++++++++++++++++++------------------------
 1 file changed, 34 insertions(+), 32 deletions(-)

diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index c12030f2bbc2..01acd543da57 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -1006,6 +1006,36 @@ on_manager_handle_add_account (GoaManager             *manager,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+typedef struct
+{
+  GoaDaemon *daemon;
+  GoaObject *object;
+  GDBusMethodInvocation *invocation;
+} ObjectInvocationData;
+
+static ObjectInvocationData *
+object_invocation_data_new (GoaDaemon             *self,
+                            GoaObject             *object,
+                            GDBusMethodInvocation *invocation)
+{
+  ObjectInvocationData *data;
+  data = g_slice_new0 (ObjectInvocationData);
+  data->daemon = g_object_ref (self);
+  data->object = g_object_ref (object);
+  data->invocation = invocation;
+  return data;
+}
+
+static void
+object_invocation_data_unref (ObjectInvocationData *data)
+{
+  g_object_unref (data->daemon);
+  g_object_unref (data->object);
+  g_slice_free (ObjectInvocationData, data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gboolean
 on_account_handle_remove (GoaAccount            *account,
                           GDBusMethodInvocation *invocation,
@@ -1105,34 +1135,6 @@ on_account_handle_remove (GoaAccount            *account,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-typedef struct
-{
-  GoaDaemon *daemon;
-  GoaObject *object;
-  GDBusMethodInvocation *invocation;
-} EnsureData;
-
-static EnsureData *
-ensure_data_new (GoaDaemon             *self,
-                             GoaObject             *object,
-                             GDBusMethodInvocation *invocation)
-{
-  EnsureData *data;
-  data = g_slice_new0 (EnsureData);
-  data->daemon = g_object_ref (self);
-  data->object = g_object_ref (object);
-  data->invocation = invocation;
-  return data;
-}
-
-static void
-ensure_data_unref (EnsureData *data)
-{
-  g_object_unref (data->daemon);
-  g_object_unref (data->object);
-  g_slice_free (EnsureData, data);
-}
-
 static gboolean
 is_authorization_error (GError *error)
 {
@@ -1159,7 +1161,7 @@ ensure_credentials_cb (GoaProvider   *provider,
                        GAsyncResult  *res,
                        gpointer       user_data)
 {
-  EnsureData *data = user_data;
+  ObjectInvocationData *data = user_data;
   gint expires_in;
   GError *error;
 
@@ -1206,7 +1208,7 @@ ensure_credentials_cb (GoaProvider   *provider,
       if (data->invocation != NULL)
         goa_account_complete_ensure_credentials (account, data->invocation, expires_in);
     }
-  ensure_data_unref (data);
+  object_invocation_data_unref (data);
 }
 
 static gboolean
@@ -1235,7 +1237,7 @@ on_account_handle_ensure_credentials (GoaAccount            *account,
                                    object,
                                    NULL, /* GCancellable */
                                    (GAsyncReadyCallback) ensure_credentials_cb,
-                                   ensure_data_new (self, object, invocation));
+                                   object_invocation_data_new (self, object, invocation));
 
  out:
   g_clear_object (&provider);
@@ -1277,7 +1279,7 @@ goa_daemon_check_credentials (GoaDaemon *self)
                                        object,
                                        NULL, /* GCancellable */
                                        (GAsyncReadyCallback) ensure_credentials_cb,
-                                       ensure_data_new (self, object, NULL));
+                                       object_invocation_data_new (self, object, NULL));
 
       g_clear_object (&provider);
     }
-- 
2.5.5


From a1d85d8b105dbf217a075e051f18f4ccbb9f3830 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 19:51:28 +0200
Subject: [PATCH 15/22] daemon: Call goa_provider_remove_account during account
 removal

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/daemon/goadaemon.c | 37 ++++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)

diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index 01acd543da57..c0768cc28294 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -1036,14 +1036,42 @@ object_invocation_data_unref (ObjectInvocationData *data)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static void
+remove_account_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+  GError *error;
+  GoaAccount *account;
+  GoaProvider *provider = GOA_PROVIDER (source_object);
+  ObjectInvocationData *data = user_data;
+
+  error= NULL;
+  if (!goa_provider_remove_account_finish (provider, res, &error))
+    {
+      g_warning ("goa_provider_remove_account() failed: %s (%s, %d)",
+                 error->message,
+                 g_quark_to_string (error->domain),
+                 error->code);
+      g_error_free (error);
+    }
+
+  goa_daemon_reload_configuration (data->daemon);
+
+  account = goa_object_peek_account (data->object);
+  goa_account_complete_remove (account, data->invocation);
+
+  object_invocation_data_unref (data);
+}
+
 static gboolean
 on_account_handle_remove (GoaAccount            *account,
                           GDBusMethodInvocation *invocation,
                           gpointer               user_data)
 {
   GoaDaemon *self = GOA_DAEMON (user_data);
+  GoaObject *object;
   GoaProvider *provider;
   GKeyFile *key_file;
+  ObjectInvocationData *data;
   const gchar *provider_type;
   gchar *path;
   gchar *group;
@@ -1121,9 +1149,12 @@ on_account_handle_remove (GoaAccount            *account,
       goto out;
     }
 
-  goa_daemon_reload_configuration (self);
-
-  goa_account_complete_remove (account, invocation);
+  object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (account)));
+  goa_provider_remove_account (provider,
+                               object,
+                               NULL,
+                               remove_account_cb,
+                               object_invocation_data_new (self, object, invocation));
 
  out:
   g_clear_object (&provider);
-- 
2.5.5


From f8dabd85c19f611572eab515c8c098840828fcdd Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Fri, 20 May 2016 18:51:06 +0200
Subject: [PATCH 16/22] kerberos: Implement GoaProvider:remove_account for
 signing out

... instead of listening to GoaClient::account-removed.

GoaClient::account-removed is emitted every time the goa-daemon
process dies, which could be due to a crash or restart or something
else. We only want to sign out the identity when the user has
explicitly asked for it to be removed. We don't want to sign them out
merely because goa-daemon died.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goabackend/goakerberosprovider.c | 72 ++++++++++++++++++++++++++++++++++++
 src/goaidentity/goaidentityservice.c | 43 ---------------------
 2 files changed, 72 insertions(+), 43 deletions(-)

diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c
index 9d6ddd65f995..f51f56a0a34a 100644
--- a/src/goabackend/goakerberosprovider.c
+++ b/src/goabackend/goakerberosprovider.c
@@ -1463,6 +1463,76 @@ out:
   return credentials_ensured;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+remove_account_in_thread_func (GTask         *task,
+                               gpointer       source_object,
+                               gpointer       task_data,
+                               GCancellable  *cancellable)
+{
+  GError *error;
+  GoaAccount *account = NULL;
+  GoaObject *object = GOA_OBJECT (task_data);
+  const gchar *identifier;
+
+  ensure_identity_manager ();
+
+  account = goa_object_get_account (object);
+  identifier = goa_account_get_identity (account);
+
+  g_debug ("Kerberos account %s removed and should now be signed out", identifier);
+
+  error = NULL;
+  if (!goa_identity_service_manager_call_sign_out_sync (identity_manager, identifier, cancellable, &error))
+    {
+      g_task_return_error (task, error);
+      goto out;
+    }
+
+  g_task_return_boolean (task, TRUE);
+
+ out:
+  g_clear_object (&account);
+}
+
+static void
+remove_account (GoaProvider          *provider,
+                GoaObject            *object,
+                GCancellable         *cancellable,
+                GAsyncReadyCallback   callback,
+                gpointer              user_data)
+{
+  GoaKerberosProvider *self = GOA_KERBEROS_PROVIDER (provider);
+  GTask *task;
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, remove_account);
+
+  g_task_set_task_data (task, g_object_ref (object), g_object_unref);
+  g_task_run_in_thread (task, remove_account_in_thread_func);
+
+  g_object_unref (task);
+}
+
+static gboolean
+remove_account_finish (GoaProvider   *provider,
+                       GAsyncResult  *res,
+                       GError       **error)
+{
+  GoaKerberosProvider *self = GOA_KERBEROS_PROVIDER (provider);
+  GTask *task;
+
+  g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
+  task = G_TASK (res);
+
+  g_warn_if_fail (g_task_get_source_tag (task) == remove_account);
+
+  return g_task_propagate_boolean (task, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static GoaIdentityServiceIdentity *
 get_identity_from_object_manager (GoaKerberosProvider *self,
                                   const char          *identifier)
@@ -1707,4 +1777,6 @@ goa_kerberos_provider_class_init (GoaKerberosProviderClass *kerberos_class)
   provider_class->refresh_account            = refresh_account;
   provider_class->show_account               = show_account;
   provider_class->ensure_credentials_sync    = ensure_credentials_sync;
+  provider_class->remove_account             = remove_account;
+  provider_class->remove_account_finish      = remove_account_finish;
 }
diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c
index 2eda31d56e74..fdc161fe97ab 100644
--- a/src/goaidentity/goaidentityservice.c
+++ b/src/goaidentity/goaidentityservice.c
@@ -1526,44 +1526,6 @@ on_account_interface_removed (GDBusObjectManager *manager,
 }
 
 static void
-on_account_removed (GoaClient          *client,
-                    GoaObject          *object,
-                    GoaIdentityService *self)
-{
-  GSimpleAsyncResult *result;
-  GoaAccount         *account;
-  const char         *provider_type;
-  const char         *account_identity;
-
-  account = goa_object_peek_account (object);
-
-  if (account == NULL)
-    return;
-
-  provider_type = goa_account_get_provider_type (account);
-
-  if (g_strcmp0 (provider_type, "kerberos") != 0)
-    return;
-
-  account_identity = goa_account_get_identity (account);
-
-  g_debug ("Kerberos account %s removed and should now be signed out", account_identity);
-
-  result = g_simple_async_result_new (G_OBJECT (self),
-                                      (GAsyncReadyCallback)
-                                      on_sign_out_for_account_change_done,
-                                      NULL,
-                                      on_account_removed);
-
-  goa_identity_manager_get_identity (self->priv->identity_manager,
-                                     account_identity,
-                                     NULL,
-                                     (GAsyncReadyCallback)
-                                     on_got_identity_for_sign_out,
-                                     result);
-}
-
-static void
 on_identities_listed (GoaIdentityManager *manager,
                       GAsyncResult       *result,
                       GoaIdentityService *self)
@@ -1596,11 +1558,6 @@ on_identities_listed (GoaIdentityManager *manager,
                     G_CALLBACK (on_identity_expired),
                     self);
 
-  g_signal_connect (G_OBJECT (self->priv->client),
-                    "account-removed",
-                    G_CALLBACK (on_account_removed),
-                    self);
-
   identities = goa_identity_manager_list_identities_finish (manager, result, &error);
 
   if (identities == NULL)
-- 
2.5.5


From 09e9884bb982e340357b89a51e0f88245e38ebff Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Thu, 26 May 2016 19:07:01 +0200
Subject: [PATCH 17/22] daemon: Add a synchronous version of
 goa_provider_get_all

This will be useful to poke at all available providers when goa-daemon
starts. Since we are doing this in the early stages of start-up, it
would be nice to be able to get the list of providers synchronously.

This function is not suitable for wider use because we can't push a
new thread-default GMainContext due to limitations (or bugs) inside
telepathy-glib.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/daemon/goadaemon.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index c0768cc28294..2e3b12c3efe9 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -80,6 +80,52 @@ static void goa_daemon_reload_configuration (GoaDaemon *self);
 
 G_DEFINE_TYPE (GoaDaemon, goa_daemon, G_TYPE_OBJECT);
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+  GError **error;
+  GList **out_providers;
+  GMainLoop *loop;
+  gboolean op_res;
+} GetAllSyncData;
+
+static void
+get_all_providers_sync_cb (GObject       *source_object,
+                           GAsyncResult  *res,
+                           gpointer       user_data)
+{
+  GetAllSyncData *data = (GetAllSyncData *) user_data;
+
+  data->op_res = goa_provider_get_all_finish (data->out_providers, res, data->error);
+  g_main_loop_quit (data->loop);
+}
+
+static gboolean
+get_all_providers_sync (GCancellable  *cancellable,
+                        GList        **out_providers,
+                        GError       **error)
+{
+  GetAllSyncData data;
+
+  data.error = error;
+  data.out_providers = out_providers;
+
+  /* HACK: Since telepathy-glib doesn't use the thread-default
+   * GMainContext for invoking the asynchronous callbacks, we can't
+   * push a new GMainContext here.
+   */
+  data.loop = g_main_loop_new (NULL, FALSE);
+
+  goa_provider_get_all (get_all_providers_sync_cb, &data);
+  g_main_loop_run (data.loop);
+  g_main_loop_unref (data.loop);
+
+  return data.op_res;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 goa_daemon_finalize (GObject *object)
 {
-- 
2.5.5


From 07237f1ab7651b808a11bdcbefeafe6909718165 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Thu, 26 May 2016 19:08:41 +0200
Subject: [PATCH 18/22] provider: Add a new vfunc for backend-specific
 initialization

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goabackend/goaprovider-priv.h |  4 ++++
 src/goabackend/goaprovider.c      | 18 ++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/src/goabackend/goaprovider-priv.h b/src/goabackend/goaprovider-priv.h
index 762989158807..c7b0f59860bd 100644
--- a/src/goabackend/goaprovider-priv.h
+++ b/src/goabackend/goaprovider-priv.h
@@ -52,6 +52,7 @@ struct _GoaProvider
  * @ensure_credentials_sync: Virtual function for goa_provider_ensure_credentials_sync().
  * @show_account: Virtual function for goa_provider_show_account().
  * @get_credentials_generation: Virtual function for goa_provider_get_credentials_generation().
+ * @initialize: Virtual function for goa_provider_initialize().
  *
  * Class structure for #GoaProvider.
  */
@@ -98,6 +99,7 @@ struct _GoaProviderClass
   guint                   (*get_credentials_generation)   (GoaProvider            *self);
   GIcon                  *(*get_provider_icon)            (GoaProvider            *self,
                                                            GoaObject              *object);
+  void                    (*initialize)                   (GoaProvider            *self);
   void                    (*remove_account)               (GoaProvider            *self,
                                                            GoaObject              *object,
                                                            GCancellable           *cancellable,
@@ -126,6 +128,8 @@ void        goa_provider_ensure_builtins_loaded                (void);
 
 void        goa_provider_ensure_extension_points_registered    (void);
 
+void        goa_provider_initialize                            (GoaProvider             *self);
+
 void        goa_provider_remove_account                        (GoaProvider             *self,
                                                                 GoaObject               *object,
                                                                 GCancellable            *cancellable,
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index 174fe9ac67be..f07fa95187fc 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -81,6 +81,8 @@ static guint goa_provider_get_credentials_generation_real (GoaProvider *self);
 static GIcon *goa_provider_get_provider_icon_real (GoaProvider *self,
                                                    GoaObject   *object);
 
+static void goa_provider_initialize_real (GoaProvider *self);
+
 static void goa_provider_remove_account_real (GoaProvider          *self,
                                               GoaObject            *object,
                                               GCancellable         *cancellable,
@@ -162,6 +164,7 @@ goa_provider_class_init (GoaProviderClass *klass)
   klass->ensure_credentials_sync = goa_provider_ensure_credentials_sync_real;
   klass->get_credentials_generation = goa_provider_get_credentials_generation_real;
   klass->get_provider_icon = goa_provider_get_provider_icon_real;
+  klass->initialize = goa_provider_initialize_real;
   klass->remove_account = goa_provider_remove_account_real;
   klass->remove_account_finish = goa_provider_remove_account_finish_real;
 
@@ -330,6 +333,21 @@ goa_provider_get_provider_features (GoaProvider *self)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+void
+goa_provider_initialize (GoaProvider *self)
+{
+  g_return_if_fail (GOA_IS_PROVIDER (self));
+
+  GOA_PROVIDER_GET_CLASS (self)->initialize (self);
+}
+
+static void
+goa_provider_initialize_real (GoaProvider *self)
+{
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /**
  * goa_provider_add_account:
  * @self: A #GoaProvider.
-- 
2.5.5


From 981298802f9b7596d241c98a8f9a546f30816372 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Thu, 26 May 2016 19:09:24 +0200
Subject: [PATCH 19/22] daemon: Call goa_provider_initialize during start-up

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/daemon/goadaemon.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index 2e3b12c3efe9..f3995cf8c369 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -251,6 +251,9 @@ static void
 goa_daemon_init (GoaDaemon *self)
 {
   static volatile GQuark goa_error_domain = 0;
+  GError *error;
+  GList *l;
+  GList *providers = NULL;
   GoaObjectSkeleton *object;
   gchar *path;
 
@@ -260,7 +263,21 @@ goa_daemon_init (GoaDaemon *self)
   goa_error_domain = GOA_ERROR;
   goa_error_domain; /* shut up -Wunused-but-set-variable */
 
-  goa_provider_ensure_builtins_loaded ();
+  error = NULL;
+  if (!get_all_providers_sync (NULL, &providers, &error))
+    {
+      g_warning ("Unable to get the list of providers: %s (%s, %d)",
+                 error->message,
+                 g_quark_to_string (error->domain),
+                 error->code);
+      g_error_free (error);
+    }
+
+  for (l = providers; l != NULL; l = l->next)
+    {
+      GoaProvider *provider = GOA_PROVIDER (l->data);
+      goa_provider_initialize (provider);
+    }
 
   /* TODO: maybe nicer to pass in a GDBusConnection* construct property */
   self->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
-- 
2.5.5


From e9748cc601a4e7cd3ebe6dd31151d91e88569fad Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Thu, 26 May 2016 19:31:28 +0200
Subject: [PATCH 20/22] telepathy: Implement GoaProvider:initialize to start
 the linker

... instead of starting it from goa-daemon.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/daemon/Makefile.am                |   3 -
 src/daemon/goatpaccountlinker.c       | 590 ----------------------------------
 src/daemon/goatpaccountlinker.h       |  54 ----
 src/daemon/main.c                     |   7 -
 src/goabackend/Makefile.am            |   1 +
 src/goabackend/goatelepathyprovider.c |  39 +++
 src/goabackend/goatpaccountlinker.c   | 590 ++++++++++++++++++++++++++++++++++
 src/goabackend/goatpaccountlinker.h   |  54 ++++
 8 files changed, 684 insertions(+), 654 deletions(-)
 delete mode 100644 src/daemon/goatpaccountlinker.c
 delete mode 100644 src/daemon/goatpaccountlinker.h
 create mode 100644 src/goabackend/goatpaccountlinker.c
 create mode 100644 src/goabackend/goatpaccountlinker.h

diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 8f5352fad39e..b318b6a4a328 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -29,14 +29,12 @@ goa_daemon_SOURCES = 						\
 				main.c				\
 	goadaemontypes.h					\
 	goadaemon.h		goadaemon.c			\
-	goatpaccountlinker.h	goatpaccountlinker.c		\
 	$(NULL)
 
 goa_daemon_CFLAGS =						\
 	$(GLIB_CFLAGS) 						\
 	$(GTK_CFLAGS)						\
 	$(REST_CFLAGS)						\
-	$(TP_CFLAGS)						\
 	$(NULL)
 
 goa_daemon_LDADD = 						\
@@ -45,7 +43,6 @@ goa_daemon_LDADD = 						\
 	$(top_builddir)/src/goabackend/libgoa-backend-1.0.la	\
 	$(GTK_LIBS)						\
 	$(REST_LIBS)						\
-	$(TP_LIBS)						\
 	$(NULL)
 
 clean-local :
diff --git a/src/daemon/goatpaccountlinker.c b/src/daemon/goatpaccountlinker.c
deleted file mode 100644
index dcdf3f761ca7..000000000000
--- a/src/daemon/goatpaccountlinker.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright (C) 2010-2013 Collabora Ltd.
- * Copyright (C) 2013 Intel Corporation
- *
- * This library 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) any later version.
- *
- * This library 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 this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* This class makes sure we have a GOA account for each Telepathy account
- * configured in the system.
- * Note that this handles only plain Telepathy accounts; the ones with
- * multiple capabilities (e.g. Facebook) are handled differently. */
-
-#include "config.h"
-
-#include <gio/gio.h>
-#include <telepathy-glib/telepathy-glib.h>
-
-#include "goatpaccountlinker.h"
-#include "goa/goa.h"
-#include "goabackend/goautils.h"
-
-#define GOA_TP_ACCOUNT_LINKER_GET_PRIVATE(obj) \
-  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOA_TYPE_TP_ACCOUNT_LINKER, \
-                                GoaTpAccountLinkerPrivate))
-
-G_DEFINE_TYPE (GoaTpAccountLinker, goa_tp_account_linker, G_TYPE_OBJECT)
-
-struct _GoaTpAccountLinkerPrivate
-{
-  TpAccountManager *account_manager;
-  GoaClient *goa_client;
-
-  GHashTable *tp_accounts; /* owned gchar *id -> reffed TpAccount * */
-  GHashTable *goa_accounts; /* owned gchar *id -> reffed GoaObject * */
-};
-
-/* The path of the Telepathy account is used as common identifier between
- * GOA and Telepathy */
-static const gchar *
-get_id_from_tp_account (TpAccount *tp_account)
-{
-  return tp_proxy_get_object_path (tp_account);
-}
-
-static const gchar *
-get_id_from_goa_account (GoaAccount *goa_account)
-{
-  return goa_account_get_identity (goa_account);
-}
-
-static gboolean
-is_telepathy_account (GoaAccount *goa_account)
-{
-  const gchar *type = goa_account_get_provider_type (goa_account);
-  return g_str_has_prefix (type, "telepathy/");
-}
-
-static void
-goa_account_chat_disabled_changed_cb (GoaAccount         *goa_account,
-                                      GParamSpec         *spec,
-                                      GoaTpAccountLinker *self)
-{
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  const gchar *id;
-  TpAccount *tp_account;
-  gboolean tp_enabled;
-  gboolean goa_enabled;
-
-  id = get_id_from_goa_account (goa_account);
-  tp_account = g_hash_table_lookup (priv->tp_accounts, id);
-  if (tp_account == NULL)
-    return;
-
-  goa_enabled = !goa_account_get_chat_disabled (goa_account);
-  tp_enabled = tp_account_is_enabled (tp_account);
-  if (tp_enabled != goa_enabled)
-    {
-      g_info ("The GOA account %s (Telepathy object path: %s) has been %s, "
-          "propagating to Telepathy",
-          goa_account_get_id (goa_account), id,
-          goa_enabled ? "enabled" : "disabled");
-      tp_account_set_enabled_async (tp_account, goa_enabled, NULL, NULL);
-    }
-}
-
-static void
-tp_account_chat_enabled_changed_cb (TpAccount          *tp_account,
-                                    GParamSpec         *spec,
-                                    GoaTpAccountLinker *self)
-{
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  const gchar *id;
-  GoaObject *goa_object;
-  GoaAccount *goa_account;
-  gboolean tp_enabled;
-  gboolean goa_enabled;
-
-  id = get_id_from_tp_account (tp_account);
-  goa_object = g_hash_table_lookup (priv->goa_accounts, id);
-  if (goa_object == NULL)
-    return;
-
-  goa_account = goa_object_peek_account (goa_object);
-  goa_enabled = !goa_account_get_chat_disabled (goa_account);
-  tp_enabled = tp_account_is_enabled (tp_account);
-  if (tp_enabled != goa_enabled)
-    {
-      g_info ("The Telepathy account %s has been %s, propagating to GOA",
-          id, tp_enabled ? "enabled" : "disabled");
-      /* When we set this property, the autogenerated code emits a notify
-       * signal immediately even if the property hasn't changed, so
-       * goa_account_chat_disabled_changed_cb() thinks that the property
-       * changed back to the old value and a cycle starts.
-       * The right notify signal will be emitted later when the property is
-       * actually changed. */
-      g_signal_handlers_block_by_func (goa_account,
-          goa_account_chat_disabled_changed_cb, self);
-      goa_account_set_chat_disabled (goa_account, !tp_enabled);
-      g_signal_handlers_unblock_by_func (goa_account,
-          goa_account_chat_disabled_changed_cb, self);
-    }
-}
-
-static void
-goa_account_created_cb (GoaManager   *manager,
-                        GAsyncResult *res,
-                        gpointer      user_data)
-{
-  TpAccount *tp_account = user_data;
-  gchar *goa_account_object_path = NULL;
-  GError *error = NULL;
-
-  if (!goa_manager_call_add_account_finish (manager,
-        &goa_account_object_path, res, &error))
-    {
-      g_critical ("Failed to create a GOA account for %s: %s (%s, %d)",
-          get_id_from_tp_account (tp_account),
-          error->message,
-          g_quark_to_string (error->domain),
-          error->code);
-      g_error_free (error);
-      goto out;
-    }
-
-  g_info ("Created new %s GOA account for Telepathy account %s",
-      goa_account_object_path, get_id_from_tp_account (tp_account));
-
- out:
-  g_object_unref (tp_account);
-}
-
-static void
-create_goa_account (GoaTpAccountLinker *self,
-                    TpAccount          *tp_account)
-{
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  GVariantBuilder credentials;
-  GVariantBuilder details;
-  gchar *provider;
-
-  g_info ("Creating new GOA account for Telepathy account %s",
-      get_id_from_tp_account (tp_account));
-
-  g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
-
-  g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
-  g_variant_builder_add (&details, "{ss}", "ChatEnabled",
-      tp_account_is_enabled (tp_account) ? "true" : "false");
-
-  provider = g_strdup_printf ("telepathy/%s",
-      tp_account_get_protocol_name (tp_account));
-
-  goa_manager_call_add_account (goa_client_get_manager (priv->goa_client),
-      provider,
-      get_id_from_tp_account (tp_account),
-      tp_account_get_display_name (tp_account),
-      g_variant_builder_end (&credentials),
-      g_variant_builder_end (&details),
-      NULL, /* GCancellable* */
-      (GAsyncReadyCallback) goa_account_created_cb,
-      g_object_ref (tp_account));
-
-  g_free (provider);
-}
-
-static gboolean
-is_account_filtered (TpAccount *tp_account)
-{
-  const gchar *env;
-  const gchar *id;
-
-  env = g_getenv ("GOA_TELEPATHY_DEBUG_ACCOUNT_FILTER");
-  if (env == NULL || env[0] == '\0')
-    return FALSE;
-
-  id = get_id_from_tp_account (tp_account);
-  if (g_strstr_len (id, -1, env) != NULL)
-    return FALSE; /* "env" is contained in "id" */
-  else
-    return TRUE;
-}
-
-static void
-tp_account_added (GoaTpAccountLinker *self,
-                  TpAccount          *tp_account)
-{
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  const gchar *id = get_id_from_tp_account (tp_account);
-  GoaObject *goa_object = NULL;
-
-  if (g_strcmp0 (tp_account_get_storage_provider (tp_account),
-        "org.gnome.OnlineAccounts") == 0)
-    {
-      g_debug ("Skipping Telepathy account %s as it's handled directly by GOA", id);
-      return;
-    }
-
-  if (is_account_filtered (tp_account))
-    {
-      g_debug ("The account %s is ignored for debugging reasons", id);
-      return;
-    }
-
-  g_debug ("Telepathy account found: %s", id);
-
-  g_hash_table_replace (priv->tp_accounts, g_strdup (id),
-      g_object_ref (tp_account));
-
-  g_signal_connect_object (tp_account, "notify::enabled",
-      G_CALLBACK (tp_account_chat_enabled_changed_cb),
-      self, 0);
-
-  goa_object = g_hash_table_lookup (priv->goa_accounts, id);
-  if (goa_object == NULL)
-    {
-      g_debug ("Found a Telepathy account with no corresponding "
-          "GOA account: %s", id);
-      create_goa_account (self, tp_account);
-    }
-  else
-    {
-      g_debug ("Found a Telepathy account with a matching "
-          "GOA account: %s", id);
-      /* Make sure the initial state is synced. */
-      tp_account_chat_enabled_changed_cb (tp_account, NULL, self);
-    }
-}
-
-static void
-goa_account_removed_by_us_cb (GObject      *object,
-                              GAsyncResult *res,
-                              gpointer      user_data)
-{
-  /* This callback is only used for debugging */
-  GoaAccount *goa_account = GOA_ACCOUNT (object);
-  GError *error = NULL;
-
-  if (!goa_account_call_remove_finish (goa_account, res, &error))
-    {
-      g_critical ("Error removing GOA account %s (Telepathy object path: %s): "
-          "%s (%s, %d)",
-          goa_account_get_id (goa_account),
-          get_id_from_goa_account (goa_account),
-          error->message,
-          g_quark_to_string (error->domain),
-          error->code);
-      g_error_free (error);
-    }
-}
-
-static void
-tp_account_removed_cb (TpAccountManager *manager,
-                       TpAccount        *tp_account,
-                       gpointer          user_data)
-{
-  GoaTpAccountLinker *self = user_data;
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  const gchar *id = get_id_from_tp_account (tp_account);
-  GoaObject *goa_object = NULL;
-
-  if (!g_hash_table_remove (priv->tp_accounts, id))
-    {
-      /* 1 - The user removes the GOA account
-       * 2 - We delete the corresponding Telepathy account and remove it
-       *     from priv->tp_accounts
-       * 3 - "account-removed" is emitted by the account manager
-       * 4 - tp_account_removed_cb is called for an unknown account
-       */
-      g_debug ("Ignoring removal of Telepathy account we asked to "
-          "remove (%s)", id);
-      return;
-    }
-
-  g_info ("Telepathy account %s removed, removing corresponding "
-      "GOA account", id);
-
-  goa_object = g_hash_table_lookup (priv->goa_accounts, id);
-  if (goa_object == NULL)
-    {
-      g_critical ("There is no GOA account for removed Telepathy "
-          "account %s", id);
-      return;
-    }
-  goa_account_call_remove (goa_object_peek_account (goa_object),
-      NULL, /* cancellable */
-      goa_account_removed_by_us_cb, NULL);
-  g_hash_table_remove (priv->goa_accounts, id);
-}
-
-static void
-tp_account_validity_changed_cb (TpAccountManager *manager,
-                                TpAccount        *tp_account,
-                                gboolean          valid,
-                                gpointer          user_data)
-{
-  GoaTpAccountLinker *self = user_data;
-
-  if (valid)
-    tp_account_added (self, tp_account);
-}
-
-static void
-goa_account_added_cb (GoaClient *client,
-                      GoaObject *goa_object,
-                      gpointer   user_data)
-{
-  GoaTpAccountLinker *self = user_data;
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  GoaAccount *goa_account = goa_object_peek_account (goa_object);
-  const gchar *id = NULL;
-  TpAccount *tp_account;
-
-  if (!is_telepathy_account (goa_account))
-    return;
-
-  id = get_id_from_goa_account (goa_account);
-  g_debug ("GOA account %s for Telepathy account %s added",
-      goa_account_get_id (goa_account), id);
-
-  g_signal_connect_object (goa_account, "notify::chat-disabled",
-      G_CALLBACK (goa_account_chat_disabled_changed_cb), self, 0);
-
-  g_hash_table_insert (priv->goa_accounts, g_strdup (id),
-      g_object_ref (goa_object));
-
-  tp_account = g_hash_table_lookup (priv->tp_accounts, id);
-  if (tp_account != NULL)
-    {
-      /* The chat enabled status may have changed during the creation of the
-       * GOA account, so we need to make sure it's synced. */
-      tp_account_chat_enabled_changed_cb (tp_account, NULL, self);
-    }
-}
-
-static void
-tp_account_removed_by_us_cb (GObject      *object,
-                             GAsyncResult *res,
-                             gpointer      user_data)
-{
-  /* This callback is only used for debugging */
-  TpAccount *tp_account = TP_ACCOUNT (object);
-  GError *error = NULL;
-
-  if (!tp_account_remove_finish (tp_account, res, &error))
-    {
-      g_critical ("Error removing Telepathy account %s: %s (%s, %d)",
-          get_id_from_tp_account (tp_account),
-          error->message,
-          g_quark_to_string (error->domain),
-          error->code);
-      g_error_free (error);
-    }
-}
-
-static void
-goa_account_removed_cb (GoaClient *client,
-                        GoaObject *goa_object,
-                        gpointer   user_data)
-{
-  GoaTpAccountLinker *self = user_data;
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  GoaAccount *goa_account = goa_object_peek_account (goa_object);
-  const gchar *id = NULL;
-  TpAccount *tp_account = NULL;
-
-  if (!is_telepathy_account (goa_account))
-    return;
-
-  id = get_id_from_goa_account (goa_account);
-  if (!g_hash_table_remove (priv->goa_accounts, id))
-    {
-      /* 1 - The user removes the Telepathy account (but not the GOA one)
-       * 2 - We delete the corresponding GOA account and remove it
-       *     from priv->goa_accounts
-       * 3 - "account-removed" is emitted by the GOA client
-       * 4 - goa_account_removed_cb is called for an unknown account
-       */
-      g_debug ("Ignoring removal of GOA account we asked to remove "
-          "(%s, Telepathy object path: %s)",
-          goa_account_get_id (goa_account),
-          id);
-      return;
-    }
-
-  g_info ("GOA account %s for Telepathy account %s removed, "
-      "removing Telepathy account",
-      goa_account_get_id (goa_account), id);
-
-  tp_account = g_hash_table_lookup (priv->tp_accounts, id);
-  if (tp_account == NULL)
-    {
-      g_critical ("There is no Telepathy account for removed GOA "
-          "account %s (Telepathy object path: %s)",
-          goa_account_get_id (goa_account), id);
-      return;
-    }
-  tp_account_remove_async (tp_account, tp_account_removed_by_us_cb, NULL);
-  g_hash_table_remove (priv->tp_accounts, id);
-}
-
-static void
-start_if_ready (GoaTpAccountLinker *self)
-{
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  GList *goa_accounts = NULL;
-  GList *tp_accounts = NULL;
-  GList *l = NULL;
-  GHashTableIter iter;
-  gpointer key, value;
-
-  if (priv->goa_client == NULL ||
-      priv->account_manager == NULL ||
-      !tp_proxy_is_prepared (priv->account_manager,
-        TP_ACCOUNT_MANAGER_FEATURE_CORE))
-    {
-      /* Not everything is ready yet */
-      return;
-    }
-
-  g_debug ("Both GOA and Tp are ready, starting tracking of accounts");
-
-  /* GOA */
-  goa_accounts = goa_client_get_accounts (priv->goa_client);
-  for (l = goa_accounts; l != NULL; l = l->next)
-    goa_account_added_cb (priv->goa_client, l->data, self);
-  g_list_free_full (goa_accounts, g_object_unref);
-
-  g_signal_connect_object (priv->goa_client, "account-added",
-      G_CALLBACK (goa_account_added_cb), self, 0);
-  g_signal_connect_object (priv->goa_client, "account-removed",
-      G_CALLBACK (goa_account_removed_cb), self, 0);
-
-  /* Telepathy */
-  tp_accounts = tp_account_manager_dup_valid_accounts (priv->account_manager);
-  for (l = tp_accounts; l != NULL; l = l->next)
-    tp_account_added (self, l->data);
-  g_list_free_full (tp_accounts, g_object_unref);
-
-  g_signal_connect_object (priv->account_manager, "account-validity-changed",
-      G_CALLBACK (tp_account_validity_changed_cb), self, 0);
-  g_signal_connect_object (priv->account_manager, "account-removed",
-      G_CALLBACK (tp_account_removed_cb), self, 0);
-
-  /* Now we check if any Telepathy account was deleted while goa-daemon
-   * was not running. */
-  g_hash_table_iter_init (&iter, priv->goa_accounts);
-  while (g_hash_table_iter_next (&iter, &key, &value))
-    {
-      const gchar *id = key;
-      GoaObject *goa_object = value;
-
-      if (!g_hash_table_lookup (priv->tp_accounts, id))
-        {
-          g_warning ("The Telepathy account %s was removed while the daemon "
-              "was not running, removing the corresponding GOA account", id);
-          goa_account_call_remove (goa_object_peek_account (goa_object),
-              NULL, /* cancellable */
-              goa_account_removed_by_us_cb,
-              NULL); /* user data */
-        }
-    }
-}
-
-static void
-account_manager_prepared_cb (GObject      *object,
-                             GAsyncResult *res,
-                             gpointer      user_data)
-{
-  GoaTpAccountLinker *self = user_data;
-  GError *error = NULL;
-
-  if (!tp_proxy_prepare_finish (object, res, &error))
-    {
-      g_critical ("Error preparing AM: %s", error->message);
-      g_clear_error (&error);
-      return;
-    }
-
-  g_debug("Telepathy account manager prepared");
-  start_if_ready (self);
-}
-
-static void
-goa_client_new_cb (GObject      *object,
-                   GAsyncResult *result,
-                   gpointer      user_data)
-{
-  GoaTpAccountLinker *self = user_data;
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  GError *error = NULL;
-
-  priv->goa_client = goa_client_new_finish (result, &error);
-  if (priv->goa_client == NULL)
-    {
-      g_critical ("Error connecting to GOA: %s", error->message);
-      g_clear_error (&error);
-      return;
-    }
-
-  g_debug("GOA client ready");
-  start_if_ready (self);
-}
-
-static void
-goa_tp_account_linker_dispose (GObject *object)
-{
-  GoaTpAccountLinker *self = GOA_TP_ACCOUNT_LINKER (object);
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-
-  g_clear_object (&priv->account_manager);
-  g_clear_object (&priv->goa_client);
-
-  g_clear_pointer (&priv->goa_accounts, g_hash_table_unref);
-  g_clear_pointer (&priv->tp_accounts, g_hash_table_unref);
-
-  G_OBJECT_CLASS (goa_tp_account_linker_parent_class)->dispose (object);
-}
-
-static void
-goa_tp_account_linker_init (GoaTpAccountLinker *self)
-{
-  GoaTpAccountLinkerPrivate *priv;
-
-  g_debug ("Starting GOA <-> Telepathy account linker");
-
-  self->priv = GOA_TP_ACCOUNT_LINKER_GET_PRIVATE (self);
-  priv = self->priv;
-
-  priv->goa_accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
-      g_free, g_object_unref);
-  priv->tp_accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
-      g_free, g_object_unref);
-
-  priv->account_manager = tp_account_manager_dup ();
-  tp_proxy_prepare_async (priv->account_manager, NULL,
-      account_manager_prepared_cb, self);
-
-  goa_client_new (NULL, goa_client_new_cb, self);
-}
-
-static void
-goa_tp_account_linker_class_init (GoaTpAccountLinkerClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  goa_utils_initialize_client_factory ();
-
-  g_type_class_add_private (gobject_class,
-      sizeof (GoaTpAccountLinkerPrivate));
-
-  gobject_class->dispose = goa_tp_account_linker_dispose;
-}
-
-GoaTpAccountLinker *
-goa_tp_account_linker_new (void)
-{
-  return g_object_new (GOA_TYPE_TP_ACCOUNT_LINKER, NULL);
-}
diff --git a/src/daemon/goatpaccountlinker.h b/src/daemon/goatpaccountlinker.h
deleted file mode 100644
index 3f5b12955df0..000000000000
--- a/src/daemon/goatpaccountlinker.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright (C) 2010-2013 Collabora Ltd.
- * Copyright (C) 2013 Intel Corporation
- *
- * This library 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) any later version.
- *
- * This library 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 this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GOA_TP_ACCOUNT_LINKER_H__
-#define __GOA_TP_ACCOUNT_LINKER_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define GOA_TYPE_TP_ACCOUNT_LINKER           (goa_tp_account_linker_get_type ())
-#define GOA_TP_ACCOUNT_LINKER(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOA_TYPE_TP_ACCOUNT_LINKER, GoaTpAccountLinker))
-#define GOA_TP_ACCOUNT_LINKER_CLASS(obj)     (G_TYPE_CHECK_CLASS_CAST ((obj), GOA_TYPE_TP_ACCOUNT_LINKER, GoaTpAccountLinkerClass))
-#define GOA_IS_TP_ACCOUNT_LINKER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOA_TYPE_TP_ACCOUNT_LINKER))
-#define GOA_IS_TP_ACCOUNT_LINKER_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE ((obj), GOA_TYPE_TP_ACCOUNT_LINKER))
-#define GOA_TP_ACCOUNT_LINKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GOA_TYPE_TP_ACCOUNT_LINKER, GoaTpAccountLinkerClass))
-
-typedef struct _GoaTpAccountLinker        GoaTpAccountLinker;
-typedef struct _GoaTpAccountLinkerClass   GoaTpAccountLinkerClass;
-typedef struct _GoaTpAccountLinkerPrivate GoaTpAccountLinkerPrivate;
-
-struct _GoaTpAccountLinker
-{
-  GObject parent_instance;
-  GoaTpAccountLinkerPrivate *priv;
-};
-
-struct _GoaTpAccountLinkerClass
-{
-  GObjectClass parent_class;
-};
-
-GType               goa_tp_account_linker_get_type      (void) G_GNUC_CONST;
-GoaTpAccountLinker *goa_tp_account_linker_new           (void);
-
-G_END_DECLS
-
-#endif
diff --git a/src/daemon/main.c b/src/daemon/main.c
index a04cc3992a83..0d1b24f51062 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -25,8 +25,6 @@
 #include <gio/gio.h>
 
 #include "goadaemon.h"
-#include "goatpaccountlinker.h"
-
 
 /* ---------------------------------------------------------------------------------------------------- */
 
@@ -40,7 +38,6 @@ static GOptionEntry opt_entries[] =
   {NULL }
 };
 static GoaDaemon *the_daemon = NULL;
-static GoaTpAccountLinker *tp_linker = NULL;
 
 static void
 on_bus_acquired (GDBusConnection *connection,
@@ -67,8 +64,6 @@ on_name_acquired (GDBusConnection *connection,
                   gpointer         user_data)
 {
   g_debug ("Acquired the name %s on the session message bus", name);
-
-  tp_linker = goa_tp_account_linker_new ();
 }
 
 static gboolean
@@ -131,8 +126,6 @@ main (int    argc,
  out:
   if (the_daemon != NULL)
     g_object_unref (the_daemon);
-  if (tp_linker != NULL)
-    g_object_unref (tp_linker);
   if (name_owner_id != 0)
     g_bus_unown_name (name_owner_id);
   g_clear_pointer (&loop, (GDestroyNotify) g_main_loop_unref);
diff --git a/src/goabackend/Makefile.am b/src/goabackend/Makefile.am
index f3b87f1c3e57..588923f88036 100644
--- a/src/goabackend/Makefile.am
+++ b/src/goabackend/Makefile.am
@@ -91,6 +91,7 @@ libgoa_backend_1_0_la_SOURCES =						\
 	goawindowsliveprovider.h	goawindowsliveprovider.c	\
 	goatelepathyfactory.h		goatelepathyfactory.c		\
 	goatelepathyprovider.h		goatelepathyprovider.c		\
+	goatpaccountlinker.h		goatpaccountlinker.c		\
 	goapocketprovider.h		goapocketprovider.c		\
 	goautils.h			goautils.c			\
 	goawebview.h			goawebview.c			\
diff --git a/src/goabackend/goatelepathyprovider.c b/src/goabackend/goatelepathyprovider.c
index 7873607c1382..8a390c82e0c6 100644
--- a/src/goabackend/goatelepathyprovider.c
+++ b/src/goabackend/goatelepathyprovider.c
@@ -26,6 +26,7 @@
 #include "goaprovider.h"
 #include "goaprovider-priv.h"
 #include "goatelepathyprovider.h"
+#include "goatpaccountlinker.h"
 #include "goautils.h"
 
 typedef struct _GoaTelepathyProviderPrivate GoaTelepathyProviderPrivate;
@@ -78,6 +79,11 @@ G_DEFINE_TYPE (GoaTelepathyProvider, goa_telepathy_provider, GOA_TYPE_PROVIDER);
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static GoaTpAccountLinker *tp_linker = NULL;
+static guint name_watcher_id = 0;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /* Telepathy / telepathy-account widgets utility functions. */
 
 static void
@@ -266,6 +272,38 @@ get_provider_features (GoaProvider *provider)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static void
+on_name_acquired (GDBusConnection *connection,
+                  const gchar     *name,
+                  const gchar     *name_owner,
+                  gpointer         user_data)
+{
+  tp_linker = goa_tp_account_linker_new ();
+  g_bus_unwatch_name (name_watcher_id);
+  name_watcher_id = 0;
+}
+
+static void
+initialize (GoaProvider *provider)
+{
+  static gsize once_init_value = 0;
+
+  if (g_once_init_enter (&once_init_value))
+    {
+      name_watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                                          "org.gnome.OnlineAccounts",
+                                          G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                          on_name_acquired,
+                                          NULL,
+                                          NULL,
+                                          NULL);
+
+      g_once_init_leave (&once_init_value, 1);
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 typedef struct
 {
   GMainLoop *loop;
@@ -1025,6 +1063,7 @@ goa_telepathy_provider_class_init (GoaTelepathyProviderClass *klass)
   provider_class->get_provider_icon     = get_provider_icon;
   provider_class->get_provider_group    = get_provider_group;
   provider_class->get_provider_features = get_provider_features;
+  provider_class->initialize            = initialize;
   provider_class->add_account           = add_account;
   provider_class->refresh_account       = refresh_account;
   provider_class->build_object          = build_object;
diff --git a/src/goabackend/goatpaccountlinker.c b/src/goabackend/goatpaccountlinker.c
new file mode 100644
index 000000000000..dcdf3f761ca7
--- /dev/null
+++ b/src/goabackend/goatpaccountlinker.c
@@ -0,0 +1,590 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2010-2013 Collabora Ltd.
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This class makes sure we have a GOA account for each Telepathy account
+ * configured in the system.
+ * Note that this handles only plain Telepathy accounts; the ones with
+ * multiple capabilities (e.g. Facebook) are handled differently. */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "goatpaccountlinker.h"
+#include "goa/goa.h"
+#include "goabackend/goautils.h"
+
+#define GOA_TP_ACCOUNT_LINKER_GET_PRIVATE(obj) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOA_TYPE_TP_ACCOUNT_LINKER, \
+                                GoaTpAccountLinkerPrivate))
+
+G_DEFINE_TYPE (GoaTpAccountLinker, goa_tp_account_linker, G_TYPE_OBJECT)
+
+struct _GoaTpAccountLinkerPrivate
+{
+  TpAccountManager *account_manager;
+  GoaClient *goa_client;
+
+  GHashTable *tp_accounts; /* owned gchar *id -> reffed TpAccount * */
+  GHashTable *goa_accounts; /* owned gchar *id -> reffed GoaObject * */
+};
+
+/* The path of the Telepathy account is used as common identifier between
+ * GOA and Telepathy */
+static const gchar *
+get_id_from_tp_account (TpAccount *tp_account)
+{
+  return tp_proxy_get_object_path (tp_account);
+}
+
+static const gchar *
+get_id_from_goa_account (GoaAccount *goa_account)
+{
+  return goa_account_get_identity (goa_account);
+}
+
+static gboolean
+is_telepathy_account (GoaAccount *goa_account)
+{
+  const gchar *type = goa_account_get_provider_type (goa_account);
+  return g_str_has_prefix (type, "telepathy/");
+}
+
+static void
+goa_account_chat_disabled_changed_cb (GoaAccount         *goa_account,
+                                      GParamSpec         *spec,
+                                      GoaTpAccountLinker *self)
+{
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  const gchar *id;
+  TpAccount *tp_account;
+  gboolean tp_enabled;
+  gboolean goa_enabled;
+
+  id = get_id_from_goa_account (goa_account);
+  tp_account = g_hash_table_lookup (priv->tp_accounts, id);
+  if (tp_account == NULL)
+    return;
+
+  goa_enabled = !goa_account_get_chat_disabled (goa_account);
+  tp_enabled = tp_account_is_enabled (tp_account);
+  if (tp_enabled != goa_enabled)
+    {
+      g_info ("The GOA account %s (Telepathy object path: %s) has been %s, "
+          "propagating to Telepathy",
+          goa_account_get_id (goa_account), id,
+          goa_enabled ? "enabled" : "disabled");
+      tp_account_set_enabled_async (tp_account, goa_enabled, NULL, NULL);
+    }
+}
+
+static void
+tp_account_chat_enabled_changed_cb (TpAccount          *tp_account,
+                                    GParamSpec         *spec,
+                                    GoaTpAccountLinker *self)
+{
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  const gchar *id;
+  GoaObject *goa_object;
+  GoaAccount *goa_account;
+  gboolean tp_enabled;
+  gboolean goa_enabled;
+
+  id = get_id_from_tp_account (tp_account);
+  goa_object = g_hash_table_lookup (priv->goa_accounts, id);
+  if (goa_object == NULL)
+    return;
+
+  goa_account = goa_object_peek_account (goa_object);
+  goa_enabled = !goa_account_get_chat_disabled (goa_account);
+  tp_enabled = tp_account_is_enabled (tp_account);
+  if (tp_enabled != goa_enabled)
+    {
+      g_info ("The Telepathy account %s has been %s, propagating to GOA",
+          id, tp_enabled ? "enabled" : "disabled");
+      /* When we set this property, the autogenerated code emits a notify
+       * signal immediately even if the property hasn't changed, so
+       * goa_account_chat_disabled_changed_cb() thinks that the property
+       * changed back to the old value and a cycle starts.
+       * The right notify signal will be emitted later when the property is
+       * actually changed. */
+      g_signal_handlers_block_by_func (goa_account,
+          goa_account_chat_disabled_changed_cb, self);
+      goa_account_set_chat_disabled (goa_account, !tp_enabled);
+      g_signal_handlers_unblock_by_func (goa_account,
+          goa_account_chat_disabled_changed_cb, self);
+    }
+}
+
+static void
+goa_account_created_cb (GoaManager   *manager,
+                        GAsyncResult *res,
+                        gpointer      user_data)
+{
+  TpAccount *tp_account = user_data;
+  gchar *goa_account_object_path = NULL;
+  GError *error = NULL;
+
+  if (!goa_manager_call_add_account_finish (manager,
+        &goa_account_object_path, res, &error))
+    {
+      g_critical ("Failed to create a GOA account for %s: %s (%s, %d)",
+          get_id_from_tp_account (tp_account),
+          error->message,
+          g_quark_to_string (error->domain),
+          error->code);
+      g_error_free (error);
+      goto out;
+    }
+
+  g_info ("Created new %s GOA account for Telepathy account %s",
+      goa_account_object_path, get_id_from_tp_account (tp_account));
+
+ out:
+  g_object_unref (tp_account);
+}
+
+static void
+create_goa_account (GoaTpAccountLinker *self,
+                    TpAccount          *tp_account)
+{
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  GVariantBuilder credentials;
+  GVariantBuilder details;
+  gchar *provider;
+
+  g_info ("Creating new GOA account for Telepathy account %s",
+      get_id_from_tp_account (tp_account));
+
+  g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
+
+  g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
+  g_variant_builder_add (&details, "{ss}", "ChatEnabled",
+      tp_account_is_enabled (tp_account) ? "true" : "false");
+
+  provider = g_strdup_printf ("telepathy/%s",
+      tp_account_get_protocol_name (tp_account));
+
+  goa_manager_call_add_account (goa_client_get_manager (priv->goa_client),
+      provider,
+      get_id_from_tp_account (tp_account),
+      tp_account_get_display_name (tp_account),
+      g_variant_builder_end (&credentials),
+      g_variant_builder_end (&details),
+      NULL, /* GCancellable* */
+      (GAsyncReadyCallback) goa_account_created_cb,
+      g_object_ref (tp_account));
+
+  g_free (provider);
+}
+
+static gboolean
+is_account_filtered (TpAccount *tp_account)
+{
+  const gchar *env;
+  const gchar *id;
+
+  env = g_getenv ("GOA_TELEPATHY_DEBUG_ACCOUNT_FILTER");
+  if (env == NULL || env[0] == '\0')
+    return FALSE;
+
+  id = get_id_from_tp_account (tp_account);
+  if (g_strstr_len (id, -1, env) != NULL)
+    return FALSE; /* "env" is contained in "id" */
+  else
+    return TRUE;
+}
+
+static void
+tp_account_added (GoaTpAccountLinker *self,
+                  TpAccount          *tp_account)
+{
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  const gchar *id = get_id_from_tp_account (tp_account);
+  GoaObject *goa_object = NULL;
+
+  if (g_strcmp0 (tp_account_get_storage_provider (tp_account),
+        "org.gnome.OnlineAccounts") == 0)
+    {
+      g_debug ("Skipping Telepathy account %s as it's handled directly by GOA", id);
+      return;
+    }
+
+  if (is_account_filtered (tp_account))
+    {
+      g_debug ("The account %s is ignored for debugging reasons", id);
+      return;
+    }
+
+  g_debug ("Telepathy account found: %s", id);
+
+  g_hash_table_replace (priv->tp_accounts, g_strdup (id),
+      g_object_ref (tp_account));
+
+  g_signal_connect_object (tp_account, "notify::enabled",
+      G_CALLBACK (tp_account_chat_enabled_changed_cb),
+      self, 0);
+
+  goa_object = g_hash_table_lookup (priv->goa_accounts, id);
+  if (goa_object == NULL)
+    {
+      g_debug ("Found a Telepathy account with no corresponding "
+          "GOA account: %s", id);
+      create_goa_account (self, tp_account);
+    }
+  else
+    {
+      g_debug ("Found a Telepathy account with a matching "
+          "GOA account: %s", id);
+      /* Make sure the initial state is synced. */
+      tp_account_chat_enabled_changed_cb (tp_account, NULL, self);
+    }
+}
+
+static void
+goa_account_removed_by_us_cb (GObject      *object,
+                              GAsyncResult *res,
+                              gpointer      user_data)
+{
+  /* This callback is only used for debugging */
+  GoaAccount *goa_account = GOA_ACCOUNT (object);
+  GError *error = NULL;
+
+  if (!goa_account_call_remove_finish (goa_account, res, &error))
+    {
+      g_critical ("Error removing GOA account %s (Telepathy object path: %s): "
+          "%s (%s, %d)",
+          goa_account_get_id (goa_account),
+          get_id_from_goa_account (goa_account),
+          error->message,
+          g_quark_to_string (error->domain),
+          error->code);
+      g_error_free (error);
+    }
+}
+
+static void
+tp_account_removed_cb (TpAccountManager *manager,
+                       TpAccount        *tp_account,
+                       gpointer          user_data)
+{
+  GoaTpAccountLinker *self = user_data;
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  const gchar *id = get_id_from_tp_account (tp_account);
+  GoaObject *goa_object = NULL;
+
+  if (!g_hash_table_remove (priv->tp_accounts, id))
+    {
+      /* 1 - The user removes the GOA account
+       * 2 - We delete the corresponding Telepathy account and remove it
+       *     from priv->tp_accounts
+       * 3 - "account-removed" is emitted by the account manager
+       * 4 - tp_account_removed_cb is called for an unknown account
+       */
+      g_debug ("Ignoring removal of Telepathy account we asked to "
+          "remove (%s)", id);
+      return;
+    }
+
+  g_info ("Telepathy account %s removed, removing corresponding "
+      "GOA account", id);
+
+  goa_object = g_hash_table_lookup (priv->goa_accounts, id);
+  if (goa_object == NULL)
+    {
+      g_critical ("There is no GOA account for removed Telepathy "
+          "account %s", id);
+      return;
+    }
+  goa_account_call_remove (goa_object_peek_account (goa_object),
+      NULL, /* cancellable */
+      goa_account_removed_by_us_cb, NULL);
+  g_hash_table_remove (priv->goa_accounts, id);
+}
+
+static void
+tp_account_validity_changed_cb (TpAccountManager *manager,
+                                TpAccount        *tp_account,
+                                gboolean          valid,
+                                gpointer          user_data)
+{
+  GoaTpAccountLinker *self = user_data;
+
+  if (valid)
+    tp_account_added (self, tp_account);
+}
+
+static void
+goa_account_added_cb (GoaClient *client,
+                      GoaObject *goa_object,
+                      gpointer   user_data)
+{
+  GoaTpAccountLinker *self = user_data;
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  GoaAccount *goa_account = goa_object_peek_account (goa_object);
+  const gchar *id = NULL;
+  TpAccount *tp_account;
+
+  if (!is_telepathy_account (goa_account))
+    return;
+
+  id = get_id_from_goa_account (goa_account);
+  g_debug ("GOA account %s for Telepathy account %s added",
+      goa_account_get_id (goa_account), id);
+
+  g_signal_connect_object (goa_account, "notify::chat-disabled",
+      G_CALLBACK (goa_account_chat_disabled_changed_cb), self, 0);
+
+  g_hash_table_insert (priv->goa_accounts, g_strdup (id),
+      g_object_ref (goa_object));
+
+  tp_account = g_hash_table_lookup (priv->tp_accounts, id);
+  if (tp_account != NULL)
+    {
+      /* The chat enabled status may have changed during the creation of the
+       * GOA account, so we need to make sure it's synced. */
+      tp_account_chat_enabled_changed_cb (tp_account, NULL, self);
+    }
+}
+
+static void
+tp_account_removed_by_us_cb (GObject      *object,
+                             GAsyncResult *res,
+                             gpointer      user_data)
+{
+  /* This callback is only used for debugging */
+  TpAccount *tp_account = TP_ACCOUNT (object);
+  GError *error = NULL;
+
+  if (!tp_account_remove_finish (tp_account, res, &error))
+    {
+      g_critical ("Error removing Telepathy account %s: %s (%s, %d)",
+          get_id_from_tp_account (tp_account),
+          error->message,
+          g_quark_to_string (error->domain),
+          error->code);
+      g_error_free (error);
+    }
+}
+
+static void
+goa_account_removed_cb (GoaClient *client,
+                        GoaObject *goa_object,
+                        gpointer   user_data)
+{
+  GoaTpAccountLinker *self = user_data;
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  GoaAccount *goa_account = goa_object_peek_account (goa_object);
+  const gchar *id = NULL;
+  TpAccount *tp_account = NULL;
+
+  if (!is_telepathy_account (goa_account))
+    return;
+
+  id = get_id_from_goa_account (goa_account);
+  if (!g_hash_table_remove (priv->goa_accounts, id))
+    {
+      /* 1 - The user removes the Telepathy account (but not the GOA one)
+       * 2 - We delete the corresponding GOA account and remove it
+       *     from priv->goa_accounts
+       * 3 - "account-removed" is emitted by the GOA client
+       * 4 - goa_account_removed_cb is called for an unknown account
+       */
+      g_debug ("Ignoring removal of GOA account we asked to remove "
+          "(%s, Telepathy object path: %s)",
+          goa_account_get_id (goa_account),
+          id);
+      return;
+    }
+
+  g_info ("GOA account %s for Telepathy account %s removed, "
+      "removing Telepathy account",
+      goa_account_get_id (goa_account), id);
+
+  tp_account = g_hash_table_lookup (priv->tp_accounts, id);
+  if (tp_account == NULL)
+    {
+      g_critical ("There is no Telepathy account for removed GOA "
+          "account %s (Telepathy object path: %s)",
+          goa_account_get_id (goa_account), id);
+      return;
+    }
+  tp_account_remove_async (tp_account, tp_account_removed_by_us_cb, NULL);
+  g_hash_table_remove (priv->tp_accounts, id);
+}
+
+static void
+start_if_ready (GoaTpAccountLinker *self)
+{
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  GList *goa_accounts = NULL;
+  GList *tp_accounts = NULL;
+  GList *l = NULL;
+  GHashTableIter iter;
+  gpointer key, value;
+
+  if (priv->goa_client == NULL ||
+      priv->account_manager == NULL ||
+      !tp_proxy_is_prepared (priv->account_manager,
+        TP_ACCOUNT_MANAGER_FEATURE_CORE))
+    {
+      /* Not everything is ready yet */
+      return;
+    }
+
+  g_debug ("Both GOA and Tp are ready, starting tracking of accounts");
+
+  /* GOA */
+  goa_accounts = goa_client_get_accounts (priv->goa_client);
+  for (l = goa_accounts; l != NULL; l = l->next)
+    goa_account_added_cb (priv->goa_client, l->data, self);
+  g_list_free_full (goa_accounts, g_object_unref);
+
+  g_signal_connect_object (priv->goa_client, "account-added",
+      G_CALLBACK (goa_account_added_cb), self, 0);
+  g_signal_connect_object (priv->goa_client, "account-removed",
+      G_CALLBACK (goa_account_removed_cb), self, 0);
+
+  /* Telepathy */
+  tp_accounts = tp_account_manager_dup_valid_accounts (priv->account_manager);
+  for (l = tp_accounts; l != NULL; l = l->next)
+    tp_account_added (self, l->data);
+  g_list_free_full (tp_accounts, g_object_unref);
+
+  g_signal_connect_object (priv->account_manager, "account-validity-changed",
+      G_CALLBACK (tp_account_validity_changed_cb), self, 0);
+  g_signal_connect_object (priv->account_manager, "account-removed",
+      G_CALLBACK (tp_account_removed_cb), self, 0);
+
+  /* Now we check if any Telepathy account was deleted while goa-daemon
+   * was not running. */
+  g_hash_table_iter_init (&iter, priv->goa_accounts);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      const gchar *id = key;
+      GoaObject *goa_object = value;
+
+      if (!g_hash_table_lookup (priv->tp_accounts, id))
+        {
+          g_warning ("The Telepathy account %s was removed while the daemon "
+              "was not running, removing the corresponding GOA account", id);
+          goa_account_call_remove (goa_object_peek_account (goa_object),
+              NULL, /* cancellable */
+              goa_account_removed_by_us_cb,
+              NULL); /* user data */
+        }
+    }
+}
+
+static void
+account_manager_prepared_cb (GObject      *object,
+                             GAsyncResult *res,
+                             gpointer      user_data)
+{
+  GoaTpAccountLinker *self = user_data;
+  GError *error = NULL;
+
+  if (!tp_proxy_prepare_finish (object, res, &error))
+    {
+      g_critical ("Error preparing AM: %s", error->message);
+      g_clear_error (&error);
+      return;
+    }
+
+  g_debug("Telepathy account manager prepared");
+  start_if_ready (self);
+}
+
+static void
+goa_client_new_cb (GObject      *object,
+                   GAsyncResult *result,
+                   gpointer      user_data)
+{
+  GoaTpAccountLinker *self = user_data;
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  GError *error = NULL;
+
+  priv->goa_client = goa_client_new_finish (result, &error);
+  if (priv->goa_client == NULL)
+    {
+      g_critical ("Error connecting to GOA: %s", error->message);
+      g_clear_error (&error);
+      return;
+    }
+
+  g_debug("GOA client ready");
+  start_if_ready (self);
+}
+
+static void
+goa_tp_account_linker_dispose (GObject *object)
+{
+  GoaTpAccountLinker *self = GOA_TP_ACCOUNT_LINKER (object);
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+
+  g_clear_object (&priv->account_manager);
+  g_clear_object (&priv->goa_client);
+
+  g_clear_pointer (&priv->goa_accounts, g_hash_table_unref);
+  g_clear_pointer (&priv->tp_accounts, g_hash_table_unref);
+
+  G_OBJECT_CLASS (goa_tp_account_linker_parent_class)->dispose (object);
+}
+
+static void
+goa_tp_account_linker_init (GoaTpAccountLinker *self)
+{
+  GoaTpAccountLinkerPrivate *priv;
+
+  g_debug ("Starting GOA <-> Telepathy account linker");
+
+  self->priv = GOA_TP_ACCOUNT_LINKER_GET_PRIVATE (self);
+  priv = self->priv;
+
+  priv->goa_accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
+      g_free, g_object_unref);
+  priv->tp_accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
+      g_free, g_object_unref);
+
+  priv->account_manager = tp_account_manager_dup ();
+  tp_proxy_prepare_async (priv->account_manager, NULL,
+      account_manager_prepared_cb, self);
+
+  goa_client_new (NULL, goa_client_new_cb, self);
+}
+
+static void
+goa_tp_account_linker_class_init (GoaTpAccountLinkerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  goa_utils_initialize_client_factory ();
+
+  g_type_class_add_private (gobject_class,
+      sizeof (GoaTpAccountLinkerPrivate));
+
+  gobject_class->dispose = goa_tp_account_linker_dispose;
+}
+
+GoaTpAccountLinker *
+goa_tp_account_linker_new (void)
+{
+  return g_object_new (GOA_TYPE_TP_ACCOUNT_LINKER, NULL);
+}
diff --git a/src/goabackend/goatpaccountlinker.h b/src/goabackend/goatpaccountlinker.h
new file mode 100644
index 000000000000..3f5b12955df0
--- /dev/null
+++ b/src/goabackend/goatpaccountlinker.h
@@ -0,0 +1,54 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2010-2013 Collabora Ltd.
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GOA_TP_ACCOUNT_LINKER_H__
+#define __GOA_TP_ACCOUNT_LINKER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_TP_ACCOUNT_LINKER           (goa_tp_account_linker_get_type ())
+#define GOA_TP_ACCOUNT_LINKER(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOA_TYPE_TP_ACCOUNT_LINKER, GoaTpAccountLinker))
+#define GOA_TP_ACCOUNT_LINKER_CLASS(obj)     (G_TYPE_CHECK_CLASS_CAST ((obj), GOA_TYPE_TP_ACCOUNT_LINKER, GoaTpAccountLinkerClass))
+#define GOA_IS_TP_ACCOUNT_LINKER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOA_TYPE_TP_ACCOUNT_LINKER))
+#define GOA_IS_TP_ACCOUNT_LINKER_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE ((obj), GOA_TYPE_TP_ACCOUNT_LINKER))
+#define GOA_TP_ACCOUNT_LINKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GOA_TYPE_TP_ACCOUNT_LINKER, GoaTpAccountLinkerClass))
+
+typedef struct _GoaTpAccountLinker        GoaTpAccountLinker;
+typedef struct _GoaTpAccountLinkerClass   GoaTpAccountLinkerClass;
+typedef struct _GoaTpAccountLinkerPrivate GoaTpAccountLinkerPrivate;
+
+struct _GoaTpAccountLinker
+{
+  GObject parent_instance;
+  GoaTpAccountLinkerPrivate *priv;
+};
+
+struct _GoaTpAccountLinkerClass
+{
+  GObjectClass parent_class;
+};
+
+GType               goa_tp_account_linker_get_type      (void) G_GNUC_CONST;
+GoaTpAccountLinker *goa_tp_account_linker_new           (void);
+
+G_END_DECLS
+
+#endif
-- 
2.5.5


From d26e6f3c6ec826ec16aaa298eaf3cca66bab33f1 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Wed, 1 Jun 2016 19:53:44 +0200
Subject: [PATCH 21/22] tplinker: Shuffle some code around

This will make the subsequent commit easier to read.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goabackend/goatpaccountlinker.c | 40 ++++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/src/goabackend/goatpaccountlinker.c b/src/goabackend/goatpaccountlinker.c
index dcdf3f761ca7..71255ec6cff9 100644
--- a/src/goabackend/goatpaccountlinker.c
+++ b/src/goabackend/goatpaccountlinker.c
@@ -68,6 +68,26 @@ is_telepathy_account (GoaAccount *goa_account)
 }
 
 static void
+tp_account_removed_by_us_cb (GObject      *object,
+                             GAsyncResult *res,
+                             gpointer      user_data)
+{
+  /* This callback is only used for debugging */
+  TpAccount *tp_account = TP_ACCOUNT (object);
+  GError *error = NULL;
+
+  if (!tp_account_remove_finish (tp_account, res, &error))
+    {
+      g_critical ("Error removing Telepathy account %s: %s (%s, %d)",
+          get_id_from_tp_account (tp_account),
+          error->message,
+          g_quark_to_string (error->domain),
+          error->code);
+      g_error_free (error);
+    }
+}
+
+static void
 goa_account_chat_disabled_changed_cb (GoaAccount         *goa_account,
                                       GParamSpec         *spec,
                                       GoaTpAccountLinker *self)
@@ -365,26 +385,6 @@ goa_account_added_cb (GoaClient *client,
 }
 
 static void
-tp_account_removed_by_us_cb (GObject      *object,
-                             GAsyncResult *res,
-                             gpointer      user_data)
-{
-  /* This callback is only used for debugging */
-  TpAccount *tp_account = TP_ACCOUNT (object);
-  GError *error = NULL;
-
-  if (!tp_account_remove_finish (tp_account, res, &error))
-    {
-      g_critical ("Error removing Telepathy account %s: %s (%s, %d)",
-          get_id_from_tp_account (tp_account),
-          error->message,
-          g_quark_to_string (error->domain),
-          error->code);
-      g_error_free (error);
-    }
-}
-
-static void
 goa_account_removed_cb (GoaClient *client,
                         GoaObject *goa_object,
                         gpointer   user_data)
-- 
2.5.5


From d73bb711099d6c24e7cef82de43dda2747d7d6c3 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <debarshir@gnome.org>
Date: Wed, 1 Jun 2016 20:00:08 +0200
Subject: [PATCH 22/22] telepathy: Use GoaProvider:remove_account for deleting
 the TpAccount

... instead of listening to GoaClient::account-removed.

API was added to GoaTpAccountLinker to explicitly request the removal
of the TpAccount. This is used by GoaTelepathyProvider in its
GoaProvider:remove_account implementation.

https://bugzilla.gnome.org/show_bug.cgi?id=766733
---
 src/goabackend/goatelepathyprovider.c |  63 ++++++++++++
 src/goabackend/goatpaccountlinker.c   | 178 ++++++++++++++++++++++++----------
 src/goabackend/goatpaccountlinker.h   |  10 ++
 3 files changed, 200 insertions(+), 51 deletions(-)

diff --git a/src/goabackend/goatelepathyprovider.c b/src/goabackend/goatelepathyprovider.c
index 8a390c82e0c6..3d76080d0751 100644
--- a/src/goabackend/goatelepathyprovider.c
+++ b/src/goabackend/goatelepathyprovider.c
@@ -787,6 +787,67 @@ out:
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static void
+remove_account_remove_tp_account_cb (GObject       *source_object,
+                                     GAsyncResult  *res,
+                                     gpointer       user_data)
+{
+  GError *error;
+  GTask *task = G_TASK (user_data);
+
+  error = NULL;
+  if (!goa_tp_account_linker_remove_tp_account_finish (tp_linker, res, &error))
+    {
+      g_task_return_error (task, error);
+      goto out;
+    }
+
+  g_task_return_boolean (task, TRUE);
+
+ out:
+  g_object_unref (task);
+}
+
+static void
+remove_account (GoaProvider          *provider,
+                GoaObject            *object,
+                GCancellable         *cancellable,
+                GAsyncReadyCallback   callback,
+                gpointer              user_data)
+{
+  GoaTelepathyProvider *self = GOA_TELEPATHY_PROVIDER (provider);
+  GTask *task;
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, remove_account);
+
+  goa_tp_account_linker_remove_tp_account (tp_linker,
+                                           object,
+                                           cancellable,
+                                           remove_account_remove_tp_account_cb,
+                                           g_object_ref (task));
+
+  g_object_unref (task);
+}
+
+static gboolean
+remove_account_finish (GoaProvider   *provider,
+                       GAsyncResult  *res,
+                       GError       **error)
+{
+  GoaTelepathyProvider *self = GOA_TELEPATHY_PROVIDER (provider);
+  GTask *task;
+
+  g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
+  task = G_TASK (res);
+
+  g_warn_if_fail (g_task_get_source_tag (task) == remove_account);
+
+  return g_task_propagate_boolean (task, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 typedef struct
 {
   guint ref_count;
@@ -1067,6 +1128,8 @@ goa_telepathy_provider_class_init (GoaTelepathyProviderClass *klass)
   provider_class->add_account           = add_account;
   provider_class->refresh_account       = refresh_account;
   provider_class->build_object          = build_object;
+  provider_class->remove_account        = remove_account;
+  provider_class->remove_account_finish = remove_account_finish;
   provider_class->show_account          = show_account;
 
   g_type_class_add_private (object_class, sizeof (GoaTelepathyProviderPrivate));
diff --git a/src/goabackend/goatpaccountlinker.c b/src/goabackend/goatpaccountlinker.c
index 71255ec6cff9..aa9f01e839c0 100644
--- a/src/goabackend/goatpaccountlinker.c
+++ b/src/goabackend/goatpaccountlinker.c
@@ -28,7 +28,6 @@
 #include <telepathy-glib/telepathy-glib.h>
 
 #include "goatpaccountlinker.h"
-#include "goa/goa.h"
 #include "goabackend/goautils.h"
 
 #define GOA_TP_ACCOUNT_LINKER_GET_PRIVATE(obj) \
@@ -44,6 +43,8 @@ struct _GoaTpAccountLinkerPrivate
 
   GHashTable *tp_accounts; /* owned gchar *id -> reffed TpAccount * */
   GHashTable *goa_accounts; /* owned gchar *id -> reffed GoaObject * */
+
+  GQueue *remove_tp_account_queue;
 };
 
 /* The path of the Telepathy account is used as common identifier between
@@ -72,9 +73,9 @@ tp_account_removed_by_us_cb (GObject      *object,
                              GAsyncResult *res,
                              gpointer      user_data)
 {
-  /* This callback is only used for debugging */
   TpAccount *tp_account = TP_ACCOUNT (object);
   GError *error = NULL;
+  GTask *task = G_TASK (user_data);
 
   if (!tp_account_remove_finish (tp_account, res, &error))
     {
@@ -83,8 +84,80 @@ tp_account_removed_by_us_cb (GObject      *object,
           error->message,
           g_quark_to_string (error->domain),
           error->code);
-      g_error_free (error);
+      g_task_return_error (task, error);
+      goto out;
+    }
+
+  g_task_return_boolean (task, TRUE);
+
+ out:
+  g_object_unref (task);
+}
+
+static void
+remove_tp_account_queue_check (GoaTpAccountLinker *self)
+{
+  GoaTpAccountLinkerPrivate *priv = self->priv;
+  GList *l;
+
+  if (priv->goa_client == NULL ||
+      priv->account_manager == NULL ||
+      !tp_proxy_is_prepared (priv->account_manager, TP_ACCOUNT_MANAGER_FEATURE_CORE))
+    {
+      /* Not everything is ready yet */
+      return;
+    }
+
+  if (priv->remove_tp_account_queue->length == 0)
+    return;
+
+  for (l = priv->remove_tp_account_queue->head; l != NULL; l = l->next)
+    {
+      GTask *task = G_TASK (l->data);
+      GoaAccount *goa_account;
+      GoaObject *goa_object;
+      TpAccount *tp_account;
+      const gchar *id;
+
+      goa_object = GOA_OBJECT (g_task_get_task_data (task));
+      goa_account = goa_object_peek_account (goa_object);
+
+      id = get_id_from_goa_account (goa_account);
+      if (!g_hash_table_remove (priv->goa_accounts, id))
+        {
+          /* 1 - The user removes the Telepathy account (but not the GOA one)
+           * 2 - We delete the corresponding GOA account and remove it
+           *     from priv->goa_accounts
+           * 3 - The Telepathy provider again tries to remove the
+           *     corresponding Telepathy account
+           */
+          g_debug ("Ignoring removal of GOA account we asked to remove "
+                   "(%s, Telepathy object path: %s)",
+                   goa_account_get_id (goa_account),
+                   id);
+          g_task_return_boolean (task, TRUE);
+          continue;
+        }
+
+      g_info ("GOA account %s for Telepathy account %s removed, "
+              "removing Telepathy account",
+              goa_account_get_id (goa_account), id);
+
+      tp_account = g_hash_table_lookup (priv->tp_accounts, id);
+      if (tp_account == NULL)
+        {
+          g_critical ("There is no Telepathy account for removed GOA "
+                      "account %s (Telepathy object path: %s)",
+                      goa_account_get_id (goa_account), id);
+          g_task_return_boolean (task, TRUE);
+          continue;
+        }
+      tp_account_remove_async (tp_account, tp_account_removed_by_us_cb, g_object_ref (task));
+      g_hash_table_remove (priv->tp_accounts, id);
     }
+
+  g_queue_foreach (priv->remove_tp_account_queue, (GFunc) g_object_unref, NULL);
+  g_queue_clear (priv->remove_tp_account_queue);
 }
 
 static void
@@ -385,52 +458,6 @@ goa_account_added_cb (GoaClient *client,
 }
 
 static void
-goa_account_removed_cb (GoaClient *client,
-                        GoaObject *goa_object,
-                        gpointer   user_data)
-{
-  GoaTpAccountLinker *self = user_data;
-  GoaTpAccountLinkerPrivate *priv = self->priv;
-  GoaAccount *goa_account = goa_object_peek_account (goa_object);
-  const gchar *id = NULL;
-  TpAccount *tp_account = NULL;
-
-  if (!is_telepathy_account (goa_account))
-    return;
-
-  id = get_id_from_goa_account (goa_account);
-  if (!g_hash_table_remove (priv->goa_accounts, id))
-    {
-      /* 1 - The user removes the Telepathy account (but not the GOA one)
-       * 2 - We delete the corresponding GOA account and remove it
-       *     from priv->goa_accounts
-       * 3 - "account-removed" is emitted by the GOA client
-       * 4 - goa_account_removed_cb is called for an unknown account
-       */
-      g_debug ("Ignoring removal of GOA account we asked to remove "
-          "(%s, Telepathy object path: %s)",
-          goa_account_get_id (goa_account),
-          id);
-      return;
-    }
-
-  g_info ("GOA account %s for Telepathy account %s removed, "
-      "removing Telepathy account",
-      goa_account_get_id (goa_account), id);
-
-  tp_account = g_hash_table_lookup (priv->tp_accounts, id);
-  if (tp_account == NULL)
-    {
-      g_critical ("There is no Telepathy account for removed GOA "
-          "account %s (Telepathy object path: %s)",
-          goa_account_get_id (goa_account), id);
-      return;
-    }
-  tp_account_remove_async (tp_account, tp_account_removed_by_us_cb, NULL);
-  g_hash_table_remove (priv->tp_accounts, id);
-}
-
-static void
 start_if_ready (GoaTpAccountLinker *self)
 {
   GoaTpAccountLinkerPrivate *priv = self->priv;
@@ -459,8 +486,6 @@ start_if_ready (GoaTpAccountLinker *self)
 
   g_signal_connect_object (priv->goa_client, "account-added",
       G_CALLBACK (goa_account_added_cb), self, 0);
-  g_signal_connect_object (priv->goa_client, "account-removed",
-      G_CALLBACK (goa_account_removed_cb), self, 0);
 
   /* Telepathy */
   tp_accounts = tp_account_manager_dup_valid_accounts (priv->account_manager);
@@ -491,6 +516,8 @@ start_if_ready (GoaTpAccountLinker *self)
               NULL); /* user data */
         }
     }
+
+  remove_tp_account_queue_check (self);
 }
 
 static void
@@ -539,6 +566,12 @@ goa_tp_account_linker_dispose (GObject *object)
   GoaTpAccountLinker *self = GOA_TP_ACCOUNT_LINKER (object);
   GoaTpAccountLinkerPrivate *priv = self->priv;
 
+  if (priv->remove_tp_account_queue != NULL)
+    {
+      g_queue_free_full (priv->remove_tp_account_queue, g_object_unref);
+      priv->remove_tp_account_queue = NULL;
+    }
+
   g_clear_object (&priv->account_manager);
   g_clear_object (&priv->goa_client);
 
@@ -563,6 +596,8 @@ goa_tp_account_linker_init (GoaTpAccountLinker *self)
   priv->tp_accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
       g_free, g_object_unref);
 
+  priv->remove_tp_account_queue = g_queue_new ();
+
   priv->account_manager = tp_account_manager_dup ();
   tp_proxy_prepare_async (priv->account_manager, NULL,
       account_manager_prepared_cb, self);
@@ -588,3 +623,44 @@ goa_tp_account_linker_new (void)
 {
   return g_object_new (GOA_TYPE_TP_ACCOUNT_LINKER, NULL);
 }
+
+void
+goa_tp_account_linker_remove_tp_account (GoaTpAccountLinker   *self,
+                                         GoaObject            *object,
+                                         GCancellable         *cancellable,
+                                         GAsyncReadyCallback   callback,
+                                         gpointer              user_data)
+{
+  GoaTpAccountLinkerPrivate *priv;
+  GTask *task;
+
+  g_return_if_fail (GOA_IS_TP_ACCOUNT_LINKER (self));
+  priv = self->priv;
+
+  g_return_if_fail (GOA_IS_OBJECT (object));
+  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, goa_tp_account_linker_remove_tp_account);
+  g_task_set_task_data (task, g_object_ref (object), g_object_unref);
+  g_queue_push_tail (priv->remove_tp_account_queue, g_object_ref (task));
+
+  remove_tp_account_queue_check (self);
+
+  g_object_unref (task);
+}
+
+gboolean
+goa_tp_account_linker_remove_tp_account_finish (GoaTpAccountLinker  *self,
+                                                GAsyncResult        *res,
+                                                GError             **error)
+{
+  GTask *task;
+
+  g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
+  task = G_TASK (res);
+
+  g_warn_if_fail (g_task_get_source_tag (task) == goa_tp_account_linker_remove_tp_account);
+
+  return g_task_propagate_boolean (task, error);
+}
diff --git a/src/goabackend/goatpaccountlinker.h b/src/goabackend/goatpaccountlinker.h
index 3f5b12955df0..8c7efd8a956e 100644
--- a/src/goabackend/goatpaccountlinker.h
+++ b/src/goabackend/goatpaccountlinker.h
@@ -22,6 +22,8 @@
 
 #include <glib-object.h>
 
+#include "goa/goa.h"
+
 G_BEGIN_DECLS
 
 #define GOA_TYPE_TP_ACCOUNT_LINKER           (goa_tp_account_linker_get_type ())
@@ -48,6 +50,14 @@ struct _GoaTpAccountLinkerClass
 
 GType               goa_tp_account_linker_get_type      (void) G_GNUC_CONST;
 GoaTpAccountLinker *goa_tp_account_linker_new           (void);
+void                goa_tp_account_linker_remove_tp_account        (GoaTpAccountLinker   *self,
+                                                                    GoaObject            *object,
+                                                                    GCancellable         *cancellable,
+                                                                    GAsyncReadyCallback   callback,
+                                                                    gpointer              user_data);
+gboolean            goa_tp_account_linker_remove_tp_account_finish (GoaTpAccountLinker   *self,
+                                                                    GAsyncResult         *res,
+                                                                    GError              **error);
 
 G_END_DECLS
 
-- 
2.5.5