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