]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-auth-factory.c
sort contacts by most recent event
[empathy.git] / libempathy / empathy-auth-factory.c
index d88e9bfd890b260c4bdbd095b0e69124d7543daa..04e619bd03cf20942c6c1f98c2a5edaa5c2c2acb 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <config.h>
-
+#include "config.h"
 #include "empathy-auth-factory.h"
 
-#include <telepathy-glib/telepathy-glib.h>
+#include <telepathy-glib/telepathy-glib-dbus.h>
+#include <tp-account-widgets/tpaw-keyring.h>
 
-#define DEBUG_FLAG EMPATHY_DEBUG_TLS
-#include "empathy-debug.h"
-#include "empathy-keyring.h"
+#include "empathy-sasl-mechanisms.h"
 #include "empathy-server-sasl-handler.h"
 #include "empathy-server-tls-handler.h"
 #include "empathy-utils.h"
 #include "empathy-goa-auth-handler.h"
 #endif /* HAVE_GOA */
 
-#include "extensions/extensions.h"
+#ifdef HAVE_UOA
+#include "empathy-uoa-auth-handler.h"
+#endif /* HAVE_UOA */
+
+#define DEBUG_FLAG EMPATHY_DEBUG_TLS
+#include "empathy-debug.h"
 
 G_DEFINE_TYPE (EmpathyAuthFactory, empathy_auth_factory, TP_TYPE_BASE_CLIENT);
 
@@ -53,12 +56,24 @@ struct _EmpathyAuthFactoryPriv {
   EmpathyGoaAuthHandler *goa_handler;
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+  EmpathyUoaAuthHandler *uoa_handler;
+#endif /* HAVE_UOA */
+
+  /* If an account failed to connect and user enters a new password to try, we
+   * store it in this hash table and will try to use it next time the account
+   * attemps to connect.
+   *
+   * reffed TpAccount -> owned password (gchar *) */
+  GHashTable *retry_passwords;
+
   gboolean dispose_run;
 };
 
 enum {
   NEW_SERVER_TLS_HANDLER,
   NEW_SERVER_SASL_HANDLER,
+  AUTH_PASSWORD_FAILED,
   LAST_SIGNAL,
 };
 
@@ -145,6 +160,18 @@ sasl_handler_invalidated_cb (EmpathyServerSASLHandler *handler,
   g_hash_table_remove (priv->sasl_handlers, tp_proxy_get_object_path (channel));
 }
 
+static void
+sasl_handler_auth_password_failed_cb (EmpathyServerSASLHandler *handler,
+    const gchar *password,
+    EmpathyAuthFactory *self)
+{
+  TpAccount *account;
+
+  account = empathy_server_sasl_handler_get_account (handler);
+
+  g_signal_emit (self, signals[AUTH_PASSWORD_FAILED], 0, account, password);
+}
+
 static void
 server_sasl_handler_ready_cb (GObject *source,
     GAsyncResult *res,
@@ -171,6 +198,8 @@ server_sasl_handler_ready_cb (GObject *source,
   else
     {
       TpChannel *channel;
+      const gchar *password;
+      TpAccount *account;
 
       if (data->context != NULL)
         tp_handle_channels_context_accept (data->context);
@@ -185,6 +214,32 @@ server_sasl_handler_ready_cb (GObject *source,
       tp_g_signal_connect_object (handler, "invalidated",
           G_CALLBACK (sasl_handler_invalidated_cb), data->self, 0);
 
+      tp_g_signal_connect_object (handler, "auth-password-failed",
+          G_CALLBACK (sasl_handler_auth_password_failed_cb), data->self, 0);
+
+      /* Is there a retry password? */
+      account = empathy_server_sasl_handler_get_account (handler);
+
+      password = g_hash_table_lookup (data->self->priv->retry_passwords,
+          account);
+      if (password != NULL)
+        {
+          gboolean save;
+
+          DEBUG ("Use retry password");
+
+          /* We want to save this new password only if there is another
+           * (wrong) password saved. The SASL handler will only save it if it
+           * manages to connect. */
+          save = empathy_server_sasl_handler_has_password (handler);
+
+          empathy_server_sasl_handler_provide_password (handler,
+              password, save);
+
+          /* We only want to try this password once */
+          g_hash_table_remove (data->self->priv->retry_passwords, account);
+        }
+
       g_signal_emit (data->self, signals[NEW_SERVER_SASL_HANDLER], 0,
           handler);
     }
@@ -226,7 +281,7 @@ common_checks (EmpathyAuthFactory *self,
        * ServerTLSConnection channels. */
       if (observe
           || tp_channel_get_channel_type_id (channel) !=
-          EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
+          TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
         {
           g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
               "Can only %s ServerTLSConnection or ServerAuthentication channels, "
@@ -308,7 +363,7 @@ handle_channels (TpBaseClient *handler,
 
   /* create a handler */
   if (tp_channel_get_channel_type_id (channel) ==
-      EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
+      TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
     {
       empathy_server_tls_handler_new_async (channel, server_tls_handler_ready_cb,
           data);
@@ -376,7 +431,7 @@ get_password_cb (GObject *source,
 {
   ObserveChannelsData *data = user_data;
 
-  if (empathy_keyring_get_account_password_finish (TP_ACCOUNT (source), result, NULL) == NULL)
+  if (tpaw_keyring_get_account_password_finish (TP_ACCOUNT (source), result, NULL) == NULL)
     {
       /* We don't actually mind if this fails, just let the approver
        * go ahead and take the channel. */
@@ -425,6 +480,32 @@ goa_claim_cb (GObject *source,
 }
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+static void
+uoa_claim_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  ObserveChannelsData *data = user_data;
+  EmpathyAuthFactory *self = data->self;
+  GError *error = NULL;
+
+  if (!tp_channel_dispatch_operation_claim_with_finish (data->dispatch_operation,
+          result, &error))
+    {
+      DEBUG ("Failed to claim: %s", error->message);
+      g_clear_error (&error);
+    }
+  else
+    {
+      empathy_uoa_auth_handler_start (self->priv->uoa_handler,
+          data->channel, data->account);
+    }
+
+  observe_channels_data_free (data);
+}
+#endif /* HAVE_UOA */
+
 static void
 observe_channels (TpBaseClient *client,
     TpAccount *account,
@@ -473,11 +554,37 @@ observe_channels (TpBaseClient *client,
     }
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+  /* UOA auth? */
+  if (empathy_uoa_auth_handler_supports (self->priv->uoa_handler, channel, account))
+    {
+      DEBUG ("Supported UOA account (%s), claim SASL channel",
+          tp_proxy_get_object_path (account));
+
+      tp_channel_dispatch_operation_claim_with_async (dispatch_operation,
+          client, uoa_claim_cb, data);
+      tp_observe_channels_context_accept (context);
+      return;
+    }
+#endif /* HAVE_UOA */
+
   /* Password auth? */
   if (empathy_sasl_channel_supports_mechanism (data->channel,
           "X-TELEPATHY-PASSWORD"))
     {
-      empathy_keyring_get_account_password_async (data->account,
+      if (g_hash_table_lookup (self->priv->retry_passwords, account) != NULL)
+        {
+          DEBUG ("We have a retry password for account %s, calling Claim",
+              tp_account_get_path_suffix (account));
+
+          tp_channel_dispatch_operation_claim_with_async (dispatch_operation,
+              client, password_claim_cb, data);
+
+          tp_observe_channels_context_accept (context);
+          return;
+        }
+
+      tpaw_keyring_get_account_password_async (data->account,
           get_password_cb, data);
       tp_observe_channels_context_delay (context);
       return;
@@ -523,9 +630,17 @@ empathy_auth_factory_init (EmpathyAuthFactory *self)
 
   self->priv->sasl_handlers = g_hash_table_new_full (g_str_hash, g_str_equal,
       NULL, g_object_unref);
+
 #ifdef HAVE_GOA
   self->priv->goa_handler = empathy_goa_auth_handler_new ();
 #endif /* HAVE_GOA */
+
+#ifdef HAVE_UOA
+  self->priv->uoa_handler = empathy_uoa_auth_handler_new ();
+#endif /* HAVE_UOA */
+
+  self->priv->retry_passwords = g_hash_table_new_full (NULL, NULL,
+      g_object_unref, g_free);
 }
 
 static void
@@ -543,7 +658,7 @@ empathy_auth_factory_constructed (GObject *obj)
   tp_base_client_take_handler_filter (client, tp_asv_new (
           /* ChannelType */
           TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
-          EMP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION,
+          TP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION,
           /* AuthenticationMethod */
           TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
           TP_HANDLE_TYPE_NONE, NULL));
@@ -587,10 +702,17 @@ empathy_auth_factory_dispose (GObject *object)
   priv->dispose_run = TRUE;
 
   g_hash_table_unref (priv->sasl_handlers);
+
 #ifdef HAVE_GOA
   g_object_unref (priv->goa_handler);
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+  g_object_unref (priv->uoa_handler);
+#endif /* HAVE_UOA */
+
+  g_hash_table_unref (priv->retry_passwords);
+
   G_OBJECT_CLASS (empathy_auth_factory_parent_class)->dispose (object);
 }
 
@@ -626,6 +748,15 @@ empathy_auth_factory_class_init (EmpathyAuthFactoryClass *klass)
       g_cclosure_marshal_generic,
       G_TYPE_NONE,
       1, EMPATHY_TYPE_SERVER_SASL_HANDLER);
+
+  signals[AUTH_PASSWORD_FAILED] =
+    g_signal_new ("auth-password-failed",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0,
+      NULL, NULL,
+      g_cclosure_marshal_generic,
+      G_TYPE_NONE,
+      2, TP_TYPE_ACCOUNT, G_TYPE_STRING);
 }
 
 EmpathyAuthFactory *
@@ -643,3 +774,12 @@ empathy_auth_factory_register (EmpathyAuthFactory *self,
 {
   return tp_base_client_register (TP_BASE_CLIENT (self), error);
 }
+
+void
+empathy_auth_factory_save_retry_password (EmpathyAuthFactory *self,
+    TpAccount *account,
+    const gchar *password)
+{
+  g_hash_table_insert (self->priv->retry_passwords,
+      g_object_ref (account), g_strdup (password));
+}