From 04de62a4e0af4843e84c933e16f249ba1df6874f Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 18 Jun 2014 22:42:58 +0200 Subject: Messages to room participants are forwarded to the IRC user For example, both JID #chan%server@biboumi/Toto and toto!server@biboumi are equivalent, except that if you send a message to the first one, subsequent messages coming from the user toto will come from that same JID. This is done to be consistent for the XMPP user, and respond from the same JID than the 'to' of the first message. fix #2468 --- src/bridge/bridge.cpp | 30 ++++++++++++++++++++++++++++-- src/bridge/bridge.hpp | 16 ++++++++++++++++ src/xmpp/xmpp_component.cpp | 36 ++++++++++++++++++++++++++++-------- src/xmpp/xmpp_component.hpp | 6 +++++- 4 files changed, 77 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 6d864c0..a0964df 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -242,8 +242,18 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st this->xmpp->send_muc_message(std::to_string(iid), nick, this->make_xmpp_body(body), this->user_jid); else - this->xmpp->send_message(std::to_string(iid), - this->make_xmpp_body(body), this->user_jid, "chat"); + { + std::string target = std::to_string(iid); + bool fulljid = false; + auto it = this->preferred_user_from.find(iid.get_local()); + if (it != this->preferred_user_from.end()) + { + target = it->second; + fulljid = true; + } + this->xmpp->send_message(target, this->make_xmpp_body(body), + this->user_jid, "chat", fulljid); + } } void Bridge::send_join_failed(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& text) @@ -343,3 +353,19 @@ void Bridge::send_iq_version_request(const std::string& nick, const std::string& { this->xmpp->send_iq_version_request(nick + "!" + hostname, this->user_jid); } + +void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid) +{ + auto it = this->preferred_user_from.find(nick); + if (it == this->preferred_user_from.end()) + this->preferred_user_from.emplace(nick, full_jid); + else + this->preferred_user_from[nick] = full_jid; +} + +void Bridge::remove_preferred_from_jid(const std::string& nick) +{ + auto it = this->preferred_user_from.find(nick); + if (it != this->preferred_user_from.end()) + this->preferred_user_from.erase(it); +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 814222b..8711829 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -123,6 +123,14 @@ public: * Get the number of server to which this bridge is connected or connecting. */ size_t active_clients() const; + /** + * Add (or replace the existing) into the preferred_user_from map + */ + void set_preferred_from_jid(const std::string& nick, const std::string& full_jid); + /** + * Remove the preferred jid for the given IRC nick + */ + void remove_preferred_from_jid(const std::string& nick); private: /** @@ -157,6 +165,14 @@ private: * their sockets. */ std::shared_ptr poller; + /** + * A map of . For example if this map contains <"toto", + * "#somechan%server@biboumi/ToTo">, whenever a private message is + * received from the user "toto", instead of forwarding it to XMPP with + * from='toto!server@biboumi', we use instead + * from='#somechan%server@biboumi/ToTo' + */ + std::unordered_map preferred_user_from; Bridge(const Bridge&) = delete; Bridge(Bridge&& other) = delete; diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index ec8517c..da9cded 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -351,13 +352,14 @@ void XmppComponent::handle_message(const Stanza& stanza) utils::ScopeGuard stanza_error([&](){ this->send_stanza_error("message", from, to_str, id, error_type, error_name, ""); - }); + }); XmlNode* body = stanza.get_child("body", COMPONENT_NS); if (type == "groupchat" && iid.is_channel) { - if (to.resource.empty()) - if (body && !body->get_inner().empty()) + if (body && !body->get_inner().empty()) + { bridge->send_channel_message(iid, body->get_inner()); + } XmlNode* subject = stanza.get_child("subject", COMPONENT_NS); if (subject) bridge->set_channel_topic(iid, subject->get_inner()); @@ -374,15 +376,30 @@ void XmppComponent::handle_message(const Stanza& stanza) { const XmlNode* condition = error->get_last_child(); if (kickable_errors.find(condition->get_name()) == kickable_errors.end()) - kickable_error = false; + kickable_error = false; } if (kickable_error) bridge->shutdown("Error from remote client"); } - else if (type == "chat" && iid.is_user && !iid.get_local().empty()) + else if (type == "chat") { if (body && !body->get_inner().empty()) - bridge->send_private_message(iid, body->get_inner()); + { + // a message for nick!server + if (iid.is_user && !iid.get_local().empty()) + { + bridge->send_private_message(iid, body->get_inner()); + bridge->remove_preferred_from_jid(iid.get_local()); + } + else if (!iid.is_user && !to.resource.empty()) + { // a message for chan%server@biboumi/Nick or + // server@biboumi/Nick + // Convert that into a message to nick!server + Iid user_iid(utils::tolower(to.resource) + "!" + iid.get_server()); + bridge->send_private_message(user_iid, body->get_inner()); + bridge->set_preferred_from_jid(user_iid.get_local(), to_str); + } + } } else if (iid.is_user) this->send_invalid_user_error(to.local, from); @@ -571,11 +588,14 @@ void* XmppComponent::get_receive_buffer(const size_t size) const return this->parser.get_buffer(size); } -void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, const std::string& to, const std::string& type) +void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, const std::string& to, const std::string& type, const bool fulljid) { XmlNode node("message"); node["to"] = to; - node["from"] = from + "@" + this->served_hostname; + if (fulljid) + node["from"] = from; + else + node["from"] = from + "@" + this->served_hostname; if (!type.empty()) node["type"] = type; XmlNode body_node("body"); diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index f1806de..17462f4 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -111,9 +111,13 @@ public: void close_document(); /** * Send a message from from@served_hostname, with the given body + * + * If fulljid is false, the provided 'from' doesn't contain the + * server-part of the JID and must be added. */ void send_message(const std::string& from, Xmpp::body&& body, - const std::string& to, const std::string& type); + const std::string& to, const std::string& type, + const bool fulljid=false); /** * Send a join from a new participant */ -- cgit v1.2.3