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