summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Thompson <will.thompson@collabora.co.uk>2012-11-14 16:43:46 +0000
committerWill Thompson <will.thompson@collabora.co.uk>2012-11-14 17:10:54 +0000
commit39ee2f08cf4e2d46aae86307f6dfa023fe347248 (patch)
treefef2e4d2a0f40fed89c9eb619f5fd3e28c88a51e
parentf51c7b9cd378a561a9926d0860c26b7581dd4dc0 (diff)
muc-channel: implement Destroy(), make Close() respawn
This fixes the issue where empathy-chat crashing means you get kicked out of all your channels. It's technically backwards-incompatible but empathy-chat has been using RemoveMembers() to leave rooms for ages, and it's a pretty destructive and annoying bug, so let's just get on with it. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=24614
-rw-r--r--src/idle-muc-channel.c39
-rw-r--r--src/idle-muc-manager.c14
-rw-r--r--tests/twisted/Makefile.am1
-rw-r--r--tests/twisted/channels/muc-destroy.py32
-rw-r--r--tests/twisted/channels/requests-muc.py29
5 files changed, 111 insertions, 4 deletions
diff --git a/src/idle-muc-channel.c b/src/idle-muc-channel.c
index d1c3e66..b6b6fb4 100644
--- a/src/idle-muc-channel.c
+++ b/src/idle-muc-channel.c
@@ -46,6 +46,7 @@
static void _password_iface_init(gpointer, gpointer);
static void subject_iface_init(gpointer, gpointer);
+static void destroyable_iface_init(gpointer, gpointer);
static void idle_muc_channel_send (GObject *obj, TpMessage *message, TpMessageSendingFlags flags);
static void idle_muc_channel_close (TpBaseChannel *base);
@@ -59,6 +60,7 @@ G_DEFINE_TYPE_WITH_CODE(IdleMUCChannel, idle_muc_channel, TP_TYPE_BASE_CHANNEL,
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_SUBJECT, subject_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_ROOM_CONFIG,
tp_base_room_config_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE, destroyable_iface_init);
)
/* property enum */
@@ -131,6 +133,7 @@ static const gchar *muc_channel_interfaces[] = {
TP_IFACE_CHANNEL_INTERFACE_ROOM,
TP_IFACE_CHANNEL_INTERFACE_SUBJECT,
TP_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG,
+ TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE,
NULL
};
@@ -1339,12 +1342,35 @@ idle_muc_channel_close (
IDLE_DEBUG ("called on %p", self);
+ if (priv->state == MUC_STATE_JOINED) {
+ tp_message_mixin_set_rescued (G_OBJECT (self));
+ tp_base_channel_reopened (base, 0);
+ } else {
+ /* FIXME: this is wrong if called while JOIN is in flight. */
+ tp_base_channel_destroyed (base);
+ }
+}
+
+
+static void
+idle_muc_channel_destroy (
+ TpSvcChannelInterfaceDestroyable *object,
+ DBusGMethodInvocation *context)
+{
+ TpBaseChannel *base = TP_BASE_CHANNEL (object);
+ IdleMUCChannel *self = IDLE_MUC_CHANNEL (object);
+ IdleMUCChannelPrivate *priv = self->priv;
+
+ IDLE_DEBUG ("called on %p", self);
+
if (priv->state == MUC_STATE_JOINED)
part_from_channel (self, NULL);
/* FIXME: this is wrong if called while JOIN is in flight. */
if (priv->state < MUC_STATE_JOINED)
tp_base_channel_destroyed (base);
+
+ tp_svc_channel_interface_destroyable_return_from_destroy (context);
}
/**
@@ -1537,3 +1563,16 @@ subject_iface_init (
IMPLEMENT (set_subject);
#undef IMPLEMENT
}
+
+static void
+destroyable_iface_init (
+ gpointer g_iface,
+ gpointer iface_data G_GNUC_UNUSED)
+{
+ TpSvcChannelInterfaceDestroyableClass *klass = g_iface;
+
+#define IMPLEMENT(x) \
+ tp_svc_channel_interface_destroyable_implement_##x (klass, idle_muc_channel_##x)
+ IMPLEMENT (destroy);
+#undef IMPLEMENT
+}
diff --git a/src/idle-muc-manager.c b/src/idle-muc-manager.c
index 5cba4d7..faf66e9 100644
--- a/src/idle-muc-manager.c
+++ b/src/idle-muc-manager.c
@@ -676,6 +676,7 @@ static GSList *take_request_tokens(IdleMUCManager *manager, IdleMUCChannel *chan
static void _channel_closed_cb(IdleMUCChannel *chan, gpointer user_data) {
IdleMUCManager *manager = IDLE_MUC_MANAGER(user_data);
IdleMUCManagerPrivate *priv = IDLE_MUC_MANAGER_GET_PRIVATE(manager);
+ TpBaseChannel *base = TP_BASE_CHANNEL (chan);
GSList *reqs = take_request_tokens(user_data, chan);
/* If there are any tokens for this channel when it closes, the request
@@ -689,10 +690,17 @@ static void _channel_closed_cb(IdleMUCChannel *chan, gpointer user_data) {
g_slist_free(reqs);
+ tp_channel_manager_emit_channel_closed_for_object (manager,
+ TP_EXPORTABLE_CHANNEL (chan));
+
if (priv->channels) {
- TpHandle handle;
- g_object_get(chan, "handle", &handle, NULL);
- g_hash_table_remove(priv->channels, GUINT_TO_POINTER(handle));
+ TpHandle handle = tp_base_channel_get_target_handle (base);
+
+ if (tp_base_channel_is_destroyed (base))
+ g_hash_table_remove(priv->channels, GUINT_TO_POINTER(handle));
+ else
+ tp_channel_manager_emit_new_channel (manager, TP_EXPORTABLE_CHANNEL (chan),
+ NULL);
}
}
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index 185ffec..8329514 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -16,6 +16,7 @@ TWISTED_TESTS = \
channels/requests-create.py \
channels/requests-muc.py \
channels/muc-channel-topic.py \
+ channels/muc-destroy.py \
channels/room-list-channel.py \
channels/room-list-multiple.py \
messages/accept-invalid-nicks.py \
diff --git a/tests/twisted/channels/muc-destroy.py b/tests/twisted/channels/muc-destroy.py
new file mode 100644
index 0000000..3513098
--- /dev/null
+++ b/tests/twisted/channels/muc-destroy.py
@@ -0,0 +1,32 @@
+"""
+Tests Destroy()ing a MUC.
+"""
+
+from servicetest import call_async, wrap_channel, EventPattern
+from idletest import exec_test
+import constants as cs
+
+def test(q, bus, conn, stream):
+ conn.Connect()
+ q.expect('dbus-signal', signal='StatusChanged',
+ args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
+
+ call_async(q, conn.Requests, "CreateChannel", {
+ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
+ cs.ROOM_NAME: "#everythingyoutouch",
+ })
+ q.expect('stream-JOIN')
+ event = q.expect('dbus-return', method='CreateChannel')
+ path, props = event.value
+ chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
+ ['Destroyable'])
+
+ call_async(q, chan.Destroyable, "Destroy")
+ q.expect_many(
+ EventPattern('stream-PART'),
+ EventPattern('dbus-signal', signal='Closed', path=path),
+ EventPattern('dbus-return', method='Destroy'),
+ )
+
+if __name__ == '__main__':
+ exec_test(test)
diff --git a/tests/twisted/channels/requests-muc.py b/tests/twisted/channels/requests-muc.py
index 8d37526..27de685 100644
--- a/tests/twisted/channels/requests-muc.py
+++ b/tests/twisted/channels/requests-muc.py
@@ -3,7 +3,7 @@ Test connecting to a IRC channel via the Requests interface
"""
import functools
-from idletest import exec_test, BaseIRCServer
+from idletest import exec_test, BaseIRCServer, sync_stream
from servicetest import (
EventPattern, call_async, sync_dbus, make_channel_proxy, assertEquals,
assertSameSets, assertContains,
@@ -89,6 +89,7 @@ def test(q, bus, conn, stream, use_room=False):
cs.CHANNEL_IFACE_ROOM,
cs.CHANNEL_IFACE_SUBJECT,
cs.CHANNEL_IFACE_ROOM_CONFIG,
+ cs.CHANNEL_IFACE_DESTROYABLE,
], props[cs.INTERFACES])
assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
assert props[cs.TARGET_ID] == '#idletest'
@@ -123,6 +124,32 @@ def test(q, bus, conn, stream, use_room=False):
assert chans[0] == (path, props)
chan = make_channel_proxy(conn, path, 'Channel')
+
+ # Make sure Close()ing the channel makes it respawn. This avoids the old
+ # bug where empathy-chat crashing booted you out of all your channels.
+ patterns = [EventPattern('stream-PART')]
+ q.forbid_events(patterns)
+ chan.Close()
+ q.expect('dbus-signal', signal='Closed', path=chan.object_path)
+ e = q.expect('dbus-signal', signal='NewChannels')
+
+ path, props = e.args[0][0]
+ assertEquals(chan.object_path, path)
+ # We requested the channel originally, but we didn't request it popping
+ # back up.
+ assertEquals(0, props[cs.INITIATOR_HANDLE])
+ assert not props[cs.REQUESTED]
+
+ # Check that ensuring a respawned channel does what you'd expect.
+ ec_yours, ec_path, ec_props = conn.EnsureChannel(request,
+ dbus_interface=cs.CONN_IFACE_REQUESTS)
+ assert not ec_yours
+ assertEquals(chan.object_path, ec_path)
+ assertEquals(props, ec_props)
+
+ sync_stream(q, stream)
+ q.unforbid_events(patterns)
+
chan.RemoveMembers([self_handle], "bye bye cruel\r\nworld",
dbus_interface=cs.CHANNEL_IFACE_GROUP)