summaryrefslogtreecommitdiff
path: root/src/irc
diff options
context:
space:
mode:
Diffstat (limited to 'src/irc')
-rw-r--r--src/irc/iid.cpp62
-rw-r--r--src/irc/iid.hpp63
-rw-r--r--src/irc/irc_client.cpp61
3 files changed, 138 insertions, 48 deletions
diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp
index 4694c0c..4893e9e 100644
--- a/src/irc/iid.cpp
+++ b/src/irc/iid.cpp
@@ -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():
+ 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;
}
-Iid::Iid()
+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();
+ }
}
diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp
index a62ac71..2302a18 100644
--- a/src/irc/iid.hpp
+++ b/src/irc/iid.hpp
@@ -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
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index c3765a6..6e22980 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -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)