From 7cd4e06f84806ff039e454a0b0fa956069ee692f Mon Sep 17 00:00:00 2001 From: Link Mauve Date: Mon, 19 May 2025 10:57:37 +0200 Subject: [PATCH] Support all allowed channel prefixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RFC 2812 specifies in §1.3 that “Channels names are strings (beginning with a '&', '#', '+' or '!' character) of length up to fifty (50) characters.” We previously only allowed the first two prefix characters, or any other one if the server overrides the list with ISUPPORT. --- doc/user.rst | 5 +++-- src/bridge/bridge.cpp | 2 +- src/irc/iid.hpp | 2 +- src/irc/irc_client.cpp | 2 +- src/xmpp/biboumi_component.cpp | 10 +++++----- tests/iid.cpp | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/user.rst b/doc/user.rst index add3480..023036a 100644 --- a/doc/user.rst +++ b/doc/user.rst @@ -41,8 +41,9 @@ IRC channels and IRC users have a local part formed like this: ``name`` can be a channel name or an user nickname. The distinction between the two is based on the first character: by default, if the name starts with -``'#'`` or ``'&'`` (but this can be overridden by the server, using the -ISUPPORT extension) then it’s a channel name, otherwise this is a nickname. +``'&'``, ``'#'``, ``'+'`` or ``'!'`` (but this can be overridden by the server, +using the ISUPPORT extension) then it’s a channel name, otherwise this is a +nickname. There is two ways to address an IRC user, using a local part like this: ``nickname`` % ``irc_server`` or by using the in-room address of the diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 728a8d7..c826fe1 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1160,7 +1160,7 @@ std::set Bridge::get_chantypes(const std::string& hostname) const { IrcClient* irc = this->find_irc_client(hostname); if (!irc) - return {'#', '&'}; + return {'&', '#', '+', '!'}; return irc->get_chantypes(); } diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index 89f4797..ef8cce5 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -20,7 +20,7 @@ class Bridge; * It’s possible to have an empty-string server, but it makes no sense in * biboumi’s context. * - * Assuming the chantypes are '#' and '&': + * Assuming the chantypes are '&', '#', '+' and '!': * * #test%irc.example.org has : * - local: "#test" (the # is part of the name, it could very well be absent, or & (for example) instead) diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index ce1c945..72da2b4 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -155,7 +155,7 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, bridge(bridge), welcomed(false), chanmodes({"", "", "", ""}), - chantypes({'#', '&'}), + chantypes({'&', '#', '+', '!'}), tokens_bucket(this->get_throttle_limit(), 1s, [this]() { if (message_queue.empty()) return true; diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 3cfa9d0..725e714 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -482,7 +482,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) // Depending on the 'to' jid in the request, we use one adhoc // command handler or an other - Iid iid(to.local, {'#', '&'}); + Iid iid(to.local, {'&', '#', '+', '!'}); AdhocCommandsHandler* adhoc_handler; if (to.local.empty()) adhoc_handler = &this->adhoc_commands_handler; @@ -532,7 +532,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) const XmlNode* query; if ((query = stanza.get_child("query", DISCO_INFO_NS))) { // Disco info - Iid iid(to.local, {'#', '&'}); + Iid iid(to.local, {'&', '#', '+', '!'}); const std::string node = query->get_tag("node"); if (to_str == this->served_hostname) { @@ -736,7 +736,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) const XmlNode* query = stanza.get_child("query", MAM_NS); - Iid iid(to.local, {'#', '&'}); + Iid iid(to.local, {'&', '#', '+', '!'}); if (query && iid.type == Iid::Type::Channel && to.resource.empty()) { const std::string query_id = query->get_tag("queryid"); @@ -865,7 +865,7 @@ void BiboumiComponent::send_archived_message(const Database::MucLogLine& log_lin bool BiboumiComponent::handle_room_configuration_form_request(const std::string& from, const Jid& to, const std::string& id) { - Iid iid(to.local, {'#', '&'}); + Iid iid(to.local, {'&', '#', '+', '!'}); if (iid.type != Iid::Type::Channel || !to.resource.empty()) return false; @@ -887,7 +887,7 @@ bool BiboumiComponent::handle_room_configuration_form_request(const std::string& bool BiboumiComponent::handle_room_configuration_form(const XmlNode& query, const std::string &from, const Jid &to, const std::string &id) { - Iid iid(to.local, {'#', '&'}); + Iid iid(to.local, {'&', '#', '+', '!'}); if (iid.type != Iid::Type::Channel || !to.resource.empty()) return false; diff --git a/tests/iid.cpp b/tests/iid.cpp index 63b2ba3..d8f17ad 100644 --- a/tests/iid.cpp +++ b/tests/iid.cpp @@ -47,7 +47,7 @@ namespace Catch TEST_CASE("Iid creation") { - const std::set chantypes {'#', '&'}; + const std::set chantypes {'&', '#', '+', '!'}; Iid iid1("foo%irc.example.org", chantypes); CHECK(std::to_string(iid1) == "foo%irc.example.org"); CHECK(iid1.get_local() == "foo"); @@ -95,7 +95,7 @@ TEST_CASE("Iid creation in fixed_server mode") { Config::set("fixed_irc_server", "fixed.example.com", false); - const std::set chantypes {'#', '&'}; + const std::set chantypes {'&', '#', '+', '!'}; Iid iid1("foo%irc.example.org", chantypes); CHECK(std::to_string(iid1) == "foo%irc.example.org"); CHECK(iid1.get_local() == "foo%irc.example.org");