Commit d8da7984 authored by louiz’'s avatar louiz’

Implement PING, user to user only (XMPP and IRC side, using CTCP PING)

ref #2757
parent e1d69806
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
#include <utils/encoding.hpp> #include <utils/encoding.hpp>
#include <utils/tolower.hpp> #include <utils/tolower.hpp>
#include <logger/logger.hpp> #include <logger/logger.hpp>
#include <utils/revstr.hpp>
#include <utils/split.hpp> #include <utils/split.hpp>
#include <xmpp/jid.hpp>
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
#include <tuple> #include <tuple>
...@@ -280,6 +282,50 @@ void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, c ...@@ -280,6 +282,50 @@ void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, c
this->send_private_message(iid, "\01VERSION "s + result + "\01", "NOTICE"); this->send_private_message(iid, "\01VERSION "s + result + "\01", "NOTICE");
} }
void Bridge::send_irc_ping_result(const Iid& iid, const std::string& id)
{
this->send_private_message(iid, "\01PING "s + utils::revstr(id), "NOTICE");
}
void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const std::string& nick,
const std::string& iq_id, const std::string& to_jid,
const std::string& from_jid)
{
Iid iid(nick + "!" + irc_hostname);
this->send_private_message(iid, "\01PING " + iq_id + "\01");
irc_responder_callback_t cb = [this, nick, iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message) -> bool
{
if (irc_hostname != hostname)
return false;
IrcUser user(message.prefix);
const std::string body = message.arguments[1];
if (message.command == "NOTICE" && user.nick == nick &&
message.arguments.size() >= 2 && body.substr(0, 6) == "\01PING ")
{
const std::string id = body.substr(6, body.size() - 6);
if (id != iq_id)
return false;
Jid jid(from_jid);
this->xmpp->send_iq_result(iq_id, to_jid, jid.local);
return true;
}
if (message.command == "401" && message.arguments.size() >= 2
&& message.arguments[1] == nick)
{
std::string error_message = "No such nick";
if (message.arguments.size() >= 3)
error_message = message.arguments[2];
this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "service-unavailable",
error_message, true);
return true;
}
return false;
};
this->add_waiting_irc(std::move(cb));
}
void Bridge::send_irc_version_request(const std::string& irc_hostname, const std::string& target, void Bridge::send_irc_version_request(const std::string& irc_hostname, const std::string& target,
const std::string& iq_id, const std::string& to_jid, const std::string& iq_id, const std::string& to_jid,
const std::string& from_jid) const std::string& from_jid)
...@@ -437,6 +483,15 @@ void Bridge::send_iq_version_request(const std::string& nick, const std::string& ...@@ -437,6 +483,15 @@ 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::send_xmpp_ping_request(const std::string& nick, const std::string& hostname,
const std::string& id)
{
// Use revstr because the forwarded ping to target XMPP user must not be
// the same that the request iq, but we also need to get it back easily
// (revstr again)
this->xmpp->send_ping_request(nick + "!" + hostname, this->user_jid, utils::revstr(id));
}
void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid) void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid)
{ {
auto it = this->preferred_user_from.find(nick); auto it = this->preferred_user_from.find(nick);
......
...@@ -68,9 +68,16 @@ public: ...@@ -68,9 +68,16 @@ public:
void set_channel_topic(const Iid& iid, const std::string& subject); void set_channel_topic(const Iid& iid, const std::string& subject);
void send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, void send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version,
const std::string& os); const std::string& os);
void send_irc_ping_result(const Iid& iid, const std::string& id);
void send_irc_version_request(const std::string& irc_hostname, const std::string& target, void send_irc_version_request(const std::string& irc_hostname, const std::string& target,
const std::string& iq_id, const std::string& to_jid, const std::string& iq_id, const std::string& to_jid,
const std::string& from_jid); const std::string& from_jid);
/**
* Directly send a CTCP PING request to the IRC user
*/
void send_irc_user_ping_request(const std::string& irc_hostname, const std::string& nick,
const std::string& iq_id, const std::string& to_jid,
const std::string& from_jid);
/*** /***
** **
...@@ -128,7 +135,11 @@ public: ...@@ -128,7 +135,11 @@ public:
* Send an iq version request coming from nick!hostname@ * Send an iq version request coming from nick!hostname@
*/ */
void send_iq_version_request(const std::string& nick, const std::string& hostname); void send_iq_version_request(const std::string& nick, const std::string& hostname);
/**
* Send an iq ping request coming from nick!hostname@
*/
void send_xmpp_ping_request(const std::string& nick, const std::string& hostname,
const std::string& id);
/** /**
* Misc * Misc
*/ */
......
...@@ -409,6 +409,9 @@ void IrcClient::on_channel_message(const IrcMessage& message) ...@@ -409,6 +409,9 @@ void IrcClient::on_channel_message(const IrcMessage& message)
"/me"s + body.substr(7, body.size() - 8), muc); "/me"s + body.substr(7, body.size() - 8), muc);
else if (body.substr(1, 8) == "VERSION\01") else if (body.substr(1, 8) == "VERSION\01")
this->bridge->send_iq_version_request(nick, this->hostname); this->bridge->send_iq_version_request(nick, this->hostname);
else if (body.substr(1, 5) == "PING ")
this->bridge->send_xmpp_ping_request(nick, this->hostname,
body.substr(6, body.size() - 7));
} }
else else
this->bridge->send_message(iid, nick, body, muc); this->bridge->send_message(iid, nick, body, muc);
......
...@@ -555,6 +555,16 @@ void XmppComponent::handle_iq(const Stanza& stanza) ...@@ -555,6 +555,16 @@ void XmppComponent::handle_iq(const Stanza& stanza)
stanza_error.disable(); stanza_error.disable();
} }
} }
else if ((query = stanza.get_child("ping", PING_NS)))
{
Iid iid(to.local);
if (iid.is_user)
{ // Ping any user (no check on the nick done ourself)
bridge->send_irc_user_ping_request(iid.get_server(),
iid.get_local(), id, from, to_str);
}
stanza_error.disable();
}
} }
else if (type == "result") else if (type == "result")
{ {
...@@ -1080,6 +1090,36 @@ void XmppComponent::send_iq_version_request(const std::string& from, ...@@ -1080,6 +1090,36 @@ void XmppComponent::send_iq_version_request(const std::string& from,
this->send_stanza(iq); this->send_stanza(iq);
} }
void XmppComponent::send_ping_request(const std::string& from,
const std::string& jid_to,
const std::string& id)
{
Stanza iq("iq");
iq["type"] = "get";
iq["id"] = id;
iq["from"] = from + "@" + this->served_hostname;
iq["to"] = jid_to;
XmlNode ping("ping");
ping["xmlns"] = PING_NS;
ping.close();
iq.add_child(std::move(ping));
iq.close();
this->send_stanza(iq);
auto result_cb = [from, id](Bridge* bridge, const Stanza& stanza)
{
Jid to(stanza.get_tag("to"));
if (to.local != from)
{
log_error("Received a corresponding ping result, but the 'to' from "
"the response mismatches the 'from' of the request");
}
else
bridge->send_irc_ping_result(from, id);
};
this->waiting_iq[id] = result_cb;
}
void XmppComponent::send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from_local_part) void XmppComponent::send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from_local_part)
{ {
Stanza iq("iq"); Stanza iq("iq");
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#define STREAMS_NS "urn:ietf:params:xml:ns:xmpp-streams" #define STREAMS_NS "urn:ietf:params:xml:ns:xmpp-streams"
#define VERSION_NS "jabber:iq:version" #define VERSION_NS "jabber:iq:version"
#define ADHOC_NS "http://jabber.org/protocol/commands" #define ADHOC_NS "http://jabber.org/protocol/commands"
#define PING_NS "urn:xmpp:ping"
/** /**
* A callback called when the waited iq result is received (it is matched * A callback called when the waited iq result is received (it is matched
* against the iq id) * against the iq id)
...@@ -216,6 +218,12 @@ public: ...@@ -216,6 +218,12 @@ public:
*/ */
void send_iq_version_request(const std::string& from, void send_iq_version_request(const std::string& from,
const std::string& jid_to); const std::string& jid_to);
/**
* Send a ping request
*/
void send_ping_request(const std::string& from,
const std::string& jid_to,
const std::string& id);
/** /**
* Send an empty iq of type result * Send an empty iq of type result
*/ */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment