From 39ee2f08cf4e2d46aae86307f6dfa023fe347248 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Wed, 14 Nov 2012 16:43:46 +0000 Subject: 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 --- src/idle-muc-channel.c | 39 +++++++++++++++++++++++++++++++++++++++ src/idle-muc-manager.c | 14 +++++++++++--- 2 files changed, 50 insertions(+), 3 deletions(-) (limited to 'src') 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); } } -- cgit v1.2.1