]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-auth-factory.c
Merge remote-tracking branch 'pochu/error-dialog'
[empathy.git] / libempathy / empathy-auth-factory.c
index 8cbb90a14dd0107e4675406107ff704868554b73..6368b1d7d914852506f49e444d351a7810d6d3c3 100644 (file)
@@ -20,9 +20,7 @@
 
 #include "empathy-auth-factory.h"
 
-#include <telepathy-glib/interfaces.h>
-#include <telepathy-glib/simple-handler.h>
-#include <telepathy-glib/util.h>
+#include <telepathy-glib/telepathy-glib.h>
 
 #define DEBUG_FLAG EMPATHY_DEBUG_TLS
 #include "empathy-debug.h"
 
 G_DEFINE_TYPE (EmpathyAuthFactory, empathy_auth_factory, TP_TYPE_BASE_CLIENT);
 
-typedef struct {
+struct _EmpathyAuthFactoryPriv {
   /* Keep a ref here so the auth client doesn't have to mess with
    * refs. It will be cleared when the channel (and so the handler)
-   * gets invalidated. */
-  EmpathyServerSASLHandler *sasl_handler;
+   * gets invalidated.
+   *
+   * The channel path of the handler's channel (borrowed gchar *) ->
+   * reffed (EmpathyServerSASLHandler *)
+   * */
+  GHashTable *sasl_handlers;
 
   gboolean dispose_run;
-} EmpathyAuthFactoryPriv;
+};
 
 enum {
   NEW_SERVER_TLS_HANDLER,
@@ -92,10 +94,8 @@ server_tls_handler_ready_cb (GObject *source,
 {
   EmpathyServerTLSHandler *handler;
   GError *error = NULL;
-  EmpathyAuthFactoryPriv *priv;
   HandlerContextData *data = user_data;
 
-  priv = GET_PRIV (data->self);
   handler = empathy_server_tls_handler_new_finish (res, &error);
 
   if (error != NULL)
@@ -124,10 +124,15 @@ sasl_handler_invalidated_cb (EmpathyServerSASLHandler *handler,
 {
   EmpathyAuthFactory *self = user_data;
   EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
+  TpChannel * channel;
+
+  channel = empathy_server_sasl_handler_get_channel (handler);
+  g_assert (channel != NULL);
 
-  DEBUG ("SASL handler is invalidated, unref it");
+  DEBUG ("SASL handler for channel %s is invalidated, unref it",
+      tp_proxy_get_object_path (channel));
 
-  tp_clear_object (&priv->sasl_handler);
+  g_hash_table_remove (priv->sasl_handlers, tp_proxy_get_object_path (channel));
 }
 
 static void
@@ -138,9 +143,10 @@ server_sasl_handler_ready_cb (GObject *source,
   EmpathyAuthFactoryPriv *priv;
   GError *error = NULL;
   HandlerContextData *data = user_data;
+  EmpathyServerSASLHandler *handler;
 
   priv = GET_PRIV (data->self);
-  priv->sasl_handler = empathy_server_sasl_handler_new_finish (res, &error);
+  handler = empathy_server_sasl_handler_new_finish (res, &error);
 
   if (error != NULL)
     {
@@ -154,14 +160,23 @@ server_sasl_handler_ready_cb (GObject *source,
     }
   else
     {
+      TpChannel *channel;
+
       if (data->context != NULL)
         tp_handle_channels_context_accept (data->context);
 
-      g_signal_connect (priv->sasl_handler, "invalidated",
-          G_CALLBACK (sasl_handler_invalidated_cb), data->self);
+      channel = empathy_server_sasl_handler_get_channel (handler);
+      g_assert (channel != NULL);
+
+      /* Pass the ref to the hash table */
+      g_hash_table_insert (priv->sasl_handlers,
+          (gpointer) tp_proxy_get_object_path (channel), handler);
+
+      tp_g_signal_connect_object (handler, "invalidated",
+          G_CALLBACK (sasl_handler_invalidated_cb), data->self, 0);
 
       g_signal_emit (data->self, signals[NEW_SERVER_SASL_HANDLER], 0,
-          priv->sasl_handler);
+          handler);
     }
 
   handler_context_data_free (data);
@@ -170,7 +185,7 @@ server_sasl_handler_ready_cb (GObject *source,
 static gboolean
 common_checks (EmpathyAuthFactory *self,
     GList *channels,
-    gboolean must_be_sasl,
+    gboolean observe,
     GError **error)
 {
   EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
@@ -178,6 +193,7 @@ common_checks (EmpathyAuthFactory *self,
   GHashTable *props;
   const gchar * const *available_mechanisms;
   const GError *dbus_error;
+  EmpathyServerSASLHandler *handler;
 
   /* there can't be more than one ServerTLSConnection or
    * ServerAuthentication channels at the same time, for the same
@@ -185,9 +201,9 @@ common_checks (EmpathyAuthFactory *self,
    */
   if (g_list_length (channels) != 1)
     {
-      g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
-          "Can't handle more than one ServerTLSConnection or ServerAuthentication "
-          "channel for the same connection.");
+      g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+          "Can't %s more than one ServerTLSConnection or ServerAuthentication "
+          "channel for the same connection.", observe ? "observe" : "handle");
 
       return FALSE;
     }
@@ -197,24 +213,33 @@ common_checks (EmpathyAuthFactory *self,
   if (tp_channel_get_channel_type_id (channel) !=
       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
     {
-      if (must_be_sasl
+      /* If we are observing we care only about ServerAuthentication channels.
+       * If we are handling we care about ServerAuthentication and
+       * ServerTLSConnection channels. */
+      if (observe
           || tp_channel_get_channel_type_id (channel) !=
           EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
         {
           g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
-              "Can only handle ServerTLSConnection or ServerAuthentication channels, "
-              "this was a %s channel", tp_channel_get_channel_type (channel));
+              "Can only %s ServerTLSConnection or ServerAuthentication channels, "
+              "this was a %s channel", observe ? "observe" : "handle",
+              tp_channel_get_channel_type (channel));
 
           return FALSE;
         }
     }
 
+  handler = g_hash_table_lookup (priv->sasl_handlers,
+          tp_proxy_get_object_path (channel));
+
   if (tp_channel_get_channel_type_id (channel) ==
       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION
-      && priv->sasl_handler != NULL)
+      && handler != NULL &&
+      !observe)
     {
-      g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
-          "Can't handle more than one ServerAuthentication channel at one time");
+      g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+          "We are already handling this channel: %s",
+          tp_proxy_get_object_path (channel));
 
       return FALSE;
     }
@@ -317,7 +342,7 @@ claim_cb (GObject *source,
   ObserveChannelsData *data = user_data;
   GError *error = NULL;
 
-  if (!tp_channel_dispatch_operation_claim_finish (
+  if (!tp_channel_dispatch_operation_claim_with_finish (
           TP_CHANNEL_DISPATCH_OPERATION (source), result, &error))
     {
       DEBUG ("Failed to call Claim: %s", error->message);
@@ -361,8 +386,8 @@ get_password_cb (GObject *source,
       DEBUG ("We have a password for account %s, calling Claim",
           tp_proxy_get_object_path (source));
 
-      tp_channel_dispatch_operation_claim_async (data->dispatch_operation,
-          claim_cb, data);
+      tp_channel_dispatch_operation_claim_with_async (data->dispatch_operation,
+          TP_BASE_CLIENT (data->self), claim_cb, data);
 
       tp_observe_channels_context_accept (data->context);
     }
@@ -437,6 +462,9 @@ empathy_auth_factory_init (EmpathyAuthFactory *self)
 {
   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
       EMPATHY_TYPE_AUTH_FACTORY, EmpathyAuthFactoryPriv);
+
+  self->priv->sasl_handlers = g_hash_table_new_full (g_str_hash, g_str_equal,
+      NULL, g_object_unref);
 }
 
 static void
@@ -444,20 +472,13 @@ empathy_auth_factory_constructed (GObject *obj)
 {
   EmpathyAuthFactory *self = EMPATHY_AUTH_FACTORY (obj);
   TpBaseClient *client = TP_BASE_CLIENT (self);
-  GError *error = NULL;
 
   /* chain up to TpBaseClient first */
   G_OBJECT_CLASS (empathy_auth_factory_parent_class)->constructed (obj);
 
-  if (error != NULL)
-    {
-      g_critical ("Failed to get TpDBusDaemon: %s", error->message);
-      g_error_free (error);
-      return;
-    }
-
   tp_base_client_set_handler_bypass_approval (client, FALSE);
 
+  /* Handle ServerTLSConnection and ServerAuthentication channels */
   tp_base_client_take_handler_filter (client, tp_asv_new (
           /* ChannelType */
           TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
@@ -481,6 +502,7 @@ empathy_auth_factory_constructed (GObject *obj)
    * Claim() on the CDO so the approver won't get it, which makes
    * sense. */
 
+  /* Observe ServerAuthentication channels */
   tp_base_client_take_observer_filter (client, tp_asv_new (
           /* ChannelType */
           TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
@@ -489,6 +511,8 @@ empathy_auth_factory_constructed (GObject *obj)
           TP_PROP_CHANNEL_TYPE_SERVER_AUTHENTICATION_AUTHENTICATION_METHOD,
           G_TYPE_STRING, TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
           NULL));
+
+  tp_base_client_set_observer_delay_approvers (client, TRUE);
 }
 
 static void
@@ -501,7 +525,7 @@ empathy_auth_factory_dispose (GObject *object)
 
   priv->dispose_run = TRUE;
 
-  tp_clear_object (&priv->sasl_handler);
+  g_hash_table_unref (priv->sasl_handlers);
 
   G_OBJECT_CLASS (empathy_auth_factory_parent_class)->dispose (object);
 }
@@ -526,7 +550,7 @@ empathy_auth_factory_class_init (EmpathyAuthFactoryClass *klass)
       G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, 0,
       NULL, NULL,
-      g_cclosure_marshal_VOID__OBJECT,
+      g_cclosure_marshal_generic,
       G_TYPE_NONE,
       1, EMPATHY_TYPE_SERVER_TLS_HANDLER);
 
@@ -535,7 +559,7 @@ empathy_auth_factory_class_init (EmpathyAuthFactoryClass *klass)
       G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, 0,
       NULL, NULL,
-      g_cclosure_marshal_VOID__OBJECT,
+      g_cclosure_marshal_generic,
       G_TYPE_NONE,
       1, EMPATHY_TYPE_SERVER_SASL_HANDLER);
 }