]> git.0d.be Git - empathy.git/blob - libempathy/empathy-auth-factory.c
fdd38b517e6bbe2512a09de6e4bff25a34dc4f28
[empathy.git] / libempathy / empathy-auth-factory.c
1 /*
2  * empathy-auth-factory.c - Source for EmpathyAuthFactory
3  * Copyright (C) 2010 Collabora Ltd.
4  * @author Cosimo Cecchi <cosimo.cecchi@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 "empathy-auth-factory.h"
23
24 #include <telepathy-glib/telepathy-glib-dbus.h>
25 #include <tp-account-widgets/tpaw-keyring.h>
26
27 #include "empathy-sasl-mechanisms.h"
28 #include "empathy-server-sasl-handler.h"
29 #include "empathy-server-tls-handler.h"
30 #include "empathy-utils.h"
31
32 #ifdef HAVE_GOA
33 #include "empathy-goa-auth-handler.h"
34 #endif /* HAVE_GOA */
35
36 #ifdef HAVE_UOA
37 #include "empathy-uoa-auth-handler.h"
38 #endif /* HAVE_UOA */
39
40 #include "extensions.h"
41
42 #define DEBUG_FLAG EMPATHY_DEBUG_TLS
43 #include "empathy-debug.h"
44
45 G_DEFINE_TYPE (EmpathyAuthFactory, empathy_auth_factory, TP_TYPE_BASE_CLIENT);
46
47 struct _EmpathyAuthFactoryPriv {
48   /* Keep a ref here so the auth client doesn't have to mess with
49    * refs. It will be cleared when the channel (and so the handler)
50    * gets invalidated.
51    *
52    * The channel path of the handler's channel (borrowed gchar *) ->
53    * reffed (EmpathyServerSASLHandler *)
54    * */
55   GHashTable *sasl_handlers;
56
57 #ifdef HAVE_GOA
58   EmpathyGoaAuthHandler *goa_handler;
59 #endif /* HAVE_GOA */
60
61 #ifdef HAVE_UOA
62   EmpathyUoaAuthHandler *uoa_handler;
63 #endif /* HAVE_UOA */
64
65   /* If an account failed to connect and user enters a new password to try, we
66    * store it in this hash table and will try to use it next time the account
67    * attemps to connect.
68    *
69    * reffed TpAccount -> owned password (gchar *) */
70   GHashTable *retry_passwords;
71
72   gboolean dispose_run;
73 };
74
75 enum {
76   NEW_SERVER_TLS_HANDLER,
77   NEW_SERVER_SASL_HANDLER,
78   AUTH_PASSWORD_FAILED,
79   LAST_SIGNAL,
80 };
81
82 static guint signals[LAST_SIGNAL] = { 0, };
83
84 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAuthFactory)
85
86 static EmpathyAuthFactory *auth_factory_singleton = NULL;
87
88 typedef struct {
89   TpHandleChannelsContext *context;
90   EmpathyAuthFactory *self;
91 } HandlerContextData;
92
93 static void
94 handler_context_data_free (HandlerContextData *data)
95 {
96   tp_clear_object (&data->self);
97   tp_clear_object (&data->context);
98
99   g_slice_free (HandlerContextData, data);
100 }
101
102 static HandlerContextData *
103 handler_context_data_new (EmpathyAuthFactory *self,
104     TpHandleChannelsContext *context)
105 {
106   HandlerContextData *data;
107
108   data = g_slice_new0 (HandlerContextData);
109   data->self = g_object_ref (self);
110
111   if (context != NULL)
112     data->context = g_object_ref (context);
113
114   return data;
115 }
116
117 static void
118 server_tls_handler_ready_cb (GObject *source,
119     GAsyncResult *res,
120     gpointer user_data)
121 {
122   EmpathyServerTLSHandler *handler;
123   GError *error = NULL;
124   HandlerContextData *data = user_data;
125
126   handler = empathy_server_tls_handler_new_finish (res, &error);
127
128   if (error != NULL)
129     {
130       DEBUG ("Failed to create a server TLS handler; error %s",
131           error->message);
132       tp_handle_channels_context_fail (data->context, error);
133
134       g_error_free (error);
135     }
136   else
137     {
138       tp_handle_channels_context_accept (data->context);
139       g_signal_emit (data->self, signals[NEW_SERVER_TLS_HANDLER], 0,
140           handler);
141
142       g_object_unref (handler);
143     }
144
145   handler_context_data_free (data);
146 }
147
148 static void
149 sasl_handler_invalidated_cb (EmpathyServerSASLHandler *handler,
150     gpointer user_data)
151 {
152   EmpathyAuthFactory *self = user_data;
153   EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
154   TpChannel * channel;
155
156   channel = empathy_server_sasl_handler_get_channel (handler);
157   g_assert (channel != NULL);
158
159   DEBUG ("SASL handler for channel %s is invalidated, unref it",
160       tp_proxy_get_object_path (channel));
161
162   g_hash_table_remove (priv->sasl_handlers, tp_proxy_get_object_path (channel));
163 }
164
165 static void
166 sasl_handler_auth_password_failed_cb (EmpathyServerSASLHandler *handler,
167     const gchar *password,
168     EmpathyAuthFactory *self)
169 {
170   TpAccount *account;
171
172   account = empathy_server_sasl_handler_get_account (handler);
173
174   g_signal_emit (self, signals[AUTH_PASSWORD_FAILED], 0, account, password);
175 }
176
177 static void
178 server_sasl_handler_ready_cb (GObject *source,
179     GAsyncResult *res,
180     gpointer user_data)
181 {
182   EmpathyAuthFactoryPriv *priv;
183   GError *error = NULL;
184   HandlerContextData *data = user_data;
185   EmpathyServerSASLHandler *handler;
186
187   priv = GET_PRIV (data->self);
188   handler = empathy_server_sasl_handler_new_finish (res, &error);
189
190   if (error != NULL)
191     {
192       DEBUG ("Failed to create a server SASL handler; error %s",
193           error->message);
194
195       if (data->context != NULL)
196         tp_handle_channels_context_fail (data->context, error);
197
198       g_error_free (error);
199     }
200   else
201     {
202       TpChannel *channel;
203       const gchar *password;
204       TpAccount *account;
205
206       if (data->context != NULL)
207         tp_handle_channels_context_accept (data->context);
208
209       channel = empathy_server_sasl_handler_get_channel (handler);
210       g_assert (channel != NULL);
211
212       /* Pass the ref to the hash table */
213       g_hash_table_insert (priv->sasl_handlers,
214           (gpointer) tp_proxy_get_object_path (channel), handler);
215
216       tp_g_signal_connect_object (handler, "invalidated",
217           G_CALLBACK (sasl_handler_invalidated_cb), data->self, 0);
218
219       tp_g_signal_connect_object (handler, "auth-password-failed",
220           G_CALLBACK (sasl_handler_auth_password_failed_cb), data->self, 0);
221
222       /* Is there a retry password? */
223       account = empathy_server_sasl_handler_get_account (handler);
224
225       password = g_hash_table_lookup (data->self->priv->retry_passwords,
226           account);
227       if (password != NULL)
228         {
229           gboolean save;
230
231           DEBUG ("Use retry password");
232
233           /* We want to save this new password only if there is another
234            * (wrong) password saved. The SASL handler will only save it if it
235            * manages to connect. */
236           save = empathy_server_sasl_handler_has_password (handler);
237
238           empathy_server_sasl_handler_provide_password (handler,
239               password, save);
240
241           /* We only want to try this password once */
242           g_hash_table_remove (data->self->priv->retry_passwords, account);
243         }
244
245       g_signal_emit (data->self, signals[NEW_SERVER_SASL_HANDLER], 0,
246           handler);
247     }
248
249   handler_context_data_free (data);
250 }
251
252 static gboolean
253 common_checks (EmpathyAuthFactory *self,
254     GList *channels,
255     gboolean observe,
256     GError **error)
257 {
258   EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
259   TpChannel *channel;
260   const GError *dbus_error;
261   EmpathyServerSASLHandler *handler;
262
263   /* there can't be more than one ServerTLSConnection or
264    * ServerAuthentication channels at the same time, for the same
265    * connection/account.
266    */
267   if (g_list_length (channels) != 1)
268     {
269       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
270           "Can't %s more than one ServerTLSConnection or ServerAuthentication "
271           "channel for the same connection.", observe ? "observe" : "handle");
272
273       return FALSE;
274     }
275
276   channel = channels->data;
277
278   if (tp_channel_get_channel_type_id (channel) !=
279       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
280     {
281       /* If we are observing we care only about ServerAuthentication channels.
282        * If we are handling we care about ServerAuthentication and
283        * ServerTLSConnection channels. */
284       if (observe
285           || tp_channel_get_channel_type_id (channel) !=
286           EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
287         {
288           g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
289               "Can only %s ServerTLSConnection or ServerAuthentication channels, "
290               "this was a %s channel", observe ? "observe" : "handle",
291               tp_channel_get_channel_type (channel));
292
293           return FALSE;
294         }
295     }
296
297   handler = g_hash_table_lookup (priv->sasl_handlers,
298           tp_proxy_get_object_path (channel));
299
300   if (tp_channel_get_channel_type_id (channel) ==
301       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION
302       && handler != NULL &&
303       !observe)
304     {
305       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
306           "We are already handling this channel: %s",
307           tp_proxy_get_object_path (channel));
308
309       return FALSE;
310     }
311
312   dbus_error = tp_proxy_get_invalidated (channel);
313   if (dbus_error != NULL)
314     {
315       *error = g_error_copy (dbus_error);
316       return FALSE;
317     }
318
319   return TRUE;
320 }
321
322 static void
323 handle_channels (TpBaseClient *handler,
324     TpAccount *account,
325     TpConnection *connection,
326     GList *channels,
327     GList *requests_satisfied,
328     gint64 user_action_time,
329     TpHandleChannelsContext *context)
330 {
331   TpChannel *channel;
332   GError *error = NULL;
333   EmpathyAuthFactory *self = EMPATHY_AUTH_FACTORY (handler);
334   HandlerContextData *data;
335
336   DEBUG ("Handle TLS or SASL carrier channels.");
337
338   if (!common_checks (self, channels, FALSE, &error))
339     {
340       DEBUG ("Failed checks: %s", error->message);
341       tp_handle_channels_context_fail (context, error);
342       g_clear_error (&error);
343       return;
344     }
345
346   /* The common checks above have checked this is fine. */
347   channel = channels->data;
348
349   /* Only password authentication is supported from here */
350   if (tp_channel_get_channel_type_id (channel) ==
351       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION &&
352       !empathy_sasl_channel_supports_mechanism (channel,
353           "X-TELEPATHY-PASSWORD"))
354     {
355       g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
356           "Only the X-TELEPATHY-PASSWORD SASL mechanism is supported");
357       DEBUG ("%s", error->message);
358       tp_handle_channels_context_fail (context, error);
359       g_clear_error (&error);
360       return;
361     }
362
363   data = handler_context_data_new (self, context);
364   tp_handle_channels_context_delay (context);
365
366   /* create a handler */
367   if (tp_channel_get_channel_type_id (channel) ==
368       EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
369     {
370       empathy_server_tls_handler_new_async (channel, server_tls_handler_ready_cb,
371           data);
372     }
373   else if (tp_channel_get_channel_type_id (channel) ==
374       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
375     {
376       empathy_server_sasl_handler_new_async (account, channel,
377           server_sasl_handler_ready_cb, data);
378     }
379 }
380
381 typedef struct
382 {
383   EmpathyAuthFactory *self;
384   TpObserveChannelsContext *context;
385   TpChannelDispatchOperation *dispatch_operation;
386   TpAccount *account;
387   TpChannel *channel;
388 } ObserveChannelsData;
389
390 static void
391 observe_channels_data_free (ObserveChannelsData *data)
392 {
393   g_object_unref (data->context);
394   g_object_unref (data->account);
395   g_object_unref (data->channel);
396   g_object_unref (data->dispatch_operation);
397   g_slice_free (ObserveChannelsData, data);
398 }
399
400 static void
401 password_claim_cb (GObject *source,
402     GAsyncResult *result,
403     gpointer user_data)
404 {
405   ObserveChannelsData *data = user_data;
406   GError *error = NULL;
407
408   if (!tp_channel_dispatch_operation_claim_with_finish (
409           TP_CHANNEL_DISPATCH_OPERATION (source), result, &error))
410     {
411       DEBUG ("Failed to call Claim: %s", error->message);
412       g_clear_error (&error);
413     }
414   else
415     {
416       HandlerContextData *h_data;
417
418       DEBUG ("Claim called successfully");
419
420       h_data = handler_context_data_new (data->self, NULL);
421
422       empathy_server_sasl_handler_new_async (TP_ACCOUNT (data->account),
423           data->channel, server_sasl_handler_ready_cb, h_data);
424     }
425
426   observe_channels_data_free (data);
427 }
428
429 static void
430 get_password_cb (GObject *source,
431     GAsyncResult *result,
432     gpointer user_data)
433 {
434   ObserveChannelsData *data = user_data;
435
436   if (tpaw_keyring_get_account_password_finish (TP_ACCOUNT (source), result, NULL) == NULL)
437     {
438       /* We don't actually mind if this fails, just let the approver
439        * go ahead and take the channel. */
440
441       DEBUG ("We don't have a password for account %s, letting the event "
442           "manager approver take it", tp_proxy_get_object_path (source));
443
444       tp_observe_channels_context_accept (data->context);
445       observe_channels_data_free (data);
446     }
447   else
448     {
449       DEBUG ("We have a password for account %s, calling Claim",
450           tp_proxy_get_object_path (source));
451
452       tp_channel_dispatch_operation_claim_with_async (data->dispatch_operation,
453           TP_BASE_CLIENT (data->self), password_claim_cb, data);
454
455       tp_observe_channels_context_accept (data->context);
456     }
457 }
458
459 #ifdef HAVE_GOA
460 static void
461 goa_claim_cb (GObject *source,
462     GAsyncResult *result,
463     gpointer user_data)
464 {
465   ObserveChannelsData *data = user_data;
466   EmpathyAuthFactory *self = data->self;
467   GError *error = NULL;
468
469   if (!tp_channel_dispatch_operation_claim_with_finish (data->dispatch_operation,
470           result, &error))
471     {
472       DEBUG ("Failed to claim: %s", error->message);
473       g_clear_error (&error);
474     }
475   else
476     {
477       empathy_goa_auth_handler_start (self->priv->goa_handler,
478           data->channel, data->account);
479     }
480
481   observe_channels_data_free (data);
482 }
483 #endif /* HAVE_GOA */
484
485 #ifdef HAVE_UOA
486 static void
487 uoa_claim_cb (GObject *source,
488     GAsyncResult *result,
489     gpointer user_data)
490 {
491   ObserveChannelsData *data = user_data;
492   EmpathyAuthFactory *self = data->self;
493   GError *error = NULL;
494
495   if (!tp_channel_dispatch_operation_claim_with_finish (data->dispatch_operation,
496           result, &error))
497     {
498       DEBUG ("Failed to claim: %s", error->message);
499       g_clear_error (&error);
500     }
501   else
502     {
503       empathy_uoa_auth_handler_start (self->priv->uoa_handler,
504           data->channel, data->account);
505     }
506
507   observe_channels_data_free (data);
508 }
509 #endif /* HAVE_UOA */
510
511 static void
512 observe_channels (TpBaseClient *client,
513     TpAccount *account,
514     TpConnection *connection,
515     GList *channels,
516     TpChannelDispatchOperation *dispatch_operation,
517     GList *requests,
518     TpObserveChannelsContext *context)
519 {
520   EmpathyAuthFactory *self = EMPATHY_AUTH_FACTORY (client);
521   TpChannel *channel;
522   GError *error = NULL;
523   ObserveChannelsData *data;
524
525   DEBUG ("New auth channel to observe");
526
527   if (!common_checks (self, channels, TRUE, &error))
528     {
529       DEBUG ("Failed checks: %s", error->message);
530       tp_observe_channels_context_fail (context, error);
531       g_clear_error (&error);
532       return;
533     }
534
535   /* The common checks above have checked this is fine. */
536   channel = channels->data;
537
538   data = g_slice_new0 (ObserveChannelsData);
539   data->self = self;
540   data->context = g_object_ref (context);
541   data->dispatch_operation = g_object_ref (dispatch_operation);
542   data->account = g_object_ref (account);
543   data->channel = g_object_ref (channel);
544
545 #ifdef HAVE_GOA
546   /* GOA auth? */
547   if (empathy_goa_auth_handler_supports (self->priv->goa_handler, channel, account))
548     {
549       DEBUG ("Supported GOA account (%s), claim SASL channel",
550           tp_proxy_get_object_path (account));
551
552       tp_channel_dispatch_operation_claim_with_async (dispatch_operation,
553           client, goa_claim_cb, data);
554       tp_observe_channels_context_accept (context);
555       return;
556     }
557 #endif /* HAVE_GOA */
558
559 #ifdef HAVE_UOA
560   /* UOA auth? */
561   if (empathy_uoa_auth_handler_supports (self->priv->uoa_handler, channel, account))
562     {
563       DEBUG ("Supported UOA account (%s), claim SASL channel",
564           tp_proxy_get_object_path (account));
565
566       tp_channel_dispatch_operation_claim_with_async (dispatch_operation,
567           client, uoa_claim_cb, data);
568       tp_observe_channels_context_accept (context);
569       return;
570     }
571 #endif /* HAVE_UOA */
572
573   /* Password auth? */
574   if (empathy_sasl_channel_supports_mechanism (data->channel,
575           "X-TELEPATHY-PASSWORD"))
576     {
577       if (g_hash_table_lookup (self->priv->retry_passwords, account) != NULL)
578         {
579           DEBUG ("We have a retry password for account %s, calling Claim",
580               tp_account_get_path_suffix (account));
581
582           tp_channel_dispatch_operation_claim_with_async (dispatch_operation,
583               client, password_claim_cb, data);
584
585           tp_observe_channels_context_accept (context);
586           return;
587         }
588
589       tpaw_keyring_get_account_password_async (data->account,
590           get_password_cb, data);
591       tp_observe_channels_context_delay (context);
592       return;
593     }
594
595   /* Unknown auth */
596   error = g_error_new_literal (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
597       "Unknown auth mechanism");
598   tp_observe_channels_context_fail (context, error);
599   g_clear_error (&error);
600
601   observe_channels_data_free (data);
602 }
603
604 static GObject *
605 empathy_auth_factory_constructor (GType type,
606     guint n_params,
607     GObjectConstructParam *params)
608 {
609   GObject *retval;
610
611   if (auth_factory_singleton != NULL)
612     {
613       retval = g_object_ref (auth_factory_singleton);
614     }
615   else
616     {
617       retval = G_OBJECT_CLASS (empathy_auth_factory_parent_class)->constructor
618         (type, n_params, params);
619
620       auth_factory_singleton = EMPATHY_AUTH_FACTORY (retval);
621       g_object_add_weak_pointer (retval, (gpointer *) &auth_factory_singleton);
622     }
623
624   return retval;
625 }
626
627 static void
628 empathy_auth_factory_init (EmpathyAuthFactory *self)
629 {
630   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
631       EMPATHY_TYPE_AUTH_FACTORY, EmpathyAuthFactoryPriv);
632
633   self->priv->sasl_handlers = g_hash_table_new_full (g_str_hash, g_str_equal,
634       NULL, g_object_unref);
635
636 #ifdef HAVE_GOA
637   self->priv->goa_handler = empathy_goa_auth_handler_new ();
638 #endif /* HAVE_GOA */
639
640 #ifdef HAVE_UOA
641   self->priv->uoa_handler = empathy_uoa_auth_handler_new ();
642 #endif /* HAVE_UOA */
643
644   self->priv->retry_passwords = g_hash_table_new_full (NULL, NULL,
645       g_object_unref, g_free);
646 }
647
648 static void
649 empathy_auth_factory_constructed (GObject *obj)
650 {
651   EmpathyAuthFactory *self = EMPATHY_AUTH_FACTORY (obj);
652   TpBaseClient *client = TP_BASE_CLIENT (self);
653
654   /* chain up to TpBaseClient first */
655   G_OBJECT_CLASS (empathy_auth_factory_parent_class)->constructed (obj);
656
657   tp_base_client_set_handler_bypass_approval (client, FALSE);
658
659   /* Handle ServerTLSConnection and ServerAuthentication channels */
660   tp_base_client_take_handler_filter (client, tp_asv_new (
661           /* ChannelType */
662           TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
663           EMP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION,
664           /* AuthenticationMethod */
665           TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
666           TP_HANDLE_TYPE_NONE, NULL));
667
668   tp_base_client_take_handler_filter (client, tp_asv_new (
669           /* ChannelType */
670           TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
671           TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
672           /* AuthenticationMethod */
673           TP_PROP_CHANNEL_TYPE_SERVER_AUTHENTICATION_AUTHENTICATION_METHOD,
674           G_TYPE_STRING, TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
675           NULL));
676
677   /* We are also an observer so that we can see new auth channels
678    * popping up and if we have the password already saved to one
679    * account where an auth channel has just appeared we can call
680    * Claim() on the CDO so the approver won't get it, which makes
681    * sense. */
682
683   /* Observe ServerAuthentication channels */
684   tp_base_client_take_observer_filter (client, tp_asv_new (
685           /* ChannelType */
686           TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
687           TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
688           /* AuthenticationMethod */
689           TP_PROP_CHANNEL_TYPE_SERVER_AUTHENTICATION_AUTHENTICATION_METHOD,
690           G_TYPE_STRING, TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
691           NULL));
692
693   tp_base_client_set_observer_delay_approvers (client, TRUE);
694 }
695
696 static void
697 empathy_auth_factory_dispose (GObject *object)
698 {
699   EmpathyAuthFactoryPriv *priv = GET_PRIV (object);
700
701   if (priv->dispose_run)
702     return;
703
704   priv->dispose_run = TRUE;
705
706   g_hash_table_unref (priv->sasl_handlers);
707
708 #ifdef HAVE_GOA
709   g_object_unref (priv->goa_handler);
710 #endif /* HAVE_GOA */
711
712 #ifdef HAVE_UOA
713   g_object_unref (priv->uoa_handler);
714 #endif /* HAVE_UOA */
715
716   g_hash_table_unref (priv->retry_passwords);
717
718   G_OBJECT_CLASS (empathy_auth_factory_parent_class)->dispose (object);
719 }
720
721 static void
722 empathy_auth_factory_class_init (EmpathyAuthFactoryClass *klass)
723 {
724   GObjectClass *oclass = G_OBJECT_CLASS (klass);
725   TpBaseClientClass *base_client_cls = TP_BASE_CLIENT_CLASS (klass);
726
727   oclass->constructor = empathy_auth_factory_constructor;
728   oclass->constructed = empathy_auth_factory_constructed;
729   oclass->dispose = empathy_auth_factory_dispose;
730
731   base_client_cls->handle_channels = handle_channels;
732   base_client_cls->observe_channels = observe_channels;
733
734   g_type_class_add_private (klass, sizeof (EmpathyAuthFactoryPriv));
735
736   signals[NEW_SERVER_TLS_HANDLER] =
737     g_signal_new ("new-server-tls-handler",
738       G_TYPE_FROM_CLASS (klass),
739       G_SIGNAL_RUN_LAST, 0,
740       NULL, NULL,
741       g_cclosure_marshal_generic,
742       G_TYPE_NONE,
743       1, EMPATHY_TYPE_SERVER_TLS_HANDLER);
744
745   signals[NEW_SERVER_SASL_HANDLER] =
746     g_signal_new ("new-server-sasl-handler",
747       G_TYPE_FROM_CLASS (klass),
748       G_SIGNAL_RUN_LAST, 0,
749       NULL, NULL,
750       g_cclosure_marshal_generic,
751       G_TYPE_NONE,
752       1, EMPATHY_TYPE_SERVER_SASL_HANDLER);
753
754   signals[AUTH_PASSWORD_FAILED] =
755     g_signal_new ("auth-password-failed",
756       G_TYPE_FROM_CLASS (klass),
757       G_SIGNAL_RUN_LAST, 0,
758       NULL, NULL,
759       g_cclosure_marshal_generic,
760       G_TYPE_NONE,
761       2, TP_TYPE_ACCOUNT, G_TYPE_STRING);
762 }
763
764 EmpathyAuthFactory *
765 empathy_auth_factory_new (TpSimpleClientFactory *factory)
766 {
767   return g_object_new (EMPATHY_TYPE_AUTH_FACTORY,
768       "factory", factory,
769       "name", "Empathy.Auth",
770       NULL);
771 }
772
773 gboolean
774 empathy_auth_factory_register (EmpathyAuthFactory *self,
775     GError **error)
776 {
777   return tp_base_client_register (TP_BASE_CLIENT (self), error);
778 }
779
780 void
781 empathy_auth_factory_save_retry_password (EmpathyAuthFactory *self,
782     TpAccount *account,
783     const gchar *password)
784 {
785   g_hash_table_insert (self->priv->retry_passwords,
786       g_object_ref (account), g_strdup (password));
787 }