Rewrite the whole IID usage
IRC users and channels are now distinguished by the separator used in the IID (% or !). ref #2468
This commit is contained in:
+26
-10
@@ -101,11 +101,12 @@ signal again or if a 2 seconds delay has passed.
|
||||
### Addressing
|
||||
|
||||
IRC entities are represented by XMPP JIDs. The domain part of the JID is
|
||||
the domain served by biboumi, and the local part depends on the concerned
|
||||
entity.
|
||||
the domain served by biboumi (the part after the `@`, biboumi.example.com in
|
||||
the examples), and the local part (the part before the `@`) depends on the
|
||||
concerned entity.
|
||||
|
||||
IRC channels and IRC users JIDs have a localpart formed like this:
|
||||
`name`, the `'%'` separator and the `irc_server`.
|
||||
IRC channels have a local part formed like this:
|
||||
`channel_name`%`irc_server`.
|
||||
|
||||
If the IRC channel you want to adress starts with the `'#'` character (or an
|
||||
other character, announced by the IRC server, like `'&'`, `'+'` or `'!'`),
|
||||
@@ -113,12 +114,16 @@ then you must include it in the JID. Some other gateway implementations, as
|
||||
well as some IRC clients, do not require them to be started by one of these
|
||||
characters, adding an implicit `'#'` in that case. Biboumi does not do that
|
||||
because this gets confusing when trying to understand the difference between
|
||||
the channels *#foo*, and *##foo*.
|
||||
the channels *#foo*, and *##foo*. Note that biboumi does not use the
|
||||
presence of these special characters to identify an IRC channel, only the
|
||||
presence of the separator `%` is used for that.
|
||||
|
||||
The name part can also be empty (for example `%irc.example.com`), in that
|
||||
The channel name can also be empty (for example `%irc.example.com`), in that
|
||||
case this represents the virtual channel provided by biboumi. See *Connect
|
||||
to an IRC server* for more details.
|
||||
|
||||
IRC users have a local part formed like this:
|
||||
`user_name`!`irc_server`.
|
||||
|
||||
On XMPP, the node part of the JID can only be lowercase. On the other hand,
|
||||
IRC nicknames are case-insensitive, this means that the nicknames toto,
|
||||
@@ -131,7 +136,7 @@ Examples:
|
||||
irc.example.com IRC server, and this is served by the biboumi instance on
|
||||
biboumi.example.com
|
||||
|
||||
`toto%irc.example.com@biboumi.example.com` is the IRC user named toto, or
|
||||
`toto!irc.example.com@biboumi.example.com` is the IRC user named toto, or
|
||||
TotO, etc.
|
||||
|
||||
`irc.example.com@biboumi.example.com` is the IRC server irc.example.com.
|
||||
@@ -139,9 +144,20 @@ Examples:
|
||||
`%irc.example.com@biboumi.example.com` is the virtual channel provided by
|
||||
biboumi, for the IRC server irc.example.com.
|
||||
|
||||
If compiled with Libidn, an IRC user has a bare JID representing the
|
||||
“hostname” provided by the IRC server. This JID can only be used to set IRC
|
||||
modes (for example to ban a user based on its IP), or to identify user.
|
||||
Note: Some JIDs are valid but make no sense in the context of
|
||||
biboumi:
|
||||
|
||||
`!irc.example.com@biboumi.example.com` is the empty-string nick on the
|
||||
irc.example.com server. It makes no sense to try to send messages to it.
|
||||
|
||||
`#test%@biboumi.example.com`, or any other JID that does not contain an
|
||||
IRC server is invalid. Any message to that kind of JID will trigger an
|
||||
error, or will be ignored.
|
||||
|
||||
If compiled with Libidn, an IRC channel participant has a bare JID
|
||||
representing the “hostname” provided by the IRC server. This JID can only
|
||||
be used to set IRC modes (for example to ban a user based on its IP), or to
|
||||
identify user. It cannot be used to contact that user using biboumi.
|
||||
|
||||
### Join an IRC channel
|
||||
|
||||
|
||||
+36
-36
@@ -106,8 +106,8 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname)
|
||||
|
||||
bool Bridge::join_irc_channel(const Iid& iid, const std::string& username)
|
||||
{
|
||||
IrcClient* irc = this->get_irc_client(iid.server, username);
|
||||
if (iid.chan.empty())
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server(), username);
|
||||
if (iid.get_local().empty())
|
||||
{ // Join the dummy channel
|
||||
if (irc->is_welcomed())
|
||||
{
|
||||
@@ -117,7 +117,7 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username)
|
||||
// joined the channel
|
||||
const IrcMessage join_message(irc->get_nick(), "JOIN", {""});
|
||||
irc->on_channel_join(join_message);
|
||||
const IrcMessage end_join_message(std::string(iid.server), "366",
|
||||
const IrcMessage end_join_message(std::string(iid.get_server()), "366",
|
||||
{irc->get_nick(),
|
||||
"", "End of NAMES list"});
|
||||
irc->on_channel_completely_joined(end_join_message);
|
||||
@@ -129,9 +129,9 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (irc->is_channel_joined(iid.chan) == false)
|
||||
if (irc->is_channel_joined(iid.get_local()) == false)
|
||||
{
|
||||
irc->send_join_command(iid.chan);
|
||||
irc->send_join_command(iid.get_local());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -139,15 +139,15 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username)
|
||||
|
||||
void Bridge::send_channel_message(const Iid& iid, const std::string& body)
|
||||
{
|
||||
if (iid.chan.empty() || iid.server.empty())
|
||||
if (iid.get_local().empty() || iid.get_server().empty())
|
||||
{
|
||||
log_warning("Cannot send message to channel: [" << iid.chan << "] on server [" << iid.server << "]");
|
||||
log_warning("Cannot send message to channel: [" << iid.get_local() << "] on server [" << iid.get_server() << "]");
|
||||
return;
|
||||
}
|
||||
IrcClient* irc = this->get_irc_client(iid.server);
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (!irc)
|
||||
{
|
||||
log_warning("Cannot send message: no client exist for server " << iid.server);
|
||||
log_warning("Cannot send message: no client exist for server " << iid.get_server());
|
||||
return;
|
||||
}
|
||||
// Because an IRC message cannot contain \n, we need to convert each line
|
||||
@@ -166,27 +166,27 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body)
|
||||
if (line.substr(0, 6) == "/mode ")
|
||||
{
|
||||
std::vector<std::string> args = utils::split(line.substr(6), ' ', false);
|
||||
irc->send_mode_command(iid.chan, args);
|
||||
irc->send_mode_command(iid.get_local(), args);
|
||||
continue; // We do not want to send that back to the
|
||||
// XMPP user, that’s not a textual message.
|
||||
}
|
||||
else if (line.substr(0, 4) == "/me ")
|
||||
irc->send_channel_message(iid.chan, action_prefix + line.substr(4) + "\01");
|
||||
irc->send_channel_message(iid.get_local(), action_prefix + line.substr(4) + "\01");
|
||||
else
|
||||
irc->send_channel_message(iid.chan, line);
|
||||
this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(),
|
||||
irc->send_channel_message(iid.get_local(), line);
|
||||
this->xmpp->send_muc_message(std::to_string(iid), irc->get_own_nick(),
|
||||
this->make_xmpp_body(line), this->user_jid);
|
||||
}
|
||||
}
|
||||
|
||||
void Bridge::send_private_message(const Iid& iid, const std::string& body, const std::string& type)
|
||||
{
|
||||
if (iid.chan.empty() || iid.server.empty())
|
||||
if (iid.get_local().empty() || iid.get_server().empty())
|
||||
return ;
|
||||
IrcClient* irc = this->get_irc_client(iid.server);
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (!irc)
|
||||
{
|
||||
log_warning("Cannot send message: no client exist for server " << iid.server);
|
||||
log_warning("Cannot send message: no client exist for server " << iid.get_server());
|
||||
return;
|
||||
}
|
||||
std::vector<std::string> lines = utils::split(body, '\n', true);
|
||||
@@ -195,38 +195,38 @@ void Bridge::send_private_message(const Iid& iid, const std::string& body, const
|
||||
for (const std::string& line: lines)
|
||||
{
|
||||
if (line.substr(0, 4) == "/me ")
|
||||
irc->send_private_message(iid.chan, action_prefix + line.substr(4) + "\01", type);
|
||||
irc->send_private_message(iid.get_local(), action_prefix + line.substr(4) + "\01", type);
|
||||
else
|
||||
irc->send_private_message(iid.chan, line, type);
|
||||
irc->send_private_message(iid.get_local(), line, type);
|
||||
}
|
||||
}
|
||||
|
||||
void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message)
|
||||
{
|
||||
IrcClient* irc = this->get_irc_client(iid.server);
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (irc)
|
||||
irc->send_part_command(iid.chan, status_message);
|
||||
irc->send_part_command(iid.get_local(), status_message);
|
||||
}
|
||||
|
||||
void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick)
|
||||
{
|
||||
IrcClient* irc = this->get_irc_client(iid.server);
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (irc)
|
||||
irc->send_nick_command(new_nick);
|
||||
}
|
||||
|
||||
void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason)
|
||||
{
|
||||
IrcClient* irc = this->get_irc_client(iid.server);
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (irc)
|
||||
irc->send_kick_command(iid.chan, target, reason);
|
||||
irc->send_kick_command(iid.get_local(), target, reason);
|
||||
}
|
||||
|
||||
void Bridge::set_channel_topic(const Iid& iid, const std::string& subject)
|
||||
{
|
||||
IrcClient* irc = this->get_irc_client(iid.server);
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (irc)
|
||||
irc->send_topic_command(iid.chan, subject);
|
||||
irc->send_topic_command(iid.get_local(), subject);
|
||||
}
|
||||
|
||||
void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, const std::string& os)
|
||||
@@ -239,22 +239,22 @@ void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, c
|
||||
void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc)
|
||||
{
|
||||
if (muc)
|
||||
this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick,
|
||||
this->xmpp->send_muc_message(std::to_string(iid), nick,
|
||||
this->make_xmpp_body(body), this->user_jid);
|
||||
else
|
||||
this->xmpp->send_message(iid.chan + "%" + iid.server,
|
||||
this->xmpp->send_message(std::to_string(iid),
|
||||
this->make_xmpp_body(body), this->user_jid, "chat");
|
||||
}
|
||||
|
||||
void Bridge::send_join_failed(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& text)
|
||||
{
|
||||
this->xmpp->send_presence_error(iid.chan + "%" + iid.server, nick, this->user_jid, type, condition, text);
|
||||
this->xmpp->send_presence_error(std::to_string(iid), nick, this->user_jid, type, condition, text);
|
||||
}
|
||||
|
||||
void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self)
|
||||
{
|
||||
this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->make_xmpp_body(message), this->user_jid, self);
|
||||
IrcClient* irc = this->get_irc_client(iid.server);
|
||||
this->xmpp->send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message), this->user_jid, self);
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (irc && irc->number_of_joined_channels() == 0)
|
||||
irc->send_quit_command("");
|
||||
}
|
||||
@@ -269,7 +269,7 @@ void Bridge::send_nick_change(Iid&& iid,
|
||||
std::string role;
|
||||
std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode);
|
||||
|
||||
this->xmpp->send_nick_change(std::move(iid.chan) + "%" + std::move(iid.server),
|
||||
this->xmpp->send_nick_change(std::to_string(iid),
|
||||
old_nick, new_nick, affiliation, role, this->user_jid, self);
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ void Bridge::send_topic(const std::string& hostname, const std::string& chan_nam
|
||||
|
||||
std::string Bridge::get_own_nick(const Iid& iid)
|
||||
{
|
||||
IrcClient* irc = this->get_irc_client(iid.server);
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (irc)
|
||||
return irc->get_own_nick();
|
||||
return "";
|
||||
@@ -322,12 +322,12 @@ size_t Bridge::active_clients() const
|
||||
|
||||
void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author)
|
||||
{
|
||||
this->xmpp->kick_user(iid.chan + "%" + iid.server, target, reason, author, this->user_jid);
|
||||
this->xmpp->kick_user(std::to_string(iid), target, reason, author, this->user_jid);
|
||||
}
|
||||
|
||||
void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname)
|
||||
{
|
||||
this->xmpp->send_nickname_conflict_error(iid.chan + "%" + iid.server, nickname, this->user_jid);
|
||||
this->xmpp->send_nickname_conflict_error(std::to_string(iid), nickname, this->user_jid);
|
||||
}
|
||||
|
||||
void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode)
|
||||
@@ -336,10 +336,10 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar
|
||||
std::string affiliation;
|
||||
|
||||
std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(mode);
|
||||
this->xmpp->send_affiliation_role_change(iid.chan + "%" + iid.server, target, affiliation, role, this->user_jid);
|
||||
this->xmpp->send_affiliation_role_change(std::to_string(iid), target, affiliation, role, this->user_jid);
|
||||
}
|
||||
|
||||
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 + "!" + hostname, this->user_jid);
|
||||
}
|
||||
|
||||
+52
-10
@@ -1,21 +1,63 @@
|
||||
#include <utils/tolower.hpp>
|
||||
|
||||
#include <irc/iid.hpp>
|
||||
|
||||
Iid::Iid(const std::string& iid)
|
||||
Iid::Iid(const std::string& iid):
|
||||
is_channel(false),
|
||||
is_user(false)
|
||||
{
|
||||
std::string::size_type sep = iid.find("%");
|
||||
const std::string::size_type sep = iid.find_first_of("%!");
|
||||
if (sep != std::string::npos)
|
||||
{
|
||||
this->chan = iid.substr(0, sep);
|
||||
sep++;
|
||||
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->chan = iid;
|
||||
return;
|
||||
}
|
||||
this->server = iid.substr(sep);
|
||||
this->set_server(iid);
|
||||
}
|
||||
|
||||
Iid::Iid()
|
||||
Iid::Iid():
|
||||
is_channel(false),
|
||||
is_user(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Iid::set_local(const std::string& loc)
|
||||
{
|
||||
this->local = utils::tolower(loc);
|
||||
}
|
||||
|
||||
void Iid::set_server(const std::string& serv)
|
||||
{
|
||||
this->server = utils::tolower(serv);
|
||||
}
|
||||
|
||||
const std::string& Iid::get_local() const
|
||||
{
|
||||
return this->local;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return iid.get_local() + iid.get_sep() + iid.get_server();
|
||||
}
|
||||
}
|
||||
|
||||
+50
-13
@@ -4,17 +4,40 @@
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* A name representing an IRC channel, on the same model than the XMPP JIDs (but much simpler).
|
||||
* The separator between the server and the channel name is '%'
|
||||
* #test%irc.freenode.org has :
|
||||
* - chan: "#test" (the # is part of the name, it could very well be absent, or & instead
|
||||
* - server: "irc.freenode.org"
|
||||
* #test has:
|
||||
* - chan: "#test"
|
||||
* - server: ""
|
||||
* %irc.freenode.org:
|
||||
* - chan: ""
|
||||
* - server: "irc.freenode.org"
|
||||
* 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.
|
||||
* It’s possible to have an empty-string server, but it makes no sense in
|
||||
* the biboumi context.
|
||||
*
|
||||
* #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
|
||||
*
|
||||
* %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
|
||||
* but has no meaning on IRC.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* irc.example.org:
|
||||
* - local: ""
|
||||
* - server: "irc.example.org"
|
||||
* - is_channel: false
|
||||
* - is_user: false
|
||||
*/
|
||||
class Iid
|
||||
{
|
||||
@@ -22,14 +45,28 @@ public:
|
||||
explicit Iid(const std::string& iid);
|
||||
explicit Iid();
|
||||
|
||||
std::string chan;
|
||||
std::string server;
|
||||
void set_local(const std::string& loc);
|
||||
void set_server(const std::string& serv);
|
||||
const std::string& get_local() const;
|
||||
const std::string& get_server() const;
|
||||
|
||||
bool is_channel;
|
||||
bool is_user;
|
||||
|
||||
std::string get_sep() const;
|
||||
|
||||
private:
|
||||
std::string local;
|
||||
std::string server;
|
||||
|
||||
Iid(const Iid&) = delete;
|
||||
Iid(Iid&&) = delete;
|
||||
Iid& operator=(const Iid&) = delete;
|
||||
Iid& operator=(Iid&&) = delete;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
const std::string to_string(const Iid& iid);
|
||||
}
|
||||
|
||||
#endif // IID_INCLUDED
|
||||
|
||||
+36
-25
@@ -102,10 +102,11 @@ void IrcClient::on_connection_close()
|
||||
log_warning(message);
|
||||
}
|
||||
|
||||
IrcChannel* IrcClient::get_channel(const std::string& name)
|
||||
IrcChannel* IrcClient::get_channel(const std::string& n)
|
||||
{
|
||||
if (name.empty())
|
||||
if (n.empty())
|
||||
return &this->dummy_channel;
|
||||
const std::string name = utils::tolower(n);
|
||||
try
|
||||
{
|
||||
return this->channels.at(name).get();
|
||||
@@ -382,15 +383,18 @@ void IrcClient::on_channel_message(const IrcMessage& message)
|
||||
const IrcUser user(message.prefix);
|
||||
const std::string nick = user.nick;
|
||||
Iid iid;
|
||||
iid.chan = utils::tolower(message.arguments[0]);
|
||||
iid.server = this->hostname;
|
||||
iid.set_local(message.arguments[0]);
|
||||
iid.set_server(this->hostname);
|
||||
const std::string body = message.arguments[1];
|
||||
bool muc = true;
|
||||
if (!this->get_channel(iid.chan)->joined)
|
||||
if (!this->get_channel(iid.get_local())->joined)
|
||||
{
|
||||
iid.chan = nick;
|
||||
iid.is_user = true;
|
||||
iid.set_local(nick);
|
||||
muc = false;
|
||||
}
|
||||
else
|
||||
iid.is_channel = true;
|
||||
if (!body.empty() && body[0] == '\01')
|
||||
{
|
||||
if (body.substr(1, 6) == "ACTION")
|
||||
@@ -460,8 +464,9 @@ void IrcClient::on_nickname_conflict(const IrcMessage& message)
|
||||
for (auto it = this->channels.begin(); it != this->channels.end(); ++it)
|
||||
{
|
||||
Iid iid;
|
||||
iid.chan = it->first;
|
||||
iid.server = this->hostname;
|
||||
iid.set_local(it->first);
|
||||
iid.set_server(this->hostname);
|
||||
iid.is_channel = true;
|
||||
this->bridge->send_nickname_conflict_error(iid, nickname);
|
||||
}
|
||||
}
|
||||
@@ -499,7 +504,7 @@ void IrcClient::on_welcome_message(const IrcMessage& message)
|
||||
|
||||
void IrcClient::on_part(const IrcMessage& message)
|
||||
{
|
||||
const std::string chan_name = utils::tolower(message.arguments[0]);
|
||||
const std::string chan_name = message.arguments[0];
|
||||
IrcChannel* channel = this->get_channel(chan_name);
|
||||
if (!channel->joined)
|
||||
return ;
|
||||
@@ -512,13 +517,14 @@ void IrcClient::on_part(const IrcMessage& message)
|
||||
std::string nick = user->nick;
|
||||
channel->remove_user(user);
|
||||
Iid iid;
|
||||
iid.chan = chan_name;
|
||||
iid.server = this->hostname;
|
||||
iid.set_local(chan_name);
|
||||
iid.set_server(this->hostname);
|
||||
iid.is_channel = true;
|
||||
bool self = channel->get_self()->nick == nick;
|
||||
if (self)
|
||||
{
|
||||
channel->joined = false;
|
||||
this->channels.erase(chan_name);
|
||||
this->channels.erase(utils::tolower(chan_name));
|
||||
// channel pointer is now invalid
|
||||
channel = nullptr;
|
||||
}
|
||||
@@ -533,8 +539,9 @@ void IrcClient::on_error(const IrcMessage& message)
|
||||
for (auto it = this->channels.begin(); it != this->channels.end(); ++it)
|
||||
{
|
||||
Iid iid;
|
||||
iid.chan = it->first;
|
||||
iid.server = this->hostname;
|
||||
iid.set_local(it->first);
|
||||
iid.set_server(this->hostname);
|
||||
iid.is_channel = true;
|
||||
IrcChannel* channel = it->second.get();
|
||||
if (!channel->joined)
|
||||
continue;
|
||||
@@ -560,8 +567,9 @@ void IrcClient::on_quit(const IrcMessage& message)
|
||||
std::string nick = user->nick;
|
||||
channel->remove_user(user);
|
||||
Iid iid;
|
||||
iid.chan = chan_name;
|
||||
iid.server = this->hostname;
|
||||
iid.set_local(chan_name);
|
||||
iid.set_server(this->hostname);
|
||||
iid.is_channel = true;
|
||||
this->bridge->send_muc_leave(std::move(iid), std::move(nick), txt, false);
|
||||
}
|
||||
}
|
||||
@@ -579,8 +587,9 @@ void IrcClient::on_nick(const IrcMessage& message)
|
||||
{
|
||||
std::string old_nick = user->nick;
|
||||
Iid iid;
|
||||
iid.chan = chan_name;
|
||||
iid.server = this->hostname;
|
||||
iid.set_local(chan_name);
|
||||
iid.set_server(this->hostname);
|
||||
iid.is_channel = true;
|
||||
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);
|
||||
@@ -606,8 +615,9 @@ void IrcClient::on_kick(const IrcMessage& message)
|
||||
channel->joined = false;
|
||||
IrcUser author(message.prefix);
|
||||
Iid iid;
|
||||
iid.chan = chan_name;
|
||||
iid.server = this->hostname;
|
||||
iid.set_local(chan_name);
|
||||
iid.set_server(this->hostname);
|
||||
iid.is_channel = true;
|
||||
this->bridge->kick_muc_user(std::move(iid), target, reason, author.nick);
|
||||
}
|
||||
|
||||
@@ -625,8 +635,9 @@ void IrcClient::on_channel_mode(const IrcMessage& message)
|
||||
// For now, just transmit the modes so the user can know what happens
|
||||
// TODO, actually interprete the mode.
|
||||
Iid iid;
|
||||
iid.chan = utils::tolower(message.arguments[0]);
|
||||
iid.server = this->hostname;
|
||||
iid.set_local(message.arguments[0]);
|
||||
iid.set_server(this->hostname);
|
||||
iid.is_channel = true;
|
||||
IrcUser user(message.prefix);
|
||||
std::string mode_arguments;
|
||||
for (size_t i = 1; i < message.arguments.size(); ++i)
|
||||
@@ -638,10 +649,10 @@ void IrcClient::on_channel_mode(const IrcMessage& message)
|
||||
mode_arguments += message.arguments[i];
|
||||
}
|
||||
}
|
||||
this->bridge->send_message(iid, "", "Mode "s + iid.chan +
|
||||
this->bridge->send_message(iid, "", "Mode "s + iid.get_local() +
|
||||
" [" + mode_arguments + "] by " + user.nick,
|
||||
true);
|
||||
const IrcChannel* channel = this->get_channel(iid.chan);
|
||||
const IrcChannel* channel = this->get_channel(iid.get_local());
|
||||
if (!channel)
|
||||
return;
|
||||
|
||||
@@ -695,7 +706,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message)
|
||||
if (!user)
|
||||
{
|
||||
log_warning("Trying to set mode for non-existing user '" << target
|
||||
<< "' in channel" << iid.chan);
|
||||
<< "' in channel" << iid.get_local());
|
||||
return;
|
||||
}
|
||||
if (add)
|
||||
|
||||
@@ -290,5 +290,41 @@ int main()
|
||||
std::cout << correctjid2 << std::endl;
|
||||
assert(correctjid2 == "zigougou@poez.io");
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ void XmppComponent::handle_presence(const Stanza& stanza)
|
||||
error_type, error_name, "");
|
||||
});
|
||||
|
||||
if (!iid.server.empty())
|
||||
if (iid.is_channel && !iid.get_server().empty())
|
||||
{ // presence toward a MUC that corresponds to an irc channel, or a
|
||||
// dummy channel if iid.chan is empty
|
||||
if (type.empty())
|
||||
@@ -353,7 +353,7 @@ void XmppComponent::handle_message(const Stanza& stanza)
|
||||
error_type, error_name, "");
|
||||
});
|
||||
XmlNode* body = stanza.get_child("body", COMPONENT_NS);
|
||||
if (type == "groupchat")
|
||||
if (type == "groupchat" && iid.is_channel)
|
||||
{
|
||||
if (to.resource.empty())
|
||||
if (body && !body->get_inner().empty())
|
||||
@@ -379,11 +379,13 @@ void XmppComponent::handle_message(const Stanza& stanza)
|
||||
if (kickable_error)
|
||||
bridge->shutdown("Error from remote client");
|
||||
}
|
||||
else if (type == "chat")
|
||||
else if (type == "chat" && iid.is_user && !iid.get_local().empty())
|
||||
{
|
||||
if (body && !body->get_inner().empty())
|
||||
bridge->send_private_message(iid, body->get_inner());
|
||||
}
|
||||
else if (iid.is_user)
|
||||
this->send_invalid_user_error(to.local, from);
|
||||
stanza_error.disable();
|
||||
}
|
||||
|
||||
@@ -671,6 +673,36 @@ void XmppComponent::send_invalid_room_error(const std::string& muc_name,
|
||||
this->send_stanza(presence);
|
||||
}
|
||||
|
||||
void XmppComponent::send_invalid_user_error(const std::string& user_name, const std::string& to)
|
||||
{
|
||||
Stanza message("message");
|
||||
message["from"] = user_name + "@" + this->served_hostname;
|
||||
message["to"] = to;
|
||||
message["type"] = "error";
|
||||
XmlNode x("x");
|
||||
x["xmlns"] = MUC_NS;
|
||||
x.close();
|
||||
message.add_child(std::move(x));
|
||||
XmlNode error("error");
|
||||
error["type"] = "cancel";
|
||||
XmlNode item_not_found("item-not-found");
|
||||
item_not_found["xmlns"] = STANZA_NS;
|
||||
item_not_found.close();
|
||||
error.add_child(std::move(item_not_found));
|
||||
XmlNode text("text");
|
||||
text["xmlns"] = STANZA_NS;
|
||||
text["xml:lang"] = "en";
|
||||
text.set_inner(user_name +
|
||||
" is not a valid IRC user name. A correct user jid is of the form: <nick>!<server>@" +
|
||||
this->served_hostname);
|
||||
text.close();
|
||||
error.add_child(std::move(text));
|
||||
error.close();
|
||||
message.add_child(std::move(error));
|
||||
message.close();
|
||||
this->send_stanza(message);
|
||||
}
|
||||
|
||||
void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to)
|
||||
{
|
||||
XmlNode message("message");
|
||||
@@ -711,7 +743,7 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str
|
||||
this->send_stanza(message);
|
||||
}
|
||||
|
||||
void XmppComponent::send_muc_leave(std::string&& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self)
|
||||
void XmppComponent::send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self)
|
||||
{
|
||||
Stanza presence("presence");
|
||||
presence["to"] = jid_to;
|
||||
|
||||
@@ -130,6 +130,12 @@ public:
|
||||
void send_invalid_room_error(const std::string& muc_jid,
|
||||
const std::string& nick,
|
||||
const std::string& to);
|
||||
/**
|
||||
* Send an error to indicate that the user tried to send a message to an
|
||||
* invalid user.
|
||||
*/
|
||||
void send_invalid_user_error(const std::string& user_name,
|
||||
const std::string& to);
|
||||
/**
|
||||
* Send the MUC topic to the user
|
||||
*/
|
||||
@@ -141,7 +147,7 @@ public:
|
||||
/**
|
||||
* Send an unavailable presence for this nick
|
||||
*/
|
||||
void send_muc_leave(std::string&& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self);
|
||||
void send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self);
|
||||
/**
|
||||
* Indicate that a participant changed his nick
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user