Set prgname instead of program_class
[nijm-empathy.git] / src / empathy-sanity-cleaning.c
bloba1a097db43208367a8638e2b48081bc200498c27
1 /*
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
24 #include "config.h"
25 #include "empathy-sanity-cleaning.h"
27 #ifdef HAVE_UOA
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"
35 #endif
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
47 * be executed.
49 #define SANITY_CLEANING_NUMBER 4
51 typedef struct
53 TpAccountManager *am;
54 GSimpleAsyncResult *result;
56 gint ref_count;
57 } SanityCtx;
59 static SanityCtx *
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);
68 ctx->ref_count = 1;
69 return ctx;
72 #ifdef HAVE_UOA
73 static SanityCtx *
74 sanity_ctx_ref (SanityCtx *ctx)
76 ctx->ref_count++;
78 return ctx;
80 #endif
82 static void
83 sanity_ctx_unref (SanityCtx *ctx)
85 ctx->ref_count--;
87 if (ctx->ref_count != 0)
88 return;
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);
98 static void
99 account_update_parameters_cb (GObject *source,
100 GAsyncResult *result,
101 gpointer user_data)
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);
112 return;
115 tp_account_reconnect_async (account, NULL, NULL);
118 /* Make sure XMPP accounts don't have a negative priority (bgo #671452) */
119 static void
120 fix_xmpp_account_priority (TpAccountManager *am)
122 GList *accounts, *l;
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;
128 GHashTable *params;
129 gint priority;
131 if (tp_strdiff (tp_account_get_protocol_name (account), "jabber"))
132 continue;
134 params = (GHashTable *) tp_account_get_parameters (account);
135 if (params == NULL)
136 continue;
138 priority = tp_asv_get_int32 (params, "priority", NULL);
139 if (priority >= 0)
140 continue;
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,
147 NULL);
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);
158 static void
159 set_facebook_account_fallback_server (TpAccountManager *am)
161 GList *accounts, *l;
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;
167 GHashTable *params;
168 gchar *fallback_servers[] = {
169 "chat.facebook.com:443",
170 NULL };
172 if (tp_strdiff (tp_account_get_service (account), "facebook"))
173 continue;
175 params = (GHashTable *) tp_account_get_parameters (account);
176 if (params == NULL)
177 continue;
179 if (tp_asv_get_strv (params, "fallback-servers") != NULL)
180 continue;
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,
187 NULL);
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);
198 static void
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")) {
211 gchar *path;
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");
223 g_free (path);
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");
228 variant = "Simple";
229 } else if (!tp_strdiff (theme, "clean")) {
230 new_theme = g_strdup ("Boxes");
231 variant = "Clean";
232 } else if (!tp_strdiff (theme, "blue")) {
233 new_theme = g_strdup ("Boxes");
234 variant = "Blue";
235 } else {
236 /* Assume that's an Adium theme name. The theme manager will fallback to
237 * 'Classic' if it can't find it. */
238 goto finally;
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);
248 finally:
249 g_free (theme);
250 g_free (new_theme);
251 g_object_unref (gsettings_chat);
254 #ifdef HAVE_UOA
255 typedef struct
257 TpAccount *new_account;
258 TpAccount *old_account;
259 gboolean enabled;
260 } UoaMigrationData;
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);
271 return data;
274 static void
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"
284 static void
285 uoa_account_remove_cb (GObject *source,
286 GAsyncResult *result,
287 gpointer user_data)
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);
302 static void
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);
313 static void
314 uoa_set_account_password_cb (GObject *source,
315 GAsyncResult *result,
316 gpointer user_data)
318 UoaMigrationData *data = user_data;
319 GError *error = NULL;
321 if (!tpaw_keyring_set_account_password_finish (data->new_account, result,
322 &error))
324 DEBUG ("Error setting old account's password on the new one: %s\n",
325 error->message);
326 g_clear_error (&error);
329 uoa_migration_done (data);
332 static void
333 uoa_get_account_password_cb (GObject *source,
334 GAsyncResult *result,
335 gpointer user_data)
337 UoaMigrationData *data = user_data;
338 const gchar *password;
339 GError *error = NULL;
341 password = tpaw_keyring_get_account_password_finish (data->old_account,
342 result, &error);
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);
350 else
352 tpaw_keyring_set_account_password_async (data->new_account, password,
353 TRUE, uoa_set_account_password_cb, data);
357 static void
358 uoa_account_created_cb (GObject *source,
359 GAsyncResult *result,
360 gpointer user_data)
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,
367 &error);
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);
376 else
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);
388 static void
389 migrate_account_to_uoa (TpAccountManager *am,
390 TpAccount *account)
392 TpAccountRequest *ar;
393 GVariant *params;
394 GVariant *param;
395 GVariantIter iter;
396 const gchar * const *supersedes;
397 guint i;
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)))
430 GVariant *k, *v;
431 const gchar *key;
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));
440 g_variant_unref (k);
441 g_variant_unref (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,
447 data);
449 g_variant_unref (params);
450 g_object_unref (ar);
453 static void
454 uoa_plugin_install_cb (GObject *source,
455 GAsyncResult *result,
456 gpointer user_data)
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);
470 goto out;
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);
478 g_object_unref (am);
480 out:
481 g_object_unref (account);
484 static gchar *
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);
493 static gboolean
494 uoa_plugin_installed (AgManager *manager,
495 TpAccount *account)
497 AgAccount *ag_account;
498 const gchar *protocol;
499 GList *l;
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);
505 if (l == NULL)
507 const gchar *packages[2];
508 gchar *pkg;
510 pkg = dup_plugin_name_for_protocol (protocol);
512 DEBUG ("%s is not installed; try to install it", pkg);
514 packages[0] = pkg;
515 packages[1] = NULL;
517 empathy_pkg_kit_install_packages_async (0, packages, NULL,
518 NULL, uoa_plugin_install_cb, g_object_ref (account));
520 g_free (pkg);
521 g_object_unref (ag_account);
522 return FALSE;
525 ag_service_list_free (l);
527 g_object_unref (ag_account);
528 return TRUE;
531 static void
532 migrate_accounts_to_uoa (SanityCtx *ctx)
534 GList *accounts, *l;
535 AgManager *manager;
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),
547 * don't migrate it.
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)))
551 continue;
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))
558 continue;
560 migrate_account_to_uoa (ctx->am, account);
563 g_list_free_full (accounts, g_object_unref);
565 g_object_unref (manager);
567 #endif
569 static void
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 ();
577 #ifdef HAVE_UOA
578 migrate_accounts_to_uoa (ctx);
579 #endif
582 static void
583 am_prepare_cb (GObject *source,
584 GAsyncResult *result,
585 gpointer user_data)
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);
595 goto out;
598 run_sanity_cleaning_tasks (ctx);
600 out:
601 sanity_ctx_unref (ctx);
604 void
605 empathy_sanity_checking_run_async (GAsyncReadyCallback callback,
606 gpointer user_data)
608 GSettings *settings;
609 guint number;
610 TpAccountManager *am;
611 GSimpleAsyncResult *result;
612 SanityCtx *ctx;
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);
623 goto out;
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);
634 g_object_unref (am);
636 out:
637 g_object_unref (settings);
638 g_object_unref (result);
641 gboolean
642 empathy_sanity_checking_run_finish (GAsyncResult *result,
643 GError **error)
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),
649 error))
650 return FALSE;
652 return TRUE;