From 158d743bf539399e48c64044639b90e5c1705ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 4 Mar 2018 22:18:58 +0100 Subject: Remove the virtual channel feature altogether --- src/irc/irc_channel.cpp | 6 ------ src/irc/irc_channel.hpp | 30 ----------------------------- src/irc/irc_client.cpp | 51 ++----------------------------------------------- src/irc/irc_client.hpp | 14 -------------- 4 files changed, 2 insertions(+), 99 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 53043c7..1fd34aa 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -58,9 +58,3 @@ void IrcChannel::remove_all_users() this->users.clear(); this->self = nullptr; } - -DummyIrcChannel::DummyIrcChannel(): - IrcChannel(), - joining(false) -{ -} diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index 8f85edb..dff1b78 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -42,33 +42,3 @@ protected: IrcUser* self{nullptr}; std::vector> users{}; }; - -/** - * 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(); - 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 - * 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; -}; - - diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 40078d9..a866726 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -145,14 +145,6 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, chanmodes({"", "", "", ""}), chantypes({'#', '&'}) { - 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."; #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); @@ -315,8 +307,6 @@ void IrcClient::on_connection_close(const std::string& error_msg) IrcChannel* IrcClient::get_channel(const std::string& n) { - if (n.empty()) - return &this->dummy_channel; const std::string name = utils::tolower(n); try { @@ -670,10 +660,7 @@ void IrcClient::on_channel_join(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[0]); IrcChannel* channel; - if (chan_name.empty()) - channel = &this->dummy_channel; - else - channel = this->get_channel(chan_name); + channel = this->get_channel(chan_name); const std::string nick = message.prefix; IrcUser* user = channel->add_user(nick, this->prefix_to_mode); if (channel->joined == false) @@ -948,18 +935,6 @@ void IrcClient::on_welcome_message(const IrcMessage& message) if (!channels_with_key.empty()) this->send_join_command(channels_with_key, keys); 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) @@ -1062,10 +1037,6 @@ void IrcClient::on_nick(const IrcMessage& message) } }; - if (this->get_dummy_channel().joined) - { - change_nick_func("", &this->get_dummy_channel()); - } for (const auto& pair: this->channels) { change_nick_func(pair.first, pair.second.get()); @@ -1248,25 +1219,7 @@ void IrcClient::on_unknown_message(const IrcMessage& message) size_t IrcClient::number_of_joined_channels() const { - if (this->dummy_channel.joined) - return this->channels.size() + 1; - else - return this->channels.size(); -} - -DummyIrcChannel& IrcClient::get_dummy_channel() -{ - return this->dummy_channel; -} - -void IrcClient::leave_dummy_channel(const std::string& exit_message, const std::string& resource) -{ - 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("%" + this->hostname, this->chantypes), std::string(this->current_nick), exit_message, true, true, resource); + return this->channels.size(); } #ifdef BOTAN_FOUND diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index de5c520..fd97fe6 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -279,15 +279,6 @@ 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(); - /** - * 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& resource); const std::string& get_hostname() const { return this->hostname; } std::string get_nick() const { return this->current_nick; } @@ -339,11 +330,6 @@ 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 (tuples with the channel name and the * password, if any), but we need a response 001 from the server before -- cgit v1.2.3 From bb596582bd2d8b9aab3fe08e76a7d24d82bf614a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 00:04:26 +0100 Subject: Add a node in the presence of a leaving participant fix #3339 --- src/irc/irc_channel.cpp | 5 ++++- src/irc/irc_channel.hpp | 2 +- src/irc/irc_client.cpp | 17 ++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 1fd34aa..58f8d5c 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -33,8 +33,9 @@ IrcUser* IrcChannel::find_user(const std::string& name) const return nullptr; } -void IrcChannel::remove_user(const IrcUser* user) +std::unique_ptr IrcChannel::remove_user(const IrcUser* user) { + std::unique_ptr result{}; const auto nick = user->nick; const bool is_self = (user == this->self); const auto it = std::find_if(this->users.begin(), this->users.end(), @@ -44,6 +45,7 @@ void IrcChannel::remove_user(const IrcUser* user) }); if (it != this->users.end()) { + result = std::move(*it); this->users.erase(it); if (is_self) { @@ -57,4 +59,5 @@ void IrcChannel::remove_all_users() { this->users.clear(); this->self = nullptr; + return result; } diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index dff1b78..ee89209 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -32,8 +32,8 @@ public: IrcUser* add_user(const std::string& name, const std::map& prefix_to_mode); IrcUser* find_user(const std::string& name) const; - void remove_user(const IrcUser* user); void remove_all_users(); + std::unique_ptr remove_user(const IrcUser* user); const std::vector>& get_users() const { return this->users; } diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index a866726..c5ef36c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -951,18 +951,18 @@ void IrcClient::on_part(const IrcMessage& message) { std::string nick = user->nick; bool self = channel->get_self() && channel->get_self()->nick == nick; - channel->remove_user(user); - Iid iid; - iid.set_local(chan_name); - iid.set_server(this->hostname); - iid.type = Iid::Type::Channel; + auto user_ptr = channel->remove_user(user); if (self) { this->channels.erase(utils::tolower(chan_name)); // channel pointer is now invalid channel = nullptr; } - this->bridge.send_muc_leave(iid, std::move(nick), txt, self, true); + Iid iid; + iid.set_local(chan_name); + iid.set_server(this->hostname); + iid.type = Iid::Type::Channel; + this->bridge.send_muc_leave(iid, *user_ptr, txt, self, true); } } @@ -979,8 +979,7 @@ void IrcClient::on_error(const IrcMessage& message) IrcChannel* channel = pair.second.get(); if (!channel->joined) continue; - std::string own_nick = channel->get_self()->nick; - this->bridge.send_muc_leave(iid, std::move(own_nick), leave_message, true, false); + this->bridge.send_muc_leave(iid, *channel->get_self(), leave_message, true, false); } this->channels.clear(); this->send_gateway_message("ERROR: " + leave_message); @@ -1005,7 +1004,7 @@ void IrcClient::on_quit(const IrcMessage& message) iid.set_local(chan_name); iid.set_server(this->hostname); iid.type = Iid::Type::Channel; - this->bridge.send_muc_leave(iid, user->nick, txt, self, false); + this->bridge.send_muc_leave(iid, *user, txt, self, false); channel->remove_user(user); } } -- cgit v1.2.3 From bb476f4a0d60bbc41393a86a370aa94ab405b081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 01:00:17 +0100 Subject: Allow to override the addresses used to connect to an IRC network fix #3273 --- src/irc/irc_client.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index c5ef36c..764f37b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -186,20 +186,22 @@ 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 " + - this->hostname + ":" + port + " (" + - (tls ? "encrypted" : "not encrypted") + ")"); - this->bind_addr = Config::get("outgoing_bind", ""); + std::string address = this->hostname; -#ifdef BOTAN_FOUND -# ifdef USE_DATABASE +#ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); +# ifdef BOTAN_FOUND this->credential_manager.set_trusted_fingerprint(options.col()); # endif + if (!options.col().empty()) + address = options.col(); #endif - this->connect(this->hostname, port, tls); + this->bridge.send_xmpp_message(this->hostname, "", "Connecting to " + + address + ":" + port + " (" + + (tls ? "encrypted" : "not encrypted") + ")"); + this->connect(address, port, tls); } void IrcClient::on_connection_failed(const std::string& reason) -- cgit v1.2.3 From 06438fe8ecf5eea62456e6da41c13bad916664fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 01:34:10 +0100 Subject: Remove an unused function --- src/irc/irc_channel.cpp | 6 ------ src/irc/irc_channel.hpp | 1 - 2 files changed, 7 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 58f8d5c..2dd20fe 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -53,11 +53,5 @@ std::unique_ptr IrcChannel::remove_user(const IrcUser* user) this->joined = false; } } -} - -void IrcChannel::remove_all_users() -{ - this->users.clear(); - this->self = nullptr; return result; } diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index ee89209..7000ada 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -32,7 +32,6 @@ public: IrcUser* add_user(const std::string& name, const std::map& prefix_to_mode); IrcUser* find_user(const std::string& name) const; - void remove_all_users(); std::unique_ptr remove_user(const IrcUser* user); const std::vector>& get_users() const { return this->users; } -- cgit v1.2.3 From 577984faf2befaa7f11a1e4a115dc8d80805fec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 18 Mar 2018 02:31:18 +0100 Subject: Allow the execution of multiple commands after the IRC connection fix #3275 --- 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 764f37b..5f93ea6 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -889,8 +889,9 @@ void IrcClient::on_welcome_message(const IrcMessage& message) #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); - if (!options.col().empty()) - this->send_raw(options.col()); + const auto commands = Database::get_after_connection_commands(options); + for (const auto& command: commands) + this->send_raw(command.col()); #endif // Install a repeated events to regularly send a PING TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this), -- cgit v1.2.3 From faa33c1a712f98de4bafee821bde7eb270bbb7f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 22 Mar 2018 20:44:30 +0100 Subject: Pass an IrcClient* to send_muc_leave instead of doing an other search --- src/irc/irc_client.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 5f93ea6..8f77e0d 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -965,7 +965,7 @@ void IrcClient::on_part(const IrcMessage& message) iid.set_local(chan_name); iid.set_server(this->hostname); iid.type = Iid::Type::Channel; - this->bridge.send_muc_leave(iid, *user_ptr, txt, self, true); + this->bridge.send_muc_leave(iid, *user_ptr, txt, self, true, {}, this); } } @@ -982,7 +982,7 @@ void IrcClient::on_error(const IrcMessage& message) IrcChannel* channel = pair.second.get(); if (!channel->joined) continue; - this->bridge.send_muc_leave(iid, *channel->get_self(), leave_message, true, false); + this->bridge.send_muc_leave(iid, *channel->get_self(), leave_message, true, false, {}, this); } this->channels.clear(); this->send_gateway_message("ERROR: " + leave_message); @@ -1007,7 +1007,7 @@ void IrcClient::on_quit(const IrcMessage& message) iid.set_local(chan_name); iid.set_server(this->hostname); iid.type = Iid::Type::Channel; - this->bridge.send_muc_leave(iid, *user, txt, self, false); + this->bridge.send_muc_leave(iid, *user, txt, self, false, {}, this); channel->remove_user(user); } } -- cgit v1.2.3 From 4f6bf078d2e60cab47f43a09decc12aa4fba08ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 15 May 2018 19:29:37 +0200 Subject: Improve the forward_server_message to concatenate everything --- 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 8f77e0d..fca043c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -536,7 +536,9 @@ void IrcClient::send_ping_command() void IrcClient::forward_server_message(const IrcMessage& message) { const std::string from = message.prefix; - const std::string body = message.arguments[1]; + std::string body; + for (auto it = std::next(message.arguments.begin()); it != message.arguments.end(); ++it) + body += *it + ' '; this->bridge.send_xmpp_message(this->hostname, from, body); } -- cgit v1.2.3 From a8e922fc890a8ef2c1c43b940f0cfc3768ea1cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 15 May 2018 19:31:26 +0200 Subject: Handle the NAMES message for an already-joined or non-existing channel If a user manually does a NAMES query, the result were interpreted as a user list, which is wrong. And with the special * argument, this would even cause a crash. Fix #3357 --- src/irc/irc_client.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index fca043c..d0b2153 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -641,6 +641,11 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[2]); IrcChannel* channel = this->get_channel(chan_name); + if (channel->joined) + { + this->forward_server_message(message); + return; + } std::vector nicks = utils::split(message.arguments[3], ' '); for (const std::string& nick: nicks) { @@ -776,6 +781,16 @@ 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); + if (chan_name == "*" || channel->joined) + { + this->forward_server_message(message); + return; + } + if (!channel->get_self()) + { + log_error("End of NAMES list but we never received our own nick."); + return; + } 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 7d3c1ed92733a05ab4282993ffe58fb88a1b50e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 23 May 2018 01:09:19 +0200 Subject: Do not use (or present to the user) the Address field in fixed mode fix #3359 --- 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 d0b2153..d7fa2cd 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -195,7 +195,8 @@ void IrcClient::start() # ifdef BOTAN_FOUND this->credential_manager.set_trusted_fingerprint(options.col()); # endif - if (!options.col().empty()) + if (Config::get("fixed_irc_server", "").empty() && + !options.col().empty()) address = options.col(); #endif this->bridge.send_xmpp_message(this->hostname, "", "Connecting to " + -- cgit v1.2.3 From 2f0e26db4cd91037463e5aa45c7538a942a9eee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 17 Jun 2018 15:16:49 +0200 Subject: =?UTF-8?q?Channels=E2=80=99=20disco#info=20includes=20the=20numbe?= =?UTF-8?q?r=20of=20participants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix #3311 --- src/irc/irc_client.cpp | 14 +++++++++++++- src/irc/irc_client.hpp | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d7fa2cd..0f3d43c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -317,9 +317,21 @@ IrcChannel* IrcClient::get_channel(const std::string& n) } catch (const std::out_of_range& exception) { - this->channels.emplace(name, std::make_unique()); + return this->channels.emplace(name, std::make_unique()).first->second.get(); + } +} + +const IrcChannel* IrcClient::find_channel(const std::string& n) const +{ + const std::string name = utils::tolower(n); + try + { return this->channels.at(name).get(); } + catch (const std::out_of_range& exception) + { + return nullptr; + } } bool IrcClient::is_channel_joined(const std::string& name) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index fd97fe6..70046be 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -67,6 +67,10 @@ public: * Return the channel with this name, create it if it does not yet exist */ IrcChannel* get_channel(const std::string& name); + /** + * Return the channel with this name. Nullptr if it is not found + */ + const IrcChannel* find_channel(const std::string& name) const; /** * Returns true if the channel is joined */ -- cgit v1.2.3 From 0b8738d87aa101117c7681ade41f8527ad515d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 22 Jun 2018 21:33:58 +0200 Subject: Archive the Mode messages, except if they are received for an unjoined chan fix #3362 --- 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 0f3d43c..96fb4ef 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1154,7 +1154,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message) } this->bridge.send_message(iid, "", "Mode " + iid.get_local() + " [" + mode_arguments + "] by " + user.nick, - true); + true, this->is_channel_joined(iid.get_local())); const IrcChannel* channel = this->get_channel(iid.get_local()); if (!channel) return; -- cgit v1.2.3 From ba97c442a8be70da6bacd7ef0461fe95e99fe765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 22 Jun 2018 21:35:16 +0200 Subject: Remove an outdated TODO comment --- src/irc/irc_client.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 96fb4ef..d5f872b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1135,8 +1135,6 @@ void IrcClient::on_channel_bad_key(const IrcMessage& 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.set_local(message.arguments[0]); iid.set_server(this->hostname); -- cgit v1.2.3 From 09b10cc80146c1ac2a0d5c53c6c8469b934189f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 25 Jun 2018 22:54:32 +0200 Subject: Throttle all commands sent to IRC servers fix #3354 --- src/irc/irc_client.cpp | 63 ++++++++++++++++++++++++++++++++----------------- src/irc/irc_client.hpp | 12 ++++++++-- src/irc/irc_message.hpp | 4 ++-- 3 files changed, 54 insertions(+), 25 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d5f872b..5a2f09b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -135,7 +135,7 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, std::string realname, std::string user_hostname, Bridge& bridge): TCPClientSocketHandler(poller), - hostname(std::move(hostname)), + hostname(hostname), user_hostname(std::move(user_hostname)), username(std::move(username)), realname(std::move(realname)), @@ -143,7 +143,14 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, bridge(bridge), welcomed(false), chanmodes({"", "", "", ""}), - chantypes({'#', '&'}) + chantypes({'#', '&'}), + tokens_bucket(Database::get_irc_server_options(bridge.get_bare_jid(), hostname).col(), 1s, [this]() { + if (message_queue.empty()) + return true; + this->actual_send(std::move(this->message_queue.front())); + this->message_queue.pop_front(); + return false; + }, "TokensBucket" + this->hostname + this->bridge.get_jid()) { #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), @@ -171,6 +178,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" + this->hostname + this->bridge.get_jid()); + TimedEventsManager::instance().cancel("TokensBucket" + this->hostname + this->bridge.get_jid()); } void IrcClient::start() @@ -390,25 +398,33 @@ void IrcClient::parse_in_buffer(const size_t) } } -void IrcClient::send_message(IrcMessage&& message) +void IrcClient::actual_send(const IrcMessage& message) { - log_debug("IRC SENDING: (", this->get_hostname(), ") ", message); - std::string res; - if (!message.prefix.empty()) - res += ":" + std::move(message.prefix) + " "; - res += message.command; - for (const std::string& arg: message.arguments) - { - if (arg.find(' ') != std::string::npos || - (!arg.empty() && arg[0] == ':')) - { - res += " :" + arg; - break; - } - res += " " + arg; - } - res += "\r\n"; - this->send_data(std::move(res)); + log_debug("IRC SENDING: (", this->get_hostname(), ") ", message); + std::string res; + if (!message.prefix.empty()) + res += ":" + message.prefix + " "; + res += message.command; + for (const std::string& arg: message.arguments) + { + if (arg.find(' ') != std::string::npos + || (!arg.empty() && arg[0] == ':')) + { + res += " :" + arg; + break; + } + res += " " + arg; + } + res += "\r\n"; + this->send_data(std::move(res)); + } + +void IrcClient::send_message(IrcMessage message, bool throttle) +{ + if (this->tokens_bucket.use_token() || !throttle) + this->actual_send(message); + else + message_queue.push_back(std::move(message)); } void IrcClient::send_raw(const std::string& txt) @@ -459,7 +475,7 @@ void IrcClient::send_topic_command(const std::string& chan_name, const std::stri void IrcClient::send_quit_command(const std::string& reason) { - this->send_message(IrcMessage("QUIT", {reason})); + this->send_message(IrcMessage("QUIT", {reason}), false); } void IrcClient::send_join_command(const std::string& chan_name, const std::string& password) @@ -1225,6 +1241,11 @@ void IrcClient::on_channel_mode(const IrcMessage& message) } } +void IrcClient::set_throttle_limit(std::size_t limit) +{ + this->tokens_bucket.set_limit(limit); +} + void IrcClient::on_user_mode(const IrcMessage& message) { this->bridge.send_xmpp_message(this->hostname, "", diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 70046be..ac5ccb0 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -16,8 +16,10 @@ #include #include #include +#include #include #include +#include class Bridge; @@ -84,8 +86,9 @@ public: * (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); + void send_message(IrcMessage message, bool throttle=true); void send_raw(const std::string& txt); + void actual_send(const IrcMessage& message); /** * Send the PONG irc command */ @@ -293,7 +296,7 @@ public: const std::vector& get_sorted_user_modes() const { return this->sorted_user_modes; } std::set get_chantypes() const { return this->chantypes; } - + void set_throttle_limit(std::size_t limit); /** * Store the history limit that the client asked when joining this room. */ @@ -330,6 +333,10 @@ private: * To communicate back with the bridge */ Bridge& bridge; + /** + * Where messaged are stored when they are throttled. + */ + std::deque message_queue{}; /** * The list of joined channels, indexed by name */ @@ -389,6 +396,7 @@ private: * the WebIRC protocole. */ Resolver dns_resolver; + TokensBucket tokens_bucket; }; diff --git a/src/irc/irc_message.hpp b/src/irc/irc_message.hpp index fe954e4..269a12a 100644 --- a/src/irc/irc_message.hpp +++ b/src/irc/irc_message.hpp @@ -14,9 +14,9 @@ public: ~IrcMessage() = default; IrcMessage(const IrcMessage&) = delete; - IrcMessage(IrcMessage&&) = delete; + IrcMessage(IrcMessage&&) = default; IrcMessage& operator=(const IrcMessage&) = delete; - IrcMessage& operator=(IrcMessage&&) = delete; + IrcMessage& operator=(IrcMessage&&) = default; std::string prefix; std::string command; -- cgit v1.2.3 From 52166e07acd785b39c0da98be4c35e886b75c3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 25 Jun 2018 22:57:13 +0200 Subject: Trivial syntax improvements --- 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 5a2f09b..b89ab1c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -480,7 +480,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) + if (!this->welcomed) { const auto it = std::find_if(begin(this->channels_to_join), end(this->channels_to_join), [&chan_name](const auto& pair) { return std::get<0>(pair) == chan_name; }); @@ -497,7 +497,7 @@ void IrcClient::send_join_command(const std::string& chan_name, const std::strin bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) { IrcChannel* channel = this->get_channel(chan_name); - if (channel->joined == false) + if (!channel->joined) { log_warning("Cannot send message to channel ", chan_name, ", it is not joined"); return false; -- cgit v1.2.3 From 0d886d5f32dda3be5827ed2c84f9bf2806b69601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 26 Jun 2018 20:42:21 +0200 Subject: Default the throttle limit to 10 if not built with database support --- src/irc/irc_client.cpp | 11 ++++++++++- src/irc/irc_client.hpp | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index b89ab1c..fee6517 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -144,7 +144,7 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, welcomed(false), chanmodes({"", "", "", ""}), chantypes({'#', '&'}), - tokens_bucket(Database::get_irc_server_options(bridge.get_bare_jid(), hostname).col(), 1s, [this]() { + tokens_bucket(this->get_throttle_limit(), 1s, [this]() { if (message_queue.empty()) return true; this->actual_send(std::move(this->message_queue.front())); @@ -1283,3 +1283,12 @@ bool IrcClient::abort_on_invalid_cert() const return true; } #endif + +std::size_t IrcClient::get_throttle_limit() const +{ +#ifdef USE_DATABASE + return Database::get_irc_server_options(this->bridge.get_bare_jid(), this->hostname).col(); +#else + return 10; +#endif +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index ac5ccb0..8c5c0c8 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -397,6 +397,7 @@ private: */ Resolver dns_resolver; TokensBucket tokens_bucket; + std::size_t get_throttle_limit() const; }; -- cgit v1.2.3 From 7a4cea426d0a07d577753ee008416e19eca6260d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 24 Jul 2018 23:14:35 +0200 Subject: Reflect messages to XMPP only when they are actually sent --- src/irc/irc_client.cpp | 21 ++++++++++++++------- src/irc/irc_client.hpp | 13 +++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'src/irc') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index fee6517..78d0fbf 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -398,8 +398,10 @@ void IrcClient::parse_in_buffer(const size_t) } } -void IrcClient::actual_send(const IrcMessage& message) +void IrcClient::actual_send(std::pair message_pair) { + const IrcMessage& message = message_pair.first; + const MessageCallback& callback = message_pair.second; log_debug("IRC SENDING: (", this->get_hostname(), ") ", message); std::string res; if (!message.prefix.empty()) @@ -417,14 +419,18 @@ void IrcClient::actual_send(const IrcMessage& message) } res += "\r\n"; this->send_data(std::move(res)); + + if (callback) + callback(this, message); } -void IrcClient::send_message(IrcMessage message, bool throttle) +void IrcClient::send_message(IrcMessage message, MessageCallback callback, bool throttle) { + auto message_pair = std::make_pair(std::move(message), std::move(callback)); if (this->tokens_bucket.use_token() || !throttle) - this->actual_send(message); + this->actual_send(std::move(message_pair)); else - message_queue.push_back(std::move(message)); + message_queue.push_back(std::move(message_pair)); } void IrcClient::send_raw(const std::string& txt) @@ -475,7 +481,7 @@ void IrcClient::send_topic_command(const std::string& chan_name, const std::stri void IrcClient::send_quit_command(const std::string& reason) { - this->send_message(IrcMessage("QUIT", {reason}), false); + this->send_message(IrcMessage("QUIT", {reason}), {}, false); } void IrcClient::send_join_command(const std::string& chan_name, const std::string& password) @@ -494,7 +500,8 @@ void IrcClient::send_join_command(const std::string& chan_name, const std::strin this->start(); } -bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) +bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body, + MessageCallback callback) { IrcChannel* channel = this->get_channel(chan_name); if (!channel->joined) @@ -517,7 +524,7 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st ::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})); + this->send_message(IrcMessage("PRIVMSG", {chan_name, line}), callback); return true; } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 8c5c0c8..aa314f8 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -21,6 +21,10 @@ #include #include +class IrcClient; + +using MessageCallback = std::function; + class Bridge; /** @@ -86,9 +90,9 @@ public: * (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, bool throttle=true); + void send_message(IrcMessage message, MessageCallback callback={}, bool throttle=true); void send_raw(const std::string& txt); - void actual_send(const IrcMessage& message); + void actual_send(std::pair message_pair); /** * Send the PONG irc command */ @@ -117,7 +121,8 @@ public: * 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); + bool send_channel_message(const std::string& chan_name, const std::string& body, + MessageCallback callback); /** * Send a PRIVMSG command for an user */ @@ -336,7 +341,7 @@ private: /** * Where messaged are stored when they are throttled. */ - std::deque message_queue{}; + std::deque> message_queue{}; /** * The list of joined channels, indexed by name */ -- cgit v1.2.3 From 7d0df9b6ddee8db69ea0a511f031f32a4537a749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Aug 2018 15:21:12 +0200 Subject: Disable the throttle limit if negative Also, invalid values result in -1 being set --- 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 78d0fbf..2835a33 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1291,7 +1291,7 @@ bool IrcClient::abort_on_invalid_cert() const } #endif -std::size_t IrcClient::get_throttle_limit() const +long int IrcClient::get_throttle_limit() const { #ifdef USE_DATABASE return Database::get_irc_server_options(this->bridge.get_bare_jid(), this->hostname).col(); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index aa314f8..1653225 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -402,7 +402,7 @@ private: */ Resolver dns_resolver; TokensBucket tokens_bucket; - std::size_t get_throttle_limit() const; + long int get_throttle_limit() const; }; -- cgit v1.2.3 From a3e865ad63a1c0d634001d9d2e86c425bc5094e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Aug 2018 23:58:32 +0200 Subject: Fix a signed/unsigned mismatch --- 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 2835a33..0b5715e 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1248,7 +1248,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message) } } -void IrcClient::set_throttle_limit(std::size_t limit) +void IrcClient::set_throttle_limit(long int limit) { this->tokens_bucket.set_limit(limit); } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 1653225..416eb30 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -301,7 +301,7 @@ public: const std::vector& get_sorted_user_modes() const { return this->sorted_user_modes; } std::set get_chantypes() const { return this->chantypes; } - void set_throttle_limit(std::size_t limit); + void set_throttle_limit(long int limit); /** * Store the history limit that the client asked when joining this room. */ -- cgit v1.2.3 From 478619b10a27f7a25ba0b1082f4b12981b29d546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 26 Aug 2018 15:42:38 +0200 Subject: Trivial little syntax changes --- 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 416eb30..674f3ff 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -34,7 +34,7 @@ class Bridge; class IrcClient: public TCPClientSocketHandler { public: - explicit IrcClient(std::shared_ptr& poller, std::string hostname, + explicit IrcClient(std::shared_ptr& poller, std::string hostname, std::string nickname, std::string username, std::string realname, std::string user_hostname, Bridge& bridge); -- cgit v1.2.3