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