]> git.0d.be Git - empathy.git/blob - libempathy/empathy-account-settings.c
Updated Polish translation
[empathy.git] / libempathy / empathy-account-settings.c
1 /*
2  * empathy-account-settings.c - Source for EmpathyAccountSettings
3  * Copyright (C) 2009 Collabora Ltd.
4  * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <telepathy-glib/account-manager.h>
26 #include <telepathy-glib/util.h>
27 #include <telepathy-glib/interfaces.h>
28 #include <telepathy-glib/gtypes.h>
29
30 #include "empathy-account-settings.h"
31 #include "empathy-connection-managers.h"
32 #include "empathy-utils.h"
33 #include "empathy-idle.h"
34
35 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
36 #include <libempathy/empathy-debug.h>
37
38 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountSettings)
39
40 G_DEFINE_TYPE(EmpathyAccountSettings, empathy_account_settings, G_TYPE_OBJECT)
41
42 enum {
43   PROP_ACCOUNT = 1,
44   PROP_CM_NAME,
45   PROP_PROTOCOL,
46   PROP_DISPLAY_NAME,
47   PROP_DISPLAY_NAME_OVERRIDDEN,
48   PROP_READY
49 };
50
51 /* private structure */
52 typedef struct _EmpathyAccountSettingsPriv EmpathyAccountSettingsPriv;
53
54 struct _EmpathyAccountSettingsPriv
55 {
56   gboolean dispose_has_run;
57   EmpathyConnectionManagers *managers;
58   TpAccountManager *account_manager;
59
60   TpConnectionManager *manager;
61
62   TpAccount *account;
63   gchar *cm_name;
64   gchar *protocol;
65   gchar *display_name;
66   gchar *icon_name;
67   gboolean display_name_overridden;
68   gboolean ready;
69
70   GHashTable *parameters;
71   GArray *unset_parameters;
72   GArray *required_params;
73
74   gulong managers_ready_id;
75
76   GSimpleAsyncResult *apply_result;
77 };
78
79 static void
80 empathy_account_settings_init (EmpathyAccountSettings *obj)
81 {
82   EmpathyAccountSettingsPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE ((obj),
83     EMPATHY_TYPE_ACCOUNT_SETTINGS, EmpathyAccountSettingsPriv);
84
85   obj->priv = priv;
86
87   /* allocate any data required by the object here */
88   priv->managers = empathy_connection_managers_dup_singleton ();
89   priv->account_manager = tp_account_manager_dup ();
90
91   priv->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
92     g_free, (GDestroyNotify) tp_g_value_slice_free);
93
94   priv->unset_parameters = g_array_new (TRUE, FALSE, sizeof (gchar *));
95 }
96
97 static void empathy_account_settings_dispose (GObject *object);
98 static void empathy_account_settings_finalize (GObject *object);
99 static void empathy_account_settings_account_ready_cb (GObject *source_object,
100     GAsyncResult *result, gpointer user_data);
101 static void empathy_account_settings_managers_ready_cb (GObject *obj,
102     GParamSpec *pspec, gpointer user_data);
103 static void empathy_account_settings_check_readyness (
104     EmpathyAccountSettings *self);
105
106 static void
107 empathy_account_settings_set_property (GObject *object,
108     guint prop_id,
109     const GValue *value,
110     GParamSpec *pspec)
111 {
112   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (object);
113   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
114
115   switch (prop_id)
116     {
117       case PROP_ACCOUNT:
118         priv->account = g_value_dup_object (value);
119         break;
120       case PROP_CM_NAME:
121         priv->cm_name = g_value_dup_string (value);
122         break;
123       case PROP_PROTOCOL:
124         priv->protocol = g_value_dup_string (value);
125         break;
126       case PROP_DISPLAY_NAME:
127         priv->display_name = g_value_dup_string (value);
128         break;
129       case PROP_DISPLAY_NAME_OVERRIDDEN:
130         priv->display_name_overridden = g_value_get_boolean (value);
131         break;
132       default:
133         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
134         break;
135     }
136 }
137
138 static void
139 empathy_account_settings_get_property (GObject *object,
140     guint prop_id,
141     GValue *value,
142     GParamSpec *pspec)
143 {
144   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (object);
145   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
146
147   switch (prop_id)
148     {
149       case PROP_ACCOUNT:
150         g_value_set_object (value, priv->account);
151         break;
152       case PROP_CM_NAME:
153         g_value_set_string (value, priv->cm_name);
154         break;
155       case PROP_PROTOCOL:
156         g_value_set_string (value, priv->protocol);
157         break;
158       case PROP_DISPLAY_NAME:
159         g_value_set_string (value, priv->display_name);
160         break;
161       case PROP_DISPLAY_NAME_OVERRIDDEN:
162         g_value_set_boolean (value, priv->display_name_overridden);
163         break;
164       case PROP_READY:
165         g_value_set_boolean (value, priv->ready);
166         break;
167       default:
168         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
169         break;
170     }
171 }
172
173 static void
174 empathy_account_settings_constructed (GObject *object)
175 {
176   EmpathyAccountSettings *self = EMPATHY_ACCOUNT_SETTINGS (object);
177   EmpathyAccountSettingsPriv *priv = GET_PRIV (self);
178
179   if (priv->account != NULL)
180     {
181       g_free (priv->cm_name);
182       g_free (priv->protocol);
183
184       priv->cm_name =
185         g_strdup (tp_account_get_connection_manager (priv->account));
186       priv->protocol =
187         g_strdup (tp_account_get_protocol (priv->account));
188       priv->icon_name = g_strdup
189         (tp_account_get_icon_name (priv->account));
190     }
191   else
192     {
193       priv->icon_name = empathy_protocol_icon_name (priv->protocol);
194     }
195
196   g_assert (priv->cm_name != NULL && priv->protocol != NULL);
197
198   empathy_account_settings_check_readyness (self);
199
200   if (!priv->ready)
201     {
202       tp_account_prepare_async (priv->account, NULL,
203           empathy_account_settings_account_ready_cb, self);
204       empathy_signal_connect_weak (priv->managers, "notify::ready",
205         G_CALLBACK (empathy_account_settings_managers_ready_cb), object);
206     }
207
208   if (G_OBJECT_CLASS (
209         empathy_account_settings_parent_class)->constructed != NULL)
210     G_OBJECT_CLASS (
211         empathy_account_settings_parent_class)->constructed (object);
212 }
213
214
215 static void
216 empathy_account_settings_class_init (
217     EmpathyAccountSettingsClass *empathy_account_settings_class)
218 {
219   GObjectClass *object_class = G_OBJECT_CLASS (empathy_account_settings_class);
220
221   g_type_class_add_private (empathy_account_settings_class, sizeof
222       (EmpathyAccountSettingsPriv));
223
224   object_class->dispose = empathy_account_settings_dispose;
225   object_class->finalize = empathy_account_settings_finalize;
226   object_class->set_property = empathy_account_settings_set_property;
227   object_class->get_property = empathy_account_settings_get_property;
228   object_class->constructed = empathy_account_settings_constructed;
229
230   g_object_class_install_property (object_class, PROP_ACCOUNT,
231     g_param_spec_object ("account",
232       "Account",
233       "The TpAccount backing these settings",
234       TP_TYPE_ACCOUNT,
235       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
236
237   g_object_class_install_property (object_class, PROP_CM_NAME,
238     g_param_spec_string ("connection-manager",
239       "connection-manager",
240       "The name of the connection manager this account uses",
241       NULL,
242       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
243
244   g_object_class_install_property (object_class, PROP_PROTOCOL,
245     g_param_spec_string ("protocol",
246       "Protocol",
247       "The name of the protocol this account uses",
248       NULL,
249       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
250
251   g_object_class_install_property (object_class, PROP_DISPLAY_NAME,
252     g_param_spec_string ("display-name",
253       "display-name",
254       "The display name account these settings belong to",
255       NULL,
256       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
257
258   g_object_class_install_property (object_class, PROP_DISPLAY_NAME_OVERRIDDEN,
259       g_param_spec_boolean ("display-name-overridden",
260         "display-name-overridden",
261         "Whether the display name for this account has been manually "
262         "overridden",
263         FALSE,
264         G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
265
266   g_object_class_install_property (object_class, PROP_READY,
267     g_param_spec_boolean ("ready",
268       "Ready",
269       "Whether this account is ready to be used",
270       FALSE,
271       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
272 }
273
274 static void
275 empathy_account_settings_dispose (GObject *object)
276 {
277   EmpathyAccountSettings *self = EMPATHY_ACCOUNT_SETTINGS (object);
278   EmpathyAccountSettingsPriv *priv = GET_PRIV (self);
279
280   if (priv->dispose_has_run)
281     return;
282
283   priv->dispose_has_run = TRUE;
284
285   if (priv->managers_ready_id != 0)
286     g_signal_handler_disconnect (priv->managers, priv->managers_ready_id);
287   priv->managers_ready_id = 0;
288
289   if (priv->managers != NULL)
290     g_object_unref (priv->managers);
291   priv->managers = NULL;
292
293   if (priv->manager != NULL)
294     g_object_unref (priv->manager);
295   priv->manager = NULL;
296
297   if (priv->account_manager != NULL)
298     g_object_unref (priv->account_manager);
299   priv->account_manager = NULL;
300
301   if (priv->account != NULL)
302     g_object_unref (priv->account);
303   priv->account = NULL;
304
305   /* release any references held by the object here */
306   if (G_OBJECT_CLASS (empathy_account_settings_parent_class)->dispose)
307     G_OBJECT_CLASS (empathy_account_settings_parent_class)->dispose (object);
308 }
309
310 static void
311 empathy_account_settings_free_unset_parameters (
312     EmpathyAccountSettings *settings)
313 {
314   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
315   guint i;
316
317   for (i = 0 ; i < priv->unset_parameters->len; i++)
318     g_free (g_array_index (priv->unset_parameters, gchar *, i));
319
320   g_array_set_size (priv->unset_parameters, 0);
321 }
322
323 static void
324 empathy_account_settings_finalize (GObject *object)
325 {
326   EmpathyAccountSettings *self = EMPATHY_ACCOUNT_SETTINGS (object);
327   EmpathyAccountSettingsPriv *priv = GET_PRIV (self);
328
329   /* free any data held directly by the object here */
330   g_free (priv->cm_name);
331   g_free (priv->protocol);
332   g_free (priv->display_name);
333   g_free (priv->icon_name);
334
335   if (priv->required_params != NULL)
336     g_array_free (priv->required_params, TRUE);
337
338   g_hash_table_destroy (priv->parameters);
339
340   empathy_account_settings_free_unset_parameters (self);
341   g_array_free (priv->unset_parameters, TRUE);
342
343   G_OBJECT_CLASS (empathy_account_settings_parent_class)->finalize (object);
344 }
345
346 static void
347 empathy_account_settings_check_readyness (EmpathyAccountSettings *self)
348 {
349   EmpathyAccountSettingsPriv *priv = GET_PRIV (self);
350   const TpConnectionManagerProtocol *tp_protocol;
351
352   if (priv->ready)
353     return;
354
355   if (priv->account != NULL
356       && !tp_account_is_prepared (priv->account, TP_ACCOUNT_FEATURE_CORE))
357       return;
358
359   if (!empathy_connection_managers_is_ready (priv->managers))
360     return;
361
362   priv->manager = empathy_connection_managers_get_cm (
363     priv->managers, priv->cm_name);
364
365   if (priv->manager == NULL)
366     return;
367
368   if (priv->account != NULL)
369     {
370       g_free (priv->display_name);
371       priv->display_name =
372         g_strdup (tp_account_get_display_name (priv->account));
373
374       g_free (priv->icon_name);
375       priv->icon_name =
376         g_strdup (tp_account_get_icon_name (priv->account));
377     }
378
379   tp_protocol = tp_connection_manager_get_protocol (priv->manager,
380     priv->protocol);
381
382   if (tp_protocol == NULL)
383     {
384       priv->manager = NULL;
385       return;
386     }
387
388   if (priv->required_params == NULL)
389     {
390       TpConnectionManagerParam *cur;
391       char *val;
392
393       priv->required_params = g_array_new (TRUE, FALSE, sizeof (gchar *));
394
395       for (cur = tp_protocol->params; cur->name != NULL; cur++)
396         {
397           if (tp_connection_manager_param_is_required (cur))
398             {
399               val = g_strdup (cur->name);
400               g_array_append_val (priv->required_params, val);
401             }
402         }
403     }
404
405   g_object_ref (priv->manager);
406
407   priv->ready = TRUE;
408   g_object_notify (G_OBJECT (self), "ready");
409 }
410
411 static void
412 empathy_account_settings_account_ready_cb (GObject *source_object,
413     GAsyncResult *result,
414     gpointer user_data)
415 {
416   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
417   TpAccount *account = TP_ACCOUNT (source_object);
418   GError *error = NULL;
419
420   if (!tp_account_prepare_finish (account, result, &error))
421     {
422       DEBUG ("Failed to prepare account: %s", error->message);
423       g_error_free (error);
424       return;
425     }
426
427   empathy_account_settings_check_readyness (settings);
428 }
429
430 static void
431 empathy_account_settings_managers_ready_cb (GObject *object,
432     GParamSpec *pspec,
433     gpointer user_data)
434 {
435   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
436
437   empathy_account_settings_check_readyness (settings);
438 }
439
440 EmpathyAccountSettings *
441 empathy_account_settings_new (const gchar *connection_manager,
442     const gchar *protocol,
443     const char *display_name)
444 {
445   return g_object_new (EMPATHY_TYPE_ACCOUNT_SETTINGS,
446       "connection-manager", connection_manager,
447       "protocol", protocol,
448       "display-name", display_name,
449       NULL);
450 }
451
452 EmpathyAccountSettings *
453 empathy_account_settings_new_for_account (TpAccount *account)
454 {
455   return g_object_new (EMPATHY_TYPE_ACCOUNT_SETTINGS,
456       "account", account,
457       NULL);
458 }
459
460 TpConnectionManagerParam *
461 empathy_account_settings_get_tp_params (EmpathyAccountSettings *settings)
462 {
463   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
464   const TpConnectionManagerProtocol *tp_protocol;
465
466   g_return_val_if_fail (priv->manager != NULL, NULL);
467   g_return_val_if_fail (priv->protocol != NULL, NULL);
468
469   tp_protocol = tp_connection_manager_get_protocol (priv->manager,
470      priv->protocol);
471   if (tp_protocol == NULL)
472     {
473       DEBUG ("Can't retrieve TpConnectionManagerProtocol for protocol '%s'",
474           priv->protocol);
475       return NULL;
476     }
477
478   return tp_protocol->params;
479 }
480
481 gboolean
482 empathy_account_settings_is_ready (EmpathyAccountSettings *settings)
483 {
484   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
485
486   return priv->ready;
487 }
488
489 const gchar *
490 empathy_account_settings_get_cm (EmpathyAccountSettings *settings)
491 {
492   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
493
494   return priv->cm_name;
495 }
496
497 const gchar *
498 empathy_account_settings_get_protocol (EmpathyAccountSettings *settings)
499 {
500   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
501
502   return priv->protocol;
503 }
504
505 gchar *
506 empathy_account_settings_get_icon_name (EmpathyAccountSettings *settings)
507 {
508   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
509
510   return priv->icon_name;
511 }
512
513 const gchar *
514 empathy_account_settings_get_display_name (EmpathyAccountSettings *settings)
515 {
516   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
517
518   return priv->display_name;
519 }
520
521 TpAccount *
522 empathy_account_settings_get_account (EmpathyAccountSettings *settings)
523 {
524   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
525
526   return priv->account;
527 }
528
529 static gboolean
530 empathy_account_settings_is_unset (EmpathyAccountSettings *settings,
531     const gchar *param)
532 {
533   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
534   GArray *a;
535   guint i;
536
537   a = priv->unset_parameters;
538
539   for (i = 0; i < a->len; i++)
540     {
541       if (!tp_strdiff (g_array_index (a, gchar *, i), param))
542         return TRUE;
543     }
544
545   return FALSE;
546 }
547
548 static TpConnectionManagerParam *
549 empathy_account_settings_get_tp_param (EmpathyAccountSettings *settings,
550     const gchar *param)
551 {
552   TpConnectionManagerParam *tp_params =
553       empathy_account_settings_get_tp_params (settings);
554   TpConnectionManagerParam *p;
555
556   for (p = tp_params; p != NULL && p->name != NULL; p++)
557     {
558       if (tp_strdiff (p->name, param))
559         continue;
560
561       return p;
562     }
563
564   return NULL;
565 }
566
567 static void
568 account_settings_remove_from_unset (EmpathyAccountSettings *settings,
569     const gchar *param)
570 {
571   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
572   guint idx;
573   gchar *val;
574
575   for (idx = 0; idx < priv->unset_parameters->len; idx++)
576     {
577       val = g_array_index (priv->unset_parameters, gchar *, idx);
578
579       if (!tp_strdiff (val, param))
580         {
581           priv->unset_parameters =
582             g_array_remove_index (priv->unset_parameters, idx);
583           g_free (val);
584
585           break;
586         }
587     }
588 }
589
590 const GValue *
591 empathy_account_settings_get_default (EmpathyAccountSettings *settings,
592     const gchar *param)
593 {
594   TpConnectionManagerParam *p;
595
596   p = empathy_account_settings_get_tp_param (settings, param);
597
598   if (p == NULL || !(p->flags & TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT))
599     return NULL;
600
601   return &(p->default_value);
602 }
603
604 const gchar *
605 empathy_account_settings_get_dbus_signature (EmpathyAccountSettings *settings,
606     const gchar *param)
607 {
608   TpConnectionManagerParam *p;
609
610   p = empathy_account_settings_get_tp_param (settings, param);
611
612   if (p == NULL)
613     return NULL;
614
615   return p->dbus_signature;
616 }
617
618 const GValue *
619 empathy_account_settings_get (EmpathyAccountSettings *settings,
620     const gchar *param)
621 {
622   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
623   const GValue *result = NULL;
624
625   /* Lookup the update parameters we set */
626   result = tp_asv_lookup (priv->parameters, param);
627   if (result != NULL)
628     return result;
629
630   /* If the parameters isn't unset use the accounts setting if any */
631   if (priv->account != NULL
632       && !empathy_account_settings_is_unset (settings, param))
633     {
634       const GHashTable *parameters;
635
636       parameters = tp_account_get_parameters (priv->account);
637       result = tp_asv_lookup (parameters, param);
638
639       if (result != NULL)
640         return result;
641     }
642
643   /* fallback to the default */
644   return empathy_account_settings_get_default (settings, param);
645 }
646
647 void
648 empathy_account_settings_unset (EmpathyAccountSettings *settings,
649     const gchar *param)
650 {
651   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
652   gchar *v;
653   if (empathy_account_settings_is_unset (settings, param))
654     return;
655
656   v = g_strdup (param);
657
658   g_array_append_val (priv->unset_parameters, v);
659   g_hash_table_remove (priv->parameters, param);
660 }
661
662 void
663 empathy_account_settings_discard_changes (EmpathyAccountSettings *settings)
664 {
665   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
666
667   g_hash_table_remove_all (priv->parameters);
668   empathy_account_settings_free_unset_parameters (settings);
669 }
670
671 const gchar *
672 empathy_account_settings_get_string (EmpathyAccountSettings *settings,
673     const gchar *param)
674 {
675   const GValue *v;
676
677   v = empathy_account_settings_get (settings, param);
678
679   if (v == NULL || !G_VALUE_HOLDS_STRING (v))
680     return NULL;
681
682   return g_value_get_string (v);
683 }
684
685 gint32
686 empathy_account_settings_get_int32 (EmpathyAccountSettings *settings,
687     const gchar *param)
688 {
689   const GValue *v;
690   gint32 ret = 0;
691
692   v = empathy_account_settings_get (settings, param);
693
694   if (v == NULL)
695     return 0;
696
697   switch G_VALUE_TYPE (v)
698     {
699       case G_TYPE_UCHAR:
700         ret = g_value_get_uchar (v);
701         break;
702       case G_TYPE_INT:
703         ret = g_value_get_int (v);
704         break;
705       case G_TYPE_UINT:
706         ret = CLAMP (g_value_get_uint (v), (guint) G_MININT32,
707             G_MAXINT32);
708         break;
709       case G_TYPE_INT64:
710         ret = CLAMP (g_value_get_int64 (v), G_MININT32, G_MAXINT32);
711         break;
712       case G_TYPE_UINT64:
713         ret = CLAMP (g_value_get_uint64 (v), (guint64) G_MININT32,
714             G_MAXINT32);
715         break;
716       default:
717         ret = 0;
718         break;
719     }
720
721   return ret;
722 }
723
724 gint64
725 empathy_account_settings_get_int64 (EmpathyAccountSettings *settings,
726     const gchar *param)
727 {
728   const GValue *v;
729   gint64 ret = 0;
730
731   v = empathy_account_settings_get (settings, param);
732   if (v == NULL)
733     return 0;
734
735   switch G_VALUE_TYPE (v)
736     {
737       case G_TYPE_UCHAR:
738         ret = g_value_get_uchar (v);
739         break;
740       case G_TYPE_INT:
741         ret = g_value_get_int (v);
742         break;
743       case G_TYPE_UINT:
744         ret = g_value_get_uint (v);
745         break;
746       case G_TYPE_INT64:
747         ret = g_value_get_int64 (v);
748         break;
749       case G_TYPE_UINT64:
750         ret = CLAMP (g_value_get_uint64 (v), (guint64) G_MININT64, G_MAXINT64);
751         break;
752       default:
753         ret = 0;
754         break;
755     }
756
757   return ret;
758 }
759
760 guint32
761 empathy_account_settings_get_uint32 (EmpathyAccountSettings *settings,
762     const gchar *param)
763 {
764   const GValue *v;
765   guint32 ret;
766
767   v = empathy_account_settings_get (settings, param);
768   if (v == NULL)
769     return 0;
770
771   switch G_VALUE_TYPE (v)
772     {
773       case G_TYPE_UCHAR:
774         ret = g_value_get_uchar (v);
775         break;
776       case G_TYPE_INT:
777         ret = MAX (0, g_value_get_int (v));
778         break;
779       case G_TYPE_UINT:
780         ret = g_value_get_uint (v);
781         break;
782       case G_TYPE_INT64:
783         ret = CLAMP (g_value_get_int64 (v), 0, G_MAXUINT32);
784         break;
785       case G_TYPE_UINT64:
786         ret = MIN (g_value_get_uint64 (v), G_MAXUINT32);
787         break;
788       default:
789         ret = 0;
790         break;
791     }
792
793   return ret;
794 }
795
796 guint64
797 empathy_account_settings_get_uint64 (EmpathyAccountSettings *settings,
798     const gchar *param)
799 {
800   const GValue *v;
801   guint64 ret = 0;
802
803   v = empathy_account_settings_get (settings, param);
804
805   if (v == NULL || !G_VALUE_HOLDS_INT (v))
806     return 0;
807
808   switch G_VALUE_TYPE (v)
809     {
810       case G_TYPE_UCHAR:
811         ret = g_value_get_uchar (v);
812         break;
813       case G_TYPE_INT:
814         ret = MAX (0, g_value_get_int (v));
815         break;
816       case G_TYPE_UINT:
817         ret = g_value_get_uint (v);
818         break;
819       case G_TYPE_INT64:
820         ret = MAX (0, g_value_get_int64 (v));
821         break;
822       case G_TYPE_UINT64:
823         ret = g_value_get_uint64 (v);
824         break;
825       default:
826         ret = 0;
827         break;
828     }
829
830   return ret;
831 }
832
833 gboolean
834 empathy_account_settings_get_boolean (EmpathyAccountSettings *settings,
835     const gchar *param)
836 {
837   const GValue *v;
838
839   v = empathy_account_settings_get (settings, param);
840
841   if (v == NULL || !G_VALUE_HOLDS_BOOLEAN (v))
842     return FALSE;
843
844   return g_value_get_boolean (v);
845 }
846
847 void
848 empathy_account_settings_set_string (EmpathyAccountSettings *settings,
849     const gchar *param,
850     const gchar *value)
851 {
852   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
853
854   tp_asv_set_string (priv->parameters, g_strdup (param), value);
855
856   account_settings_remove_from_unset (settings, param);
857 }
858
859 void
860 empathy_account_settings_set_int32 (EmpathyAccountSettings *settings,
861     const gchar *param,
862     gint32 value)
863 {
864   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
865
866   tp_asv_set_int32 (priv->parameters, g_strdup (param), value);
867
868   account_settings_remove_from_unset (settings, param);
869 }
870
871 void
872 empathy_account_settings_set_int64 (EmpathyAccountSettings *settings,
873     const gchar *param,
874     gint64 value)
875 {
876   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
877
878   tp_asv_set_int64 (priv->parameters, g_strdup (param), value);
879
880   account_settings_remove_from_unset (settings, param);
881 }
882
883 void
884 empathy_account_settings_set_uint32 (EmpathyAccountSettings *settings,
885     const gchar *param,
886     guint32 value)
887 {
888   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
889
890   tp_asv_set_uint32 (priv->parameters, g_strdup (param), value);
891
892   account_settings_remove_from_unset (settings, param);
893 }
894
895 void
896 empathy_account_settings_set_uint64 (EmpathyAccountSettings *settings,
897     const gchar *param,
898     guint64 value)
899 {
900   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
901
902   tp_asv_set_uint64 (priv->parameters, g_strdup (param), value);
903
904   account_settings_remove_from_unset (settings, param);
905 }
906
907 void
908 empathy_account_settings_set_boolean (EmpathyAccountSettings *settings,
909     const gchar *param,
910     gboolean value)
911 {
912   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
913
914   tp_asv_set_boolean (priv->parameters, g_strdup (param), value);
915
916   account_settings_remove_from_unset (settings, param);
917 }
918
919 static void
920 account_settings_display_name_set_cb (GObject *src,
921     GAsyncResult *res,
922     gpointer user_data)
923 {
924   GError *error = NULL;
925   TpAccount *account = TP_ACCOUNT (src);
926   GSimpleAsyncResult *set_result = user_data;
927
928   tp_account_set_display_name_finish (account, res, &error);
929
930   if (error != NULL)
931     {
932       g_simple_async_result_set_from_error (set_result, error);
933       g_error_free (error);
934     }
935
936   g_simple_async_result_complete (set_result);
937   g_object_unref (set_result);
938 }
939
940 void
941 empathy_account_settings_set_display_name_async (
942   EmpathyAccountSettings *settings,
943   const gchar *name,
944   GAsyncReadyCallback callback,
945   gpointer user_data)
946 {
947   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
948   GSimpleAsyncResult *result;
949
950   result = g_simple_async_result_new (G_OBJECT (settings),
951       callback, user_data, empathy_account_settings_set_display_name_finish);
952
953   if (!tp_strdiff (name, priv->display_name))
954     {
955       /* Nothing to do */
956       g_simple_async_result_complete_in_idle (result);
957       return;
958     }
959
960   if (priv->account == NULL)
961     {
962       if (priv->display_name != NULL)
963         g_free (priv->display_name);
964
965       priv->display_name = g_strdup (name);
966
967       g_simple_async_result_complete_in_idle (result);
968
969       return;
970     }
971
972   tp_account_set_display_name_async (priv->account, name,
973       account_settings_display_name_set_cb, result);
974 }
975
976 gboolean
977 empathy_account_settings_set_display_name_finish (
978   EmpathyAccountSettings *settings,
979   GAsyncResult *result,
980   GError **error)
981 {
982   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
983       error))
984     return FALSE;
985
986   g_return_val_if_fail (g_simple_async_result_is_valid (result,
987     G_OBJECT (settings), empathy_account_settings_set_display_name_finish),
988       FALSE);
989
990   return TRUE;
991 }
992
993 static void
994 account_settings_icon_name_set_cb (GObject *src,
995     GAsyncResult *res,
996     gpointer user_data)
997 {
998   GError *error = NULL;
999   TpAccount *account = TP_ACCOUNT (src);
1000   GSimpleAsyncResult *set_result = user_data;
1001
1002   tp_account_set_icon_name_finish (account, res, &error);
1003
1004   if (error != NULL)
1005     {
1006       g_simple_async_result_set_from_error (set_result, error);
1007       g_error_free (error);
1008     }
1009
1010   g_simple_async_result_complete (set_result);
1011   g_object_unref (set_result);
1012 }
1013
1014 void
1015 empathy_account_settings_set_icon_name_async (
1016   EmpathyAccountSettings *settings,
1017   const gchar *name,
1018   GAsyncReadyCallback callback,
1019   gpointer user_data)
1020 {
1021   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
1022   GSimpleAsyncResult *result;
1023
1024   result = g_simple_async_result_new (G_OBJECT (settings),
1025       callback, user_data, empathy_account_settings_set_icon_name_finish);
1026
1027   if (priv->account == NULL)
1028     {
1029       if (priv->icon_name != NULL)
1030         g_free (priv->icon_name);
1031
1032       priv->icon_name = g_strdup (name);
1033
1034       g_simple_async_result_complete_in_idle (result);
1035
1036       return;
1037     }
1038
1039   tp_account_set_icon_name_async (priv->account, name,
1040       account_settings_icon_name_set_cb, result);
1041 }
1042
1043 gboolean
1044 empathy_account_settings_set_icon_name_finish (
1045   EmpathyAccountSettings *settings,
1046   GAsyncResult *result,
1047   GError **error)
1048 {
1049   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
1050       error))
1051     return FALSE;
1052
1053   g_return_val_if_fail (g_simple_async_result_is_valid (result,
1054     G_OBJECT (settings), empathy_account_settings_set_icon_name_finish),
1055       FALSE);
1056
1057   return TRUE;
1058 }
1059
1060 static void
1061 empathy_account_settings_account_updated (GObject *source,
1062     GAsyncResult *result,
1063     gpointer user_data)
1064 {
1065   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
1066   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
1067   GSimpleAsyncResult *r;
1068   GError *error = NULL;
1069
1070   if (!tp_account_update_parameters_finish (TP_ACCOUNT (source),
1071           result, NULL, &error))
1072     {
1073       g_simple_async_result_set_from_error (priv->apply_result, error);
1074       g_error_free (error);
1075     }
1076   else
1077     {
1078       empathy_account_settings_discard_changes (settings);
1079     }
1080
1081   r = priv->apply_result;
1082   priv->apply_result = NULL;
1083
1084   g_simple_async_result_complete (r);
1085   g_object_unref (r);
1086 }
1087
1088 static void
1089 empathy_account_settings_created_cb (GObject *source,
1090     GAsyncResult *result,
1091     gpointer user_data)
1092 {
1093   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
1094   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
1095   TpAccount *account;
1096   GError *error = NULL;
1097   GSimpleAsyncResult *r;
1098
1099   account = tp_account_manager_create_account_finish (
1100     TP_ACCOUNT_MANAGER (source), result, &error);
1101
1102   if (account == NULL)
1103     {
1104       g_simple_async_result_set_from_error (priv->apply_result, error);
1105     }
1106   else
1107     {
1108       priv->account = g_object_ref (account);
1109       empathy_account_settings_discard_changes (settings);
1110     }
1111
1112   r = priv->apply_result;
1113   priv->apply_result = NULL;
1114
1115   g_simple_async_result_complete (r);
1116   g_object_unref (r);
1117 }
1118
1119
1120 static void
1121 empathy_account_settings_do_create_account (EmpathyAccountSettings *settings)
1122 {
1123   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
1124   GHashTable *properties;
1125   TpConnectionPresenceType type;
1126   gchar *status;
1127   gchar *message;
1128   EmpathyIdle *idle;
1129
1130   properties = tp_asv_new (NULL, NULL);
1131
1132   idle = empathy_idle_dup_singleton ();
1133   type = empathy_idle_get_requested_presence (idle, &status, &message);
1134   g_object_unref (idle);
1135
1136   if (type != TP_CONNECTION_PRESENCE_TYPE_UNSET)
1137     {
1138       /* Create the account with the requested presence the same as the current
1139         * global requested presence, but don't enable it */
1140       GValueArray *presence;
1141       GValue vtype = { 0, };
1142       GValue vstatus = { 0, };
1143       GValue vmessage = { 0, };
1144
1145       presence = g_value_array_new (3);
1146
1147       g_value_init (&vtype, G_TYPE_UINT);
1148       g_value_set_uint (&vtype, type);
1149       g_value_array_append (presence, &vtype);
1150
1151       g_value_init (&vstatus, G_TYPE_STRING);
1152       g_value_take_string (&vstatus, status);
1153       g_value_array_append (presence, &vstatus);
1154
1155       g_value_init (&vmessage, G_TYPE_STRING);
1156       g_value_take_string (&vmessage, message);
1157       g_value_array_append (presence, &vmessage);
1158
1159       tp_asv_take_boxed (properties, TP_IFACE_ACCOUNT ".RequestedPresence",
1160         TP_STRUCT_TYPE_SIMPLE_PRESENCE, presence);
1161     }
1162
1163   tp_asv_set_string (properties, TP_IFACE_ACCOUNT ".Icon",
1164       priv->icon_name);
1165
1166   tp_account_manager_create_account_async (priv->account_manager,
1167     priv->cm_name, priv->protocol, priv->display_name,
1168     priv->parameters, properties,
1169     empathy_account_settings_created_cb,
1170     settings);
1171
1172   g_hash_table_unref (properties);
1173 }
1174
1175 static void
1176 empathy_account_settings_manager_ready_cb (GObject *source_object,
1177     GAsyncResult *result,
1178     gpointer user_data)
1179 {
1180   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
1181   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
1182   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
1183   GError *error = NULL;
1184
1185   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
1186     {
1187       DEBUG ("Failed to prepare account manager: %s", error->message);
1188       g_error_free (error);
1189       return;
1190     }
1191
1192   g_assert (priv->apply_result != NULL && priv->account == NULL);
1193   empathy_account_settings_do_create_account (settings);
1194 }
1195
1196 void
1197 empathy_account_settings_apply_async (EmpathyAccountSettings *settings,
1198     GAsyncReadyCallback callback,
1199     gpointer user_data)
1200 {
1201   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
1202
1203   if (priv->apply_result != NULL)
1204     {
1205       g_simple_async_report_error_in_idle (G_OBJECT (settings),
1206           callback, user_data,
1207           G_IO_ERROR, G_IO_ERROR_PENDING, "Applying already in progress");
1208       return;
1209     }
1210
1211   priv->apply_result = g_simple_async_result_new (G_OBJECT (settings),
1212       callback, user_data, empathy_account_settings_apply_finish);
1213
1214   if (priv->account == NULL)
1215     {
1216       tp_account_manager_prepare_async (priv->account_manager, NULL,
1217           empathy_account_settings_manager_ready_cb, settings);
1218     }
1219   else
1220     {
1221       tp_account_update_parameters_async (priv->account,
1222           priv->parameters, (const gchar **)priv->unset_parameters->data,
1223           empathy_account_settings_account_updated, settings);
1224     }
1225 }
1226
1227 gboolean
1228 empathy_account_settings_apply_finish (EmpathyAccountSettings *settings,
1229     GAsyncResult *result,
1230     GError **error)
1231 {
1232   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
1233       error))
1234     return FALSE;
1235
1236   g_return_val_if_fail (g_simple_async_result_is_valid (result,
1237     G_OBJECT (settings), empathy_account_settings_apply_finish), FALSE);
1238
1239   return TRUE;
1240 }
1241
1242 gboolean
1243 empathy_account_settings_has_account (EmpathyAccountSettings *settings,
1244     TpAccount *account)
1245 {
1246   EmpathyAccountSettingsPriv *priv;
1247   const gchar *account_path;
1248   const gchar *priv_account_path;
1249
1250   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), FALSE);
1251   g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
1252
1253   priv = GET_PRIV (settings);
1254
1255   if (priv->account == NULL)
1256     return FALSE;
1257
1258   account_path = tp_proxy_get_object_path (TP_PROXY (account));
1259   priv_account_path = tp_proxy_get_object_path (TP_PROXY (priv->account));
1260
1261   return (!tp_strdiff (account_path, priv_account_path));
1262 }
1263
1264 gboolean
1265 empathy_account_settings_is_valid (EmpathyAccountSettings *settings)
1266 {
1267   EmpathyAccountSettingsPriv *priv;
1268   guint idx;
1269   gchar *current;
1270   gboolean missed = FALSE;
1271
1272   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), FALSE);
1273
1274   priv = GET_PRIV (settings);
1275
1276   for (idx = 0; idx < priv->required_params->len; idx++)
1277     {
1278       current = g_array_index (priv->required_params, gchar *, idx);
1279
1280       /* first, look if it's set in our own parameters */
1281       if (tp_asv_lookup (priv->parameters, current))
1282         continue;
1283
1284       /* if we did not unset the parameter, look if it's in the account */
1285       if (priv->account != NULL &&
1286           !empathy_account_settings_is_unset (settings, current))
1287         {
1288           const GHashTable *account_params;
1289
1290           account_params = tp_account_get_parameters (priv->account);
1291           if (tp_asv_lookup (account_params, current))
1292             continue;
1293         }
1294
1295       missed = TRUE;
1296       break;
1297     }
1298
1299   return !missed;
1300 }
1301
1302 const TpConnectionManagerProtocol *
1303 empathy_account_settings_get_tp_protocol (EmpathyAccountSettings *self)
1304 {
1305   EmpathyAccountSettingsPriv *priv = GET_PRIV (self);
1306
1307   return tp_connection_manager_get_protocol (priv->manager, priv->protocol);
1308 }