Commit 34fc1d40 authored by louiz’'s avatar louiz’

Implement a basic webirc support

See https://kiwiirc.com/docs/webirc

fix #3135
parent 2c932cf0
...@@ -96,6 +96,13 @@ The configuration file uses a simple format of the form ...@@ -96,6 +96,13 @@ The configuration file uses a simple format of the form
username of each user will be set to the nick they used to connect to the username of each user will be set to the nick they used to connect to the
IRC server. IRC server.
`webirc_password`
Configure a password to be communicated to the IRC server, as part of the
WEBIRC message (see https://kiwiirc.com/docs/webirc). If this option is
set, an additional DNS resolution of the hostname of each XMPP server will
be made when connecting to an IRC server.
`log_file` `log_file`
A filename into which logs are written. If none is provided, the logs are A filename into which logs are written. If none is provided, the logs are
......
...@@ -56,7 +56,8 @@ void Bridge::clean() ...@@ -56,7 +56,8 @@ void Bridge::clean()
while (it != this->irc_clients.end()) while (it != this->irc_clients.end())
{ {
IrcClient* client = it->second.get(); IrcClient* client = it->second.get();
if (!client->is_connected() && !client->is_connecting()) if (!client->is_connected() && !client->is_connecting() &&
!client->get_resolver().is_resolving())
it = this->irc_clients.erase(it); it = this->irc_clients.erase(it);
else else
++it; ++it;
...@@ -94,16 +95,17 @@ IrcClient* Bridge::make_irc_client(const std::string& hostname, const std::strin ...@@ -94,16 +95,17 @@ IrcClient* Bridge::make_irc_client(const std::string& hostname, const std::strin
{ {
auto username = nickname; auto username = nickname;
auto realname = nickname; auto realname = nickname;
Jid jid(this->user_jid);
if (Config::get("realname_from_jid", "false") == "true") if (Config::get("realname_from_jid", "false") == "true")
{ {
Jid jid(this->user_jid);
username = jid.local; username = jid.local;
realname = this->get_bare_jid(); realname = this->get_bare_jid();
} }
this->irc_clients.emplace(hostname, this->irc_clients.emplace(hostname,
std::make_shared<IrcClient>(this->poller, hostname, std::make_shared<IrcClient>(this->poller, hostname,
nickname, username, nickname, username,
realname, this)); realname, jid.domain,
this));
std::shared_ptr<IrcClient> irc = this->irc_clients.at(hostname); std::shared_ptr<IrcClient> irc = this->irc_clients.at(hostname);
return irc.get(); return irc.get();
} }
......
...@@ -26,9 +26,11 @@ using namespace std::chrono_literals; ...@@ -26,9 +26,11 @@ using namespace std::chrono_literals;
IrcClient::IrcClient(std::shared_ptr<Poller> poller, const std::string& hostname, IrcClient::IrcClient(std::shared_ptr<Poller> poller, const std::string& hostname,
const std::string& nickname, const std::string& username, const std::string& nickname, const std::string& username,
const std::string& realname, Bridge* bridge): const std::string& realname, const std::string& user_hostname,
Bridge* bridge):
TCPSocketHandler(poller), TCPSocketHandler(poller),
hostname(hostname), hostname(hostname),
user_hostname(user_hostname),
username(username), username(username),
realname(realname), realname(realname),
current_nick(nickname), current_nick(nickname),
...@@ -113,6 +115,39 @@ void IrcClient::on_connection_failed(const std::string& reason) ...@@ -113,6 +115,39 @@ void IrcClient::on_connection_failed(const std::string& reason)
void IrcClient::on_connected() void IrcClient::on_connected()
{ {
const auto webirc_password = Config::get("webirc_password", "");
static std::string resolved_ip;
if (!webirc_password.empty())
{
if (!resolved_ip.empty())
this->send_webirc_command(webirc_password, resolved_ip);
else
{ // Start resolving the hostname of the user, and call
// on_connected again when it’s done
this->dns_resolver.resolve(this->user_hostname, "5222",
[this](const struct addrinfo* addr)
{
resolved_ip = addr_to_string(addr);
// Only continue the process if we
// didn’t get connected while we were
// resolving
if (this->is_connected())
this->on_connected();
},
[this](const char* error_msg)
{
if (this->is_connected())
{
this->on_connection_close("Could not resolve hostname "s + this->user_hostname +
": " + error_msg);
this->send_quit_command("");
}
});
return;
}
}
#ifdef USE_DATABASE #ifdef USE_DATABASE
auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(),
this->get_hostname()); this->get_hostname());
...@@ -253,7 +288,7 @@ void IrcClient::send_raw(const std::string& txt) ...@@ -253,7 +288,7 @@ void IrcClient::send_raw(const std::string& txt)
void IrcClient::send_user_command(const std::string& username, const std::string& realname) void IrcClient::send_user_command(const std::string& username, const std::string& realname)
{ {
this->send_message(IrcMessage("USER", {username, "ignored", "ignored", realname})); this->send_message(IrcMessage("USER", {username, this->user_hostname, "ignored", realname}));
} }
void IrcClient::send_nick_command(const std::string& nick) void IrcClient::send_nick_command(const std::string& nick)
...@@ -266,6 +301,11 @@ void IrcClient::send_pass_command(const std::string& password) ...@@ -266,6 +301,11 @@ void IrcClient::send_pass_command(const std::string& password)
this->send_message(IrcMessage("PASS", {password})); this->send_message(IrcMessage("PASS", {password}));
} }
void IrcClient::send_webirc_command(const std::string& password, const std::string& user_ip)
{
this->send_message(IrcMessage("WEBIRC", {password, "biboumi", this->user_hostname, user_ip}));
}
void IrcClient::send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason) void IrcClient::send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason)
{ {
this->send_message(IrcMessage("KICK", {chan_name, target, reason})); this->send_message(IrcMessage("KICK", {chan_name, target, reason}));
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <irc/iid.hpp> #include <irc/iid.hpp>
#include <network/tcp_socket_handler.hpp> #include <network/tcp_socket_handler.hpp>
#include <network/resolver.hpp>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
...@@ -27,7 +28,8 @@ class IrcClient: public TCPSocketHandler ...@@ -27,7 +28,8 @@ class IrcClient: public TCPSocketHandler
public: public:
explicit IrcClient(std::shared_ptr<Poller> poller, const std::string& hostname, explicit IrcClient(std::shared_ptr<Poller> poller, const std::string& hostname,
const std::string& nickname, const std::string& username, const std::string& nickname, const std::string& username,
const std::string& realname, Bridge* bridge); const std::string& realname, const std::string& user_hostname,
Bridge* bridge);
~IrcClient(); ~IrcClient();
/** /**
* Connect to the IRC server * Connect to the IRC server
...@@ -88,6 +90,7 @@ public: ...@@ -88,6 +90,7 @@ public:
*/ */
void send_nick_command(const std::string& username); void send_nick_command(const std::string& username);
void send_pass_command(const std::string& password); void send_pass_command(const std::string& password);
void send_webirc_command(const std::string& password, const std::string& user_ip);
/** /**
* Send the JOIN irc command. * Send the JOIN irc command.
*/ */
...@@ -250,11 +253,18 @@ public: ...@@ -250,11 +253,18 @@ public:
std::string get_nick() const { return this->current_nick; } std::string get_nick() const { return this->current_nick; }
bool is_welcomed() const { return this->welcomed; } bool is_welcomed() const { return this->welcomed; }
const Resolver& get_resolver() const;
private: private:
/** /**
* The hostname of the server we are connected to. * The hostname of the server we are connected to.
*/ */
const std::string hostname; const std::string hostname;
/**
* The hostname of the user. This is used in the USER and the WEBIRC
* commands, but only the one in WEBIRC will be used by the IRC server.
*/
const std::string user_hostname;
/** /**
* The username used in the USER irc command * The username used in the USER irc command
*/ */
...@@ -330,6 +340,11 @@ private: ...@@ -330,6 +340,11 @@ private:
* A set of (lowercase) nicknames to which we sent a private message. * A set of (lowercase) nicknames to which we sent a private message.
*/ */
std::set<std::string> nicks_to_treat_as_private; std::set<std::string> nicks_to_treat_as_private;
/**
* DNS resolver, used to resolve the hostname of the user if we are using
* the WebIRC protocole.
*/
Resolver dns_resolver;
IrcClient(const IrcClient&) = delete; IrcClient(const IrcClient&) = delete;
IrcClient(IrcClient&&) = delete; IrcClient(IrcClient&&) = delete;
......
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