[telepathy-idle/master] Don't emit NewChannels twice when joining
Will Thompson
will.thompson at collabora.co.uk
Thu Sep 10 16:07:40 PDT 2009
Before, as soon as you created the channel CreateChannel would return,
and NewChannels would be emitted; later, when you finish joining the
channel, it'd be emitted again. This patch restores the
currently-considered-correct behaviour whereby the new channel is only
announced when you've finished joining it (successfully or not).
---
src/idle-muc-manager.c | 82 +++++++++++++++++++---------
tests/twisted/channels/join-muc-channel.py | 1 +
2 files changed, 58 insertions(+), 25 deletions(-)
diff --git a/src/idle-muc-manager.c b/src/idle-muc-manager.c
index b73a49a..26375a3 100644
--- a/src/idle-muc-manager.c
+++ b/src/idle-muc-manager.c
@@ -50,6 +50,11 @@ typedef struct _IdleMUCManagerPrivate IdleMUCManagerPrivate;
struct _IdleMUCManagerPrivate {
IdleConnection *conn;
GHashTable *channels;
+
+ /* Map from IdleMUCChannel * (borrowed from channels) to a GSList * of
+ * request tokens. */
+ GHashTable *queued_requests;
+
gulong status_changed_id;
gboolean dispose_has_run;
};
@@ -84,7 +89,7 @@ static gboolean _muc_manager_request_channel (TpChannelManager *manager, gpointe
static gboolean _muc_manager_ensure_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties);
static gboolean _muc_manager_request (IdleMUCManager *self, gpointer request_token, GHashTable *request_properties, gboolean require_new);
-static IdleMUCChannel *_muc_manager_new_channel(IdleMUCManager *manager, TpHandle handle, gpointer request_token);
+static IdleMUCChannel *_muc_manager_new_channel(IdleMUCManager *manager, TpHandle handle);
static void _channel_closed_cb(IdleMUCChannel *chan, gpointer user_data);
static void _channel_join_ready_cb(IdleMUCChannel *chan, guint err, gpointer user_data);
@@ -126,6 +131,7 @@ static void idle_muc_manager_init(IdleMUCManager *obj) {
IdleMUCManagerPrivate *priv = IDLE_MUC_MANAGER_GET_PRIVATE(obj);
priv->channels = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
+ priv->queued_requests = g_hash_table_new(NULL, NULL);
}
static void idle_muc_manager_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
@@ -270,7 +276,7 @@ static IdleParserHandlerResult _invite_handler(IdleParser *parser, IdleParserMes
idle_connection_emit_queued_aliases_changed(priv->conn);
if (!chan) {
- chan = _muc_manager_new_channel(manager, room_handle, NULL);
+ chan = _muc_manager_new_channel(manager, room_handle);
tp_channel_manager_emit_new_channel(TP_CHANNEL_MANAGER(user_data), (TpExportableChannel *) chan, NULL);
idle_muc_channel_invited(chan, inviter_handle);
}
@@ -294,8 +300,8 @@ static IdleParserHandlerResult _join_handler(IdleParser *parser, IdleParserMessa
IdleMUCChannel *chan = g_hash_table_lookup(priv->channels, GUINT_TO_POINTER(room_handle));
if (!chan) {
- /* XXX: emit request_already_satisified? use request_channel API? */
- chan = _muc_manager_new_channel(manager, room_handle, NULL);
+ chan = _muc_manager_new_channel(manager, room_handle);
+ tp_channel_manager_emit_new_channel(TP_CHANNEL_MANAGER(user_data), (TpExportableChannel *) chan, NULL);
}
idle_muc_channel_join(chan, joiner_handle);
@@ -619,12 +625,14 @@ _muc_manager_foreach_channel_class (TpChannelManager *manager,
}
-static IdleMUCChannel *_muc_manager_new_channel(IdleMUCManager *manager, TpHandle handle, gpointer request_token)
+static IdleMUCChannel *_muc_manager_new_channel(IdleMUCManager *manager, TpHandle handle)
{
IdleMUCManagerPrivate *priv = IDLE_MUC_MANAGER_GET_PRIVATE(manager);
IdleMUCChannel *chan;
gchar *object_path;
+ g_assert(g_hash_table_lookup(priv->channels, GUINT_TO_POINTER(handle)) == NULL);
+
object_path = g_strdup_printf("%s/MucChannel%u", priv->conn->parent.object_path, handle);
chan = g_object_new(IDLE_TYPE_MUC_CHANNEL, "connection", priv->conn, "object-path", object_path, "handle", handle, NULL);
@@ -635,20 +643,41 @@ static IdleMUCChannel *_muc_manager_new_channel(IdleMUCManager *manager, TpHandl
g_free(object_path);
- GSList* tokens = NULL;
- if (request_token != NULL)
- tokens = g_slist_prepend (tokens, request_token);
+ return chan;
+}
+
+static void associate_request(IdleMUCManager *manager, IdleMUCChannel *chan, gpointer request) {
+ IdleMUCManagerPrivate *priv = IDLE_MUC_MANAGER_GET_PRIVATE(manager);
+ GSList *reqs = g_hash_table_lookup(priv->queued_requests, chan);
+
+ g_hash_table_steal(priv->queued_requests, chan);
+ g_hash_table_insert(priv->queued_requests, chan, g_slist_prepend(reqs, request));
+}
- tp_channel_manager_emit_new_channel (manager, TP_EXPORTABLE_CHANNEL (chan),
- tokens);
+static GSList *take_request_tokens(IdleMUCManager *manager, IdleMUCChannel *chan) {
+ IdleMUCManagerPrivate *priv = IDLE_MUC_MANAGER_GET_PRIVATE(manager);
+ GSList *reqs = g_hash_table_lookup(priv->queued_requests, chan);
- g_slist_free (tokens);
+ g_hash_table_steal(priv->queued_requests, chan);
- return chan;
+ return g_slist_reverse(reqs);
}
static void _channel_closed_cb(IdleMUCChannel *chan, gpointer user_data) {
- IdleMUCManagerPrivate *priv = IDLE_MUC_MANAGER_GET_PRIVATE(user_data);
+ IdleMUCManager *manager = IDLE_MUC_MANAGER(user_data);
+ IdleMUCManagerPrivate *priv = IDLE_MUC_MANAGER_GET_PRIVATE(manager);
+ GSList *reqs = take_request_tokens(user_data, chan);
+
+ /* If there are any tokens for this channel when it closes, the request
+ * didn't finish before we killed the channel.
+ */
+ for (GSList *l = reqs; l != NULL; l = l->next) {
+ tp_channel_manager_emit_request_failed(manager, l->data, TP_ERRORS,
+ TP_ERROR_DISCONNECTED,
+ "Unable to complete this channel request, we're disconnecting!");
+ }
+
+ g_slist_free(reqs);
if (priv->channels) {
TpHandle handle;
@@ -660,10 +689,11 @@ static void _channel_closed_cb(IdleMUCChannel *chan, gpointer user_data) {
static void _channel_join_ready_cb(IdleMUCChannel *chan, guint err, gpointer user_data) {
TpChannelManager *manager = TP_CHANNEL_MANAGER(user_data);
IdleMUCManagerPrivate *priv = IDLE_MUC_MANAGER_GET_PRIVATE(user_data);
+ GSList *reqs = take_request_tokens(user_data, chan);
if (err == MUC_CHANNEL_JOIN_ERROR_NONE) {
- tp_channel_manager_emit_new_channel(manager, (TpExportableChannel *) chan, NULL);
- return;
+ tp_channel_manager_emit_new_channel(manager, (TpExportableChannel *) chan, reqs);
+ goto out;
}
gint err_code = 0;
@@ -693,15 +723,15 @@ static void _channel_join_ready_cb(IdleMUCChannel *chan, guint err, gpointer use
break;
}
- /* XXX: old: tp_channel_factory_iface_emit_channel_error(). is this a
- * suitable replacement?
- * FIXME: eventually we need to hook up the request_token so that this error
- * is associated with the proper request
- */
- tp_channel_manager_emit_request_failed(manager, NULL, TP_ERRORS, err_code, err_msg);
+ for (GSList *l = reqs; reqs != NULL; reqs = reqs->next) {
+ tp_channel_manager_emit_request_failed(manager, l->data, TP_ERRORS, err_code, err_msg);
+ }
if (priv->channels)
g_hash_table_remove(priv->channels, GUINT_TO_POINTER(handle));
+
+out:
+ g_slist_free (reqs);
}
@@ -786,19 +816,21 @@ _muc_manager_request (IdleMUCManager *self,
"That channel has already been created (or requested)");
goto error;
}
- else
+ else if (idle_muc_channel_is_ready (channel))
{
tp_channel_manager_emit_request_already_satisfied (self,
request_token,
TP_EXPORTABLE_CHANNEL (channel));
+ return TRUE;
}
}
else
{
- channel = _muc_manager_new_channel (self, handle,
- request_token);
+ channel = _muc_manager_new_channel (self, handle);
+ idle_muc_channel_join_attempt(channel);
}
- idle_muc_channel_join_attempt(channel);
+
+ associate_request(self, channel, request_token);
return TRUE;
}
diff --git a/tests/twisted/channels/join-muc-channel.py b/tests/twisted/channels/join-muc-channel.py
index 0643bac..0ad6417 100644
--- a/tests/twisted/channels/join-muc-channel.py
+++ b/tests/twisted/channels/join-muc-channel.py
@@ -18,6 +18,7 @@ def test(q, bus, conn, stream):
q.expect('dbus-signal', signal='StatusChanged', args=[0, 1])
room_handles = conn.RequestHandles(HT_ROOM, ['#idletest'])
call_async(q, conn, 'RequestChannel', CHANNEL_TYPE_TEXT, HT_ROOM, room_handles[0], True)
+ q.expect('stream-JOIN')
event = q.expect('dbus-return', method='RequestChannel')
obj_path = event.value[0]
--
1.5.6.5
More information about the telepathy-commits
mailing list