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>
31 #include <tp-account-widgets/tpaw-keyring.h>
32 #include <tp-account-widgets/tpaw-uoa-utils.h>
34 #include "empathy-pkg-kit.h"
37 #include "empathy-gsettings.h"
38 #include "empathy-theme-manager.h"
40 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
41 #include "empathy-debug.h"
44 * This number has to be increased each time a new task is added or modified.
46 * If the number stored in gsettings is lower than it, all the tasks will
49 #define SANITY_CLEANING_NUMBER 4
54 GSimpleAsyncResult
*result
;
60 sanity_ctx_new (TpAccountManager
*am
,
61 GSimpleAsyncResult
*result
)
63 SanityCtx
*ctx
= g_slice_new0 (SanityCtx
);
65 ctx
->am
= g_object_ref (am
);
66 ctx
->result
= g_object_ref (result
);
74 sanity_ctx_ref (SanityCtx
*ctx
)
83 sanity_ctx_unref (SanityCtx
*ctx
)
87 if (ctx
->ref_count
!= 0)
90 g_simple_async_result_complete_in_idle (ctx
->result
);
92 g_object_unref (ctx
->am
);
93 g_object_unref (ctx
->result
);
95 g_slice_free (SanityCtx
, ctx
);
99 account_update_parameters_cb (GObject
*source
,
100 GAsyncResult
*result
,
103 GError
*error
= NULL
;
104 TpAccount
*account
= TP_ACCOUNT (source
);
106 if (!tp_account_update_parameters_finish (account
, result
, NULL
, &error
))
108 DEBUG ("Failed to update parameters of account '%s': %s",
109 tp_account_get_path_suffix (account
), error
->message
);
111 g_error_free (error
);
115 tp_account_reconnect_async (account
, NULL
, NULL
);
118 /* Make sure XMPP accounts don't have a negative priority (bgo #671452) */
120 fix_xmpp_account_priority (TpAccountManager
*am
)
124 accounts
= tp_account_manager_dup_valid_accounts (am
);
125 for (l
= accounts
; l
!= NULL
; l
= g_list_next (l
))
127 TpAccount
*account
= l
->data
;
131 if (tp_strdiff (tp_account_get_protocol_name (account
), "jabber"))
134 params
= (GHashTable
*) tp_account_get_parameters (account
);
138 priority
= tp_asv_get_int32 (params
, "priority", NULL
);
142 DEBUG ("Resetting XMPP priority of account '%s' to 0",
143 tp_account_get_path_suffix (account
));
145 params
= tp_asv_new (
146 "priority", G_TYPE_INT
, 0,
149 tp_account_update_parameters_async (account
, params
, NULL
,
150 account_update_parameters_cb
, NULL
);
152 g_hash_table_unref (params
);
155 g_list_free_full (accounts
, g_object_unref
);
159 set_facebook_account_fallback_server (TpAccountManager
*am
)
163 accounts
= tp_account_manager_dup_valid_accounts (am
);
164 for (l
= accounts
; l
!= NULL
; l
= g_list_next (l
))
166 TpAccount
*account
= l
->data
;
168 gchar
*fallback_servers
[] = {
169 "chat.facebook.com:443",
172 if (tp_strdiff (tp_account_get_service (account
), "facebook"))
175 params
= (GHashTable
*) tp_account_get_parameters (account
);
179 if (tp_asv_get_strv (params
, "fallback-servers") != NULL
)
182 DEBUG ("Setting chat.facebook.com:443 as a fallback on account '%s'",
183 tp_account_get_path_suffix (account
));
185 params
= tp_asv_new (
186 "fallback-servers", G_TYPE_STRV
, fallback_servers
,
189 tp_account_update_parameters_async (account
, params
, NULL
,
190 account_update_parameters_cb
, NULL
);
192 g_hash_table_unref (params
);
195 g_list_free_full (accounts
, g_object_unref
);
199 upgrade_chat_theme_settings (void)
201 GSettings
*gsettings_chat
;
202 gchar
*theme
, *new_theme
= NULL
;
203 const char *variant
= "";
205 gsettings_chat
= g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA
);
207 theme
= g_settings_get_string (gsettings_chat
,
208 EMPATHY_PREFS_CHAT_THEME
);
210 if (!tp_strdiff (theme
, "adium")) {
213 path
= g_settings_get_string (gsettings_chat
,
214 EMPATHY_PREFS_CHAT_ADIUM_PATH
);
216 new_theme
= empathy_theme_manager_dup_theme_name_from_path (path
);
217 if (new_theme
== NULL
)
219 /* Use the Classic theme as fallback */
220 new_theme
= g_strdup ("Classic");
224 } else if (!tp_strdiff (theme
, "gnome")) {
225 new_theme
= g_strdup ("PlanetGNOME");
226 } else if (!tp_strdiff (theme
, "simple")) {
227 new_theme
= g_strdup ("Boxes");
229 } else if (!tp_strdiff (theme
, "clean")) {
230 new_theme
= g_strdup ("Boxes");
232 } else if (!tp_strdiff (theme
, "blue")) {
233 new_theme
= g_strdup ("Boxes");
236 /* Assume that's an Adium theme name. The theme manager will fallback to
237 * 'Classic' if it can't find it. */
241 DEBUG ("Migrating to '%s' variant '%s'", new_theme
, variant
);
243 g_settings_set_string (gsettings_chat
,
244 EMPATHY_PREFS_CHAT_THEME
, new_theme
);
245 g_settings_set_string (gsettings_chat
,
246 EMPATHY_PREFS_CHAT_THEME_VARIANT
, variant
);
251 g_object_unref (gsettings_chat
);
257 TpAccount
*new_account
;
258 TpAccount
*old_account
;
262 static UoaMigrationData
*
263 uoa_migration_data_new (TpAccount
*account
)
265 UoaMigrationData
*data
;
267 data
= g_slice_new0 (UoaMigrationData
);
268 data
->old_account
= g_object_ref (account
);
269 data
->enabled
= tp_account_is_enabled (account
);
275 uoa_migration_data_free (UoaMigrationData
*data
)
277 g_clear_object (&data
->new_account
);
278 g_clear_object (&data
->old_account
);
279 g_slice_free (UoaMigrationData
, data
);
282 #define DATA_SANITY_CTX "data-sanity-ctx"
285 uoa_account_remove_cb (GObject
*source
,
286 GAsyncResult
*result
,
289 TpAccount
*account
= TP_ACCOUNT (source
);
290 GError
*error
= NULL
;
292 if (!tp_account_remove_finish (account
, result
, &error
))
294 DEBUG ("Failed to remove account '%s': %s",
295 tp_account_get_path_suffix (account
), error
->message
);
296 g_error_free (error
);
299 g_object_set_data (G_OBJECT (account
), DATA_SANITY_CTX
, NULL
);
303 uoa_migration_done (UoaMigrationData
*data
)
305 tp_account_remove_async (data
->old_account
, uoa_account_remove_cb
, NULL
);
307 if (data
->new_account
!= NULL
)
308 tp_account_set_enabled_async (data
->new_account
, data
->enabled
, NULL
, NULL
);
310 uoa_migration_data_free (data
);
314 uoa_set_account_password_cb (GObject
*source
,
315 GAsyncResult
*result
,
318 UoaMigrationData
*data
= user_data
;
319 GError
*error
= NULL
;
321 if (!tpaw_keyring_set_account_password_finish (data
->new_account
, result
,
324 DEBUG ("Error setting old account's password on the new one: %s\n",
326 g_clear_error (&error
);
329 uoa_migration_done (data
);
333 uoa_get_account_password_cb (GObject
*source
,
334 GAsyncResult
*result
,
337 UoaMigrationData
*data
= user_data
;
338 const gchar
*password
;
339 GError
*error
= NULL
;
341 password
= tpaw_keyring_get_account_password_finish (data
->old_account
,
343 if (password
== NULL
)
345 DEBUG ("Error getting old account's password: %s\n", error
->message
);
346 g_clear_error (&error
);
348 uoa_migration_done (data
);
352 tpaw_keyring_set_account_password_async (data
->new_account
, password
,
353 TRUE
, uoa_set_account_password_cb
, data
);
358 uoa_account_created_cb (GObject
*source
,
359 GAsyncResult
*result
,
362 TpAccountRequest
*ar
= (TpAccountRequest
*) source
;
363 UoaMigrationData
*data
= user_data
;
364 GError
*error
= NULL
;
366 data
->new_account
= tp_account_request_create_account_finish (ar
, result
,
368 if (data
->new_account
== NULL
)
370 DEBUG ("Failed to migrate account '%s' to UOA: %s",
371 tp_account_get_path_suffix (data
->old_account
), error
->message
);
372 g_clear_error (&error
);
374 uoa_migration_done (data
);
378 DEBUG ("New account %s created to superseed %s",
379 tp_account_get_path_suffix (data
->new_account
),
380 tp_account_get_path_suffix (data
->old_account
));
382 /* Migrate password as well */
383 tpaw_keyring_get_account_password_async (data
->old_account
,
384 uoa_get_account_password_cb
, data
);
389 migrate_account_to_uoa (TpAccountManager
*am
,
392 TpAccountRequest
*ar
;
396 const gchar
* const *supersedes
;
398 UoaMigrationData
*data
;
400 DEBUG ("Migrating account %s to UOA storage\n",
401 tp_account_get_path_suffix (account
));
403 ar
= tp_account_request_new (am
,
404 tp_account_get_cm_name (account
),
405 tp_account_get_protocol_name (account
),
406 tp_account_get_display_name (account
));
407 tp_account_request_set_storage_provider (ar
, EMPATHY_UOA_PROVIDER
);
408 tp_account_request_set_icon_name (ar
,
409 tp_account_get_icon_name (account
));
410 tp_account_request_set_nickname (ar
,
411 tp_account_get_nickname (account
));
412 tp_account_request_set_service (ar
,
413 tp_account_get_service (account
));
415 /* Do not enable the new account until we imported the password as well */
416 tp_account_request_set_enabled (ar
, FALSE
);
418 supersedes
= tp_account_get_supersedes (account
);
420 for (i
= 0; supersedes
[i
] != NULL
; i
++)
421 tp_account_request_add_supersedes (ar
, supersedes
[i
]);
423 tp_account_request_add_supersedes (ar
,
424 tp_proxy_get_object_path (account
));
426 params
= tp_account_dup_parameters_vardict (account
);
427 g_variant_iter_init (&iter
, params
);
428 while ((param
= g_variant_iter_next_value (&iter
)))
433 k
= g_variant_get_child_value (param
, 0);
434 key
= g_variant_get_string (k
, NULL
);
435 v
= g_variant_get_child_value (param
, 1);
437 tp_account_request_set_parameter (ar
, key
,
438 g_variant_get_variant (v
));
444 data
= uoa_migration_data_new (account
);
445 tp_account_set_enabled_async (account
, FALSE
, NULL
, NULL
);
446 tp_account_request_create_account_async (ar
, uoa_account_created_cb
,
449 g_variant_unref (params
);
454 uoa_plugin_install_cb (GObject
*source
,
455 GAsyncResult
*result
,
458 TpAccount
*account
= user_data
;
459 GError
*error
= NULL
;
460 TpAccountManager
*am
;
462 if (!empathy_pkg_kit_install_packages_finish (result
, &error
))
464 DEBUG ("Failed to install plugin for account '%s' (%s); remove it",
465 tp_account_get_path_suffix (account
), error
->message
);
467 g_error_free (error
);
469 tp_account_remove_async (account
, uoa_account_remove_cb
, NULL
);
473 DEBUG ("Plugin for account '%s' has been installed; migrate account",
474 tp_account_get_path_suffix (account
));
476 am
= tp_account_manager_dup ();
477 migrate_account_to_uoa (am
, account
);
481 g_object_unref (account
);
485 dup_plugin_name_for_protocol (const gchar
*protocol
)
487 if (!tp_strdiff (protocol
, "local-xmpp"))
488 return g_strdup ("account-plugin-salut");
490 return g_strdup_printf ("account-plugin-%s", protocol
);
494 uoa_plugin_installed (AgManager
*manager
,
497 AgAccount
*ag_account
;
498 const gchar
*protocol
;
501 protocol
= tp_account_get_protocol_name (account
);
502 ag_account
= ag_manager_create_account (manager
, protocol
);
504 l
= ag_account_list_services_by_type (ag_account
, TPAW_UOA_SERVICE_TYPE
);
507 const gchar
*packages
[2];
510 pkg
= dup_plugin_name_for_protocol (protocol
);
512 DEBUG ("%s is not installed; try to install it", pkg
);
517 empathy_pkg_kit_install_packages_async (0, packages
, NULL
,
518 NULL
, uoa_plugin_install_cb
, g_object_ref (account
));
521 g_object_unref (ag_account
);
525 ag_service_list_free (l
);
527 g_object_unref (ag_account
);
532 migrate_accounts_to_uoa (SanityCtx
*ctx
)
537 DEBUG ("Start migrating accounts to UOA");
539 manager
= tpaw_uoa_manager_dup ();
541 accounts
= tp_account_manager_dup_valid_accounts (ctx
->am
);
542 for (l
= accounts
; l
!= NULL
; l
= g_list_next (l
))
544 TpAccount
*account
= l
->data
;
546 /* If account is already in a specific storage (like UOA or GOA),
548 * Note that we cannot migrate GOA accounts anyway, since we can't delete
549 * them it would create duplicated accounts. */
550 if (!tp_str_empty (tp_account_get_storage_provider (account
)))
553 g_object_set_data_full (G_OBJECT (account
), DATA_SANITY_CTX
,
554 sanity_ctx_ref (ctx
), (GDestroyNotify
) sanity_ctx_unref
);
556 /* Try to install the plugin if it's missing */
557 if (!uoa_plugin_installed (manager
, account
))
560 migrate_account_to_uoa (ctx
->am
, account
);
563 g_list_free_full (accounts
, g_object_unref
);
565 g_object_unref (manager
);
570 run_sanity_cleaning_tasks (SanityCtx
*ctx
)
572 DEBUG ("Starting sanity cleaning tasks");
574 fix_xmpp_account_priority (ctx
->am
);
575 set_facebook_account_fallback_server (ctx
->am
);
576 upgrade_chat_theme_settings ();
578 migrate_accounts_to_uoa (ctx
);
583 am_prepare_cb (GObject
*source
,
584 GAsyncResult
*result
,
587 GError
*error
= NULL
;
588 TpAccountManager
*am
= TP_ACCOUNT_MANAGER (source
);
589 SanityCtx
*ctx
= user_data
;
591 if (!tp_proxy_prepare_finish (am
, result
, &error
))
593 DEBUG ("Failed to prepare account manager: %s", error
->message
);
594 g_simple_async_result_take_error (ctx
->result
, error
);
598 run_sanity_cleaning_tasks (ctx
);
601 sanity_ctx_unref (ctx
);
605 empathy_sanity_checking_run_async (GAsyncReadyCallback callback
,
610 TpAccountManager
*am
;
611 GSimpleAsyncResult
*result
;
614 result
= g_simple_async_result_new (NULL
, callback
, user_data
,
615 empathy_sanity_checking_run_async
);
617 settings
= g_settings_new (EMPATHY_PREFS_SCHEMA
);
618 number
= g_settings_get_uint (settings
, EMPATHY_PREFS_SANITY_CLEANING_NUMBER
);
620 if (number
== SANITY_CLEANING_NUMBER
)
622 g_simple_async_result_complete_in_idle (result
);
626 am
= tp_account_manager_dup ();
628 ctx
= sanity_ctx_new (am
, result
);
629 tp_proxy_prepare_async (am
, NULL
, am_prepare_cb
, ctx
);
631 g_settings_set_uint (settings
, EMPATHY_PREFS_SANITY_CLEANING_NUMBER
,
632 SANITY_CLEANING_NUMBER
);
637 g_object_unref (settings
);
638 g_object_unref (result
);
642 empathy_sanity_checking_run_finish (GAsyncResult
*result
,
645 g_return_val_if_fail (g_simple_async_result_is_valid (result
, NULL
,
646 empathy_sanity_checking_run_async
), FALSE
);
648 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result
),