From 87aaacdb420341bf3619922332d58b95249971bc Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 3 Nov 2013 00:22:32 +0100 Subject: Rename libirc and libxmpp to irc and xmpp --- src/irc/irc_client.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ src/irc/irc_client.hpp | 60 +++++++++++++++++++++++++++++++++++++++++ src/irc/irc_message.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++ src/irc/irc_message.hpp | 28 +++++++++++++++++++ 4 files changed, 225 insertions(+) create mode 100644 src/irc/irc_client.cpp create mode 100644 src/irc/irc_client.hpp create mode 100644 src/irc/irc_message.cpp create mode 100644 src/irc/irc_message.hpp (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp new file mode 100644 index 0000000..83d1b0d --- /dev/null +++ b/src/irc/irc_client.cpp @@ -0,0 +1,72 @@ +#include +#include + +#include +#include + +IrcClient::IrcClient() +{ + std::cout << "IrcClient()" << std::endl; +} + +IrcClient::~IrcClient() +{ + std::cout << "~IrcClient()" << std::endl; +} + +void IrcClient::on_connected() +{ +} + +void IrcClient::on_connection_close() +{ + std::cout << "Connection closed by remote server." << std::endl; + this->close(); +} + +void IrcClient::parse_in_buffer() +{ + while (true) + { + auto pos = this->in_buf.find("\r\n"); + if (pos == std::string::npos) + break ; + IrcMessage message(this->in_buf.substr(0, pos)); + this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); + std::cout << message << std::endl; + } +} + +void IrcClient::send_message(IrcMessage&& message) +{ + std::string res; + if (!message.prefix.empty()) + res += ":" + std::move(message.prefix) + " "; + res += std::move(message.command); + for (const std::string& arg: message.arguments) + { + if (arg.find(" ") != std::string::npos) + { + res += " :" + arg; + break; + } + res += " " + arg; + } + res += "\r\n"; + this->send_data(std::move(res)); +} + +void IrcClient::send_user_command(const std::string& username, const std::string& realname) +{ + this->send_message(IrcMessage("USER", {username, "NONE", "NONE", realname})); +} + +void IrcClient::send_nick_command(const std::string& nick) +{ + this->send_message(IrcMessage("NICK", {nick})); +} + +void IrcClient::send_join_command(const std::string& chan_name) +{ + this->send_message(IrcMessage("JOIN", {chan_name})); +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp new file mode 100644 index 0000000..e380f5b --- /dev/null +++ b/src/irc/irc_client.hpp @@ -0,0 +1,60 @@ +#ifndef IRC_CLIENT_INCLUDED +# define IRC_CLIENT_INCLUDED + +#include + +#include + +#include + +/** + * Represent one IRC client, i.e. an endpoint connected to a single IRC + * server, through a TCP socket, receiving and sending commands to it. + * + * TODO: TLS support, maybe, but that's not high priority + */ +class IrcClient: public SocketHandler +{ +public: + explicit IrcClient(); + ~IrcClient(); + /** + * Called when successfully connected to the server + */ + void on_connected(); + /** + * Close the connection, remove us from the poller + */ + void on_connection_close(); + /** + * Parse the data we have received so far and try to get one or more + * complete messages from it. + */ + void parse_in_buffer(); + /** + * Serialize the given message into a line, and send that into the socket + * (actually, into our out_buf and signal the poller that we want to wach + * for send events to be ready) + */ + void send_message(IrcMessage&& message); + /** + * Send the USER irc command + */ + void send_user_command(const std::string& username, const std::string& realname); + /** + * Send the NICK irc command + */ + void send_nick_command(const std::string& username); + /** + * Send the JOIN irc command + */ + void send_join_command(const std::string& chan_name); + +private: + IrcClient(const IrcClient&) = delete; + IrcClient(IrcClient&&) = delete; + IrcClient& operator=(const IrcClient&) = delete; + IrcClient& operator=(IrcClient&&) = delete; +}; + +#endif // IRC_CLIENT_INCLUDED diff --git a/src/irc/irc_message.cpp b/src/irc/irc_message.cpp new file mode 100644 index 0000000..18fa3ec --- /dev/null +++ b/src/irc/irc_message.cpp @@ -0,0 +1,65 @@ +#include +#include + +IrcMessage::IrcMessage(std::string&& line) +{ + std::string::size_type pos; + + // optional prefix + if (line[0] == ':') + { + pos = line.find(" "); + this->prefix = line.substr(1, pos); + line = line.substr(pos + 1, std::string::npos); + } + // command + pos = line.find(" "); + this->command = line.substr(0, pos); + line = line.substr(pos + 1, std::string::npos); + // arguments + do + { + if (line[0] == ':') + { + this->arguments.emplace_back(line.substr(1, std::string::npos)); + break ; + } + pos = line.find(" "); + this->arguments.emplace_back(line.substr(0, pos)); + line = line.substr(pos + 1, std::string::npos); + } while (pos != std::string::npos); +} + +IrcMessage::IrcMessage(std::string&& prefix, + std::string&& command, + std::vector&& args): + prefix(std::move(prefix)), + command(std::move(command)), + arguments(std::move(args)) +{ +} + +IrcMessage::IrcMessage(std::string&& command, + std::vector&& args): + prefix(), + command(std::move(command)), + arguments(std::move(args)) +{ +} + +IrcMessage::~IrcMessage() +{ +} + +std::ostream& operator<<(std::ostream& os, const IrcMessage& message) +{ + os << "IrcMessage"; + os << "[" << message.command << "]"; + for (const std::string& arg: message.arguments) + { + os << "{" << arg << "}"; + } + if (!message.prefix.empty()) + os << "(from: " << message.prefix << ")"; + return os; +} diff --git a/src/irc/irc_message.hpp b/src/irc/irc_message.hpp new file mode 100644 index 0000000..a0bd772 --- /dev/null +++ b/src/irc/irc_message.hpp @@ -0,0 +1,28 @@ +#ifndef IRC_MESSAGE_INCLUDED +# define IRC_MESSAGE_INCLUDED + +#include +#include +#include + +class IrcMessage +{ +public: + explicit IrcMessage(std::string&& line); + explicit IrcMessage(std::string&& prefix, std::string&& command, std::vector&& args); + explicit IrcMessage(std::string&& command, std::vector&& args); + ~IrcMessage(); + + std::string prefix; + std::string command; + std::vector arguments; + + IrcMessage(const IrcMessage&) = delete; + IrcMessage(IrcMessage&&) = delete; + IrcMessage& operator=(const IrcMessage&) = delete; + IrcMessage& operator=(IrcMessage&&) = delete; +}; + +std::ostream& operator<<(std::ostream& os, const IrcMessage& message); + +#endif // IRC_MESSAGE_INCLUDED -- cgit v1.2.3 From d834d6ed0647ba7e51e81f600fe259156e2b8070 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 3 Nov 2013 17:54:07 +0100 Subject: Exit the poller when it handles no connection at all --- src/irc/irc_client.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 83d1b0d..80f36ee 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -21,7 +21,6 @@ void IrcClient::on_connected() void IrcClient::on_connection_close() { std::cout << "Connection closed by remote server." << std::endl; - this->close(); } void IrcClient::parse_in_buffer() -- cgit v1.2.3 From bf7b05ef72bbdac97704d262ddfe418908267535 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 6 Nov 2013 20:51:05 +0100 Subject: Implement the Bridge class to translate between the two protocols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add all useful classes as well: Jid, Iid, IrcChannel, IrcUser etc to properly keep the informations about what we receive from the IRC server. Only handle the MUC join stanza, and send the list of users in the IRC channel to the XMPP user, and the IRC channel’s topic, for now. --- src/irc/iid.cpp | 17 ++++++++ src/irc/iid.hpp | 34 ++++++++++++++++ src/irc/irc_channel.cpp | 24 +++++++++++ src/irc/irc_channel.hpp | 34 ++++++++++++++++ src/irc/irc_client.cpp | 105 ++++++++++++++++++++++++++++++++++++++++++++++-- src/irc/irc_client.hpp | 60 ++++++++++++++++++++++++++- src/irc/irc_user.cpp | 24 +++++++++++ src/irc/irc_user.hpp | 24 +++++++++++ 8 files changed, 318 insertions(+), 4 deletions(-) create mode 100644 src/irc/iid.cpp create mode 100644 src/irc/iid.hpp create mode 100644 src/irc/irc_channel.cpp create mode 100644 src/irc/irc_channel.hpp create mode 100644 src/irc/irc_user.cpp create mode 100644 src/irc/irc_user.hpp (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp new file mode 100644 index 0000000..ffc8d88 --- /dev/null +++ b/src/irc/iid.cpp @@ -0,0 +1,17 @@ +#include + +Iid::Iid(const std::string& iid) +{ + std::string::size_type sep = iid.find("%"); + if (sep != std::string::npos) + { + this->chan = iid.substr(0, sep); + sep++; + } + else + { + this->chan = iid; + return; + } + this->server = iid.substr(sep); +} diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp new file mode 100644 index 0000000..aacc9e6 --- /dev/null +++ b/src/irc/iid.hpp @@ -0,0 +1,34 @@ +#ifndef IID_INCLUDED +# define IID_INCLUDED + +#include + +/** + * 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" + */ +class Iid +{ +public: + explicit Iid(const std::string& iid); + + std::string chan; + std::string server; + +private: + Iid(const Iid&) = delete; + Iid(Iid&&) = delete; + Iid& operator=(const Iid&) = delete; + Iid& operator=(Iid&&) = delete; +}; + +#endif // IID_INCLUDED diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp new file mode 100644 index 0000000..223305b --- /dev/null +++ b/src/irc/irc_channel.cpp @@ -0,0 +1,24 @@ +#include +#include + +IrcChannel::IrcChannel(): + joined(false), + self(nullptr) +{ +} + +void IrcChannel::set_self(const std::string& name) +{ + this->self = std::make_unique(name); +} + +IrcUser* IrcChannel::add_user(const std::string& name) +{ + this->users.emplace_back(std::make_unique(name)); + return this->users.back().get(); +} + +IrcUser* IrcChannel::get_self() const +{ + return this->self.get(); +} diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp new file mode 100644 index 0000000..da0f298 --- /dev/null +++ b/src/irc/irc_channel.hpp @@ -0,0 +1,34 @@ +#ifndef IRC_CHANNEL_INCLUDED +# define IRC_CHANNEL_INCLUDED + +#include +#include +#include +#include + +/** + * Keep the state of a joined channel (the list of occupants with their + * informations (mode, etc), the modes, etc) + */ +class IrcChannel +{ +public: + explicit IrcChannel(); + + bool joined; + std::string topic; + void set_self(const std::string& name); + IrcUser* get_self() const; + IrcUser* add_user(const std::string& name); + +private: + std::unique_ptr self; + std::vector> users; + + IrcChannel(const IrcChannel&) = delete; + IrcChannel(IrcChannel&&) = delete; + IrcChannel& operator=(const IrcChannel&) = delete; + IrcChannel& operator=(IrcChannel&&) = delete; +}; + +#endif // IRC_CHANNEL_INCLUDED diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 80f36ee..7875b1c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1,10 +1,18 @@ -#include #include +#include +#include +#include + +#include +#include #include #include -IrcClient::IrcClient() +IrcClient::IrcClient(const std::string& hostname, const std::string& username, Bridge* bridge): + hostname(hostname), + username(username), + bridge(bridge) { std::cout << "IrcClient()" << std::endl; } @@ -14,8 +22,15 @@ IrcClient::~IrcClient() std::cout << "~IrcClient()" << std::endl; } +void IrcClient::start() +{ + this->connect(this->hostname, "6667"); +} + void IrcClient::on_connected() { + this->send_nick_command(this->username); + this->send_user_command(this->username, this->username); } void IrcClient::on_connection_close() @@ -23,6 +38,19 @@ void IrcClient::on_connection_close() std::cout << "Connection closed by remote server." << std::endl; } +IrcChannel* IrcClient::get_channel(const std::string& name) +{ + try + { + return this->channels.at(name).get(); + } + catch (const std::out_of_range& exception) + { + this->channels.emplace(name, std::make_unique()); + return this->channels.at(name).get(); + } +} + void IrcClient::parse_in_buffer() { while (true) @@ -33,6 +61,21 @@ void IrcClient::parse_in_buffer() IrcMessage message(this->in_buf.substr(0, pos)); this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); std::cout << message << std::endl; + // TODO map function and command name properly + if (message.command == "PING") + this->send_pong_command(); + else if (message.command == "NOTICE" || + message.command == "375" || + message.command == "372") + this->forward_server_message(message); + else if (message.command == "JOIN") + this->on_self_channel_join(message); + else if (message.command == "353") + this->set_and_forward_user_list(message); + else if (message.command == "332") + this->on_topic_received(message); + else if (message.command == "366") + this->on_channel_completely_joined(message); } } @@ -52,6 +95,8 @@ void IrcClient::send_message(IrcMessage&& message) res += " " + arg; } res += "\r\n"; + std::cout << "=== IRC SENDING ===" << std::endl; + std::cout << res << std::endl; this->send_data(std::move(res)); } @@ -67,5 +112,59 @@ void IrcClient::send_nick_command(const std::string& nick) void IrcClient::send_join_command(const std::string& chan_name) { - this->send_message(IrcMessage("JOIN", {chan_name})); + IrcChannel* channel = this->get_channel(chan_name); + if (channel->joined == false) + this->send_message(IrcMessage("JOIN", {chan_name})); +} + +void IrcClient::send_pong_command() +{ + this->send_message(IrcMessage("PONG", {})); +} + +void IrcClient::forward_server_message(const IrcMessage& message) +{ + const std::string from = message.prefix; + const std::string body = message.arguments[1]; + + this->bridge->send_xmpp_message(this->hostname, from, body); +} + +void IrcClient::set_and_forward_user_list(const IrcMessage& message) +{ + const std::string chan_name = message.arguments[2]; + IrcChannel* channel = this->get_channel(chan_name); + std::vector nicks = utils::split(message.arguments[3], ' '); + for (const std::string& nick: nicks) + { + IrcUser* user = channel->add_user(nick); + if (user->nick != channel->get_self()->nick) + { + std::cout << "Adding user [" << nick << "] to chan " << chan_name << std::endl; + this->bridge->send_user_join(this->hostname, chan_name, user->nick); + } + } +} + +void IrcClient::on_self_channel_join(const IrcMessage& message) +{ + const std::string chan_name = message.arguments[0]; + IrcChannel* channel = this->get_channel(chan_name); + channel->joined = true; + channel->set_self(message.prefix); +} + +void IrcClient::on_topic_received(const IrcMessage& message) +{ + const std::string chan_name = message.arguments[1]; + IrcChannel* channel = this->get_channel(chan_name); + channel->topic = message.arguments[2]; +} + +void IrcClient::on_channel_completely_joined(const IrcMessage& message) +{ + const std::string chan_name = message.arguments[1]; + IrcChannel* channel = this->get_channel(chan_name); + this->bridge->send_self_join(this->hostname, chan_name, channel->get_self()->nick); + this->bridge->send_topic(this->hostname, chan_name, channel->topic); } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index e380f5b..db1b83b 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -2,11 +2,16 @@ # define IRC_CLIENT_INCLUDED #include +#include +#include #include +#include #include +class Bridge; + /** * Represent one IRC client, i.e. an endpoint connected to a single IRC * server, through a TCP socket, receiving and sending commands to it. @@ -16,8 +21,12 @@ class IrcClient: public SocketHandler { public: - explicit IrcClient(); + explicit IrcClient(const std::string& hostname, const std::string& username, Bridge* bridge); ~IrcClient(); + /** + * Connect to the IRC server + */ + void start(); /** * Called when successfully connected to the server */ @@ -31,12 +40,20 @@ public: * complete messages from it. */ void parse_in_buffer(); + /** + * Return the channel with this name, create it if it does not yet exist + */ + IrcChannel* get_channel(const std::string& name); /** * Serialize the given message into a line, and send that into the socket * (actually, into our out_buf and signal the poller that we want to wach * for send events to be ready) */ void send_message(IrcMessage&& message); + /** + * Send the PONG irc command + */ + void send_pong_command(); /** * Send the USER irc command */ @@ -49,8 +66,49 @@ public: * Send the JOIN irc command */ void send_join_command(const std::string& chan_name); + /** + * Forward the server message received from IRC to the XMPP component + */ + void forward_server_message(const IrcMessage& message); + /** + * Forward the join of an other user into an IRC channel, and save the + * IrcUsers in the IrcChannel + */ + void set_and_forward_user_list(const IrcMessage& message); + /** + * Remember our nick and host, when we are joined to the channel. The list + * of user comes after so we do not send the self-presence over XMPP yet. + */ + void on_self_channel_join(const IrcMessage& message); + /** + * Save the topic in the IrcChannel + */ + void on_topic_received(const IrcMessage& message); + /** + * The channel has been completely joined (self presence, topic, all names + * received etc), send the self presence and topic to the XMPP user. + */ + void on_channel_completely_joined(const IrcMessage& message); private: + /** + * The hostname of the server we are connected to. + */ + const std::string hostname; + /** + * The user name used in the USER irc command + */ + const std::string username; + /** + * Raw pointer because the bridge owns us. + */ + Bridge* bridge; + + /** + * The list of joined channels, indexed by name + */ + std::unordered_map> channels; + IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; IrcClient& operator=(const IrcClient&) = delete; diff --git a/src/irc/irc_user.cpp b/src/irc/irc_user.cpp new file mode 100644 index 0000000..fc853bc --- /dev/null +++ b/src/irc/irc_user.cpp @@ -0,0 +1,24 @@ +#include + +#include + +IrcUser::IrcUser(const std::string& name) +{ + const std::string::size_type sep = name.find("!"); + if (sep == std::string::npos) + { + if (name[0] == '@' || name[0] == '+') + this->nick = name.substr(1); + else + this->nick = name; + } + else + { + if (name[0] == '@' || name[0] == '+') + this->nick = name.substr(1, sep); + else + this->nick = name.substr(0, sep); + this->host = name.substr(sep+1); + } + std::cout << "Created user: [" << this->nick << "!" << this->host << std::endl; +} diff --git a/src/irc/irc_user.hpp b/src/irc/irc_user.hpp new file mode 100644 index 0000000..b76b2ef --- /dev/null +++ b/src/irc/irc_user.hpp @@ -0,0 +1,24 @@ +#ifndef IRC_USER_INCLUDED +# define IRC_USER_INCLUDED + +#include + +/** + * Keeps various information about one IRC channel user + */ +class IrcUser +{ +public: + explicit IrcUser(const std::string& name); + + std::string nick; + std::string host; + +private: + IrcUser(const IrcUser&) = delete; + IrcUser(IrcUser&&) = delete; + IrcUser& operator=(const IrcUser&) = delete; + IrcUser& operator=(IrcUser&&) = delete; +}; + +#endif // IRC_USER_INCLUDED -- cgit v1.2.3 From a418b6ed5d70f0e61e71bb1adce2a693ade89e30 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 7 Nov 2013 01:53:09 +0100 Subject: Send and receive messages Also correctly respond to PING with the id, escape some XML content, but not always --- src/irc/iid.cpp | 4 ++++ src/irc/iid.hpp | 1 + src/irc/irc_client.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++----- src/irc/irc_client.hpp | 32 +++++++++++++++++++++++++-- 4 files changed, 89 insertions(+), 7 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index ffc8d88..4694c0c 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -15,3 +15,7 @@ Iid::Iid(const std::string& iid) } this->server = iid.substr(sep); } + +Iid::Iid() +{ +} diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index aacc9e6..a62ac71 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -20,6 +20,7 @@ class Iid { public: explicit Iid(const std::string& iid); + explicit Iid(); std::string chan; std::string server; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 7875b1c..cf57bd7 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -12,7 +12,9 @@ IrcClient::IrcClient(const std::string& hostname, const std::string& username, Bridge* bridge): hostname(hostname), username(username), - bridge(bridge) + current_nick(username), + bridge(bridge), + welcomed(false) { std::cout << "IrcClient()" << std::endl; } @@ -51,6 +53,11 @@ IrcChannel* IrcClient::get_channel(const std::string& name) } } +std::string IrcClient::get_own_nick() const +{ + return this->current_nick; +} + void IrcClient::parse_in_buffer() { while (true) @@ -63,19 +70,23 @@ void IrcClient::parse_in_buffer() std::cout << message << std::endl; // TODO map function and command name properly if (message.command == "PING") - this->send_pong_command(); + this->send_pong_command(message); else if (message.command == "NOTICE" || message.command == "375" || message.command == "372") this->forward_server_message(message); else if (message.command == "JOIN") this->on_self_channel_join(message); + else if (message.command == "PRIVMSG") + this->on_channel_message(message); else if (message.command == "353") this->set_and_forward_user_list(message); else if (message.command == "332") this->on_topic_received(message); else if (message.command == "366") this->on_channel_completely_joined(message); + else if (message.command == "001") + this->on_welcome_message(message); } } @@ -102,7 +113,7 @@ void IrcClient::send_message(IrcMessage&& message) void IrcClient::send_user_command(const std::string& username, const std::string& realname) { - this->send_message(IrcMessage("USER", {username, "NONE", "NONE", realname})); + this->send_message(IrcMessage("USER", {username, "ignored", "ignored", realname})); } void IrcClient::send_nick_command(const std::string& nick) @@ -112,14 +123,32 @@ void IrcClient::send_nick_command(const std::string& nick) void IrcClient::send_join_command(const std::string& chan_name) { + if (this->welcomed == false) + { + this->channels_to_join.push_back(chan_name); + return ; + } IrcChannel* channel = this->get_channel(chan_name); if (channel->joined == false) this->send_message(IrcMessage("JOIN", {chan_name})); } -void IrcClient::send_pong_command() +bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) { - this->send_message(IrcMessage("PONG", {})); + IrcChannel* channel = this->get_channel(chan_name); + if (channel->joined == false) + { + std::cout << "Cannot send message to channel " << chan_name << ", it is not joined" << std::endl; + return false; + } + this->send_message(IrcMessage("PRIVMSG", {chan_name, body})); + return true; +} + +void IrcClient::send_pong_command(const IrcMessage& message) +{ + const std::string id = message.arguments[0]; + this->send_message(IrcMessage("PONG", {id})); } void IrcClient::forward_server_message(const IrcMessage& message) @@ -154,6 +183,17 @@ void IrcClient::on_self_channel_join(const IrcMessage& message) channel->set_self(message.prefix); } +void IrcClient::on_channel_message(const IrcMessage& message) +{ + const IrcUser user(message.prefix); + const std::string nick = user.nick; + Iid iid; + iid.chan = message.arguments[0]; + iid.server = this->hostname; + const std::string body = message.arguments[1]; + this->bridge->send_muc_message(iid, nick, body); +} + void IrcClient::on_topic_received(const IrcMessage& message) { const std::string chan_name = message.arguments[1]; @@ -168,3 +208,12 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) this->bridge->send_self_join(this->hostname, chan_name, channel->get_self()->nick); this->bridge->send_topic(this->hostname, chan_name, channel->topic); } + +void IrcClient::on_welcome_message(const IrcMessage& message) +{ + this->current_nick = message.arguments[0]; + this->welcomed = true; + for (const std::string& chan_name: this->channels_to_join) + this->send_join_command(chan_name); + this->channels_to_join.clear(); +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index db1b83b..50f3781 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -44,6 +44,10 @@ public: * Return the channel with this name, create it if it does not yet exist */ IrcChannel* get_channel(const std::string& name); + /** + * Return our own nick + */ + std::string get_own_nick() const; /** * Serialize the given message into a line, and send that into the socket * (actually, into our out_buf and signal the poller that we want to wach @@ -53,7 +57,7 @@ public: /** * Send the PONG irc command */ - void send_pong_command(); + void send_pong_command(const IrcMessage& message); /** * Send the USER irc command */ @@ -66,6 +70,11 @@ public: * Send the JOIN irc command */ void send_join_command(const std::string& chan_name); + /** + * Send a PRIVMSG command for a channel + * Return true if the message was actually sent + */ + bool send_channel_message(const std::string& chan_name, const std::string& body); /** * Forward the server message received from IRC to the XMPP component */ @@ -80,6 +89,10 @@ public: * of user comes after so we do not send the self-presence over XMPP yet. */ void on_self_channel_join(const IrcMessage& message); + /** + * When a channel message is received + */ + void on_channel_message(const IrcMessage& message); /** * Save the topic in the IrcChannel */ @@ -89,6 +102,10 @@ public: * received etc), send the self presence and topic to the XMPP user. */ void on_channel_completely_joined(const IrcMessage& message); + /** + * When a message 001 is received, join the rooms we wanted to join, and set our actual nickname + */ + void on_welcome_message(const IrcMessage& message); private: /** @@ -99,15 +116,26 @@ private: * The user name used in the USER irc command */ const std::string username; + /** + * Our current nickname on the server + */ + std::string current_nick; /** * Raw pointer because the bridge owns us. */ Bridge* bridge; - /** * The list of joined channels, indexed by name */ std::unordered_map> channels; + /** + * A list of chan we want to join, but we need a response 001 from + * the server before sending the actual JOIN commands. So we just keep the + * channel names in a list, and send the JOIN commands for each of them + * whenever the WELCOME message is received. + */ + std::vector channels_to_join; + bool welcomed; IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; -- cgit v1.2.3 From 7c671499350e22f8bfba2f72b9827aa5b200f7b0 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 9 Nov 2013 23:17:48 +0100 Subject: Implement part and join, both ways --- src/irc/irc_channel.cpp | 24 ++++++++++++++++++++++ src/irc/irc_channel.hpp | 2 ++ src/irc/irc_client.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++------- src/irc/irc_client.hpp | 10 ++++++++- src/irc/irc_user.cpp | 8 ++++++-- 5 files changed, 88 insertions(+), 10 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 223305b..6daf708 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -22,3 +22,27 @@ IrcUser* IrcChannel::get_self() const { return this->self.get(); } + +IrcUser* IrcChannel::find_user(const std::string& name) +{ + IrcUser user(name); + for (const auto& u: this->users) + { + if (u->nick == user.nick) + return u.get(); + } + return nullptr; +} + +void IrcChannel::remove_user(const IrcUser* user) +{ + for (auto it = this->users.begin(); it != this->users.end(); ++it) + { + IrcUser* u = it->get(); + if (u->nick == user->nick) + { + this->users.erase(it); + break ; + } + } +} diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index da0f298..3786697 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -20,6 +20,8 @@ public: void set_self(const std::string& name); IrcUser* get_self() const; IrcUser* add_user(const std::string& name); + IrcUser* find_user(const std::string& name); + void remove_user(const IrcUser* user); private: std::unique_ptr self; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index cf57bd7..e3d7653 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -76,7 +76,7 @@ void IrcClient::parse_in_buffer() message.command == "372") this->forward_server_message(message); else if (message.command == "JOIN") - this->on_self_channel_join(message); + this->on_channel_join(message); else if (message.command == "PRIVMSG") this->on_channel_message(message); else if (message.command == "353") @@ -87,6 +87,8 @@ void IrcClient::parse_in_buffer() this->on_channel_completely_joined(message); else if (message.command == "001") this->on_welcome_message(message); + else if (message.command == "PART") + this->on_part(message); } } @@ -128,9 +130,7 @@ void IrcClient::send_join_command(const std::string& chan_name) this->channels_to_join.push_back(chan_name); return ; } - IrcChannel* channel = this->get_channel(chan_name); - if (channel->joined == false) - this->send_message(IrcMessage("JOIN", {chan_name})); + this->send_message(IrcMessage("JOIN", {chan_name})); } bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) @@ -145,6 +145,15 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st return true; } +void IrcClient::send_part_command(const std::string& chan_name, const std::string& status_message) +{ + IrcChannel* channel = this->get_channel(chan_name); + if (channel->joined == true) + { + this->send_message(IrcMessage("PART", {chan_name, status_message})); + } +} + void IrcClient::send_pong_command(const IrcMessage& message) { const std::string id = message.arguments[0]; @@ -175,12 +184,21 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) } } -void IrcClient::on_self_channel_join(const IrcMessage& message) +void IrcClient::on_channel_join(const IrcMessage& message) { const std::string chan_name = message.arguments[0]; IrcChannel* channel = this->get_channel(chan_name); - channel->joined = true; - channel->set_self(message.prefix); + const std::string nick = message.prefix; + if (channel->joined == false) + { + channel->joined = true; + channel->set_self(nick); + } + else + { + IrcUser* user = channel->add_user(nick); + this->bridge->send_user_join(this->hostname, chan_name, user->nick); + } } void IrcClient::on_channel_message(const IrcMessage& message) @@ -217,3 +235,25 @@ void IrcClient::on_welcome_message(const IrcMessage& message) this->send_join_command(chan_name); this->channels_to_join.clear(); } + +void IrcClient::on_part(const IrcMessage& message) +{ + const std::string chan_name = message.arguments[0]; + IrcChannel* channel = this->get_channel(chan_name); + std::string txt; + if (message.arguments.size() >= 2) + txt = message.arguments[1]; + const IrcUser* user = channel->find_user(message.prefix); + if (user) + { + std::string nick = user->nick; + channel->remove_user(user); + Iid iid; + iid.chan = chan_name; + iid.server = this->hostname; + bool self = channel->get_self()->nick == nick; + this->bridge->send_muc_leave(std::move(iid), std::move(nick), std::move(txt), self); + if (self) + channel->joined = false; + } +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 50f3781..e58ffbc 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -75,6 +75,10 @@ public: * Return true if the message was actually sent */ bool send_channel_message(const std::string& chan_name, const std::string& body); + /** + * Send the PART irc command + */ + void send_part_command(const std::string& chan_name, const std::string& status_message); /** * Forward the server message received from IRC to the XMPP component */ @@ -88,7 +92,7 @@ public: * Remember our nick and host, when we are joined to the channel. The list * of user comes after so we do not send the self-presence over XMPP yet. */ - void on_self_channel_join(const IrcMessage& message); + void on_channel_join(const IrcMessage& message); /** * When a channel message is received */ @@ -106,6 +110,10 @@ public: * When a message 001 is received, join the rooms we wanted to join, and set our actual nickname */ void on_welcome_message(const IrcMessage& message); + /** + * When a PART message is received + */ + void on_part(const IrcMessage& message); private: /** diff --git a/src/irc/irc_user.cpp b/src/irc/irc_user.cpp index fc853bc..afe8623 100644 --- a/src/irc/irc_user.cpp +++ b/src/irc/irc_user.cpp @@ -7,14 +7,18 @@ IrcUser::IrcUser(const std::string& name) const std::string::size_type sep = name.find("!"); if (sep == std::string::npos) { - if (name[0] == '@' || name[0] == '+') + if (name[0] == '~' || name[0] == '&' + || name[0] == '@' || name[0] == '%' + || name[0] == '+') this->nick = name.substr(1); else this->nick = name; } else { - if (name[0] == '@' || name[0] == '+') + if (name[0] == '~' || name[0] == '&' + || name[0] == '@' || name[0] == '%' + || name[0] == '+') this->nick = name.substr(1, sep); else this->nick = name.substr(0, sep); -- cgit v1.2.3 From 0bb7ee0127a625ca8b6c25d9f593bfaa3d5af84b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 10 Nov 2013 05:08:50 +0100 Subject: Handle IRC QUIT command --- src/irc/irc_client.cpp | 24 ++++++++++++++++++++++++ src/irc/irc_client.hpp | 4 ++++ 2 files changed, 28 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index e3d7653..8de7c8f 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -89,6 +89,8 @@ void IrcClient::parse_in_buffer() this->on_welcome_message(message); else if (message.command == "PART") this->on_part(message); + else if (message.command == "QUIT") + this->on_quit(message); } } @@ -257,3 +259,25 @@ void IrcClient::on_part(const IrcMessage& message) channel->joined = false; } } + +void IrcClient::on_quit(const IrcMessage& message) +{ + std::string txt; + if (message.arguments.size() >= 1) + txt = message.arguments[0]; + for (auto it = this->channels.begin(); it != this->channels.end(); ++it) + { + const std::string chan_name = it->first; + IrcChannel* channel = it->second.get(); + const IrcUser* user = channel->find_user(message.prefix); + if (user) + { + std::string nick = user->nick; + channel->remove_user(user); + Iid iid; + iid.chan = chan_name; + iid.server = this->hostname; + this->bridge->send_muc_leave(std::move(iid), std::move(nick), std::move(txt), false); + } + } +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index e58ffbc..33ab894 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -114,6 +114,10 @@ public: * When a PART message is received */ void on_part(const IrcMessage& message); + /** + * When a QUIT message is received + */ + void on_quit(const IrcMessage& message); private: /** -- cgit v1.2.3 From 10d528717723a72dd3240c634980a461cf9fa2df Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 10 Nov 2013 06:33:04 +0100 Subject: Handle private messages, both ways --- src/irc/irc_client.cpp | 13 ++++++++++++- src/irc/irc_client.hpp | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 8de7c8f..71b0fe2 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -147,6 +147,11 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st return true; } +void IrcClient::send_private_message(const std::string& username, const std::string& body) +{ + this->send_message(IrcMessage("PRIVMSG", {username, body})); +} + void IrcClient::send_part_command(const std::string& chan_name, const std::string& status_message) { IrcChannel* channel = this->get_channel(chan_name); @@ -211,7 +216,13 @@ void IrcClient::on_channel_message(const IrcMessage& message) iid.chan = message.arguments[0]; iid.server = this->hostname; const std::string body = message.arguments[1]; - this->bridge->send_muc_message(iid, nick, body); + bool muc = true; + if (!this->get_channel(iid.chan)->joined) + { + iid.chan = nick; + muc = false; + } + this->bridge->send_message(iid, nick, body, muc); } void IrcClient::on_topic_received(const IrcMessage& message) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 33ab894..bb51a4e 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -75,6 +75,10 @@ public: * Return true if the message was actually sent */ bool send_channel_message(const std::string& chan_name, const std::string& body); + /** + * Send a PRIVMSG command for an user + */ + void send_private_message(const std::string& username, const std::string& body); /** * Send the PART irc command */ -- cgit v1.2.3 From 096a4e3bafe6e2d238e4592f57f22f19f363fcbd Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 11 Nov 2013 00:24:34 +0100 Subject: Handle nick changes, both ways --- src/irc/irc_client.cpp | 45 +++++++++++++++++++++++++++++++++++++++------ src/irc/irc_client.hpp | 10 +++++++++- 2 files changed, 48 insertions(+), 7 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 71b0fe2..30b1204 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -53,6 +53,12 @@ IrcChannel* IrcClient::get_channel(const std::string& name) } } +bool IrcClient::is_channel_joined(const std::string& name) +{ + IrcChannel* client = this->get_channel(name); + return client->joined; +} + std::string IrcClient::get_own_nick() const { return this->current_nick; @@ -91,6 +97,8 @@ void IrcClient::parse_in_buffer() this->on_part(message); else if (message.command == "QUIT") this->on_quit(message); + else if (message.command == "NICK") + this->on_nick(message); } } @@ -128,11 +136,9 @@ void IrcClient::send_nick_command(const std::string& nick) void IrcClient::send_join_command(const std::string& chan_name) { if (this->welcomed == false) - { - this->channels_to_join.push_back(chan_name); - return ; - } - this->send_message(IrcMessage("JOIN", {chan_name})); + this->channels_to_join.push_back(chan_name); + else + this->send_message(IrcMessage("JOIN", {chan_name})); } bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) @@ -288,7 +294,34 @@ void IrcClient::on_quit(const IrcMessage& message) Iid iid; iid.chan = chan_name; iid.server = this->hostname; - this->bridge->send_muc_leave(std::move(iid), std::move(nick), std::move(txt), false); + this->bridge->send_muc_leave(std::move(iid), std::move(nick), txt, false); } } } + +void IrcClient::on_nick(const IrcMessage& message) +{ + const std::string new_nick = message.arguments[0]; + for (auto it = this->channels.begin(); it != this->channels.end(); ++it) + { + const std::string chan_name = it->first; + IrcChannel* channel = it->second.get(); + IrcUser* user = channel->find_user(message.prefix); + if (user) + { + std::string old_nick = user->nick; + Iid iid; + iid.chan = chan_name; + iid.server = this->hostname; + bool self = channel->get_self()->nick == old_nick; + this->bridge->send_nick_change(std::move(iid), old_nick, new_nick, self); + user->nick = new_nick; + if (self) + { + channel->get_self()->nick = new_nick; + this->current_nick = new_nick; + } + } + } +} + diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index bb51a4e..d9ea069 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -44,6 +44,10 @@ public: * Return the channel with this name, create it if it does not yet exist */ IrcChannel* get_channel(const std::string& name); + /** + * Returns true if the channel is joined + */ + bool is_channel_joined(const std::string& name); /** * Return our own nick */ @@ -67,7 +71,7 @@ public: */ void send_nick_command(const std::string& username); /** - * Send the JOIN irc command + * Send the JOIN irc command. */ void send_join_command(const std::string& chan_name); /** @@ -118,6 +122,10 @@ public: * When a PART message is received */ void on_part(const IrcMessage& message); + /** + * When a NICK message is received + */ + void on_nick(const IrcMessage& message); /** * When a QUIT message is received */ -- cgit v1.2.3 From 5817a95b5ee89480788832be35679dfcd2ed833b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 12 Nov 2013 23:43:43 +0100 Subject: Basic handling of modes, both ways --- src/irc/irc_channel.hpp | 1 - src/irc/irc_client.cpp | 43 ++++++++++++++++++++++++++++++++++++++++--- src/irc/irc_client.hpp | 19 +++++++++++++------ 3 files changed, 53 insertions(+), 10 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index 3786697..c4b6d2c 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -26,7 +26,6 @@ public: private: std::unique_ptr self; std::vector> users; - IrcChannel(const IrcChannel&) = delete; IrcChannel(IrcChannel&&) = delete; IrcChannel& operator=(const IrcChannel&) = delete; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 30b1204..0d8c614 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -162,9 +162,15 @@ void IrcClient::send_part_command(const std::string& chan_name, const std::strin { IrcChannel* channel = this->get_channel(chan_name); if (channel->joined == true) - { - this->send_message(IrcMessage("PART", {chan_name, status_message})); - } + this->send_message(IrcMessage("PART", {chan_name, status_message})); +} + +void IrcClient::send_mode_command(const std::string& chan_name, const std::vector& arguments) +{ + std::vector args(arguments); + args.insert(args.begin(), chan_name); + IrcMessage m("MODE", std::move(args)); + this->send_message(std::move(m)); } void IrcClient::send_pong_command(const IrcMessage& message) @@ -325,3 +331,34 @@ void IrcClient::on_nick(const IrcMessage& message) } } +void IrcClient::on_mode(const IrcMessage& message) +{ + const std::string target = message.arguments[0]; + if (target[0] == '&' || target[0] == '#' || + target[0] == '!' || target[0] == '+') + this->on_channel_mode(message); + else + this->on_user_mode(message); +} + +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 = message.arguments[0]; + iid.server = this->hostname; + IrcUser user(message.prefix); + this->bridge->send_message(iid, "", std::string("Mode ") + iid.chan + + " [" + message.arguments[1] + + (message.arguments.size() > 2 ? (" " + message.arguments[2]): "") + + "] by " + user.nick, + true); +} + +void IrcClient::on_user_mode(const IrcMessage& message) +{ + this->bridge->send_xmpp_message(this->hostname, "", + std::string("User mode for ") + message.arguments[0] + + " is [" + message.arguments[1] + "]"); +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index d9ea069..722f850 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -87,6 +87,10 @@ public: * Send the PART irc command */ void send_part_command(const std::string& chan_name, const std::string& status_message); + /** + * Send the MODE irc command + */ + void send_mode_command(const std::string& chan_name, const std::vector& arguments); /** * Forward the server message received from IRC to the XMPP component */ @@ -118,17 +122,20 @@ public: * When a message 001 is received, join the rooms we wanted to join, and set our actual nickname */ void on_welcome_message(const IrcMessage& message); - /** - * When a PART message is received - */ void on_part(const IrcMessage& message); + void on_nick(const IrcMessage& message); + void on_mode(const IrcMessage& message); /** - * When a NICK message is received + * A mode towards our own user is received (note, that is different from a + * channel mode towards or own nick, see + * http://tools.ietf.org/html/rfc2812#section-3.1.5 VS #section-3.2.3) */ - void on_nick(const IrcMessage& message); + void on_user_mode(const IrcMessage& message); /** - * When a QUIT message is received + * A mode towards a channel. Note that this can change the mode of the + * channel itself or an IrcUser in it. */ + void on_channel_mode(const IrcMessage& message); void on_quit(const IrcMessage& message); private: -- cgit v1.2.3 From 3cfaab9a2debe03829b1ff26fe94e775e1d18e0a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 12 Nov 2013 23:47:00 +0100 Subject: Map irc commands to callbacks, in a clean way --- src/irc/irc_client.cpp | 30 +++++------------------------- src/irc/irc_client.hpp | 24 +++++++++++++++++++++++- 2 files changed, 28 insertions(+), 26 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0d8c614..1d2e487 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -74,31 +74,11 @@ void IrcClient::parse_in_buffer() IrcMessage message(this->in_buf.substr(0, pos)); this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); std::cout << message << std::endl; - // TODO map function and command name properly - if (message.command == "PING") - this->send_pong_command(message); - else if (message.command == "NOTICE" || - message.command == "375" || - message.command == "372") - this->forward_server_message(message); - else if (message.command == "JOIN") - this->on_channel_join(message); - else if (message.command == "PRIVMSG") - this->on_channel_message(message); - else if (message.command == "353") - this->set_and_forward_user_list(message); - else if (message.command == "332") - this->on_topic_received(message); - else if (message.command == "366") - this->on_channel_completely_joined(message); - else if (message.command == "001") - this->on_welcome_message(message); - else if (message.command == "PART") - this->on_part(message); - else if (message.command == "QUIT") - this->on_quit(message); - else if (message.command == "NICK") - this->on_nick(message); + auto cb = irc_callbacks.find(message.command); + if (cb != irc_callbacks.end()) + (this->*(cb->second))(message); + else + std::cout << "No handler for command " << message.command << std::endl; } } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 722f850..07ff02c 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -167,11 +167,33 @@ private: */ std::vector channels_to_join; bool welcomed; - IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; IrcClient& operator=(const IrcClient&) = delete; IrcClient& operator=(IrcClient&&) = delete; }; +/** + * Define a map of functions to be called for each IRC command we can + * handle. + */ +typedef void (IrcClient::*irc_callback_t)(const IrcMessage&); + +static const std::unordered_map irc_callbacks = { + {"NOTICE", &IrcClient::forward_server_message}, + {"375", &IrcClient::forward_server_message}, + {"372", &IrcClient::forward_server_message}, + {"JOIN", &IrcClient::on_channel_join}, + {"PRIVMSG", &IrcClient::on_channel_message}, + {"353", &IrcClient::set_and_forward_user_list}, + {"332", &IrcClient::on_topic_received}, + {"366", &IrcClient::on_channel_completely_joined}, + {"001", &IrcClient::on_welcome_message}, + {"PART", &IrcClient::on_part}, + {"QUIT", &IrcClient::on_quit}, + {"NICK", &IrcClient::on_nick}, + {"MODE", &IrcClient::on_mode}, + {"PING", &IrcClient::send_pong_command}, +}; + #endif // IRC_CLIENT_INCLUDED -- cgit v1.2.3 From 0859801230f999889d0f7356864888e8c5936cda Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 13 Nov 2013 01:24:36 +0100 Subject: Handle KICK in irc channel, both ways --- src/irc/irc_client.cpp | 20 ++++++++++++++++++++ src/irc/irc_client.hpp | 6 ++++++ 2 files changed, 26 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 1d2e487..82abbd9 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -113,6 +113,11 @@ void IrcClient::send_nick_command(const std::string& nick) this->send_message(IrcMessage("NICK", {nick})); } +void IrcClient::send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason) +{ + this->send_message(IrcMessage("KICK", {chan_name, target, reason})); +} + void IrcClient::send_join_command(const std::string& chan_name) { if (this->welcomed == false) @@ -311,6 +316,21 @@ void IrcClient::on_nick(const IrcMessage& message) } } +void IrcClient::on_kick(const IrcMessage& message) +{ + const std::string target = message.arguments[1]; + const std::string reason = message.arguments[2]; + const std::string chan_name = message.arguments[0]; + IrcChannel* channel = this->get_channel(chan_name); + if (channel->get_self()->nick == target) + channel->joined = false; + IrcUser author(message.prefix); + Iid iid; + iid.chan = chan_name; + iid.server = this->hostname; + this->bridge->kick_muc_user(std::move(iid), target, reason, author.nick); +} + void IrcClient::on_mode(const IrcMessage& message) { const std::string target = message.arguments[0]; diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 07ff02c..3b22fa0 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -91,6 +91,10 @@ public: * Send the MODE irc command */ void send_mode_command(const std::string& chan_name, const std::vector& arguments); + /** + * Send the KICK irc command + */ + void send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason); /** * Forward the server message received from IRC to the XMPP component */ @@ -124,6 +128,7 @@ public: void on_welcome_message(const IrcMessage& message); void on_part(const IrcMessage& message); void on_nick(const IrcMessage& message); + void on_kick(const IrcMessage& message); void on_mode(const IrcMessage& message); /** * A mode towards our own user is received (note, that is different from a @@ -194,6 +199,7 @@ static const std::unordered_map irc_callbacks = { {"NICK", &IrcClient::on_nick}, {"MODE", &IrcClient::on_mode}, {"PING", &IrcClient::send_pong_command}, + {"KICK", &IrcClient::on_kick}, }; #endif // IRC_CLIENT_INCLUDED -- cgit v1.2.3 From 1e122d3342ef4336f17bd5606be7101748627415 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 17 Nov 2013 11:35:43 +0100 Subject: Send the motd as one single big message We append each line to a string, and when the MOTD is complete, we send that string at once. --- src/irc/irc_client.cpp | 21 +++++++++++++++++++++ src/irc/irc_client.hpp | 25 +++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 82abbd9..f339580 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -222,6 +222,27 @@ void IrcClient::on_channel_message(const IrcMessage& message) this->bridge->send_message(iid, nick, body, muc); } +void IrcClient::empty_motd(const IrcMessage& message) +{ + (void)message; + this->motd.erase(); +} + +void IrcClient::on_motd_line(const IrcMessage& message) +{ + const std::string body = message.arguments[1]; + // We could send the MOTD without a line break between each IRC-message, + // but sometimes it contains some ASCII art, we use line breaks to keep + // them intact. + this->motd += body+"\n"; +} + +void IrcClient::send_motd(const IrcMessage& message) +{ + (void)message; + this->bridge->send_xmpp_message(this->hostname, "", this->motd); +} + void IrcClient::on_topic_received(const IrcMessage& message) { const std::string chan_name = message.arguments[1]; diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 3b22fa0..aa420f4 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -99,6 +99,18 @@ public: * Forward the server message received from IRC to the XMPP component */ void forward_server_message(const IrcMessage& message); + /** + * Just empty the motd we kept as a string + */ + void empty_motd(const IrcMessage& message); + /** + * Send the MOTD string as one single "big" message + */ + void send_motd(const IrcMessage& message); + /** + * Append this line to the MOTD + */ + void on_motd_line(const IrcMessage& message); /** * Forward the join of an other user into an IRC channel, and save the * IrcUsers in the IrcChannel @@ -172,6 +184,11 @@ private: */ std::vector channels_to_join; bool welcomed; + /** + * Each motd line received is appended to this string, which we send when + * the motd is completely received + */ + std::string motd; IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; IrcClient& operator=(const IrcClient&) = delete; @@ -186,8 +203,12 @@ typedef void (IrcClient::*irc_callback_t)(const IrcMessage&); static const std::unordered_map irc_callbacks = { {"NOTICE", &IrcClient::forward_server_message}, - {"375", &IrcClient::forward_server_message}, - {"372", &IrcClient::forward_server_message}, + {"RPL_MOTDSTART", &IrcClient::empty_motd}, + {"375", &IrcClient::empty_motd}, + {"RPL_MOTD", &IrcClient::on_motd_line}, + {"372", &IrcClient::on_motd_line}, + {"RPL_MOTDEND", &IrcClient::send_motd}, + {"376", &IrcClient::send_motd}, {"JOIN", &IrcClient::on_channel_join}, {"PRIVMSG", &IrcClient::on_channel_message}, {"353", &IrcClient::set_and_forward_user_list}, -- cgit v1.2.3 From 12a18ca748a27111bb24a7f6518f831494e5ca47 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 21 Nov 2013 19:38:31 +0100 Subject: TIL override and final --- src/irc/irc_client.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index aa420f4..4749cac 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -30,16 +30,16 @@ public: /** * Called when successfully connected to the server */ - void on_connected(); + void on_connected() override final; /** * Close the connection, remove us from the poller */ - void on_connection_close(); + void on_connection_close() override final; /** * Parse the data we have received so far and try to get one or more * complete messages from it. */ - void parse_in_buffer(); + void parse_in_buffer() override final; /** * Return the channel with this name, create it if it does not yet exist */ -- cgit v1.2.3 From 61ecaab40078901800e3e20282f1ae7852a7c938 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 28 Nov 2013 00:55:20 +0100 Subject: Re-add support for /me messages from IRC It was recently removed because it was handled in the old "convert irc colors" code. It now is in the right place. --- src/irc/irc_client.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index f339580..72eec02 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -219,7 +219,14 @@ void IrcClient::on_channel_message(const IrcMessage& message) iid.chan = nick; muc = false; } - this->bridge->send_message(iid, nick, body, muc); + if (!body.empty() && body[0] == '\01') + { + if (body.substr(1, 6) == "ACTION") + this->bridge->send_message(iid, nick, + std::string("/me") + body.substr(7, body.size() - 8), muc); + } + else + this->bridge->send_message(iid, nick, body, muc); } void IrcClient::empty_motd(const IrcMessage& message) -- cgit v1.2.3 From 1151c26c363e736a98c5fcb723c753658fe35b9b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 28 Nov 2013 02:14:42 +0100 Subject: Channel names are case insensitive But some servers (epiknet for example) send channel names with an uppercase --- src/irc/irc_client.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 72eec02..dc0986f 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -174,7 +175,7 @@ void IrcClient::forward_server_message(const IrcMessage& message) void IrcClient::set_and_forward_user_list(const IrcMessage& message) { - const std::string chan_name = message.arguments[2]; + const std::string chan_name = utils::tolower(message.arguments[2]); IrcChannel* channel = this->get_channel(chan_name); std::vector nicks = utils::split(message.arguments[3], ' '); for (const std::string& nick: nicks) @@ -190,7 +191,7 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) void IrcClient::on_channel_join(const IrcMessage& message) { - const std::string chan_name = message.arguments[0]; + const std::string chan_name = utils::tolower(message.arguments[0]); IrcChannel* channel = this->get_channel(chan_name); const std::string nick = message.prefix; if (channel->joined == false) @@ -252,14 +253,14 @@ void IrcClient::send_motd(const IrcMessage& message) void IrcClient::on_topic_received(const IrcMessage& message) { - const std::string chan_name = message.arguments[1]; + const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); channel->topic = message.arguments[2]; } void IrcClient::on_channel_completely_joined(const IrcMessage& message) { - const std::string chan_name = message.arguments[1]; + const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); this->bridge->send_self_join(this->hostname, chan_name, channel->get_self()->nick); this->bridge->send_topic(this->hostname, chan_name, channel->topic); @@ -276,7 +277,7 @@ void IrcClient::on_welcome_message(const IrcMessage& message) void IrcClient::on_part(const IrcMessage& message) { - const std::string chan_name = message.arguments[0]; + const std::string chan_name = utils::tolower(message.arguments[0]); IrcChannel* channel = this->get_channel(chan_name); std::string txt; if (message.arguments.size() >= 2) @@ -348,7 +349,7 @@ void IrcClient::on_kick(const IrcMessage& message) { const std::string target = message.arguments[1]; const std::string reason = message.arguments[2]; - const std::string chan_name = message.arguments[0]; + const std::string chan_name = utils::tolower(message.arguments[0]); IrcChannel* channel = this->get_channel(chan_name); if (channel->get_self()->nick == target) channel->joined = false; -- cgit v1.2.3 From d6832fbcc98557952387f3ce2899bbebacd7c204 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 28 Nov 2013 21:09:27 +0100 Subject: :3 --- src/irc/irc_client.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index dc0986f..2d158fb 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -91,7 +91,8 @@ void IrcClient::send_message(IrcMessage&& message) res += std::move(message.command); for (const std::string& arg: message.arguments) { - if (arg.find(" ") != std::string::npos) + if (arg.find(" ") != std::string::npos || + (!arg.empty()) && arg[0] == ':') { res += " :" + arg; break; -- cgit v1.2.3 From 6bd176f15ebf146874bc7f4525870e52921cc2fe Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 30 Nov 2013 18:53:45 +0100 Subject: Fix a parenthesis ambiguity --- src/irc/irc_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 2d158fb..0061561 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -92,7 +92,7 @@ void IrcClient::send_message(IrcMessage&& message) for (const std::string& arg: message.arguments) { if (arg.find(" ") != std::string::npos || - (!arg.empty()) && arg[0] == ':') + (!arg.empty() && arg[0] == ':')) { res += " :" + arg; break; -- cgit v1.2.3 From 2662ed89e2cd41477582140e482f1ddbbfdb235e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 3 Dec 2013 18:27:20 +0100 Subject: Add a logger class --- src/irc/irc_client.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0061561..4e5efe1 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -4,6 +4,7 @@ #include #include +// #include #include #include -- cgit v1.2.3 From a4c845ab6c54172ea305f33734c83238c75d421a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 3 Dec 2013 19:10:44 +0100 Subject: Use the logger everywhere --- src/irc/irc_client.cpp | 17 +++++++---------- src/irc/irc_user.cpp | 1 - 2 files changed, 7 insertions(+), 11 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 4e5efe1..1a9e61b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -4,7 +4,7 @@ #include #include -// #include +#include #include #include @@ -18,12 +18,10 @@ IrcClient::IrcClient(const std::string& hostname, const std::string& username, B bridge(bridge), welcomed(false) { - std::cout << "IrcClient()" << std::endl; } IrcClient::~IrcClient() { - std::cout << "~IrcClient()" << std::endl; } void IrcClient::start() @@ -39,7 +37,7 @@ void IrcClient::on_connected() void IrcClient::on_connection_close() { - std::cout << "Connection closed by remote server." << std::endl; + log_warning("Connection closed by remote server."); } IrcChannel* IrcClient::get_channel(const std::string& name) @@ -74,18 +72,19 @@ void IrcClient::parse_in_buffer() if (pos == std::string::npos) break ; IrcMessage message(this->in_buf.substr(0, pos)); + log_debug("IRC RECEIVING: " << message); this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); - std::cout << message << std::endl; auto cb = irc_callbacks.find(message.command); if (cb != irc_callbacks.end()) (this->*(cb->second))(message); else - std::cout << "No handler for command " << message.command << std::endl; + log_info("No handler for command " << message.command); } } void IrcClient::send_message(IrcMessage&& message) { + log_debug("IRC SENDING: " << message); std::string res; if (!message.prefix.empty()) res += ":" + std::move(message.prefix) + " "; @@ -101,8 +100,6 @@ void IrcClient::send_message(IrcMessage&& message) res += " " + arg; } res += "\r\n"; - std::cout << "=== IRC SENDING ===" << std::endl; - std::cout << res << std::endl; this->send_data(std::move(res)); } @@ -134,7 +131,7 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st IrcChannel* channel = this->get_channel(chan_name); if (channel->joined == false) { - std::cout << "Cannot send message to channel " << chan_name << ", it is not joined" << std::endl; + log_warning("Cannot send message to channel " << chan_name << ", it is not joined"); return false; } this->send_message(IrcMessage("PRIVMSG", {chan_name, body})); @@ -185,7 +182,7 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) IrcUser* user = channel->add_user(nick); if (user->nick != channel->get_self()->nick) { - std::cout << "Adding user [" << nick << "] to chan " << chan_name << std::endl; + log_debug("Adding user [" << nick << "] to chan " << chan_name); this->bridge->send_user_join(this->hostname, chan_name, user->nick); } } diff --git a/src/irc/irc_user.cpp b/src/irc/irc_user.cpp index afe8623..f9866ef 100644 --- a/src/irc/irc_user.cpp +++ b/src/irc/irc_user.cpp @@ -24,5 +24,4 @@ IrcUser::IrcUser(const std::string& name) this->nick = name.substr(0, sep); this->host = name.substr(sep+1); } - std::cout << "Created user: [" << this->nick << "!" << this->host << std::endl; } -- cgit v1.2.3 From 6fa548a194082648724078cc777da34c30dd40a1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 3 Dec 2013 19:56:57 +0100 Subject: Display all the MODE arguments in the message --- src/irc/irc_client.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 1a9e61b..af3df62 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -377,10 +377,18 @@ void IrcClient::on_channel_mode(const IrcMessage& message) iid.chan = message.arguments[0]; iid.server = this->hostname; IrcUser user(message.prefix); + std::string mode_arguments; + for (size_t i = 1; i < message.arguments.size(); ++i) + { + if (!message.arguments[i].empty()) + { + if (i != 1) + mode_arguments += " "; + mode_arguments += message.arguments[i]; + } + } this->bridge->send_message(iid, "", std::string("Mode ") + iid.chan + - " [" + message.arguments[1] + - (message.arguments.size() > 2 ? (" " + message.arguments[2]): "") - + "] by " + user.nick, + " [" + mode_arguments + "] by " + user.nick, true); } -- cgit v1.2.3 From e2117bcb0abfde30ad503b99da58699cf0f2a95b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 8 Dec 2013 04:44:46 +0100 Subject: Enforce a simple limit of 400 bytes for IRC messages body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The limit for the whole message is 512 bytes, we limit the body to 400 (instead of doing a calculation based on the command name and the other parameters), because it's simple, easy and that’s enough. fixes #2416 --- src/irc/irc_client.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index af3df62..0d4d102 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -134,13 +134,27 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st log_warning("Cannot send message to channel " << chan_name << ", it is not joined"); return false; } - this->send_message(IrcMessage("PRIVMSG", {chan_name, body})); + // Cut the message body into 400-bytes parts (because the whole command + // must fit into 512 bytes, that's an easy way to make sure the chan name + // + body fits. I’m lazy.) + std::string::size_type pos = 0; + while (pos < body.size()) + { + this->send_message(IrcMessage("PRIVMSG", {chan_name, body.substr(pos, 400)})); + pos += 400; + } return true; } void IrcClient::send_private_message(const std::string& username, const std::string& body) { - this->send_message(IrcMessage("PRIVMSG", {username, body})); + std::string::size_type pos = 0; + while (pos < body.size()) + { + this->send_message(IrcMessage("PRIVMSG", {username, body.substr(pos, 400)})); + pos += 400; + } + } void IrcClient::send_part_command(const std::string& chan_name, const std::string& status_message) -- cgit v1.2.3 From b11126a19dbaadf4c32fb8dbec22754ad0712c26 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 8 Dec 2013 20:14:12 +0100 Subject: Provide a JID for IRC users, and add a stringprep dependency for this --- src/irc/irc_client.cpp | 8 ++++---- src/irc/irc_message.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0d4d102..0f29a2b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -193,11 +193,11 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) std::vector nicks = utils::split(message.arguments[3], ' '); for (const std::string& nick: nicks) { - IrcUser* user = channel->add_user(nick); + const IrcUser* user = channel->add_user(nick); if (user->nick != channel->get_self()->nick) { log_debug("Adding user [" << nick << "] to chan " << chan_name); - this->bridge->send_user_join(this->hostname, chan_name, user->nick); + this->bridge->send_user_join(this->hostname, chan_name, user); } } } @@ -214,8 +214,8 @@ void IrcClient::on_channel_join(const IrcMessage& message) } else { - IrcUser* user = channel->add_user(nick); - this->bridge->send_user_join(this->hostname, chan_name, user->nick); + const IrcUser* user = channel->add_user(nick); + this->bridge->send_user_join(this->hostname, chan_name, user); } } diff --git a/src/irc/irc_message.cpp b/src/irc/irc_message.cpp index 18fa3ec..eb3eb47 100644 --- a/src/irc/irc_message.cpp +++ b/src/irc/irc_message.cpp @@ -9,7 +9,7 @@ IrcMessage::IrcMessage(std::string&& line) if (line[0] == ':') { pos = line.find(" "); - this->prefix = line.substr(1, pos); + this->prefix = line.substr(1, pos - 1); line = line.substr(pos + 1, std::string::npos); } // command -- cgit v1.2.3 From b29290f73a24f2d5af7bde45c9ff5332c7a1f5a6 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 9 Dec 2013 03:53:01 +0100 Subject: Lowercase the chan names in two missing cases --- src/irc/irc_client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0f29a2b..ed98653 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -224,7 +224,7 @@ void IrcClient::on_channel_message(const IrcMessage& message) const IrcUser user(message.prefix); const std::string nick = user.nick; Iid iid; - iid.chan = message.arguments[0]; + iid.chan = utils::tolower(message.arguments[0]); iid.server = this->hostname; const std::string body = message.arguments[1]; bool muc = true; @@ -388,7 +388,7 @@ 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 = message.arguments[0]; + iid.chan = utils::tolower(message.arguments[0]); iid.server = this->hostname; IrcUser user(message.prefix); std::string mode_arguments; -- cgit v1.2.3 From 3afb63a650b8b925ce1ba722dd42b7418f623713 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 21 Dec 2013 21:04:41 +0100 Subject: Shutdown cleanly on SIGINT --- src/irc/irc_client.cpp | 20 ++++++++++++++++++++ src/irc/irc_client.hpp | 6 ++++++ 2 files changed, 26 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index ed98653..2115bdc 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -118,6 +118,11 @@ void IrcClient::send_kick_command(const std::string& chan_name, const std::strin this->send_message(IrcMessage("KICK", {chan_name, target, reason})); } +void IrcClient::send_quit_command() +{ + this->send_message(IrcMessage("QUIT", {"gateway shutdown"})); +} + void IrcClient::send_join_command(const std::string& chan_name) { if (this->welcomed == false) @@ -310,6 +315,21 @@ void IrcClient::on_part(const IrcMessage& message) } } +void IrcClient::on_error(const IrcMessage& message) +{ + const std::string leave_message = message.arguments[0]; + // The user is out of all the channels + for (auto it = this->channels.begin(); it != this->channels.end(); ++it) + { + Iid iid; + iid.chan = it->first; + iid.server = this->hostname; + IrcChannel* channel = it->second.get(); + std::string own_nick = channel->get_self()->nick; + this->bridge->send_muc_leave(std::move(iid), std::move(own_nick), leave_message, true); + } +} + void IrcClient::on_quit(const IrcMessage& message) { std::string txt; diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 4749cac..4038cdf 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -95,6 +95,10 @@ public: * Send the KICK irc command */ void send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason); + /** + * Send the QUIT irc command + */ + void send_quit_command(); /** * Forward the server message received from IRC to the XMPP component */ @@ -139,6 +143,7 @@ public: */ void on_welcome_message(const IrcMessage& message); void on_part(const IrcMessage& message); + void on_error(const IrcMessage& message); void on_nick(const IrcMessage& message); void on_kick(const IrcMessage& message); void on_mode(const IrcMessage& message); @@ -216,6 +221,7 @@ static const std::unordered_map irc_callbacks = { {"366", &IrcClient::on_channel_completely_joined}, {"001", &IrcClient::on_welcome_message}, {"PART", &IrcClient::on_part}, + {"ERROR", &IrcClient::on_error}, {"QUIT", &IrcClient::on_quit}, {"NICK", &IrcClient::on_nick}, {"MODE", &IrcClient::on_mode}, -- cgit v1.2.3 From b8ce9ed43d809daefe17714b36aa0874ca5f6cc8 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 26 Dec 2013 14:30:07 +0100 Subject: Check that channels are joined before acting on objects in it --- src/irc/irc_client.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 2115bdc..bde9973 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -297,6 +297,8 @@ void IrcClient::on_part(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[0]); IrcChannel* channel = this->get_channel(chan_name); + if (!channel->joined) + return ; std::string txt; if (message.arguments.size() >= 2) txt = message.arguments[1]; @@ -325,6 +327,8 @@ void IrcClient::on_error(const IrcMessage& message) iid.chan = it->first; iid.server = this->hostname; IrcChannel* channel = it->second.get(); + if (!channel->joined) + continue; std::string own_nick = channel->get_self()->nick; this->bridge->send_muc_leave(std::move(iid), std::move(own_nick), leave_message, true); } @@ -384,6 +388,8 @@ void IrcClient::on_kick(const IrcMessage& message) const std::string reason = message.arguments[2]; const std::string chan_name = utils::tolower(message.arguments[0]); IrcChannel* channel = this->get_channel(chan_name); + if (!channel->joined) + return ; if (channel->get_self()->nick == target) channel->joined = false; IrcUser author(message.prefix); -- cgit v1.2.3 From 9df757fc6737b59f56d5b808ef48baba760b142e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 26 Dec 2013 14:57:13 +0100 Subject: Handle topic changes --- src/irc/irc_client.cpp | 2 ++ src/irc/irc_client.hpp | 1 + 2 files changed, 3 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index bde9973..bdeb2f8 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -274,6 +274,8 @@ void IrcClient::on_topic_received(const IrcMessage& message) const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); channel->topic = message.arguments[2]; + if (channel->joined) + this->bridge->send_topic(this->hostname, chan_name, channel->topic); } void IrcClient::on_channel_completely_joined(const IrcMessage& message) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 4038cdf..99ee6c0 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -218,6 +218,7 @@ static const std::unordered_map irc_callbacks = { {"PRIVMSG", &IrcClient::on_channel_message}, {"353", &IrcClient::set_and_forward_user_list}, {"332", &IrcClient::on_topic_received}, + {"TOPIC", &IrcClient::on_topic_received}, {"366", &IrcClient::on_channel_completely_joined}, {"001", &IrcClient::on_welcome_message}, {"PART", &IrcClient::on_part}, -- cgit v1.2.3 From 483e17020dc4f19223001ab36da0dc48a15a0d3e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Dec 2013 11:49:28 +0100 Subject: Be verbose about the connection status, and some errors --- src/irc/irc_client.cpp | 25 ++++++++++++++++++++++++- src/irc/irc_client.hpp | 18 ++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index bdeb2f8..881de96 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -33,11 +33,14 @@ void IrcClient::on_connected() { this->send_nick_command(this->username); this->send_user_command(this->username, this->username); + this->send_gateway_message("Connected to IRC server."); } void IrcClient::on_connection_close() { - log_warning("Connection closed by remote server."); + static const std::string message = "Connection closed by remote server."; + this->send_gateway_message(message); + log_warning(message); } IrcChannel* IrcClient::get_channel(const std::string& name) @@ -191,6 +194,11 @@ void IrcClient::forward_server_message(const IrcMessage& message) this->bridge->send_xmpp_message(this->hostname, from, body); } +void IrcClient::send_gateway_message(const std::string& message, const std::string& from) +{ + this->bridge->send_xmpp_message(this->hostname, from, message); +} + void IrcClient::set_and_forward_user_list(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[2]); @@ -286,6 +294,20 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) this->bridge->send_topic(this->hostname, chan_name, channel->topic); } +void IrcClient::on_erroneous_nickname(const IrcMessage& message) +{ + const std::string error_msg = message.arguments.size() >= 3 ? + message.arguments[2]: "Erroneous nickname"; + this->send_gateway_message(error_msg + ": " + message.arguments[1], message.prefix); +} + +void IrcClient::on_generic_error(const IrcMessage& message) +{ + const std::string error_msg = message.arguments.size() >= 3 ? + message.arguments[2]: "Unspecified error"; + this->send_gateway_message(message.arguments[1] + ": " + error_msg, message.prefix); +} + void IrcClient::on_welcome_message(const IrcMessage& message) { this->current_nick = message.arguments[0]; @@ -334,6 +356,7 @@ void IrcClient::on_error(const IrcMessage& message) std::string own_nick = channel->get_self()->nick; this->bridge->send_muc_leave(std::move(iid), std::move(own_nick), leave_message, true); } + this->send_gateway_message(std::string("ERROR: ") + leave_message); } void IrcClient::on_quit(const IrcMessage& message) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 99ee6c0..e695e53 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -99,6 +99,12 @@ public: * Send the QUIT irc command */ void send_quit_command(); + /** + * Send a message to the gateway user, not generated by the IRC server, + * but that might be useful because we want to be verbose (for example we + * might want to notify the user about the connexion state) + */ + void send_gateway_message(const std::string& message, const std::string& from=""); /** * Forward the server message received from IRC to the XMPP component */ @@ -138,6 +144,14 @@ public: * received etc), send the self presence and topic to the XMPP user. */ void on_channel_completely_joined(const IrcMessage& message); + /** + * We tried to set an invalid nickname + */ + void on_erroneous_nickname(const IrcMessage& message); + /** + * Handles most errors from the server by just forwarding the message to the user. + */ + void on_generic_error(const IrcMessage& message); /** * When a message 001 is received, join the rooms we wanted to join, and set our actual nickname */ @@ -208,6 +222,8 @@ typedef void (IrcClient::*irc_callback_t)(const IrcMessage&); static const std::unordered_map irc_callbacks = { {"NOTICE", &IrcClient::forward_server_message}, + {"002", &IrcClient::forward_server_message}, + {"003", &IrcClient::forward_server_message}, {"RPL_MOTDSTART", &IrcClient::empty_motd}, {"375", &IrcClient::empty_motd}, {"RPL_MOTD", &IrcClient::on_motd_line}, @@ -220,6 +236,8 @@ static const std::unordered_map irc_callbacks = { {"332", &IrcClient::on_topic_received}, {"TOPIC", &IrcClient::on_topic_received}, {"366", &IrcClient::on_channel_completely_joined}, + {"432", &IrcClient::on_erroneous_nickname}, + {"461", &IrcClient::on_generic_error}, {"001", &IrcClient::on_welcome_message}, {"PART", &IrcClient::on_part}, {"ERROR", &IrcClient::on_error}, -- cgit v1.2.3 From aa53276859a5fc80071d24111a311297e058e603 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Dec 2013 11:53:29 +0100 Subject: Keep a "connected" state in the SocketHandler class --- src/irc/irc_client.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 881de96..4e37a63 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -128,6 +128,8 @@ void IrcClient::send_quit_command() void IrcClient::send_join_command(const std::string& chan_name) { + if (!this->connected) + this->start(); if (this->welcomed == false) this->channels_to_join.push_back(chan_name); else -- cgit v1.2.3 From e8e592d1ace5413a1e7d8b59b9467c78d8d68ea9 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Dec 2013 12:01:26 +0100 Subject: Remove disconnected IrcClients --- src/irc/irc_client.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 4e37a63..afdc629 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -58,8 +58,8 @@ IrcChannel* IrcClient::get_channel(const std::string& name) bool IrcClient::is_channel_joined(const std::string& name) { - IrcChannel* client = this->get_channel(name); - return client->joined; + IrcChannel* channel = this->get_channel(name); + return channel->joined; } std::string IrcClient::get_own_nick() const @@ -339,7 +339,12 @@ void IrcClient::on_part(const IrcMessage& message) bool self = channel->get_self()->nick == nick; this->bridge->send_muc_leave(std::move(iid), std::move(nick), std::move(txt), self); if (self) + { channel->joined = false; + this->channels.erase(chan_name); + // channel pointer is now invalid + channel = nullptr; + } } } @@ -358,6 +363,7 @@ void IrcClient::on_error(const IrcMessage& message) std::string own_nick = channel->get_self()->nick; this->bridge->send_muc_leave(std::move(iid), std::move(own_nick), leave_message, true); } + this->channels.clear(); this->send_gateway_message(std::string("ERROR: ") + leave_message); } -- cgit v1.2.3 From 43cc60e4a9e2859fdf67c89e58ee18cf7571f186 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Dec 2013 15:34:58 +0100 Subject: Handle nickname conflicts by sending the correct XMPP error presence --- src/irc/irc_client.cpp | 13 +++++++++++++ src/irc/irc_client.hpp | 6 ++++++ 2 files changed, 19 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index afdc629..10a5b12 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -303,6 +303,19 @@ void IrcClient::on_erroneous_nickname(const IrcMessage& message) this->send_gateway_message(error_msg + ": " + message.arguments[1], message.prefix); } +void IrcClient::on_nickname_conflict(const IrcMessage& message) +{ + const std::string nickname = message.arguments[1]; + this->on_generic_error(message); + for (auto it = this->channels.begin(); it != this->channels.end(); ++it) + { + Iid iid; + iid.chan = it->first; + iid.server = this->hostname; + this->bridge->send_nickname_conflict_error(iid, nickname); + } +} + void IrcClient::on_generic_error(const IrcMessage& message) { const std::string error_msg = message.arguments.size() >= 3 ? diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index e695e53..eced4b6 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -148,6 +148,11 @@ public: * We tried to set an invalid nickname */ void on_erroneous_nickname(const IrcMessage& message); + /** + * When the IRC servers denies our nickname because of a conflict. Send a + * presence conflict from all channels, because the name is server-wide. + */ + void on_nickname_conflict(const IrcMessage& message); /** * Handles most errors from the server by just forwarding the message to the user. */ @@ -237,6 +242,7 @@ static const std::unordered_map irc_callbacks = { {"TOPIC", &IrcClient::on_topic_received}, {"366", &IrcClient::on_channel_completely_joined}, {"432", &IrcClient::on_erroneous_nickname}, + {"433", &IrcClient::on_nickname_conflict}, {"461", &IrcClient::on_generic_error}, {"001", &IrcClient::on_welcome_message}, {"PART", &IrcClient::on_part}, -- cgit v1.2.3 From a075517824da7e82e1be7b67d615834851482861 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Dec 2013 17:42:48 +0100 Subject: Basic isupport support CHANMODES and PREFIX only --- src/irc/irc_client.cpp | 29 ++++++++++++++++++++++++++++- src/irc/irc_client.hpp | 21 +++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 10a5b12..912ee45 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -16,7 +16,8 @@ IrcClient::IrcClient(const std::string& hostname, const std::string& username, B username(username), current_nick(username), bridge(bridge), - welcomed(false) + welcomed(false), + chanmodes({"", "", "", ""}) { } @@ -196,6 +197,32 @@ void IrcClient::forward_server_message(const IrcMessage& message) this->bridge->send_xmpp_message(this->hostname, from, body); } +void IrcClient::on_isupport_message(const IrcMessage& message) +{ + const size_t len = message.arguments.size(); + for (size_t i = 1; i < len; ++i) + { + const std::string token = message.arguments[i]; + if (token.substr(0, 10) == "CHANMODES=") + { + this->chanmodes = utils::split(token.substr(11), ','); + // make sure we have 4 strings + this->chanmodes.resize(4); + } + else if (token.substr(0, 7) == "PREFIX=") + { + size_t i = 8; // jump PREFIX=( + size_t j = 9; + // Find the ) char + while (j < token.size() && token[j] != ')') + j++; + j++; + while (j < token.size() && token[i] != ')') + this->prefix_to_mode[token[j++]] = token[i++]; + } + } +} + void IrcClient::send_gateway_message(const std::string& message, const std::string& from) { this->bridge->send_xmpp_message(this->hostname, from, message); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index eced4b6..a0258ee 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -8,7 +8,9 @@ #include #include +#include #include +#include class Bridge; @@ -109,6 +111,11 @@ public: * Forward the server message received from IRC to the XMPP component */ void forward_server_message(const IrcMessage& message); + /** + * When receiving the isupport informations. See + * http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt + */ + void on_isupport_message(const IrcMessage& message); /** * Just empty the motd we kept as a string */ @@ -208,11 +215,24 @@ private: */ std::vector channels_to_join; bool welcomed; + /** + * See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt section 3.3 + * We store the possible chanmodes in this object. + * chanmodes[0] contains modes of type A, [1] of type B etc + */ + std::vector chanmodes; /** * Each motd line received is appended to this string, which we send when * the motd is completely received */ std::string motd; + /** + * See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt section 3.14 + * The example given would be transformed into + * modes_to_prefix = {{'a', '&'}, {'b', '*'}} + */ + std::map prefix_to_mode; + IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; IrcClient& operator=(const IrcClient&) = delete; @@ -229,6 +249,7 @@ static const std::unordered_map irc_callbacks = { {"NOTICE", &IrcClient::forward_server_message}, {"002", &IrcClient::forward_server_message}, {"003", &IrcClient::forward_server_message}, + {"005", &IrcClient::on_isupport_message}, {"RPL_MOTDSTART", &IrcClient::empty_motd}, {"375", &IrcClient::empty_motd}, {"RPL_MOTD", &IrcClient::on_motd_line}, -- cgit v1.2.3 From acf769d83a40e971ccc1346225688841465b36ee Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 29 Dec 2013 19:57:43 +0100 Subject: Use isupport informations to know the user modes when joining Also remove the duplicate send_self_join methods, user only send_user_join --- src/irc/irc_channel.cpp | 5 +++-- src/irc/irc_channel.hpp | 4 +++- src/irc/irc_client.cpp | 15 ++++++++++----- src/irc/irc_user.cpp | 30 +++++++++++++++--------------- src/irc/irc_user.hpp | 6 +++++- 5 files changed, 36 insertions(+), 24 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 6daf708..80e9b24 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -12,9 +12,10 @@ void IrcChannel::set_self(const std::string& name) this->self = std::make_unique(name); } -IrcUser* IrcChannel::add_user(const std::string& name) +IrcUser* IrcChannel::add_user(const std::string& name, + const std::map prefix_to_mode) { - this->users.emplace_back(std::make_unique(name)); + this->users.emplace_back(std::make_unique(name, prefix_to_mode)); return this->users.back().get(); } diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index c4b6d2c..edb779a 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -5,6 +5,7 @@ #include #include #include +#include /** * Keep the state of a joined channel (the list of occupants with their @@ -19,7 +20,8 @@ public: std::string topic; void set_self(const std::string& name); IrcUser* get_self() const; - IrcUser* add_user(const std::string& name); + IrcUser* add_user(const std::string& name, + const std::map prefix_to_mode); IrcUser* find_user(const std::string& name); void remove_user(const IrcUser* user); diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 912ee45..cdda2b5 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -235,11 +235,16 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) std::vector nicks = utils::split(message.arguments[3], ' '); for (const std::string& nick: nicks) { - const IrcUser* user = channel->add_user(nick); + const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); if (user->nick != channel->get_self()->nick) { log_debug("Adding user [" << nick << "] to chan " << chan_name); - this->bridge->send_user_join(this->hostname, chan_name, user); + this->bridge->send_user_join(this->hostname, chan_name, user, false); + } + else + { + // we now know the modes of self, so copy the modes into self + channel->get_self()->modes = user->modes; } } } @@ -256,8 +261,8 @@ void IrcClient::on_channel_join(const IrcMessage& message) } else { - const IrcUser* user = channel->add_user(nick); - this->bridge->send_user_join(this->hostname, chan_name, user); + const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); + this->bridge->send_user_join(this->hostname, chan_name, user, false); } } @@ -319,7 +324,7 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); - this->bridge->send_self_join(this->hostname, chan_name, channel->get_self()->nick); + this->bridge->send_user_join(this->hostname, chan_name, channel->get_self(), true); this->bridge->send_topic(this->hostname, chan_name, channel->topic); } diff --git a/src/irc/irc_user.cpp b/src/irc/irc_user.cpp index f9866ef..934988a 100644 --- a/src/irc/irc_user.cpp +++ b/src/irc/irc_user.cpp @@ -2,26 +2,26 @@ #include -IrcUser::IrcUser(const std::string& name) +IrcUser::IrcUser(const std::string& name, + const std::map& prefix_to_mode) { + if (name.empty()) + return ; const std::string::size_type sep = name.find("!"); + const std::map::const_iterator prefix = prefix_to_mode.find(name[0]); + const size_t name_begin = prefix == prefix_to_mode.end()? 0: 1; if (sep == std::string::npos) - { - if (name[0] == '~' || name[0] == '&' - || name[0] == '@' || name[0] == '%' - || name[0] == '+') - this->nick = name.substr(1); - else - this->nick = name; - } + this->nick = name.substr(name_begin); else { - if (name[0] == '~' || name[0] == '&' - || name[0] == '@' || name[0] == '%' - || name[0] == '+') - this->nick = name.substr(1, sep); - else - this->nick = name.substr(0, sep); + this->nick = name.substr(name_begin, sep); this->host = name.substr(sep+1); } + if (prefix != prefix_to_mode.end()) + this->modes.insert(prefix->second); +} + +IrcUser::IrcUser(const std::string& name): + IrcUser(name, {}) +{ } diff --git a/src/irc/irc_user.hpp b/src/irc/irc_user.hpp index b76b2ef..f30da4d 100644 --- a/src/irc/irc_user.hpp +++ b/src/irc/irc_user.hpp @@ -2,6 +2,8 @@ # define IRC_USER_INCLUDED #include +#include +#include /** * Keeps various information about one IRC channel user @@ -9,10 +11,12 @@ class IrcUser { public: + explicit IrcUser(const std::string& name, + const std::map& prefix_to_mode); explicit IrcUser(const std::string& name); - std::string nick; std::string host; + std::set modes; private: IrcUser(const IrcUser&) = delete; -- cgit v1.2.3 From e840704b58a984351971e8034e74f5e9fdfaf114 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 4 Jan 2014 01:30:03 +0100 Subject: Convert received modes into roles and affiliations --- src/irc/irc_channel.cpp | 2 +- src/irc/irc_channel.hpp | 2 +- src/irc/irc_client.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++++- src/irc/irc_client.hpp | 7 ++++- src/irc/irc_user.cpp | 20 +++++++++++++ src/irc/irc_user.hpp | 4 +++ 6 files changed, 106 insertions(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 80e9b24..99783fa 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -24,7 +24,7 @@ IrcUser* IrcChannel::get_self() const return this->self.get(); } -IrcUser* IrcChannel::find_user(const std::string& name) +IrcUser* IrcChannel::find_user(const std::string& name) const { IrcUser user(name); for (const auto& u: this->users) diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index edb779a..0160469 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -22,7 +22,7 @@ public: IrcUser* get_self() const; IrcUser* add_user(const std::string& name, const std::map prefix_to_mode); - IrcUser* find_user(const std::string& name); + IrcUser* find_user(const std::string& name) const; void remove_user(const IrcUser* user); private: diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index cdda2b5..8a57371 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -218,7 +218,10 @@ void IrcClient::on_isupport_message(const IrcMessage& message) j++; j++; while (j < token.size() && token[i] != ')') - this->prefix_to_mode[token[j++]] = token[i++]; + { + this->sorted_user_modes.push_back(token[i]); + this->prefix_to_mode[token[j++]] = token[i++]; + } } } } @@ -508,6 +511,76 @@ void IrcClient::on_channel_mode(const IrcMessage& message) this->bridge->send_message(iid, "", std::string("Mode ") + iid.chan + " [" + mode_arguments + "] by " + user.nick, true); + const IrcChannel* channel = this->get_channel(iid.chan); + if (!channel) + return; + + // parse the received modes, we need to handle things like "+m-oo coucou toutou" + const std::string modes = message.arguments[1]; + // a list of modified IrcUsers. When we applied all modes, we check the + // modes that now applies to each of them, and send a notification for + // each one. This is to disallow sending two notifications or more when a + // single MODE command changes two or more modes on the same participant + std::set modified_users; + // If it is true, the modes are added, if it’s false they are + // removed. When we encounter the '+' char, the value is changed to true, + // and with '-' it is changed to false. + bool add = true; + bool use_arg; + size_t arg_pos = 2; + for (const char c: modes) + { + if (c == '+') + add = true; + else if (c == '-') + add = false; + else + { // lookup the mode symbol in the 4 chanmodes lists, depending on + // the list where it is found, it takes an argument or not + size_t type; + for (type = 0; type < 4; ++type) + if (this->chanmodes[type].find(c) != std::string::npos) + break; + if (type == 4) // if mode was not found + { + // That mode can also be of type B if it is present in the + // prefix_to_mode map + for (const std::pair& pair: this->prefix_to_mode) + if (pair.second == c) + { + type = 1; + break; + } + } + // modes of type A, B or C (but only with add == true) + if (type == 0 || type == 1 || + (type == 2 && add == true)) + use_arg = true; + else // modes of type C (but only with add == false), D, or unknown + use_arg = false; + if (use_arg == true && message.arguments.size() > arg_pos) + { + const std::string target = message.arguments[arg_pos++]; + IrcUser* user = channel->find_user(target); + if (!user) + { + log_warning("Trying to set mode for non-existing user '" << target + << "' in channel" << iid.chan); + return; + } + if (add) + user->add_mode(c); + else + user->remove_mode(c); + modified_users.insert(user); + } + } + } + for (const IrcUser* u: modified_users) + { + char most_significant_mode = u->get_most_significant_mode(this->sorted_user_modes); + this->bridge->send_affiliation_role_change(iid, u->nick, most_significant_mode); + } } void IrcClient::on_user_mode(const IrcMessage& message) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index a0258ee..96ded44 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -229,9 +229,14 @@ private: /** * See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt section 3.14 * The example given would be transformed into - * modes_to_prefix = {{'a', '&'}, {'b', '*'}} + * modes_to_prefix = {{'&', 'a'}, {'*', 'b'}} */ std::map prefix_to_mode; + /** + * Available user modes, sorted from most significant to least significant + * (for example 'ahov' is a common order). + */ + std::vector sorted_user_modes; IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; diff --git a/src/irc/irc_user.cpp b/src/irc/irc_user.cpp index 934988a..0f1b1ee 100644 --- a/src/irc/irc_user.cpp +++ b/src/irc/irc_user.cpp @@ -25,3 +25,23 @@ IrcUser::IrcUser(const std::string& name): IrcUser(name, {}) { } + +void IrcUser::add_mode(const char mode) +{ + this->modes.insert(mode); +} + +void IrcUser::remove_mode(const char mode) +{ + this->modes.erase(mode); +} + +char IrcUser::get_most_significant_mode(const std::vector& modes) const +{ + for (const char mode: modes) + { + if (this->modes.find(mode) != this->modes.end()) + return mode; + } + return 0; +} diff --git a/src/irc/irc_user.hpp b/src/irc/irc_user.hpp index f30da4d..d3397ca 100644 --- a/src/irc/irc_user.hpp +++ b/src/irc/irc_user.hpp @@ -1,6 +1,7 @@ #ifndef IRC_USER_INCLUDED # define IRC_USER_INCLUDED +#include #include #include #include @@ -14,6 +15,9 @@ public: explicit IrcUser(const std::string& name, const std::map& prefix_to_mode); explicit IrcUser(const std::string& name); + void add_mode(const char mode); + void remove_mode(const char mode); + char get_most_significant_mode(const std::vector& sorted_user_modes) const; std::string nick; std::string host; std::set modes; -- cgit v1.2.3 From fbec16f1a208881ea49923287aae27978d79681e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 4 Jan 2014 01:53:50 +0100 Subject: Possibility to change a channel's topic --- src/irc/irc_client.cpp | 5 +++++ src/irc/irc_client.hpp | 1 + 2 files changed, 6 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 8a57371..644cfd1 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -122,6 +122,11 @@ void IrcClient::send_kick_command(const std::string& chan_name, const std::strin this->send_message(IrcMessage("KICK", {chan_name, target, reason})); } +void IrcClient::send_topic_command(const std::string& chan_name, const std::string& topic) +{ + this->send_message(IrcMessage("TOPIC", {chan_name, topic})); +} + void IrcClient::send_quit_command() { this->send_message(IrcMessage("QUIT", {"gateway shutdown"})); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 96ded44..a058b19 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -97,6 +97,7 @@ public: * Send the KICK irc command */ void send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason); + void send_topic_command(const std::string& chan_name, const std::string& topic); /** * Send the QUIT irc command */ -- cgit v1.2.3 From d90c1978def803390203f0fada3621de8abba0e5 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 4 Jan 2014 01:54:09 +0100 Subject: Fix a bug when receiving a topic change The number of arguments is not always the same --- src/irc/irc_client.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 644cfd1..1e8e326 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -321,9 +321,11 @@ void IrcClient::send_motd(const IrcMessage& message) void IrcClient::on_topic_received(const IrcMessage& message) { - const std::string chan_name = utils::tolower(message.arguments[1]); + if (message.arguments.size() < 2) + return; + const std::string chan_name = utils::tolower(message.arguments[message.arguments.size() - 2]); IrcChannel* channel = this->get_channel(chan_name); - channel->topic = message.arguments[2]; + channel->topic = message.arguments[message.arguments.size() - 1]; if (channel->joined) this->bridge->send_topic(this->hostname, chan_name, channel->topic); } -- cgit v1.2.3 From fef9c8193ddf8cdf81978874be788af9441e2286 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 6 Jan 2014 01:22:43 +0100 Subject: Also set the role and affiliation of users already in the chan --- src/irc/irc_client.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 1e8e326..644351e 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -247,7 +247,9 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) if (user->nick != channel->get_self()->nick) { log_debug("Adding user [" << nick << "] to chan " << chan_name); - this->bridge->send_user_join(this->hostname, chan_name, user, false); + this->bridge->send_user_join(this->hostname, chan_name, user, + user->get_most_significant_mode(this->sorted_user_modes), + false); } else { @@ -270,7 +272,9 @@ void IrcClient::on_channel_join(const IrcMessage& message) else { const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); - this->bridge->send_user_join(this->hostname, chan_name, user, false); + this->bridge->send_user_join(this->hostname, chan_name, user, + user->get_most_significant_mode(this->sorted_user_modes), + false); } } @@ -334,7 +338,9 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); - this->bridge->send_user_join(this->hostname, chan_name, channel->get_self(), true); + this->bridge->send_user_join(this->hostname, chan_name, channel->get_self(), + channel->get_self()->get_most_significant_mode(this->sorted_user_modes), + true); this->bridge->send_topic(this->hostname, chan_name, channel->topic); } -- cgit v1.2.3 From c8b41d5e350354881caa933ab363a2e90f991524 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 8 Feb 2014 07:52:22 +0100 Subject: Be verbose about IRC server connection failures, and handle them properly --- src/irc/irc_client.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 644351e..a84f96e 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -27,7 +27,12 @@ IrcClient::~IrcClient() void IrcClient::start() { - this->connect(this->hostname, "6667"); + this->bridge->send_xmpp_message(this->hostname, "", std::string("Connecting to ") + + this->hostname + ":" + "6667"); + std::pair res = this->connect(this->hostname, "6667"); + if (!res.first) + this->bridge->send_xmpp_message(this->hostname, "", + std::string("Connection failed: ") + res.second); } void IrcClient::on_connected() -- cgit v1.2.3 From 274859c096b25444d475d1319e9296a868ec258c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 8 Feb 2014 08:22:42 +0100 Subject: Handle most generic error IRC messages --- src/irc/irc_client.hpp | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index a058b19..7380a8d 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -270,7 +270,6 @@ static const std::unordered_map irc_callbacks = { {"366", &IrcClient::on_channel_completely_joined}, {"432", &IrcClient::on_erroneous_nickname}, {"433", &IrcClient::on_nickname_conflict}, - {"461", &IrcClient::on_generic_error}, {"001", &IrcClient::on_welcome_message}, {"PART", &IrcClient::on_part}, {"ERROR", &IrcClient::on_error}, @@ -279,6 +278,55 @@ static const std::unordered_map irc_callbacks = { {"MODE", &IrcClient::on_mode}, {"PING", &IrcClient::send_pong_command}, {"KICK", &IrcClient::on_kick}, + + {"401", &IrcClient::on_generic_error}, + {"402", &IrcClient::on_generic_error}, + {"403", &IrcClient::on_generic_error}, + {"404", &IrcClient::on_generic_error}, + {"405", &IrcClient::on_generic_error}, + {"406", &IrcClient::on_generic_error}, + {"407", &IrcClient::on_generic_error}, + {"408", &IrcClient::on_generic_error}, + {"409", &IrcClient::on_generic_error}, + {"410", &IrcClient::on_generic_error}, + {"411", &IrcClient::on_generic_error}, + {"412", &IrcClient::on_generic_error}, + {"414", &IrcClient::on_generic_error}, + {"421", &IrcClient::on_generic_error}, + {"422", &IrcClient::on_generic_error}, + {"423", &IrcClient::on_generic_error}, + {"424", &IrcClient::on_generic_error}, + {"431", &IrcClient::on_generic_error}, + {"436", &IrcClient::on_generic_error}, + {"441", &IrcClient::on_generic_error}, + {"442", &IrcClient::on_generic_error}, + {"443", &IrcClient::on_generic_error}, + {"444", &IrcClient::on_generic_error}, + {"446", &IrcClient::on_generic_error}, + {"451", &IrcClient::on_generic_error}, + {"461", &IrcClient::on_generic_error}, + {"462", &IrcClient::on_generic_error}, + {"463", &IrcClient::on_generic_error}, + {"464", &IrcClient::on_generic_error}, + {"465", &IrcClient::on_generic_error}, + {"467", &IrcClient::on_generic_error}, + {"470", &IrcClient::on_generic_error}, + {"471", &IrcClient::on_generic_error}, + {"472", &IrcClient::on_generic_error}, + {"473", &IrcClient::on_generic_error}, + {"474", &IrcClient::on_generic_error}, + {"475", &IrcClient::on_generic_error}, + {"476", &IrcClient::on_generic_error}, + {"477", &IrcClient::on_generic_error}, + {"481", &IrcClient::on_generic_error}, + {"482", &IrcClient::on_generic_error}, + {"483", &IrcClient::on_generic_error}, + {"484", &IrcClient::on_generic_error}, + {"485", &IrcClient::on_generic_error}, + {"487", &IrcClient::on_generic_error}, + {"491", &IrcClient::on_generic_error}, + {"501", &IrcClient::on_generic_error}, + {"502", &IrcClient::on_generic_error}, }; #endif // IRC_CLIENT_INCLUDED -- cgit v1.2.3 From cf9f3a1f2855b358aa9bbc31f234801e9e1efc28 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 17 Feb 2014 01:43:58 +0100 Subject: Include role and affiliation in the join presence of the nick change process --- src/irc/irc_client.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index a84f96e..bb2fc75 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -469,8 +469,9 @@ void IrcClient::on_nick(const IrcMessage& message) Iid iid; iid.chan = chan_name; iid.server = this->hostname; - bool self = channel->get_self()->nick == old_nick; - this->bridge->send_nick_change(std::move(iid), old_nick, new_nick, self); + 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); user->nick = new_nick; if (self) { -- cgit v1.2.3 From 112197f6ab8ec392aecfccd10af5547633fe7482 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 19 Feb 2014 02:38:22 +0100 Subject: Fix the joined flag on channels, avoid sending the topic twice when joining --- src/irc/irc_client.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index bb2fc75..d65da87 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -270,10 +270,7 @@ void IrcClient::on_channel_join(const IrcMessage& message) IrcChannel* channel = this->get_channel(chan_name); const std::string nick = message.prefix; if (channel->joined == false) - { - channel->joined = true; - channel->set_self(nick); - } + channel->set_self(nick); else { const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); @@ -343,6 +340,7 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); + channel->joined = true; this->bridge->send_user_join(this->hostname, chan_name, channel->get_self(), channel->get_self()->get_most_significant_mode(this->sorted_user_modes), true); -- cgit v1.2.3 From 16be9af3fcd23fa8590692cbe84af20cfe6a60b2 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 19 Feb 2014 23:59:43 +0100 Subject: Send unavailable presence to all muc when the IRC server closes the connection --- src/irc/irc_client.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d65da87..e134bea 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -46,6 +46,8 @@ void IrcClient::on_connection_close() { static const std::string message = "Connection closed by remote server."; this->send_gateway_message(message); + const IrcMessage error{"ERROR", {message}}; + this->on_error(error); log_warning(message); } -- cgit v1.2.3 From 190c4ff1762e5e762e913f98033369ed75ed5291 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 20 Feb 2014 02:19:50 +0100 Subject: QUIT the irc server when the last channel is left --- src/irc/irc_client.cpp | 11 ++++++++--- src/irc/irc_client.hpp | 6 +++++- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index e134bea..0d5c4e3 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -134,9 +134,9 @@ void IrcClient::send_topic_command(const std::string& chan_name, const std::stri this->send_message(IrcMessage("TOPIC", {chan_name, topic})); } -void IrcClient::send_quit_command() +void IrcClient::send_quit_command(const std::string& reason) { - this->send_message(IrcMessage("QUIT", {"gateway shutdown"})); + this->send_message(IrcMessage("QUIT", {reason})); } void IrcClient::send_join_command(const std::string& chan_name) @@ -403,7 +403,6 @@ void IrcClient::on_part(const IrcMessage& message) iid.chan = chan_name; iid.server = this->hostname; bool self = channel->get_self()->nick == nick; - this->bridge->send_muc_leave(std::move(iid), std::move(nick), std::move(txt), self); if (self) { channel->joined = false; @@ -411,6 +410,7 @@ void IrcClient::on_part(const IrcMessage& message) // channel pointer is now invalid channel = nullptr; } + this->bridge->send_muc_leave(std::move(iid), std::move(nick), std::move(txt), self); } } @@ -608,3 +608,8 @@ void IrcClient::on_user_mode(const IrcMessage& message) std::string("User mode for ") + message.arguments[0] + " is [" + message.arguments[1] + "]"); } + +size_t IrcClient::number_of_joined_channels() const +{ + return this->channels.size(); +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 7380a8d..5cd1403 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -101,7 +101,7 @@ public: /** * Send the QUIT irc command */ - void send_quit_command(); + void send_quit_command(const std::string& reason); /** * Send a message to the gateway user, not generated by the IRC server, * but that might be useful because we want to be verbose (for example we @@ -186,6 +186,10 @@ public: */ void on_channel_mode(const IrcMessage& message); void on_quit(const IrcMessage& message); + /** + * Return the number of joined channels + */ + size_t number_of_joined_channels() const; private: /** -- cgit v1.2.3 From 99aba5667d0d7ba6657f9c175a9342126bc4b0f2 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 22 Feb 2014 21:42:24 +0100 Subject: Connection to servers does not block the process anymore --- src/irc/irc_client.cpp | 11 +++++++---- src/irc/irc_client.hpp | 4 ++++ 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0d5c4e3..d35437c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -29,10 +29,13 @@ void IrcClient::start() { this->bridge->send_xmpp_message(this->hostname, "", std::string("Connecting to ") + this->hostname + ":" + "6667"); - std::pair res = this->connect(this->hostname, "6667"); - if (!res.first) - this->bridge->send_xmpp_message(this->hostname, "", - std::string("Connection failed: ") + res.second); + this->connect(this->hostname, "6667"); +} + +void IrcClient::on_connection_failed(const std::string& reason) +{ + this->bridge->send_xmpp_message(this->hostname, "", + std::string("Connection failed: ") + reason); } void IrcClient::on_connected() diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 5cd1403..28a1424 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -29,6 +29,10 @@ public: * Connect to the IRC server */ void start(); + /** + * Called when the connection to the server cannot be established + */ + void on_connection_failed(const std::string& reason) override final; /** * Called when successfully connected to the server */ -- cgit v1.2.3 From 76b131e13a842657b899d8852efb0f92b2d32145 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 25 Feb 2014 02:10:45 +0100 Subject: Do not try to connect to an irc server if we are connected or connecting --- src/irc/irc_client.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d35437c..232b87f 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -27,6 +27,8 @@ IrcClient::~IrcClient() void IrcClient::start() { + if (this->connected || this->connecting) + return ; this->bridge->send_xmpp_message(this->hostname, "", std::string("Connecting to ") + this->hostname + ":" + "6667"); this->connect(this->hostname, "6667"); @@ -144,8 +146,7 @@ void IrcClient::send_quit_command(const std::string& reason) void IrcClient::send_join_command(const std::string& chan_name) { - if (!this->connected) - this->start(); + this->start(); if (this->welcomed == false) this->channels_to_join.push_back(chan_name); else -- cgit v1.2.3 From 86d4347af8532ef85472e47c01d645fa5ad1b3b1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 28 Feb 2014 01:14:38 +0100 Subject: Avoid unnecessary copies by recv()ing data directly into the expat buffer --- src/irc/irc_client.cpp | 2 +- src/irc/irc_client.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 232b87f..0c36372 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -80,7 +80,7 @@ std::string IrcClient::get_own_nick() const return this->current_nick; } -void IrcClient::parse_in_buffer() +void IrcClient::parse_in_buffer(const size_t) { while (true) { diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 28a1424..908db8e 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -45,7 +45,7 @@ public: * Parse the data we have received so far and try to get one or more * complete messages from it. */ - void parse_in_buffer() override final; + void parse_in_buffer(const size_t) override final; /** * Return the channel with this name, create it if it does not yet exist */ -- cgit v1.2.3 From e196d2f1f400f5c9634ed42fcbdf5c5fb63a13fb Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 24 Mar 2014 18:37:31 +0100 Subject: Do not send data if we are connected, send it only once we actually are --- src/irc/irc_client.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0c36372..3737b91 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -45,6 +45,7 @@ void IrcClient::on_connected() this->send_nick_command(this->username); this->send_user_command(this->username, this->username); this->send_gateway_message("Connected to IRC server."); + this->send_pending_data(); } void IrcClient::on_connection_close() -- cgit v1.2.3 From e971f64f92c640d3ee634b01eeba7fbf056fdaac Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 28 Mar 2014 01:47:48 +0100 Subject: Catch all exception produced by a received message (irc or xmpp) --- src/irc/irc_client.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 3737b91..884f214 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -93,7 +93,13 @@ void IrcClient::parse_in_buffer(const size_t) this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); auto cb = irc_callbacks.find(message.command); if (cb != irc_callbacks.end()) - (this->*(cb->second))(message); + { + try { + (this->*(cb->second))(message); + } catch (const std::exception& e) { + log_error("Unhandled exception: " << e.what()); + } + } else log_info("No handler for command " << message.command); } -- cgit v1.2.3 From 020325dbb071f1735bceb80de9f982aefcd2de47 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 13 Apr 2014 15:37:56 +0200 Subject: [WIP] DummyIrcChannel --- src/irc/irc_channel.cpp | 6 ++++++ src/irc/irc_channel.hpp | 33 ++++++++++++++++++++++++++++++++- src/irc/irc_client.cpp | 23 ++++++++++++++++++++++- src/irc/irc_client.hpp | 17 +++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 99783fa..0604528 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -47,3 +47,9 @@ void IrcChannel::remove_user(const IrcUser* user) } } } + +DummyIrcChannel::DummyIrcChannel(): + IrcChannel(), + joining(false) +{ +} diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index 0160469..ab04d60 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -25,13 +25,44 @@ public: IrcUser* find_user(const std::string& name) const; void remove_user(const IrcUser* user); -private: +protected: std::unique_ptr self; std::vector> users; + +private: IrcChannel(const IrcChannel&) = delete; IrcChannel(IrcChannel&&) = delete; IrcChannel& operator=(const IrcChannel&) = delete; IrcChannel& operator=(IrcChannel&&) = delete; }; +/** + * A special channel that is not actually linked to any real irc + * channel. This is just a channel representing a connection to the + * server. If an user wants to maintain the connection to the server without + * having to be on any irc channel of that server, he can just join this + * dummy channel. + * It’s not actually dummy because it’s useful and it does things, but well. + */ +class DummyIrcChannel: public IrcChannel +{ +public: + explicit DummyIrcChannel(); + + /** + * This flag is at true whenever the user wants to join this channel, but + * he is not yet connected to the server. When the connection is made, we + * check that flag and if it’s true, we inform the user that he has just + * joined that channel. + * If the user is already connected to the server when he tries to join + * the channel, we don’t use that flag, we just join it immediately. + */ + bool joining; +private: + DummyIrcChannel(const DummyIrcChannel&) = delete; + DummyIrcChannel(DummyIrcChannel&&) = delete; + DummyIrcChannel& operator=(const DummyIrcChannel&) = delete; + DummyIrcChannel& operator=(DummyIrcChannel&&) = delete; +}; + #endif // IRC_CHANNEL_INCLUDED diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 884f214..e565658 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -280,7 +280,11 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) void IrcClient::on_channel_join(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[0]); - IrcChannel* channel = this->get_channel(chan_name); + IrcChannel* channel; + if (chan_name.empty()) + channel = &this->dummy_channel; + else + channel = this->get_channel(chan_name); const std::string nick = message.prefix; if (channel->joined == false) channel->set_self(nick); @@ -394,6 +398,18 @@ void IrcClient::on_welcome_message(const IrcMessage& message) for (const std::string& chan_name: this->channels_to_join) this->send_join_command(chan_name); this->channels_to_join.clear(); + // Indicate that the dummy channel is joined as well, if needed + if (this->dummy_channel.joining) + { + // Simulate a message coming from the IRC server saying that we joined + // the channel + const IrcMessage join_message(this->get_nick(), "JOIN", {""}); + this->on_channel_join(join_message); + const IrcMessage end_join_message(std::string(this->hostname), "366", + {this->get_nick(), + "", "End of NAMES list"}); + this->on_channel_completely_joined(end_join_message); + } } void IrcClient::on_part(const IrcMessage& message) @@ -624,3 +640,8 @@ size_t IrcClient::number_of_joined_channels() const { return this->channels.size(); } + +DummyIrcChannel& IrcClient::get_dummy_channel() +{ + return this->dummy_channel; +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 908db8e..960d36f 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -194,6 +194,14 @@ public: * Return the number of joined channels */ size_t number_of_joined_channels() const; + /** + * Get a reference to the unique dummy channel + */ + DummyIrcChannel& get_dummy_channel(); + + const std::string& get_hostname() const { return this->hostname; } + std::string get_nick() const { return this->current_nick; } + bool is_welcomed() const { return this->welcomed; } private: /** @@ -216,6 +224,11 @@ private: * The list of joined channels, indexed by name */ std::unordered_map> channels; + /** + * A single channel with a iid of the form "hostname" (normal channel have + * an iid of the form "chan%hostname". + */ + DummyIrcChannel dummy_channel; /** * A list of chan we want to join, but we need a response 001 from * the server before sending the actual JOIN commands. So we just keep the @@ -223,6 +236,10 @@ private: * whenever the WELCOME message is received. */ std::vector channels_to_join; + /** + * This flag indicates that the server is completely joined (connection + * has been established, we are authentified and we have a nick) + */ bool welcomed; /** * See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt section 3.3 -- cgit v1.2.3 From 576fb3d132a11ca787f98da67889690b03c7ba8d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 15 Apr 2014 04:44:09 +0200 Subject: Correctly use the dummy channel whenever we interract with an empty-string chan --- src/irc/irc_client.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index e565658..7be7cc8 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -59,6 +59,8 @@ void IrcClient::on_connection_close() IrcChannel* IrcClient::get_channel(const std::string& name) { + if (name.empty()) + return &this->dummy_channel; try { return this->channels.at(name).get(); -- cgit v1.2.3 From cfca16bbecac9f14812db6d06588aae60cc55649 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 15 Apr 2014 04:44:51 +0200 Subject: Ability to leave the dummy channel --- src/irc/irc_client.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 7be7cc8..78acce5 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -197,7 +197,12 @@ void IrcClient::send_part_command(const std::string& chan_name, const std::strin { IrcChannel* channel = this->get_channel(chan_name); if (channel->joined == true) - this->send_message(IrcMessage("PART", {chan_name, status_message})); + { + if (chan_name.empty()) + this->bridge->send_muc_leave(Iid(std::string("%") + this->hostname), std::string(this->current_nick), "", true); + else + this->send_message(IrcMessage("PART", {chan_name, status_message})); + } } void IrcClient::send_mode_command(const std::string& chan_name, const std::vector& arguments) -- cgit v1.2.3 From 5739d418e2b35dfc038fe1a12f8b5c7eeeed6868 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 15 Apr 2014 04:56:50 +0200 Subject: Better way to leave the dummy room --- src/irc/irc_channel.cpp | 6 ++++++ src/irc/irc_channel.hpp | 1 + src/irc/irc_client.cpp | 12 +++++++++++- src/irc/irc_client.hpp | 5 +++++ 4 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 0604528..7b0e766 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -48,6 +48,12 @@ void IrcChannel::remove_user(const IrcUser* user) } } +void IrcChannel::remove_all_users() +{ + this->users.clear(); + this->self.reset(); +} + DummyIrcChannel::DummyIrcChannel(): IrcChannel(), joining(false) diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index ab04d60..1c074b5 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -24,6 +24,7 @@ public: const std::map prefix_to_mode); IrcUser* find_user(const std::string& name) const; void remove_user(const IrcUser* user); + void remove_all_users(); protected: std::unique_ptr self; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 78acce5..f44821e 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -199,7 +199,7 @@ void IrcClient::send_part_command(const std::string& chan_name, const std::strin if (channel->joined == true) { if (chan_name.empty()) - this->bridge->send_muc_leave(Iid(std::string("%") + this->hostname), std::string(this->current_nick), "", true); + this->leave_dummy_channel(status_message); else this->send_message(IrcMessage("PART", {chan_name, status_message})); } @@ -652,3 +652,13 @@ DummyIrcChannel& IrcClient::get_dummy_channel() { return this->dummy_channel; } + +void IrcClient::leave_dummy_channel(const std::string& exit_message) +{ + if (!this->dummy_channel.joined) + return; + this->dummy_channel.joined = false; + this->dummy_channel.joining = false; + this->dummy_channel.remove_all_users(); + this->bridge->send_muc_leave(Iid(std::string("%") + this->hostname), std::string(this->current_nick), exit_message, true); +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 960d36f..811d416 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -198,6 +198,11 @@ public: * Get a reference to the unique dummy channel */ DummyIrcChannel& get_dummy_channel(); + /** + * Leave the dummy channel: forward a message to the user to indicate that + * he left it, and mark it as not joined. + */ + void leave_dummy_channel(const std::string& exit_message); const std::string& get_hostname() const { return this->hostname; } std::string get_nick() const { return this->current_nick; } -- cgit v1.2.3 From 28065d3d52cc48abd39a8556a0c282014b18f25a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 15 Apr 2014 05:08:07 +0200 Subject: Do not disconnect from the IRC server if the dummy channel is joined --- src/irc/irc_client.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index f44821e..55c442b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -645,7 +645,10 @@ void IrcClient::on_user_mode(const IrcMessage& message) size_t IrcClient::number_of_joined_channels() const { - return this->channels.size(); + if (this->dummy_channel.joined) + return this->channels.size() + 1; + else + return this->channels.size(); } DummyIrcChannel& IrcClient::get_dummy_channel() -- cgit v1.2.3 From 3bc6f1834738a1ee5a97580678ce204c0c215b71 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 15 Apr 2014 05:22:32 +0200 Subject: Add an explanatory topic on the dummy channel --- src/irc/irc_client.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 55c442b..537b738 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -19,6 +19,14 @@ IrcClient::IrcClient(const std::string& hostname, const std::string& username, B welcomed(false), chanmodes({"", "", "", ""}) { + this->dummy_channel.topic = "This is a virtual channel provided for " + "convenience by biboumi, it is not connected " + "to any actual IRC channel of the server '" + this->hostname + + "', and sending messages in it has no effect. " + "Its main goal is to keep the connection to the IRC server " + "alive without having to join a real channel of that server. " + "To disconnect from the IRC server, leave this room and all " + "other IRC channels of that server."; } IrcClient::~IrcClient() -- cgit v1.2.3 From 77a84fd2d99bcffd562f09c8235e5bcd365accb1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 25 Apr 2014 00:35:57 +0200 Subject: NOTICE from channels are displayed in the channel, with a green "[notice]" --- src/irc/irc_client.cpp | 15 +++++++++++++++ src/irc/irc_client.hpp | 6 +++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 537b738..f077e37 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -235,6 +235,21 @@ void IrcClient::forward_server_message(const IrcMessage& message) this->bridge->send_xmpp_message(this->hostname, from, body); } +void IrcClient::on_notice(const IrcMessage& message) +{ + std::string from = message.prefix; + const std::string to = message.arguments[0]; + const std::string body = message.arguments[1]; + + if (to == this->current_nick) + this->bridge->send_xmpp_message(this->hostname, from, body); + else + { + IrcMessage modified_message(std::move(from), "PRIVMSG", {to, std::string("\u000303[notice]\u0003 ") + body}); + this->on_channel_message(modified_message); + } +} + void IrcClient::on_isupport_message(const IrcMessage& message) { const size_t len = message.arguments.size(); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 811d416..849190a 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -147,6 +147,10 @@ public: * When a channel message is received */ void on_channel_message(const IrcMessage& message); + /** + * A notice is received + */ + void on_notice(const IrcMessage& message); /** * Save the topic in the IrcChannel */ @@ -282,7 +286,7 @@ private: typedef void (IrcClient::*irc_callback_t)(const IrcMessage&); static const std::unordered_map irc_callbacks = { - {"NOTICE", &IrcClient::forward_server_message}, + {"NOTICE", &IrcClient::on_notice}, {"002", &IrcClient::forward_server_message}, {"003", &IrcClient::forward_server_message}, {"005", &IrcClient::on_isupport_message}, -- cgit v1.2.3 From c6059e5a215624e205cae401183f3a8bb1bf87d0 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 28 Apr 2014 18:46:25 +0200 Subject: Upgrade to C++14 --- src/irc/irc_channel.cpp | 1 - src/irc/irc_client.cpp | 1 - 2 files changed, 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 7b0e766..2c0f8b1 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -1,5 +1,4 @@ #include -#include IrcChannel::IrcChannel(): joined(false), diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index f077e37..e70dbe4 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include -- cgit v1.2.3 From f6e6b8905be010d7329316cea4546900ad8a2d19 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 29 Apr 2014 21:50:13 +0200 Subject: Use C++14 string_literals --- src/irc/irc_client.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index e70dbe4..da5a947 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -10,6 +10,9 @@ #include #include +#include +using namespace std::string_literals; + IrcClient::IrcClient(const std::string& hostname, const std::string& username, Bridge* bridge): hostname(hostname), username(username), @@ -36,7 +39,7 @@ void IrcClient::start() { if (this->connected || this->connecting) return ; - this->bridge->send_xmpp_message(this->hostname, "", std::string("Connecting to ") + + this->bridge->send_xmpp_message(this->hostname, "", "Connecting to "s + this->hostname + ":" + "6667"); this->connect(this->hostname, "6667"); } @@ -44,7 +47,7 @@ void IrcClient::start() void IrcClient::on_connection_failed(const std::string& reason) { this->bridge->send_xmpp_message(this->hostname, "", - std::string("Connection failed: ") + reason); + "Connection failed: "s + reason); } void IrcClient::on_connected() @@ -244,7 +247,7 @@ void IrcClient::on_notice(const IrcMessage& message) this->bridge->send_xmpp_message(this->hostname, from, body); else { - IrcMessage modified_message(std::move(from), "PRIVMSG", {to, std::string("\u000303[notice]\u0003 ") + body}); + IrcMessage modified_message(std::move(from), "PRIVMSG", {to, "\u000303[notice]\u0003 "s + body}); this->on_channel_message(modified_message); } } @@ -344,7 +347,7 @@ void IrcClient::on_channel_message(const IrcMessage& message) { if (body.substr(1, 6) == "ACTION") this->bridge->send_message(iid, nick, - std::string("/me") + body.substr(7, body.size() - 8), muc); + "/me"s + body.substr(7, body.size() - 8), muc); } else this->bridge->send_message(iid, nick, body, muc); @@ -486,7 +489,7 @@ void IrcClient::on_error(const IrcMessage& message) this->bridge->send_muc_leave(std::move(iid), std::move(own_nick), leave_message, true); } this->channels.clear(); - this->send_gateway_message(std::string("ERROR: ") + leave_message); + this->send_gateway_message("ERROR: "s + leave_message); } void IrcClient::on_quit(const IrcMessage& message) @@ -583,7 +586,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message) mode_arguments += message.arguments[i]; } } - this->bridge->send_message(iid, "", std::string("Mode ") + iid.chan + + this->bridge->send_message(iid, "", "Mode "s + iid.chan + " [" + mode_arguments + "] by " + user.nick, true); const IrcChannel* channel = this->get_channel(iid.chan); @@ -661,7 +664,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message) void IrcClient::on_user_mode(const IrcMessage& message) { this->bridge->send_xmpp_message(this->hostname, "", - std::string("User mode for ") + message.arguments[0] + + "User mode for "s + message.arguments[0] + " is [" + message.arguments[1] + "]"); } @@ -685,5 +688,5 @@ 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(std::string("%") + this->hostname), std::string(this->current_nick), exit_message, true); + this->bridge->send_muc_leave(Iid("%"s + this->hostname), std::string(this->current_nick), exit_message, true); } -- cgit v1.2.3 From 5ec05cb0edda6b01ff5c21a42edf9142b90399e5 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 6 May 2014 22:50:37 +0200 Subject: Forward CTCP version request to XMPP --- src/irc/irc_client.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index da5a947..5f70efb 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -348,6 +348,8 @@ void IrcClient::on_channel_message(const IrcMessage& message) if (body.substr(1, 6) == "ACTION") this->bridge->send_message(iid, nick, "/me"s + body.substr(7, body.size() - 8), muc); + else if (body.substr(1, 8) == "VERSION\01") + this->bridge->send_iq_version_request(nick, this->hostname); } else this->bridge->send_message(iid, nick, body, muc); -- cgit v1.2.3 From 579ca4bdb6b8806d821daa2ee47d60260b64f0f8 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 7 May 2014 02:02:47 +0200 Subject: Forward iq version results to IRC --- src/irc/irc_client.cpp | 4 ++-- src/irc/irc_client.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 5f70efb..c149311 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -192,12 +192,12 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st return true; } -void IrcClient::send_private_message(const std::string& username, const std::string& body) +void IrcClient::send_private_message(const std::string& username, const std::string& body, const std::string& type) { std::string::size_type pos = 0; while (pos < body.size()) { - this->send_message(IrcMessage("PRIVMSG", {username, body.substr(pos, 400)})); + this->send_message(IrcMessage(std::string(type), {username, body.substr(pos, 400)})); pos += 400; } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 849190a..a2e2afe 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -88,7 +88,7 @@ public: /** * Send a PRIVMSG command for an user */ - void send_private_message(const std::string& username, const std::string& body); + void send_private_message(const std::string& username, const std::string& body, const std::string& type); /** * Send the PART irc command */ -- cgit v1.2.3 From 712b7bdfdfe5d77001669dd1d11a860437dc3849 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 14 May 2014 21:48:38 +0200 Subject: Correctly handle the usage of ! as a IRC user mode indicator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since “!” is also the separator between the nickname and the user hostname, having “!” as the user mode (e.g. !nick!~some@host.bla) would cause the nick to be empty. Now we skip it if it is a valid user mode indicator. --- src/irc/irc_user.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_user.cpp b/src/irc/irc_user.cpp index 0f1b1ee..8785270 100644 --- a/src/irc/irc_user.cpp +++ b/src/irc/irc_user.cpp @@ -7,14 +7,14 @@ IrcUser::IrcUser(const std::string& name, { if (name.empty()) return ; - const std::string::size_type sep = name.find("!"); const std::map::const_iterator prefix = prefix_to_mode.find(name[0]); - const size_t name_begin = prefix == prefix_to_mode.end()? 0: 1; + const std::string::size_type name_begin = prefix == prefix_to_mode.end()? 0: 1; + const std::string::size_type sep = name.find("!", name_begin); if (sep == std::string::npos) this->nick = name.substr(name_begin); else { - this->nick = name.substr(name_begin, sep); + this->nick = name.substr(name_begin, sep-name_begin); this->host = name.substr(sep+1); } if (prefix != prefix_to_mode.end()) -- cgit v1.2.3 From 5507adbe9473f4b41e52d16498f14850773e5e45 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 27 May 2014 01:01:44 +0200 Subject: SocketHandlers own the poller and add themself into it only when the socket is created MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to call socket() with the parameters provided by getaddrinfo, so we can’t addd the fd into the poller immediately. We need to wait the connection attempt, and then the SocketHandler can call add_socket_handler itself, if the connection succeeds, or is in progress. --- src/irc/irc_client.cpp | 3 ++- src/irc/irc_client.hpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index c149311..cea08f2 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -13,7 +13,8 @@ #include using namespace std::string_literals; -IrcClient::IrcClient(const std::string& hostname, const std::string& username, Bridge* bridge): +IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& username, Bridge* bridge): + SocketHandler(poller), hostname(hostname), username(username), current_nick(username), diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index a2e2afe..e70ee33 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -23,7 +24,7 @@ class Bridge; class IrcClient: public SocketHandler { public: - explicit IrcClient(const std::string& hostname, const std::string& username, Bridge* bridge); + explicit IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& username, Bridge* bridge); ~IrcClient(); /** * Connect to the IRC server -- cgit v1.2.3 From 796af0531e0f5eb5fa2b800370338ede120a867d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 27 May 2014 02:17:25 +0200 Subject: Add support for CHANTYPES isupport element, to know the prefixes of channels --- src/irc/irc_client.cpp | 15 ++++++++++++--- src/irc/irc_client.hpp | 6 ++++++ 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index cea08f2..03402e7 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -20,7 +20,8 @@ IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname current_nick(username), bridge(bridge), welcomed(false), - chanmodes({"", "", "", ""}) + chanmodes({"", "", "", ""}), + chantypes({'#', '&'}) { this->dummy_channel.topic = "This is a virtual channel provided for " "convenience by biboumi, it is not connected " @@ -279,6 +280,15 @@ void IrcClient::on_isupport_message(const IrcMessage& message) this->prefix_to_mode[token[j++]] = token[i++]; } } + else if (token.substr(0, 10) == "CHANTYPES=") + { + // Remove the default types, they apply only if no other value is + // specified. + this->chantypes.clear(); + size_t i = 11; + while (i < token.size()) + this->chantypes.insert(token[i++]); + } } } @@ -564,8 +574,7 @@ void IrcClient::on_kick(const IrcMessage& message) void IrcClient::on_mode(const IrcMessage& message) { const std::string target = message.arguments[0]; - if (target[0] == '&' || target[0] == '#' || - target[0] == '!' || target[0] == '+') + if (this->chantypes.find(target[0]) != this->chantypes.end()) this->on_channel_mode(message); else this->on_user_mode(message); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index e70ee33..e6fb393 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -12,6 +12,7 @@ #include #include #include +#include class Bridge; @@ -257,6 +258,11 @@ private: * chanmodes[0] contains modes of type A, [1] of type B etc */ std::vector chanmodes; + /** + * See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt + * section 3.5 + */ + std::set chantypes; /** * Each motd line received is appended to this string, which we send when * the motd is completely received -- cgit v1.2.3 From aea923bcb99f8a7dee83202b035bc377cf835c65 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 27 May 2014 02:30:11 +0200 Subject: Use the CHANTYPES values to differentiate channel or user notices It also happens to fix #2517 because this used to create buggy channels named "auth" and stuf like that. --- src/irc/irc_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 03402e7..1411689 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -245,7 +245,7 @@ void IrcClient::on_notice(const IrcMessage& message) const std::string to = message.arguments[0]; const std::string body = message.arguments[1]; - if (to == this->current_nick) + if (!to.empty() && this->chantypes.find(to[0]) == this->chantypes.end()) this->bridge->send_xmpp_message(this->hostname, from, body); else { -- cgit v1.2.3 From 34739728f930f461ae6763a5f144f709a9919e59 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 26 May 2014 18:34:56 +0200 Subject: Fix a by-one error in the CHANTYPES parsing --- src/irc/irc_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 1411689..270e0ed 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -285,7 +285,7 @@ void IrcClient::on_isupport_message(const IrcMessage& message) // Remove the default types, they apply only if no other value is // specified. this->chantypes.clear(); - size_t i = 11; + size_t i = 10; while (i < token.size()) this->chantypes.insert(token[i++]); } -- cgit v1.2.3 From 6c2d03da4ea0443624b6bf434b6a654c12e48438 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 28 May 2014 01:27:41 +0200 Subject: Send an error presence when the connection to the IRC server fails --- src/irc/irc_client.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 270e0ed..f08e9d6 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -50,6 +50,13 @@ void IrcClient::on_connection_failed(const std::string& reason) { this->bridge->send_xmpp_message(this->hostname, "", "Connection failed: "s + reason); + // Send an error message for all room that the user wanted to join + for (const std::string& channel: this->channels_to_join) + { + Iid iid(channel + "%" + this->hostname); + this->bridge->send_join_failed(iid, this->current_nick, + "cancel", "item-not-found", reason); + } } void IrcClient::on_connected() @@ -167,11 +174,11 @@ void IrcClient::send_quit_command(const std::string& reason) void IrcClient::send_join_command(const std::string& chan_name) { - this->start(); if (this->welcomed == false) this->channels_to_join.push_back(chan_name); else this->send_message(IrcMessage("JOIN", {chan_name})); + this->start(); } bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) -- cgit v1.2.3 From c2311b2893f3db755b67c43e5ad60cef66b10ab2 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 30 May 2014 16:08:23 +0200 Subject: Send (every 240s) a PING command to all connected irc servers fix #2452 --- src/irc/irc_client.cpp | 15 +++++++++++++++ src/irc/irc_client.hpp | 1 + 2 files changed, 16 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index f08e9d6..01bf569 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,8 +11,11 @@ #include #include +#include #include + using namespace std::string_literals; +using namespace std::chrono_literals; IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& username, Bridge* bridge): SocketHandler(poller), @@ -35,6 +39,9 @@ IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname IrcClient::~IrcClient() { + // This event may or may not exist (if we never got connected, it + // doesn't), but it's ok + TimedEventsManager::instance().cancel("PING"s + this->hostname + this->bridge->get_jid()); } void IrcClient::start() @@ -238,6 +245,11 @@ void IrcClient::send_pong_command(const IrcMessage& message) this->send_message(IrcMessage("PONG", {id})); } +void IrcClient::send_ping_command() +{ + this->send_message(IrcMessage("PING", {"biboumi"})); +} + void IrcClient::forward_server_message(const IrcMessage& message) { const std::string from = message.prefix; @@ -447,6 +459,9 @@ void IrcClient::on_welcome_message(const IrcMessage& message) { this->current_nick = message.arguments[0]; this->welcomed = true; + // Install a repeated events to regularly send a PING + TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this), + "PING"s + this->hostname + this->bridge->get_jid())); for (const std::string& chan_name: this->channels_to_join) this->send_join_command(chan_name); this->channels_to_join.clear(); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index e6fb393..2f28c95 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -70,6 +70,7 @@ public: * Send the PONG irc command */ void send_pong_command(const IrcMessage& message); + void send_ping_command(); /** * Send the USER irc command */ -- cgit v1.2.3 From 23f32ba39ebe5e9bbdfc4dd00d9914c0f0447ef4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 18 May 2014 20:23:08 +0200 Subject: Implement TLS support using Botan For now, it tries two TLS ports and then connects to the non-tls port. In the future we would like the user to be able to configure that. fix #2435 --- src/irc/irc_client.cpp | 36 +++++++++++++++++++++++++++--------- src/irc/irc_client.hpp | 9 +++++++-- 2 files changed, 34 insertions(+), 11 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 01bf569..c3765a6 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -14,6 +14,8 @@ #include #include +#include "config.h" + using namespace std::string_literals; using namespace std::chrono_literals; @@ -35,6 +37,13 @@ IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname "alive without having to join a real channel of that server. " "To disconnect from the IRC server, leave this room and all " "other IRC channels of that server."; + // TODO: get the values from the preferences of the user, and only use the + // list of default ports if the user didn't specify anything + this->ports_to_try.emplace("6667", false); // standard non-encrypted port +#ifdef BOTAN_FOUND + this->ports_to_try.emplace("6670", true); // non-standard but I want it for some servers + this->ports_to_try.emplace("6697", true); // standard encrypted port +#endif // BOTAN_FOUND } IrcClient::~IrcClient() @@ -48,29 +57,39 @@ void IrcClient::start() { if (this->connected || this->connecting) return ; + std::string port; + bool tls; + std::tie(port, tls) = this->ports_to_try.top(); + this->ports_to_try.pop(); this->bridge->send_xmpp_message(this->hostname, "", "Connecting to "s + - this->hostname + ":" + "6667"); - this->connect(this->hostname, "6667"); + this->hostname + ":" + port + " (" + + (tls ? "encrypted" : "not encrypted") + ")"); + this->connect(this->hostname, port, tls); } void IrcClient::on_connection_failed(const std::string& reason) { this->bridge->send_xmpp_message(this->hostname, "", "Connection failed: "s + reason); - // Send an error message for all room that the user wanted to join - for (const std::string& channel: this->channels_to_join) + if (this->ports_to_try.empty()) { - Iid iid(channel + "%" + this->hostname); - this->bridge->send_join_failed(iid, this->current_nick, - "cancel", "item-not-found", reason); + // Send an error message for all room that the user wanted to join + for (const std::string& channel: this->channels_to_join) + { + Iid iid(channel + "%" + this->hostname); + this->bridge->send_join_failed(iid, this->current_nick, + "cancel", "item-not-found", reason); + } } + else // try the next port + this->start(); } void IrcClient::on_connected() { this->send_nick_command(this->username); this->send_user_command(this->username, this->username); - this->send_gateway_message("Connected to IRC server."); + this->send_gateway_message("Connected to IRC server"s + (this->use_tls ? " (encrypted)": "") + "."); this->send_pending_data(); } @@ -326,7 +345,6 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); if (user->nick != channel->get_self()->nick) { - log_debug("Adding user [" << nick << "] to chan " << chan_name); this->bridge->send_user_join(this->hostname, chan_name, user, user->get_most_significant_mode(this->sorted_user_modes), false); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 2f28c95..7dff1db 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -19,8 +20,6 @@ class Bridge; /** * Represent one IRC client, i.e. an endpoint connected to a single IRC * server, through a TCP socket, receiving and sending commands to it. - * - * TODO: TLS support, maybe, but that's not high priority */ class IrcClient: public SocketHandler { @@ -280,6 +279,12 @@ private: * (for example 'ahov' is a common order). */ std::vector sorted_user_modes; + /** + * A list of ports to which we will try to connect, in reverse. Each port + * is associated with a boolean telling if we should use TLS or not if the + * connection succeeds on that port. + */ + std::stack> ports_to_try; IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; -- cgit v1.2.3 From 7c1a38999c2eebfbd0939c9f8f8f864f10d9bc9a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 11 Jun 2014 02:37:11 +0200 Subject: Rewrite the whole IID usage IRC users and channels are now distinguished by the separator used in the IID (% or !). ref #2468 --- src/irc/iid.cpp | 62 +++++++++++++++++++++++++++++++++++++++++-------- src/irc/iid.hpp | 63 +++++++++++++++++++++++++++++++++++++++----------- src/irc/irc_client.cpp | 61 ++++++++++++++++++++++++++++-------------------- 3 files changed, 138 insertions(+), 48 deletions(-) (limited to 'src/irc') 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 + #include -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 /** - * 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) -- cgit v1.2.3 From a705b9af7b1bbce6b6c94788398a4cff9cad9ec9 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 19 Jun 2014 01:10:13 +0200 Subject: =?UTF-8?q?Remove=20a=20duplicate=20=E2=80=9Cconnection=20closed?= =?UTF-8?q?=E2=80=9D=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/irc/irc_client.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 6e22980..cc54971 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -96,7 +96,6 @@ void IrcClient::on_connected() void IrcClient::on_connection_close() { static const std::string message = "Connection closed by remote server."; - this->send_gateway_message(message); const IrcMessage error{"ERROR", {message}}; this->on_error(error); log_warning(message); -- cgit v1.2.3 From 26ffc8fe121e03e1b663aa0015a71b0fc914f95e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 19 Jun 2014 22:21:49 +0200 Subject: Implement a way to add callbacks, waiting for an IRC event to return an iq --- src/irc/iid.cpp | 8 ++++++++ src/irc/iid.hpp | 2 +- src/irc/irc_client.cpp | 7 ++++++- 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 4893e9e..0bb991f 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -20,6 +20,14 @@ Iid::Iid(const std::string& iid): this->set_server(iid); } +Iid::Iid(const Iid& other): + is_channel(other.is_channel), + is_user(other.is_user), + local(other.local), + server(other.server) +{ +} + Iid::Iid(): is_channel(false), is_user(false) diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index 2302a18..c547dea 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -43,6 +43,7 @@ class Iid { public: explicit Iid(const std::string& iid); + explicit Iid(const Iid&); explicit Iid(); void set_local(const std::string& loc); @@ -59,7 +60,6 @@ private: std::string local; std::string server; - Iid(const Iid&) = delete; Iid(Iid&&) = delete; Iid& operator=(const Iid&) = delete; Iid& operator=(Iid&&) = delete; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index cc54971..d179aaa 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -136,8 +136,11 @@ void IrcClient::parse_in_buffer(const size_t) if (pos == std::string::npos) break ; IrcMessage message(this->in_buf.substr(0, pos)); - log_debug("IRC RECEIVING: " << message); this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); + log_debug("IRC RECEIVING: " << message); + + // Call the standard callback (if any), associated with the command + // name that we just received. auto cb = irc_callbacks.find(message.command); if (cb != irc_callbacks.end()) { @@ -149,6 +152,8 @@ void IrcClient::parse_in_buffer(const size_t) } else log_info("No handler for command " << message.command); + // Try to find a waiting_iq, which response will be triggered by this IrcMessage + this->bridge->trigger_response_iq(this->hostname, message); } } -- cgit v1.2.3 From 04d999168ac4629f5e49939f3659b32b2da2563d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 2 Jul 2014 03:01:09 +0200 Subject: Add a level of inheritance above SocketHandler SocketHandler has been renamed to TCPSocketHandler SocketHandler is now a simple interface with a few methods, used only by Poller. This way we can inherite from the new SocketHandler class, to handle other types of sockets, and still make them manageable by the poller without any change in the Poller class. --- src/irc/irc_client.cpp | 2 +- src/irc/irc_client.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d179aaa..6468094 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -20,7 +20,7 @@ using namespace std::string_literals; using namespace std::chrono_literals; IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& username, Bridge* bridge): - SocketHandler(poller), + TCPSocketHandler(poller), hostname(hostname), username(username), current_nick(username), diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 7dff1db..afa6437 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include @@ -21,7 +21,7 @@ class Bridge; * Represent one IRC client, i.e. an endpoint connected to a single IRC * server, through a TCP socket, receiving and sending commands to it. */ -class IrcClient: public SocketHandler +class IrcClient: public TCPSocketHandler { public: explicit IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& username, Bridge* bridge); -- cgit v1.2.3 From 11a31db2d5bcc158bb8902e74f192dbc82827f53 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 15 Jul 2014 15:39:25 +0200 Subject: Send the reason of the connection close to the user --- src/irc/irc_client.cpp | 6 ++++-- src/irc/irc_client.hpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 6468094..e518ffc 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -93,9 +93,11 @@ void IrcClient::on_connected() this->send_pending_data(); } -void IrcClient::on_connection_close() +void IrcClient::on_connection_close(const std::string& error_msg) { - static const std::string message = "Connection closed by remote server."; + std::string message = "Connection closed by remote server."; + if (!error_msg.empty()) + message += ": " + error_msg; const IrcMessage error{"ERROR", {message}}; this->on_error(error); log_warning(message); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index afa6437..88d2d72 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -41,7 +41,7 @@ public: /** * Close the connection, remove us from the poller */ - void on_connection_close() override final; + void on_connection_close(const std::string& error) override final; /** * Parse the data we have received so far and try to get one or more * complete messages from it. -- cgit v1.2.3 From e3ea0d62c79cf74e154f24d7f5a0fa8c7d26d73b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 8 Aug 2014 00:46:27 +0200 Subject: Use generic send_presence_error() instead of almost identical specializations --- src/irc/irc_client.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index e518ffc..678cac8 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -77,8 +77,9 @@ void IrcClient::on_connection_failed(const std::string& reason) for (const std::string& channel: this->channels_to_join) { Iid iid(channel + "%" + this->hostname); - this->bridge->send_join_failed(iid, this->current_nick, - "cancel", "item-not-found", reason); + this->bridge->send_presence_error(iid, this->current_nick, + "cancel", "item-not-found", + "", reason); } } else // try the next port -- cgit v1.2.3 From 41e8a3ba9b57e67aec5d0d30112338664afbd6e4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 8 Aug 2014 00:47:05 +0200 Subject: Send a proper error on IRC message 438 (nickname change too fast) fix #2576 --- src/irc/irc_client.cpp | 19 +++++++++++++++++++ src/irc/irc_client.hpp | 5 +++++ 2 files changed, 24 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 678cac8..f9ebfa0 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -478,6 +478,25 @@ void IrcClient::on_nickname_conflict(const IrcMessage& message) } } +void IrcClient::on_nickname_change_too_fast(const IrcMessage& message) +{ + const std::string nickname = message.arguments[1]; + std::string txt; + if (message.arguments.size() >= 3) + txt = message.arguments[2]; + this->on_generic_error(message); + for (auto it = this->channels.begin(); it != this->channels.end(); ++it) + { + Iid iid; + iid.set_local(it->first); + iid.set_server(this->hostname); + iid.is_channel = true; + this->bridge->send_presence_error(iid, nickname, + "cancel", "not-acceptable", + "", txt); + } +} + void IrcClient::on_generic_error(const IrcMessage& message) { const std::string error_msg = message.arguments.size() >= 3 ? diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 88d2d72..9bef04a 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -171,6 +171,10 @@ public: * presence conflict from all channels, because the name is server-wide. */ void on_nickname_conflict(const IrcMessage& message); + /** + * Idem, but for when the user changes their nickname too quickly + */ + void on_nickname_change_too_fast(const IrcMessage& message); /** * Handles most errors from the server by just forwarding the message to the user. */ @@ -317,6 +321,7 @@ static const std::unordered_map irc_callbacks = { {"366", &IrcClient::on_channel_completely_joined}, {"432", &IrcClient::on_erroneous_nickname}, {"433", &IrcClient::on_nickname_conflict}, + {"438", &IrcClient::on_nickname_change_too_fast}, {"001", &IrcClient::on_welcome_message}, {"PART", &IrcClient::on_part}, {"ERROR", &IrcClient::on_error}, -- cgit v1.2.3 From e1d69806ed7c92bdfe1bf632064bf68b3d1d266b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 12 Nov 2014 04:05:56 +0100 Subject: =?UTF-8?q?Rename=20iq=5Fresponder=5Fcallback=5Ft=20to=20irc=5F?= =?UTF-8?q?=E2=80=A6=20and=20add=20the=20equivalent=20to=20wait=20for=20iq?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/irc/iid.hpp | 2 +- src/irc/irc_client.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index c547dea..d30cbaa 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -42,7 +42,7 @@ class Iid { public: - explicit Iid(const std::string& iid); + Iid(const std::string& iid); explicit Iid(const Iid&); explicit Iid(); diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index f9ebfa0..90f0644 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -156,7 +156,7 @@ void IrcClient::parse_in_buffer(const size_t) else log_info("No handler for command " << message.command); // Try to find a waiting_iq, which response will be triggered by this IrcMessage - this->bridge->trigger_response_iq(this->hostname, message); + this->bridge->trigger_on_irc_message(this->hostname, message); } } -- cgit v1.2.3 From d8da7984b23bf8f30b5f8f53895cbae5be50347a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 12 Nov 2014 06:16:10 +0100 Subject: Implement PING, user to user only (XMPP and IRC side, using CTCP PING) ref #2757 --- src/irc/irc_client.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 90f0644..707593f 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -409,6 +409,9 @@ void IrcClient::on_channel_message(const IrcMessage& message) "/me"s + body.substr(7, body.size() - 8), muc); else if (body.substr(1, 8) == "VERSION\01") this->bridge->send_iq_version_request(nick, this->hostname); + else if (body.substr(1, 5) == "PING ") + this->bridge->send_xmpp_ping_request(nick, this->hostname, + body.substr(6, body.size() - 7)); } else this->bridge->send_message(iid, nick, body, muc); -- cgit v1.2.3 From 720e31a5113c25e48d7754bb812ab84c6c31d1d9 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 17 Dec 2014 13:37:57 +0100 Subject: Fix a few issues reported by static analyzers --- src/irc/irc_channel.cpp | 2 +- src/irc/irc_channel.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 2c0f8b1..b1b3983 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -12,7 +12,7 @@ void IrcChannel::set_self(const std::string& name) } IrcUser* IrcChannel::add_user(const std::string& name, - const std::map prefix_to_mode) + const std::map& prefix_to_mode) { this->users.emplace_back(std::make_unique(name, prefix_to_mode)); return this->users.back().get(); diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index 1c074b5..568de0a 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -21,7 +21,7 @@ public: void set_self(const std::string& name); IrcUser* get_self() const; IrcUser* add_user(const std::string& name, - const std::map prefix_to_mode); + const std::map& prefix_to_mode); IrcUser* find_user(const std::string& name) const; void remove_user(const IrcUser* user); void remove_all_users(); -- cgit v1.2.3 From b79dbefbe71824d8d42c5034a6900644a0850c4c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 12 Jan 2015 22:50:06 +0100 Subject: If we sent a message to a user, their notices are considered private messages fix #2882 --- src/irc/irc_client.cpp | 27 +++++++++++++++++++++++++-- src/irc/irc_client.hpp | 4 ++++ 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 707593f..228fc6e 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -243,7 +243,9 @@ void IrcClient::send_private_message(const std::string& username, const std::str this->send_message(IrcMessage(std::string(type), {username, body.substr(pos, 400)})); pos += 400; } - + // We always try to insert and we don't care if the username was already + // in the set. + this->nicks_to_treat_as_private.insert(username); } void IrcClient::send_part_command(const std::string& chan_name, const std::string& status_message) @@ -292,9 +294,30 @@ void IrcClient::on_notice(const IrcMessage& message) const std::string body = message.arguments[1]; if (!to.empty() && this->chantypes.find(to[0]) == this->chantypes.end()) - this->bridge->send_xmpp_message(this->hostname, from, body); + { + // The notice is for the us precisely. + + // Find out if we already sent a private message to this user. If yes + // we treat that message as a private message coming from + // it. Otherwise we treat it as a notice coming from the server. + IrcUser user(from); + std::string nick = utils::tolower(user.nick); + log_debug("received notice from nick: " << nick); + 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(iid, nick, body, muc); + this->bridge->send_message({nick + "!" + this->hostname}, nick, body, + false); + } + else + this->bridge->send_xmpp_message(this->hostname, from, body); + } else { + // The notice was directed at a channel we are in. Modify the message + // to indicate that it is a notice, and make it a MUC message coming + // from the MUC JID IrcMessage modified_message(std::move(from), "PRIVMSG", {to, "\u000303[notice]\u0003 "s + body}); this->on_channel_message(modified_message); } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 9bef04a..70d7955 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -289,6 +289,10 @@ private: * connection succeeds on that port. */ std::stack> ports_to_try; + /** + * A set of (lowercase) nicknames to which we sent a private message. + */ + std::set nicks_to_treat_as_private; IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; -- cgit v1.2.3 From e2e2f3089469e3e2acbdf1ac6902241d994057c6 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 12 Jan 2015 22:57:08 +0100 Subject: Remove a dummy commented line --- src/irc/irc_client.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 228fc6e..b892684 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -306,7 +306,6 @@ 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(iid, nick, body, muc); this->bridge->send_message({nick + "!" + this->hostname}, nick, body, false); } -- cgit v1.2.3 From e4fcbd3030f033c24102db9f6b6abfb540332c9d Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 14 Jan 2015 12:38:46 +0100 Subject: Add support for password-protected IRC rooms. --- src/irc/irc_client.cpp | 4 ++-- src/irc/irc_client.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index b892684..a29fb0a 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -206,12 +206,12 @@ void IrcClient::send_quit_command(const std::string& reason) this->send_message(IrcMessage("QUIT", {reason})); } -void IrcClient::send_join_command(const std::string& chan_name) +void IrcClient::send_join_command(const std::string& chan_name, const std::string& password) { if (this->welcomed == false) this->channels_to_join.push_back(chan_name); else - this->send_message(IrcMessage("JOIN", {chan_name})); + this->send_message(IrcMessage("JOIN", {chan_name, password})); this->start(); } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 70d7955..29da868 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -81,7 +81,7 @@ public: /** * Send the JOIN irc command. */ - void send_join_command(const std::string& chan_name); + void send_join_command(const std::string& chan_name, const std::string& password = ""); /** * Send a PRIVMSG command for a channel * Return true if the message was actually sent -- cgit v1.2.3 From 60569993b4532caffd8b1a6646292efbbd933585 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 14 Jan 2015 13:48:34 +0100 Subject: Make the password work when we join our first channel on that server Because we need to wait for the welcome message, when we connect to the server, before sending the JOIN command, we need to also save the value of the password to reuse it when we actually send the JOIN command --- src/irc/irc_client.cpp | 10 +++++----- src/irc/irc_client.hpp | 14 ++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index a29fb0a..12f39d6 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -74,9 +74,9 @@ void IrcClient::on_connection_failed(const std::string& reason) if (this->ports_to_try.empty()) { // Send an error message for all room that the user wanted to join - for (const std::string& channel: this->channels_to_join) + for (const auto& tuple: this->channels_to_join) { - Iid iid(channel + "%" + this->hostname); + Iid iid(std::get<0>(tuple) + "%" + this->hostname); this->bridge->send_presence_error(iid, this->current_nick, "cancel", "item-not-found", "", reason); @@ -209,7 +209,7 @@ void IrcClient::send_quit_command(const std::string& reason) void IrcClient::send_join_command(const std::string& chan_name, const std::string& password) { if (this->welcomed == false) - this->channels_to_join.push_back(chan_name); + this->channels_to_join.emplace_back(chan_name, password); else this->send_message(IrcMessage("JOIN", {chan_name, password})); this->start(); @@ -536,8 +536,8 @@ void IrcClient::on_welcome_message(const IrcMessage& message) // Install a repeated events to regularly send a PING TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this), "PING"s + this->hostname + this->bridge->get_jid())); - for (const std::string& chan_name: this->channels_to_join) - this->send_join_command(chan_name); + for (const auto& tuple: this->channels_to_join) + this->send_join_command(std::get<0>(tuple), std::get<1>(tuple)); this->channels_to_join.clear(); // Indicate that the dummy channel is joined as well, if needed if (this->dummy_channel.joining) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 29da868..578fce2 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -81,7 +82,7 @@ public: /** * Send the JOIN irc command. */ - void send_join_command(const std::string& chan_name, const std::string& password = ""); + void send_join_command(const std::string& chan_name, const std::string& password); /** * Send a PRIVMSG command for a channel * Return true if the message was actually sent @@ -245,12 +246,13 @@ private: */ DummyIrcChannel dummy_channel; /** - * A list of chan we want to join, but we need a response 001 from - * the server before sending the actual JOIN commands. So we just keep the - * channel names in a list, and send the JOIN commands for each of them - * whenever the WELCOME message is received. + * A list of chan we want to join (tuples with the channel name and the + * password, if any), but we need a response 001 from the server before + * sending the actual JOIN commands. So we just keep the channel names in + * a list, and send the JOIN commands for each of them whenever the + * WELCOME message is received. */ - std::vector channels_to_join; + std::vector> channels_to_join; /** * This flag indicates that the server is completely joined (connection * has been established, we are authentified and we have a nick) -- cgit v1.2.3 From 4203384e2adcc57ddaf0ede6ca7745fb4a828c44 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 14 Jan 2015 13:53:25 +0100 Subject: Do not send an empty password at all, if the user didn't provide one --- src/irc/irc_client.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 12f39d6..2549138 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -210,6 +210,8 @@ void IrcClient::send_join_command(const std::string& chan_name, const std::strin { if (this->welcomed == false) this->channels_to_join.emplace_back(chan_name, password); + else if (password.empty()) + this->send_message(IrcMessage("JOIN", {chan_name})); else this->send_message(IrcMessage("JOIN", {chan_name, password})); this->start(); -- cgit v1.2.3 From a447214f10e894a7de827c3ff10c185280ed2538 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 14 Jan 2015 13:56:27 +0100 Subject: Remove a recent debug line that should not be there --- src/irc/irc_client.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 2549138..ee8d2d8 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -304,7 +304,6 @@ void IrcClient::on_notice(const IrcMessage& message) // it. Otherwise we treat it as a notice coming from the server. IrcUser user(from); std::string nick = utils::tolower(user.nick); - log_debug("received notice from nick: " << nick); if (this->nicks_to_treat_as_private.find(nick) != this->nicks_to_treat_as_private.end()) { // We previously sent a message to that nick) -- cgit v1.2.3 From 1c43c3af4cbefcd482f4145ee3d7553631a7485d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 25 Feb 2015 16:37:31 +0100 Subject: Include the IRC hostname in the IRC RECEIVING and SENDING debug messages fix #2715 --- src/irc/irc_client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index ee8d2d8..f83b48c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -140,7 +140,7 @@ void IrcClient::parse_in_buffer(const size_t) break ; IrcMessage message(this->in_buf.substr(0, pos)); this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); - log_debug("IRC RECEIVING: " << message); + log_debug("IRC RECEIVING: (" << this->get_hostname() << ") " << message); // Call the standard callback (if any), associated with the command // name that we just received. @@ -162,7 +162,7 @@ void IrcClient::parse_in_buffer(const size_t) void IrcClient::send_message(IrcMessage&& message) { - log_debug("IRC SENDING: " << message); + log_debug("IRC SENDING: (" << this->get_hostname() << ") " << message); std::string res; if (!message.prefix.empty()) res += ":" + std::move(message.prefix) + " "; -- cgit v1.2.3 From 2df0ebf2dfed1dcbf80c92bff8361e2a04581bec Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 25 Feb 2015 18:35:30 +0100 Subject: Add support for a fixed_irc_server configuration This option lets the administrator choose a specific IRC server, and only that server can be used with this biboumi instance. In this mode, JIDs to use are changed like this: - #chan%irc.example.com@biboumi.example.com -> #chan@biboumi.example.com - user!irc.example.com@biboumi.example.com -> user!@biboumi.example.com - #chan%irc.example.com@biboumi.example.com/Nick -> #chan@biboumi.example.com/Nick - %irc.example.com@biboumi.example.com -> no equivalent - irc.example.com@biboumi.example.com -> no equivalent --- src/irc/iid.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- src/irc/iid.hpp | 4 ++++ 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 0bb991f..d4dc8ce 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -1,10 +1,21 @@ #include +#include #include Iid::Iid(const std::string& iid): is_channel(false), is_user(false) +{ + 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); +} + + +void Iid::init(const std::string& iid) { const std::string::size_type sep = iid.find_first_of("%!"); if (sep != std::string::npos) @@ -20,6 +31,29 @@ Iid::Iid(const std::string& iid): 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_first_of("%!"); + + // 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)); + if (iid[sep] == '%') + this->is_channel = true; + else + this->is_user = true; + } +} + Iid::Iid(const Iid& other): is_channel(other.is_channel), is_user(other.is_user), @@ -66,6 +100,14 @@ std::string Iid::get_sep() const namespace std { const std::string to_string(const Iid& iid) { - return iid.get_local() + iid.get_sep() + iid.get_server(); + if (Config::get("fixed_irc_server", "").empty()) + return iid.get_local() + iid.get_sep() + iid.get_server(); + else + { + if (iid.get_sep() == "!") + return iid.get_local() + iid.get_sep(); + else + return iid.get_local(); + } } } diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index d30cbaa..91779b2 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -57,6 +57,10 @@ public: std::string get_sep() const; private: + + void init(const std::string& iid); + void init_with_fixed_server(const std::string& iid, const std::string& hostname); + std::string local; std::string server; -- cgit v1.2.3 From c307df85c8e7d9bcd4570269bf13c3e92c3f5954 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 25 Feb 2015 19:05:04 +0100 Subject: Do not handle the "%" char in a special way, in the fixed_server mode Also fix some doc --- src/irc/iid.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index d4dc8ce..9d39129 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -35,7 +35,7 @@ void Iid::init_with_fixed_server(const std::string& iid, const std::string& host { this->set_server(hostname); - const std::string::size_type sep = iid.find_first_of("%!"); + const std::string::size_type sep = iid.find("!"); // Without any separator, we consider that it's a channel if (sep == std::string::npos) @@ -47,9 +47,6 @@ void Iid::init_with_fixed_server(const std::string& iid, const std::string& host // but the part behind it (the hostname) is ignored { this->set_local(iid.substr(0, sep)); - if (iid[sep] == '%') - this->is_channel = true; - else this->is_user = true; } } -- cgit v1.2.3 From c01befb054075ab414fd602859e5999a138aa5bf Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 26 Feb 2015 05:02:08 +0100 Subject: Implement room discovery using the LIST irc command ref #2472 --- src/irc/irc_client.cpp | 5 +++++ src/irc/irc_client.hpp | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index f83b48c..dedb5de 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -196,6 +196,11 @@ void IrcClient::send_kick_command(const std::string& chan_name, const std::strin this->send_message(IrcMessage("KICK", {chan_name, target, reason})); } +void IrcClient::send_list_command() +{ + this->send_message(IrcMessage("LIST", {})); +} + void IrcClient::send_topic_command(const std::string& chan_name, const std::string& topic) { this->send_message(IrcMessage("TOPIC", {chan_name, topic})); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 578fce2..86edbab 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -104,6 +104,10 @@ public: * Send the KICK irc command */ void send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason); + /** + * Send the LIST irc command + */ + void send_list_command(); void send_topic_command(const std::string& chan_name, const std::string& topic); /** * Send the QUIT irc command -- cgit v1.2.3 From d600a2843f1dbe3b1ba2dead9a020cc73d7d10ae Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Feb 2015 12:16:09 +0100 Subject: Remove all the libs that are now in louloulibs --- src/irc/irc_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index dedb5de..cbbd4ea 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -14,7 +14,7 @@ #include #include -#include "config.h" +#include "louloulibs.h" using namespace std::string_literals; using namespace std::chrono_literals; -- cgit v1.2.3 From ffcce28c7711ff69e46445c466bd439362e3d0d4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 24 Mar 2015 04:34:05 +0100 Subject: Do not log a warning when we receive a PONG command --- src/irc/irc_client.cpp | 4 ++++ src/irc/irc_client.hpp | 6 ++++++ 2 files changed, 10 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index cbbd4ea..694baf8 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -281,6 +281,10 @@ void IrcClient::send_pong_command(const IrcMessage& message) this->send_message(IrcMessage("PONG", {id})); } +void IrcClient::on_pong(const IrcMessage& message) +{ +} + void IrcClient::send_ping_command() { this->send_message(IrcMessage("PING", {"biboumi"})); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 86edbab..03951be 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -70,6 +70,11 @@ public: * Send the PONG irc command */ void send_pong_command(const IrcMessage& message); + /** + * Do nothing when we receive a PONG command (but also do not log that no + * handler exist) + */ + void on_pong(const IrcMessage& message); void send_ping_command(); /** * Send the USER irc command @@ -339,6 +344,7 @@ static const std::unordered_map irc_callbacks = { {"NICK", &IrcClient::on_nick}, {"MODE", &IrcClient::on_mode}, {"PING", &IrcClient::send_pong_command}, + {"PONG", &IrcClient::on_pong}, {"KICK", &IrcClient::on_kick}, {"401", &IrcClient::on_generic_error}, -- cgit v1.2.3 From ad0465b32051e224f6a234f3ed36494905e59cbf Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 20 Apr 2015 20:33:02 +0200 Subject: Decode incoming JIDs local part according to xep 0106 This let users send message to nicks such as Q@CServe.quakenet.org fix #3047 --- src/irc/iid.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 9d39129..5d8dc0a 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -1,5 +1,6 @@ #include #include +#include #include @@ -68,6 +69,7 @@ Iid::Iid(): void Iid::set_local(const std::string& loc) { this->local = utils::tolower(loc); + xep0106::decode(local); } void Iid::set_server(const std::string& serv) -- cgit v1.2.3 From 61bfd1db008295b33350e7c6b9a1b98a7964f9c6 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 21 Apr 2015 02:48:28 +0200 Subject: Revert "Decode incoming JIDs local part according to xep 0106" This reverts commit ad0465b32051e224f6a234f3ed36494905e59cbf. Conflicts: louloulibs --- src/irc/iid.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 5d8dc0a..9d39129 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -1,6 +1,5 @@ #include #include -#include #include @@ -69,7 +68,6 @@ Iid::Iid(): void Iid::set_local(const std::string& loc) { this->local = utils::tolower(loc); - xep0106::decode(local); } void Iid::set_server(const std::string& serv) -- cgit v1.2.3 From a8225dc54c019788722bda3bda8d55151c1ccdef Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 21 Apr 2015 15:35:10 +0200 Subject: Properly check for connecting or connected status before reconnecting Note, in our context, is_connecting() includes the resolving part as well as the actual connection (if we are using c-ares) fix #3048 --- src/irc/irc_client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 694baf8..b0ce93a 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -55,8 +55,8 @@ IrcClient::~IrcClient() void IrcClient::start() { - if (this->connected || this->connecting) - return ; + if (this->is_connecting() || this->is_connected()) + return; std::string port; bool tls; std::tie(port, tls) = this->ports_to_try.top(); -- cgit v1.2.3 From 0a6b673b14efc4f623ea445045e6fc60e9842a25 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 7 May 2015 17:01:17 +0200 Subject: Support raw IRC messages Messages received on an IRC server JID are forwarded as raw IRC messages. fix #2486 --- src/irc/irc_client.cpp | 5 +++++ src/irc/irc_client.hpp | 1 + 2 files changed, 6 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index b0ce93a..717f7e3 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -181,6 +181,11 @@ void IrcClient::send_message(IrcMessage&& message) this->send_data(std::move(res)); } +void IrcClient::send_raw(const std::string& txt) +{ + this->send_data(txt + "\r\n"); +} + void IrcClient::send_user_command(const std::string& username, const std::string& realname) { this->send_message(IrcMessage("USER", {username, "ignored", "ignored", realname})); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 03951be..08021c1 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -66,6 +66,7 @@ public: * for send events to be ready) */ void send_message(IrcMessage&& message); + void send_raw(const std::string& txt); /** * Send the PONG irc command */ -- cgit v1.2.3 From 163ace553f3e65dcf9f97070faa5dbab0d31bac0 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 7 May 2015 17:17:01 +0200 Subject: Handle all unknown IRC command by forwarding the arguments as a message body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way, the users can receive the result of any IRC command (although not parsed nor formatted in anyway) when biboumi doesn’t support it fix #2884 --- src/irc/irc_client.cpp | 23 ++++++++++++++++++++++- src/irc/irc_client.hpp | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 717f7e3..677f6be 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -154,7 +155,11 @@ void IrcClient::parse_in_buffer(const size_t) } } else - log_info("No handler for command " << message.command); + { + log_info("No handler for command " << message.command << + ", forwarding the arguments to the user"); + this->on_unknown_message(message); + } // Try to find a waiting_iq, which response will be triggered by this IrcMessage this->bridge->trigger_on_irc_message(this->hostname, message); } @@ -797,6 +802,22 @@ void IrcClient::on_user_mode(const IrcMessage& message) " is [" + message.arguments[1] + "]"); } +void IrcClient::on_unknown_message(const IrcMessage& message) +{ + if (message.arguments.size() < 2) + return ; + std::string from = message.prefix; + const std::string to = message.arguments[0]; + std::stringstream ss; + for (auto it = message.arguments.begin() + 1; it != message.arguments.end(); ++it) + { + ss << *it; + if (it + 1 != message.arguments.end()) + ss << " "; + } + this->bridge->send_xmpp_message(this->hostname, from, ss.str()); +} + size_t IrcClient::number_of_joined_channels() const { if (this->dummy_channel.joined) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 08021c1..4ab0fcb 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -211,6 +211,7 @@ public: */ void on_channel_mode(const IrcMessage& message); void on_quit(const IrcMessage& message); + void on_unknown_message(const IrcMessage& message); /** * Return the number of joined channels */ -- cgit v1.2.3 From 221ed2553dcc5c43bfeb71f97e86147735d77856 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 7 May 2015 17:18:40 +0200 Subject: Two trivial fixes --- src/irc/irc_client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 677f6be..7dcda8e 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -291,7 +291,7 @@ void IrcClient::send_pong_command(const IrcMessage& message) this->send_message(IrcMessage("PONG", {id})); } -void IrcClient::on_pong(const IrcMessage& message) +void IrcClient::on_pong(const IrcMessage&) { } @@ -316,7 +316,7 @@ void IrcClient::on_notice(const IrcMessage& message) if (!to.empty() && this->chantypes.find(to[0]) == this->chantypes.end()) { - // The notice is for the us precisely. + // The notice is for us precisely. // Find out if we already sent a private message to this user. If yes // we treat that message as a private message coming from -- cgit v1.2.3 From 7fe0dc2667229287ab9f1825e84403a25bc863fe Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 11 May 2015 05:31:11 +0200 Subject: Fix the case of the nick for ping requests fix #3041 --- src/irc/irc_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 7dcda8e..5f6aaaf 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -452,7 +452,7 @@ void IrcClient::on_channel_message(const IrcMessage& message) else if (body.substr(1, 8) == "VERSION\01") this->bridge->send_iq_version_request(nick, this->hostname); else if (body.substr(1, 5) == "PING ") - this->bridge->send_xmpp_ping_request(nick, this->hostname, + this->bridge->send_xmpp_ping_request(utils::tolower(nick), this->hostname, body.substr(6, body.size() - 7)); } else -- cgit v1.2.3 From fa466f33f4c8009e69fe0ebf31c7eef1c394377b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 19 May 2015 06:00:07 +0200 Subject: Ignore commands that flood the user with private messages when listing chans ref #2472 --- src/irc/irc_client.cpp | 12 ++++++++++++ src/irc/irc_client.hpp | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 5f6aaaf..d048e47 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -459,6 +459,18 @@ void IrcClient::on_channel_message(const IrcMessage& message) this->bridge->send_message(iid, nick, body, muc); } +void IrcClient::on_rpl_liststart(const IrcMessage&) +{ +} + +void IrcClient::on_rpl_list(const IrcMessage&) +{ +} + +void IrcClient::on_rpl_listend(const IrcMessage&) +{ +} + void IrcClient::empty_motd(const IrcMessage& message) { (void)message; diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 4ab0fcb..0d1604d 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -151,6 +151,23 @@ public: * IrcUsers in the IrcChannel */ void set_and_forward_user_list(const IrcMessage& message); + /** + * Signal the start of the LIST response. The RFC says its obsolete and + * “not used”, but I we receive it on some servers, so just ignore it. + */ + void on_rpl_liststart(const IrcMessage& message); + /** + * A single LIST response line (one channel) + * + * The command is handled in a wait_irc callback. This general handler is + * empty and just used to avoid sending a message stanza for each received + * channel. + */ + void on_rpl_list(const IrcMessage& message); + /** + * Signal the end of the LIST response, ignore. + */ + void on_rpl_listend(const IrcMessage& message); /** * Remember our nick and host, when we are joined to the channel. The list * of user comes after so we do not send the self-presence over XMPP yet. @@ -324,6 +341,12 @@ static const std::unordered_map irc_callbacks = { {"002", &IrcClient::forward_server_message}, {"003", &IrcClient::forward_server_message}, {"005", &IrcClient::on_isupport_message}, + {"RPL_LISTSTART", &IrcClient::on_rpl_liststart}, + {"321", &IrcClient::on_rpl_liststart}, + {"RPL_LIST", &IrcClient::on_rpl_list}, + {"322", &IrcClient::on_rpl_list}, + {"RPL_LISTEND", &IrcClient::on_rpl_listend}, + {"323", &IrcClient::on_rpl_listend}, {"RPL_MOTDSTART", &IrcClient::empty_motd}, {"375", &IrcClient::empty_motd}, {"RPL_MOTD", &IrcClient::on_motd_line}, -- cgit v1.2.3 From e454c12bd7f695d6450dc804c07aa5637a8b1c00 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 19 May 2015 06:43:38 +0200 Subject: =?UTF-8?q?Do=20not=20forward=20CTCP=20commands=20(PING,=20VERSION?= =?UTF-8?q?=E2=80=A6)=20to=20the=20user=20as=20private=20messages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some XMPP client ping themselves inside MUCs, to know if they are still in there, this created a flood of PING message in private. If the user is interested in knowing when they receive a ping or version request, they can still read their XML logs --- src/irc/irc_client.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d048e47..905a336 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -314,6 +314,10 @@ void IrcClient::on_notice(const IrcMessage& message) const std::string to = message.arguments[0]; const std::string body = message.arguments[1]; + if (!body.empty() && body[0] == '\01' && body[body.size() - 1] == '\01') + // Do not forward the notice to the user if it's a CTCP command + return ; + if (!to.empty() && this->chantypes.find(to[0]) == this->chantypes.end()) { // The notice is for us precisely. -- cgit v1.2.3 From ece4b4969b296a3da010fb22768348650e70962d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 9 Jul 2015 15:30:24 +0200 Subject: If hostname resolution fails, do not try all possible ports --- src/irc/irc_client.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 905a336..4e8385c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -72,6 +72,11 @@ void IrcClient::on_connection_failed(const std::string& reason) { this->bridge->send_xmpp_message(this->hostname, "", "Connection failed: "s + reason); + + if (this->hostname_resolution_failed) + while (!this->ports_to_try.empty()) + this->ports_to_try.pop(); + if (this->ports_to_try.empty()) { // Send an error message for all room that the user wanted to join -- cgit v1.2.3 From 4cfcc79114d89096219039104674d35ca1aba5ca Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 6 Sep 2015 18:55:48 +0200 Subject: Check the number of argument of every IRC command received from the server Each IrcClient callback has a max and min size of argument, we call the callback only if the parsed message has a correct number of arguments, otherwise it is ignored (with a warning logged). --- src/irc/irc_client.cpp | 26 +++++--- src/irc/irc_client.hpp | 167 +++++++++++++++++++++++++------------------------ 2 files changed, 103 insertions(+), 90 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 4e8385c..6ab19b7 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -150,14 +150,26 @@ void IrcClient::parse_in_buffer(const size_t) // Call the standard callback (if any), associated with the command // name that we just received. - auto cb = irc_callbacks.find(message.command); - if (cb != irc_callbacks.end()) + auto it = irc_callbacks.find(message.command); + if (it != irc_callbacks.end()) { - try { - (this->*(cb->second))(message); - } catch (const std::exception& e) { - log_error("Unhandled exception: " << e.what()); - } + const auto& limits = it->second.second; + // Check that the Message is well formed before actually calling + // the callback. limits.first is the min number of arguments, + // second is the max + if (message.arguments.size() < limits.first || + (limits.second > 0 && message.arguments.size() > limits.second)) + log_warning("Invalid number of arguments for IRC command “" << message.command << + "”: " << message.arguments.size()); + else + { + const auto& cb = it->second.first; + try { + (this->*(cb))(message); + } catch (const std::exception& e) { + log_error("Unhandled exception: " << e.what()); + } + } } else { diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 0d1604d..a3f69a0 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -336,90 +336,91 @@ private: */ typedef void (IrcClient::*irc_callback_t)(const IrcMessage&); -static const std::unordered_map irc_callbacks = { - {"NOTICE", &IrcClient::on_notice}, - {"002", &IrcClient::forward_server_message}, - {"003", &IrcClient::forward_server_message}, - {"005", &IrcClient::on_isupport_message}, - {"RPL_LISTSTART", &IrcClient::on_rpl_liststart}, - {"321", &IrcClient::on_rpl_liststart}, - {"RPL_LIST", &IrcClient::on_rpl_list}, - {"322", &IrcClient::on_rpl_list}, - {"RPL_LISTEND", &IrcClient::on_rpl_listend}, - {"323", &IrcClient::on_rpl_listend}, - {"RPL_MOTDSTART", &IrcClient::empty_motd}, - {"375", &IrcClient::empty_motd}, - {"RPL_MOTD", &IrcClient::on_motd_line}, - {"372", &IrcClient::on_motd_line}, - {"RPL_MOTDEND", &IrcClient::send_motd}, - {"376", &IrcClient::send_motd}, - {"JOIN", &IrcClient::on_channel_join}, - {"PRIVMSG", &IrcClient::on_channel_message}, - {"353", &IrcClient::set_and_forward_user_list}, - {"332", &IrcClient::on_topic_received}, - {"TOPIC", &IrcClient::on_topic_received}, - {"366", &IrcClient::on_channel_completely_joined}, - {"432", &IrcClient::on_erroneous_nickname}, - {"433", &IrcClient::on_nickname_conflict}, - {"438", &IrcClient::on_nickname_change_too_fast}, - {"001", &IrcClient::on_welcome_message}, - {"PART", &IrcClient::on_part}, - {"ERROR", &IrcClient::on_error}, - {"QUIT", &IrcClient::on_quit}, - {"NICK", &IrcClient::on_nick}, - {"MODE", &IrcClient::on_mode}, - {"PING", &IrcClient::send_pong_command}, - {"PONG", &IrcClient::on_pong}, - {"KICK", &IrcClient::on_kick}, +static const std::unordered_map>> irc_callbacks = { + {"NOTICE", {&IrcClient::on_notice, {2, 0}}}, + {"002", {&IrcClient::forward_server_message, {2, 0}}}, + {"003", {&IrcClient::forward_server_message, {2, 0}}}, + {"005", {&IrcClient::on_isupport_message, {0, 0}}}, + {"RPL_LISTSTART", {&IrcClient::on_rpl_liststart, {0, 0}}}, + {"321", {&IrcClient::on_rpl_liststart, {0, 0}}}, + {"RPL_LIST", {&IrcClient::on_rpl_list, {0, 0}}}, + {"322", {&IrcClient::on_rpl_list, {0, 0}}}, + {"RPL_LISTEND", {&IrcClient::on_rpl_listend, {0, 0}}}, + {"323", {&IrcClient::on_rpl_listend, {0, 0}}}, + {"RPL_MOTDSTART", {&IrcClient::empty_motd, {0, 0}}}, + {"375", {&IrcClient::empty_motd, {0, 0}}}, + {"RPL_MOTD", {&IrcClient::on_motd_line, {2, 0}}}, + {"372", {&IrcClient::on_motd_line, {2, 0}}}, + {"RPL_MOTDEND", {&IrcClient::send_motd, {0, 0}}}, + {"376", {&IrcClient::send_motd, {0, 0}}}, + {"JOIN", {&IrcClient::on_channel_join, {1, 0}}}, + {"PRIVMSG", {&IrcClient::on_channel_message, {2, 0}}}, + {"353", {&IrcClient::set_and_forward_user_list, {4, 0}}}, + {"332", {&IrcClient::on_topic_received, {2, 0}}}, + {"TOPIC", {&IrcClient::on_topic_received, {2, 0}}}, + {"366", {&IrcClient::on_channel_completely_joined, {2, 0}}}, + {"432", {&IrcClient::on_erroneous_nickname, {2, 0}}}, + {"433", {&IrcClient::on_nickname_conflict, {2, 0}}}, + {"438", {&IrcClient::on_nickname_change_too_fast, {2, 0}}}, + {"001", {&IrcClient::on_welcome_message, {1, 0}}}, + {"PART", {&IrcClient::on_part, {1, 0}}}, + {"ERROR", {&IrcClient::on_error, {1, 0}}}, + {"QUIT", {&IrcClient::on_quit, {0, 0}}}, + {"NICK", {&IrcClient::on_nick, {1, 0}}}, + {"MODE", {&IrcClient::on_mode, {1, 0}}}, + {"PING", {&IrcClient::send_pong_command, {1, 0}}}, + {"PONG", {&IrcClient::on_pong, {0, 0}}}, + {"KICK", {&IrcClient::on_kick, {3, 0}}}, - {"401", &IrcClient::on_generic_error}, - {"402", &IrcClient::on_generic_error}, - {"403", &IrcClient::on_generic_error}, - {"404", &IrcClient::on_generic_error}, - {"405", &IrcClient::on_generic_error}, - {"406", &IrcClient::on_generic_error}, - {"407", &IrcClient::on_generic_error}, - {"408", &IrcClient::on_generic_error}, - {"409", &IrcClient::on_generic_error}, - {"410", &IrcClient::on_generic_error}, - {"411", &IrcClient::on_generic_error}, - {"412", &IrcClient::on_generic_error}, - {"414", &IrcClient::on_generic_error}, - {"421", &IrcClient::on_generic_error}, - {"422", &IrcClient::on_generic_error}, - {"423", &IrcClient::on_generic_error}, - {"424", &IrcClient::on_generic_error}, - {"431", &IrcClient::on_generic_error}, - {"436", &IrcClient::on_generic_error}, - {"441", &IrcClient::on_generic_error}, - {"442", &IrcClient::on_generic_error}, - {"443", &IrcClient::on_generic_error}, - {"444", &IrcClient::on_generic_error}, - {"446", &IrcClient::on_generic_error}, - {"451", &IrcClient::on_generic_error}, - {"461", &IrcClient::on_generic_error}, - {"462", &IrcClient::on_generic_error}, - {"463", &IrcClient::on_generic_error}, - {"464", &IrcClient::on_generic_error}, - {"465", &IrcClient::on_generic_error}, - {"467", &IrcClient::on_generic_error}, - {"470", &IrcClient::on_generic_error}, - {"471", &IrcClient::on_generic_error}, - {"472", &IrcClient::on_generic_error}, - {"473", &IrcClient::on_generic_error}, - {"474", &IrcClient::on_generic_error}, - {"475", &IrcClient::on_generic_error}, - {"476", &IrcClient::on_generic_error}, - {"477", &IrcClient::on_generic_error}, - {"481", &IrcClient::on_generic_error}, - {"482", &IrcClient::on_generic_error}, - {"483", &IrcClient::on_generic_error}, - {"484", &IrcClient::on_generic_error}, - {"485", &IrcClient::on_generic_error}, - {"487", &IrcClient::on_generic_error}, - {"491", &IrcClient::on_generic_error}, - {"501", &IrcClient::on_generic_error}, - {"502", &IrcClient::on_generic_error}, + {"401", {&IrcClient::on_generic_error, {2, 0}}}, + {"402", {&IrcClient::on_generic_error, {2, 0}}}, + {"403", {&IrcClient::on_generic_error, {2, 0}}}, + {"404", {&IrcClient::on_generic_error, {2, 0}}}, + {"405", {&IrcClient::on_generic_error, {2, 0}}}, + {"406", {&IrcClient::on_generic_error, {2, 0}}}, + {"407", {&IrcClient::on_generic_error, {2, 0}}}, + {"408", {&IrcClient::on_generic_error, {2, 0}}}, + {"409", {&IrcClient::on_generic_error, {2, 0}}}, + {"410", {&IrcClient::on_generic_error, {2, 0}}}, + {"411", {&IrcClient::on_generic_error, {2, 0}}}, + {"412", {&IrcClient::on_generic_error, {2, 0}}}, + {"414", {&IrcClient::on_generic_error, {2, 0}}}, + {"421", {&IrcClient::on_generic_error, {2, 0}}}, + {"422", {&IrcClient::on_generic_error, {2, 0}}}, + {"423", {&IrcClient::on_generic_error, {2, 0}}}, + {"424", {&IrcClient::on_generic_error, {2, 0}}}, + {"431", {&IrcClient::on_generic_error, {2, 0}}}, + {"436", {&IrcClient::on_generic_error, {2, 0}}}, + {"441", {&IrcClient::on_generic_error, {2, 0}}}, + {"442", {&IrcClient::on_generic_error, {2, 0}}}, + {"443", {&IrcClient::on_generic_error, {2, 0}}}, + {"444", {&IrcClient::on_generic_error, {2, 0}}}, + {"446", {&IrcClient::on_generic_error, {2, 0}}}, + {"451", {&IrcClient::on_generic_error, {2, 0}}}, + {"461", {&IrcClient::on_generic_error, {2, 0}}}, + {"462", {&IrcClient::on_generic_error, {2, 0}}}, + {"463", {&IrcClient::on_generic_error, {2, 0}}}, + {"464", {&IrcClient::on_generic_error, {2, 0}}}, + {"465", {&IrcClient::on_generic_error, {2, 0}}}, + {"467", {&IrcClient::on_generic_error, {2, 0}}}, + {"470", {&IrcClient::on_generic_error, {2, 0}}}, + {"471", {&IrcClient::on_generic_error, {2, 0}}}, + {"472", {&IrcClient::on_generic_error, {2, 0}}}, + {"473", {&IrcClient::on_generic_error, {2, 0}}}, + {"474", {&IrcClient::on_generic_error, {2, 0}}}, + {"475", {&IrcClient::on_generic_error, {2, 0}}}, + {"476", {&IrcClient::on_generic_error, {2, 0}}}, + {"477", {&IrcClient::on_generic_error, {2, 0}}}, + {"481", {&IrcClient::on_generic_error, {2, 0}}}, + {"482", {&IrcClient::on_generic_error, {2, 0}}}, + {"483", {&IrcClient::on_generic_error, {2, 0}}}, + {"484", {&IrcClient::on_generic_error, {2, 0}}}, + {"485", {&IrcClient::on_generic_error, {2, 0}}}, + {"487", {&IrcClient::on_generic_error, {2, 0}}}, + {"491", {&IrcClient::on_generic_error, {2, 0}}}, + {"501", {&IrcClient::on_generic_error, {2, 0}}}, + {"502", {&IrcClient::on_generic_error, {2, 0}}}, }; #endif // IRC_CLIENT_INCLUDED -- cgit v1.2.3 From 73573ebb2abb2aea119a6c99e2bf4a302f2ba834 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 6 Sep 2015 18:57:35 +0200 Subject: Trivial cleanup in irc_client.cpp --- src/irc/irc_client.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 6ab19b7..29f0b54 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -492,9 +492,8 @@ void IrcClient::on_rpl_listend(const IrcMessage&) { } -void IrcClient::empty_motd(const IrcMessage& message) +void IrcClient::empty_motd(const IrcMessage&) { - (void)message; this->motd.erase(); } @@ -507,16 +506,13 @@ void IrcClient::on_motd_line(const IrcMessage& message) this->motd += body+"\n"; } -void IrcClient::send_motd(const IrcMessage& message) +void IrcClient::send_motd(const IrcMessage&) { - (void)message; this->bridge->send_xmpp_message(this->hostname, "", this->motd); } void IrcClient::on_topic_received(const IrcMessage& message) { - if (message.arguments.size() < 2) - return; const std::string chan_name = utils::tolower(message.arguments[message.arguments.size() - 2]); IrcChannel* channel = this->get_channel(chan_name); channel->topic = message.arguments[message.arguments.size() - 1]; @@ -709,9 +705,9 @@ void IrcClient::on_nick(const IrcMessage& message) void IrcClient::on_kick(const IrcMessage& message) { + const std::string chan_name = utils::tolower(message.arguments[0]); const std::string target = message.arguments[1]; const std::string reason = message.arguments[2]; - const std::string chan_name = utils::tolower(message.arguments[0]); IrcChannel* channel = this->get_channel(chan_name); if (!channel->joined) return ; -- cgit v1.2.3 From 532228a3cefd92fe43ad0f52149b7f0f5ab5cb79 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 18 Sep 2015 22:02:01 +0200 Subject: =?UTF-8?q?Send=20a=20PASS=20IRC=20command=20if=20the=20=E2=80=9Cp?= =?UTF-8?q?ass=E2=80=9D=20config=20is=20sot=20by=20a=20user,=20on=20an=20I?= =?UTF-8?q?RC=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix #3068 --- src/irc/irc_client.cpp | 12 ++++++++++++ src/irc/irc_client.hpp | 1 + 2 files changed, 13 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 29f0b54..bac3e34 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -94,6 +95,12 @@ void IrcClient::on_connection_failed(const std::string& reason) void IrcClient::on_connected() { +#ifdef USE_DATABASE + auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), + this->get_hostname()); + if (!options.pass.value().empty()) + this->send_pass_command(options.pass.value()); +#endif this->send_nick_command(this->username); this->send_user_command(this->username, this->username); this->send_gateway_message("Connected to IRC server"s + (this->use_tls ? " (encrypted)": "") + "."); @@ -218,6 +225,11 @@ void IrcClient::send_nick_command(const std::string& nick) this->send_message(IrcMessage("NICK", {nick})); } +void IrcClient::send_pass_command(const std::string& password) +{ + this->send_message(IrcMessage("PASS", {password})); +} + void IrcClient::send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason) { this->send_message(IrcMessage("KICK", {chan_name, target, reason})); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index a3f69a0..4e61d14 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -85,6 +85,7 @@ public: * Send the NICK irc command */ void send_nick_command(const std::string& username); + void send_pass_command(const std::string& password); /** * Send the JOIN irc command. */ -- cgit v1.2.3 From 890cfe90996ac4c3916c84d178049d9b3b23465b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 21 Sep 2015 04:27:23 +0200 Subject: Provide Ports and TLS Ports IRC-server ad-hoc options This let any user choose which ports to use when connecting to the IRC server. This also lets the user choose whether or not to force TLS usage (by setting no non-TLS port). fix #2731 --- src/irc/irc_client.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index bac3e34..c6174bf 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -16,11 +16,13 @@ #include #include +#include "biboumi.h" #include "louloulibs.h" using namespace std::string_literals; using namespace std::chrono_literals; + IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& username, Bridge* bridge): TCPSocketHandler(poller), hostname(hostname), @@ -39,13 +41,25 @@ IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname "alive without having to join a real channel of that server. " "To disconnect from the IRC server, leave this room and all " "other IRC channels of that server."; - // TODO: get the values from the preferences of the user, and only use the - // list of default ports if the user didn't specify anything +#ifdef USE_DATABASE + auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), + this->get_hostname()); + std::vector ports = utils::split(options.ports, ';', false); + for (auto it = ports.rbegin(); it != ports.rend(); ++it) + this->ports_to_try.emplace(*it, false); +# ifdef BOTAN_FOUND + ports = utils::split(options.tlsPorts, ';', false); + for (auto it = ports.rbegin(); it != ports.rend(); ++it) + this->ports_to_try.emplace(*it, true); +# endif // BOTAN_FOUND + +#else // not USE_DATABASE this->ports_to_try.emplace("6667", false); // standard non-encrypted port -#ifdef BOTAN_FOUND +# ifdef BOTAN_FOUND this->ports_to_try.emplace("6670", true); // non-standard but I want it for some servers this->ports_to_try.emplace("6697", true); // standard encrypted port -#endif // BOTAN_FOUND +# endif // BOTAN_FOUND +#endif // USE_DATABASE } IrcClient::~IrcClient() -- cgit v1.2.3 From ceec98907776dcd73b0c02a46ca135196e5f223e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 21 Sep 2015 18:56:37 +0200 Subject: Add a field (in the configure form) to specifiy an after-connect IRC command --- src/irc/irc_client.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index c6174bf..26f9a46 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -226,6 +226,7 @@ void IrcClient::send_message(IrcMessage&& message) void IrcClient::send_raw(const std::string& txt) { + log_debug("IRC SENDING (raw): (" << this->get_hostname() << ") " << txt); this->send_data(txt + "\r\n"); } @@ -608,6 +609,12 @@ void IrcClient::on_welcome_message(const IrcMessage& message) { this->current_nick = message.arguments[0]; this->welcomed = true; +#ifdef USE_DATABASE + auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), + this->get_hostname()); + if (!options.afterConnectionCommand.value().empty()) + this->send_raw(options.afterConnectionCommand.value()); +#endif // Install a repeated events to regularly send a PING TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this), "PING"s + this->hostname + this->bridge->get_jid())); -- cgit v1.2.3 From 7247228e9785fd7c8d796d4aa0eb3b9c6fc8f221 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 22 Sep 2015 03:50:08 +0200 Subject: Connection may be closed from our side too --- src/irc/irc_client.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 26f9a46..b4df7dd 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -123,9 +123,11 @@ void IrcClient::on_connected() void IrcClient::on_connection_close(const std::string& error_msg) { - std::string message = "Connection closed by remote server."; + std::string message = "Connection closed"; if (!error_msg.empty()) message += ": " + error_msg; + else + message += "."; const IrcMessage error{"ERROR", {message}}; this->on_error(error); log_warning(message); -- cgit v1.2.3 From f904d57940699e332f75a77062912431c6e51188 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 23 Sep 2015 18:24:06 +0200 Subject: Provide username and realname IRC server options Used in the USER command when connecting to the IRC server, instead of the first nick. fix #3028 --- src/irc/irc_client.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index b4df7dd..00d9f43 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -116,7 +116,17 @@ void IrcClient::on_connected() this->send_pass_command(options.pass.value()); #endif this->send_nick_command(this->username); +#ifdef USE_DATABASE + std::string username = this->username; + if (!options.username.value().empty()) + username = options.username.value(); + std::string realname = this->username; + if (!options.realname.value().empty()) + realname = options.realname.value(); + this->send_user_command(username, realname); +#else this->send_user_command(this->username, this->username); +#endif // USE_DATABASE this->send_gateway_message("Connected to IRC server"s + (this->use_tls ? " (encrypted)": "") + "."); this->send_pending_data(); } -- cgit v1.2.3 From 6512f830fa2baa85a7c688843ebd42eb528e2ad6 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 12 Oct 2015 16:35:50 +0200 Subject: The realname is also saved as an IrcClient member --- src/irc/irc_client.cpp | 15 ++++++++------- src/irc/irc_client.hpp | 8 ++++++-- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 00d9f43..4692eef 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -27,6 +27,7 @@ IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname TCPSocketHandler(poller), hostname(hostname), username(username), + realname(username), current_nick(username), bridge(bridge), welcomed(false), @@ -115,18 +116,18 @@ void IrcClient::on_connected() if (!options.pass.value().empty()) this->send_pass_command(options.pass.value()); #endif + this->send_nick_command(this->username); + #ifdef USE_DATABASE - std::string username = this->username; if (!options.username.value().empty()) - username = options.username.value(); - std::string realname = this->username; + this->username = options.username.value(); if (!options.realname.value().empty()) - realname = options.realname.value(); + this->realname = options.realname.value(); this->send_user_command(username, realname); -#else - this->send_user_command(this->username, this->username); -#endif // USE_DATABASE +#endif + this->send_user_command(this->username, this->realname); + this->send_gateway_message("Connected to IRC server"s + (this->use_tls ? " (encrypted)": "") + "."); this->send_pending_data(); } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 4e61d14..a6b51ce 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -254,9 +254,13 @@ private: */ const std::string hostname; /** - * The user name used in the USER irc command + * The username used in the USER irc command */ - const std::string username; + std::string username; + /** + * The realname used in the USER irc command + */ + std::string realname; /** * Our current nickname on the server */ -- cgit v1.2.3 From 84aafab6040f8fd126e6c4941631d44f122c4b9a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 12 Oct 2015 16:47:27 +0200 Subject: =?UTF-8?q?Provide=20the=20=E2=80=9Crealname=5Fcustomization?= =?UTF-8?q?=E2=80=9D=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #3136 --- src/irc/irc_client.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 4692eef..d6c7021 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -120,11 +121,14 @@ void IrcClient::on_connected() this->send_nick_command(this->username); #ifdef USE_DATABASE - if (!options.username.value().empty()) - this->username = options.username.value(); - if (!options.realname.value().empty()) - this->realname = options.realname.value(); - this->send_user_command(username, realname); + if (Config::get("realname_customization", "true") == "true") + { + if (!options.username.value().empty()) + this->username = options.username.value(); + if (!options.realname.value().empty()) + this->realname = options.realname.value(); + this->send_user_command(username, realname); + } #endif this->send_user_command(this->username, this->realname); -- cgit v1.2.3 From 1aa2c2d857037f3274297527ca3971a75203d39c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 12 Oct 2015 17:14:29 +0200 Subject: Introduce the realname_from_jid option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When set to true, the realname and username are extracted (by default) from the user’s JID fix #3136 --- src/irc/irc_client.cpp | 8 +++++--- src/irc/irc_client.hpp | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d6c7021..0289d72 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -24,12 +24,14 @@ using namespace std::string_literals; using namespace std::chrono_literals; -IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& username, Bridge* bridge): +IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, + const std::string& nickname, const std::string& username, + const std::string& realname, Bridge* bridge): TCPSocketHandler(poller), hostname(hostname), username(username), - realname(username), - current_nick(username), + realname(realname), + current_nick(nickname), bridge(bridge), welcomed(false), chanmodes({"", "", "", ""}), diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index a6b51ce..7a04164 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -25,7 +25,9 @@ class Bridge; class IrcClient: public TCPSocketHandler { public: - explicit IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& username, Bridge* bridge); + explicit IrcClient(std::shared_ptr poller, const std::string& hostname, + const std::string& nickname, const std::string& username, + const std::string& realname, Bridge* bridge); ~IrcClient(); /** * Connect to the IRC server -- cgit v1.2.3 From 142516a69bb000ce80cbb6509d1f407438a94663 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 26 Oct 2015 20:09:39 +0100 Subject: Fix some trivial issues reported by cppcheck --- src/irc/irc_client.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0289d72..8f92f9b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -888,7 +888,6 @@ void IrcClient::on_unknown_message(const IrcMessage& message) if (message.arguments.size() < 2) return ; std::string from = message.prefix; - const std::string to = message.arguments[0]; std::stringstream ss; for (auto it = message.arguments.begin() + 1; it != message.arguments.end(); ++it) { -- cgit v1.2.3 From 2c932cf0f7ca9bc82430c1da5097653f6a4d0bf4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 31 Oct 2015 05:36:33 +0100 Subject: Fix the double sending of the USER command --- src/irc/irc_client.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 8f92f9b..f6b8f9c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -131,9 +131,11 @@ void IrcClient::on_connected() this->realname = options.realname.value(); this->send_user_command(username, realname); } -#endif + else + this->send_user_command(this->username, this->realname); +#else this->send_user_command(this->username, this->realname); - +#endif this->send_gateway_message("Connected to IRC server"s + (this->use_tls ? " (encrypted)": "") + "."); this->send_pending_data(); } -- cgit v1.2.3 From 34fc1d4010d23be947c00fc956f2bdded2374cee Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 31 Oct 2015 06:17:35 +0100 Subject: Implement a basic webirc support See https://kiwiirc.com/docs/webirc fix #3135 --- src/irc/irc_client.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++-- src/irc/irc_client.hpp | 17 ++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index f6b8f9c..3161b85 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -26,9 +26,11 @@ using namespace std::chrono_literals; IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& nickname, const std::string& username, - const std::string& realname, Bridge* bridge): + const std::string& realname, const std::string& user_hostname, + Bridge* bridge): TCPSocketHandler(poller), hostname(hostname), + user_hostname(user_hostname), username(username), realname(realname), current_nick(nickname), @@ -113,6 +115,39 @@ void IrcClient::on_connection_failed(const std::string& reason) void IrcClient::on_connected() { + const auto webirc_password = Config::get("webirc_password", ""); + static std::string resolved_ip; + + if (!webirc_password.empty()) + { + if (!resolved_ip.empty()) + this->send_webirc_command(webirc_password, resolved_ip); + else + { // Start resolving the hostname of the user, and call + // on_connected again when it’s done + this->dns_resolver.resolve(this->user_hostname, "5222", + [this](const struct addrinfo* addr) + { + resolved_ip = addr_to_string(addr); + // Only continue the process if we + // didn’t get connected while we were + // resolving + if (this->is_connected()) + this->on_connected(); + }, + [this](const char* error_msg) + { + if (this->is_connected()) + { + this->on_connection_close("Could not resolve hostname "s + this->user_hostname + + ": " + error_msg); + this->send_quit_command(""); + } + }); + return; + } + } + #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), this->get_hostname()); @@ -253,7 +288,7 @@ void IrcClient::send_raw(const std::string& txt) void IrcClient::send_user_command(const std::string& username, const std::string& realname) { - this->send_message(IrcMessage("USER", {username, "ignored", "ignored", realname})); + this->send_message(IrcMessage("USER", {username, this->user_hostname, "ignored", realname})); } void IrcClient::send_nick_command(const std::string& nick) @@ -266,6 +301,11 @@ void IrcClient::send_pass_command(const std::string& password) this->send_message(IrcMessage("PASS", {password})); } +void IrcClient::send_webirc_command(const std::string& password, const std::string& user_ip) +{ + this->send_message(IrcMessage("WEBIRC", {password, "biboumi", this->user_hostname, user_ip})); +} + void IrcClient::send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason) { this->send_message(IrcMessage("KICK", {chan_name, target, reason})); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 7a04164..885ec84 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -27,7 +28,8 @@ class IrcClient: public TCPSocketHandler public: explicit IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& nickname, const std::string& username, - const std::string& realname, Bridge* bridge); + const std::string& realname, const std::string& user_hostname, + Bridge* bridge); ~IrcClient(); /** * Connect to the IRC server @@ -88,6 +90,7 @@ public: */ void send_nick_command(const std::string& username); void send_pass_command(const std::string& password); + void send_webirc_command(const std::string& password, const std::string& user_ip); /** * Send the JOIN irc command. */ @@ -250,11 +253,18 @@ public: std::string get_nick() const { return this->current_nick; } bool is_welcomed() const { return this->welcomed; } + const Resolver& get_resolver() const; + private: /** * The hostname of the server we are connected to. */ const std::string hostname; + /** + * The hostname of the user. This is used in the USER and the WEBIRC + * commands, but only the one in WEBIRC will be used by the IRC server. + */ + const std::string user_hostname; /** * The username used in the USER irc command */ @@ -330,6 +340,11 @@ private: * A set of (lowercase) nicknames to which we sent a private message. */ std::set nicks_to_treat_as_private; + /** + * DNS resolver, used to resolve the hostname of the user if we are using + * the WebIRC protocole. + */ + Resolver dns_resolver; IrcClient(const IrcClient&) = delete; IrcClient(IrcClient&&) = delete; -- cgit v1.2.3 From 6fb4cf5e4db2babad567524df6be3e2798a0fb63 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 31 Oct 2015 06:23:51 +0100 Subject: Do not forget to implement a method --- src/irc/irc_client.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 885ec84..cdae0aa 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -253,7 +253,7 @@ public: std::string get_nick() const { return this->current_nick; } bool is_welcomed() const { return this->welcomed; } - const Resolver& get_resolver() const; + const Resolver& get_resolver() const { return this->dns_resolver; } private: /** -- cgit v1.2.3 From 0a4041f7e9d30fae9b2bfcfaaf1dc3efb368f86f Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 2 Nov 2015 17:14:21 +0100 Subject: Fix the initial IRC nickname (was using realname, by mistake) --- src/irc/irc_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 3161b85..7caf443 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -155,7 +155,7 @@ void IrcClient::on_connected() this->send_pass_command(options.pass.value()); #endif - this->send_nick_command(this->username); + this->send_nick_command(this->current_nick); #ifdef USE_DATABASE if (Config::get("realname_customization", "true") == "true") -- cgit v1.2.3 From e8386bd14e9783f0bef39bdf577545522e33e719 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 3 Nov 2015 16:56:38 +0100 Subject: Provide an adhoc option to let user pass the cert verif for some IRC servers --- src/irc/irc_client.cpp | 11 +++++++++++ src/irc/irc_client.hpp | 3 +++ 2 files changed, 14 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 7caf443..93ea2ae 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -962,3 +962,14 @@ void IrcClient::leave_dummy_channel(const std::string& exit_message) this->dummy_channel.remove_all_users(); this->bridge->send_muc_leave(Iid("%"s + this->hostname), std::string(this->current_nick), exit_message, true); } + +#ifdef BOTAN_FOUND +bool IrcClient::abort_on_invalid_cert() const +{ +#ifdef USE_DATABASE + auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), this->hostname); + return options.verifyCert.value(); +#endif + return true; +} +#endif diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index cdae0aa..733fc92 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -52,6 +52,9 @@ public: * complete messages from it. */ void parse_in_buffer(const size_t) override final; +#ifdef BOTAN_FOUND + virtual bool abort_on_invalid_cert() const override final; +#endif /** * Return the channel with this name, create it if it does not yet exist */ -- cgit v1.2.3 From 241768836ddfb9e3609f987224cd821058fcc948 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 1 Dec 2015 16:08:40 +0100 Subject: Add the outgoing_bind option Lets the admin choose a local address to bind each outgoing (IRC) socket. --- src/irc/irc_client.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 93ea2ae..e53c540 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -86,6 +86,9 @@ void IrcClient::start() this->bridge->send_xmpp_message(this->hostname, "", "Connecting to "s + this->hostname + ":" + port + " (" + (tls ? "encrypted" : "not encrypted") + ")"); + + this->bind_addr = Config::get("outgoing_bind", ""); + this->connect(this->hostname, port, tls); } -- cgit v1.2.3 From 1f6eea62f46789c0d3ebe7da133ccad2e59c89c8 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 3 Dec 2015 21:14:24 +0100 Subject: Add an ad-hoc command to disconnect a user from one or more IRC server fix #3077 --- src/irc/irc_message.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_message.hpp b/src/irc/irc_message.hpp index a0bd772..01e78cf 100644 --- a/src/irc/irc_message.hpp +++ b/src/irc/irc_message.hpp @@ -8,9 +8,9 @@ class IrcMessage { public: - explicit IrcMessage(std::string&& line); - explicit IrcMessage(std::string&& prefix, std::string&& command, std::vector&& args); - explicit IrcMessage(std::string&& command, std::vector&& args); + IrcMessage(std::string&& line); + IrcMessage(std::string&& prefix, std::string&& command, std::vector&& args); + IrcMessage(std::string&& command, std::vector&& args); ~IrcMessage(); std::string prefix; -- cgit v1.2.3 From 7e2427148e9023483f266cd3ac4e167d50320796 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 21 Dec 2015 20:45:40 +0100 Subject: =?UTF-8?q?Use=20references=20instead=20of=20raw=20pointer,=20to?= =?UTF-8?q?=20store=20the=20=E2=80=9Cparent=E2=80=9D=20object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Bridge and IrcClient --- src/irc/irc_client.cpp | 74 +++++++++++++++++++++++++------------------------- src/irc/irc_client.hpp | 6 ++-- 2 files changed, 40 insertions(+), 40 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index e53c540..4aa45ac 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -27,7 +27,7 @@ using namespace std::chrono_literals; IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& nickname, const std::string& username, const std::string& realname, const std::string& user_hostname, - Bridge* bridge): + Bridge& bridge): TCPSocketHandler(poller), hostname(hostname), user_hostname(user_hostname), @@ -48,7 +48,7 @@ IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname "To disconnect from the IRC server, leave this room and all " "other IRC channels of that server."; #ifdef USE_DATABASE - auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), + auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); std::vector ports = utils::split(options.ports, ';', false); for (auto it = ports.rbegin(); it != ports.rend(); ++it) @@ -72,7 +72,7 @@ IrcClient::~IrcClient() { // This event may or may not exist (if we never got connected, it // doesn't), but it's ok - TimedEventsManager::instance().cancel("PING"s + this->hostname + this->bridge->get_jid()); + TimedEventsManager::instance().cancel("PING"s + this->hostname + this->bridge.get_jid()); } void IrcClient::start() @@ -83,7 +83,7 @@ void IrcClient::start() bool tls; std::tie(port, tls) = this->ports_to_try.top(); this->ports_to_try.pop(); - this->bridge->send_xmpp_message(this->hostname, "", "Connecting to "s + + this->bridge.send_xmpp_message(this->hostname, "", "Connecting to "s + this->hostname + ":" + port + " (" + (tls ? "encrypted" : "not encrypted") + ")"); @@ -94,7 +94,7 @@ void IrcClient::start() void IrcClient::on_connection_failed(const std::string& reason) { - this->bridge->send_xmpp_message(this->hostname, "", + this->bridge.send_xmpp_message(this->hostname, "", "Connection failed: "s + reason); if (this->hostname_resolution_failed) @@ -107,7 +107,7 @@ void IrcClient::on_connection_failed(const std::string& reason) for (const auto& tuple: this->channels_to_join) { Iid iid(std::get<0>(tuple) + "%" + this->hostname); - this->bridge->send_presence_error(iid, this->current_nick, + this->bridge.send_presence_error(iid, this->current_nick, "cancel", "item-not-found", "", reason); } @@ -152,7 +152,7 @@ void IrcClient::on_connected() } #ifdef USE_DATABASE - auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), + auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); if (!options.pass.value().empty()) this->send_pass_command(options.pass.value()); @@ -258,7 +258,7 @@ void IrcClient::parse_in_buffer(const size_t) this->on_unknown_message(message); } // Try to find a waiting_iq, which response will be triggered by this IrcMessage - this->bridge->trigger_on_irc_message(this->hostname, message); + this->bridge.trigger_on_irc_message(this->hostname, message); } } @@ -413,7 +413,7 @@ void IrcClient::forward_server_message(const IrcMessage& message) const std::string from = message.prefix; const std::string body = message.arguments[1]; - this->bridge->send_xmpp_message(this->hostname, from, body); + this->bridge.send_xmpp_message(this->hostname, from, body); } void IrcClient::on_notice(const IrcMessage& message) @@ -438,11 +438,11 @@ 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}, nick, body, false); } else - this->bridge->send_xmpp_message(this->hostname, from, body); + this->bridge.send_xmpp_message(this->hostname, from, body); } else { @@ -494,7 +494,7 @@ void IrcClient::on_isupport_message(const IrcMessage& message) void IrcClient::send_gateway_message(const std::string& message, const std::string& from) { - this->bridge->send_xmpp_message(this->hostname, from, message); + this->bridge.send_xmpp_message(this->hostname, from, message); } void IrcClient::set_and_forward_user_list(const IrcMessage& message) @@ -507,7 +507,7 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); if (user->nick != channel->get_self()->nick) { - this->bridge->send_user_join(this->hostname, chan_name, user, + this->bridge.send_user_join(this->hostname, chan_name, user, user->get_most_significant_mode(this->sorted_user_modes), false); } @@ -533,7 +533,7 @@ void IrcClient::on_channel_join(const IrcMessage& message) else { const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); - this->bridge->send_user_join(this->hostname, chan_name, user, + this->bridge.send_user_join(this->hostname, chan_name, user, user->get_most_significant_mode(this->sorted_user_modes), false); } @@ -559,16 +559,16 @@ void IrcClient::on_channel_message(const IrcMessage& message) if (!body.empty() && body[0] == '\01') { if (body.substr(1, 6) == "ACTION") - this->bridge->send_message(iid, nick, + this->bridge.send_message(iid, nick, "/me"s + body.substr(7, body.size() - 8), muc); else if (body.substr(1, 8) == "VERSION\01") - this->bridge->send_iq_version_request(nick, this->hostname); + this->bridge.send_iq_version_request(nick, this->hostname); else if (body.substr(1, 5) == "PING ") - this->bridge->send_xmpp_ping_request(utils::tolower(nick), this->hostname, + this->bridge.send_xmpp_ping_request(utils::tolower(nick), this->hostname, body.substr(6, body.size() - 7)); } else - this->bridge->send_message(iid, nick, body, muc); + this->bridge.send_message(iid, nick, body, muc); } void IrcClient::on_rpl_liststart(const IrcMessage&) @@ -599,7 +599,7 @@ void IrcClient::on_motd_line(const IrcMessage& message) void IrcClient::send_motd(const IrcMessage&) { - this->bridge->send_xmpp_message(this->hostname, "", this->motd); + this->bridge.send_xmpp_message(this->hostname, "", this->motd); } void IrcClient::on_topic_received(const IrcMessage& message) @@ -608,7 +608,7 @@ void IrcClient::on_topic_received(const IrcMessage& message) IrcChannel* channel = this->get_channel(chan_name); channel->topic = message.arguments[message.arguments.size() - 1]; if (channel->joined) - this->bridge->send_topic(this->hostname, chan_name, channel->topic); + this->bridge.send_topic(this->hostname, chan_name, channel->topic); } void IrcClient::on_channel_completely_joined(const IrcMessage& message) @@ -616,10 +616,10 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); channel->joined = true; - this->bridge->send_user_join(this->hostname, chan_name, channel->get_self(), + this->bridge.send_user_join(this->hostname, chan_name, channel->get_self(), channel->get_self()->get_most_significant_mode(this->sorted_user_modes), true); - this->bridge->send_topic(this->hostname, chan_name, channel->topic); + this->bridge.send_topic(this->hostname, chan_name, channel->topic); } void IrcClient::on_erroneous_nickname(const IrcMessage& message) @@ -639,7 +639,7 @@ void IrcClient::on_nickname_conflict(const IrcMessage& message) iid.set_local(it->first); iid.set_server(this->hostname); iid.is_channel = true; - this->bridge->send_nickname_conflict_error(iid, nickname); + this->bridge.send_nickname_conflict_error(iid, nickname); } } @@ -656,7 +656,7 @@ void IrcClient::on_nickname_change_too_fast(const IrcMessage& message) iid.set_local(it->first); iid.set_server(this->hostname); iid.is_channel = true; - this->bridge->send_presence_error(iid, nickname, + this->bridge.send_presence_error(iid, nickname, "cancel", "not-acceptable", "", txt); } @@ -674,14 +674,14 @@ void IrcClient::on_welcome_message(const IrcMessage& message) this->current_nick = message.arguments[0]; this->welcomed = true; #ifdef USE_DATABASE - auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), + auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); if (!options.afterConnectionCommand.value().empty()) this->send_raw(options.afterConnectionCommand.value()); #endif // Install a repeated events to regularly send a PING TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this), - "PING"s + this->hostname + this->bridge->get_jid())); + "PING"s + this->hostname + this->bridge.get_jid())); for (const auto& tuple: this->channels_to_join) this->send_join_command(std::get<0>(tuple), std::get<1>(tuple)); this->channels_to_join.clear(); @@ -725,7 +725,7 @@ void IrcClient::on_part(const IrcMessage& message) // channel pointer is now invalid channel = nullptr; } - this->bridge->send_muc_leave(std::move(iid), std::move(nick), std::move(txt), self); + this->bridge.send_muc_leave(std::move(iid), std::move(nick), std::move(txt), self); } } @@ -743,7 +743,7 @@ void IrcClient::on_error(const IrcMessage& message) if (!channel->joined) continue; std::string own_nick = channel->get_self()->nick; - this->bridge->send_muc_leave(std::move(iid), std::move(own_nick), leave_message, true); + this->bridge.send_muc_leave(std::move(iid), std::move(own_nick), leave_message, true); } this->channels.clear(); this->send_gateway_message("ERROR: "s + leave_message); @@ -767,7 +767,7 @@ void IrcClient::on_quit(const IrcMessage& message) 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); + this->bridge.send_muc_leave(std::move(iid), std::move(nick), txt, false); } } } @@ -789,7 +789,7 @@ void IrcClient::on_nick(const IrcMessage& message) 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); + this->bridge.send_nick_change(std::move(iid), old_nick, new_nick, user_mode, self); user->nick = new_nick; if (self) { @@ -815,7 +815,7 @@ void IrcClient::on_kick(const IrcMessage& message) 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); + this->bridge.kick_muc_user(std::move(iid), target, reason, author.nick); } void IrcClient::on_mode(const IrcMessage& message) @@ -846,7 +846,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message) mode_arguments += message.arguments[i]; } } - this->bridge->send_message(iid, "", "Mode "s + iid.get_local() + + this->bridge.send_message(iid, "", "Mode "s + iid.get_local() + " [" + mode_arguments + "] by " + user.nick, true); const IrcChannel* channel = this->get_channel(iid.get_local()); @@ -917,13 +917,13 @@ void IrcClient::on_channel_mode(const IrcMessage& message) for (const IrcUser* u: modified_users) { char most_significant_mode = u->get_most_significant_mode(this->sorted_user_modes); - this->bridge->send_affiliation_role_change(iid, u->nick, most_significant_mode); + this->bridge.send_affiliation_role_change(iid, u->nick, most_significant_mode); } } void IrcClient::on_user_mode(const IrcMessage& message) { - this->bridge->send_xmpp_message(this->hostname, "", + this->bridge.send_xmpp_message(this->hostname, "", "User mode for "s + message.arguments[0] + " is [" + message.arguments[1] + "]"); } @@ -940,7 +940,7 @@ void IrcClient::on_unknown_message(const IrcMessage& message) if (it + 1 != message.arguments.end()) ss << " "; } - this->bridge->send_xmpp_message(this->hostname, from, ss.str()); + this->bridge.send_xmpp_message(this->hostname, from, ss.str()); } size_t IrcClient::number_of_joined_channels() const @@ -963,14 +963,14 @@ 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), std::string(this->current_nick), exit_message, true); } #ifdef BOTAN_FOUND bool IrcClient::abort_on_invalid_cert() const { #ifdef USE_DATABASE - auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), this->hostname); + auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->hostname); return options.verifyCert.value(); #endif return true; diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 733fc92..7c2a43f 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -29,7 +29,7 @@ public: explicit IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& nickname, const std::string& username, const std::string& realname, const std::string& user_hostname, - Bridge* bridge); + Bridge& bridge); ~IrcClient(); /** * Connect to the IRC server @@ -281,9 +281,9 @@ private: */ std::string current_nick; /** - * Raw pointer because the bridge owns us. + * To communicate back with the bridge */ - Bridge* bridge; + Bridge& bridge; /** * The list of joined channels, indexed by name */ -- cgit v1.2.3 From a38b17692e0297cbd5d719f059bd0a1b6ef39fe4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 29 Dec 2015 11:19:39 +0100 Subject: Support multi-prefix See http://ircv3.net/specs/extensions/multi-prefix-3.1.html ref #3103 --- src/irc/irc_client.cpp | 3 +++ src/irc/irc_user.cpp | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 4aa45ac..e71d38c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -151,6 +151,9 @@ void IrcClient::on_connected() } } + this->send_message({"CAP", {"REQ", "multi-prefix"}}); + this->send_message({"CAP", {"END"}}); + #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); diff --git a/src/irc/irc_user.cpp b/src/irc/irc_user.cpp index 8785270..9fa3612 100644 --- a/src/irc/irc_user.cpp +++ b/src/irc/irc_user.cpp @@ -7,8 +7,20 @@ IrcUser::IrcUser(const std::string& name, { if (name.empty()) return ; - const std::map::const_iterator prefix = prefix_to_mode.find(name[0]); - const std::string::size_type name_begin = prefix == prefix_to_mode.end()? 0: 1; + + // One or more prefix (with multi-prefix support) may come before the + // actual nick + std::string::size_type name_begin = 0; + while (name_begin != name.size()) + { + const auto prefix = prefix_to_mode.find(name[name_begin]); + // This is not a prefix + if (prefix == prefix_to_mode.end()) + break; + this->modes.insert(prefix->second); + name_begin++; + } + const std::string::size_type sep = name.find("!", name_begin); if (sep == std::string::npos) this->nick = name.substr(name_begin); @@ -17,8 +29,6 @@ IrcUser::IrcUser(const std::string& name, this->nick = name.substr(name_begin, sep-name_begin); this->host = name.substr(sep+1); } - if (prefix != prefix_to_mode.end()) - this->modes.insert(prefix->second); } IrcUser::IrcUser(const std::string& name): -- cgit v1.2.3 From 1f8333f23f060750673d0b7c573f2e2d12142adf Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 30 Dec 2015 21:34:11 +0100 Subject: Support a trusted SHA1 fingerprint to be configured for each IRC server --- src/irc/irc_client.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index e71d38c..1a83446 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -89,6 +89,13 @@ void IrcClient::start() this->bind_addr = Config::get("outgoing_bind", ""); +#ifdef BOTAN_FOUND +# ifdef USE_DATABASE + auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), + this->get_hostname()); + this->credential_manager.set_trusted_fingerprint(options.trustedFingerprint); +# endif +#endif this->connect(this->hostname, port, tls); } -- cgit v1.2.3 From 0a352e557d2a0760601847a97c562759fb04d529 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 2 Feb 2016 17:41:38 +0100 Subject: Move the irc callbacks into the cpp file --- src/irc/irc_client.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ src/irc/irc_client.hpp | 93 -------------------------------------------------- 2 files changed, 92 insertions(+), 93 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 1a83446..0efae04 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -23,6 +23,98 @@ using namespace std::string_literals; using namespace std::chrono_literals; +/** + * Define a map of functions to be called for each IRC command we can + * handle. + */ +typedef void (IrcClient::*irc_callback_t)(const IrcMessage&); + +static const std::unordered_map>> irc_callbacks = { + {"NOTICE", {&IrcClient::on_notice, {2, 0}}}, + {"002", {&IrcClient::forward_server_message, {2, 0}}}, + {"003", {&IrcClient::forward_server_message, {2, 0}}}, + {"005", {&IrcClient::on_isupport_message, {0, 0}}}, + {"RPL_LISTSTART", {&IrcClient::on_rpl_liststart, {0, 0}}}, + {"321", {&IrcClient::on_rpl_liststart, {0, 0}}}, + {"RPL_LIST", {&IrcClient::on_rpl_list, {0, 0}}}, + {"322", {&IrcClient::on_rpl_list, {0, 0}}}, + {"RPL_LISTEND", {&IrcClient::on_rpl_listend, {0, 0}}}, + {"323", {&IrcClient::on_rpl_listend, {0, 0}}}, + {"RPL_MOTDSTART", {&IrcClient::empty_motd, {0, 0}}}, + {"375", {&IrcClient::empty_motd, {0, 0}}}, + {"RPL_MOTD", {&IrcClient::on_motd_line, {2, 0}}}, + {"372", {&IrcClient::on_motd_line, {2, 0}}}, + {"RPL_MOTDEND", {&IrcClient::send_motd, {0, 0}}}, + {"376", {&IrcClient::send_motd, {0, 0}}}, + {"JOIN", {&IrcClient::on_channel_join, {1, 0}}}, + {"PRIVMSG", {&IrcClient::on_channel_message, {2, 0}}}, + {"353", {&IrcClient::set_and_forward_user_list, {4, 0}}}, + {"332", {&IrcClient::on_topic_received, {2, 0}}}, + {"TOPIC", {&IrcClient::on_topic_received, {2, 0}}}, + {"366", {&IrcClient::on_channel_completely_joined, {2, 0}}}, + {"432", {&IrcClient::on_erroneous_nickname, {2, 0}}}, + {"433", {&IrcClient::on_nickname_conflict, {2, 0}}}, + {"438", {&IrcClient::on_nickname_change_too_fast, {2, 0}}}, + {"001", {&IrcClient::on_welcome_message, {1, 0}}}, + {"PART", {&IrcClient::on_part, {1, 0}}}, + {"ERROR", {&IrcClient::on_error, {1, 0}}}, + {"QUIT", {&IrcClient::on_quit, {0, 0}}}, + {"NICK", {&IrcClient::on_nick, {1, 0}}}, + {"MODE", {&IrcClient::on_mode, {1, 0}}}, + {"PING", {&IrcClient::send_pong_command, {1, 0}}}, + {"PONG", {&IrcClient::on_pong, {0, 0}}}, + {"KICK", {&IrcClient::on_kick, {3, 0}}}, + + {"401", {&IrcClient::on_generic_error, {2, 0}}}, + {"402", {&IrcClient::on_generic_error, {2, 0}}}, + {"403", {&IrcClient::on_generic_error, {2, 0}}}, + {"404", {&IrcClient::on_generic_error, {2, 0}}}, + {"405", {&IrcClient::on_generic_error, {2, 0}}}, + {"406", {&IrcClient::on_generic_error, {2, 0}}}, + {"407", {&IrcClient::on_generic_error, {2, 0}}}, + {"408", {&IrcClient::on_generic_error, {2, 0}}}, + {"409", {&IrcClient::on_generic_error, {2, 0}}}, + {"410", {&IrcClient::on_generic_error, {2, 0}}}, + {"411", {&IrcClient::on_generic_error, {2, 0}}}, + {"412", {&IrcClient::on_generic_error, {2, 0}}}, + {"414", {&IrcClient::on_generic_error, {2, 0}}}, + {"421", {&IrcClient::on_generic_error, {2, 0}}}, + {"422", {&IrcClient::on_generic_error, {2, 0}}}, + {"423", {&IrcClient::on_generic_error, {2, 0}}}, + {"424", {&IrcClient::on_generic_error, {2, 0}}}, + {"431", {&IrcClient::on_generic_error, {2, 0}}}, + {"436", {&IrcClient::on_generic_error, {2, 0}}}, + {"441", {&IrcClient::on_generic_error, {2, 0}}}, + {"442", {&IrcClient::on_generic_error, {2, 0}}}, + {"443", {&IrcClient::on_generic_error, {2, 0}}}, + {"444", {&IrcClient::on_generic_error, {2, 0}}}, + {"446", {&IrcClient::on_generic_error, {2, 0}}}, + {"451", {&IrcClient::on_generic_error, {2, 0}}}, + {"461", {&IrcClient::on_generic_error, {2, 0}}}, + {"462", {&IrcClient::on_generic_error, {2, 0}}}, + {"463", {&IrcClient::on_generic_error, {2, 0}}}, + {"464", {&IrcClient::on_generic_error, {2, 0}}}, + {"465", {&IrcClient::on_generic_error, {2, 0}}}, + {"467", {&IrcClient::on_generic_error, {2, 0}}}, + {"470", {&IrcClient::on_generic_error, {2, 0}}}, + {"471", {&IrcClient::on_generic_error, {2, 0}}}, + {"472", {&IrcClient::on_generic_error, {2, 0}}}, + {"473", {&IrcClient::on_generic_error, {2, 0}}}, + {"474", {&IrcClient::on_generic_error, {2, 0}}}, + {"475", {&IrcClient::on_generic_error, {2, 0}}}, + {"476", {&IrcClient::on_generic_error, {2, 0}}}, + {"477", {&IrcClient::on_generic_error, {2, 0}}}, + {"481", {&IrcClient::on_generic_error, {2, 0}}}, + {"482", {&IrcClient::on_generic_error, {2, 0}}}, + {"483", {&IrcClient::on_generic_error, {2, 0}}}, + {"484", {&IrcClient::on_generic_error, {2, 0}}}, + {"485", {&IrcClient::on_generic_error, {2, 0}}}, + {"487", {&IrcClient::on_generic_error, {2, 0}}}, + {"491", {&IrcClient::on_generic_error, {2, 0}}}, + {"501", {&IrcClient::on_generic_error, {2, 0}}}, + {"502", {&IrcClient::on_generic_error, {2, 0}}}, +}; IrcClient::IrcClient(std::shared_ptr poller, const std::string& hostname, const std::string& nickname, const std::string& username, diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 7c2a43f..628f547 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -355,97 +355,4 @@ private: IrcClient& operator=(IrcClient&&) = delete; }; -/** - * Define a map of functions to be called for each IRC command we can - * handle. - */ -typedef void (IrcClient::*irc_callback_t)(const IrcMessage&); - -static const std::unordered_map>> irc_callbacks = { - {"NOTICE", {&IrcClient::on_notice, {2, 0}}}, - {"002", {&IrcClient::forward_server_message, {2, 0}}}, - {"003", {&IrcClient::forward_server_message, {2, 0}}}, - {"005", {&IrcClient::on_isupport_message, {0, 0}}}, - {"RPL_LISTSTART", {&IrcClient::on_rpl_liststart, {0, 0}}}, - {"321", {&IrcClient::on_rpl_liststart, {0, 0}}}, - {"RPL_LIST", {&IrcClient::on_rpl_list, {0, 0}}}, - {"322", {&IrcClient::on_rpl_list, {0, 0}}}, - {"RPL_LISTEND", {&IrcClient::on_rpl_listend, {0, 0}}}, - {"323", {&IrcClient::on_rpl_listend, {0, 0}}}, - {"RPL_MOTDSTART", {&IrcClient::empty_motd, {0, 0}}}, - {"375", {&IrcClient::empty_motd, {0, 0}}}, - {"RPL_MOTD", {&IrcClient::on_motd_line, {2, 0}}}, - {"372", {&IrcClient::on_motd_line, {2, 0}}}, - {"RPL_MOTDEND", {&IrcClient::send_motd, {0, 0}}}, - {"376", {&IrcClient::send_motd, {0, 0}}}, - {"JOIN", {&IrcClient::on_channel_join, {1, 0}}}, - {"PRIVMSG", {&IrcClient::on_channel_message, {2, 0}}}, - {"353", {&IrcClient::set_and_forward_user_list, {4, 0}}}, - {"332", {&IrcClient::on_topic_received, {2, 0}}}, - {"TOPIC", {&IrcClient::on_topic_received, {2, 0}}}, - {"366", {&IrcClient::on_channel_completely_joined, {2, 0}}}, - {"432", {&IrcClient::on_erroneous_nickname, {2, 0}}}, - {"433", {&IrcClient::on_nickname_conflict, {2, 0}}}, - {"438", {&IrcClient::on_nickname_change_too_fast, {2, 0}}}, - {"001", {&IrcClient::on_welcome_message, {1, 0}}}, - {"PART", {&IrcClient::on_part, {1, 0}}}, - {"ERROR", {&IrcClient::on_error, {1, 0}}}, - {"QUIT", {&IrcClient::on_quit, {0, 0}}}, - {"NICK", {&IrcClient::on_nick, {1, 0}}}, - {"MODE", {&IrcClient::on_mode, {1, 0}}}, - {"PING", {&IrcClient::send_pong_command, {1, 0}}}, - {"PONG", {&IrcClient::on_pong, {0, 0}}}, - {"KICK", {&IrcClient::on_kick, {3, 0}}}, - - {"401", {&IrcClient::on_generic_error, {2, 0}}}, - {"402", {&IrcClient::on_generic_error, {2, 0}}}, - {"403", {&IrcClient::on_generic_error, {2, 0}}}, - {"404", {&IrcClient::on_generic_error, {2, 0}}}, - {"405", {&IrcClient::on_generic_error, {2, 0}}}, - {"406", {&IrcClient::on_generic_error, {2, 0}}}, - {"407", {&IrcClient::on_generic_error, {2, 0}}}, - {"408", {&IrcClient::on_generic_error, {2, 0}}}, - {"409", {&IrcClient::on_generic_error, {2, 0}}}, - {"410", {&IrcClient::on_generic_error, {2, 0}}}, - {"411", {&IrcClient::on_generic_error, {2, 0}}}, - {"412", {&IrcClient::on_generic_error, {2, 0}}}, - {"414", {&IrcClient::on_generic_error, {2, 0}}}, - {"421", {&IrcClient::on_generic_error, {2, 0}}}, - {"422", {&IrcClient::on_generic_error, {2, 0}}}, - {"423", {&IrcClient::on_generic_error, {2, 0}}}, - {"424", {&IrcClient::on_generic_error, {2, 0}}}, - {"431", {&IrcClient::on_generic_error, {2, 0}}}, - {"436", {&IrcClient::on_generic_error, {2, 0}}}, - {"441", {&IrcClient::on_generic_error, {2, 0}}}, - {"442", {&IrcClient::on_generic_error, {2, 0}}}, - {"443", {&IrcClient::on_generic_error, {2, 0}}}, - {"444", {&IrcClient::on_generic_error, {2, 0}}}, - {"446", {&IrcClient::on_generic_error, {2, 0}}}, - {"451", {&IrcClient::on_generic_error, {2, 0}}}, - {"461", {&IrcClient::on_generic_error, {2, 0}}}, - {"462", {&IrcClient::on_generic_error, {2, 0}}}, - {"463", {&IrcClient::on_generic_error, {2, 0}}}, - {"464", {&IrcClient::on_generic_error, {2, 0}}}, - {"465", {&IrcClient::on_generic_error, {2, 0}}}, - {"467", {&IrcClient::on_generic_error, {2, 0}}}, - {"470", {&IrcClient::on_generic_error, {2, 0}}}, - {"471", {&IrcClient::on_generic_error, {2, 0}}}, - {"472", {&IrcClient::on_generic_error, {2, 0}}}, - {"473", {&IrcClient::on_generic_error, {2, 0}}}, - {"474", {&IrcClient::on_generic_error, {2, 0}}}, - {"475", {&IrcClient::on_generic_error, {2, 0}}}, - {"476", {&IrcClient::on_generic_error, {2, 0}}}, - {"477", {&IrcClient::on_generic_error, {2, 0}}}, - {"481", {&IrcClient::on_generic_error, {2, 0}}}, - {"482", {&IrcClient::on_generic_error, {2, 0}}}, - {"483", {&IrcClient::on_generic_error, {2, 0}}}, - {"484", {&IrcClient::on_generic_error, {2, 0}}}, - {"485", {&IrcClient::on_generic_error, {2, 0}}}, - {"487", {&IrcClient::on_generic_error, {2, 0}}}, - {"491", {&IrcClient::on_generic_error, {2, 0}}}, - {"501", {&IrcClient::on_generic_error, {2, 0}}}, - {"502", {&IrcClient::on_generic_error, {2, 0}}}, -}; - #endif // IRC_CLIENT_INCLUDED -- cgit v1.2.3 From 464261d4ed462f5d74507fe4d17bc5f76b5f726d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 11 Apr 2016 17:14:39 +0200 Subject: Support RPL_NOTPIC and 005 --- src/irc/irc_client.cpp | 16 ++++++++++++++++ src/irc/irc_client.hpp | 8 ++++++++ 2 files changed, 24 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0efae04..1150155 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -34,6 +34,7 @@ static const std::unordered_mapbridge.send_xmpp_message(this->hostname, from, message); @@ -690,6 +697,15 @@ void IrcClient::empty_motd(const IrcMessage&) this->motd.erase(); } +void IrcClient::on_empty_topic(const IrcMessage& message) +{ + const std::string chan_name = utils::tolower(message.arguments[message.arguments.size() - 1]); + log_debug("empty topic for " << chan_name); + IrcChannel* channel = this->get_channel(chan_name); + if (channel) + channel->topic.clear(); +} + void IrcClient::on_motd_line(const IrcMessage& message) { const std::string body = message.arguments[1]; diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 628f547..5efecc6 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -143,6 +143,10 @@ public: * http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt */ void on_isupport_message(const IrcMessage& message); + /** + * Does nothing yet. Isn’t that duplicating features from 005? + */ + void on_server_myinfo(const IrcMessage& message); /** * Just empty the motd we kept as a string */ @@ -194,6 +198,10 @@ public: * Save the topic in the IrcChannel */ void on_topic_received(const IrcMessage& message); + /** + * Empty the topic + */ + void on_empty_topic(const IrcMessage& message); /** * The channel has been completely joined (self presence, topic, all names * received etc), send the self presence and topic to the XMPP user. -- cgit v1.2.3 From 04d28f968b227067e77e365d317fc251d3c965f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 19 Apr 2016 02:43:26 +0200 Subject: Forward the topic authors, handle the author from 333 messages fix #2 --- src/irc/irc_channel.hpp | 1 + src/irc/irc_client.cpp | 16 ++++++++++++++-- src/irc/irc_client.hpp | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index 568de0a..651b8ed 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -18,6 +18,7 @@ public: bool joined; std::string topic; + std::string topic_author; void set_self(const std::string& name); IrcUser* get_self() const; IrcUser* add_user(const std::string& name, diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 1150155..327b170 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -55,6 +55,8 @@ static const std::unordered_mapget_channel(chan_name); channel->topic = message.arguments[message.arguments.size() - 1]; + channel->topic_author = author.nick; if (channel->joined) - this->bridge.send_topic(this->hostname, chan_name, channel->topic); + this->bridge.send_topic(this->hostname, chan_name, channel->topic, channel->topic_author); +} + +void IrcClient::on_topic_who_time_received(const IrcMessage& message) +{ + IrcUser author(message.arguments[2]); + const std::string chan_name = utils::tolower(message.arguments[1]); + IrcChannel* channel = this->get_channel(chan_name); + channel->topic_author = author.nick; } void IrcClient::on_channel_completely_joined(const IrcMessage& message) @@ -737,7 +749,7 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) this->bridge.send_user_join(this->hostname, chan_name, channel->get_self(), channel->get_self()->get_most_significant_mode(this->sorted_user_modes), true); - this->bridge.send_topic(this->hostname, chan_name, channel->topic); + this->bridge.send_topic(this->hostname, chan_name, channel->topic, channel->topic_author); } void IrcClient::on_erroneous_nickname(const IrcMessage& message) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 5efecc6..ceaa860 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -198,6 +198,10 @@ public: * Save the topic in the IrcChannel */ void on_topic_received(const IrcMessage& message); + /** + * Save the topic author in the IrcChannel + */ + void on_topic_who_time_received(const IrcMessage& message); /** * Empty the topic */ -- cgit v1.2.3 From af42073830087d97385e507f27f601e8769541b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 4 May 2016 14:16:40 +0200 Subject: Style fix Move all constructors at the top of classes --- src/irc/iid.cpp | 8 -------- src/irc/iid.hpp | 12 ++++++------ src/irc/irc_channel.hpp | 20 +++++++++----------- src/irc/irc_client.hpp | 11 ++++++----- src/irc/irc_message.cpp | 4 ---- src/irc/irc_message.hpp | 10 +++++----- src/irc/irc_user.hpp | 13 +++++++------ 7 files changed, 33 insertions(+), 45 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 9d39129..212fb8f 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -51,14 +51,6 @@ void Iid::init_with_fixed_server(const std::string& iid, const std::string& host } } -Iid::Iid(const Iid& other): - is_channel(other.is_channel), - is_user(other.is_user), - local(other.local), - server(other.server) -{ -} - Iid::Iid(): is_channel(false), is_user(false) diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index 91779b2..1c026e8 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -43,8 +43,12 @@ class Iid { public: Iid(const std::string& iid); - explicit Iid(const Iid&); - explicit Iid(); + Iid(); + Iid(const Iid&) = default; + + Iid(Iid&&) = delete; + Iid& operator=(const Iid&) = delete; + Iid& operator=(Iid&&) = delete; void set_local(const std::string& loc); void set_server(const std::string& serv); @@ -63,10 +67,6 @@ private: std::string local; std::string server; - - Iid(Iid&&) = delete; - Iid& operator=(const Iid&) = delete; - Iid& operator=(Iid&&) = delete; }; namespace std { diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index 651b8ed..e22947b 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -16,6 +16,11 @@ class IrcChannel public: explicit IrcChannel(); + IrcChannel(const IrcChannel&) = delete; + IrcChannel(IrcChannel&&) = delete; + IrcChannel& operator=(const IrcChannel&) = delete; + IrcChannel& operator=(IrcChannel&&) = delete; + bool joined; std::string topic; std::string topic_author; @@ -30,12 +35,6 @@ public: protected: std::unique_ptr self; std::vector> users; - -private: - IrcChannel(const IrcChannel&) = delete; - IrcChannel(IrcChannel&&) = delete; - IrcChannel& operator=(const IrcChannel&) = delete; - IrcChannel& operator=(IrcChannel&&) = delete; }; /** @@ -50,6 +49,10 @@ class DummyIrcChannel: public IrcChannel { public: explicit DummyIrcChannel(); + DummyIrcChannel(const DummyIrcChannel&) = delete; + DummyIrcChannel(DummyIrcChannel&&) = delete; + DummyIrcChannel& operator=(const DummyIrcChannel&) = delete; + DummyIrcChannel& operator=(DummyIrcChannel&&) = delete; /** * This flag is at true whenever the user wants to join this channel, but @@ -60,11 +63,6 @@ public: * the channel, we don’t use that flag, we just join it immediately. */ bool joining; -private: - DummyIrcChannel(const DummyIrcChannel&) = delete; - DummyIrcChannel(DummyIrcChannel&&) = delete; - DummyIrcChannel& operator=(const DummyIrcChannel&) = delete; - DummyIrcChannel& operator=(DummyIrcChannel&&) = delete; }; #endif // IRC_CHANNEL_INCLUDED diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index ceaa860..7af097c 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -31,6 +31,12 @@ public: const std::string& realname, const std::string& user_hostname, Bridge& bridge); ~IrcClient(); + + IrcClient(const IrcClient&) = delete; + IrcClient(IrcClient&&) = delete; + IrcClient& operator=(const IrcClient&) = delete; + IrcClient& operator=(IrcClient&&) = delete; + /** * Connect to the IRC server */ @@ -360,11 +366,6 @@ private: * the WebIRC protocole. */ Resolver dns_resolver; - - IrcClient(const IrcClient&) = delete; - IrcClient(IrcClient&&) = delete; - IrcClient& operator=(const IrcClient&) = delete; - IrcClient& operator=(IrcClient&&) = delete; }; #endif // IRC_CLIENT_INCLUDED diff --git a/src/irc/irc_message.cpp b/src/irc/irc_message.cpp index eb3eb47..966a47c 100644 --- a/src/irc/irc_message.cpp +++ b/src/irc/irc_message.cpp @@ -47,10 +47,6 @@ IrcMessage::IrcMessage(std::string&& command, { } -IrcMessage::~IrcMessage() -{ -} - std::ostream& operator<<(std::ostream& os, const IrcMessage& message) { os << "IrcMessage"; diff --git a/src/irc/irc_message.hpp b/src/irc/irc_message.hpp index 01e78cf..29ed946 100644 --- a/src/irc/irc_message.hpp +++ b/src/irc/irc_message.hpp @@ -11,16 +11,16 @@ public: IrcMessage(std::string&& line); IrcMessage(std::string&& prefix, std::string&& command, std::vector&& args); IrcMessage(std::string&& command, std::vector&& args); - ~IrcMessage(); - - std::string prefix; - std::string command; - std::vector arguments; + ~IrcMessage() = default; IrcMessage(const IrcMessage&) = delete; IrcMessage(IrcMessage&&) = delete; IrcMessage& operator=(const IrcMessage&) = delete; IrcMessage& operator=(IrcMessage&&) = delete; + + std::string prefix; + std::string command; + std::vector arguments; }; std::ostream& operator<<(std::ostream& os, const IrcMessage& message); diff --git a/src/irc/irc_user.hpp b/src/irc/irc_user.hpp index d3397ca..4b6cd7a 100644 --- a/src/irc/irc_user.hpp +++ b/src/irc/irc_user.hpp @@ -15,18 +15,19 @@ public: explicit IrcUser(const std::string& name, const std::map& prefix_to_mode); explicit IrcUser(const std::string& name); + + IrcUser(const IrcUser&) = delete; + IrcUser(IrcUser&&) = delete; + IrcUser& operator=(const IrcUser&) = delete; + IrcUser& operator=(IrcUser&&) = delete; + void add_mode(const char mode); void remove_mode(const char mode); char get_most_significant_mode(const std::vector& sorted_user_modes) const; + std::string nick; std::string host; std::set modes; - -private: - IrcUser(const IrcUser&) = delete; - IrcUser(IrcUser&&) = delete; - IrcUser& operator=(const IrcUser&) = delete; - IrcUser& operator=(IrcUser&&) = delete; }; #endif // IRC_USER_INCLUDED -- cgit v1.2.3 From fdddd447b3976f26a4146ebf91abfc04736a006b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 13 May 2016 01:22:49 +0200 Subject: =?UTF-8?q?Use=20=E2=80=9Cusing=E2=80=9D=20instead=20of=20typedef?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/irc/irc_client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 327b170..0b1b079 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -27,10 +27,10 @@ using namespace std::chrono_literals; * Define a map of functions to be called for each IRC command we can * handle. */ -typedef void (IrcClient::*irc_callback_t)(const IrcMessage&); +using IrcCallback = void (IrcClient::*)(const IrcMessage&); static const std::unordered_map>> irc_callbacks = { + std::pair>> irc_callbacks = { {"NOTICE", {&IrcClient::on_notice, {2, 0}}}, {"002", {&IrcClient::forward_server_message, {2, 0}}}, {"003", {&IrcClient::forward_server_message, {2, 0}}}, -- cgit v1.2.3 From 507d0c2cbe3c41e3d8e6d38862fe418cb551adf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 2 Jun 2016 01:35:15 +0200 Subject: Forward everything to all concerned XMPP resources --- src/irc/irc_channel.hpp | 2 ++ src/irc/irc_client.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index e22947b..3319505 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -31,6 +31,8 @@ public: IrcUser* find_user(const std::string& name) const; void remove_user(const IrcUser* user); void remove_all_users(); + const std::vector>& get_users() const + { return this->users; } protected: std::unique_ptr self; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0b1b079..ae68528 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -701,7 +701,7 @@ void IrcClient::empty_motd(const IrcMessage&) void IrcClient::on_empty_topic(const IrcMessage& message) { - const std::string chan_name = utils::tolower(message.arguments[message.arguments.size() - 1]); + const std::string chan_name = utils::tolower(message.arguments[1]); log_debug("empty topic for " << chan_name); IrcChannel* channel = this->get_channel(chan_name); if (channel) -- cgit v1.2.3 From 2d11a5f49454717c404b25825f18e696281207d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 8 Jun 2016 01:32:39 +0200 Subject: Support multiple nick session, except for IQs ref #2556 --- src/irc/iid.cpp | 5 +++++ src/irc/iid.hpp | 2 ++ src/irc/irc_channel.cpp | 15 ++++++--------- src/irc/irc_client.cpp | 12 +++--------- src/irc/irc_client.hpp | 2 ++ 5 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 212fb8f..66b66b7 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -100,3 +100,8 @@ namespace std { } } } + +std::tuple Iid::to_tuple() const +{ + return std::make_tuple(this->get_local(), this->get_server()); +} diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index 1c026e8..9747595 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -60,6 +60,8 @@ public: std::string get_sep() const; + std::tuple to_tuple() const; + private: void init(const std::string& iid); diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index b1b3983..9801513 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -1,4 +1,5 @@ #include +#include IrcChannel::IrcChannel(): joined(false), @@ -36,15 +37,11 @@ IrcUser* IrcChannel::find_user(const std::string& name) const void IrcChannel::remove_user(const IrcUser* user) { - for (auto it = this->users.begin(); it != this->users.end(); ++it) - { - IrcUser* u = it->get(); - if (u->nick == user->nick) - { - this->users.erase(it); - break ; - } - } + this->users.erase(std::remove_if(this->users.begin(), this->users.end(), + [user](const std::unique_ptr& u) + { + return user->nick == u->nick; + }), this->users.end()); } void IrcChannel::remove_all_users() diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index ae68528..d16ffc7 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -618,9 +618,7 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); if (user->nick != channel->get_self()->nick) { - this->bridge.send_user_join(this->hostname, chan_name, user, - user->get_most_significant_mode(this->sorted_user_modes), - false); + this->bridge.send_user_join(this->hostname, chan_name, user, user->get_most_significant_mode(this->sorted_user_modes), false); } else { @@ -644,9 +642,7 @@ void IrcClient::on_channel_join(const IrcMessage& message) else { const IrcUser* user = channel->add_user(nick, this->prefix_to_mode); - this->bridge.send_user_join(this->hostname, chan_name, user, - user->get_most_significant_mode(this->sorted_user_modes), - false); + this->bridge.send_user_join(this->hostname, chan_name, user, user->get_most_significant_mode(this->sorted_user_modes), false); } } @@ -746,9 +742,7 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); channel->joined = true; - this->bridge.send_user_join(this->hostname, chan_name, channel->get_self(), - channel->get_self()->get_most_significant_mode(this->sorted_user_modes), - true); + this->bridge.send_user_join(this->hostname, chan_name, channel->get_self(), channel->get_self()->get_most_significant_mode(this->sorted_user_modes), true); this->bridge.send_topic(this->hostname, chan_name, channel->topic, channel->topic_author); } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 7af097c..f075ce6 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -276,6 +276,8 @@ public: const Resolver& get_resolver() const { return this->dns_resolver; } + const std::vector& get_sorted_user_modes() const { return sorted_user_modes; } + private: /** * The hostname of the server we are connected to. -- cgit v1.2.3 From 5a2e61161792cf51209f240e40e28036195f35be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 13 Jun 2016 19:59:17 +0200 Subject: Show off, with some variadic templates, for the logger module --- src/irc/irc_client.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d16ffc7..e320db9 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -333,7 +333,7 @@ void IrcClient::parse_in_buffer(const size_t) break ; IrcMessage message(this->in_buf.substr(0, pos)); this->in_buf = this->in_buf.substr(pos + 2, std::string::npos); - log_debug("IRC RECEIVING: (" << this->get_hostname() << ") " << message); + log_debug("IRC RECEIVING: (", this->get_hostname(), ") ", message); // Call the standard callback (if any), associated with the command // name that we just received. @@ -346,21 +346,21 @@ void IrcClient::parse_in_buffer(const size_t) // second is the max if (message.arguments.size() < limits.first || (limits.second > 0 && message.arguments.size() > limits.second)) - log_warning("Invalid number of arguments for IRC command “" << message.command << - "”: " << message.arguments.size()); + log_warning("Invalid number of arguments for IRC command “", message.command, + "”: ", message.arguments.size()); else { const auto& cb = it->second.first; try { (this->*(cb))(message); } catch (const std::exception& e) { - log_error("Unhandled exception: " << e.what()); + log_error("Unhandled exception: ", e.what()); } } } else { - log_info("No handler for command " << message.command << + log_info("No handler for command ", message.command, ", forwarding the arguments to the user"); this->on_unknown_message(message); } @@ -371,7 +371,7 @@ void IrcClient::parse_in_buffer(const size_t) void IrcClient::send_message(IrcMessage&& message) { - log_debug("IRC SENDING: (" << this->get_hostname() << ") " << message); + log_debug("IRC SENDING: (", this->get_hostname(), ") ", message); std::string res; if (!message.prefix.empty()) res += ":" + std::move(message.prefix) + " "; @@ -392,7 +392,7 @@ void IrcClient::send_message(IrcMessage&& message) void IrcClient::send_raw(const std::string& txt) { - log_debug("IRC SENDING (raw): (" << this->get_hostname() << ") " << txt); + log_debug("IRC SENDING (raw): (", this->get_hostname(), ") ", txt); this->send_data(txt + "\r\n"); } @@ -452,7 +452,7 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st IrcChannel* channel = this->get_channel(chan_name); if (channel->joined == false) { - log_warning("Cannot send message to channel " << chan_name << ", it is not joined"); + log_warning("Cannot send message to channel ", chan_name, ", it is not joined"); return false; } // Cut the message body into 400-bytes parts (because the whole command @@ -698,7 +698,7 @@ void IrcClient::empty_motd(const IrcMessage&) void IrcClient::on_empty_topic(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[1]); - log_debug("empty topic for " << chan_name); + log_debug("empty topic for ", chan_name); IrcChannel* channel = this->get_channel(chan_name); if (channel) channel->topic.clear(); @@ -1026,8 +1026,8 @@ void IrcClient::on_channel_mode(const IrcMessage& message) IrcUser* user = channel->find_user(target); if (!user) { - log_warning("Trying to set mode for non-existing user '" << target - << "' in channel" << iid.get_local()); + log_warning("Trying to set mode for non-existing user '", target + , "' in channel", iid.get_local()); return; } if (add) -- cgit v1.2.3 From 80d0c19c5a8d548a8c6019033bf574ff2be4c0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 14 Jun 2016 20:14:36 +0200 Subject: Refactor, test and improve the way we cut too-long messages for IRC --- src/irc/irc_client.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index e320db9..2cf0840 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -455,15 +456,13 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st log_warning("Cannot send message to channel ", chan_name, ", it is not joined"); return false; } - // Cut the message body into 400-bytes parts (because the whole command - // must fit into 512 bytes, that's an easy way to make sure the chan name - // + body fits. I’m lazy.) - std::string::size_type pos = 0; - while (pos < body.size()) - { - this->send_message(IrcMessage("PRIVMSG", {chan_name, body.substr(pos, 400)})); - pos += 400; - } + // Cut the message body into 512-bytes parts, because the whole command + // must fit into 512 bytes. + // Count the ':' at the start of the text, and two spaces + const auto line_size = 512 - ::strlen("PRIVMSG") - chan_name.length() - 3; + const auto lines = cut(body, line_size); + for (const auto& line: lines) + this->send_message(IrcMessage("PRIVMSG", {chan_name, line})); return true; } -- cgit v1.2.3 From 4b1c580bb9bc03d656e59d702c72c3e793a1bbe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Jun 2016 12:19:19 +0200 Subject: cut messages at 512 bytes, taking into account the UTF-8 codepoints ref #3067 --- src/irc/irc_client.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 2cf0840..1d56361 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -388,6 +388,8 @@ void IrcClient::send_message(IrcMessage&& message) res += " " + arg; } res += "\r\n"; + log_debug("Effective size: ", res.size()); + log_debug(res); this->send_data(std::move(res)); } @@ -458,8 +460,7 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st } // Cut the message body into 512-bytes parts, because the whole command // must fit into 512 bytes. - // Count the ':' at the start of the text, and two spaces - const auto line_size = 512 - ::strlen("PRIVMSG") - chan_name.length() - 3; + const auto line_size = 500 - ::strlen("PRIVMSG ") - chan_name.length() - ::strlen(" :\r\n"); const auto lines = cut(body, line_size); for (const auto& line: lines) this->send_message(IrcMessage("PRIVMSG", {chan_name, line})); -- cgit v1.2.3 From 849c50f9f33d5a391f623272b007810c816aca68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Jun 2016 15:47:05 +0200 Subject: Save our own host, as reported by the server --- src/irc/irc_client.cpp | 13 +++++++++++++ src/irc/irc_client.hpp | 10 ++++++++++ 2 files changed, 23 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 1d56361..324f725 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -59,6 +59,7 @@ static const std::unordered_mapbridge.send_topic(this->hostname, chan_name, channel->topic, channel->topic_author); } +void IrcClient::on_own_host_received(const IrcMessage& message) +{ + this->own_host = message.arguments[1]; + const std::string from = message.prefix; + if (message.arguments.size() >= 3) + this->bridge.send_xmpp_message(this->hostname, from, + this->own_host + " " + message.arguments[2]); + else + this->bridge.send_xmpp_message(this->hostname, from, this->own_host + + " is now your displayed host"); +} + void IrcClient::on_erroneous_nickname(const IrcMessage& message) { const std::string error_msg = message.arguments.size() >= 3 ? diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index f075ce6..718d8a7 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -217,6 +217,10 @@ public: * received etc), send the self presence and topic to the XMPP user. */ void on_channel_completely_joined(const IrcMessage& message); + /** + * Save our own host, as reported by the server + */ + void on_own_host_received(const IrcMessage& message); /** * We tried to set an invalid nickname */ @@ -283,6 +287,12 @@ private: * The hostname of the server we are connected to. */ const std::string hostname; + /** + * Our own host, as reported by the IRC server. + * By default (and if it is not overridden by the server), it is a + * meaningless string, with the maximum allowed size + */ + std::string own_host{63, '*'}; /** * The hostname of the user. This is used in the USER and the WEBIRC * commands, but only the one in WEBIRC will be used by the IRC server. -- cgit v1.2.3 From 430bf3a6610da0f44bdeb0ea37bdf9ceabb8ed01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Jun 2016 15:47:43 +0200 Subject: Properly calculate the maximum size of each message line, before cutting fix #3067 --- src/irc/irc_client.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 324f725..4492176 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -389,8 +389,6 @@ void IrcClient::send_message(IrcMessage&& message) res += " " + arg; } res += "\r\n"; - log_debug("Effective size: ", res.size()); - log_debug(res); this->send_data(std::move(res)); } @@ -459,9 +457,15 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st log_warning("Cannot send message to channel ", chan_name, ", it is not joined"); return false; } - // Cut the message body into 512-bytes parts, because the whole command - // must fit into 512 bytes. - const auto line_size = 500 - ::strlen("PRIVMSG ") - chan_name.length() - ::strlen(" :\r\n"); + // The max size is 512, taking into account the whole message, not just + // the text we send. + // This includes our own nick, username and host (because this will be + // added by the server into our message), in addition to the basic + // components of the message we send (command name, chan name, \r\n et) + // : + NICK + ! + USER + @ + HOST + + PRIVMSG + + CHAN + + : + \r\n + const auto line_size = 512 - + this->current_nick.size() - this->username.size() - this->own_host.size() - + ::strlen(":!@ PRIVMSG ") - chan_name.length() - ::strlen(" :\r\n"); const auto lines = cut(body, line_size); for (const auto& line: lines) this->send_message(IrcMessage("PRIVMSG", {chan_name, line})); -- cgit v1.2.3 From c1f678e4503083e56d0bef0386657c083c0117ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Jun 2016 16:47:11 +0200 Subject: Fix a missing include for strlen --- src/irc/irc_client.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 4492176..dd83307 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 0391f17f999618decffaf3c9261024ab04a33f63 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 21 Jun 2016 23:15:25 +0100 Subject: Add XEP-0106 support to the bridge This allows the user to join channels containing forbidden characters in the local part, like #r&d or #group/project. --- src/irc/iid.cpp | 19 +++++++++++++++---- src/irc/iid.hpp | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.cpp b/src/irc/iid.cpp index 66b66b7..0e2841e 100644 --- a/src/irc/iid.cpp +++ b/src/irc/iid.cpp @@ -3,6 +3,8 @@ #include +#include + Iid::Iid(const std::string& iid): is_channel(false), is_user(false) @@ -59,7 +61,9 @@ Iid::Iid(): void Iid::set_local(const std::string& loc) { - this->local = utils::tolower(loc); + std::string local(utils::tolower(loc)); + xep0106::decode(local); + this->local = local; } void Iid::set_server(const std::string& serv) @@ -72,6 +76,13 @@ const std::string& Iid::get_local() const return this->local; } +const std::string Iid::get_encoded_local() const +{ + std::string local(this->local); + xep0106::encode(local); + return local; +} + const std::string& Iid::get_server() const { return this->server; @@ -90,13 +101,13 @@ namespace std { const std::string to_string(const Iid& iid) { if (Config::get("fixed_irc_server", "").empty()) - return iid.get_local() + iid.get_sep() + iid.get_server(); + return iid.get_encoded_local() + iid.get_sep() + iid.get_server(); else { if (iid.get_sep() == "!") - return iid.get_local() + iid.get_sep(); + return iid.get_encoded_local() + iid.get_sep(); else - return iid.get_local(); + return iid.get_encoded_local(); } } } diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index 9747595..a55ae21 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -53,6 +53,7 @@ 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; -- cgit v1.2.3 From 57263961b487bd839cbce5fe7547933240792fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Jun 2016 22:14:32 +0200 Subject: Fix a use after free in IrcChannel::remove_user --- src/irc/irc_channel.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 9801513..e769245 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -37,11 +37,14 @@ IrcUser* IrcChannel::find_user(const std::string& name) const void IrcChannel::remove_user(const IrcUser* user) { - this->users.erase(std::remove_if(this->users.begin(), this->users.end(), - [user](const std::unique_ptr& u) - { - return user->nick == u->nick; - }), this->users.end()); + const auto nick = user->nick; + const auto it = std::find_if(this->users.begin(), this->users.end(), + [nick](const std::unique_ptr& u) + { + return nick == u->nick; + }); + if (it != this->users.end()) + this->users.erase(it); } void IrcChannel::remove_all_users() -- cgit v1.2.3 From 81f8f45b371d1a0ef72c2768fbd1f9188fe83616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 4 Jul 2016 17:53:53 +0200 Subject: Replace all include guards by #pragma once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s $CURRENT_YEAR --- src/irc/iid.hpp | 6 +++--- src/irc/irc_channel.hpp | 6 +++--- src/irc/irc_client.hpp | 6 +++--- src/irc/irc_message.hpp | 6 +++--- src/irc/irc_user.hpp | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src/irc') diff --git a/src/irc/iid.hpp b/src/irc/iid.hpp index a55ae21..3b11470 100644 --- a/src/irc/iid.hpp +++ b/src/irc/iid.hpp @@ -1,5 +1,5 @@ -#ifndef IID_INCLUDED -# define IID_INCLUDED +#pragma once + #include @@ -76,4 +76,4 @@ namespace std { const std::string to_string(const Iid& iid); } -#endif // IID_INCLUDED + diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index 3319505..2bcefaf 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -1,5 +1,5 @@ -#ifndef IRC_CHANNEL_INCLUDED -# define IRC_CHANNEL_INCLUDED +#pragma once + #include #include @@ -67,4 +67,4 @@ public: bool joining; }; -#endif // IRC_CHANNEL_INCLUDED + diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 718d8a7..fc3918e 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -1,5 +1,5 @@ -#ifndef IRC_CLIENT_INCLUDED -# define IRC_CLIENT_INCLUDED +#pragma once + #include #include @@ -380,4 +380,4 @@ private: Resolver dns_resolver; }; -#endif // IRC_CLIENT_INCLUDED + diff --git a/src/irc/irc_message.hpp b/src/irc/irc_message.hpp index 29ed946..fe954e4 100644 --- a/src/irc/irc_message.hpp +++ b/src/irc/irc_message.hpp @@ -1,5 +1,5 @@ -#ifndef IRC_MESSAGE_INCLUDED -# define IRC_MESSAGE_INCLUDED +#pragma once + #include #include @@ -25,4 +25,4 @@ public: std::ostream& operator<<(std::ostream& os, const IrcMessage& message); -#endif // IRC_MESSAGE_INCLUDED + diff --git a/src/irc/irc_user.hpp b/src/irc/irc_user.hpp index 4b6cd7a..c84030e 100644 --- a/src/irc/irc_user.hpp +++ b/src/irc/irc_user.hpp @@ -1,5 +1,5 @@ -#ifndef IRC_USER_INCLUDED -# define IRC_USER_INCLUDED +#pragma once + #include #include @@ -30,4 +30,4 @@ public: std::set modes; }; -#endif // IRC_USER_INCLUDED + -- cgit v1.2.3