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