[telepathy-haze/master] Don't assume purple_account_new returns a new account.

Will Thompson will.thompson at collabora.co.uk
Wed Mar 25 17:42:43 PDT 2009


If an existing account for a given (prpl, username) exists, it's
returned by purple_account_new (). If you called RequestConnection
for an already-connected account Haze would trample over that account's
ui_data before tp-glib failed RequestConnection (due to the connection
unique name being the same), and then it would point to freed memory and
crash Haze.

Fixes fd.o #18361
---
 src/connection-manager.c |    6 ++++++
 src/connection.c         |   38 +++++++++++++++++++++++++++++---------
 src/connection.h         |    2 ++
 3 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/src/connection-manager.c b/src/connection-manager.c
index 7818a8a..54fcbe3 100644
--- a/src/connection-manager.c
+++ b/src/connection-manager.c
@@ -440,6 +440,12 @@ _haze_connection_manager_new_connection (TpBaseConnectionManager *base,
                                          "parameters",      params,
                                          NULL);
 
+    if (!haze_connection_create_account (conn, error))
+      {
+        g_object_unref (conn);
+        return FALSE;
+      }
+
     cm->connections = g_list_prepend(cm->connections, conn);
     g_signal_connect (conn, "shutdown-finished",
                       G_CALLBACK (connection_shutdown_finished_cb),
diff --git a/src/connection.c b/src/connection.c
index f4dd7bb..069cf8e 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -289,23 +289,42 @@ _set_option (const PurpleAccountOption *option,
     g_hash_table_remove (context->params, option->pref_name);
 }
 
-static void
-_create_account (HazeConnection *self)
+/**
+ * haze_connection_create_account:
+ *
+ * Attempts to create a PurpleAccount corresponding to this connection. Must be
+ * called immediately after constructing a connection. It's a shame GObject
+ * constructors can't fail.
+ *
+ * Returns: %TRUE if the account was successfully created and hooked up;
+ *          %FALSE with @error set in the TP_ERRORS domain if the account
+ *          already existed or another error occurred.
+ */
+gboolean
+haze_connection_create_account (HazeConnection *self,
+                                GError **error)
 {
     HazeConnectionPrivate *priv = HAZE_CONNECTION_GET_PRIVATE(self);
     GHashTable *params = priv->parameters;
     PurplePluginProtocolInfo *prpl_info = priv->protocol_info->prpl_info;
-
+    const gchar *prpl_id = priv->protocol_info->prpl_id;
     const gchar *username, *password;
     struct _i_want_closure context;
 
+    g_return_val_if_fail (self->account == NULL, FALSE);
+
     username = _get_param_string (params, "account");
-    g_assert (username);
+    g_assert (username != NULL);
+
+    if (purple_accounts_find (username, prpl_id) != NULL)
+      {
+        g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+            "a connection already exists to %s on %s", username, prpl_id);
+        return FALSE;
+      }
 
-    g_assert (self->account == NULL);
     self->account = purple_account_new (username, priv->protocol_info->prpl_id);
     purple_accounts_add (self->account);
-    g_assert (self->account);
     g_hash_table_remove (params, "account");
 
     self->account->ui_data = self;
@@ -322,6 +341,8 @@ _create_account (HazeConnection *self)
     g_list_foreach (prpl_info->protocol_options, (GFunc) _set_option, &context);
 
     g_hash_table_foreach (params, (GHFunc) _warn_unhandled_parameter, "lala");
+
+    return TRUE;
 }
 
 static gboolean
@@ -329,10 +350,11 @@ _haze_connection_start_connecting (TpBaseConnection *base,
                                    GError **error)
 {
     HazeConnection *self = HAZE_CONNECTION(base);
-
     TpHandleRepoIface *contact_handles =
         tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT);
 
+    g_return_val_if_fail (self->account != NULL, FALSE);
+
     base->self_handle = tp_handle_ensure (contact_handles,
         purple_account_get_username (self->account), NULL, error);
     if (!base->self_handle)
@@ -486,8 +508,6 @@ haze_connection_constructor (GType type,
 
     priv->disconnecting = FALSE;
 
-    _create_account (self);
-
     tp_contacts_mixin_init (object,
         G_STRUCT_OFFSET (HazeConnection, contacts));
     tp_base_connection_register_with_contacts_mixin (
diff --git a/src/connection.h b/src/connection.h
index dda734b..8d9a1ef 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -86,6 +86,8 @@ haze_connection_handle_inspect (HazeConnection *conn,
                                 TpHandleType handle_type,
                                 TpHandle handle);
 
+gboolean haze_connection_create_account (HazeConnection *self, GError **error);
+
 GType haze_connection_get_type (void);
 
 /* TYPE MACROS */
-- 
1.5.6.5




More information about the telepathy-commits mailing list