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