diff options
Diffstat (limited to 'src/bridge')
-rw-r--r-- | src/bridge/bridge.cpp | 98 | ||||
-rw-r--r-- | src/bridge/bridge.hpp | 13 |
2 files changed, 49 insertions, 62 deletions
diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 54bee84..1c646fe 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -5,6 +5,7 @@ #include <utils/empty_if_fixed_server.hpp> #include <utils/encoding.hpp> #include <utils/tolower.hpp> +#include <utils/uuid.hpp> #include <logger/logger.hpp> #include <utils/revstr.hpp> #include <utils/split.hpp> @@ -63,7 +64,6 @@ void Bridge::shutdown(const std::string& exit_message) for (auto& pair: this->irc_clients) { pair.second->send_quit_command(exit_message); - pair.second->leave_dummy_channel(exit_message, {}); } } @@ -103,7 +103,7 @@ const std::string& Bridge::get_jid() const std::string Bridge::get_bare_jid() const { Jid jid(this->user_jid); - return jid.local + "@" + jid.domain; + return jid.bare(); } Xmpp::body Bridge::make_xmpp_body(const std::string& str, const std::string& encoding) @@ -166,56 +166,36 @@ IrcClient* Bridge::find_irc_client(const std::string& hostname) const } } -bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, - const std::string& resource, HistoryLimit history_limit) +bool Bridge::join_irc_channel(const Iid& iid, std::string nickname, + const std::string& password, + const std::string& resource, + HistoryLimit history_limit, + const bool force_join) { const auto& hostname = iid.get_server(); +#ifdef USE_DATABASE + auto soptions = Database::get_irc_server_options(this->get_bare_jid(), hostname); + if (!soptions.col<Database::Nick>().empty()) + nickname = soptions.col<Database::Nick>(); +#endif IrcClient* irc = this->make_irc_client(hostname, nickname); irc->history_limit = history_limit; this->add_resource_to_server(hostname, resource); auto res_in_chan = this->is_resource_in_chan(ChannelKey{iid.get_local(), hostname}, resource); if (!res_in_chan) this->add_resource_to_chan(ChannelKey{iid.get_local(), hostname}, resource); - if (iid.get_local().empty()) - { // Join the dummy channel - if (irc->is_welcomed()) - { - if (res_in_chan) - return false; - // Immediately simulate a message coming from the IRC server saying that we - // joined the channel - if (irc->get_dummy_channel().joined) - { - this->generate_channel_join_for_resource(iid, resource); - } - else - { - const IrcMessage join_message(irc->get_nick(), "JOIN", {""}); - irc->on_channel_join(join_message); - const IrcMessage end_join_message(std::string(iid.get_server()), "366", - {irc->get_nick(), - "", "End of NAMES list"}); - irc->on_channel_completely_joined(end_join_message); - } - } - else - { - irc->get_dummy_channel().joining = true; - irc->start(); - } - return true; - } if (irc->is_channel_joined(iid.get_local()) == false) { irc->send_join_command(iid.get_local(), password); return true; - } else if (!res_in_chan) { + } else if (!res_in_chan || force_join) { + // See https://github.com/xsf/xeps/pull/499 for the force_join argument this->generate_channel_join_for_resource(iid, resource); } return false; } -void Bridge::send_channel_message(const Iid& iid, const std::string& body) +void Bridge::send_channel_message(const Iid& iid, const std::string& body, std::string id) { if (iid.get_server().empty()) { @@ -240,6 +220,7 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) std::vector<std::string> lines = utils::split(body, '\n', true); if (lines.empty()) return ; + bool first = true; for (const std::string& line: lines) { if (line.substr(0, 5) == "/mode") @@ -261,9 +242,12 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), std::get<0>(xmpp_body), irc->get_own_nick()); #endif + if (!first || id.empty()) + id = utils::gen_uuid(); for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) this->xmpp.send_muc_message(std::to_string(iid), irc->get_own_nick(), this->make_xmpp_body(line), - this->user_jid + "/" + resource, uuid); + this->user_jid + "/" + resource, uuid, id); + first = false; } } @@ -445,15 +429,11 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con #endif if (channel->joined && !channel->parting && !persistent) { - const auto& chan_name = iid.get_local(); - if (chan_name.empty()) - irc->leave_dummy_channel(status_message, resource); - else - irc->send_part_command(iid.get_local(), status_message); + irc->send_part_command(iid.get_local(), status_message); } else if (channel->joined) { - this->send_muc_leave(iid, channel->get_self()->nick, "", true, true, resource); + this->send_muc_leave(iid, *channel->get_self(), "", true, true, resource, irc); } if (persistent) this->remove_resource_from_chan(key, resource); @@ -464,9 +444,9 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con else { if (channel && channel->joined) - this->send_muc_leave(iid, channel->get_self()->nick, + this->send_muc_leave(iid, *channel->get_self(), "Biboumi note: " + std::to_string(resources - 1) + " resources are still in this channel.", - true, true, resource); + true, true, resource, irc); this->remove_resource_from_chan(key, resource); } if (this->number_of_channels_the_resource_is_in(iid.get_server(), resource) == 0) @@ -839,19 +819,19 @@ void Bridge::send_irc_version_request(const std::string& irc_hostname, const std void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { const auto encoding = in_encoding_for(*this, iid); + std::string uuid{}; if (muc) { #ifdef USE_DATABASE const auto xmpp_body = this->make_xmpp_body(body, encoding); if (!nick.empty() && this->record_history) - Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), - std::get<0>(xmpp_body), nick); + uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), + std::get<0>(xmpp_body), nick); #endif for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) { this->xmpp.send_muc_message(std::to_string(iid), nick, this->make_xmpp_body(body, encoding), - this->user_jid + "/" + resource, {}); - + this->user_jid + "/" + resource, uuid, utils::gen_uuid()); } } else @@ -881,19 +861,24 @@ void Bridge::send_presence_error(const Iid& iid, const std::string& nick, this->xmpp.send_presence_error(std::to_string(iid), nick, this->user_jid, type, condition, error_code, text); } -void Bridge::send_muc_leave(const Iid& iid, const std::string& nick, +void Bridge::send_muc_leave(const Iid& iid, const IrcUser& user, const std::string& message, const bool self, const bool user_requested, - const std::string& resource) + const std::string& resource, + const IrcClient* client) { + std::string affiliation; + std::string role; + std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user.get_most_significant_mode(client->get_sorted_user_modes())); + if (!resource.empty()) - this->xmpp.send_muc_leave(std::to_string(iid), nick, this->make_xmpp_body(message), - this->user_jid + "/" + resource, self, user_requested); + this->xmpp.send_muc_leave(std::to_string(iid), user.nick, this->make_xmpp_body(message), + this->user_jid + "/" + resource, self, user_requested, affiliation, role); else { for (const auto &res: this->resources_in_chan[iid.to_tuple()]) - this->xmpp.send_muc_leave(std::to_string(iid), nick, this->make_xmpp_body(message), - this->user_jid + "/" + res, self, user_requested); + this->xmpp.send_muc_leave(std::to_string(iid), user.nick, this->make_xmpp_body(message), + this->user_jid + "/" + res, self, user_requested, affiliation, role); if (self) { // Copy the resources currently in that channel @@ -1020,7 +1005,7 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam auto limit = coptions.col<Database::MaxHistoryLength>(); if (history_limit.stanzas >= 0 && history_limit.stanzas < limit) limit = history_limit.stanzas; - const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since); + const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, Id::unset_value, Database::Paging::last); chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { @@ -1254,9 +1239,6 @@ std::size_t Bridge::number_of_channels_the_resource_is_in(const std::string& irc res++; } - IrcClient* irc = this->find_irc_client(irc_hostname); - if (irc && (irc->get_dummy_channel().joined || irc->get_dummy_channel().joining)) - res++; return res; } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index c2f0233..8e7d9d7 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -75,9 +75,13 @@ public: * Try to join an irc_channel, does nothing and return true if the channel * was already joined. */ - bool join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, const std::string& resource, HistoryLimit history_limit); + bool join_irc_channel(const Iid& iid, std::string nickname, + const std::string& password, + const std::string& resource, + HistoryLimit history_limit, + const bool force_join); - void send_channel_message(const Iid& iid, const std::string& body); + void send_channel_message(const Iid& iid, const std::string& body, std::string id); void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); void send_raw_message(const std::string& hostname, const std::string& body); void leave_irc_channel(Iid&& iid, const std::string& status_message, const std::string& resource); @@ -170,10 +174,11 @@ public: /** * Send an unavailable presence from this participant */ - void send_muc_leave(const Iid& iid, const std::string& nick, + void send_muc_leave(const Iid& iid, const IrcUser& nick, const std::string& message, const bool self, const bool user_requested, - const std::string& resource=""); + const std::string& resource, + const IrcClient* client); /** * Send presences to indicate that an user old_nick (ourself if self == * true) changed his nick to new_nick. The user_mode is needed because |