diff options
author | Xavier Claessens <xclaesse@gmail.com> | 2011-10-27 18:09:59 +0800 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2011-11-04 17:10:19 +0800 |
commit | d3e575fd305487eb8a15a66941651325904ba90b (patch) | |
tree | 2aa27a2f1142ba3f9a34bc04263172ccc4494a39 /libempathy | |
parent | baeff8af237dd7c4a18d578ed71b3ee87ceb278d (diff) | |
download | gsoc2013-empathy-d3e575fd305487eb8a15a66941651325904ba90b.tar gsoc2013-empathy-d3e575fd305487eb8a15a66941651325904ba90b.tar.gz gsoc2013-empathy-d3e575fd305487eb8a15a66941651325904ba90b.tar.bz2 gsoc2013-empathy-d3e575fd305487eb8a15a66941651325904ba90b.tar.lz gsoc2013-empathy-d3e575fd305487eb8a15a66941651325904ba90b.tar.xz gsoc2013-empathy-d3e575fd305487eb8a15a66941651325904ba90b.tar.zst gsoc2013-empathy-d3e575fd305487eb8a15a66941651325904ba90b.zip |
Import Facebook and windows Live GOA accounts
Implement their auth mechanisms
Fixes bug #661068 and #652544
Diffstat (limited to 'libempathy')
-rw-r--r-- | libempathy/Makefile.am | 2 | ||||
-rw-r--r-- | libempathy/empathy-auth-factory.c | 98 | ||||
-rw-r--r-- | libempathy/empathy-goa-auth-handler.c | 436 | ||||
-rw-r--r-- | libempathy/empathy-goa-auth-handler.h | 72 | ||||
-rw-r--r-- | libempathy/empathy-utils.c | 15 | ||||
-rw-r--r-- | libempathy/empathy-utils.h | 3 |
6 files changed, 601 insertions, 25 deletions
diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index 079b4736b..0662f2cf0 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -29,6 +29,7 @@ libempathy_headers = \ action-chain-internal.h \ empathy-account-settings.h \ empathy-auth-factory.h \ + empathy-goa-auth-handler.h \ empathy-camera-monitor.h \ empathy-chatroom-manager.h \ empathy-chatroom.h \ @@ -72,6 +73,7 @@ libempathy_handwritten_source = \ action-chain.c \ empathy-account-settings.c \ empathy-auth-factory.c \ + empathy-goa-auth-handler.c \ empathy-camera-monitor.c \ empathy-chatroom-manager.c \ empathy-chatroom.c \ diff --git a/libempathy/empathy-auth-factory.c b/libempathy/empathy-auth-factory.c index 663dce050..03f2cd16d 100644 --- a/libempathy/empathy-auth-factory.c +++ b/libempathy/empathy-auth-factory.c @@ -27,6 +27,7 @@ #include "empathy-keyring.h" #include "empathy-server-sasl-handler.h" #include "empathy-server-tls-handler.h" +#include "empathy-goa-auth-handler.h" #include "empathy-utils.h" #include "extensions/extensions.h" @@ -42,6 +43,7 @@ struct _EmpathyAuthFactoryPriv { * reffed (EmpathyServerSASLHandler *) * */ GHashTable *sasl_handlers; + EmpathyGoaAuthHandler *goa_handler; gboolean dispose_run; }; @@ -190,8 +192,6 @@ common_checks (EmpathyAuthFactory *self, { EmpathyAuthFactoryPriv *priv = GET_PRIV (self); TpChannel *channel; - GHashTable *props; - const gchar * const *available_mechanisms; const GError *dbus_error; EmpathyServerSASLHandler *handler; @@ -244,23 +244,7 @@ common_checks (EmpathyAuthFactory *self, return FALSE; } - props = tp_channel_borrow_immutable_properties (channel); - available_mechanisms = tp_asv_get_boxed (props, - TP_PROP_CHANNEL_INTERFACE_SASL_AUTHENTICATION_AVAILABLE_MECHANISMS, - G_TYPE_STRV); - - if (tp_channel_get_channel_type_id (channel) == - TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION - && !tp_strv_contains (available_mechanisms, "X-TELEPATHY-PASSWORD")) - { - g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Only the X-TELEPATHY-PASSWORD SASL mechanism is supported"); - - return FALSE; - } - dbus_error = tp_proxy_get_invalidated (channel); - if (dbus_error != NULL) { *error = g_error_copy (dbus_error); @@ -297,6 +281,20 @@ handle_channels (TpBaseClient *handler, /* The common checks above have checked this is fine. */ channel = channels->data; + /* Only password authentication is supported from here */ + if (tp_channel_get_channel_type_id (channel) == + TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION && + !empathy_sasl_channel_supports_mechanism (channel, + "X-TELEPATHY-PASSWORD")) + { + g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, + "Only the X-TELEPATHY-PASSWORD SASL mechanism is supported"); + DEBUG ("%s", error->message); + tp_handle_channels_context_fail (context, error); + g_clear_error (&error); + return; + } + data = handler_context_data_new (self, context); tp_handle_channels_context_delay (context); @@ -335,7 +333,7 @@ observe_channels_data_free (ObserveChannelsData *data) } static void -claim_cb (GObject *source, +password_claim_cb (GObject *source, GAsyncResult *result, gpointer user_data) { @@ -387,13 +385,37 @@ get_password_cb (GObject *source, tp_proxy_get_object_path (source)); tp_channel_dispatch_operation_claim_with_async (data->dispatch_operation, - TP_BASE_CLIENT (data->self), claim_cb, data); + TP_BASE_CLIENT (data->self), password_claim_cb, data); tp_observe_channels_context_accept (data->context); } } static void +goa_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_goa_auth_handler_start (self->priv->goa_handler, + data->channel, data->account); + } + + observe_channels_data_free (data); +} + +static void observe_channels (TpBaseClient *client, TpAccount *account, TpConnection *connection, @@ -417,9 +439,7 @@ observe_channels (TpBaseClient *client, return; } - /* We're now sure this is a server auth channel using the SASL auth - * type and X-TELEPATHY-PASSWORD is available. Great. */ - + /* The common checks above have checked this is fine. */ channel = channels->data; data = g_slice_new0 (ObserveChannelsData); @@ -429,9 +449,35 @@ observe_channels (TpBaseClient *client, data->account = g_object_ref (account); data->channel = g_object_ref (channel); - empathy_keyring_get_account_password_async (account, get_password_cb, data); + /* GOA auth? */ + if (empathy_goa_auth_handler_supports (self->priv->goa_handler, channel, account)) + { + DEBUG ("Supported GOA account (%s), claim SASL channel", + tp_proxy_get_object_path (account)); + + tp_channel_dispatch_operation_claim_with_async (dispatch_operation, + client, goa_claim_cb, data); + tp_observe_channels_context_accept (context); + return; + } - tp_observe_channels_context_delay (context); + /* Password auth? */ + if (empathy_sasl_channel_supports_mechanism (data->channel, + "X-TELEPATHY-PASSWORD")) + { + empathy_keyring_get_account_password_async (data->account, + get_password_cb, data); + tp_observe_channels_context_delay (context); + return; + } + + /* Unknown auth */ + error = g_error_new_literal (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, + "Unknown auth mechanism"); + tp_observe_channels_context_fail (context, error); + g_clear_error (&error); + + observe_channels_data_free (data); } static GObject * @@ -465,6 +511,7 @@ 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); + self->priv->goa_handler = empathy_goa_auth_handler_new (); } static void @@ -526,6 +573,7 @@ empathy_auth_factory_dispose (GObject *object) priv->dispose_run = TRUE; g_hash_table_unref (priv->sasl_handlers); + g_object_unref (priv->goa_handler); G_OBJECT_CLASS (empathy_auth_factory_parent_class)->dispose (object); } diff --git a/libempathy/empathy-goa-auth-handler.c b/libempathy/empathy-goa-auth-handler.c new file mode 100644 index 000000000..a439c72c2 --- /dev/null +++ b/libempathy/empathy-goa-auth-handler.c @@ -0,0 +1,436 @@ +/* + * empathy-auth-goa.c - Source for Goa SASL authentication + * Copyright (C) 2011 Collabora Ltd. + * @author Xavier Claessens <xavier.claessens@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#define GOA_API_IS_SUBJECT_TO_CHANGE /* awesome! */ +#include <goa/goa.h> + +#include <libsoup/soup.h> +#include <string.h> + +#define DEBUG_FLAG EMPATHY_DEBUG_SASL +#include "empathy-debug.h" +#include "empathy-utils.h" +#include "empathy-goa-auth-handler.h" + +#define MECH_FACEBOOK "X-FACEBOOK-PLATFORM" +#define MECH_MSN "X-MESSENGER-OAUTH2" + +static const gchar *supported_mechanisms[] = { + MECH_FACEBOOK, + MECH_MSN, + NULL}; + +struct _EmpathyGoaAuthHandlerPriv +{ + GoaClient *client; + gboolean client_preparing; + + /* List of AuthData waiting for client to be created */ + GList *auth_queue; +}; + +G_DEFINE_TYPE (EmpathyGoaAuthHandler, empathy_goa_auth_handler, G_TYPE_OBJECT); + +static void +empathy_goa_auth_handler_init (EmpathyGoaAuthHandler *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + EMPATHY_TYPE_GOA_AUTH_HANDLER, EmpathyGoaAuthHandlerPriv); +} + +static void +empathy_goa_auth_handler_dispose (GObject *object) +{ + EmpathyGoaAuthHandler *self = (EmpathyGoaAuthHandler *) object; + + /* AuthData keeps a ref on self */ + g_assert (self->priv->auth_queue == NULL); + + tp_clear_object (&self->priv->client); + + G_OBJECT_CLASS (empathy_goa_auth_handler_parent_class)->dispose (object); +} + +static void +empathy_goa_auth_handler_class_init (EmpathyGoaAuthHandlerClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->dispose = empathy_goa_auth_handler_dispose; + + g_type_class_add_private (klass, sizeof (EmpathyGoaAuthHandlerPriv)); +} + +EmpathyGoaAuthHandler * +empathy_goa_auth_handler_new (void) +{ + return g_object_new (EMPATHY_TYPE_GOA_AUTH_HANDLER, NULL); +} + +typedef struct +{ + EmpathyGoaAuthHandler *self; + TpChannel *channel; + TpAccount *account; + + GoaObject *goa_object; + gchar *access_token; +} AuthData; + +static void +auth_data_free (AuthData *data) +{ + tp_clear_object (&data->self); + tp_clear_object (&data->channel); + tp_clear_object (&data->account); + tp_clear_object (&data->goa_object); + g_free (data->access_token); + g_slice_free (AuthData, data); +} + +static void +fail_auth (AuthData *data) +{ + DEBUG ("Auth failed for account %s", + tp_proxy_get_object_path (data->account)); + + tp_channel_close_async (data->channel, NULL, NULL); + auth_data_free (data); +} + +static void +sasl_status_changed_cb (TpChannel *channel, + guint status, + const gchar *reason, + GHashTable *details, + gpointer user_data, + GObject *self) +{ + switch (status) + { + case TP_SASL_STATUS_SERVER_SUCCEEDED: + tp_cli_channel_interface_sasl_authentication_call_accept_sasl (channel, + -1, NULL, NULL, NULL, NULL); + break; + + case TP_SASL_STATUS_SUCCEEDED: + case TP_SASL_STATUS_SERVER_FAILED: + case TP_SASL_STATUS_CLIENT_FAILED: + tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); + break; + + default: + break; + } +} + +static void +facebook_new_challenge_cb (TpChannel *channel, + const GArray *challenge, + gpointer user_data, + GObject *weak_object) +{ + AuthData *data = user_data; + GoaOAuth2Based *oauth2; + const gchar *client_id; + GHashTable *h; + GHashTable *params; + gchar *response; + GArray *response_array; + + DEBUG ("new challenge for %s:\n%s", + tp_proxy_get_object_path (data->account), + challenge->data); + + h = soup_form_decode (challenge->data); + + oauth2 = goa_object_get_oauth2_based (data->goa_object); + client_id = goa_oauth2_based_get_client_id (oauth2); + + /* See https://developers.facebook.com/docs/chat/#platauth */ + params = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (params, "method", g_hash_table_lookup (h, "method")); + g_hash_table_insert (params, "nonce", g_hash_table_lookup (h, "nonce")); + g_hash_table_insert (params, "access_token", data->access_token); + g_hash_table_insert (params, "api_key", (gpointer) client_id); + g_hash_table_insert (params, "call_id", "0"); + g_hash_table_insert (params, "v", "1.0"); + + response = soup_form_encode_hash (params); + DEBUG ("Response: %s", response); + + response_array = g_array_new (FALSE, FALSE, sizeof (gchar)); + g_array_append_vals (response_array, response, strlen (response)); + + tp_cli_channel_interface_sasl_authentication_call_respond (data->channel, -1, + response_array, NULL, NULL, NULL, NULL); + + g_hash_table_unref (h); + g_hash_table_unref (params); + g_object_unref (oauth2); + g_free (response); + g_array_unref (response_array); +} + +static void +got_oauth2_access_token_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GoaOAuth2Based *oauth2 = (GoaOAuth2Based *) source; + AuthData *data = user_data; + gint expires_in; + GError *error = NULL; + + if (!goa_oauth2_based_call_get_access_token_finish (oauth2, + &data->access_token, &expires_in, result, &error)) + { + DEBUG ("Failed to get access token: %s", error->message); + fail_auth (data); + g_clear_error (&error); + return; + } + + DEBUG ("Got access token for %s:\n%s", + tp_proxy_get_object_path (data->account), + data->access_token); + + tp_cli_channel_interface_sasl_authentication_connect_to_sasl_status_changed ( + data->channel, sasl_status_changed_cb, NULL, NULL, NULL, NULL); + g_assert_no_error (error); + + if (empathy_sasl_channel_supports_mechanism (data->channel, MECH_FACEBOOK)) + { + /* Give ownership of data to signal connection */ + tp_cli_channel_interface_sasl_authentication_connect_to_new_challenge ( + data->channel, facebook_new_challenge_cb, + data, (GDestroyNotify) auth_data_free, + NULL, NULL); + + DEBUG ("Start %s mechanism for account %s", MECH_FACEBOOK, + tp_proxy_get_object_path (data->account)); + + tp_cli_channel_interface_sasl_authentication_call_start_mechanism ( + data->channel, -1, MECH_FACEBOOK, NULL, NULL, NULL, NULL); + } + else if (empathy_sasl_channel_supports_mechanism (data->channel, MECH_MSN)) + { + guchar *token_decoded; + gsize token_decoded_len; + GArray *token_decoded_array; + + /* Wocky will base64 encode, but token actually already is base64, so we + * decode now and it will be re-encoded. */ + token_decoded = g_base64_decode (data->access_token, &token_decoded_len); + token_decoded_array = g_array_new (FALSE, FALSE, sizeof (guchar)); + g_array_append_vals (token_decoded_array, token_decoded, token_decoded_len); + + DEBUG ("Start %s mechanism for account %s", MECH_MSN, + tp_proxy_get_object_path (data->account)); + + tp_cli_channel_interface_sasl_authentication_call_start_mechanism_with_data ( + data->channel, -1, MECH_MSN, token_decoded_array, + NULL, NULL, NULL, NULL); + + g_array_unref (token_decoded_array); + g_free (token_decoded); + auth_data_free (data); + } + else + { + /* We already checked it supports one of supported_mechanisms, so this + * can't happen */ + g_assert_not_reached (); + } +} + +static void +ensure_credentials_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + AuthData *data = user_data; + GoaAccount *goa_account = (GoaAccount *) source; + GoaOAuth2Based *oauth2; + gint expires_in; + GError *error = NULL; + + if (!goa_account_call_ensure_credentials_finish (goa_account, &expires_in, + result, &error)) + { + DEBUG ("Failed to EnsureCredentials: %s", error->message); + fail_auth (data); + g_clear_error (&error); + return; + } + + /* We support only oaut2 */ + oauth2 = goa_object_get_oauth2_based (data->goa_object); + if (oauth2 == NULL) + { + DEBUG ("GoaObject does not implement oauth2"); + fail_auth (data); + return; + } + + DEBUG ("Goa daemon has credentials for %s, get the access token", + tp_proxy_get_object_path (data->account)); + + goa_oauth2_based_call_get_access_token (oauth2, NULL, + got_oauth2_access_token_cb, data); + + g_object_unref (oauth2); +} + +static void +start_auth (AuthData *data) +{ + EmpathyGoaAuthHandler *self = data->self; + const GValue *id_value; + const gchar *id; + GList *goa_accounts, *l; + gboolean found = FALSE; + + id_value = tp_account_get_storage_identifier (data->account); + id = g_value_get_string (id_value); + + goa_accounts = goa_client_get_accounts (self->priv->client); + for (l = goa_accounts; l != NULL && !found; l = l->next) + { + GoaObject *goa_object = l->data; + GoaAccount *goa_account; + + goa_account = goa_object_get_account (goa_object); + if (!tp_strdiff (goa_account_get_id (goa_account), id)) + { + data->goa_object = g_object_ref (goa_object); + + DEBUG ("Found the GoaAccount for %s, ensure credentials", + tp_proxy_get_object_path (data->account)); + + goa_account_call_ensure_credentials (goa_account, NULL, + ensure_credentials_cb, data); + + found = TRUE; + } + + g_object_unref (goa_account); + } + g_list_free_full (goa_accounts, g_object_unref); + + if (!found) + { + DEBUG ("Cannot find GoaAccount"); + fail_auth (data); + } +} + +static void +client_new_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + EmpathyGoaAuthHandler *self = user_data; + GList *l; + GError *error = NULL; + + self->priv->client_preparing = FALSE; + self->priv->client = goa_client_new_finish (result, &error); + if (self->priv->client == NULL) + { + DEBUG ("Error getting GoaClient: %s", error->message); + g_clear_error (&error); + } + + /* process queued data */ + for (l = self->priv->auth_queue; l != NULL; l = l->next) + { + AuthData *data = l->data; + + if (self->priv->client != NULL) + start_auth (data); + else + fail_auth (data); + } + + tp_clear_pointer (&self->priv->auth_queue, g_list_free); +} + +void +empathy_goa_auth_handler_start (EmpathyGoaAuthHandler *self, + TpChannel *channel, + TpAccount *account) +{ + AuthData *data; + + g_return_if_fail (TP_IS_CHANNEL (channel)); + g_return_if_fail (TP_IS_ACCOUNT (account)); + g_return_if_fail (empathy_goa_auth_handler_supports (self, channel, account)); + + DEBUG ("Start Goa auth for account: %s", + tp_proxy_get_object_path (account)); + + data = g_slice_new0 (AuthData); + data->self = g_object_ref (self); + data->channel = g_object_ref (channel); + data->account = g_object_ref (account); + + if (self->priv->client == NULL) + { + /* GOA client not ready yet, queue data */ + if (!self->priv->client_preparing) + { + goa_client_new (NULL, client_new_cb, self); + self->priv->client_preparing = TRUE; + } + + self->priv->auth_queue = g_list_prepend (self->priv->auth_queue, data); + } + else + { + start_auth (data); + } +} + +gboolean +empathy_goa_auth_handler_supports (EmpathyGoaAuthHandler *self, + TpChannel *channel, + TpAccount *account) +{ + const gchar *provider; + const gchar * const *iter; + + g_return_val_if_fail (TP_IS_CHANNEL (channel), FALSE); + g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE); + + provider = tp_account_get_storage_provider (account); + if (tp_strdiff (provider, EMPATHY_GOA_PROVIDER)) + return FALSE; + + for (iter = supported_mechanisms; *iter != NULL; iter++) + { + if (empathy_sasl_channel_supports_mechanism (channel, *iter)) + return TRUE; + } + + return FALSE; +} diff --git a/libempathy/empathy-goa-auth-handler.h b/libempathy/empathy-goa-auth-handler.h new file mode 100644 index 000000000..5b7c08774 --- /dev/null +++ b/libempathy/empathy-goa-auth-handler.h @@ -0,0 +1,72 @@ +/* + * empathy-auth-goa.h - Header for Goa SASL authentication + * Copyright (C) 2011 Collabora Ltd. + * @author Xavier Claessens <xavier.claessens@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __EMPATHY_GOA_AUTH_HANDLER_H__ +#define __EMPATHY_GOA_AUTH_HANDLER_H__ + +#include <telepathy-glib/telepathy-glib.h> + +G_BEGIN_DECLS + +typedef struct _EmpathyGoaAuthHandler EmpathyGoaAuthHandler; +typedef struct _EmpathyGoaAuthHandlerClass EmpathyGoaAuthHandlerClass; +typedef struct _EmpathyGoaAuthHandlerPriv EmpathyGoaAuthHandlerPriv; + +struct _EmpathyGoaAuthHandlerClass { + GObjectClass parent_class; +}; + +struct _EmpathyGoaAuthHandler { + GObject parent; + EmpathyGoaAuthHandlerPriv *priv; +}; + +GType empathy_goa_auth_handler_get_type (void); + +/* TYPE MACROS */ +#define EMPATHY_TYPE_GOA_AUTH_HANDLER \ + (empathy_goa_auth_handler_get_type ()) +#define EMPATHY_GOA_AUTH_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_GOA_AUTH_HANDLER, \ + EmpathyGoaAuthHandler)) +#define EMPATHY_GOA_AUTH_HANDLER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_GOA_AUTH_HANDLER, \ + EmpathyGoaAuthHandlerClass)) +#define EMPATHY_IS_GOA_AUTH_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), EMPATHY_TYPE_GOA_AUTH_HANDLER)) +#define EMPATHY_IS_GOA_AUTH_HANDLER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), EMPATHY_TYPE_GOA_AUTH_HANDLER)) +#define EMPATHY_GOA_AUTH_HANDLER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_GOA_AUTH_HANDLER, \ + EmpathyGoaAuthHandlerClass)) + +EmpathyGoaAuthHandler *empathy_goa_auth_handler_new (void); + +void empathy_goa_auth_handler_start (EmpathyGoaAuthHandler *self, + TpChannel *channel, + TpAccount *account); + +gboolean empathy_goa_auth_handler_supports (EmpathyGoaAuthHandler *self, + TpChannel *channel, + TpAccount *account); + +G_END_DECLS + +#endif /* #ifndef __EMPATHY_GOA_AUTH_HANDLER_H__*/ diff --git a/libempathy/empathy-utils.c b/libempathy/empathy-utils.c index c4c2780ac..83fe4ce7e 100644 --- a/libempathy/empathy-utils.c +++ b/libempathy/empathy-utils.c @@ -1148,3 +1148,18 @@ while_finish: if (can_video_call != NULL) *can_video_call = can_video; } + +gboolean +empathy_sasl_channel_supports_mechanism (TpChannel *channel, + const gchar *mechanism) +{ + GHashTable *props; + const gchar * const *available_mechanisms; + + props = tp_channel_borrow_immutable_properties (channel); + available_mechanisms = tp_asv_get_boxed (props, + TP_PROP_CHANNEL_INTERFACE_SASL_AUTHENTICATION_AVAILABLE_MECHANISMS, + G_TYPE_STRV); + + return tp_strv_contains (available_mechanisms, mechanism); +} diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h index 4983c89a6..f8d47ec8a 100644 --- a/libempathy/empathy-utils.h +++ b/libempathy/empathy-utils.h @@ -118,6 +118,9 @@ void empathy_individual_can_audio_video_call (FolksIndividual *individual, gboolean *can_video_call, EmpathyContact **out_contact); +gboolean empathy_sasl_channel_supports_mechanism (TpChannel *channel, + const gchar *mechanism); + /* Copied from wocky/wocky-utils.h */ #define empathy_implement_finish_void(source, tag) \ |