From e6a90fc25c19b4cfceff7b1d89c58927753ee98d Mon Sep 17 00:00:00 2001 From: fiaxh Date: Fri, 14 Aug 2020 16:42:56 +0200 Subject: [PATCH] Implement MUC self ping --- libdino/src/service/muc_manager.vala | 47 ++++++++++++++++++- libdino/src/service/stream_interactor.vala | 3 ++ xmpp-vala/CMakeLists.txt | 1 + xmpp-vala/src/module/xep/0199_ping.vala | 4 +- .../src/module/xep/0410_muc_self_ping.vala | 18 +++++++ 5 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 xmpp-vala/src/module/xep/0410_muc_self_ping.vala diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala index 94536ba2..8eba524d 100644 --- a/libdino/src/service/muc_manager.vala +++ b/libdino/src/service/muc_manager.vala @@ -21,7 +21,8 @@ public class MucManager : StreamInteractionModule, Object { public signal void conference_removed(Account account, Jid jid); private StreamInteractor stream_interactor; - private HashMap> mucs_joining = new HashMap>(Account.hash_func, Account.equals_func); + private HashMap> mucs_todo = new HashMap>(Account.hash_func, Account.equals_func); + private HashMap> mucs_joining = new HashMap>(Account.hash_func, Account.equals_func); 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); @@ -42,6 +43,13 @@ public class MucManager : StreamInteractionModule, Object { part(conversation.account, conversation.counterpart); } }); + stream_interactor.stream_resumed.connect((account, stream) => self_ping(account)); + Timeout.add_seconds(60 * 3, () => { + foreach (Account account in stream_interactor.get_accounts()) { + self_ping(account); + } + return true; + }); } public async Muc.JoinResult? join(Account account, Jid jid, string? nick, string? password) { @@ -58,10 +66,15 @@ public class MucManager : StreamInteractionModule, Object { } if (!mucs_joining.has_key(account)) { - mucs_joining[account] = new ArrayList(Jid.equals_bare_func); + mucs_joining[account] = new HashSet(Jid.hash_bare_func, Jid.equals_bare_func); } mucs_joining[account].add(jid); + if (!mucs_todo.has_key(account)) { + mucs_todo[account] = new HashSet(Jid.hash_bare_func, Jid.equals_bare_func); + } + mucs_todo[account].add(jid.with_resource(nick_)); + Muc.JoinResult? res = yield stream.get_module(Xep.Muc.Module.IDENTITY).enter(stream, jid.bare_jid, nick_, password, history_since); mucs_joining[account].remove(jid); @@ -84,6 +97,8 @@ public class MucManager : StreamInteractionModule, Object { } public void part(Account account, Jid jid) { + mucs_todo[account].remove(jid); + XmppStream? stream = stream_interactor.get_stream(account); if (stream == null) return; unset_autojoin(account, stream, jid); @@ -123,6 +138,11 @@ public class MucManager : StreamInteractionModule, Object { conversation.nickname = new_nick; + if (mucs_todo.has_key(conversation.account)) { + mucs_todo[conversation.account].remove(conversation.counterpart); + mucs_todo[conversation.account].add(conversation.counterpart.with_resource(new_nick)); + } + // Update nick in bookmark Set? conferences = yield bookmarks_provider[conversation.account].get_conferences(stream); if (conferences == null) return; @@ -466,6 +486,29 @@ public class MucManager : StreamInteractionModule, Object { }); } + private void self_ping(Account account) { + XmppStream? stream = stream_interactor.get_stream(account); + if (stream == null) return; + + if (!mucs_todo.has_key(account)) return; + + foreach (Jid jid in mucs_todo[account]) { + + bool joined = false; + + Xmpp.Xep.MucSelfPing.is_joined.begin(stream, jid, (_, res) => { + joined = Xmpp.Xep.MucSelfPing.is_joined.end(res); + }); + + Timeout.add_seconds(10, () => { + if (joined || !mucs_todo.has_key(account) || stream_interactor.get_stream(account) != stream) return false; + + join.begin(account, jid.bare_jid, jid.resourcepart, null); + return false; + }); + } + } + private class ReceivedMessageListener : MessageListener { public string[] after_actions_const = new string[]{ }; diff --git a/libdino/src/service/stream_interactor.vala b/libdino/src/service/stream_interactor.vala index db6d58d8..e60a43d6 100644 --- a/libdino/src/service/stream_interactor.vala +++ b/libdino/src/service/stream_interactor.vala @@ -9,6 +9,7 @@ public class StreamInteractor : Object { public signal void account_added(Account account); public signal void account_removed(Account account); + public signal void stream_resumed(Account account, XmppStream stream); public signal void stream_negotiated(Account account, XmppStream stream); public signal void attached_modules(Account account, XmppStream stream); @@ -70,6 +71,8 @@ public class StreamInteractor : Object { var flag = stream.get_flag(Xep.StreamManagement.Flag.IDENTITY); if (flag == null || flag.resumed == false) { stream_negotiated(account, stream); + } else if (flag != null && flag.resumed == true) { + stream_resumed(account, stream); } }); } diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt index 6691f950..f2e89b4e 100644 --- a/xmpp-vala/CMakeLists.txt +++ b/xmpp-vala/CMakeLists.txt @@ -94,6 +94,7 @@ SOURCES "src/module/xep/0368_srv_records_tls.vala" "src/module/xep/0380_explicit_encryption.vala" "src/module/xep/0391_jingle_encrypted_transports.vala" + "src/module/xep/0410_muc_self_ping.vala" "src/module/xep/pixbuf_storage.vala" "src/util.vala" diff --git a/xmpp-vala/src/module/xep/0199_ping.vala b/xmpp-vala/src/module/xep/0199_ping.vala index 12997f32..f3e68660 100644 --- a/xmpp-vala/src/module/xep/0199_ping.vala +++ b/xmpp-vala/src/module/xep/0199_ping.vala @@ -6,10 +6,10 @@ namespace Xmpp.Xep.Ping { public class Module : XmppStreamModule, Iq.Handler { public static ModuleIdentity IDENTITY = new ModuleIdentity(NS_URI, "0199_ping"); - public async void send_ping(XmppStream stream, Jid jid) { + public async Iq.Stanza send_ping(XmppStream stream, Jid jid) { StanzaNode ping_node = new StanzaNode.build("ping", NS_URI).add_self_xmlns(); Iq.Stanza iq = new Iq.Stanza.get(ping_node) { to=jid }; - yield stream.get_module(Iq.Module.IDENTITY).send_iq_async(stream, iq); + return yield stream.get_module(Iq.Module.IDENTITY).send_iq_async(stream, iq); } public override void attach(XmppStream stream) { diff --git a/xmpp-vala/src/module/xep/0410_muc_self_ping.vala b/xmpp-vala/src/module/xep/0410_muc_self_ping.vala new file mode 100644 index 00000000..84772333 --- /dev/null +++ b/xmpp-vala/src/module/xep/0410_muc_self_ping.vala @@ -0,0 +1,18 @@ +namespace Xmpp.Xep.MucSelfPing { + + public static async bool is_joined(XmppStream stream, Jid jid) { + Iq.Stanza iq_result = yield stream.get_module(Xmpp.Xep.Ping.Module.IDENTITY).send_ping(stream, jid); + + if (!iq_result.is_error()) { + return true; + } else { + var error_stanza = iq_result.get_error(); + if (error_stanza.condition in new string[] {ErrorStanza.CONDITION_SERVICE_UNAVAILABLE, ErrorStanza.CONDITION_FEATURE_NOT_IMPLEMENTED}) { + // the client is joined, but the pinged client does not implement XMPP Ping + return true; + } + } + return false; + } + +}