diff options
Diffstat (limited to 'src/irc')
-rw-r--r-- | src/irc/iid.cpp | 109 | ||||
-rw-r--r-- | src/irc/iid.hpp | 58 | ||||
-rw-r--r-- | src/irc/irc_client.cpp | 26 | ||||
-rw-r--r-- | src/irc/irc_client.hpp | 3 |
4 files changed, 105 insertions, 91 deletions
diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 0e2841e..c951a49 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -1,62 +1,70 @@ #include <utils/tolower.hpp> #include <config/config.hpp> - +#include <bridge/bridge.hpp> #include <irc/iid.hpp> #include <utils/encoding.hpp> -Iid::Iid(const std::string& iid): - is_channel(false), - is_user(false) +Iid::Iid(const std::string local, const std::string server, Iid::Type type): + type(type), + local(local), + server(server) { - 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); } +Iid::Iid(const std::string& iid, const std::set<char>& chantypes) +{ + this->init(iid); + this->set_type(std::set<char>(chantypes)); +} -void Iid::init(const std::string& iid) +Iid::Iid(const std::string& iid, const std::initializer_list<char>& chantypes): + Iid(iid, std::set<char>(chantypes)) { - const std::string::size_type sep = iid.find_first_of("%!"); - if (sep != std::string::npos) - { - if (iid[sep] == '%') - this->is_channel = true; - else - this->is_user = true; - this->set_local(iid.substr(0, sep)); - this->set_server(iid.substr(sep + 1)); - } - else - this->set_server(iid); } -void Iid::init_with_fixed_server(const std::string& iid, const std::string& hostname) +Iid::Iid(const std::string& iid, const Bridge *bridge) +{ + this->init(iid); + const auto chantypes = bridge->get_chantypes(this->server); + this->set_type(chantypes); +} + +void Iid::set_type(const std::set<char>& chantypes) { - this->set_server(hostname); + if (this->local.empty()) + return; - const std::string::size_type sep = iid.find("!"); + if (chantypes.count(this->local[0]) == 1) + this->type = Iid::Type::Channel; + else + this->type = Iid::Type::User; +} - // Without any separator, we consider that it's a channel - if (sep == std::string::npos) +void Iid::init(const std::string& iid) +{ + const std::string fixed_irc_server = Config::get("fixed_irc_server", ""); + + if (fixed_irc_server.empty()) + { + const std::string::size_type sep = iid.find('%'); + if (sep != std::string::npos) { - this->is_channel = true; - this->set_local(iid); + this->set_local(iid.substr(0, sep)); + this->set_server(iid.substr(sep + 1)); + this->type = Iid::Type::Channel; } - else // A separator can be present to differenciate a channel from a user, - // but the part behind it (the hostname) is ignored + else { - this->set_local(iid.substr(0, sep)); - this->is_user = true; + this->set_server(iid); + this->type = Iid::Type::Server; } -} - -Iid::Iid(): - is_channel(false), - is_user(false) -{ + } + else + { + this->set_server(fixed_irc_server); + this->set_local(iid); + } } void Iid::set_local(const std::string& loc) @@ -88,27 +96,18 @@ const std::string& Iid::get_server() const return this->server; } -std::string Iid::get_sep() const -{ - if (this->is_channel) - return "%"; - else if (this->is_user) - return "!"; - return ""; -} - namespace std { const std::string to_string(const Iid& iid) { if (Config::get("fixed_irc_server", "").empty()) - return iid.get_encoded_local() + iid.get_sep() + iid.get_server(); + { + if (iid.type == Iid::Type::Server) + return iid.get_server(); + else + return iid.get_encoded_local() + iid.separator + iid.get_server(); + } else - { - if (iid.get_sep() == "!") - return iid.get_encoded_local() + iid.get_sep(); - else - return iid.get_encoded_local(); - } + return iid.get_encoded_local(); } } diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index 3b11470..7361c51 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -2,48 +2,64 @@ #include <string> +#include <set> + +class Bridge; /** * A name representing an IRC channel on an IRC server, or an IRC user on an * IRC server, or just an IRC server. * - * The separator for an user is '!', for a channel it's '%'. If no separator - * is present, it's just an irc server. + * The separator is '%' between the local part (nickname or channel) and the + * server part. If no separator is present, it's just an irc server. + * If it is present, the first character of the local part determines if it’s + * a channel or a user: ff the local part is empty or if its first character + * is part of the chantypes characters, then it’s a channel, otherwise it’s + * a user. + * * It’s possible to have an empty-string server, but it makes no sense in - * the biboumi context. + * biboumi’s context. + * + * 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) * - server: "irc.example.org" - * - is_channel: true - * - is_user: false + * - type: channel * * %irc.example.org: * - local: "" * - server: "irc.example.org" - * - is_channel: true - * - is_user: false - * Note: this is the special empty-string channel, used internal in biboumi + * - type: channel + * Note: this is the special empty-string channel, used internally in biboumi * but has no meaning on IRC. * - * foo!irc.example.org + * foo%irc.example.org * - local: "foo" * - server: "irc.example.org" - * - is_channel: false - * - is_user: true - * Note: the empty-string user (!irc.example.org) has no special meaning in biboumi + * - type: user + * Note: the empty-string user (!irc.example.org) makes no sense for biboumi * * irc.example.org: * - local: "" * - server: "irc.example.org" - * - is_channel: false - * - is_user: false + * - type: server */ class Iid { public: - Iid(const std::string& iid); - Iid(); + enum class Type + { + Channel, + User, + Server, + }; + static constexpr auto separator = "%"; + Iid(const std::string& iid, const std::set<char>& chantypes); + Iid(const std::string& iid, const std::initializer_list<char>& chantypes); + Iid(const std::string& iid, const Bridge* bridge); + Iid(const std::string local, const std::string server, Type type); + Iid() = default; Iid(const Iid&) = default; Iid(Iid&&) = delete; @@ -52,21 +68,19 @@ public: void set_local(const std::string& loc); void set_server(const std::string& serv); + const std::string& get_local() const; const std::string get_encoded_local() const; const std::string& get_server() const; - bool is_channel; - bool is_user; - - std::string get_sep() const; - std::tuple<std::string, std::string> to_tuple() const; + Type type { Type::Server }; + private: void init(const std::string& iid); - void init_with_fixed_server(const std::string& iid, const std::string& hostname); + void set_type(const std::set<char>& chantypes); std::string local; std::string server; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index dd83307..d00b6ee 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -213,7 +213,7 @@ void IrcClient::on_connection_failed(const std::string& reason) // Send an error message for all room that the user wanted to join for (const auto& tuple: this->channels_to_join) { - Iid iid(std::get<0>(tuple) + "%" + this->hostname); + Iid iid(std::get<0>(tuple) + "%" + this->hostname, this->chantypes); this->bridge.send_presence_error(iid, this->current_nick, "cancel", "item-not-found", "", reason); @@ -551,7 +551,7 @@ void IrcClient::on_notice(const IrcMessage& message) if (this->nicks_to_treat_as_private.find(nick) != this->nicks_to_treat_as_private.end()) { // We previously sent a message to that nick) - this->bridge.send_message({nick + "!" + this->hostname}, nick, body, + this->bridge.send_message({nick, this->hostname, Iid::Type::User}, nick, body, false); } else @@ -663,12 +663,12 @@ void IrcClient::on_channel_message(const IrcMessage& message) bool muc = true; if (!this->get_channel(iid.get_local())->joined) { - iid.is_user = true; + iid.type = Iid::Type::User; iid.set_local(nick); muc = false; } else - iid.is_channel = true; + iid.type = Iid::Type::Channel; if (!body.empty() && body[0] == '\01') { if (body.substr(1, 6) == "ACTION") @@ -780,7 +780,7 @@ void IrcClient::on_nickname_conflict(const IrcMessage& message) Iid iid; iid.set_local(it->first); iid.set_server(this->hostname); - iid.is_channel = true; + iid.type = Iid::Type::Channel; this->bridge.send_nickname_conflict_error(iid, nickname); } } @@ -797,7 +797,7 @@ void IrcClient::on_nickname_change_too_fast(const IrcMessage& message) Iid iid; iid.set_local(it->first); iid.set_server(this->hostname); - iid.is_channel = true; + iid.type = Iid::Type::Channel; this->bridge.send_presence_error(iid, nickname, "cancel", "not-acceptable", "", txt); @@ -858,7 +858,7 @@ void IrcClient::on_part(const IrcMessage& message) Iid iid; iid.set_local(chan_name); iid.set_server(this->hostname); - iid.is_channel = true; + iid.type = Iid::Type::Channel; bool self = channel->get_self()->nick == nick; if (self) { @@ -880,7 +880,7 @@ void IrcClient::on_error(const IrcMessage& message) Iid iid; iid.set_local(it->first); iid.set_server(this->hostname); - iid.is_channel = true; + iid.type = Iid::Type::Channel; IrcChannel* channel = it->second.get(); if (!channel->joined) continue; @@ -908,7 +908,7 @@ void IrcClient::on_quit(const IrcMessage& message) Iid iid; iid.set_local(chan_name); iid.set_server(this->hostname); - iid.is_channel = true; + iid.type = Iid::Type::Channel; this->bridge.send_muc_leave(std::move(iid), std::move(nick), txt, false); } } @@ -928,7 +928,7 @@ void IrcClient::on_nick(const IrcMessage& message) Iid iid; iid.set_local(chan_name); iid.set_server(this->hostname); - iid.is_channel = true; + iid.type = Iid::Type::Channel; const bool self = channel->get_self()->nick == old_nick; const char user_mode = user->get_most_significant_mode(this->sorted_user_modes); this->bridge.send_nick_change(std::move(iid), old_nick, new_nick, user_mode, self); @@ -956,7 +956,7 @@ void IrcClient::on_kick(const IrcMessage& message) Iid iid; iid.set_local(chan_name); iid.set_server(this->hostname); - iid.is_channel = true; + iid.type = Iid::Type::Channel; this->bridge.kick_muc_user(std::move(iid), target, reason, author.nick); } @@ -976,7 +976,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message) Iid iid; iid.set_local(message.arguments[0]); iid.set_server(this->hostname); - iid.is_channel = true; + iid.type = Iid::Type::Channel; IrcUser user(message.prefix); std::string mode_arguments; for (size_t i = 1; i < message.arguments.size(); ++i) @@ -1105,7 +1105,7 @@ void IrcClient::leave_dummy_channel(const std::string& exit_message) this->dummy_channel.joined = false; this->dummy_channel.joining = false; this->dummy_channel.remove_all_users(); - this->bridge.send_muc_leave(Iid("%"s + this->hostname), std::string(this->current_nick), exit_message, true); + this->bridge.send_muc_leave(Iid("%"s + this->hostname, this->chantypes), std::string(this->current_nick), exit_message, true); } #ifdef BOTAN_FOUND diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index fc3918e..fa35e65 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -280,8 +280,9 @@ public: const Resolver& get_resolver() const { return this->dns_resolver; } - const std::vector<char>& get_sorted_user_modes() const { return sorted_user_modes; } + const std::vector<char>& get_sorted_user_modes() const { return this->sorted_user_modes; } + std::set<char> get_chantypes() const { return this->chantypes; } private: /** * The hostname of the server we are connected to. |