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
This commit is contained in:
Florent Le Coz
2014-06-18 22:42:58 +02:00
parent 56eb5df28a
commit 04de62a4e0
4 changed files with 77 additions and 11 deletions
+28 -2
View File
@@ -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->xmpp->send_muc_message(std::to_string(iid), nick,
this->make_xmpp_body(body), this->user_jid); this->make_xmpp_body(body), this->user_jid);
else 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) 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); 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);
}
+16
View File
@@ -123,6 +123,14 @@ public:
* Get the number of server to which this bridge is connected or connecting. * Get the number of server to which this bridge is connected or connecting.
*/ */
size_t active_clients() const; size_t active_clients() const;
/**
* Add (or replace the existing) <nick, jid> 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: private:
/** /**
@@ -157,6 +165,14 @@ private:
* their sockets. * their sockets.
*/ */
std::shared_ptr<Poller> poller; std::shared_ptr<Poller> poller;
/**
* A map of <nick, full_jid>. 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<std::string, std::string> preferred_user_from;
Bridge(const Bridge&) = delete; Bridge(const Bridge&) = delete;
Bridge(Bridge&& other) = delete; Bridge(Bridge&& other) = delete;
+23 -3
View File
@@ -1,4 +1,5 @@
#include <utils/scopeguard.hpp> #include <utils/scopeguard.hpp>
#include <utils/tolower.hpp>
#include <logger/logger.hpp> #include <logger/logger.hpp>
#include <xmpp/xmpp_component.hpp> #include <xmpp/xmpp_component.hpp>
@@ -355,9 +356,10 @@ void XmppComponent::handle_message(const Stanza& stanza)
XmlNode* body = stanza.get_child("body", COMPONENT_NS); XmlNode* body = stanza.get_child("body", COMPONENT_NS);
if (type == "groupchat" && iid.is_channel) 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()); bridge->send_channel_message(iid, body->get_inner());
}
XmlNode* subject = stanza.get_child("subject", COMPONENT_NS); XmlNode* subject = stanza.get_child("subject", COMPONENT_NS);
if (subject) if (subject)
bridge->set_channel_topic(iid, subject->get_inner()); bridge->set_channel_topic(iid, subject->get_inner());
@@ -379,10 +381,25 @@ void XmppComponent::handle_message(const Stanza& stanza)
if (kickable_error) if (kickable_error)
bridge->shutdown("Error from remote client"); 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()) if (body && !body->get_inner().empty())
{
// a message for nick!server
if (iid.is_user && !iid.get_local().empty())
{
bridge->send_private_message(iid, body->get_inner()); 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) else if (iid.is_user)
this->send_invalid_user_error(to.local, from); this->send_invalid_user_error(to.local, from);
@@ -571,10 +588,13 @@ void* XmppComponent::get_receive_buffer(const size_t size) const
return this->parser.get_buffer(size); 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"); XmlNode node("message");
node["to"] = to; node["to"] = to;
if (fulljid)
node["from"] = from;
else
node["from"] = from + "@" + this->served_hostname; node["from"] = from + "@" + this->served_hostname;
if (!type.empty()) if (!type.empty())
node["type"] = type; node["type"] = type;
+5 -1
View File
@@ -111,9 +111,13 @@ public:
void close_document(); void close_document();
/** /**
* Send a message from from@served_hostname, with the given body * 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, 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 * Send a join from a new participant
*/ */