diff options
Diffstat (limited to 'libempathy/empathy-account-settings.c')
-rw-r--r-- | libempathy/empathy-account-settings.c | 261 |
1 files changed, 238 insertions, 23 deletions
diff --git a/libempathy/empathy-account-settings.c b/libempathy/empathy-account-settings.c index e5191a96c..fe08f52c0 100644 --- a/libempathy/empathy-account-settings.c +++ b/libempathy/empathy-account-settings.c @@ -29,6 +29,7 @@ #include "empathy-account-settings.h" #include "empathy-connection-managers.h" +#include "empathy-keyring.h" #include "empathy-utils.h" #include "empathy-idle.h" @@ -49,6 +50,13 @@ enum { PROP_READY }; +enum { + PASSWORD_RETRIEVED = 1, + LAST_SIGNAL +}; + +static gulong signals[LAST_SIGNAL] = { 0, }; + /* private structure */ typedef struct _EmpathyAccountSettingsPriv EmpathyAccountSettingsPriv; @@ -59,6 +67,7 @@ struct _EmpathyAccountSettingsPriv TpAccountManager *account_manager; TpConnectionManager *manager; + TpProtocol *protocol_obj; TpAccount *account; gchar *cm_name; @@ -69,6 +78,15 @@ struct _EmpathyAccountSettingsPriv gboolean display_name_overridden; gboolean ready; + gboolean supports_sasl; + gboolean password_changed; + + gchar *password; + gchar *password_original; + + gboolean password_retrieved; + gboolean password_requested; + /* Parameter name (gchar *) -> parameter value (GValue) */ GHashTable *parameters; /* Keys are parameter names from the hash above (gchar *). @@ -80,6 +98,7 @@ struct _EmpathyAccountSettingsPriv GList *required_params; gulong managers_ready_id; + gboolean preparing_protocol; GSimpleAsyncResult *apply_result; }; @@ -226,8 +245,12 @@ empathy_account_settings_constructed (GObject *object) TP_ACCOUNT_FEATURE_STORAGE, 0 }; - tp_proxy_prepare_async (priv->account, features, - empathy_account_settings_account_ready_cb, self); + if (priv->account != NULL) + { + tp_proxy_prepare_async (priv->account, features, + empathy_account_settings_account_ready_cb, self); + } + tp_g_signal_connect_object (priv->managers, "notify::ready", G_CALLBACK (empathy_account_settings_managers_ready_cb), object, 0); } @@ -303,6 +326,13 @@ empathy_account_settings_class_init ( "Whether this account is ready to be used", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); + + signals[PASSWORD_RETRIEVED] = + g_signal_new ("password-retrieved", + G_TYPE_FROM_CLASS (empathy_account_settings_class), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void @@ -320,21 +350,11 @@ empathy_account_settings_dispose (GObject *object) g_signal_handler_disconnect (priv->managers, priv->managers_ready_id); priv->managers_ready_id = 0; - if (priv->managers != NULL) - g_object_unref (priv->managers); - priv->managers = NULL; - - if (priv->manager != NULL) - g_object_unref (priv->manager); - priv->manager = NULL; - - if (priv->account_manager != NULL) - g_object_unref (priv->account_manager); - priv->account_manager = NULL; - - if (priv->account != NULL) - g_object_unref (priv->account); - priv->account = NULL; + tp_clear_object (&priv->managers); + tp_clear_object (&priv->manager); + tp_clear_object (&priv->account_manager); + tp_clear_object (&priv->account); + tp_clear_object (&priv->protocol_obj); /* release any references held by the object here */ if (G_OBJECT_CLASS (empathy_account_settings_parent_class)->dispose) @@ -367,6 +387,8 @@ empathy_account_settings_finalize (GObject *object) g_free (priv->service); g_free (priv->display_name); g_free (priv->icon_name); + g_free (priv->password); + g_free (priv->password_original); if (priv->required_params != NULL) { @@ -385,10 +407,60 @@ empathy_account_settings_finalize (GObject *object) } static void +empathy_account_settings_protocol_obj_prepared_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + EmpathyAccountSettings *self = user_data; + GError *error = NULL; + + if (!tp_proxy_prepare_finish (source, result, &error)) + { + DEBUG ("Failed to prepare protocol object: %s", error->message); + g_clear_error (&error); + return; + } + + empathy_account_settings_check_readyness (self); +} + +static void +empathy_account_settings_get_password_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + EmpathyAccountSettings *self = user_data; + EmpathyAccountSettingsPriv *priv = GET_PRIV (self); + const gchar *password; + GError *error = NULL; + + password = empathy_keyring_get_password_finish (TP_ACCOUNT (source), + result, &error); + + if (error != NULL) + { + DEBUG ("Failed to get password: %s", error->message); + g_clear_error (&error); + } + + /* It doesn't really matter if getting the password failed; that + * just means that it's not there, or let's act like that at + * least. */ + + g_assert (priv->password == NULL); + + priv->password = g_strdup (password); + priv->password_original = g_strdup (password); + + g_signal_emit (self, signals[PASSWORD_RETRIEVED], 0); +} + +static void empathy_account_settings_check_readyness (EmpathyAccountSettings *self) { EmpathyAccountSettingsPriv *priv = GET_PRIV (self); const TpConnectionManagerProtocol *tp_protocol; + GQuark features[] = { TP_PROTOCOL_FEATURE_CORE, 0 }; if (priv->ready) return; @@ -400,12 +472,17 @@ empathy_account_settings_check_readyness (EmpathyAccountSettings *self) if (!empathy_connection_managers_is_ready (priv->managers)) return; - priv->manager = empathy_connection_managers_get_cm ( - priv->managers, priv->cm_name); + if (priv->manager == NULL) + { + priv->manager = empathy_connection_managers_get_cm ( + priv->managers, priv->cm_name); + } if (priv->manager == NULL) return; + g_object_ref (priv->manager); + if (priv->account != NULL) { g_free (priv->display_name); @@ -440,7 +517,43 @@ empathy_account_settings_check_readyness (EmpathyAccountSettings *self) } } - g_object_ref (priv->manager); + if (priv->protocol_obj == NULL) + { + priv->protocol_obj = g_object_ref ( + tp_connection_manager_get_protocol_object (priv->manager, + priv->protocol)); + } + + if (!tp_proxy_is_prepared (priv->protocol_obj, TP_PROTOCOL_FEATURE_CORE) + && !priv->preparing_protocol) + { + priv->preparing_protocol = TRUE; + tp_proxy_prepare_async (priv->protocol_obj, features, + empathy_account_settings_protocol_obj_prepared_cb, self); + return; + } + else + { + if (tp_strv_contains (tp_protocol_get_authentication_types ( + priv->protocol_obj), + TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION)) + { + priv->supports_sasl = TRUE; + } + } + + /* priv->account won't be a proper account if it's the account + * assistant showing this widget. */ + if (priv->supports_sasl && !priv->password_requested + && priv->account != NULL) + { + priv->password_requested = TRUE; + + /* Make this call but don't block on its readiness. We'll signal + * if it's updated later with ::password-retrieved. */ + empathy_keyring_get_password_async (priv->account, + empathy_account_settings_get_password_cb, self); + } priv->ready = TRUE; g_object_notify (G_OBJECT (self), "ready"); @@ -701,6 +814,14 @@ empathy_account_settings_unset (EmpathyAccountSettings *settings, if (empathy_account_settings_is_unset (settings, param)) return; + if (priv->supports_sasl && !tp_strdiff (param, "password")) + { + g_free (priv->password); + priv->password = NULL; + priv->password_changed = TRUE; + return; + } + v = g_strdup (param); g_array_append_val (priv->unset_parameters, v); @@ -714,14 +835,24 @@ empathy_account_settings_discard_changes (EmpathyAccountSettings *settings) g_hash_table_remove_all (priv->parameters); empathy_account_settings_free_unset_parameters (settings); + + priv->password_changed = FALSE; + g_free (priv->password); + priv->password = g_strdup (priv->password_original); } const gchar * empathy_account_settings_get_string (EmpathyAccountSettings *settings, const gchar *param) { + EmpathyAccountSettingsPriv *priv = GET_PRIV (settings); const GValue *v; + if (!tp_strdiff (param, "password") && priv->supports_sasl) + { + return priv->password; + } + v = empathy_account_settings_get (settings, param); if (v == NULL || !G_VALUE_HOLDS_STRING (v)) @@ -916,7 +1047,16 @@ empathy_account_settings_set_string (EmpathyAccountSettings *settings, g_return_if_fail (param != NULL); g_return_if_fail (value != NULL); - tp_asv_set_string (priv->parameters, g_strdup (param), value); + if (!tp_strdiff (param, "password") && priv->supports_sasl) + { + g_free (priv->password); + priv->password = g_strdup (value); + priv->password_changed = TRUE; + } + else + { + tp_asv_set_string (priv->parameters, g_strdup (param), value); + } account_settings_remove_from_unset (settings, param); } @@ -1152,6 +1292,55 @@ empathy_account_settings_set_icon_name_finish ( } static void +empathy_account_settings_processed_password (GObject *source, + GAsyncResult *result, + gpointer user_data, + gpointer finish_func) +{ + EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data); + EmpathyAccountSettingsPriv *priv = GET_PRIV (settings); + GSimpleAsyncResult *r; + GError *error = NULL; + gboolean (*func) (TpAccount *source, GAsyncResult *result, GError **error) = + finish_func; + + g_free (priv->password_original); + priv->password_original = g_strdup (priv->password); + + if (!func (TP_ACCOUNT (source), result, &error)) + { + g_simple_async_result_set_from_error (priv->apply_result, error); + g_error_free (error); + } + + empathy_account_settings_discard_changes (settings); + + r = priv->apply_result; + priv->apply_result = NULL; + + g_simple_async_result_complete (r); + g_object_unref (r); +} + +static void +empathy_account_settings_set_password_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + empathy_account_settings_processed_password (source, result, user_data, + empathy_keyring_set_password_finish); +} + +static void +empathy_account_settings_delete_password_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + empathy_account_settings_processed_password (source, result, user_data, + empathy_keyring_delete_password_finish); +} + +static void empathy_account_settings_account_updated (GObject *source, GAsyncResult *result, gpointer user_data) @@ -1166,12 +1355,30 @@ empathy_account_settings_account_updated (GObject *source, { g_simple_async_result_set_from_error (priv->apply_result, error); g_error_free (error); + goto out; } - else + + /* Only set the password in the keyring if the CM supports SASL and + * it's changed. */ + if (priv->supports_sasl && priv->password_changed) { - empathy_account_settings_discard_changes (settings); + if (priv->password != NULL) + { + empathy_keyring_set_password_async (priv->account, priv->password, + empathy_account_settings_set_password_cb, settings); + } + else + { + empathy_keyring_delete_password_async (priv->account, + empathy_account_settings_delete_password_cb, settings); + } + + return; } +out: + empathy_account_settings_discard_changes (settings); + r = priv->apply_result; priv->apply_result = NULL; @@ -1451,3 +1658,11 @@ empathy_account_settings_get_tp_protocol (EmpathyAccountSettings *self) return tp_connection_manager_get_protocol (priv->manager, priv->protocol); } + +gboolean +empathy_account_settings_supports_sasl (EmpathyAccountSettings *self) +{ + EmpathyAccountSettingsPriv *priv = GET_PRIV (self); + + return priv->supports_sasl; +} |