]> git.0d.be Git - empathy.git/blobdiff - src/empathy-sanity-cleaning.c
Updated Spanish translation
[empathy.git] / src / empathy-sanity-cleaning.c
index 7437be47d890acb65c7064e9373f710601e8bed7..a1a097db43208367a8638e2b48081bc200498c27 100644 (file)
  */
 
 #include "config.h"
-
 #include "empathy-sanity-cleaning.h"
 
-#include <telepathy-glib/telepathy-glib.h>
+#ifdef HAVE_UOA
+#include <libaccounts-glib/ag-account-service.h>
+#include <libaccounts-glib/ag-manager.h>
+#include <libaccounts-glib/ag-service.h>
+#include <tp-account-widgets/tpaw-keyring.h>
+#include <tp-account-widgets/tpaw-uoa-utils.h>
 
-#include <libempathy/empathy-gsettings.h>
+#include "empathy-pkg-kit.h"
+#endif
 
-#include <libempathy-gtk/empathy-theme-manager.h>
+#include "empathy-gsettings.h"
+#include "empathy-theme-manager.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
-#include <libempathy/empathy-debug.h>
+#include "empathy-debug.h"
 
 /*
  * This number has to be increased each time a new task is added or modified.
  * If the number stored in gsettings is lower than it, all the tasks will
  * be executed.
  */
-#define SANITY_CLEANING_NUMBER 3
+#define SANITY_CLEANING_NUMBER 4
+
+typedef struct
+{
+  TpAccountManager *am;
+  GSimpleAsyncResult *result;
+
+  gint ref_count;
+} SanityCtx;
+
+static SanityCtx *
+sanity_ctx_new (TpAccountManager *am,
+    GSimpleAsyncResult *result)
+{
+  SanityCtx *ctx = g_slice_new0 (SanityCtx);
+
+  ctx->am = g_object_ref (am);
+  ctx->result = g_object_ref (result);
+
+  ctx->ref_count = 1;
+  return ctx;
+}
+
+#ifdef HAVE_UOA
+static SanityCtx *
+sanity_ctx_ref (SanityCtx *ctx)
+{
+  ctx->ref_count++;
+
+  return ctx;
+}
+#endif
+
+static void
+sanity_ctx_unref (SanityCtx *ctx)
+{
+  ctx->ref_count--;
+
+  if (ctx->ref_count != 0)
+    return;
+
+  g_simple_async_result_complete_in_idle (ctx->result);
+
+  g_object_unref (ctx->am);
+  g_object_unref (ctx->result);
+
+  g_slice_free (SanityCtx, ctx);
+}
 
 static void
 account_update_parameters_cb (GObject *source,
@@ -68,7 +121,7 @@ fix_xmpp_account_priority (TpAccountManager *am)
 {
   GList *accounts, *l;
 
-  accounts = tp_account_manager_get_valid_accounts (am);
+  accounts = tp_account_manager_dup_valid_accounts (am);
   for (l = accounts; l != NULL; l = g_list_next (l))
     {
       TpAccount *account = l->data;
@@ -99,7 +152,7 @@ fix_xmpp_account_priority (TpAccountManager *am)
       g_hash_table_unref (params);
     }
 
-  g_list_free (accounts);
+  g_list_free_full (accounts, g_object_unref);
 }
 
 static void
@@ -107,7 +160,7 @@ set_facebook_account_fallback_server (TpAccountManager *am)
 {
   GList *accounts, *l;
 
-  accounts = tp_account_manager_get_valid_accounts (am);
+  accounts = tp_account_manager_dup_valid_accounts (am);
   for (l = accounts; l != NULL; l = g_list_next (l))
     {
       TpAccount *account = l->data;
@@ -139,7 +192,7 @@ set_facebook_account_fallback_server (TpAccountManager *am)
       g_hash_table_unref (params);
     }
 
-  g_list_free (accounts);
+  g_list_free_full (accounts, g_object_unref);
 }
 
 static void
@@ -198,14 +251,332 @@ finally:
   g_object_unref (gsettings_chat);
 }
 
+#ifdef HAVE_UOA
+typedef struct
+{
+  TpAccount *new_account;
+  TpAccount *old_account;
+  gboolean enabled;
+} UoaMigrationData;
+
+static UoaMigrationData *
+uoa_migration_data_new (TpAccount *account)
+{
+  UoaMigrationData *data;
+
+  data = g_slice_new0 (UoaMigrationData);
+  data->old_account = g_object_ref (account);
+  data->enabled = tp_account_is_enabled (account);
+
+  return data;
+}
+
+static void
+uoa_migration_data_free (UoaMigrationData *data)
+{
+  g_clear_object (&data->new_account);
+  g_clear_object (&data->old_account);
+  g_slice_free (UoaMigrationData, data);
+}
+
+#define DATA_SANITY_CTX "data-sanity-ctx"
+
+static void
+uoa_account_remove_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  TpAccount *account = TP_ACCOUNT (source);
+  GError *error = NULL;
+
+  if (!tp_account_remove_finish (account, result, &error))
+    {
+      DEBUG ("Failed to remove account '%s': %s",
+          tp_account_get_path_suffix (account), error->message);
+      g_error_free (error);
+    }
+
+  g_object_set_data (G_OBJECT (account), DATA_SANITY_CTX, NULL);
+}
+
+static void
+uoa_migration_done (UoaMigrationData *data)
+{
+  tp_account_remove_async (data->old_account, uoa_account_remove_cb, NULL);
+
+  if (data->new_account != NULL)
+    tp_account_set_enabled_async (data->new_account, data->enabled, NULL, NULL);
+
+  uoa_migration_data_free (data);
+}
+
+static void
+uoa_set_account_password_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  UoaMigrationData *data = user_data;
+  GError *error = NULL;
+
+  if (!tpaw_keyring_set_account_password_finish (data->new_account, result,
+          &error))
+    {
+      DEBUG ("Error setting old account's password on the new one: %s\n",
+          error->message);
+      g_clear_error (&error);
+    }
+
+  uoa_migration_done (data);
+}
+
+static void
+uoa_get_account_password_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  UoaMigrationData *data = user_data;
+  const gchar *password;
+  GError *error = NULL;
+
+  password = tpaw_keyring_get_account_password_finish (data->old_account,
+      result, &error);
+  if (password == NULL)
+    {
+      DEBUG ("Error getting old account's password: %s\n", error->message);
+      g_clear_error (&error);
+
+      uoa_migration_done (data);
+    }
+  else
+    {
+      tpaw_keyring_set_account_password_async (data->new_account, password,
+          TRUE, uoa_set_account_password_cb, data);
+    }
+}
+
+static void
+uoa_account_created_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  TpAccountRequest *ar = (TpAccountRequest *) source;
+  UoaMigrationData *data = user_data;
+  GError *error = NULL;
+
+  data->new_account = tp_account_request_create_account_finish (ar, result,
+      &error);
+  if (data->new_account == NULL)
+    {
+      DEBUG ("Failed to migrate account '%s' to UOA: %s",
+          tp_account_get_path_suffix (data->old_account), error->message);
+      g_clear_error (&error);
+
+      uoa_migration_done (data);
+    }
+  else
+    {
+      DEBUG ("New account %s created to superseed %s",
+          tp_account_get_path_suffix (data->new_account),
+          tp_account_get_path_suffix (data->old_account));
+
+      /* Migrate password as well */
+      tpaw_keyring_get_account_password_async (data->old_account,
+          uoa_get_account_password_cb, data);
+    }
+}
+
+static void
+migrate_account_to_uoa (TpAccountManager *am,
+    TpAccount *account)
+{
+  TpAccountRequest *ar;
+  GVariant *params;
+  GVariant *param;
+  GVariantIter iter;
+  const gchar * const *supersedes;
+  guint i;
+  UoaMigrationData *data;
+
+  DEBUG ("Migrating account %s to UOA storage\n",
+      tp_account_get_path_suffix (account));
+
+  ar = tp_account_request_new (am,
+      tp_account_get_cm_name (account),
+      tp_account_get_protocol_name (account),
+      tp_account_get_display_name (account));
+  tp_account_request_set_storage_provider (ar, EMPATHY_UOA_PROVIDER);
+  tp_account_request_set_icon_name (ar,
+      tp_account_get_icon_name (account));
+  tp_account_request_set_nickname (ar,
+      tp_account_get_nickname (account));
+  tp_account_request_set_service (ar,
+      tp_account_get_service (account));
+
+  /* Do not enable the new account until we imported the password as well */
+  tp_account_request_set_enabled (ar, FALSE);
+
+  supersedes = tp_account_get_supersedes (account);
+
+  for (i = 0; supersedes[i] != NULL; i++)
+    tp_account_request_add_supersedes (ar, supersedes[i]);
+
+  tp_account_request_add_supersedes (ar,
+      tp_proxy_get_object_path (account));
+
+  params = tp_account_dup_parameters_vardict (account);
+  g_variant_iter_init (&iter, params);
+  while ((param = g_variant_iter_next_value (&iter)))
+    {
+      GVariant *k, *v;
+      const gchar *key;
+
+      k = g_variant_get_child_value (param, 0);
+      key = g_variant_get_string (k, NULL);
+      v = g_variant_get_child_value (param, 1);
+
+      tp_account_request_set_parameter (ar, key,
+          g_variant_get_variant (v));
+
+      g_variant_unref (k);
+      g_variant_unref (v);
+    }
+
+  data = uoa_migration_data_new (account);
+  tp_account_set_enabled_async (account, FALSE, NULL, NULL);
+  tp_account_request_create_account_async (ar, uoa_account_created_cb,
+      data);
+
+  g_variant_unref (params);
+  g_object_unref (ar);
+}
+
+static void
+uoa_plugin_install_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  TpAccount *account = user_data;
+  GError *error = NULL;
+  TpAccountManager *am;
+
+  if (!empathy_pkg_kit_install_packages_finish (result, &error))
+    {
+      DEBUG ("Failed to install plugin for account '%s' (%s); remove it",
+          tp_account_get_path_suffix (account), error->message);
+
+      g_error_free (error);
+
+      tp_account_remove_async (account, uoa_account_remove_cb, NULL);
+      goto out;
+    }
+
+  DEBUG ("Plugin for account '%s' has been installed; migrate account",
+      tp_account_get_path_suffix (account));
+
+  am = tp_account_manager_dup ();
+  migrate_account_to_uoa (am, account);
+  g_object_unref (am);
+
+out:
+  g_object_unref (account);
+}
+
+static gchar *
+dup_plugin_name_for_protocol (const gchar *protocol)
+{
+  if (!tp_strdiff (protocol, "local-xmpp"))
+    return g_strdup ("account-plugin-salut");
+
+  return g_strdup_printf ("account-plugin-%s", protocol);
+}
+
+static gboolean
+uoa_plugin_installed (AgManager *manager,
+    TpAccount *account)
+{
+  AgAccount *ag_account;
+  const gchar *protocol;
+  GList *l;
+
+  protocol = tp_account_get_protocol_name (account);
+  ag_account = ag_manager_create_account (manager, protocol);
+
+  l = ag_account_list_services_by_type (ag_account, TPAW_UOA_SERVICE_TYPE);
+  if (l == NULL)
+    {
+      const gchar *packages[2];
+      gchar *pkg;
+
+      pkg = dup_plugin_name_for_protocol (protocol);
+
+      DEBUG ("%s is not installed; try to install it", pkg);
+
+      packages[0] = pkg;
+      packages[1] = NULL;
+
+      empathy_pkg_kit_install_packages_async (0, packages, NULL,
+          NULL, uoa_plugin_install_cb, g_object_ref (account));
+
+      g_free (pkg);
+      g_object_unref (ag_account);
+      return FALSE;
+    }
+
+  ag_service_list_free (l);
+
+  g_object_unref (ag_account);
+  return TRUE;
+}
+
+static void
+migrate_accounts_to_uoa (SanityCtx *ctx)
+{
+  GList *accounts, *l;
+  AgManager *manager;
+
+  DEBUG ("Start migrating accounts to UOA");
+
+  manager = tpaw_uoa_manager_dup ();
+
+  accounts = tp_account_manager_dup_valid_accounts (ctx->am);
+  for (l = accounts; l != NULL; l = g_list_next (l))
+    {
+      TpAccount *account = l->data;
+
+      /* If account is already in a specific storage (like UOA or GOA),
+       * don't migrate it.
+       * Note that we cannot migrate GOA accounts anyway, since we can't delete
+       * them it would create duplicated accounts. */
+      if (!tp_str_empty (tp_account_get_storage_provider (account)))
+        continue;
+
+      g_object_set_data_full (G_OBJECT (account), DATA_SANITY_CTX,
+          sanity_ctx_ref (ctx), (GDestroyNotify) sanity_ctx_unref);
+
+      /* Try to install the plugin if it's missing */
+      if (!uoa_plugin_installed (manager, account))
+        continue;
+
+      migrate_account_to_uoa (ctx->am, account);
+    }
+
+  g_list_free_full (accounts, g_object_unref);
+
+  g_object_unref (manager);
+}
+#endif
+
 static void
-run_sanity_cleaning_tasks (TpAccountManager *am)
+run_sanity_cleaning_tasks (SanityCtx *ctx)
 {
   DEBUG ("Starting sanity cleaning tasks");
 
-  fix_xmpp_account_priority (am);
-  set_facebook_account_fallback_server (am);
+  fix_xmpp_account_priority (ctx->am);
+  set_facebook_account_fallback_server (ctx->am);
   upgrade_chat_theme_settings ();
+#ifdef HAVE_UOA
+  migrate_accounts_to_uoa (ctx);
+#endif
 }
 
 static void
@@ -215,37 +586,68 @@ am_prepare_cb (GObject *source,
 {
   GError *error = NULL;
   TpAccountManager *am = TP_ACCOUNT_MANAGER (source);
+  SanityCtx *ctx = user_data;
 
   if (!tp_proxy_prepare_finish (am, result, &error))
     {
       DEBUG ("Failed to prepare account manager: %s", error->message);
-      g_error_free (error);
-      return;
+      g_simple_async_result_take_error (ctx->result, error);
+      goto out;
     }
 
-  run_sanity_cleaning_tasks (am);
+  run_sanity_cleaning_tasks (ctx);
+
+out:
+  sanity_ctx_unref (ctx);
 }
 
-void empathy_sanity_checking_run_if_needed (void)
+void
+empathy_sanity_checking_run_async (GAsyncReadyCallback callback,
+    gpointer user_data)
 {
   GSettings *settings;
   guint number;
   TpAccountManager *am;
+  GSimpleAsyncResult *result;
+  SanityCtx *ctx;
+
+  result = g_simple_async_result_new (NULL, callback, user_data,
+      empathy_sanity_checking_run_async);
 
   settings = g_settings_new (EMPATHY_PREFS_SCHEMA);
   number = g_settings_get_uint (settings, EMPATHY_PREFS_SANITY_CLEANING_NUMBER);
 
   if (number == SANITY_CLEANING_NUMBER)
-    goto out;
+    {
+      g_simple_async_result_complete_in_idle (result);
+      goto out;
+    }
 
   am = tp_account_manager_dup ();
 
-  tp_proxy_prepare_async (am, NULL, am_prepare_cb, NULL);
+  ctx = sanity_ctx_new (am, result);
+  tp_proxy_prepare_async (am, NULL, am_prepare_cb, ctx);
 
   g_settings_set_uint (settings, EMPATHY_PREFS_SANITY_CLEANING_NUMBER,
       SANITY_CLEANING_NUMBER);
 
   g_object_unref (am);
+
 out:
   g_object_unref (settings);
+  g_object_unref (result);
+}
+
+gboolean
+empathy_sanity_checking_run_finish (GAsyncResult *result,
+    GError **error)
+{
+  g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+        empathy_sanity_checking_run_async), FALSE);
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
+        error))
+    return FALSE;
+
+  return TRUE;
 }