diff --git a/libdino/src/service/module_manager.vala b/libdino/src/service/module_manager.vala index ebcff6ab..c3f524df 100644 --- a/libdino/src/service/module_manager.vala +++ b/libdino/src/service/module_manager.vala @@ -78,6 +78,7 @@ public class ModuleManager { module_map[account].add(new Xep.JingleFileTransfer.Module()); module_map[account].add(new Xep.Jet.Module()); module_map[account].add(new Xep.LastMessageCorrection.Module()); + module_map[account].add(new Xep.DirectMucInvitations.Module()); initialize_account_modules(account, module_map[account]); } } diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala index b5d85236..5a224a18 100644 --- a/libdino/src/service/muc_manager.vala +++ b/libdino/src/service/muc_manager.vala @@ -26,6 +26,7 @@ public class MucManager : StreamInteractionModule, Object { private HashMap enter_errors = new HashMap(Jid.hash_func, Jid.equals_func); private ReceivedMessageListener received_message_listener; private HashMap bookmarks_provider = new HashMap(Account.hash_func, Account.equals_func); + private HashMap> invites = new HashMap>(Account.hash_func, Account.equals_func); public static void start(StreamInteractor stream_interactor) { MucManager m = new MucManager(stream_interactor); @@ -364,7 +365,10 @@ public class MucManager : StreamInteractionModule, Object { subject_set(account, jid, subject); }); stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).invite_received.connect( (stream, room_jid, from_jid, password, reason) => { - invite_received(account, room_jid, from_jid, password, reason); + on_invite_received(account, room_jid, from_jid, password, reason); + }); + stream_interactor.module_manager.get_module(account, Xep.DirectMucInvitations.Module.IDENTITY).invite_received.connect( (stream, room_jid, from_jid, password, reason) => { + on_invite_received(account, room_jid, from_jid, password, reason); }); stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).voice_request_received.connect( (stream, room_jid, from_jid, nick) => { voice_request_received(account, room_jid, from_jid, nick); @@ -409,6 +413,22 @@ public class MucManager : StreamInteractionModule, Object { } } + private void on_invite_received(Account account, Jid room_jid, Jid from_jid, string? password, string? reason) { + if (!invites.has_key(account)) { + invites[account] = new LinkedList(Jid.equals_func); + } + if (invites[account].contains(room_jid)) return; + invites[account].add(room_jid); + + invite_received(account, room_jid, from_jid, password, reason); + + Timeout.add_seconds(5, () => { + // We don't want to show the same invite (direct+mediated) twice, but a distinct invite is fine + invites[account].remove(room_jid); + return false; + }); + } + private void join_all_active(Account account) { Gee.List conversations = stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations(account); foreach (Conversation conversation in conversations) { diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt index 5778c2de..fcc74fdc 100644 --- a/xmpp-vala/CMakeLists.txt +++ b/xmpp-vala/CMakeLists.txt @@ -88,6 +88,7 @@ SOURCES "src/module/xep/0199_ping.vala" "src/module/xep/0203_delayed_delivery.vala" "src/module/xep/0234_jingle_file_transfer.vala" + "src/module/xep/0249_direct_muc_invitations.vala" "src/module/xep/0260_jingle_socks5_bytestreams.vala" "src/module/xep/0261_jingle_in_band_bytestreams.vala" "src/module/xep/0280_message_carbons.vala" diff --git a/xmpp-vala/src/module/xep/0249_direct_muc_invitations.vala b/xmpp-vala/src/module/xep/0249_direct_muc_invitations.vala new file mode 100644 index 00000000..2ccab33d --- /dev/null +++ b/xmpp-vala/src/module/xep/0249_direct_muc_invitations.vala @@ -0,0 +1,55 @@ +namespace Xmpp.Xep.DirectMucInvitations { + + private const string NS_URI = "jabber:x:conference"; + + public class Module : XmppStreamModule { + public static ModuleIdentity IDENTITY = new ModuleIdentity(NS_URI, "0249_direct_muc_invitations"); + + public signal void invite_received(XmppStream stream, Jid room_jid, Jid from_jid, string? password, string? reason); + + public void invite(XmppStream stream, Jid to_muc, Jid jid) { + MessageStanza message = new MessageStanza() { to=jid }; + StanzaNode invite_node = new StanzaNode.build("x", NS_URI).add_self_xmlns() + .put_attribute("jid", to_muc.to_string()); + message.stanza.put_node(invite_node); + stream.get_module(MessageModule.IDENTITY).send_message.begin(stream, message); + } + + private void received_message(XmppStream stream, MessageStanza message) { + StanzaNode? x_node = message.stanza.get_subnode("x", NS_URI); + if (x_node == null) return; + + string? room_str = x_node.get_attribute("jid", NS_URI); + if (room_str == null) return; + Jid? room_jid = null; + try { + room_jid = new Jid(room_str); + } catch (Error e) { + return; + } + if (room_jid == null) return; + + string? password = x_node.get_attribute("password", NS_URI); + string? reason = x_node.get_attribute("reason", NS_URI); + + invite_received(stream, room_jid, message.from, password, reason); + } + + public override void attach(XmppStream stream) { + stream.get_module(MessageModule.IDENTITY).received_message.connect(received_message); + } + + public override void detach(XmppStream stream) { + stream.get_module(MessageModule.IDENTITY).received_message.connect(received_message); + } + + public override string get_ns() { + return NS_URI; + } + + public override string get_id() { + return IDENTITY.id; + } + } + +}