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/bridge/bridge.cpp | 24 +++++++++++++++++------- src/bridge/bridge.hpp | 2 +- src/irc/irc_channel.cpp | 5 ++++- src/irc/irc_channel.hpp | 2 +- src/irc/irc_client.cpp | 17 ++++++++--------- src/xmpp/xmpp_component.cpp | 6 +++++- src/xmpp/xmpp_component.hpp | 3 ++- tests/end_to_end/__main__.py | 3 ++- 8 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index cd3492f..9269bb7 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -419,7 +419,7 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con } 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); } if (persistent) this->remove_resource_from_chan(key, resource); @@ -430,7 +430,7 @@ 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); this->remove_resource_from_chan(key, resource); @@ -847,19 +847,29 @@ 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 IrcClient* client = this->find_irc_client(iid.get_server()); + if (!client) + { + log_error("Tried to send an unavailable presence for non existant client: ", std::to_string(iid)); + return; + } + 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 diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index c2f0233..44df4c2 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -170,7 +170,7 @@ 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=""); 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); } } diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index 9be9e34..a71d810 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -425,7 +425,8 @@ void XmppComponent::send_history_message(const std::string& muc_name, const std: #endif void XmppComponent::send_muc_leave(const std::string& muc_name, const std::string& nick, Xmpp::body&& message, - const std::string& jid_to, const bool self, const bool user_requested) + const std::string& jid_to, const bool self, const bool user_requested, + const std::string& affiliation, const std::string& role) { Stanza presence("presence"); { @@ -447,6 +448,9 @@ void XmppComponent::send_muc_leave(const std::string& muc_name, const std::strin status["code"] = "332"; } } + XmlSubNode item(x, "item"); + item["affiliation"] = affiliation; + item["role"] = role; if (!message_str.empty()) { XmlSubNode status(presence, "status"); diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index 1daa6fb..06cc6ff 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -150,7 +150,8 @@ public: Xmpp::body&& message, const std::string& jid_to, const bool self, - const bool user_requested); + const bool user_requested, + const std::string& affiliation, const std::string& role); /** * Indicate that a participant changed his nick */ diff --git a/tests/end_to_end/__main__.py b/tests/end_to_end/__main__.py index f09b765..af61547 100644 --- a/tests/end_to_end/__main__.py +++ b/tests/end_to_end/__main__.py @@ -1149,7 +1149,8 @@ if __name__ == '__main__': ""), # Only user 1 receives the unavailable presence partial(expect_stanza, - "/presence[@from='#foo%{irc_server_one}/{nick_one}'][@to='{jid_one}/{resource_one}'][@type='unavailable']/muc_user:x/muc_user:status[@code='110']"), + ("/presence[@from='#foo%{irc_server_one}/{nick_one}'][@to='{jid_one}/{resource_one}'][@type='unavailable']/muc_user:x/muc_user:status[@code='110']", + "/presence/muc_user:x/muc_user:item[@affiliation='admin'][@role='moderator']")), # Second user sends a channel message partial(send_stanza, "coucou"), -- cgit v1.2.3