From 5475d16b574e1daf9c1e5f94b5b821bfb1b9c8f8 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 11 May 2015 04:47:31 +0200 Subject: Return a stanza error whenever the IRCClient for a given server does not exist Instead of ignoring the stanza, we send back an error of type remote-server-not-found each time it's possible. Also avoid having to do if (!irc) return; everytime. fix #3045 --- src/bridge/bridge.cpp | 71 +++++++++++++++++++----------------------- src/bridge/bridge.hpp | 16 ++++++++-- src/xmpp/biboumi_component.cpp | 20 ++++++++++++ 3 files changed, 66 insertions(+), 41 deletions(-) diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 45cdc01..16264d4 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -99,6 +99,18 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string } IrcClient* Bridge::get_irc_client(const std::string& hostname) +{ + try + { + return this->irc_clients.at(hostname).get(); + } + catch (const std::out_of_range& exception) + { + throw IRCNotConnected(hostname); + } +} + +IrcClient* Bridge::find_irc_client(const std::string& hostname) { try { @@ -145,17 +157,17 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username, const void Bridge::send_channel_message(const Iid& iid, const std::string& body) { - if (iid.get_local().empty() || iid.get_server().empty()) + if (iid.get_server().empty()) { - log_warning("Cannot send message to channel: [" << iid.get_local() << "] on server [" << iid.get_server() << "]"); + this->xmpp->send_stanza_error("message", this->user_jid, std::to_string(iid), "", + "cancel", "remote-server-not-found", + std::to_string(iid) + " is not a valid channel name. " + "A correct room jid is of the form: #%", + false); return; } IrcClient* irc = this->get_irc_client(iid.get_server()); - if (!irc) - { - log_warning("Cannot send message: no client exist for server " << iid.get_server()); - return; - } + // Because an IRC message cannot contain \n, we need to convert each line // of text into a separate IRC message. For conveniance, we also cut the // message into submessages on the XMPP side, this way the user of the @@ -190,8 +202,6 @@ void Bridge::forward_affiliation_role_change(const Iid& iid, const std::string& const std::string& role) { IrcClient* irc = this->get_irc_client(iid.get_server()); - if (!irc) - return; IrcChannel* chan = irc->get_channel(iid.get_local()); if (!chan || !chan->joined) return; @@ -254,13 +264,15 @@ void Bridge::forward_affiliation_role_change(const Iid& iid, const std::string& void Bridge::send_private_message(const Iid& iid, const std::string& body, const std::string& type) { if (iid.get_local().empty() || iid.get_server().empty()) - return ; - IrcClient* irc = this->get_irc_client(iid.get_server()); - if (!irc) { - log_warning("Cannot send message: no client exist for server " << iid.get_server()); + this->xmpp->send_stanza_error("message", this->user_jid, std::to_string(iid), "", + "cancel", "remote-server-not-found", + std::to_string(iid) + " is not a valid channel name. " + "A correct room jid is of the form: #%", + false); return; } + IrcClient* irc = this->get_irc_client(iid.get_server()); std::vector lines = utils::split(body, '\n', true); if (lines.empty()) return ; @@ -276,26 +288,19 @@ void Bridge::send_private_message(const Iid& iid, const std::string& body, const void Bridge::send_raw_message(const std::string& hostname, const std::string& body) { IrcClient* irc = this->get_irc_client(hostname); - if (!irc) - { - log_warning("Cannot send message: no client exist for server " << hostname); - return ; - } irc->send_raw(body); } void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) { IrcClient* irc = this->get_irc_client(iid.get_server()); - if (irc) - irc->send_part_command(iid.get_local(), status_message); + irc->send_part_command(iid.get_local(), status_message); } void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick) { IrcClient* irc = this->get_irc_client(iid.get_server()); - if (irc) - irc->send_nick_command(new_nick); + irc->send_nick_command(new_nick); } void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq_id, @@ -303,10 +308,8 @@ void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq { IrcClient* irc = this->get_irc_client(iid.get_server()); - if (!irc) - return; - irc->send_list_command(); + irc_responder_callback_t cb = [this, iid, iq_id, to_jid](const std::string& irc_hostname, const IrcMessage& message) -> bool { @@ -340,9 +343,6 @@ void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std: { IrcClient* irc = this->get_irc_client(iid.get_server()); - if (!irc) - return; - irc->send_kick_command(iid.get_local(), target, reason); irc_responder_callback_t cb = [this, target, iq_id, to_jid, iid](const std::string& irc_hostname, const IrcMessage& message) -> bool @@ -387,8 +387,7 @@ void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std: void Bridge::set_channel_topic(const Iid& iid, const std::string& subject) { IrcClient* irc = this->get_irc_client(iid.get_server()); - if (irc) - irc->send_topic_command(iid.get_local(), subject); + irc->send_topic_command(iid.get_local(), subject); } void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, const std::string& os) @@ -447,12 +446,6 @@ void Bridge::send_irc_participant_ping_request(const Iid& iid, const std::string const std::string& from_jid) { IrcClient* irc = this->get_irc_client(iid.get_server()); - if (!irc) - { - this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found", - "Not connected to IRC server"s + iid.get_server(), true); - return; - } IrcChannel* chan = irc->get_channel(iid.get_local()); if (!chan->joined) { @@ -475,7 +468,7 @@ void Bridge::on_gateway_ping(const std::string& irc_hostname, const std::string& const std::string& from_jid) { Jid jid(from_jid); - if (irc_hostname.empty() || this->get_irc_client(irc_hostname)) + if (irc_hostname.empty() || this->find_irc_client(irc_hostname)) this->xmpp->send_iq_result(iq_id, to_jid, jid.local); else this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "service-unavailable", @@ -548,7 +541,7 @@ void Bridge::send_presence_error(const Iid& iid, const std::string& nick, void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self) { this->xmpp->send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message), this->user_jid, self); - IrcClient* irc = this->get_irc_client(iid.get_server()); + IrcClient* irc = this->find_irc_client(iid.get_server()); if (irc && irc->number_of_joined_channels() == 0) irc->send_quit_command(""); } @@ -603,7 +596,7 @@ void Bridge::send_topic(const std::string& hostname, const std::string& chan_nam std::string Bridge::get_own_nick(const Iid& iid) { - IrcClient* irc = this->get_irc_client(iid.get_server()); + IrcClient* irc = this->find_irc_client(iid.get_server()); if (irc) return irc->get_own_nick(); return ""; diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index cc9d042..72a8e90 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -193,10 +194,14 @@ private: */ IrcClient* get_irc_client(const std::string& hostname, const std::string& username); /** - * This version does not create the IrcClient if it does not exist, and - * returns nullptr in that case + * This version does not create the IrcClient if it does not exist, throws + * a IRCServerNotConnected error in that case. */ IrcClient* get_irc_client(const std::string& hostname); + /** + * Idem, but returns nullptr if the server does not exist. + */ + IrcClient* find_irc_client(const std::string& hostname); /** * The JID of the user associated with this bridge. Messages from/to this * JID are only managed by this bridge. @@ -240,4 +245,11 @@ private: Bridge& operator=(Bridge&&) = delete; }; +struct IRCNotConnected: public std::exception +{ + IRCNotConnected(const std::string& hostname): + hostname(hostname) {} + const std::string hostname; +}; + #endif // BRIDGE_INCLUDED diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 37383a8..4996438 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -166,6 +166,8 @@ void BiboumiComponent::handle_message(const Stanza& stanza) error_type, error_name, ""); }); XmlNode* body = stanza.get_child("body", COMPONENT_NS); + + try { // catch IRCNotConnected exceptions if (type == "groupchat" && iid.is_channel) { if (body && !body->get_inner().empty()) @@ -220,6 +222,13 @@ void BiboumiComponent::handle_message(const Stanza& stanza) } else if (iid.is_user) this->send_invalid_user_error(to.local, from); + } catch (const IRCNotConnected& ex) + { + this->send_stanza_error("message", from, to_str, id, + "cancel", "remote-server-not-found", + "Not connected to IRC server "s + ex.hostname, + true); + } stanza_error.disable(); } @@ -262,6 +271,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) this->send_stanza_error("iq", from, to_str, id, error_type, error_name, ""); }); + try { if (type == "set") { XmlNode* query; @@ -412,6 +422,16 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) } } } + } + catch (const IRCNotConnected& ex) + { + this->send_stanza_error("iq", from, to_str, id, + "cancel", "remote-server-not-found", + "Not connected to IRC server "s + ex.hostname, + true); + stanza_error.disable(); + return; + } error_type = "cancel"; error_name = "feature-not-implemented"; } -- cgit v1.2.3