From 2df0ebf2dfed1dcbf80c92bff8361e2a04581bec Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 25 Feb 2015 18:35:30 +0100 Subject: 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 --- doc/biboumi.1.md | 14 ++++ src/bridge/bridge.cpp | 9 +-- src/irc/iid.cpp | 44 ++++++++++++- src/irc/iid.hpp | 4 ++ src/test.cpp | 126 +++++++++++++++++++++++++++--------- src/utils/empty_if_fixed_server.cpp | 8 +++ src/utils/empty_if_fixed_server.hpp | 26 ++++++++ 7 files changed, 194 insertions(+), 37 deletions(-) create mode 100644 src/utils/empty_if_fixed_server.cpp create mode 100644 src/utils/empty_if_fixed_server.hpp diff --git a/doc/biboumi.1.md b/doc/biboumi.1.md index 18df220..9e95139 100644 --- a/doc/biboumi.1.md +++ b/doc/biboumi.1.md @@ -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 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` A filename into which logs are written. If none is provided, the logs are diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index fc00c8c..e312345 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -542,13 +543,13 @@ void Bridge::send_user_join(const std::string& hostname, std::string role; 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); } 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) @@ -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) { - 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, @@ -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 // 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)); + 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) diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 0bb991f..d4dc8ce 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -1,10 +1,21 @@ #include +#include #include Iid::Iid(const std::string& iid): is_channel(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("%!"); if (sep != std::string::npos) @@ -20,6 +31,29 @@ Iid::Iid(const std::string& 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): is_channel(other.is_channel), is_user(other.is_user), @@ -66,6 +100,14 @@ std::string Iid::get_sep() const namespace std { 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(); + } } } diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index d30cbaa..91779b2 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -57,6 +57,10 @@ public: std::string get_sep() const; 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 server; diff --git a/src/test.cpp b/src/test.cpp index a4371b2..9fa2c99 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -303,38 +303,100 @@ int main() /** * IID parsing */ - std::cout << color << "Testing IID parsing…" << reset << std::endl; - Iid iid1("foo!irc.example.org"); - std::cout << std::to_string(iid1) << std::endl; - assert(std::to_string(iid1) == "foo!irc.example.org"); - assert(iid1.get_local() == "foo"); - assert(iid1.get_server() == "irc.example.org"); - 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%irc.example.org"); - assert(iid2.get_local() == "#test"); - assert(iid2.get_server() == "irc.example.org"); - assert(iid2.is_channel); - assert(!iid2.is_user); - - Iid iid3("%irc.example.org"); - std::cout << std::to_string(iid3) << std::endl; - assert(std::to_string(iid3) == "%irc.example.org"); - assert(iid3.get_local() == ""); - assert(iid3.get_server() == "irc.example.org"); - assert(iid3.is_channel); - assert(!iid3.is_user); - - Iid iid4("irc.example.org"); - std::cout << std::to_string(iid4) << std::endl; - assert(std::to_string(iid4) == "irc.example.org"); - assert(iid4.get_local() == ""); - assert(iid4.get_server() == "irc.example.org"); - assert(!iid4.is_channel); - assert(!iid4.is_user); + { + std::cout << color << "Testing IID parsing…" << reset << std::endl; + Iid iid1("foo!irc.example.org"); + std::cout << std::to_string(iid1) << std::endl; + assert(std::to_string(iid1) == "foo!irc.example.org"); + assert(iid1.get_local() == "foo"); + assert(iid1.get_server() == "irc.example.org"); + 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%irc.example.org"); + assert(iid2.get_local() == "#test"); + assert(iid2.get_server() == "irc.example.org"); + assert(iid2.is_channel); + assert(!iid2.is_user); + + Iid iid3("%irc.example.org"); + std::cout << std::to_string(iid3) << std::endl; + assert(std::to_string(iid3) == "%irc.example.org"); + assert(iid3.get_local() == ""); + assert(iid3.get_server() == "irc.example.org"); + assert(iid3.is_channel); + assert(!iid3.is_user); + + Iid iid4("irc.example.org"); + std::cout << std::to_string(iid4) << std::endl; + assert(std::to_string(iid4) == "irc.example.org"); + assert(iid4.get_local() == ""); + assert(iid4.get_server() == "irc.example.org"); + 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; } diff --git a/src/utils/empty_if_fixed_server.cpp b/src/utils/empty_if_fixed_server.cpp new file mode 100644 index 0000000..85fd86d --- /dev/null +++ b/src/utils/empty_if_fixed_server.cpp @@ -0,0 +1,8 @@ +// #include + +// #include + +// namespace utils +// { +// inline std::string empty_if_fixed_server(std::string&& str) +// } diff --git a/src/utils/empty_if_fixed_server.hpp b/src/utils/empty_if_fixed_server.hpp new file mode 100644 index 0000000..8739fd9 --- /dev/null +++ b/src/utils/empty_if_fixed_server.hpp @@ -0,0 +1,26 @@ +#ifndef EMPTY_IF_FIXED_SERVER_HPP_INCLUDED +#define EMPTY_IF_FIXED_SERVER_HPP_INCLUDED + +#include + +#include + +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 */ -- cgit v1.2.3 From c307df85c8e7d9bcd4570269bf13c3e92c3f5954 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 25 Feb 2015 19:05:04 +0100 Subject: Do not handle the "%" char in a special way, in the fixed_server mode Also fix some doc --- doc/biboumi.1.md | 22 +++++++++++++--------- src/irc/iid.cpp | 5 +---- src/test.cpp | 10 +++++----- src/utils/empty_if_fixed_server.cpp | 8 -------- 4 files changed, 19 insertions(+), 26 deletions(-) delete mode 100644 src/utils/empty_if_fixed_server.cpp diff --git a/doc/biboumi.1.md b/doc/biboumi.1.md index 9e95139..3fd5a25 100644 --- a/doc/biboumi.1.md +++ b/doc/biboumi.1.md @@ -63,15 +63,19 @@ The configuration file uses a simple format of the form 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. + server only. This means that a JID like "#chan@biboumi.example.com" must + be used instead of "#chan%irc.example.org@biboumi.example.com". 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"). On the other hand, the '%' lose + any meaning. It can appear in the JID but will not be interpreted as a + separator (thus the JID "#channel%hello@biboumi.example.com" points to the + channel named "#channel%hello" on the configured IRC server) 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, while forbidding + access to any other IRC server. `log_file` diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index d4dc8ce..9d39129 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -35,7 +35,7 @@ void Iid::init_with_fixed_server(const std::string& iid, const std::string& host { this->set_server(hostname); - const std::string::size_type sep = iid.find_first_of("%!"); + const std::string::size_type sep = iid.find("!"); // Without any separator, we consider that it's a channel if (sep == std::string::npos) @@ -47,9 +47,6 @@ void Iid::init_with_fixed_server(const std::string& iid, const std::string& host // 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; } } diff --git a/src/test.cpp b/src/test.cpp index 9fa2c99..553140f 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -369,13 +369,13 @@ int main() 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(std::to_string(iid2) == "#test%irc.example.org"); + assert(iid2.get_local() == "#test%irc.example.org"); 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 + // Note that it is impossible to adress the IRC server directly, or to // use the virtual channel, in that mode // Iid iid3("%irc.example.org"); @@ -391,8 +391,8 @@ int main() Iid iid6("##channel%"); std::cout << std::to_string(iid6) << std::endl; - assert(std::to_string(iid6) == "##channel"); - assert(iid6.get_local() == "##channel"); + 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); diff --git a/src/utils/empty_if_fixed_server.cpp b/src/utils/empty_if_fixed_server.cpp deleted file mode 100644 index 85fd86d..0000000 --- a/src/utils/empty_if_fixed_server.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// #include - -// #include - -// namespace utils -// { -// inline std::string empty_if_fixed_server(std::string&& str) -// } -- cgit v1.2.3