2 * empathy-sanity-cleaning.c
3 * Code automatically called when starting a specific version of Empathy for
4 * the first time doing misc cleaning.
6 * Copyright (C) 2012 Collabora Ltd.
7 * @author Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "empathy-sanity-cleaning.h"
28 #include <libaccounts-glib/ag-account-service.h>
29 #include <libaccounts-glib/ag-manager.h>
30 #include <libaccounts-glib/ag-service.h>
32 #include "empathy-pkg-kit.h"
33 #include "empathy-uoa-utils.h"
36 #include "empathy-gsettings.h"
37 #include "empathy-theme-manager.h"
39 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
40 #include "empathy-debug.h"
43 * This number has to be increased each time a new task is added or modified.
45 * If the number stored in gsettings is lower than it, all the tasks will
48 #define SANITY_CLEANING_NUMBER 4
53 GSimpleAsyncResult *result;
59 sanity_ctx_new (TpAccountManager *am,
60 GSimpleAsyncResult *result)
62 SanityCtx *ctx = g_slice_new0 (SanityCtx);
64 ctx->am = g_object_ref (am);
65 ctx->result = g_object_ref (result);
73 sanity_ctx_ref (SanityCtx *ctx)
82 sanity_ctx_unref (SanityCtx *ctx)
86 if (ctx->ref_count != 0)
89 g_simple_async_result_complete_in_idle (ctx->result);
91 g_object_unref (ctx->am);
92 g_object_unref (ctx->result);
94 g_slice_free (SanityCtx, ctx);
98 account_update_parameters_cb (GObject *source,
102 GError *error = NULL;
103 TpAccount *account = TP_ACCOUNT (source);
105 if (!tp_account_update_parameters_finish (account, result, NULL, &error))
107 DEBUG ("Failed to update parameters of account '%s': %s",
108 tp_account_get_path_suffix (account), error->message);
110 g_error_free (error);
114 tp_account_reconnect_async (account, NULL, NULL);
117 /* Make sure XMPP accounts don't have a negative priority (bgo #671452) */
119 fix_xmpp_account_priority (TpAccountManager *am)
123 accounts = tp_account_manager_dup_valid_accounts (am);
124 for (l = accounts; l != NULL; l = g_list_next (l))
126 TpAccount *account = l->data;
130 if (tp_strdiff (tp_account_get_protocol_name (account), "jabber"))
133 params = (GHashTable *) tp_account_get_parameters (account);
137 priority = tp_asv_get_int32 (params, "priority", NULL);
141 DEBUG ("Resetting XMPP priority of account '%s' to 0",
142 tp_account_get_path_suffix (account));
144 params = tp_asv_new (
145 "priority", G_TYPE_INT, 0,
148 tp_account_update_parameters_async (account, params, NULL,
149 account_update_parameters_cb, NULL);
151 g_hash_table_unref (params);
154 g_list_free_full (accounts, g_object_unref);
158 set_facebook_account_fallback_server (TpAccountManager *am)
162 accounts = tp_account_manager_dup_valid_accounts (am);
163 for (l = accounts; l != NULL; l = g_list_next (l))
165 TpAccount *account = l->data;
167 gchar *fallback_servers[] = {
168 "chat.facebook.com:443",
171 if (tp_strdiff (tp_account_get_service (account), "facebook"))
174 params = (GHashTable *) tp_account_get_parameters (account);
178 if (tp_asv_get_strv (params, "fallback-servers") != NULL)
181 DEBUG ("Setting chat.facebook.com:443 as a fallback on account '%s'",
182 tp_account_get_path_suffix (account));
184 params = tp_asv_new (
185 "fallback-servers", G_TYPE_STRV, fallback_servers,
188 tp_account_update_parameters_async (account, params, NULL,
189 account_update_parameters_cb, NULL);
191 g_hash_table_unref (params);
194 g_list_free_full (accounts, g_object_unref);
198 upgrade_chat_theme_settings (void)
200 GSettings *gsettings_chat;
201 gchar *theme, *new_theme = NULL;
202 const char *variant = "";
204 gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
206 theme = g_settings_get_string (gsettings_chat,
207 EMPATHY_PREFS_CHAT_THEME);
209 if (!tp_strdiff (theme, "adium")) {
212 path = g_settings_get_string (gsettings_chat,
213 EMPATHY_PREFS_CHAT_ADIUM_PATH);
215 new_theme = empathy_theme_manager_dup_theme_name_from_path (path);
216 if (new_theme == NULL)
218 /* Use the Classic theme as fallback */
219 new_theme = g_strdup ("Classic");
223 } else if (!tp_strdiff (theme, "gnome")) {
224 new_theme = g_strdup ("PlanetGNOME");
225 } else if (!tp_strdiff (theme, "simple")) {
226 new_theme = g_strdup ("Boxes");
228 } else if (!tp_strdiff (theme, "clean")) {
229 new_theme = g_strdup ("Boxes");
231 } else if (!tp_strdiff (theme, "blue")) {
232 new_theme = g_strdup ("Boxes");
235 /* Assume that's an Adium theme name. The theme manager will fallback to
236 * 'Classic' if it can't find it. */
240 DEBUG ("Migrating to '%s' variant '%s'", new_theme, variant);
242 g_settings_set_string (gsettings_chat,
243 EMPATHY_PREFS_CHAT_THEME, new_theme);
244 g_settings_set_string (gsettings_chat,
245 EMPATHY_PREFS_CHAT_THEME_VARIANT, variant);
250 g_object_unref (gsettings_chat);
256 TpAccount *new_account;
257 TpAccount *old_account;
261 static UoaMigrationData *
262 uoa_migration_data_new (TpAccount *account)
264 UoaMigrationData *data;
266 data = g_slice_new0 (UoaMigrationData);
267 data->old_account = g_object_ref (account);
268 data->enabled = tp_account_is_enabled (account);
274 uoa_migration_data_free (UoaMigrationData *data)
276 g_clear_object (&data->new_account);
277 g_clear_object (&data->old_account);
278 g_slice_free (UoaMigrationData, data);
281 #define DATA_SANITY_CTX "data-sanity-ctx"
284 uoa_account_remove_cb (GObject *source,
285 GAsyncResult *result,
288 TpAccount *account = TP_ACCOUNT (source);
289 GError *error = NULL;
291 if (!tp_account_remove_finish (account, result, &error))
293 DEBUG ("Failed to remove account '%s': %s",
294 tp_account_get_path_suffix (account), error->message);
295 g_error_free (error);
298 g_object_set_data (G_OBJECT (account), DATA_SANITY_CTX, NULL);
302 uoa_migration_done (UoaMigrationData *data)
304 tp_account_remove_async (data->old_account, uoa_account_remove_cb, NULL);
306 if (data->new_account != NULL)
307 tp_account_set_enabled_async (data->new_account, data->enabled, NULL, NULL);
309 uoa_migration_data_free (data);
313 uoa_set_account_password_cb (GObject *source,
314 GAsyncResult *result,
317 UoaMigrationData *data = user_data;
318 GError *error = NULL;
320 if (!empathy_keyring_set_account_password_finish (data->new_account, result,
323 DEBUG ("Error setting old account's password on the new one: %s\n",
325 g_clear_error (&error);
328 uoa_migration_done (data);
332 uoa_get_account_password_cb (GObject *source,
333 GAsyncResult *result,
336 UoaMigrationData *data = user_data;
337 const gchar *password;
338 GError *error = NULL;
340 password = empathy_keyring_get_account_password_finish (data->old_account,
342 if (password == NULL)
344 DEBUG ("Error getting old account's password: %s\n", error->message);
345 g_clear_error (&error);
347 uoa_migration_done (data);
351 empathy_keyring_set_account_password_async (data->new_account, password,
352 TRUE, uoa_set_account_password_cb, data);
357 uoa_account_created_cb (GObject *source,
358 GAsyncResult *result,
361 TpAccountRequest *ar = (TpAccountRequest *) source;
362 UoaMigrationData *data = user_data;
363 GError *error = NULL;
365 data->new_account = tp_account_request_create_account_finish (ar, result,
367 if (data->new_account == NULL)
369 DEBUG ("Failed to migrate account '%s' to UOA: %s",
370 tp_account_get_path_suffix (data->old_account), error->message);
371 g_clear_error (&error);
373 uoa_migration_done (data);
377 DEBUG ("New account %s created to superseed %s",
378 tp_account_get_path_suffix (data->new_account),
379 tp_account_get_path_suffix (data->old_account));
381 /* Migrate password as well */
382 empathy_keyring_get_account_password_async (data->old_account,
383 uoa_get_account_password_cb, data);
388 migrate_account_to_uoa (TpAccountManager *am,
391 TpAccountRequest *ar;
395 const gchar * const *supersedes;
397 UoaMigrationData *data;
399 DEBUG ("Migrating account %s to UOA storage\n",
400 tp_account_get_path_suffix (account));
402 ar = tp_account_request_new (am,
403 tp_account_get_cm_name (account),
404 tp_account_get_protocol_name (account),
405 tp_account_get_display_name (account));
406 tp_account_request_set_storage_provider (ar, EMPATHY_UOA_PROVIDER);
407 tp_account_request_set_icon_name (ar,
408 tp_account_get_icon_name (account));
409 tp_account_request_set_nickname (ar,
410 tp_account_get_nickname (account));
411 tp_account_request_set_service (ar,
412 tp_account_get_service (account));
414 /* Do not enable the new account until we imported the password as well */
415 tp_account_request_set_enabled (ar, FALSE);
417 supersedes = tp_account_get_supersedes (account);
419 for (i = 0; supersedes[i] != NULL; i++)
420 tp_account_request_add_supersedes (ar, supersedes[i]);
422 tp_account_request_add_supersedes (ar,
423 tp_proxy_get_object_path (account));
425 params = tp_account_dup_parameters_vardict (account);
426 g_variant_iter_init (&iter, params);
427 while ((param = g_variant_iter_next_value (&iter)))
432 k = g_variant_get_child_value (param, 0);
433 key = g_variant_get_string (k, NULL);
434 v = g_variant_get_child_value (param, 1);
436 tp_account_request_set_parameter (ar, key,
437 g_variant_get_variant (v));
443 data = uoa_migration_data_new (account);
444 tp_account_set_enabled_async (account, FALSE, NULL, NULL);
445 tp_account_request_create_account_async (ar, uoa_account_created_cb,
448 g_variant_unref (params);
453 uoa_plugin_install_cb (GObject *source,
454 GAsyncResult *result,
457 TpAccount *account = user_data;
458 GError *error = NULL;
459 TpAccountManager *am;
461 if (!empathy_pkg_kit_install_packages_finish (result, &error))
463 DEBUG ("Failed to install plugin for account '%s' (%s); remove it",
464 tp_account_get_path_suffix (account), error->message);
466 g_error_free (error);
468 tp_account_remove_async (account, uoa_account_remove_cb, NULL);
472 DEBUG ("Plugin for account '%s' has been installed; migrate account",
473 tp_account_get_path_suffix (account));
475 am = tp_account_manager_dup ();
476 migrate_account_to_uoa (am, account);
480 g_object_unref (account);
484 dup_plugin_name_for_protocol (const gchar *protocol)
486 if (!tp_strdiff (protocol, "local-xmpp"))
487 return g_strdup ("account-plugin-salut");
489 return g_strdup_printf ("account-plugin-%s", protocol);
493 uoa_plugin_installed (AgManager *manager,
496 AgAccount *ag_account;
497 const gchar *protocol;
500 protocol = tp_account_get_protocol_name (account);
501 ag_account = ag_manager_create_account (manager, protocol);
503 l = ag_account_list_services_by_type (ag_account, EMPATHY_UOA_SERVICE_TYPE);
506 const gchar *packages[2];
509 pkg = dup_plugin_name_for_protocol (protocol);
511 DEBUG ("%s is not installed; try to install it", pkg);
516 empathy_pkg_kit_install_packages_async (0, packages, NULL,
517 NULL, uoa_plugin_install_cb, g_object_ref (account));
520 g_object_unref (ag_account);
524 ag_service_list_free (l);
526 g_object_unref (ag_account);
531 migrate_accounts_to_uoa (SanityCtx *ctx)
536 DEBUG ("Start migrating accounts to UOA");
538 manager = empathy_uoa_manager_dup ();
540 accounts = tp_account_manager_dup_valid_accounts (ctx->am);
541 for (l = accounts; l != NULL; l = g_list_next (l))
543 TpAccount *account = l->data;
545 /* If account is already in a specific storage (like UOA or GOA),
547 * Note that we cannot migrate GOA accounts anyway, since we can't delete
548 * them it would create duplicated accounts. */
549 if (!tp_str_empty (tp_account_get_storage_provider (account)))
552 g_object_set_data_full (G_OBJECT (account), DATA_SANITY_CTX,
553 sanity_ctx_ref (ctx), (GDestroyNotify) sanity_ctx_unref);
555 /* Try to install the plugin if it's missing */
556 if (!uoa_plugin_installed (manager, account))
559 migrate_account_to_uoa (ctx->am, account);
562 g_list_free_full (accounts, g_object_unref);
564 g_object_unref (manager);
569 run_sanity_cleaning_tasks (SanityCtx *ctx)
571 DEBUG ("Starting sanity cleaning tasks");
573 fix_xmpp_account_priority (ctx->am);
574 set_facebook_account_fallback_server (ctx->am);
575 upgrade_chat_theme_settings ();
577 migrate_accounts_to_uoa (ctx);
582 am_prepare_cb (GObject *source,
583 GAsyncResult *result,
586 GError *error = NULL;
587 TpAccountManager *am = TP_ACCOUNT_MANAGER (source);
588 SanityCtx *ctx = user_data;
590 if (!tp_proxy_prepare_finish (am, result, &error))
592 DEBUG ("Failed to prepare account manager: %s", error->message);
593 g_simple_async_result_take_error (ctx->result, error);
597 run_sanity_cleaning_tasks (ctx);
600 sanity_ctx_unref (ctx);
604 empathy_sanity_checking_run_async (GAsyncReadyCallback callback,
609 TpAccountManager *am;
610 GSimpleAsyncResult *result;
613 result = g_simple_async_result_new (NULL, callback, user_data,
614 empathy_sanity_checking_run_async);
616 settings = g_settings_new (EMPATHY_PREFS_SCHEMA);
617 number = g_settings_get_uint (settings, EMPATHY_PREFS_SANITY_CLEANING_NUMBER);
619 if (number == SANITY_CLEANING_NUMBER)
621 g_simple_async_result_complete_in_idle (result);
625 am = tp_account_manager_dup ();
627 ctx = sanity_ctx_new (am, result);
628 tp_proxy_prepare_async (am, NULL, am_prepare_cb, ctx);
630 g_settings_set_uint (settings, EMPATHY_PREFS_SANITY_CLEANING_NUMBER,
631 SANITY_CLEANING_NUMBER);
636 g_object_unref (settings);
637 g_object_unref (result);
641 empathy_sanity_checking_run_finish (GAsyncResult *result,
644 g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
645 empathy_sanity_checking_run_async), FALSE);
647 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),