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