Implement a basic webirc support
See https://kiwiirc.com/docs/webirc fix #3135
This commit is contained in:
@@ -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()
|
|||||||
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
|
|||||||
{
|
{
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-2
@@ -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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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}));
|
||||||
|
|||||||
+16
-1
@@ -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
|
|||||||
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:
|
|||||||
*/
|
*/
|
||||||
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:
|
|||||||
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:
|
|||||||
* 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;
|
||||||
|
|||||||
Reference in New Issue
Block a user