]> git.0d.be Git - empathy.git/blob - src/empathy-sanity-cleaning.c
Updated gujarati file
[empathy.git] / src / empathy-sanity-cleaning.c
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.
5  *
6  * Copyright (C) 2012 Collabora Ltd.
7  * @author Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "config.h"
25
26 #include "empathy-sanity-cleaning.h"
27
28 #include <telepathy-glib/telepathy-glib.h>
29
30 #include <libempathy/empathy-account-settings.h>
31 #include <libempathy/empathy-gsettings.h>
32
33 #include <libempathy-gtk/empathy-theme-manager.h>
34
35 #ifdef HAVE_UOA
36 #include <libempathy/empathy-pkg-kit.h>
37 #include <libempathy/empathy-uoa-utils.h>
38
39 #include <libaccounts-glib/ag-account-service.h>
40 #include <libaccounts-glib/ag-manager.h>
41 #include <libaccounts-glib/ag-service.h>
42 #endif
43
44 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
45 #include <libempathy/empathy-debug.h>
46 #include <libempathy/empathy-keyring.h>
47
48 /*
49  * This number has to be increased each time a new task is added or modified.
50  *
51  * If the number stored in gsettings is lower than it, all the tasks will
52  * be executed.
53  */
54 #define SANITY_CLEANING_NUMBER 4
55
56 typedef struct
57 {
58   TpAccountManager *am;
59   GSimpleAsyncResult *result;
60
61   gint ref_count;
62 } SanityCtx;
63
64 static SanityCtx *
65 sanity_ctx_new (TpAccountManager *am,
66     GSimpleAsyncResult *result)
67 {
68   SanityCtx *ctx = g_slice_new0 (SanityCtx);
69
70   ctx->am = g_object_ref (am);
71   ctx->result = g_object_ref (result);
72
73   ctx->ref_count = 1;
74   return ctx;
75 }
76
77 #ifdef HAVE_UOA
78 static SanityCtx *
79 sanity_ctx_ref (SanityCtx *ctx)
80 {
81   ctx->ref_count++;
82
83   return ctx;
84 }
85 #endif
86
87 static void
88 sanity_ctx_unref (SanityCtx *ctx)
89 {
90   ctx->ref_count--;
91
92   if (ctx->ref_count != 0)
93     return;
94
95   g_simple_async_result_complete_in_idle (ctx->result);
96
97   g_object_unref (ctx->am);
98   g_object_unref (ctx->result);
99
100   g_slice_free (SanityCtx, ctx);
101 }
102
103 static void
104 account_update_parameters_cb (GObject *source,
105     GAsyncResult *result,
106     gpointer user_data)
107 {
108   GError *error = NULL;
109   TpAccount *account = TP_ACCOUNT (source);
110
111   if (!tp_account_update_parameters_finish (account, result, NULL, &error))
112     {
113       DEBUG ("Failed to update parameters of account '%s': %s",
114           tp_account_get_path_suffix (account), error->message);
115
116       g_error_free (error);
117       return;
118     }
119
120   tp_account_reconnect_async (account, NULL, NULL);
121 }
122
123 /* Make sure XMPP accounts don't have a negative priority (bgo #671452) */
124 static void
125 fix_xmpp_account_priority (TpAccountManager *am)
126 {
127   GList *accounts, *l;
128
129   accounts = tp_account_manager_dup_valid_accounts (am);
130   for (l = accounts; l != NULL; l = g_list_next (l))
131     {
132       TpAccount *account = l->data;
133       GHashTable *params;
134       gint priority;
135
136       if (tp_strdiff (tp_account_get_protocol_name (account), "jabber"))
137         continue;
138
139       params = (GHashTable *) tp_account_get_parameters (account);
140       if (params == NULL)
141         continue;
142
143       priority = tp_asv_get_int32 (params, "priority", NULL);
144       if (priority >= 0)
145         continue;
146
147       DEBUG ("Resetting XMPP priority of account '%s' to 0",
148           tp_account_get_path_suffix (account));
149
150       params = tp_asv_new (
151           "priority", G_TYPE_INT, 0,
152           NULL);
153
154       tp_account_update_parameters_async (account, params, NULL,
155           account_update_parameters_cb, NULL);
156
157       g_hash_table_unref (params);
158     }
159
160   g_list_free_full (accounts, g_object_unref);
161 }
162
163 static void
164 set_facebook_account_fallback_server (TpAccountManager *am)
165 {
166   GList *accounts, *l;
167
168   accounts = tp_account_manager_dup_valid_accounts (am);
169   for (l = accounts; l != NULL; l = g_list_next (l))
170     {
171       TpAccount *account = l->data;
172       GHashTable *params;
173       gchar *fallback_servers[] = {
174           "chat.facebook.com:443",
175           NULL };
176
177       if (tp_strdiff (tp_account_get_service (account), "facebook"))
178         continue;
179
180       params = (GHashTable *) tp_account_get_parameters (account);
181       if (params == NULL)
182         continue;
183
184       if (tp_asv_get_strv (params, "fallback-servers") != NULL)
185         continue;
186
187       DEBUG ("Setting chat.facebook.com:443 as a fallback on account '%s'",
188           tp_account_get_path_suffix (account));
189
190       params = tp_asv_new (
191           "fallback-servers", G_TYPE_STRV, fallback_servers,
192           NULL);
193
194       tp_account_update_parameters_async (account, params, NULL,
195           account_update_parameters_cb, NULL);
196
197       g_hash_table_unref (params);
198     }
199
200   g_list_free_full (accounts, g_object_unref);
201 }
202
203 static void
204 upgrade_chat_theme_settings (void)
205 {
206   GSettings *gsettings_chat;
207   gchar *theme, *new_theme = NULL;
208   const char *variant = "";
209
210   gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
211
212   theme = g_settings_get_string (gsettings_chat,
213       EMPATHY_PREFS_CHAT_THEME);
214
215   if (!tp_strdiff (theme, "adium")) {
216     gchar *path;
217
218     path = g_settings_get_string (gsettings_chat,
219         EMPATHY_PREFS_CHAT_ADIUM_PATH);
220
221     new_theme = empathy_theme_manager_dup_theme_name_from_path (path);
222     if (new_theme == NULL)
223       {
224         /* Use the Classic theme as fallback */
225         new_theme = g_strdup ("Classic");
226       }
227
228     g_free (path);
229   } else if (!tp_strdiff (theme, "gnome")) {
230     new_theme = g_strdup ("PlanetGNOME");
231   } else if (!tp_strdiff (theme, "simple")) {
232     new_theme = g_strdup ("Boxes");
233     variant = "Simple";
234   } else if (!tp_strdiff (theme, "clean")) {
235     new_theme = g_strdup ("Boxes");
236     variant = "Clean";
237   } else if (!tp_strdiff (theme, "blue")) {
238     new_theme = g_strdup ("Boxes");
239     variant = "Blue";
240   } else {
241     /* Assume that's an Adium theme name. The theme manager will fallback to
242      * 'Classic' if it can't find it. */
243     goto finally;
244   }
245
246   DEBUG ("Migrating to '%s' variant '%s'", new_theme, variant);
247
248   g_settings_set_string (gsettings_chat,
249     EMPATHY_PREFS_CHAT_THEME, new_theme);
250   g_settings_set_string (gsettings_chat,
251     EMPATHY_PREFS_CHAT_THEME_VARIANT, variant);
252
253 finally:
254   g_free (theme);
255   g_free (new_theme);
256   g_object_unref (gsettings_chat);
257 }
258
259 #ifdef HAVE_UOA
260 typedef struct
261 {
262   TpAccount *new_account;
263   TpAccount *old_account;
264   gboolean enabled;
265 } UoaMigrationData;
266
267 static UoaMigrationData *
268 uoa_migration_data_new (TpAccount *account)
269 {
270   UoaMigrationData *data;
271
272   data = g_slice_new0 (UoaMigrationData);
273   data->old_account = g_object_ref (account);
274   data->enabled = tp_account_is_enabled (account);
275
276   return data;
277 }
278
279 static void
280 uoa_migration_data_free (UoaMigrationData *data)
281 {
282   g_clear_object (&data->new_account);
283   g_clear_object (&data->old_account);
284   g_slice_free (UoaMigrationData, data);
285 }
286
287 #define DATA_SANITY_CTX "data-sanity-ctx"
288
289 static void
290 uoa_account_remove_cb (GObject *source,
291     GAsyncResult *result,
292     gpointer user_data)
293 {
294   TpAccount *account = TP_ACCOUNT (source);
295   GError *error = NULL;
296
297   if (!tp_account_remove_finish (account, result, &error))
298     {
299       DEBUG ("Failed to remove account '%s': %s",
300           tp_account_get_path_suffix (account), error->message);
301       g_error_free (error);
302     }
303
304   g_object_set_data (G_OBJECT (account), DATA_SANITY_CTX, NULL);
305 }
306
307 static void
308 uoa_migration_done (UoaMigrationData *data)
309 {
310   tp_account_remove_async (data->old_account, uoa_account_remove_cb, NULL);
311
312   if (data->new_account != NULL)
313     tp_account_set_enabled_async (data->new_account, data->enabled, NULL, NULL);
314
315   uoa_migration_data_free (data);
316 }
317
318 static void
319 uoa_set_account_password_cb (GObject *source,
320     GAsyncResult *result,
321     gpointer user_data)
322 {
323   UoaMigrationData *data = user_data;
324   GError *error = NULL;
325
326   if (!empathy_keyring_set_account_password_finish (data->new_account, result,
327           &error))
328     {
329       DEBUG ("Error setting old account's password on the new one: %s\n",
330           error->message);
331       g_clear_error (&error);
332     }
333
334   uoa_migration_done (data);
335 }
336
337 static void
338 uoa_get_account_password_cb (GObject *source,
339     GAsyncResult *result,
340     gpointer user_data)
341 {
342   UoaMigrationData *data = user_data;
343   const gchar *password;
344   GError *error = NULL;
345
346   password = empathy_keyring_get_account_password_finish (data->old_account,
347       result, &error);
348   if (password == NULL)
349     {
350       DEBUG ("Error getting old account's password: %s\n", error->message);
351       g_clear_error (&error);
352
353       uoa_migration_done (data);
354     }
355   else
356     {
357       empathy_keyring_set_account_password_async (data->new_account, password,
358           TRUE, uoa_set_account_password_cb, data);
359     }
360 }
361
362 static void
363 uoa_account_created_cb (GObject *source,
364     GAsyncResult *result,
365     gpointer user_data)
366 {
367   TpAccountRequest *ar = (TpAccountRequest *) source;
368   UoaMigrationData *data = user_data;
369   GError *error = NULL;
370
371   data->new_account = tp_account_request_create_account_finish (ar, result,
372       &error);
373   if (data->new_account == NULL)
374     {
375       DEBUG ("Failed to migrate account '%s' to UOA: %s",
376           tp_account_get_path_suffix (data->old_account), error->message);
377       g_clear_error (&error);
378
379       uoa_migration_done (data);
380     }
381   else
382     {
383       DEBUG ("New account %s created to superseed %s",
384           tp_account_get_path_suffix (data->new_account),
385           tp_account_get_path_suffix (data->old_account));
386
387       /* Migrate password as well */
388       empathy_keyring_get_account_password_async (data->old_account,
389           uoa_get_account_password_cb, data);
390     }
391 }
392
393 static void
394 migrate_account_to_uoa (TpAccountManager *am,
395     TpAccount *account)
396 {
397   TpAccountRequest *ar;
398   GVariant *params;
399   GVariant *param;
400   GVariantIter iter;
401   const gchar * const *supersedes;
402   UoaMigrationData *data;
403
404   DEBUG ("Migrating account %s to UOA storage\n",
405       tp_account_get_path_suffix (account));
406
407   ar = tp_account_request_new (am,
408       tp_account_get_cm_name (account),
409       tp_account_get_protocol_name (account),
410       tp_account_get_display_name (account));
411   tp_account_request_set_storage_provider (ar, EMPATHY_UOA_PROVIDER);
412   tp_account_request_set_icon_name (ar,
413       tp_account_get_icon_name (account));
414   tp_account_request_set_nickname (ar,
415       tp_account_get_nickname (account));
416   tp_account_request_set_service (ar,
417       tp_account_get_service (account));
418
419   /* Do not enable the new account until we imported the password as well */
420   tp_account_request_set_enabled (ar, FALSE);
421
422   supersedes = tp_account_get_supersedes (account);
423   while (*supersedes != NULL)
424     tp_account_request_add_supersedes (ar, *supersedes);
425   tp_account_request_add_supersedes (ar,
426       tp_proxy_get_object_path (account));
427
428   params = tp_account_dup_parameters_vardict (account);
429   g_variant_iter_init (&iter, params);
430   while ((param = g_variant_iter_next_value (&iter)))
431     {
432       GVariant *k, *v;
433       const gchar *key;
434
435       k = g_variant_get_child_value (param, 0);
436       key = g_variant_get_string (k, NULL);
437       v = g_variant_get_child_value (param, 1);
438
439       tp_account_request_set_parameter (ar, key,
440           g_variant_get_variant (v));
441
442       g_variant_unref (k);
443       g_variant_unref (v);
444     }
445
446   data = uoa_migration_data_new (account);
447   tp_account_set_enabled_async (account, FALSE, NULL, NULL);
448   tp_account_request_create_account_async (ar, uoa_account_created_cb,
449       data);
450
451   g_variant_unref (params);
452   g_object_unref (ar);
453 }
454
455 static void
456 uoa_plugin_install_cb (GObject *source,
457     GAsyncResult *result,
458     gpointer user_data)
459 {
460   TpAccount *account = user_data;
461   GError *error = NULL;
462   TpAccountManager *am;
463
464   if (!empathy_pkg_kit_install_packages_finish (result, &error))
465     {
466       DEBUG ("Failed to install plugin for account '%s' (%s); remove it",
467           tp_account_get_path_suffix (account), error->message);
468
469       g_error_free (error);
470
471       tp_account_remove_async (account, uoa_account_remove_cb, NULL);
472       goto out;
473     }
474
475   DEBUG ("Plugin for account '%s' has been installed; migrate account",
476       tp_account_get_path_suffix (account));
477
478   am = tp_account_manager_dup ();
479   migrate_account_to_uoa (am, account);
480   g_object_unref (am);
481
482 out:
483   g_object_unref (account);
484 }
485
486 static gchar *
487 dup_plugin_name_for_protocol (const gchar *protocol)
488 {
489   if (!tp_strdiff (protocol, "local-xmpp"))
490     return g_strdup ("account-plugin-salut");
491
492   return g_strdup_printf ("account-plugin-%s", protocol);
493 }
494
495 static gboolean
496 uoa_plugin_installed (AgManager *manager,
497     TpAccount *account)
498 {
499   AgAccount *ag_account;
500   const gchar *protocol;
501   GList *l;
502
503   protocol = tp_account_get_protocol_name (account);
504   ag_account = ag_manager_create_account (manager, protocol);
505
506   l = ag_account_list_services_by_type (ag_account, EMPATHY_UOA_SERVICE_TYPE);
507   if (l == NULL)
508     {
509       const gchar *packages[2];
510       gchar *pkg;
511
512       pkg = dup_plugin_name_for_protocol (protocol);
513
514       DEBUG ("%s is not installed; try to install it", pkg);
515
516       packages[0] = pkg;
517       packages[1] = NULL;
518
519       empathy_pkg_kit_install_packages_async (0, packages, NULL,
520           NULL, uoa_plugin_install_cb, g_object_ref (account));
521
522       g_free (pkg);
523       g_object_unref (ag_account);
524       return FALSE;
525     }
526
527   ag_service_list_free (l);
528
529   g_object_unref (ag_account);
530   return TRUE;
531 }
532
533 static void
534 migrate_accounts_to_uoa (SanityCtx *ctx)
535 {
536   GList *accounts, *l;
537   AgManager *manager;
538
539   DEBUG ("Start migrating accounts to UOA");
540
541   manager = empathy_uoa_manager_dup ();
542
543   accounts = tp_account_manager_dup_valid_accounts (ctx->am);
544   for (l = accounts; l != NULL; l = g_list_next (l))
545     {
546       TpAccount *account = l->data;
547
548       /* If account is already in a specific storage (like UOA or GOA),
549        * don't migrate it.
550        * Note that we cannot migrate GOA accounts anyway, since we can't delete
551        * them it would create duplicated accounts. */
552       if (!tp_str_empty (tp_account_get_storage_provider (account)))
553         continue;
554
555       g_object_set_data_full (G_OBJECT (account), DATA_SANITY_CTX,
556           sanity_ctx_ref (ctx), (GDestroyNotify) sanity_ctx_unref);
557
558       /* Try to install the plugin if it's missing */
559       if (!uoa_plugin_installed (manager, account))
560         continue;
561
562       migrate_account_to_uoa (ctx->am, account);
563     }
564
565   g_list_free_full (accounts, g_object_unref);
566
567   g_object_unref (manager);
568 }
569 #endif
570
571 static void
572 run_sanity_cleaning_tasks (SanityCtx *ctx)
573 {
574   DEBUG ("Starting sanity cleaning tasks");
575
576   fix_xmpp_account_priority (ctx->am);
577   set_facebook_account_fallback_server (ctx->am);
578   upgrade_chat_theme_settings ();
579 #ifdef HAVE_UOA
580   migrate_accounts_to_uoa (ctx);
581 #endif
582 }
583
584 static void
585 am_prepare_cb (GObject *source,
586     GAsyncResult *result,
587     gpointer user_data)
588 {
589   GError *error = NULL;
590   TpAccountManager *am = TP_ACCOUNT_MANAGER (source);
591   SanityCtx *ctx = user_data;
592
593   if (!tp_proxy_prepare_finish (am, result, &error))
594     {
595       DEBUG ("Failed to prepare account manager: %s", error->message);
596       g_simple_async_result_take_error (ctx->result, error);
597       goto out;
598     }
599
600   run_sanity_cleaning_tasks (ctx);
601
602 out:
603   sanity_ctx_unref (ctx);
604 }
605
606 void
607 empathy_sanity_checking_run_async (GAsyncReadyCallback callback,
608     gpointer user_data)
609 {
610   GSettings *settings;
611   guint number;
612   TpAccountManager *am;
613   GSimpleAsyncResult *result;
614   SanityCtx *ctx;
615
616   result = g_simple_async_result_new (NULL, callback, user_data,
617       empathy_sanity_checking_run_async);
618
619   settings = g_settings_new (EMPATHY_PREFS_SCHEMA);
620   number = g_settings_get_uint (settings, EMPATHY_PREFS_SANITY_CLEANING_NUMBER);
621
622   if (number == SANITY_CLEANING_NUMBER)
623     {
624       g_simple_async_result_complete_in_idle (result);
625       goto out;
626     }
627
628   am = tp_account_manager_dup ();
629
630   ctx = sanity_ctx_new (am, result);
631   tp_proxy_prepare_async (am, NULL, am_prepare_cb, ctx);
632
633   g_settings_set_uint (settings, EMPATHY_PREFS_SANITY_CLEANING_NUMBER,
634       SANITY_CLEANING_NUMBER);
635
636   g_object_unref (am);
637
638 out:
639   g_object_unref (settings);
640   g_object_unref (result);
641 }
642
643 gboolean
644 empathy_sanity_checking_run_finish (GAsyncResult *result,
645     GError **error)
646 {
647   g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
648         empathy_sanity_checking_run_async), FALSE);
649
650   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
651         error))
652     return FALSE;
653
654   return TRUE;
655 }