Commit 2df0ebf2 authored by louiz’'s avatar louiz’

Add support for a fixed_irc_server configuration

This option lets the administrator choose a specific IRC server, and only
that server can be used with this biboumi instance.

In this mode, JIDs to use are changed like this:

- #chan%irc.example.com@biboumi.example.com      -> #chan@biboumi.example.com
- user!irc.example.com@biboumi.example.com       -> user!@biboumi.example.com
- #chan%irc.example.com@biboumi.example.com/Nick -> #chan@biboumi.example.com/Nick
- %irc.example.com@biboumi.example.com           -> no equivalent
- irc.example.com@biboumi.example.com            -> no equivalent
parent 1c43c3af
...@@ -59,6 +59,20 @@ The configuration file uses a simple format of the form ...@@ -59,6 +59,20 @@ The configuration file uses a simple format of the form
privileges), for example some administration ad-hoc commands will only be privileges), for example some administration ad-hoc commands will only be
available to that JID. available to that JID.
`fixed_irc_server`
If this option contains the hostname of an IRC server (for example
irc.example.org), then biboumi will enforce the connexion to that IRC
server only. This means that a JID like "#chan@irc.biboumi.org" must be
used instead of "#chan%irc.example.org@irc.biboumi.org". In that mode,
the virtual channel (see *Connect to an IRC server*) is not available and
you still need to use the ! separator to send message to an IRC user (for
example "foo!@biboumi.example.com" to send a message to foo), although the
in-room JID still work as expected ("#channel@biboumi.example.com/Nick").
This option can for example be used by an administrator that just wants to
let their users join their own IRC server using an XMPP client, but
without letting them join any other IRC servers on the internet.
`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
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <xmpp/xmpp_stanza.hpp> #include <xmpp/xmpp_stanza.hpp>
#include <irc/irc_message.hpp> #include <irc/irc_message.hpp>
#include <network/poller.hpp> #include <network/poller.hpp>
#include <utils/empty_if_fixed_server.hpp>
#include <utils/encoding.hpp> #include <utils/encoding.hpp>
#include <utils/tolower.hpp> #include <utils/tolower.hpp>
#include <logger/logger.hpp> #include <logger/logger.hpp>
...@@ -542,13 +543,13 @@ void Bridge::send_user_join(const std::string& hostname, ...@@ -542,13 +543,13 @@ void Bridge::send_user_join(const std::string& hostname,
std::string role; std::string role;
std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode);
this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host, this->xmpp->send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host,
affiliation, role, this->user_jid, self); affiliation, role, this->user_jid, self);
} }
void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic) void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic)
{ {
this->xmpp->send_topic(chan_name + "%" + hostname, this->make_xmpp_body(topic), this->user_jid); this->xmpp->send_topic(chan_name + utils::empty_if_fixed_server("%" + hostname), this->make_xmpp_body(topic), this->user_jid);
} }
std::string Bridge::get_own_nick(const Iid& iid) std::string Bridge::get_own_nick(const Iid& iid)
...@@ -585,7 +586,7 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar ...@@ -585,7 +586,7 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar
void Bridge::send_iq_version_request(const std::string& nick, const std::string& hostname) void Bridge::send_iq_version_request(const std::string& nick, const std::string& hostname)
{ {
this->xmpp->send_iq_version_request(nick + "!" + hostname, this->user_jid); this->xmpp->send_iq_version_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid);
} }
void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& hostname, void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& hostname,
...@@ -594,7 +595,7 @@ void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& ...@@ -594,7 +595,7 @@ void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string&
// Use revstr because the forwarded ping to target XMPP user must not be // 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 // the same that the request iq, but we also need to get it back easily
// (revstr again) // (revstr again)
this->xmpp->send_ping_request(nick + "!" + hostname, this->user_jid, utils::revstr(id)); this->xmpp->send_ping_request(nick + "!" + utils::empty_if_fixed_server(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)
......
#include <utils/tolower.hpp> #include <utils/tolower.hpp>
#include <config/config.hpp>
#include <irc/iid.hpp> #include <irc/iid.hpp>
Iid::Iid(const std::string& iid): Iid::Iid(const std::string& iid):
is_channel(false), is_channel(false),
is_user(false) is_user(false)
{
const std::string fixed_irc_server = Config::get("fixed_irc_server", "");
if (fixed_irc_server.empty())
this->init(iid);
else
this->init_with_fixed_server(iid, fixed_irc_server);
}
void Iid::init(const std::string& iid)
{ {
const std::string::size_type sep = iid.find_first_of("%!"); const std::string::size_type sep = iid.find_first_of("%!");
if (sep != std::string::npos) if (sep != std::string::npos)
...@@ -20,6 +31,29 @@ Iid::Iid(const std::string& iid): ...@@ -20,6 +31,29 @@ Iid::Iid(const std::string& iid):
this->set_server(iid); this->set_server(iid);
} }
void Iid::init_with_fixed_server(const std::string& iid, const std::string& hostname)
{
this->set_server(hostname);
const std::string::size_type sep = iid.find_first_of("%!");
// Without any separator, we consider that it's a channel
if (sep == std::string::npos)
{
this->is_channel = true;
this->set_local(iid);
}
else // A separator can be present to differenciate a channel from a user,
// but the part behind it (the hostname) is ignored
{
this->set_local(iid.substr(0, sep));
if (iid[sep] == '%')
this->is_channel = true;
else
this->is_user = true;
}
}
Iid::Iid(const Iid& other): Iid::Iid(const Iid& other):
is_channel(other.is_channel), is_channel(other.is_channel),
is_user(other.is_user), is_user(other.is_user),
...@@ -66,6 +100,14 @@ std::string Iid::get_sep() const ...@@ -66,6 +100,14 @@ std::string Iid::get_sep() const
namespace std { namespace std {
const std::string to_string(const Iid& iid) const std::string to_string(const Iid& iid)
{ {
return iid.get_local() + iid.get_sep() + iid.get_server(); if (Config::get("fixed_irc_server", "").empty())
return iid.get_local() + iid.get_sep() + iid.get_server();
else
{
if (iid.get_sep() == "!")
return iid.get_local() + iid.get_sep();
else
return iid.get_local();
}
} }
} }
...@@ -57,6 +57,10 @@ public: ...@@ -57,6 +57,10 @@ public:
std::string get_sep() const; std::string get_sep() const;
private: private:
void init(const std::string& iid);
void init_with_fixed_server(const std::string& iid, const std::string& hostname);
std::string local; std::string local;
std::string server; std::string server;
......
...@@ -303,38 +303,100 @@ int main() ...@@ -303,38 +303,100 @@ int main()
/** /**
* IID parsing * IID parsing
*/ */
std::cout << color << "Testing IID parsing…" << reset << std::endl; {
Iid iid1("foo!irc.example.org"); std::cout << color << "Testing IID parsing…" << reset << std::endl;
std::cout << std::to_string(iid1) << std::endl; Iid iid1("foo!irc.example.org");
assert(std::to_string(iid1) == "foo!irc.example.org"); std::cout << std::to_string(iid1) << std::endl;
assert(iid1.get_local() == "foo"); assert(std::to_string(iid1) == "foo!irc.example.org");
assert(iid1.get_server() == "irc.example.org"); assert(iid1.get_local() == "foo");
assert(!iid1.is_channel); assert(iid1.get_server() == "irc.example.org");
assert(iid1.is_user); assert(!iid1.is_channel);
assert(iid1.is_user);
Iid iid2("#test%irc.example.org");
std::cout << std::to_string(iid2) << std::endl; Iid iid2("#test%irc.example.org");
assert(std::to_string(iid2) == "#test%irc.example.org"); std::cout << std::to_string(iid2) << std::endl;
assert(iid2.get_local() == "#test"); assert(std::to_string(iid2) == "#test%irc.example.org");
assert(iid2.get_server() == "irc.example.org"); assert(iid2.get_local() == "#test");
assert(iid2.is_channel); assert(iid2.get_server() == "irc.example.org");
assert(!iid2.is_user); assert(iid2.is_channel);
assert(!iid2.is_user);
Iid iid3("%irc.example.org");
std::cout << std::to_string(iid3) << std::endl; Iid iid3("%irc.example.org");
assert(std::to_string(iid3) == "%irc.example.org"); std::cout << std::to_string(iid3) << std::endl;
assert(iid3.get_local() == ""); assert(std::to_string(iid3) == "%irc.example.org");
assert(iid3.get_server() == "irc.example.org"); assert(iid3.get_local() == "");
assert(iid3.is_channel); assert(iid3.get_server() == "irc.example.org");
assert(!iid3.is_user); assert(iid3.is_channel);
assert(!iid3.is_user);
Iid iid4("irc.example.org");
std::cout << std::to_string(iid4) << std::endl; Iid iid4("irc.example.org");
assert(std::to_string(iid4) == "irc.example.org"); std::cout << std::to_string(iid4) << std::endl;
assert(iid4.get_local() == ""); assert(std::to_string(iid4) == "irc.example.org");
assert(iid4.get_server() == "irc.example.org"); assert(iid4.get_local() == "");
assert(!iid4.is_channel); assert(iid4.get_server() == "irc.example.org");
assert(!iid4.is_user); assert(!iid4.is_channel);
assert(!iid4.is_user);
Iid iid5("nick!");
std::cout << std::to_string(iid5) << std::endl;
assert(std::to_string(iid5) == "nick!");
assert(iid5.get_local() == "nick");
assert(iid5.get_server() == "");
assert(!iid5.is_channel);
assert(iid5.is_user);
Iid iid6("##channel%");
std::cout << std::to_string(iid6) << std::endl;
assert(std::to_string(iid6) == "##channel%");
assert(iid6.get_local() == "##channel");
assert(iid6.get_server() == "");
assert(iid6.is_channel);
assert(!iid6.is_user);
}
{
std::cout << color << "Testing IID parsing with a fixed server configured…" << reset << std::endl;
// Now do the same tests, but with a configured fixed_irc_server
Config::set("fixed_irc_server", "fixed.example.com", false);
Iid iid1("foo!irc.example.org");
std::cout << std::to_string(iid1) << std::endl;
assert(std::to_string(iid1) == "foo!");
assert(iid1.get_local() == "foo");
assert(iid1.get_server() == "fixed.example.com");
assert(!iid1.is_channel);
assert(iid1.is_user);
Iid iid2("#test%irc.example.org");
std::cout << std::to_string(iid2) << std::endl;
assert(std::to_string(iid2) == "#test");
assert(iid2.get_local() == "#test");
assert(iid2.get_server() == "fixed.example.com");
assert(iid2.is_channel);
assert(!iid2.is_user);
// Note that it is impossible to adress the XMPP server directly, or to
// use the virtual channel, in that mode
// Iid iid3("%irc.example.org");
// Iid iid4("irc.example.org");
Iid iid5("nick!");
std::cout << std::to_string(iid5) << std::endl;
assert(std::to_string(iid5) == "nick!");
assert(iid5.get_local() == "nick");
assert(iid5.get_server() == "fixed.example.com");
assert(!iid5.is_channel);
assert(iid5.is_user);
Iid iid6("##channel%");
std::cout << std::to_string(iid6) << std::endl;
assert(std::to_string(iid6) == "##channel");
assert(iid6.get_local() == "##channel");
assert(iid6.get_server() == "fixed.example.com");
assert(iid6.is_channel);
assert(!iid6.is_user);
}
return 0; return 0;
} }
// #include <utils/empty_if_fixed_server.hpp>
// #include <config/config.hpp>
// namespace utils
// {
// inline std::string empty_if_fixed_server(std::string&& str)
// }
#ifndef EMPTY_IF_FIXED_SERVER_HPP_INCLUDED
#define EMPTY_IF_FIXED_SERVER_HPP_INCLUDED
#include <string>
#include <config/config.hpp>
namespace utils
{
inline std::string empty_if_fixed_server(std::string&& str)
{
if (!Config::get("fixed_irc_server", "").empty())
return {};
return str;
}
inline std::string empty_if_fixed_server(const std::string& str)
{
if (!Config::get("fixed_irc_server", "").empty())
return {};
return str;
}
}
#endif /* EMPTY_IF_FIXED_SERVER_HPP_INCLUDED */
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