]> git.0d.be Git - empathy.git/blob - libempathy/empathy-account-settings.c
Rename empathy_account_get_connection_for to empathy_account_get_connection_for_path
[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 const GValue *
519 empathy_account_settings_get_default (EmpathyAccountSettings *settings,
520     const gchar *param)
521 {
522   TpConnectionManagerParam *p;
523
524   p = empathy_account_settings_get_tp_param (settings, param);
525
526   if (p == NULL || !(p->flags & TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT))
527     return NULL;
528
529   return &(p->default_value);
530 }
531
532 const gchar *
533 empathy_account_settings_get_dbus_signature (EmpathyAccountSettings *settings,
534     const gchar *param)
535 {
536   TpConnectionManagerParam *p;
537
538   p = empathy_account_settings_get_tp_param (settings, param);
539
540   if (p == NULL)
541     return NULL;
542
543   return p->dbus_signature;
544 }
545
546 const GValue *
547 empathy_account_settings_get (EmpathyAccountSettings *settings,
548     const gchar *param)
549 {
550   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
551   const GValue *result = NULL;
552
553   /* Lookup the update parameters we set */
554   result = tp_asv_lookup (priv->parameters, param);
555   if (result != NULL)
556     return result;
557
558   /* If the parameters isn't unset use the accounts setting if any */
559   if (priv->account != NULL
560       && !empathy_account_settings_is_unset (settings, param))
561     {
562       const GHashTable *parameters;
563
564       parameters = empathy_account_get_parameters (priv->account);
565       result = tp_asv_lookup (parameters, param);
566
567       if (result != NULL)
568         return result;
569     }
570
571   /* fallback to the default */
572   return empathy_account_settings_get_default (settings, param);
573 }
574
575
576 void
577 empathy_account_settings_unset (EmpathyAccountSettings *settings,
578     const gchar *param)
579 {
580   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
581   gchar *v;
582   if (empathy_account_settings_is_unset (settings, param))
583     return;
584
585   v = g_strdup (param);
586
587   g_array_append_val (priv->unset_parameters, v);
588   g_hash_table_remove (priv->parameters, param);
589 }
590
591 const gchar *
592 empathy_account_settings_get_string (EmpathyAccountSettings *settings,
593     const gchar *param)
594 {
595   const GValue *v;
596
597   v = empathy_account_settings_get (settings, param);
598
599   if (v == NULL || !G_VALUE_HOLDS_STRING (v))
600     return NULL;
601
602   return g_value_get_string (v);
603 }
604
605 gint32
606 empathy_account_settings_get_int32 (EmpathyAccountSettings *settings,
607     const gchar *param)
608 {
609   const GValue *v;
610   gint32 ret = 0;
611
612   v = empathy_account_settings_get (settings, param);
613
614   if (v == NULL)
615     return 0;
616
617   switch G_VALUE_TYPE (v)
618     {
619       case G_TYPE_UCHAR:
620         ret = g_value_get_uchar (v);
621         break;
622       case G_TYPE_INT:
623         ret = g_value_get_int (v);
624         break;
625       case G_TYPE_UINT:
626         ret = CLAMP (G_MININT32, g_value_get_uint (v), G_MAXINT32);
627         break;
628       case G_TYPE_INT64:
629         ret = CLAMP (G_MININT32, g_value_get_int64 (v), G_MAXINT32);
630         break;
631       case G_TYPE_UINT64:
632         ret = CLAMP (G_MININT32, g_value_get_uint64 (v), G_MAXINT32);
633         break;
634       default:
635         ret = 0;
636         break;
637     }
638
639   return ret;
640 }
641
642 gint64
643 empathy_account_settings_get_int64 (EmpathyAccountSettings *settings,
644     const gchar *param)
645 {
646   const GValue *v;
647   gint64 ret = 0;
648
649   v = empathy_account_settings_get (settings, param);
650   if (v == NULL)
651     return 0;
652
653   switch G_VALUE_TYPE (v)
654     {
655       case G_TYPE_UCHAR:
656         ret = g_value_get_uchar (v);
657         break;
658       case G_TYPE_INT:
659         ret = g_value_get_int (v);
660         break;
661       case G_TYPE_UINT:
662         ret = g_value_get_uint (v);
663         break;
664       case G_TYPE_INT64:
665         ret = g_value_get_int64 (v);
666         break;
667       case G_TYPE_UINT64:
668         ret = CLAMP (G_MININT64, g_value_get_uint64 (v), G_MAXINT64);
669         break;
670       default:
671         ret = 0;
672         break;
673     }
674
675   return ret;
676 }
677
678 guint32
679 empathy_account_settings_get_uint32 (EmpathyAccountSettings *settings,
680     const gchar *param)
681 {
682   const GValue *v;
683   guint32 ret;
684
685   v = empathy_account_settings_get (settings, param);
686
687   switch G_VALUE_TYPE (v)
688     {
689       case G_TYPE_UCHAR:
690         ret = g_value_get_uchar (v);
691         break;
692       case G_TYPE_INT:
693         ret = MAX (0, g_value_get_int (v));
694         break;
695       case G_TYPE_UINT:
696         ret = g_value_get_uint (v);
697         break;
698       case G_TYPE_INT64:
699         ret = CLAMP (0, g_value_get_int64 (v), G_MAXUINT32);
700         break;
701       case G_TYPE_UINT64:
702         ret = CLAMP (0, g_value_get_uint64 (v), G_MAXUINT32);
703         break;
704       default:
705         ret = 0;
706         break;
707     }
708
709   return ret;
710 }
711
712 guint64
713 empathy_account_settings_get_uint64 (EmpathyAccountSettings *settings,
714     const gchar *param)
715 {
716   const GValue *v;
717   guint64 ret = 0;
718
719   v = empathy_account_settings_get (settings, param);
720
721   if (v == NULL || !G_VALUE_HOLDS_INT (v))
722     return 0;
723
724   switch G_VALUE_TYPE (v)
725     {
726       case G_TYPE_UCHAR:
727         ret = g_value_get_uchar (v);
728         break;
729       case G_TYPE_INT:
730         ret = MAX (0, g_value_get_int (v));
731         break;
732       case G_TYPE_UINT:
733         ret = g_value_get_uint (v);
734         break;
735       case G_TYPE_INT64:
736         ret = MAX (0, g_value_get_int64 (v));
737         break;
738       case G_TYPE_UINT64:
739         ret = CLAMP (0, g_value_get_uint64 (v), G_MAXUINT64);
740         break;
741       default:
742         ret = 0;
743         break;
744     }
745
746   return ret;
747 }
748
749 gboolean
750 empathy_account_settings_get_boolean (EmpathyAccountSettings *settings,
751     const gchar *param)
752 {
753   const GValue *v;
754
755   v = empathy_account_settings_get (settings, param);
756
757   if (v == NULL || !G_VALUE_HOLDS_BOOLEAN (v))
758     return FALSE;
759
760   return g_value_get_boolean (v);
761 }
762
763 void
764 empathy_account_settings_set_string (EmpathyAccountSettings *settings,
765     const gchar *param,
766     const gchar *value)
767 {
768   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
769
770   tp_asv_set_string (priv->parameters, g_strdup (param), value);
771 }
772
773 void
774 empathy_account_settings_set_int32 (EmpathyAccountSettings *settings,
775     const gchar *param,
776     gint32 value)
777 {
778   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
779
780   tp_asv_set_int32 (priv->parameters, g_strdup (param), value);
781 }
782
783 void
784 empathy_account_settings_set_int64 (EmpathyAccountSettings *settings,
785     const gchar *param,
786     gint64 value)
787 {
788   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
789
790   tp_asv_set_int64 (priv->parameters, g_strdup (param), value);
791 }
792
793 void
794 empathy_account_settings_set_uint32 (EmpathyAccountSettings *settings,
795     const gchar *param,
796     guint32 value)
797 {
798   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
799
800   tp_asv_set_uint32 (priv->parameters, g_strdup (param), value);
801 }
802
803 void
804 empathy_account_settings_set_uint64 (EmpathyAccountSettings *settings,
805     const gchar *param,
806     guint64 value)
807 {
808   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
809
810   tp_asv_set_uint64 (priv->parameters, g_strdup (param), value);
811 }
812
813 void
814 empathy_account_settings_set_boolean (EmpathyAccountSettings *settings,
815     const gchar *param,
816     gboolean value)
817 {
818   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
819
820   tp_asv_set_boolean (priv->parameters, g_strdup (param), value);
821 }
822
823 static void
824 account_settings_display_name_set_cb (GObject *src,
825     GAsyncResult *res,
826     gpointer user_data)
827 {
828   GError *error = NULL;
829   EmpathyAccount *account = EMPATHY_ACCOUNT (src);
830   GSimpleAsyncResult *set_result = user_data;
831
832   empathy_account_set_display_name_finish (account, res, &error);
833
834   if (error != NULL)
835     {
836       g_simple_async_result_set_from_error (set_result, error);
837       g_error_free (error);
838     }
839
840   g_simple_async_result_complete (set_result);
841   g_object_unref (set_result);
842 }
843
844 void
845 empathy_account_settings_set_display_name_async (
846   EmpathyAccountSettings *settings,
847   const gchar *name,
848   GAsyncReadyCallback callback,
849   gpointer user_data)
850 {
851   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
852   GSimpleAsyncResult *result;
853
854   result = g_simple_async_result_new (G_OBJECT (settings),
855       callback, user_data, empathy_account_settings_set_display_name_finish);
856
857   if (priv->account == NULL)
858     {
859       if (priv->display_name != NULL)
860         g_free (priv->display_name);
861
862       priv->display_name = g_strdup (name);
863
864       g_simple_async_result_complete_in_idle (result);
865
866       return;
867     }
868
869   empathy_account_set_display_name_async (priv->account, name,
870       account_settings_display_name_set_cb, result);
871 }
872
873 gboolean
874 empathy_account_settings_set_display_name_finish (
875   EmpathyAccountSettings *settings,
876   GAsyncResult *result,
877   GError **error)
878 {
879   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
880       error))
881     return FALSE;
882
883   g_return_val_if_fail (g_simple_async_result_is_valid (result,
884     G_OBJECT (settings), empathy_account_settings_set_display_name_finish), FALSE);
885
886   return TRUE;
887 }
888
889 static void
890 empathy_account_settings_account_updated (GObject *source,
891     GAsyncResult *result,
892     gpointer user_data)
893 {
894   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
895   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
896   GSimpleAsyncResult *r;
897   GError *error = NULL;
898
899   if (!empathy_account_update_settings_finish (EMPATHY_ACCOUNT (source),
900     result, &error))
901     {
902       g_simple_async_result_set_from_error (priv->apply_result, error);
903       g_error_free (error);
904     }
905
906   r = priv->apply_result;
907   priv->apply_result = NULL;
908
909   g_simple_async_result_complete (r);
910   g_object_unref (r);
911 }
912
913 static void
914 empathy_account_settings_created_cb (GObject *source,
915     GAsyncResult *result,
916     gpointer user_data)
917 {
918   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
919   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
920   EmpathyAccount *account;
921   GError *error = NULL;
922   GSimpleAsyncResult *r;
923
924   account = empathy_account_manager_create_account_finish (
925     EMPATHY_ACCOUNT_MANAGER (source), result, &error);
926
927   if (account == NULL)
928     {
929       g_simple_async_result_set_from_error (priv->apply_result, error);
930     }
931   else
932     {
933       priv->account = g_object_ref (account);
934     }
935
936   r = priv->apply_result;
937   priv->apply_result = NULL;
938
939   g_simple_async_result_complete (r);
940   g_object_unref (r);
941 }
942
943
944 static void
945 empathy_account_settings_do_create_account (EmpathyAccountSettings *settings)
946 {
947   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
948   GHashTable *properties;
949   TpConnectionPresenceType type;
950   gchar *status;
951   gchar *message;
952
953   properties = tp_asv_new (NULL, NULL);
954
955   type = empathy_account_manager_get_requested_global_presence
956     (priv->account_manager, &status, &message);
957
958   if (type != TP_CONNECTION_PRESENCE_TYPE_UNSET)
959     {
960       /* Create the account with the requested presence the same as the current
961         * global requested presence, but don't enable it */
962       GValueArray *presence;
963       GValue vtype = { 0, };
964       GValue vstatus = { 0, };
965       GValue vmessage = { 0, };
966
967       presence = g_value_array_new (3);
968
969       g_value_init (&vtype, G_TYPE_UINT);
970       g_value_set_uint (&vtype, type);
971       g_value_array_append (presence, &vtype);
972
973       g_value_init (&vstatus, G_TYPE_STRING);
974       g_value_take_string (&vstatus, status);
975       g_value_array_append (presence, &vstatus);
976
977       g_value_init (&vmessage, G_TYPE_STRING);
978       g_value_take_string (&vmessage, message);
979       g_value_array_append (presence, &vmessage);
980
981       tp_asv_take_boxed (properties, TP_IFACE_ACCOUNT ".RequestedPresence",
982         TP_STRUCT_TYPE_SIMPLE_PRESENCE, presence);
983     }
984
985   empathy_account_manager_create_account_async (priv->account_manager,
986     priv->cm_name, priv->protocol, priv->display_name,
987     priv->parameters, properties,
988     empathy_account_settings_created_cb,
989     settings);
990
991   g_hash_table_unref (properties);
992 }
993
994 static void
995 empathy_account_settings_manager_ready_cb (EmpathyAccountManager *manager,
996     GParamSpec *spec,
997     gpointer user_data)
998 {
999   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
1000   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
1001
1002   if (empathy_account_manager_is_ready (manager))
1003     {
1004       g_assert (priv->apply_result != NULL && priv->account == NULL);
1005       g_signal_handler_disconnect (priv->account_manager,
1006         priv->account_manager_ready_id);
1007       priv->account_manager_ready_id = 0;
1008
1009       empathy_account_settings_do_create_account (settings);
1010     }
1011 }
1012
1013 void
1014 empathy_account_settings_apply_async (EmpathyAccountSettings *settings,
1015     GAsyncReadyCallback callback,
1016     gpointer user_data)
1017 {
1018   EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
1019
1020   if (priv->apply_result != NULL)
1021     {
1022       g_simple_async_report_error_in_idle (G_OBJECT (settings),
1023         callback, user_data,
1024         G_IO_ERROR, G_IO_ERROR_PENDING, "Applying already in progress");
1025       return;
1026     }
1027
1028   priv->apply_result = g_simple_async_result_new (G_OBJECT (settings),
1029       callback, user_data, empathy_account_settings_apply_finish);
1030
1031   if (priv->account == NULL)
1032     {
1033       if (empathy_account_manager_is_ready (priv->account_manager))
1034         empathy_account_settings_do_create_account (settings);
1035       else
1036         priv->account_manager_ready_id = g_signal_connect (
1037             priv->account_manager,
1038             "notify::ready",
1039             G_CALLBACK (empathy_account_settings_manager_ready_cb),
1040             settings);
1041     }
1042   else
1043     {
1044       empathy_account_update_settings_async (priv->account,
1045         priv->parameters, (const gchar **)priv->unset_parameters->data,
1046         empathy_account_settings_account_updated, settings);
1047
1048       g_hash_table_remove_all (priv->parameters);
1049       empathy_account_settings_free_unset_parameters (settings);
1050     }
1051 }
1052
1053 gboolean
1054 empathy_account_settings_apply_finish (EmpathyAccountSettings *settings,
1055     GAsyncResult *result,
1056     GError **error)
1057 {
1058   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
1059       error))
1060     return FALSE;
1061
1062   g_return_val_if_fail (g_simple_async_result_is_valid (result,
1063     G_OBJECT (settings), empathy_account_settings_apply_finish), FALSE);
1064
1065   return TRUE;
1066 }
1067
1068 gboolean
1069 empathy_account_settings_has_account (EmpathyAccountSettings *settings,
1070     EmpathyAccount *account)
1071 {
1072   EmpathyAccountSettingsPriv *priv;
1073
1074   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), FALSE);
1075   g_return_val_if_fail (EMPATHY_IS_ACCOUNT (account), FALSE);
1076
1077   priv = GET_PRIV (settings);
1078
1079   return (account == priv->account);
1080 }
1081
1082 gboolean
1083 empathy_account_settings_is_valid (EmpathyAccountSettings *settings)
1084 {
1085   EmpathyAccountSettingsPriv *priv;
1086   int idx;
1087   gchar *current;
1088   gboolean missed = FALSE;
1089
1090   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), FALSE);
1091
1092   priv = GET_PRIV (settings);
1093
1094   for (idx = 0; idx < priv->required_params->len; idx++)
1095     {
1096       current = g_array_index (priv->required_params, gchar *, idx);
1097
1098       /* first, look if it's set in our own parameters */
1099       if (tp_asv_lookup (priv->parameters, current))
1100         continue;
1101
1102       /* if we did not unset the parameter, look if it's in the account */
1103       if (priv->account != NULL &&
1104           !empathy_account_settings_is_unset (settings, current))
1105         {
1106           const GHashTable *account_params;
1107
1108           account_params = empathy_account_get_parameters (priv->account);
1109           if (tp_asv_lookup (account_params, current))
1110             continue;
1111         }
1112
1113       missed = TRUE;
1114       break;
1115     }
1116
1117   return !missed;
1118 }