]> git.0d.be Git - empathy.git/blob - tp-account-widgets/tpaw-account-settings.c
tpaw-utils: use self->priv instead of EMPATHY_GET_PRIV(self)
[empathy.git] / tp-account-widgets / tpaw-account-settings.c
1 /*
2  * tpaw-account-settings.c - Source for TpawAccountSettings
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 #include "config.h"
22 #include "tpaw-account-settings.h"
23
24 #include "tpaw-connection-managers.h"
25 #include "tpaw-keyring.h"
26 #include "empathy-utils.h"
27 #include "tpaw-utils.h"
28
29 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
30 #include "empathy-debug.h"
31
32 G_DEFINE_TYPE(TpawAccountSettings, tpaw_account_settings, G_TYPE_OBJECT)
33
34 enum {
35   PROP_ACCOUNT = 1,
36   PROP_CM_NAME,
37   PROP_PROTOCOL,
38   PROP_SERVICE,
39   PROP_DISPLAY_NAME,
40   PROP_DISPLAY_NAME_OVERRIDDEN,
41   PROP_READY
42 };
43
44 enum {
45   PASSWORD_RETRIEVED = 1,
46   LAST_SIGNAL
47 };
48
49 static gulong signals[LAST_SIGNAL] = { 0, };
50
51 struct _TpawAccountSettingsPriv
52 {
53   gboolean dispose_has_run;
54   TpawConnectionManagers *managers;
55   TpAccountManager *account_manager;
56
57   TpConnectionManager *manager;
58   TpProtocol *protocol_obj;
59
60   TpAccount *account;
61   gchar *cm_name;
62   gchar *protocol;
63   gchar *service;
64   gchar *display_name;
65   gchar *icon_name;
66   gchar *storage_provider;
67   gboolean display_name_overridden;
68   gboolean ready;
69
70   gboolean supports_sasl;
71   gboolean remember_password;
72
73   gchar *password;
74   gchar *password_original;
75
76   gboolean password_retrieved;
77   gboolean password_requested;
78
79   /* Parameter name (gchar *) -> parameter value (GVariant) */
80   GHashTable *parameters;
81   /* Keys are parameter names from the hash above (gchar *).
82    * Values are regular expresions that should match corresponding parameter
83    * values (GRegex *). Possible regexp patterns are defined in
84    * tpaw-account-widget.c */
85   GHashTable *param_regexps;
86   GArray *unset_parameters;
87   GList *required_params;
88
89   gulong managers_ready_id;
90   gboolean preparing_protocol;
91
92   /* If TRUE, the account should have 'tel' in its
93    * Account.Interface.Addressing.URISchemes property. */
94   gboolean uri_scheme_tel;
95   /* If TRUE, Service property needs to be updated when applying changes */
96   gboolean update_service;
97
98   GSimpleAsyncResult *apply_result;
99 };
100
101 static void
102 tpaw_account_settings_init (TpawAccountSettings *obj)
103 {
104   obj->priv = G_TYPE_INSTANCE_GET_PRIVATE ((obj),
105     TPAW_TYPE_ACCOUNT_SETTINGS, TpawAccountSettingsPriv);
106
107   /* allocate any data required by the object here */
108   obj->priv->managers = tpaw_connection_managers_dup_singleton ();
109   obj->priv->account_manager = tp_account_manager_dup ();
110
111   obj->priv->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
112     g_free, (GDestroyNotify) g_variant_unref);
113
114   obj->priv->param_regexps = g_hash_table_new_full (g_str_hash, g_str_equal,
115     g_free, (GDestroyNotify) g_regex_unref);
116
117   obj->priv->unset_parameters = g_array_new (TRUE, FALSE, sizeof (gchar *));
118
119   obj->priv->required_params = NULL;
120 }
121
122 static void tpaw_account_settings_dispose (GObject *object);
123 static void tpaw_account_settings_finalize (GObject *object);
124 static void tpaw_account_settings_account_ready_cb (GObject *source_object,
125     GAsyncResult *result, gpointer user_data);
126 static void tpaw_account_settings_managers_ready_cb (GObject *obj,
127     GParamSpec *pspec, gpointer user_data);
128 static void tpaw_account_settings_check_readyness (
129     TpawAccountSettings *self);
130
131 static void
132 tpaw_account_settings_set_property (GObject *object,
133     guint prop_id,
134     const GValue *value,
135     GParamSpec *pspec)
136 {
137   TpawAccountSettings *self = TPAW_ACCOUNT_SETTINGS (object);
138
139   switch (prop_id)
140     {
141       case PROP_ACCOUNT:
142         self->priv->account = g_value_dup_object (value);
143         break;
144       case PROP_CM_NAME:
145         self->priv->cm_name = g_value_dup_string (value);
146         break;
147       case PROP_PROTOCOL:
148         self->priv->protocol = g_value_dup_string (value);
149         break;
150       case PROP_SERVICE:
151         self->priv->service = g_value_dup_string (value);
152         break;
153       case PROP_DISPLAY_NAME:
154         self->priv->display_name = g_value_dup_string (value);
155         break;
156       case PROP_DISPLAY_NAME_OVERRIDDEN:
157         self->priv->display_name_overridden = g_value_get_boolean (value);
158         break;
159       default:
160         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
161         break;
162     }
163 }
164
165 static void
166 tpaw_account_settings_get_property (GObject *object,
167     guint prop_id,
168     GValue *value,
169     GParamSpec *pspec)
170 {
171   TpawAccountSettings *self = TPAW_ACCOUNT_SETTINGS (object);
172
173   switch (prop_id)
174     {
175       case PROP_ACCOUNT:
176         g_value_set_object (value, self->priv->account);
177         break;
178       case PROP_CM_NAME:
179         g_value_set_string (value, self->priv->cm_name);
180         break;
181       case PROP_PROTOCOL:
182         g_value_set_string (value, self->priv->protocol);
183         break;
184       case PROP_SERVICE:
185         g_value_set_string (value, self->priv->service);
186         break;
187       case PROP_DISPLAY_NAME:
188         g_value_set_string (value, self->priv->display_name);
189         break;
190       case PROP_DISPLAY_NAME_OVERRIDDEN:
191         g_value_set_boolean (value, self->priv->display_name_overridden);
192         break;
193       case PROP_READY:
194         g_value_set_boolean (value, self->priv->ready);
195         break;
196       default:
197         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
198         break;
199     }
200 }
201
202 static void
203 tpaw_account_settings_constructed (GObject *object)
204 {
205   TpawAccountSettings *self = TPAW_ACCOUNT_SETTINGS (object);
206
207   if (self->priv->account != NULL)
208     {
209       g_free (self->priv->cm_name);
210       g_free (self->priv->protocol);
211       g_free (self->priv->service);
212
213       self->priv->cm_name =
214         g_strdup (tp_account_get_cm_name (self->priv->account));
215       self->priv->protocol =
216         g_strdup (tp_account_get_protocol_name (self->priv->account));
217       self->priv->service =
218         g_strdup (tp_account_get_service (self->priv->account));
219       self->priv->icon_name = g_strdup
220         (tp_account_get_icon_name (self->priv->account));
221     }
222   else
223     {
224       self->priv->icon_name = tpaw_protocol_icon_name (self->priv->protocol);
225     }
226
227   g_assert (self->priv->cm_name != NULL && self->priv->protocol != NULL);
228
229   tpaw_account_settings_check_readyness (self);
230
231   if (!self->priv->ready)
232     {
233       GQuark features[] = {
234           TP_ACCOUNT_FEATURE_CORE,
235           TP_ACCOUNT_FEATURE_STORAGE,
236           TP_ACCOUNT_FEATURE_ADDRESSING,
237           0 };
238
239       if (self->priv->account != NULL)
240         {
241           tp_proxy_prepare_async (self->priv->account, features,
242               tpaw_account_settings_account_ready_cb, self);
243         }
244
245       tp_g_signal_connect_object (self->priv->managers, "notify::ready",
246         G_CALLBACK (tpaw_account_settings_managers_ready_cb), object, 0);
247     }
248
249   if (G_OBJECT_CLASS (
250         tpaw_account_settings_parent_class)->constructed != NULL)
251     G_OBJECT_CLASS (
252         tpaw_account_settings_parent_class)->constructed (object);
253 }
254
255
256 static void
257 tpaw_account_settings_class_init (
258     TpawAccountSettingsClass *tpaw_account_settings_class)
259 {
260   GObjectClass *object_class = G_OBJECT_CLASS (tpaw_account_settings_class);
261
262   g_type_class_add_private (tpaw_account_settings_class, sizeof
263       (TpawAccountSettingsPriv));
264
265   object_class->dispose = tpaw_account_settings_dispose;
266   object_class->finalize = tpaw_account_settings_finalize;
267   object_class->set_property = tpaw_account_settings_set_property;
268   object_class->get_property = tpaw_account_settings_get_property;
269   object_class->constructed = tpaw_account_settings_constructed;
270
271   g_object_class_install_property (object_class, PROP_ACCOUNT,
272     g_param_spec_object ("account",
273       "Account",
274       "The TpAccount backing these settings",
275       TP_TYPE_ACCOUNT,
276       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
277
278   g_object_class_install_property (object_class, PROP_CM_NAME,
279     g_param_spec_string ("connection-manager",
280       "connection-manager",
281       "The name of the connection manager this account uses",
282       NULL,
283       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
284
285   g_object_class_install_property (object_class, PROP_PROTOCOL,
286     g_param_spec_string ("protocol",
287       "Protocol",
288       "The name of the protocol this account uses",
289       NULL,
290       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
291
292   g_object_class_install_property (object_class, PROP_SERVICE,
293     g_param_spec_string ("service",
294       "Service",
295       "The service of this account, or NULL",
296       NULL,
297       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
298
299   g_object_class_install_property (object_class, PROP_DISPLAY_NAME,
300     g_param_spec_string ("display-name",
301       "display-name",
302       "The display name account these settings belong to",
303       NULL,
304       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
305
306   g_object_class_install_property (object_class, PROP_DISPLAY_NAME_OVERRIDDEN,
307       g_param_spec_boolean ("display-name-overridden",
308         "display-name-overridden",
309         "Whether the display name for this account has been manually "
310         "overridden",
311         FALSE,
312         G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
313
314   g_object_class_install_property (object_class, PROP_READY,
315     g_param_spec_boolean ("ready",
316       "Ready",
317       "Whether this account is ready to be used",
318       FALSE,
319       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
320
321   signals[PASSWORD_RETRIEVED] =
322       g_signal_new ("password-retrieved",
323           G_TYPE_FROM_CLASS (tpaw_account_settings_class),
324           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
325           g_cclosure_marshal_generic,
326           G_TYPE_NONE, 0);
327 }
328
329 static void
330 tpaw_account_settings_dispose (GObject *object)
331 {
332   TpawAccountSettings *self = TPAW_ACCOUNT_SETTINGS (object);
333
334   if (self->priv->dispose_has_run)
335     return;
336
337   self->priv->dispose_has_run = TRUE;
338
339   if (self->priv->managers_ready_id != 0)
340     g_signal_handler_disconnect (self->priv->managers,
341         self->priv->managers_ready_id);
342   self->priv->managers_ready_id = 0;
343
344   tp_clear_object (&self->priv->managers);
345   tp_clear_object (&self->priv->manager);
346   tp_clear_object (&self->priv->account_manager);
347   tp_clear_object (&self->priv->account);
348   tp_clear_object (&self->priv->protocol_obj);
349
350   /* release any references held by the object here */
351   if (G_OBJECT_CLASS (tpaw_account_settings_parent_class)->dispose)
352     G_OBJECT_CLASS (tpaw_account_settings_parent_class)->dispose (object);
353 }
354
355 static void
356 tpaw_account_settings_free_unset_parameters (
357     TpawAccountSettings *settings)
358 {
359   guint i;
360
361   for (i = 0 ; i < settings->priv->unset_parameters->len; i++)
362     g_free (g_array_index (settings->priv->unset_parameters, gchar *, i));
363
364   g_array_set_size (settings->priv->unset_parameters, 0);
365 }
366
367 static void
368 tpaw_account_settings_finalize (GObject *object)
369 {
370   TpawAccountSettings *self = TPAW_ACCOUNT_SETTINGS (object);
371   GList *l;
372
373   /* free any data held directly by the object here */
374   g_free (self->priv->cm_name);
375   g_free (self->priv->protocol);
376   g_free (self->priv->service);
377   g_free (self->priv->display_name);
378   g_free (self->priv->icon_name);
379   g_free (self->priv->password);
380   g_free (self->priv->password_original);
381   g_free (self->priv->storage_provider);
382
383   if (self->priv->required_params != NULL)
384     {
385       for (l = self->priv->required_params; l; l = l->next)
386         g_free (l->data);
387       g_list_free (self->priv->required_params);
388     }
389
390   g_hash_table_unref (self->priv->parameters);
391   g_hash_table_unref (self->priv->param_regexps);
392
393   tpaw_account_settings_free_unset_parameters (self);
394   g_array_unref (self->priv->unset_parameters);
395
396   G_OBJECT_CLASS (tpaw_account_settings_parent_class)->finalize (object);
397 }
398
399 static void
400 tpaw_account_settings_protocol_obj_prepared_cb (GObject *source,
401     GAsyncResult *result,
402     gpointer user_data)
403 {
404   TpawAccountSettings *self = user_data;
405   GError *error = NULL;
406
407   if (!tp_proxy_prepare_finish (source, result, &error))
408     {
409       DEBUG ("Failed to prepare protocol object: %s", error->message);
410       g_clear_error (&error);
411       return;
412     }
413
414   tpaw_account_settings_check_readyness (self);
415 }
416
417 static void
418 tpaw_account_settings_get_password_cb (GObject *source,
419     GAsyncResult *result,
420     gpointer user_data)
421 {
422   TpawAccountSettings *self = user_data;
423   const gchar *password;
424   GError *error = NULL;
425
426   password = tpaw_keyring_get_account_password_finish (TP_ACCOUNT (source),
427       result, &error);
428
429   if (error != NULL)
430     {
431       DEBUG ("Failed to get password: %s", error->message);
432       g_clear_error (&error);
433     }
434
435   /* It doesn't really matter if getting the password failed; that
436    * just means that it's not there, or let's act like that at
437    * least. */
438
439   g_assert (self->priv->password == NULL);
440
441   self->priv->password = g_strdup (password);
442   self->priv->password_original = g_strdup (password);
443
444   g_signal_emit (self, signals[PASSWORD_RETRIEVED], 0);
445 }
446
447 static gboolean
448 account_has_uri_scheme_tel (TpAccount *account)
449 {
450   return tp_account_associated_with_uri_scheme (account, "tel");
451 }
452
453 static GVariant * tpaw_account_settings_dup (
454     TpawAccountSettings *settings,
455     const gchar *param);
456
457 static void
458 tpaw_account_settings_check_readyness (TpawAccountSettings *self)
459 {
460   GQuark features[] = { TP_PROTOCOL_FEATURE_CORE, 0 };
461
462   if (self->priv->ready)
463     return;
464
465   if (self->priv->account != NULL
466       && !tp_account_is_prepared (self->priv->account,
467         TP_ACCOUNT_FEATURE_CORE))
468       return;
469
470   if (!tpaw_connection_managers_is_ready (self->priv->managers))
471     return;
472
473   if (self->priv->manager == NULL)
474     {
475       self->priv->manager = tpaw_connection_managers_get_cm (
476           self->priv->managers, self->priv->cm_name);
477     }
478
479   if (self->priv->manager == NULL)
480     return;
481
482   g_object_ref (self->priv->manager);
483
484   if (self->priv->account != NULL)
485     {
486       g_free (self->priv->display_name);
487       self->priv->display_name =
488         g_strdup (tp_account_get_display_name (self->priv->account));
489
490       g_free (self->priv->icon_name);
491       self->priv->icon_name =
492         g_strdup (tp_account_get_icon_name (self->priv->account));
493
494       self->priv->uri_scheme_tel = account_has_uri_scheme_tel (
495           self->priv->account);
496     }
497
498   if (self->priv->protocol_obj == NULL)
499     {
500       self->priv->protocol_obj = g_object_ref (
501           tp_connection_manager_get_protocol_object (self->priv->manager,
502             self->priv->protocol));
503     }
504
505   if (!tp_proxy_is_prepared (self->priv->protocol_obj,
506         TP_PROTOCOL_FEATURE_CORE)
507       && !self->priv->preparing_protocol)
508     {
509       self->priv->preparing_protocol = TRUE;
510       tp_proxy_prepare_async (self->priv->protocol_obj, features,
511           tpaw_account_settings_protocol_obj_prepared_cb, self);
512       return;
513     }
514   else
515     {
516       if (tp_strv_contains (tp_protocol_get_authentication_types (
517                   self->priv->protocol_obj),
518               TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION))
519         {
520           self->priv->supports_sasl = TRUE;
521         }
522     }
523
524   if (self->priv->required_params == NULL)
525     {
526       GList *params, *l;
527
528       params = tp_protocol_dup_params (self->priv->protocol_obj);
529       for (l = params; l != NULL; l = g_list_next (l))
530         {
531           TpConnectionManagerParam *cur = l->data;
532
533           if (tp_connection_manager_param_is_required (cur))
534             {
535               self->priv->required_params = g_list_append (
536                   self->priv->required_params,
537                   g_strdup (tp_connection_manager_param_get_name (cur)));
538             }
539         }
540
541        g_list_free_full (params,
542            (GDestroyNotify) tp_connection_manager_param_free);
543     }
544
545   /* self->priv->account won't be a proper account if it's the account
546    * assistant showing this widget. */
547   if (self->priv->supports_sasl && !self->priv->password_requested
548       && self->priv->account != NULL)
549     {
550       self->priv->password_requested = TRUE;
551
552       /* Make this call but don't block on its readiness. We'll signal
553        * if it's updated later with ::password-retrieved. */
554       tpaw_keyring_get_account_password_async (self->priv->account,
555           tpaw_account_settings_get_password_cb, self);
556     }
557
558   self->priv->ready = TRUE;
559   g_object_notify (G_OBJECT (self), "ready");
560 }
561
562 static void
563 tpaw_account_settings_account_ready_cb (GObject *source_object,
564     GAsyncResult *result,
565     gpointer user_data)
566 {
567   TpawAccountSettings *settings = TPAW_ACCOUNT_SETTINGS (user_data);
568   TpAccount *account = TP_ACCOUNT (source_object);
569   GError *error = NULL;
570
571   if (!tp_proxy_prepare_finish (account, result, &error))
572     {
573       DEBUG ("Failed to prepare account: %s", error->message);
574       g_error_free (error);
575       return;
576     }
577
578   tpaw_account_settings_check_readyness (settings);
579 }
580
581 static void
582 tpaw_account_settings_managers_ready_cb (GObject *object,
583     GParamSpec *pspec,
584     gpointer user_data)
585 {
586   TpawAccountSettings *settings = TPAW_ACCOUNT_SETTINGS (user_data);
587
588   tpaw_account_settings_check_readyness (settings);
589 }
590
591 TpawAccountSettings *
592 tpaw_account_settings_new (const gchar *connection_manager,
593     const gchar *protocol,
594     const gchar *service,
595     const char *display_name)
596 {
597   return g_object_new (TPAW_TYPE_ACCOUNT_SETTINGS,
598       "connection-manager", connection_manager,
599       "protocol", protocol,
600       "service", service,
601       "display-name", display_name,
602       NULL);
603 }
604
605 TpawAccountSettings *
606 tpaw_account_settings_new_for_account (TpAccount *account)
607 {
608   return g_object_new (TPAW_TYPE_ACCOUNT_SETTINGS,
609       "account", account,
610       NULL);
611 }
612
613 GList *
614 tpaw_account_settings_dup_tp_params (TpawAccountSettings *settings)
615 {
616   g_return_val_if_fail (settings->priv->protocol_obj != NULL, NULL);
617
618   return tp_protocol_dup_params (settings->priv->protocol_obj);
619 }
620
621 gboolean
622 tpaw_account_settings_is_ready (TpawAccountSettings *settings)
623 {
624   return settings->priv->ready;
625 }
626
627 const gchar *
628 tpaw_account_settings_get_cm (TpawAccountSettings *settings)
629 {
630   return settings->priv->cm_name;
631 }
632
633 const gchar *
634 tpaw_account_settings_get_protocol (TpawAccountSettings *settings)
635 {
636   return settings->priv->protocol;
637 }
638
639 const gchar *
640 tpaw_account_settings_get_service (TpawAccountSettings *settings)
641 {
642   return settings->priv->service;
643 }
644
645 void
646 tpaw_account_settings_set_service (TpawAccountSettings *settings,
647     const gchar *service)
648 {
649   if (!tp_strdiff (settings->priv->service, service))
650     return;
651
652   g_free (settings->priv->service);
653   settings->priv->service = g_strdup (service);
654   g_object_notify (G_OBJECT (settings), "service");
655   settings->priv->update_service = TRUE;
656 }
657
658 gchar *
659 tpaw_account_settings_get_icon_name (TpawAccountSettings *settings)
660 {
661   return settings->priv->icon_name;
662 }
663
664 const gchar *
665 tpaw_account_settings_get_display_name (TpawAccountSettings *settings)
666 {
667   return settings->priv->display_name;
668 }
669
670 TpAccount *
671 tpaw_account_settings_get_account (TpawAccountSettings *settings)
672 {
673   return settings->priv->account;
674 }
675
676 static gboolean
677 tpaw_account_settings_is_unset (TpawAccountSettings *settings,
678     const gchar *param)
679 {
680   GArray *a;
681   guint i;
682
683   a = settings->priv->unset_parameters;
684
685   for (i = 0; i < a->len; i++)
686     {
687       if (!tp_strdiff (g_array_index (a, gchar *, i), param))
688         return TRUE;
689     }
690
691   return FALSE;
692 }
693
694 static const TpConnectionManagerParam *
695 tpaw_account_settings_get_tp_param (TpawAccountSettings *settings,
696     const gchar *param)
697 {
698   return tp_protocol_get_param (settings->priv->protocol_obj, param);
699 }
700
701 gboolean
702 tpaw_account_settings_have_tp_param (TpawAccountSettings *settings,
703     const gchar *param)
704 {
705   return (tpaw_account_settings_get_tp_param (settings, param) != NULL);
706 }
707
708 static void
709 account_settings_remove_from_unset (TpawAccountSettings *settings,
710     const gchar *param)
711 {
712   guint idx;
713   gchar *val;
714
715   for (idx = 0; idx < settings->priv->unset_parameters->len; idx++)
716     {
717       val = g_array_index (settings->priv->unset_parameters, gchar *, idx);
718
719       if (!tp_strdiff (val, param))
720         {
721           settings->priv->unset_parameters =
722             g_array_remove_index (settings->priv->unset_parameters, idx);
723           g_free (val);
724
725           break;
726         }
727     }
728 }
729
730 GVariant *
731 tpaw_account_settings_dup_default (TpawAccountSettings *settings,
732     const gchar *param)
733 {
734   const TpConnectionManagerParam *p;
735
736   p = tpaw_account_settings_get_tp_param (settings, param);
737   if (p == NULL)
738     return NULL;
739
740   return tp_connection_manager_param_dup_default_variant (p);
741 }
742
743 const gchar *
744 tpaw_account_settings_get_dbus_signature (TpawAccountSettings *settings,
745     const gchar *param)
746 {
747   const TpConnectionManagerParam *p;
748
749   p = tpaw_account_settings_get_tp_param (settings, param);
750
751   if (p == NULL)
752     return NULL;
753
754   return tp_connection_manager_param_get_dbus_signature (p);
755 }
756
757 static GVariant *
758 tpaw_account_settings_dup (TpawAccountSettings *settings,
759     const gchar *param)
760 {
761   GVariant *result;
762
763   /* Lookup the update parameters we set */
764   result = g_hash_table_lookup (settings->priv->parameters, param);
765   if (result != NULL)
766     return g_variant_ref (result);
767
768   /* If the parameters isn't unset use the accounts setting if any */
769   if (settings->priv->account != NULL
770       && !tpaw_account_settings_is_unset (settings, param))
771     {
772       GVariant *parameters;
773
774       parameters = tp_account_dup_parameters_vardict (
775           settings->priv->account);
776       result = g_variant_lookup_value (parameters, param, NULL);
777       g_variant_unref (parameters);
778
779       if (result != NULL)
780         /* g_variant_lookup_value() is (transfer full) */
781         return result;
782     }
783
784   /* fallback to the default */
785   return tpaw_account_settings_dup_default (settings, param);
786 }
787
788 void
789 tpaw_account_settings_unset (TpawAccountSettings *settings,
790     const gchar *param)
791 {
792   gchar *v;
793   if (tpaw_account_settings_is_unset (settings, param))
794     return;
795
796   if (settings->priv->supports_sasl && !tp_strdiff (param, "password"))
797     {
798       g_free (settings->priv->password);
799       settings->priv->password = NULL;
800       return;
801     }
802
803   v = g_strdup (param);
804
805   g_array_append_val (settings->priv->unset_parameters, v);
806   g_hash_table_remove (settings->priv->parameters, param);
807 }
808
809 void
810 tpaw_account_settings_discard_changes (TpawAccountSettings *settings)
811 {
812   g_hash_table_remove_all (settings->priv->parameters);
813   tpaw_account_settings_free_unset_parameters (settings);
814
815   g_free (settings->priv->password);
816   settings->priv->password = g_strdup (settings->priv->password_original);
817
818   if (settings->priv->account != NULL)
819     settings->priv->uri_scheme_tel = account_has_uri_scheme_tel (
820         settings->priv->account);
821   else
822     settings->priv->uri_scheme_tel = FALSE;
823 }
824
825 gchar *
826 tpaw_account_settings_dup_string (TpawAccountSettings *settings,
827     const gchar *param)
828 {
829   GVariant *v;
830   gchar *result = NULL;
831
832   if (!tp_strdiff (param, "password") && settings->priv->supports_sasl)
833     {
834       return g_strdup (settings->priv->password);
835     }
836
837   v = tpaw_account_settings_dup (settings, param);
838   if (v == NULL)
839     return NULL;
840
841   if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
842     result = g_variant_dup_string (v, NULL);
843
844   g_variant_unref (v);
845   return result;
846 }
847
848 GStrv
849 tpaw_account_settings_dup_strv (TpawAccountSettings *settings,
850     const gchar *param)
851 {
852   GVariant *v;
853   GStrv result = NULL;
854
855   v = tpaw_account_settings_dup (settings, param);
856   if (v == NULL)
857     return NULL;
858
859   if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING_ARRAY))
860     result = g_variant_dup_strv (v, NULL);
861
862   g_variant_unref (v);
863   return result;
864 }
865
866 gint32
867 tpaw_account_settings_get_int32 (TpawAccountSettings *settings,
868     const gchar *param)
869 {
870   GVariant *v;
871   gint32 ret = 0;
872
873   v = tpaw_account_settings_dup (settings, param);
874   if (v == NULL)
875     return 0;
876
877   if (g_variant_is_of_type (v, G_VARIANT_TYPE_BYTE))
878     ret = g_variant_get_byte (v);
879   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT32))
880     ret = g_variant_get_int32 (v);
881   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT32))
882     ret = CLAMP (g_variant_get_uint32 (v), (guint) G_MININT32,
883         G_MAXINT32);
884   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT64))
885     ret = CLAMP (g_variant_get_int64 (v), G_MININT32, G_MAXINT32);
886   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT64))
887     ret = CLAMP (g_variant_get_uint64 (v), (guint64) G_MININT32, G_MAXINT32);
888   else
889     {
890       gchar *tmp;
891
892       tmp = g_variant_print (v, TRUE);
893       DEBUG ("Unsupported type for param '%s': %s'", param, tmp);
894       g_free (tmp);
895     }
896
897   g_variant_unref (v);
898   return ret;
899 }
900
901 gint64
902 tpaw_account_settings_get_int64 (TpawAccountSettings *settings,
903     const gchar *param)
904 {
905   GVariant *v;
906   gint64 ret = 0;
907
908   v = tpaw_account_settings_dup (settings, param);
909   if (v == NULL)
910     return 0;
911
912   if (g_variant_is_of_type (v, G_VARIANT_TYPE_BYTE))
913     ret = g_variant_get_byte (v);
914   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT32))
915     ret = g_variant_get_int32 (v);
916   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT32))
917     ret = g_variant_get_uint32 (v);
918   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT64))
919     ret = g_variant_get_int64 (v);
920   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT64))
921     ret = CLAMP (g_variant_get_uint64 (v), (guint64) G_MININT64, G_MAXINT64);
922   else
923     {
924       gchar *tmp;
925
926       tmp = g_variant_print (v, TRUE);
927       DEBUG ("Unsupported type for param '%s': %s'", param, tmp);
928       g_free (tmp);
929     }
930
931   g_variant_unref (v);
932   return ret;
933 }
934
935 guint32
936 tpaw_account_settings_get_uint32 (TpawAccountSettings *settings,
937     const gchar *param)
938 {
939   GVariant *v;
940   guint32 ret = 0;
941
942   v = tpaw_account_settings_dup (settings, param);
943   if (v == NULL)
944     return 0;
945
946   if (g_variant_is_of_type (v, G_VARIANT_TYPE_BYTE))
947     ret = g_variant_get_byte (v);
948   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT32))
949     ret = MAX (0, g_variant_get_int32 (v));
950   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT32))
951     ret = g_variant_get_uint32 (v);
952   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT64))
953     ret = CLAMP (g_variant_get_int64 (v), 0, G_MAXUINT32);
954   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT64))
955     ret = MIN (g_variant_get_uint64 (v), G_MAXUINT32);
956   else
957     {
958       gchar *tmp;
959
960       tmp = g_variant_print (v, TRUE);
961       DEBUG ("Unsupported type for param '%s': %s'", param, tmp);
962       g_free (tmp);
963     }
964
965   g_variant_unref (v);
966   return ret;
967 }
968
969 guint64
970 tpaw_account_settings_get_uint64 (TpawAccountSettings *settings,
971     const gchar *param)
972 {
973   GVariant *v;
974   guint64 ret = 0;
975
976   v = tpaw_account_settings_dup (settings, param);
977   if (v == NULL)
978     return 0;
979
980   if (g_variant_is_of_type (v, G_VARIANT_TYPE_BYTE))
981     ret = g_variant_get_byte (v);
982   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT32))
983     ret = MAX (0, g_variant_get_int32 (v));
984   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT32))
985     ret = g_variant_get_uint32 (v);
986   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT64))
987     ret = MAX (0, g_variant_get_int64 (v));
988   else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT64))
989     ret = g_variant_get_uint64 (v);
990   else
991     {
992       gchar *tmp;
993
994       tmp = g_variant_print (v, TRUE);
995       DEBUG ("Unsupported type for param '%s': %s'", param, tmp);
996       g_free (tmp);
997     }
998
999
1000   g_variant_unref (v);
1001   return ret;
1002 }
1003
1004 gboolean
1005 tpaw_account_settings_get_boolean (TpawAccountSettings *settings,
1006     const gchar *param)
1007 {
1008   GVariant *v;
1009   gboolean result = FALSE;
1010
1011   v = tpaw_account_settings_dup (settings, param);
1012   if (v == NULL)
1013     return result;
1014
1015   if (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN))
1016     result = g_variant_get_boolean (v);
1017
1018   return result;
1019 }
1020
1021 void
1022 tpaw_account_settings_set (TpawAccountSettings *settings,
1023     const gchar *param,
1024     GVariant *v)
1025 {
1026   g_return_if_fail (param != NULL);
1027   g_return_if_fail (v != NULL);
1028
1029   if (!tp_strdiff (param, "password") && settings->priv->supports_sasl &&
1030       g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
1031     {
1032       g_free (settings->priv->password);
1033       settings->priv->password = g_variant_dup_string (v, NULL);
1034     }
1035   else
1036     {
1037       g_hash_table_insert (settings->priv->parameters, g_strdup (param),
1038           g_variant_ref_sink (v));
1039     }
1040
1041   account_settings_remove_from_unset (settings, param);
1042 }
1043
1044 static void
1045 account_settings_display_name_set_cb (GObject *src,
1046     GAsyncResult *res,
1047     gpointer user_data)
1048 {
1049   GError *error = NULL;
1050   TpAccount *account = TP_ACCOUNT (src);
1051   GSimpleAsyncResult *set_result = user_data;
1052
1053   tp_account_set_display_name_finish (account, res, &error);
1054
1055   if (error != NULL)
1056     {
1057       g_simple_async_result_set_from_error (set_result, error);
1058       g_error_free (error);
1059     }
1060
1061   g_simple_async_result_complete (set_result);
1062   g_object_unref (set_result);
1063 }
1064
1065 void
1066 tpaw_account_settings_set_display_name_async (
1067   TpawAccountSettings *settings,
1068   const gchar *name,
1069   GAsyncReadyCallback callback,
1070   gpointer user_data)
1071 {
1072   GSimpleAsyncResult *result;
1073
1074   g_return_if_fail (name != NULL);
1075
1076   result = g_simple_async_result_new (G_OBJECT (settings),
1077       callback, user_data, tpaw_account_settings_set_display_name_finish);
1078
1079   if (!tp_strdiff (name, settings->priv->display_name))
1080     {
1081       /* Nothing to do */
1082       g_simple_async_result_complete_in_idle (result);
1083       return;
1084     }
1085
1086   g_free (settings->priv->display_name);
1087   settings->priv->display_name = g_strdup (name);
1088
1089   if (settings->priv->account == NULL)
1090     {
1091       g_simple_async_result_complete_in_idle (result);
1092       return;
1093     }
1094
1095   tp_account_set_display_name_async (settings->priv->account, name,
1096       account_settings_display_name_set_cb, result);
1097 }
1098
1099 gboolean
1100 tpaw_account_settings_set_display_name_finish (
1101   TpawAccountSettings *settings,
1102   GAsyncResult *result,
1103   GError **error)
1104 {
1105   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
1106       error))
1107     return FALSE;
1108
1109   g_return_val_if_fail (g_simple_async_result_is_valid (result,
1110     G_OBJECT (settings), tpaw_account_settings_set_display_name_finish),
1111       FALSE);
1112
1113   return TRUE;
1114 }
1115
1116 static void
1117 account_settings_icon_name_set_cb (GObject *src,
1118     GAsyncResult *res,
1119     gpointer user_data)
1120 {
1121   GError *error = NULL;
1122   TpAccount *account = TP_ACCOUNT (src);
1123   GSimpleAsyncResult *set_result = user_data;
1124
1125   tp_account_set_icon_name_finish (account, res, &error);
1126
1127   if (error != NULL)
1128     {
1129       g_simple_async_result_set_from_error (set_result, error);
1130       g_error_free (error);
1131     }
1132
1133   g_simple_async_result_complete (set_result);
1134   g_object_unref (set_result);
1135 }
1136
1137 void
1138 tpaw_account_settings_set_icon_name_async (
1139   TpawAccountSettings *settings,
1140   const gchar *name,
1141   GAsyncReadyCallback callback,
1142   gpointer user_data)
1143 {
1144   GSimpleAsyncResult *result;
1145
1146   g_return_if_fail (name != NULL);
1147
1148   result = g_simple_async_result_new (G_OBJECT (settings),
1149       callback, user_data, tpaw_account_settings_set_icon_name_finish);
1150
1151   if (settings->priv->account == NULL)
1152     {
1153       if (settings->priv->icon_name != NULL)
1154         g_free (settings->priv->icon_name);
1155
1156       settings->priv->icon_name = g_strdup (name);
1157
1158       g_simple_async_result_complete_in_idle (result);
1159
1160       return;
1161     }
1162
1163   tp_account_set_icon_name_async (settings->priv->account, name,
1164       account_settings_icon_name_set_cb, result);
1165 }
1166
1167 gboolean
1168 tpaw_account_settings_set_icon_name_finish (
1169   TpawAccountSettings *settings,
1170   GAsyncResult *result,
1171   GError **error)
1172 {
1173   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
1174       error))
1175     return FALSE;
1176
1177   g_return_val_if_fail (g_simple_async_result_is_valid (result,
1178     G_OBJECT (settings), tpaw_account_settings_set_icon_name_finish),
1179       FALSE);
1180
1181   return TRUE;
1182 }
1183
1184 static void
1185 tpaw_account_settings_processed_password (GObject *source,
1186     GAsyncResult *result,
1187     gpointer user_data,
1188     gpointer finish_func)
1189 {
1190   TpawAccountSettings *settings = TPAW_ACCOUNT_SETTINGS (user_data);
1191   GSimpleAsyncResult *r;
1192   GError *error = NULL;
1193   gboolean (*func) (TpAccount *source, GAsyncResult *result, GError **error) =
1194     finish_func;
1195
1196   g_free (settings->priv->password_original);
1197   settings->priv->password_original = g_strdup (settings->priv->password);
1198
1199   if (!func (TP_ACCOUNT (source), result, &error))
1200     {
1201       g_simple_async_result_set_from_error (settings->priv->apply_result,
1202           error);
1203       g_error_free (error);
1204     }
1205
1206   tpaw_account_settings_discard_changes (settings);
1207
1208   r = settings->priv->apply_result;
1209   settings->priv->apply_result = NULL;
1210
1211   g_simple_async_result_complete (r);
1212   g_object_unref (r);
1213 }
1214
1215 static void
1216 tpaw_account_settings_set_password_cb (GObject *source,
1217     GAsyncResult *result,
1218     gpointer user_data)
1219 {
1220   tpaw_account_settings_processed_password (source, result, user_data,
1221       tpaw_keyring_set_account_password_finish);
1222 }
1223
1224 static void
1225 tpaw_account_settings_delete_password_cb (GObject *source,
1226     GAsyncResult *result,
1227     gpointer user_data)
1228 {
1229   tpaw_account_settings_processed_password (source, result, user_data,
1230       tpaw_keyring_delete_account_password_finish);
1231 }
1232
1233 static void
1234 update_account_uri_schemes (TpawAccountSettings *self)
1235 {
1236   if (self->priv->uri_scheme_tel == account_has_uri_scheme_tel (
1237         self->priv->account))
1238     return;
1239
1240   tp_account_set_uri_scheme_association_async (self->priv->account, "tel",
1241       self->priv->uri_scheme_tel, NULL, NULL);
1242 }
1243
1244 static void
1245 set_service_cb (GObject *source,
1246     GAsyncResult *result,
1247     gpointer user_data)
1248 {
1249   GError *error = NULL;
1250
1251   if (!tp_account_set_service_finish (TP_ACCOUNT (source), result, &error))
1252     {
1253       DEBUG ("Failed to set Account.Service: %s", error->message);
1254       g_error_free (error);
1255     }
1256 }
1257
1258 static void
1259 update_account_service (TpawAccountSettings *self)
1260 {
1261   if (!self->priv->update_service)
1262     return;
1263
1264   tp_account_set_service_async (self->priv->account,
1265       self->priv->service != NULL ? self->priv->service : "",
1266       set_service_cb, self);
1267 }
1268
1269 static void
1270 tpaw_account_settings_account_updated (GObject *source,
1271     GAsyncResult *result,
1272     gpointer user_data)
1273 {
1274   TpawAccountSettings *settings = TPAW_ACCOUNT_SETTINGS (user_data);
1275   GSimpleAsyncResult *r;
1276   GError *error = NULL;
1277   GStrv reconnect_required = NULL;
1278
1279   if (!tp_account_update_parameters_vardict_finish (TP_ACCOUNT (source),
1280           result, &reconnect_required, &error))
1281     {
1282       g_simple_async_result_set_from_error (settings->priv->apply_result,
1283           error);
1284       g_error_free (error);
1285       goto out;
1286     }
1287
1288   update_account_uri_schemes (settings);
1289   update_account_service (settings);
1290
1291   g_simple_async_result_set_op_res_gboolean (settings->priv->apply_result,
1292       g_strv_length (reconnect_required) > 0);
1293
1294   /* Only set the password in the keyring if the CM supports SASL. */
1295   if (settings->priv->supports_sasl)
1296     {
1297       if (settings->priv->password != NULL)
1298         {
1299           /* FIXME: we shouldn't save the password if we
1300            * can't (MaySaveResponse=False) but we don't have API to check that
1301            * at this point (fdo #35382). */
1302           tpaw_keyring_set_account_password_async (settings->priv->account,
1303               settings->priv->password, settings->priv->remember_password,
1304               tpaw_account_settings_set_password_cb, settings);
1305         }
1306       else
1307         {
1308           tpaw_keyring_delete_account_password_async (
1309               settings->priv->account,
1310               tpaw_account_settings_delete_password_cb, settings);
1311         }
1312
1313       return;
1314     }
1315
1316 out:
1317   tpaw_account_settings_discard_changes (settings);
1318
1319   r = settings->priv->apply_result;
1320   settings->priv->apply_result = NULL;
1321
1322   g_simple_async_result_complete (r);
1323   g_object_unref (r);
1324   g_strfreev (reconnect_required);
1325 }
1326
1327 static void
1328 tpaw_account_settings_created_cb (GObject *source,
1329     GAsyncResult *result,
1330     gpointer user_data)
1331 {
1332   TpawAccountSettings *settings = TPAW_ACCOUNT_SETTINGS (user_data);
1333   GError *error = NULL;
1334   GSimpleAsyncResult *r;
1335
1336   settings->priv->account = tp_account_request_create_account_finish (
1337       TP_ACCOUNT_REQUEST (source), result, &error);
1338
1339   if (settings->priv->account == NULL)
1340     {
1341       g_simple_async_result_set_from_error (settings->priv->apply_result,
1342           error);
1343     }
1344   else
1345     {
1346       if (settings->priv->supports_sasl && settings->priv->password != NULL)
1347         {
1348           /* Save the password before connecting */
1349           /* FIXME: we shouldn't save the password if we
1350            * can't (MaySaveResponse=False) but we don't have API to check that
1351            * at this point (fdo #35382). */
1352           tpaw_keyring_set_account_password_async (settings->priv->account,
1353               settings->priv->password, settings->priv->remember_password,
1354               tpaw_account_settings_set_password_cb,
1355               settings);
1356           return;
1357         }
1358
1359       update_account_uri_schemes (settings);
1360
1361       tpaw_account_settings_discard_changes (settings);
1362     }
1363
1364   r = settings->priv->apply_result;
1365   settings->priv->apply_result = NULL;
1366
1367   g_simple_async_result_complete (r);
1368   g_object_unref (r);
1369 }
1370
1371 static void
1372 tpaw_account_settings_do_create_account (TpawAccountSettings *self)
1373 {
1374   TpAccountRequest *account_req;
1375   GHashTableIter iter;
1376   gpointer k, v;
1377
1378   account_req = tp_account_request_new (self->priv->account_manager,
1379       self->priv->cm_name, self->priv->protocol, "New Account");
1380
1381   tp_account_request_set_icon_name (account_req, self->priv->icon_name);
1382
1383   tp_account_request_set_display_name (account_req,
1384       self->priv->display_name);
1385
1386   if (self->priv->service != NULL)
1387     tp_account_request_set_service (account_req, self->priv->service);
1388
1389   g_hash_table_iter_init (&iter, self->priv->parameters);
1390   while (g_hash_table_iter_next (&iter, &k, &v))
1391     {
1392       const gchar *key = k;
1393       GVariant *value = v;
1394
1395       tp_account_request_set_parameter (account_req, key, value);
1396     }
1397
1398   if (self->priv->storage_provider != NULL)
1399     {
1400       tp_account_request_set_storage_provider (account_req,
1401           self->priv->storage_provider);
1402     }
1403
1404   tp_account_request_create_account_async (account_req,
1405       tpaw_account_settings_created_cb, self);
1406 }
1407
1408 static GVariant *
1409 build_parameters_variant (TpawAccountSettings *self)
1410 {
1411   GVariantBuilder *builder;
1412   GHashTableIter iter;
1413   gpointer k, v;
1414
1415   builder = g_variant_builder_new (G_VARIANT_TYPE_VARDICT);
1416
1417   g_hash_table_iter_init (&iter, self->priv->parameters);
1418   while (g_hash_table_iter_next (&iter, &k, &v))
1419     {
1420       const gchar *key = k;
1421       GVariant *value = v;
1422       GVariant *entry;
1423
1424       entry = g_variant_new_dict_entry (g_variant_new_string (key),
1425           g_variant_new_variant (value));
1426
1427       g_variant_builder_add_value (builder, entry);
1428     }
1429
1430   return g_variant_builder_end (builder);
1431 }
1432
1433 void
1434 tpaw_account_settings_apply_async (TpawAccountSettings *settings,
1435     GAsyncReadyCallback callback,
1436     gpointer user_data)
1437 {
1438   if (settings->priv->apply_result != NULL)
1439     {
1440       g_simple_async_report_error_in_idle (G_OBJECT (settings),
1441           callback, user_data,
1442           G_IO_ERROR, G_IO_ERROR_PENDING, "Applying already in progress");
1443       return;
1444     }
1445
1446   settings->priv->apply_result = g_simple_async_result_new (
1447       G_OBJECT (settings), callback, user_data,
1448       tpaw_account_settings_apply_finish);
1449
1450   /* We'll have to reconnect only if we change none DBus_Property on an
1451    * existing account. */
1452   g_simple_async_result_set_op_res_gboolean (settings->priv->apply_result,
1453       FALSE);
1454
1455   if (settings->priv->account == NULL)
1456     {
1457       g_assert (settings->priv->apply_result != NULL &&
1458           settings->priv->account == NULL);
1459
1460       tpaw_account_settings_do_create_account (settings);
1461     }
1462   else
1463     {
1464       tp_account_update_parameters_vardict_async (settings->priv->account,
1465           build_parameters_variant (settings),
1466           (const gchar **) settings->priv->unset_parameters->data,
1467           tpaw_account_settings_account_updated, settings);
1468     }
1469 }
1470
1471 gboolean
1472 tpaw_account_settings_apply_finish (TpawAccountSettings *settings,
1473     GAsyncResult *result,
1474     gboolean *reconnect_required,
1475     GError **error)
1476 {
1477   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
1478       error))
1479     return FALSE;
1480
1481   g_return_val_if_fail (g_simple_async_result_is_valid (result,
1482     G_OBJECT (settings), tpaw_account_settings_apply_finish), FALSE);
1483
1484   if (reconnect_required != NULL)
1485     *reconnect_required = g_simple_async_result_get_op_res_gboolean (
1486         G_SIMPLE_ASYNC_RESULT (result));
1487
1488   return TRUE;
1489 }
1490
1491 gboolean
1492 tpaw_account_settings_has_account (TpawAccountSettings *settings,
1493     TpAccount *account)
1494 {
1495   const gchar *account_path;
1496   const gchar *priv_account_path;
1497
1498   g_return_val_if_fail (TPAW_IS_ACCOUNT_SETTINGS (settings), FALSE);
1499   g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
1500
1501   if (settings->priv->account == NULL)
1502     return FALSE;
1503
1504   account_path = tp_proxy_get_object_path (TP_PROXY (account));
1505   priv_account_path = tp_proxy_get_object_path (
1506       TP_PROXY (settings->priv->account));
1507
1508   return (!tp_strdiff (account_path, priv_account_path));
1509 }
1510
1511 void
1512 tpaw_account_settings_set_regex (TpawAccountSettings *settings,
1513     const gchar *param,
1514     const gchar *pattern)
1515 {
1516   GRegex *regex;
1517   GError *error = NULL;
1518
1519   regex = g_regex_new (pattern, 0, 0, &error);
1520   if (regex == NULL)
1521     {
1522       g_warning ("Failed to create reg exp: %s", error->message);
1523       g_error_free (error);
1524       return;
1525     }
1526
1527   g_hash_table_insert (settings->priv->param_regexps, g_strdup (param),
1528       regex);
1529 }
1530
1531 gboolean
1532 tpaw_account_settings_parameter_is_valid (
1533     TpawAccountSettings *settings,
1534     const gchar *param)
1535 {
1536   const GRegex *regex;
1537
1538   g_return_val_if_fail (TPAW_IS_ACCOUNT_SETTINGS (settings), FALSE);
1539
1540   if (g_list_find_custom (settings->priv->required_params, param,
1541         (GCompareFunc) strcmp))
1542     {
1543       /* first, look if it's set in our own parameters */
1544       if (g_hash_table_lookup (settings->priv->parameters, param) != NULL)
1545         goto test_regex;
1546
1547       /* if we did not unset the parameter, look if it's in the account */
1548       if (settings->priv->account != NULL &&
1549           !tpaw_account_settings_is_unset (settings, param))
1550         {
1551           const GHashTable *account_params;
1552
1553           account_params = tp_account_get_parameters (
1554               settings->priv->account);
1555           if (tp_asv_lookup (account_params, param))
1556             goto test_regex;
1557         }
1558
1559       return FALSE;
1560     }
1561
1562 test_regex:
1563   /* test whether parameter value matches its regex */
1564   regex = g_hash_table_lookup (settings->priv->param_regexps, param);
1565   if (regex)
1566     {
1567       gchar *value;
1568       gboolean match;
1569
1570       value = tpaw_account_settings_dup_string (settings, param);
1571       if (value == NULL)
1572         return FALSE;
1573
1574       match = g_regex_match (regex, value, 0, NULL);
1575
1576       g_free (value);
1577       return match;
1578     }
1579
1580   return TRUE;
1581 }
1582
1583 gboolean
1584 tpaw_account_settings_is_valid (TpawAccountSettings *settings)
1585 {
1586   const gchar *param;
1587   GHashTableIter iter;
1588   GList *l;
1589
1590   g_return_val_if_fail (TPAW_IS_ACCOUNT_SETTINGS (settings), FALSE);
1591
1592   for (l = settings->priv->required_params; l; l = l->next)
1593     {
1594       if (!tpaw_account_settings_parameter_is_valid (settings, l->data))
1595         return FALSE;
1596     }
1597
1598   g_hash_table_iter_init (&iter, settings->priv->param_regexps);
1599   while (g_hash_table_iter_next (&iter, (gpointer *) &param, NULL))
1600     {
1601       if (!tpaw_account_settings_parameter_is_valid (settings, param))
1602         return FALSE;
1603     }
1604
1605   return TRUE;
1606 }
1607
1608 TpProtocol *
1609 tpaw_account_settings_get_tp_protocol (TpawAccountSettings *self)
1610 {
1611   return self->priv->protocol_obj;
1612 }
1613
1614 gboolean
1615 tpaw_account_settings_supports_sasl (TpawAccountSettings *self)
1616 {
1617   return self->priv->supports_sasl;
1618 }
1619
1620 gboolean
1621 tpaw_account_settings_param_is_supported (TpawAccountSettings *self,
1622     const gchar *param)
1623 {
1624   return tp_protocol_has_param (self->priv->protocol_obj, param);
1625 }
1626
1627 void
1628 tpaw_account_settings_set_uri_scheme_tel (TpawAccountSettings *self,
1629     gboolean associate)
1630 {
1631   self->priv->uri_scheme_tel = associate;
1632 }
1633
1634 gboolean
1635 tpaw_account_settings_has_uri_scheme_tel (
1636     TpawAccountSettings *self)
1637 {
1638   return self->priv->uri_scheme_tel;
1639 }
1640
1641 void
1642 tpaw_account_settings_set_storage_provider (TpawAccountSettings *self,
1643     const gchar *storage)
1644 {
1645   g_free (self->priv->storage_provider);
1646   self->priv->storage_provider = g_strdup (storage);
1647 }
1648
1649 void
1650 tpaw_account_settings_set_remember_password (TpawAccountSettings *self,
1651     gboolean remember)
1652 {
1653   self->priv->remember_password = remember;
1654 }