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