Don’t use ! as the separator for nicknames, use % instead
It’s now easier to use. The distinction between a nick and a channel name is based on the first character (by default it's '#' and '&'). The user doesn’t have to worry about which separator to use anymore. fix #3066
This commit is contained in:
+57
-58
@@ -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));
|
||||
}
|
||||
|
||||
Iid::Iid(const std::string& iid, const std::initializer_list<char>& chantypes):
|
||||
Iid(iid, std::set<char>(chantypes))
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (this->local.empty())
|
||||
return;
|
||||
|
||||
if (chantypes.count(this->local[0]) == 1)
|
||||
this->type = Iid::Type::Channel;
|
||||
else
|
||||
this->type = Iid::Type::User;
|
||||
}
|
||||
|
||||
void Iid::init(const std::string& iid)
|
||||
{
|
||||
const std::string::size_type sep = iid.find_first_of("%!");
|
||||
if (sep != std::string::npos)
|
||||
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)
|
||||
{
|
||||
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));
|
||||
this->type = Iid::Type::Channel;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->set_server(iid);
|
||||
this->type = Iid::Type::Server;
|
||||
}
|
||||
}
|
||||
else
|
||||
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("!");
|
||||
|
||||
// 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));
|
||||
this->is_user = true;
|
||||
}
|
||||
}
|
||||
|
||||
Iid::Iid():
|
||||
is_channel(false),
|
||||
is_user(false)
|
||||
{
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
-22
@@ -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;
|
||||
|
||||
+13
-13
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user