From 05561dd677b4098d1a618bcc3e01fc77c5ce19de Mon Sep 17 00:00:00 2001 From: fiaxh Date: Sun, 17 Nov 2019 17:53:46 +0100 Subject: [PATCH] Parse presence delivery errors when joining MUC fixes #224 --- libdino/src/service/muc_manager.vala | 11 ++-- .../add_conference_dialog.vala | 8 +-- .../conference_details_fragment.vala | 58 +++++++++++-------- main/src/ui/application.vala | 1 - xmpp-vala/src/module/xep/0045_muc/flag.vala | 1 + xmpp-vala/src/module/xep/0045_muc/module.vala | 26 ++++++++- 6 files changed, 66 insertions(+), 39 deletions(-) diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala index 2c4512e6..fa76ddd5 100644 --- a/libdino/src/service/muc_manager.vala +++ b/libdino/src/service/muc_manager.vala @@ -1,6 +1,7 @@ using Gee; using Xmpp; +using Xmpp.Xep; using Dino.Entities; namespace Dino { @@ -36,9 +37,9 @@ public class MucManager : StreamInteractionModule, Object { stream_interactor.get_module(MessageProcessor.IDENTITY).received_pipeline.connect(received_message_listener); } - public void join(Account account, Jid jid, string? nick, string? password) { + public async Muc.JoinResult? join(Account account, Jid jid, string? nick, string? password) { XmppStream? stream = stream_interactor.get_stream(account); - if (stream == null) return; + if (stream == null) return null; string nick_ = nick ?? account.bare_jid.localpart ?? account.bare_jid.domainpart; DateTime? history_since = null; @@ -48,7 +49,7 @@ public class MucManager : StreamInteractionModule, Object { if (last_message != null) history_since = last_message.time; } - stream.get_module(Xep.Muc.Module.IDENTITY).enter(stream, jid.bare_jid, nick_, password, history_since); + return yield stream.get_module(Xep.Muc.Module.IDENTITY).enter(stream, jid.bare_jid, nick_, password, history_since); } public void part(Account account, Jid jid) { @@ -323,7 +324,7 @@ public class MucManager : StreamInteractionModule, Object { Gee.List conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(account); foreach (Conversation conversation in conversations) { if (conversation.type_ == Conversation.Type.GROUPCHAT && conversation.nickname != null) { - join(account, conversation.counterpart, conversation.nickname, null); + join.begin(account, conversation.counterpart, conversation.nickname, null); } } } @@ -345,7 +346,7 @@ public class MucManager : StreamInteractionModule, Object { if (conference.jid.equals(conversation.counterpart)) is_active = true; } if (!is_active || !is_joined(jid, account)) { - join(account, conference.jid, conference.nick, conference.password); + join.begin(account, conference.jid, conference.nick, conference.password); } } else { // Leave if we should leave diff --git a/main/src/ui/add_conversation/add_conference_dialog.vala b/main/src/ui/add_conversation/add_conference_dialog.vala index 12a7b57a..9639eed3 100644 --- a/main/src/ui/add_conversation/add_conference_dialog.vala +++ b/main/src/ui/add_conversation/add_conference_dialog.vala @@ -3,6 +3,7 @@ using Gtk; using Dino.Entities; using Xmpp; +using Xmpp.Xep; namespace Dino.Ui { @@ -49,7 +50,6 @@ public class AddConferenceDialog : Gtk.Dialog { cancel_button.clicked.connect(on_cancel); ok_button.label = _("Next"); ok_button.sensitive = select_fragment.done; - ok_button.clicked.disconnect(on_ok_button_clicked); ok_button.clicked.connect(on_next_button_clicked); details_fragment.notify["done"].disconnect(set_ok_sensitive_from_details); select_fragment.notify["done"].connect(set_ok_sensitive_from_select); @@ -69,7 +69,6 @@ public class AddConferenceDialog : Gtk.Dialog { ok_button.label = _("Join"); ok_button.sensitive = details_fragment.done; ok_button.clicked.disconnect(on_next_button_clicked); - ok_button.clicked.connect(on_ok_button_clicked); select_fragment.notify["done"].disconnect(set_ok_sensitive_from_select); details_fragment.notify["done"].connect(set_ok_sensitive_from_details); } @@ -143,7 +142,6 @@ public class AddConferenceDialog : Gtk.Dialog { Button ok_button = new Button() { label=_("Join"), halign = Align.END, can_focus=true, can_default=true, visible=true }; ok_button.get_style_context().add_class("suggested-action"); - ok_button.clicked.connect(on_ok_button_clicked); details_fragment.notify["done"].connect(() => { ok_button.sensitive = select_fragment.done; }); details_fragment.ok_button = ok_button; @@ -182,10 +180,6 @@ public class AddConferenceDialog : Gtk.Dialog { show_conference_details_view(); } - private void on_ok_button_clicked() { - stream_interactor.get_module(MucManager.IDENTITY).join(details_fragment.account, new Jid(details_fragment.jid), details_fragment.nick, details_fragment.password); - } - private void on_joined(Account account, Jid jid, string nick) { if (account.equals(details_fragment.account) && jid.equals_bare(new Jid(details_fragment.jid))) { Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(jid, account, Conversation.Type.GROUPCHAT); diff --git a/main/src/ui/add_conversation/conference_details_fragment.vala b/main/src/ui/add_conversation/conference_details_fragment.vala index 5d0ebd9b..876f7050 100644 --- a/main/src/ui/add_conversation/conference_details_fragment.vala +++ b/main/src/ui/add_conversation/conference_details_fragment.vala @@ -3,6 +3,7 @@ using Gtk; using Dino.Entities; using Xmpp; +using Xmpp.Xep; namespace Dino.Ui { @@ -86,9 +87,9 @@ protected class ConferenceDetailsFragment : Box { set { if (value != null) { value.clicked.connect(() => { - ok_button.label = _("Joining…"); - ok_button.sensitive = false; + on_ok_button_clicked(); }); + ok_button_ = value; } } @@ -96,7 +97,6 @@ protected class ConferenceDetailsFragment : Box { public ConferenceDetailsFragment(StreamInteractor stream_interactor) { this.stream_interactor = stream_interactor; - this.ok_button = ok_button; account_combobox.initialize(stream_interactor); @@ -114,7 +114,6 @@ protected class ConferenceDetailsFragment : Box { jid_entry.key_release_event.connect(() => { done = true; return false; }); // just for notifying nick_entry.key_release_event.connect(() => { done = true; return false; }); - stream_interactor.get_module(MucManager.IDENTITY).enter_error.connect(on_enter_error); notification_button.clicked.connect(() => { notification_revealer.set_reveal_child(false); }); clear(); @@ -137,29 +136,40 @@ protected class ConferenceDetailsFragment : Box { password_stack.set_visible_child_name("entry"); } - private void on_enter_error(Account account, Jid jid, Xmpp.Xep.Muc.MucEnterError error) { + private async void on_ok_button_clicked() { + ok_button.label = _("Joining…"); + ok_button.sensitive = false; + + Muc.JoinResult? join_result = yield stream_interactor.get_module(MucManager.IDENTITY).join(account, new Jid(jid), nick, password); + ok_button.label = _("Join"); ok_button.sensitive = true; + if (join_result == null || join_result.nick != null) return; + string label_text = ""; - switch (error) { - case Xmpp.Xep.Muc.MucEnterError.PASSWORD_REQUIRED: - label_text = _("Password required to enter room"); - password_text_label.visible = true; - password_stack.visible = true; - break; - case Xmpp.Xep.Muc.MucEnterError.BANNED: - label_text = _("Banned from joining or creating conference"); break; - case Xmpp.Xep.Muc.MucEnterError.ROOM_DOESNT_EXIST: - label_text = _("Room does not exist"); break; - case Xmpp.Xep.Muc.MucEnterError.CREATION_RESTRICTED: - label_text = _("Not allowed to create room"); break; - case Xmpp.Xep.Muc.MucEnterError.NOT_IN_MEMBER_LIST: - label_text = _("Members-only room"); break; - case Xmpp.Xep.Muc.MucEnterError.USE_RESERVED_ROOMNICK: - case Xmpp.Xep.Muc.MucEnterError.NICK_CONFLICT: - label_text = _("Choose a different nick"); break; - case Xmpp.Xep.Muc.MucEnterError.OCCUPANT_LIMIT_REACHED: - label_text = _("Too many occupants in room"); break; + if (join_result.muc_error != null) { + switch (join_result.muc_error) { + case Muc.MucEnterError.PASSWORD_REQUIRED: + label_text = _("Password required to enter room"); + password_text_label.visible = true; + password_stack.visible = true; + break; + case Muc.MucEnterError.BANNED: + label_text = _("Banned from joining or creating conference"); break; + case Muc.MucEnterError.ROOM_DOESNT_EXIST: + label_text = _("Room does not exist"); break; + case Muc.MucEnterError.CREATION_RESTRICTED: + label_text = _("Not allowed to create room"); break; + case Muc.MucEnterError.NOT_IN_MEMBER_LIST: + label_text = _("Members-only room"); break; + case Muc.MucEnterError.USE_RESERVED_ROOMNICK: + case Muc.MucEnterError.NICK_CONFLICT: + label_text = _("Choose a different nick"); break; + case Muc.MucEnterError.OCCUPANT_LIMIT_REACHED: + label_text = _("Too many occupants in room"); break; + } + } else if (join_result.stanza_error != null) { + label_text = _("Failed connecting to %s").printf((new Jid(jid)).domainpart); } notification_label.label = label_text; notification_revealer.set_reveal_child(true); diff --git a/main/src/ui/application.vala b/main/src/ui/application.vala index d9377aeb..138411a0 100644 --- a/main/src/ui/application.vala +++ b/main/src/ui/application.vala @@ -169,7 +169,6 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application { content_area.add(conference_fragment); dialog.response.connect((response_id) => { if (response_id == ResponseType.OK) { - stream_interactor.get_module(MucManager.IDENTITY).join(conference_fragment.account, new Jid(conference_fragment.jid), conference_fragment.nick, conference_fragment.password); dialog.destroy(); } else if (response_id == ResponseType.CANCEL) { dialog.destroy(); diff --git a/xmpp-vala/src/module/xep/0045_muc/flag.vala b/xmpp-vala/src/module/xep/0045_muc/flag.vala index c6c2ef3b..ad181922 100644 --- a/xmpp-vala/src/module/xep/0045_muc/flag.vala +++ b/xmpp-vala/src/module/xep/0045_muc/flag.vala @@ -9,6 +9,7 @@ public class Flag : XmppStreamFlag { private HashMap room_names = new HashMap(Jid.hash_bare_func, Jid.equals_bare_func); private HashMap enter_ids = new HashMap(Jid.hash_bare_func, Jid.equals_bare_func); + public HashMap> enter_futures = new HashMap>(Jid.hash_func, Jid.equals_func); private HashMap own_nicks = new HashMap(Jid.hash_bare_func, Jid.equals_bare_func); private HashMap subjects = new HashMap(Jid.hash_bare_func, Jid.equals_bare_func); private HashMap subjects_by = new HashMap(Jid.hash_bare_func, Jid.equals_bare_func); diff --git a/xmpp-vala/src/module/xep/0045_muc/module.vala b/xmpp-vala/src/module/xep/0045_muc/module.vala index 85c78266..8ce0e20e 100644 --- a/xmpp-vala/src/module/xep/0045_muc/module.vala +++ b/xmpp-vala/src/module/xep/0045_muc/module.vala @@ -53,6 +53,12 @@ public enum Feature { UNSECURED } +public class JoinResult : Object { + public MucEnterError? muc_error { get; set; } + public string? stanza_error { get; set; } + public string? nick { get; set; } +} + public class Module : XmppStreamModule { public static ModuleIdentity IDENTITY = new ModuleIdentity(NS_URI, "0045_muc_module"); @@ -74,7 +80,7 @@ public class Module : XmppStreamModule { received_pipeline_listener = new ReceivedPipelineListener(this); } - public void enter(XmppStream stream, Jid bare_jid, string nick, string? password, DateTime? history_since) { + public async JoinResult? enter(XmppStream stream, Jid bare_jid, string nick, string? password, DateTime? history_since) { Presence.Stanza presence = new Presence.Stanza(); presence.to = bare_jid.with_resource(nick); StanzaNode x_node = new StanzaNode.build("x", NS_URI).add_self_xmlns(); @@ -92,6 +98,16 @@ public class Module : XmppStreamModule { query_room_info(stream, bare_jid); stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence); + + var promise = new Promise(); + stream.get_flag(Flag.IDENTITY).enter_futures[bare_jid] = promise; + try { + JoinResult? enter_result = yield promise.future.wait_async(); + stream.get_flag(Flag.IDENTITY).enter_futures.unset(bare_jid); + return enter_result; + } catch (Gee.FutureError e) { + return null; + } } public void exit(XmppStream stream, Jid jid) { @@ -262,7 +278,12 @@ public class Module : XmppStreamModule { if (ErrorStanza.TYPE_CANCEL == error_stanza.type_) error = MucEnterError.USE_RESERVED_ROOMNICK; break; } - if (error != MucEnterError.NONE) room_enter_error(stream, bare_jid, error); + if (error != MucEnterError.NONE) { + room_enter_error(stream, bare_jid, error); + flag.enter_futures[bare_jid].set_value(new JoinResult() {muc_error=error}); + } else { + flag.enter_futures[bare_jid].set_value(new JoinResult() {stanza_error=error_stanza.condition}); + } flag.finish_muc_enter(bare_jid); } } @@ -279,6 +300,7 @@ public class Module : XmppStreamModule { if (flag.get_enter_id(bare_jid) != null) { room_entered(stream, bare_jid, presence.from.resourcepart); flag.finish_muc_enter(bare_jid, presence.from.resourcepart); + flag.enter_futures[bare_jid].set_value(new JoinResult() {nick=presence.from.resourcepart}); } } string? affiliation_str = x_node.get_deep_attribute("item", "affiliation");