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/bridge/bridge.cpp | 57 +++++++++++++++++++++++++++++++ src/bridge/bridge.hpp | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 src/bridge/bridge.cpp create mode 100644 src/bridge/bridge.hpp (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp new file mode 100644 index 0000000..638777d --- /dev/null +++ b/src/bridge/bridge.cpp @@ -0,0 +1,57 @@ +#include +#include +#include + +Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller): + user_jid(user_jid), + xmpp(xmpp), + poller(poller) +{ +} + +Bridge::~Bridge() +{ +} + +IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string& username) +{ + try + { + return this->irc_clients.at(hostname).get(); + } + catch (const std::out_of_range& exception) + { + this->irc_clients.emplace(hostname, std::make_shared(hostname, username, this)); + std::shared_ptr irc = this->irc_clients.at(hostname); + this->poller->add_socket_handler(irc); + irc->start(); + return irc.get(); + } +} + +void Bridge::join_irc_channel(const Iid& iid, const std::string& username) +{ + IrcClient* irc = this->get_irc_client(iid.server, username); + irc->send_join_command(iid.chan); +} + +void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg) +{ + const std::string body = std::string("[") + author + std::string("] ") + msg; + this->xmpp->send_message(from, body, this->user_jid); +} + +void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, const std::string nick) +{ + this->xmpp->send_user_join(chan_name + "%" + hostname, nick, this->user_jid); +} + +void Bridge::send_self_join(const std::string& hostname, const std::string& chan_name, const std::string nick) +{ + this->xmpp->send_self_join(chan_name + "%" + hostname, nick, this->user_jid); +} + +void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic) +{ + this->xmpp->send_topic(chan_name + "%" + hostname, topic, this->user_jid); +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp new file mode 100644 index 0000000..f9ddcca --- /dev/null +++ b/src/bridge/bridge.hpp @@ -0,0 +1,94 @@ +#ifndef BRIDGE_INCLUDED +# define BRIDGE_INCLUDED + +#include +#include + +#include +#include +#include + +class XmppComponent; +class Poller; + +/** + * One bridge is spawned for each XMPP user that uses the component. The + * bridge spawns IrcClients when needed (when the user wants to join a + * channel on a new server) and does the translation between the two + * protocols. + */ +class Bridge +{ +public: + explicit Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller); + ~Bridge(); + + /*** + ** + ** From XMPP to IRC. + ** + **/ + + void join_irc_channel(const Iid& iid, const std::string& username); + + /*** + ** + ** From IRC to XMPP. + ** + **/ + + /** + * Send a message corresponding to a server NOTICE, the from attribute + * should be juste the server hostname@irc.component. + */ + void send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg); + /** + * Send the presence of a new user in the MUC. + */ + void send_user_join(const std::string& hostname, const std::string& chan_name, const std::string nick); + /** + * Send the self presence of an user when the MUC is fully joined. + */ + void send_self_join(const std::string& hostname, const std::string& chan_name, const std::string nick); + /** + * Send the topic of the MUC to the user + */ + void send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic); + +private: + /** + * Returns the client for the given hostname, create one (and use the + * username in this case) if none is found, and connect that newly-created + * client immediately. + */ + IrcClient* get_irc_client(const std::string& hostname, const std::string& username); + /** + * The JID of the user associated with this bridge. Messages from/to this + * JID are only managed by this bridge. + */ + std::string user_jid; + /** + * One IrcClient for each IRC server we need to be connected to. + * The pointer is shared by the bridge and the poller. + */ + std::unordered_map> irc_clients; + /** + * A raw pointer, because we do not own it, the XMPP component owns us, + * but we still need to communicate with it, when sending messages from + * IRC to XMPP. + */ + XmppComponent* xmpp; + /** + * Poller, to give it the IrcClients that we spawn, to make it manage + * their sockets. + * We don't own it. + */ + Poller* poller; + + Bridge(const Bridge&) = delete; + Bridge(Bridge&& other) = delete; + Bridge& operator=(const Bridge&) = delete; + Bridge& operator=(Bridge&&) = delete; +}; + +#endif // BRIDGE_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/bridge/bridge.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++- src/bridge/bridge.hpp | 11 ++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 638777d..5047a78 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -2,6 +2,8 @@ #include #include +#include + Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller): user_jid(user_jid), xmpp(xmpp), @@ -29,15 +31,54 @@ 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) + { + return nullptr; + } +} + + void Bridge::join_irc_channel(const Iid& iid, const std::string& username) { IrcClient* irc = this->get_irc_client(iid.server, username); irc->send_join_command(iid.chan); } +void Bridge::send_channel_message(const Iid& iid, const std::string& body) +{ + if (iid.chan.empty() || iid.server.empty()) + { + std::cout << "Cannot send message to channel: [" << iid.chan << "] on server [" << iid.server << "]" << std::endl; + return; + } + IrcClient* irc = this->get_irc_client(iid.server); + if (!irc) + { + std::cout << "Cannot send message: no client exist for server " << iid.server << std::endl; + return; + } + irc->send_channel_message(iid.chan, body); + this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), body, this->user_jid); +} + +void Bridge::send_muc_message(const Iid& iid, const std::string& nick, const std::string& body) +{ + this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, body, this->user_jid); +} + void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg) { - const std::string body = std::string("[") + author + std::string("] ") + msg; + std::string body; + if (!author.empty()) + body = std::string("[") + author + std::string("] ") + msg; + else + body = msg; this->xmpp->send_message(from, body, this->user_jid); } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index f9ddcca..38cf565 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -30,6 +30,7 @@ public: **/ void join_irc_channel(const Iid& iid, const std::string& username); + void send_channel_message(const Iid& iid, const std::string& body); /*** ** @@ -54,7 +55,10 @@ public: * Send the topic of the MUC to the user */ void send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic); - + /** + * Send a MUC message from some participant + */ + void send_muc_message(const Iid& iid, const std::string& nick, const std::string& body); private: /** * Returns the client for the given hostname, create one (and use the @@ -62,6 +66,11 @@ private: * client immediately. */ 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 + */ + IrcClient* get_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. -- cgit v1.2.3 From f38b31a63ee203e53d1135a87f1b4e9faaf7dd3f Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 9 Nov 2013 21:40:29 +0100 Subject: Remove IRC colors from the body when forwarding it to XMPP --- src/bridge/bridge.cpp | 23 +++++++++++++++++++---- src/bridge/bridge.hpp | 1 + 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 5047a78..f028f5b 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1,6 +1,9 @@ #include +#include #include #include +#include + #include @@ -15,6 +18,17 @@ Bridge::~Bridge() { } +std::string Bridge::sanitize_for_xmpp(const std::string& str) +{ + std::string res; + if (utils::is_valid_utf8(str.c_str())) + res = str; + else + res = utils::convert_to_utf8(str, "ISO-8859-1"); + remove_irc_colors(res); + return res; +} + IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string& username) { try @@ -43,7 +57,6 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname) } } - void Bridge::join_irc_channel(const Iid& iid, const std::string& username) { IrcClient* irc = this->get_irc_client(iid.server, username); @@ -64,12 +77,14 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) return; } irc->send_channel_message(iid.chan, body); + // We do not need to convert body to utf-8: it comes from our XMPP server, + // so it's ok to send it back this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), body, this->user_jid); } void Bridge::send_muc_message(const Iid& iid, const std::string& nick, const std::string& body) { - this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, body, this->user_jid); + this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, this->sanitize_for_xmpp(body), this->user_jid); } void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg) @@ -79,7 +94,7 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho body = std::string("[") + author + std::string("] ") + msg; else body = msg; - this->xmpp->send_message(from, body, this->user_jid); + this->xmpp->send_message(from, this->sanitize_for_xmpp(body), this->user_jid); } void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, const std::string nick) @@ -94,5 +109,5 @@ void Bridge::send_self_join(const std::string& hostname, const std::string& chan void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic) { - this->xmpp->send_topic(chan_name + "%" + hostname, topic, this->user_jid); + this->xmpp->send_topic(chan_name + "%" + hostname, this->sanitize_for_xmpp(topic), this->user_jid); } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 38cf565..f7fd7c6 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -23,6 +23,7 @@ public: explicit Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller); ~Bridge(); + static std::string sanitize_for_xmpp(const std::string& str); /*** ** ** From XMPP to IRC. -- 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/bridge/bridge.cpp | 12 ++++++++++++ src/bridge/bridge.hpp | 6 ++++++ 2 files changed, 18 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index f028f5b..9dbea2f 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -82,11 +82,23 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), body, this->user_jid); } +void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) +{ + IrcClient* irc = this->get_irc_client(iid.server); + if (irc) + irc->send_part_command(iid.chan, status_message); +} + void Bridge::send_muc_message(const Iid& iid, const std::string& nick, const std::string& body) { this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, this->sanitize_for_xmpp(body), this->user_jid); } +void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, std::string&& message, const bool self) +{ + this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->sanitize_for_xmpp(message), this->user_jid, self); +} + void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg) { std::string body; diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index f7fd7c6..93bb321 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -32,6 +32,7 @@ public: void join_irc_channel(const Iid& iid, const std::string& username); void send_channel_message(const Iid& iid, const std::string& body); + void leave_irc_channel(Iid&& iid, std::string&& status_message); /*** ** @@ -60,6 +61,11 @@ public: * Send a MUC message from some participant */ void send_muc_message(const Iid& iid, const std::string& nick, const std::string& body); + /** + * Send an unavailable presence from this participant + */ + void send_muc_leave(Iid&& iid, std::string&& nick, std::string&& message, const bool self); + private: /** * Returns the client for the given hostname, create one (and use the -- cgit v1.2.3 From 8acd7a02aeda01c0ac828b05c36f10bbacaea70e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 9 Nov 2013 23:20:12 +0100 Subject: Aaaand, I forgot to add files --- src/bridge/colors.cpp | 20 ++++++++++++++++++++ src/bridge/colors.hpp | 21 +++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/bridge/colors.cpp create mode 100644 src/bridge/colors.hpp (limited to 'src/bridge') diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp new file mode 100644 index 0000000..f49f31f --- /dev/null +++ b/src/bridge/colors.cpp @@ -0,0 +1,20 @@ +#include +#include + +#include + +void remove_irc_colors(std::string& str) +{ + auto it = std::remove_if(str.begin(), str.end(), + [](const char c) + { + if (c == IRC_COLOR_BOLD_CHAR || c == IRC_COLOR_COLOR_CHAR || + c == IRC_COLOR_FIXED_CHAR || c == IRC_COLOR_RESET_CHAR || + c == IRC_COLOR_REVERSE_CHAR || c == IRC_COLOR_REVERSE2_CHAR || + c == IRC_COLOR_UNDERLINE_CHAR || c == IRC_COLOR_ITALIC_CHAR) + return true; + return false; + } + ); + str.erase(it, str.end()); +} diff --git a/src/bridge/colors.hpp b/src/bridge/colors.hpp new file mode 100644 index 0000000..a4775e1 --- /dev/null +++ b/src/bridge/colors.hpp @@ -0,0 +1,21 @@ +#ifndef COLORS_INCLUDED +# define COLORS_INCLUDED + +#include + +/** + * A module handling the conversion between IRC colors and XHTML-IM, and vice versa. + */ + +#define IRC_COLOR_BOLD_CHAR '\x02' +#define IRC_COLOR_COLOR_CHAR '\x03' +#define IRC_COLOR_RESET_CHAR '\x0F' +#define IRC_COLOR_FIXED_CHAR '\x11' +#define IRC_COLOR_REVERSE_CHAR '\x12' +#define IRC_COLOR_REVERSE2_CHAR '\x16' +#define IRC_COLOR_ITALIC_CHAR '\x1D' +#define IRC_COLOR_UNDERLINE_CHAR '\x1F' + +void remove_irc_colors(std::string& str); + +#endif // COLORS_INCLUDED -- cgit v1.2.3 From 7ba2d0fb45e7466e6fb38002bf1866d1f5e39c28 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 10 Nov 2013 05:41:22 +0100 Subject: Handle the ACTION (/me) IRC command, both ways --- src/bridge/bridge.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 9dbea2f..89a6231 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -4,9 +4,11 @@ #include #include - #include +static const char* action_prefix = "\01ACTION "; +static const size_t action_prefix_len = 8; + Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller): user_jid(user_jid), xmpp(xmpp), @@ -76,7 +78,10 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) std::cout << "Cannot send message: no client exist for server " << iid.server << std::endl; return; } - irc->send_channel_message(iid.chan, body); + if (body.substr(0, 4) == "/me ") + irc->send_channel_message(iid.chan, action_prefix + body.substr(4) + "\01"); + else + irc->send_channel_message(iid.chan, body); // We do not need to convert body to utf-8: it comes from our XMPP server, // so it's ok to send it back this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), body, this->user_jid); @@ -91,7 +96,16 @@ void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) void Bridge::send_muc_message(const Iid& iid, const std::string& nick, const std::string& body) { - this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, this->sanitize_for_xmpp(body), this->user_jid); + const std::string& utf8_body = this->sanitize_for_xmpp(body); + if (utf8_body.substr(0, action_prefix_len) == action_prefix) + { // Special case for ACTION (/me) messages: + // "\01ACTION goes out\01" == "/me goes out" + this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, + std::string("/me ") + utf8_body.substr(action_prefix_len, utf8_body.size() - action_prefix_len - 1), + this->user_jid); + } + else + this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, utf8_body, this->user_jid); } void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, std::string&& message, const bool self) -- 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/bridge/bridge.cpp | 22 ++++++++++++++++------ src/bridge/bridge.hpp | 3 ++- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 89a6231..1f394bf 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -87,6 +87,15 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), body, this->user_jid); } +void Bridge::send_private_message(const Iid& iid, const std::string& body) +{ + if (iid.chan.empty() || iid.server.empty()) + return ; + IrcClient* irc = this->get_irc_client(iid.server); + if (irc) + irc->send_private_message(iid.chan, body); +} + void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) { IrcClient* irc = this->get_irc_client(iid.server); @@ -94,18 +103,19 @@ void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) irc->send_part_command(iid.chan, status_message); } -void Bridge::send_muc_message(const Iid& iid, const std::string& nick, const std::string& body) +void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { - const std::string& utf8_body = this->sanitize_for_xmpp(body); + std::string utf8_body = this->sanitize_for_xmpp(body); if (utf8_body.substr(0, action_prefix_len) == action_prefix) { // Special case for ACTION (/me) messages: // "\01ACTION goes out\01" == "/me goes out" - this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, - std::string("/me ") + utf8_body.substr(action_prefix_len, utf8_body.size() - action_prefix_len - 1), - this->user_jid); + utf8_body = std::string("/me ") + + utf8_body.substr(action_prefix_len, utf8_body.size() - action_prefix_len - 1); } - else + if (muc) this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, utf8_body, this->user_jid); + else + this->xmpp->send_message(iid.chan + "%" + iid.server, utf8_body, this->user_jid); } void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, std::string&& message, const bool self) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 93bb321..e0f4598 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -32,6 +32,7 @@ public: void join_irc_channel(const Iid& iid, const std::string& username); void send_channel_message(const Iid& iid, const std::string& body); + void send_private_message(const Iid& iid, const std::string& body); void leave_irc_channel(Iid&& iid, std::string&& status_message); /*** @@ -60,7 +61,7 @@ public: /** * Send a MUC message from some participant */ - void send_muc_message(const Iid& iid, const std::string& nick, const std::string& body); + void send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc); /** * Send an unavailable presence from this participant */ -- 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/bridge/bridge.cpp | 32 +++++++++++++++++++++++++++++--- src/bridge/bridge.hpp | 19 +++++++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 1f394bf..d292af3 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -59,10 +59,15 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname) } } -void Bridge::join_irc_channel(const Iid& iid, const std::string& username) +bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) { IrcClient* irc = this->get_irc_client(iid.server, username); - irc->send_join_command(iid.chan); + if (irc->is_channel_joined(iid.chan) == false) + { + irc->send_join_command(iid.chan); + return true; + } + return false; } void Bridge::send_channel_message(const Iid& iid, const std::string& body) @@ -103,6 +108,13 @@ void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) irc->send_part_command(iid.chan, status_message); } +void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick) +{ + IrcClient* irc = this->get_irc_client(iid.server); + if (irc) + irc->send_nick_command(new_nick); +} + void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { std::string utf8_body = this->sanitize_for_xmpp(body); @@ -118,11 +130,17 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st this->xmpp->send_message(iid.chan + "%" + iid.server, utf8_body, this->user_jid); } -void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, std::string&& message, const bool self) +void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self) { this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->sanitize_for_xmpp(message), this->user_jid, self); } +void Bridge::send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self) +{ + this->xmpp->send_nick_change(std::move(iid.chan) + "%" + std::move(iid.server), + old_nick, new_nick, this->user_jid, self); +} + void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg) { std::string body; @@ -147,3 +165,11 @@ void Bridge::send_topic(const std::string& hostname, const std::string& chan_nam { this->xmpp->send_topic(chan_name + "%" + hostname, this->sanitize_for_xmpp(topic), this->user_jid); } + +std::string Bridge::get_own_nick(const Iid& iid) +{ + IrcClient* irc = this->get_irc_client(iid.server); + if (irc) + return irc->get_own_nick(); + return ""; +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index e0f4598..0466ee1 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -30,10 +30,15 @@ public: ** **/ - void join_irc_channel(const Iid& iid, const std::string& username); + /** + * 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& username); void send_channel_message(const Iid& iid, const std::string& body); void send_private_message(const Iid& iid, const std::string& body); void leave_irc_channel(Iid&& iid, std::string&& status_message); + void send_irc_nick_change(const Iid& iid, const std::string& new_nick); /*** ** @@ -65,7 +70,17 @@ public: /** * Send an unavailable presence from this participant */ - void send_muc_leave(Iid&& iid, std::string&& nick, std::string&& message, const bool self); + void send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self); + /** + * Send presences to indicate that an user old_nick (ourself if self == + * true) changed his nick to new_nick + */ + void send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self); + + /** + * Misc + */ + std::string get_own_nick(const Iid& iid); private: /** -- 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/bridge/bridge.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index d292af3..0b26a7f 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -4,6 +4,7 @@ #include #include +#include #include static const char* action_prefix = "\01ACTION "; @@ -83,6 +84,12 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) std::cout << "Cannot send message: no client exist for server " << iid.server << std::endl; return; } + if (body.substr(0, 6) == "/mode ") + { + std::vector args = utils::split(body.substr(6), ' ', false); + irc->send_mode_command(iid.chan, args); + return; + } if (body.substr(0, 4) == "/me ") irc->send_channel_message(iid.chan, action_prefix + body.substr(4) + "\01"); else -- 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/bridge/bridge.cpp | 12 ++++++++++++ src/bridge/bridge.hpp | 2 ++ 2 files changed, 14 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 0b26a7f..e39cdd3 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -122,6 +122,13 @@ void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick) irc->send_nick_command(new_nick); } +void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason) +{ + IrcClient* irc = this->get_irc_client(iid.server); + if (irc) + irc->send_kick_command(iid.chan, target, reason); +} + void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { std::string utf8_body = this->sanitize_for_xmpp(body); @@ -180,3 +187,8 @@ std::string Bridge::get_own_nick(const Iid& iid) return irc->get_own_nick(); return ""; } + +void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author) +{ + this->xmpp->kick_user(iid.chan + "%" + iid.server, target, reason, author, this->user_jid); +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 0466ee1..b2124bd 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -39,6 +39,7 @@ public: void send_private_message(const Iid& iid, const std::string& body); void leave_irc_channel(Iid&& iid, std::string&& status_message); void send_irc_nick_change(const Iid& iid, const std::string& new_nick); + void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason); /*** ** @@ -76,6 +77,7 @@ public: * true) changed his nick to new_nick */ void send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self); + void kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author); /** * Misc -- cgit v1.2.3 From abce2fc92ec80e95066f6362492351b85ad8aef1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 13 Nov 2013 01:36:30 +0100 Subject: Do not crash on special chars in the content of message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That’s ugly, and we need to sanitize everything properly, and also handle these special messages. --- src/bridge/colors.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index f49f31f..b34ab4a 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -11,7 +11,11 @@ void remove_irc_colors(std::string& str) if (c == IRC_COLOR_BOLD_CHAR || c == IRC_COLOR_COLOR_CHAR || c == IRC_COLOR_FIXED_CHAR || c == IRC_COLOR_RESET_CHAR || c == IRC_COLOR_REVERSE_CHAR || c == IRC_COLOR_REVERSE2_CHAR || - c == IRC_COLOR_UNDERLINE_CHAR || c == IRC_COLOR_ITALIC_CHAR) + c == IRC_COLOR_UNDERLINE_CHAR || c == IRC_COLOR_ITALIC_CHAR || + // HACK: until we properly handle things + // like ^AVERSION^A, remove the ^A chars + // here. + c == '\u0001') return true; return false; } -- cgit v1.2.3 From bfcc9cdc7462c515c308592735bc661103fb92b5 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 21 Nov 2013 00:58:14 +0100 Subject: Send XMPP multi-line messages as multiple IRC messages --- src/bridge/bridge.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index e39cdd3..e24ab88 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -73,6 +73,10 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) void Bridge::send_channel_message(const Iid& iid, const std::string& body) { + std::vector lines = utils::split(body, '\n', true); + if (lines.empty()) + return ; + const std::string first_line = lines[0]; if (iid.chan.empty() || iid.server.empty()) { std::cout << "Cannot send message to channel: [" << iid.chan << "] on server [" << iid.server << "]" << std::endl; @@ -84,16 +88,19 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) std::cout << "Cannot send message: no client exist for server " << iid.server << std::endl; return; } - if (body.substr(0, 6) == "/mode ") + if (first_line.substr(0, 6) == "/mode ") { - std::vector args = utils::split(body.substr(6), ' ', false); + std::vector args = utils::split(first_line.substr(6), ' ', false); irc->send_mode_command(iid.chan, args); return; } - if (body.substr(0, 4) == "/me ") - irc->send_channel_message(iid.chan, action_prefix + body.substr(4) + "\01"); + if (first_line.substr(0, 4) == "/me ") + irc->send_channel_message(iid.chan, action_prefix + first_line.substr(4) + "\01"); else - irc->send_channel_message(iid.chan, body); + irc->send_channel_message(iid.chan, first_line); + // Send each of the other lines of the message as a separate IRC message + for (std::vector::const_iterator it = lines.begin() + 1; it != lines.end(); ++it) + irc->send_channel_message(iid.chan, *it); // We do not need to convert body to utf-8: it comes from our XMPP server, // so it's ok to send it back this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), body, this->user_jid); -- cgit v1.2.3 From fba01f46468050d4f3b8eb35373ed49a3584868e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 22 Nov 2013 21:00:07 +0100 Subject: Remove incomplete implementation of remove_irc_colors --- src/bridge/bridge.cpp | 1 - src/bridge/colors.cpp | 17 ----------------- src/bridge/colors.hpp | 1 - 3 files changed, 19 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index e24ab88..e08e2a4 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -28,7 +28,6 @@ std::string Bridge::sanitize_for_xmpp(const std::string& str) res = str; else res = utils::convert_to_utf8(str, "ISO-8859-1"); - remove_irc_colors(res); return res; } diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index b34ab4a..2f30354 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -3,22 +3,5 @@ #include -void remove_irc_colors(std::string& str) { - auto it = std::remove_if(str.begin(), str.end(), - [](const char c) - { - if (c == IRC_COLOR_BOLD_CHAR || c == IRC_COLOR_COLOR_CHAR || - c == IRC_COLOR_FIXED_CHAR || c == IRC_COLOR_RESET_CHAR || - c == IRC_COLOR_REVERSE_CHAR || c == IRC_COLOR_REVERSE2_CHAR || - c == IRC_COLOR_UNDERLINE_CHAR || c == IRC_COLOR_ITALIC_CHAR || - // HACK: until we properly handle things - // like ^AVERSION^A, remove the ^A chars - // here. - c == '\u0001') - return true; - return false; - } - ); - str.erase(it, str.end()); } diff --git a/src/bridge/colors.hpp b/src/bridge/colors.hpp index a4775e1..da4498c 100644 --- a/src/bridge/colors.hpp +++ b/src/bridge/colors.hpp @@ -16,6 +16,5 @@ #define IRC_COLOR_ITALIC_CHAR '\x1D' #define IRC_COLOR_UNDERLINE_CHAR '\x1F' -void remove_irc_colors(std::string& str); #endif // COLORS_INCLUDED -- cgit v1.2.3 From e6f20d3c0fd4ba8696a4410a366741c9b9f3562d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 22 Nov 2013 21:00:32 +0100 Subject: Implement IRC format to xhtml-im conversion The generated XML is very verbose because each IRC formatting tag makes us close a element and reopen it with the new style applied. However, this works quite well and is easy to implement. --- src/bridge/bridge.cpp | 26 ++++---- src/bridge/bridge.hpp | 3 +- src/bridge/colors.cpp | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/bridge/colors.hpp | 56 +++++++++++++---- 4 files changed, 220 insertions(+), 27 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index e08e2a4..7e6f801 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -21,14 +21,14 @@ Bridge::~Bridge() { } -std::string Bridge::sanitize_for_xmpp(const std::string& str) +Xmpp::body Bridge::make_xmpp_body(const std::string& str) { std::string res; if (utils::is_valid_utf8(str.c_str())) res = str; else res = utils::convert_to_utf8(str, "ISO-8859-1"); - return res; + return irc_format_to_xhtmlim(res); } IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string& username) @@ -102,7 +102,8 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) irc->send_channel_message(iid.chan, *it); // We do not need to convert body to utf-8: it comes from our XMPP server, // so it's ok to send it back - this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), body, this->user_jid); + this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), + this->make_xmpp_body(body), this->user_jid); } void Bridge::send_private_message(const Iid& iid, const std::string& body) @@ -137,22 +138,17 @@ void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std: void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { - std::string utf8_body = this->sanitize_for_xmpp(body); - if (utf8_body.substr(0, action_prefix_len) == action_prefix) - { // Special case for ACTION (/me) messages: - // "\01ACTION goes out\01" == "/me goes out" - utf8_body = std::string("/me ") + - utf8_body.substr(action_prefix_len, utf8_body.size() - action_prefix_len - 1); - } if (muc) - this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, utf8_body, this->user_jid); + this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, + this->make_xmpp_body(body), this->user_jid); else - this->xmpp->send_message(iid.chan + "%" + iid.server, utf8_body, this->user_jid); + this->xmpp->send_message(iid.chan + "%" + iid.server, + this->make_xmpp_body(body), this->user_jid); } void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self) { - this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->sanitize_for_xmpp(message), this->user_jid, self); + this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->make_xmpp_body(message), this->user_jid, self); } void Bridge::send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self) @@ -168,7 +164,7 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho body = std::string("[") + author + std::string("] ") + msg; else body = msg; - this->xmpp->send_message(from, this->sanitize_for_xmpp(body), this->user_jid); + this->xmpp->send_message(from, this->make_xmpp_body(body), this->user_jid); } void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, const std::string nick) @@ -183,7 +179,7 @@ void Bridge::send_self_join(const std::string& hostname, const std::string& chan void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic) { - this->xmpp->send_topic(chan_name + "%" + hostname, this->sanitize_for_xmpp(topic), this->user_jid); + this->xmpp->send_topic(chan_name + "%" + hostname, this->make_xmpp_body(topic), this->user_jid); } std::string Bridge::get_own_nick(const Iid& iid) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index b2124bd..1443191 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -2,6 +2,7 @@ # define BRIDGE_INCLUDED #include +#include #include #include @@ -23,7 +24,7 @@ public: explicit Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller); ~Bridge(); - static std::string sanitize_for_xmpp(const std::string& str); + static Xmpp::body make_xmpp_body(const std::string& str); /*** ** ** From XMPP to IRC. diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index 2f30354..024121b 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -1,7 +1,169 @@ #include +#include +#include + #include #include +#include + +static const char IRC_NUM_COLORS = 16; + +static const char* irc_colors_to_css[IRC_NUM_COLORS] = { + "white", + "black", + "blue", + "green", + "indianred", + "red", + "magenta", + "brown", + "yellow", + "lightgreen", + "cyan", + "lightcyan", + "lightblue", + "lightmagenta", + "gray", + "white", +}; + +#define XHTML_NS "http://www.w3.org/1999/xhtml" + +struct styles_t { + bool strong; + bool underline; + bool italic; + int fg; + int bg; +}; + +/** We keep the currently-applied CSS styles in a structure. Each time a tag + * is found, update this style list, then close the current span XML element + * (if it is open), then reopen it with all the new styles in it. This is + * done this way because IRC formatting does not map well with XML + * (hierarchical tags), it’s a lot easier and cleaner to remove all styles + * and reapply them for each tag, instead of trying to keep a consistent + * hierarchy of span, strong, em etc tags. The generated XML is one-level + * deep only. +*/ +Xmpp::body irc_format_to_xhtmlim(const std::string& s) +{ + if (s.find_first_of(irc_format_char) == std::string::npos) + // there is no special formatting at all + return std::make_tuple(s, nullptr); + + std::string cleaned; + + styles_t styles = {false, false, false, -1, -1}; + + std::unique_ptr result = std::make_unique("body"); + (*result)["xmlns"] = XHTML_NS; + + XmlNode* current_node = result.get(); + std::string::size_type pos_start = 0; + std::string::size_type pos_end; + + while ((pos_end = s.find_first_of(irc_format_char, pos_start)) != std::string::npos) + { + const std::string txt = s.substr(pos_start, pos_end-pos_start); + cleaned += txt; + if (current_node->has_children()) + current_node->get_last_child()->set_tail(txt); + else + current_node->set_inner(txt); + + if (s[pos_end] == IRC_FORMAT_BOLD_CHAR) + styles.strong = !styles.strong; + else if (s[pos_end] == IRC_FORMAT_UNDERLINE_CHAR) + styles.underline = !styles.underline; + else if (s[pos_end] == IRC_FORMAT_ITALIC_CHAR) + styles.italic = !styles.italic; + else if (s[pos_end] == IRC_FORMAT_RESET_CHAR) + styles = {false, false, false, -1, -1}; + else if (s[pos_end] == IRC_FORMAT_REVERSE_CHAR) + { } // TODO + else if (s[pos_end] == IRC_FORMAT_REVERSE2_CHAR) + { } // TODO + else if (s[pos_end] == IRC_FORMAT_FIXED_CHAR) + { } // TODO + else if (s[pos_end] == IRC_FORMAT_COLOR_CHAR) + { + size_t pos = pos_end + 1; + styles.fg = -1; + styles.bg = -1; + // get the first number following the format char + if (pos < s.size() && s[pos] >= '0' && s[pos] <= '9') + { // first digit + styles.fg = s[pos++] - '0'; + if (pos < s.size() && s[pos] >= '0' && s[pos] <= '9') + // second digit + styles.fg = styles.fg * 10 + s[pos++] - '0'; + } + if (pos < s.size() && s[pos] == ',') + { // get bg color after the comma + pos++; + if (pos < s.size() && s[pos] >= '0' && s[pos] <= '9') + { // first digit + styles.bg = s[pos++] - '0'; + if (pos < s.size() && s[pos] >= '0' && s[pos] <= '9') + // second digit + styles.bg = styles.bg * 10 + s[pos++] - '0'; + } + } + pos_end = pos - 1; + } + + // close opened span, if any + if (current_node != result.get()) + { + current_node->close(); + result->add_child(current_node); + current_node = result.get(); + } + // Take all currently-applied style and create a new span with it + std::string styles_str; + if (styles.strong) + styles_str += "font-weight:bold;"; + if (styles.underline) + styles_str += "text-decoration:underline;"; + if (styles.italic) + styles_str += "font-style:italic;"; + if (styles.fg != -1) + styles_str += std::string("color:") + + irc_colors_to_css[styles.fg % IRC_NUM_COLORS] + ";"; + if (styles.bg != -1) + styles_str += std::string("background-color:") + + irc_colors_to_css[styles.bg % IRC_NUM_COLORS] + ";"; + if (!styles_str.empty()) + { + current_node = new XmlNode("span"); + (*current_node)["style"] = styles_str; + } + + pos_start = pos_end + 1; + } + + // If some text remains, without any format char, just append that text at + // the end of the current node + const std::string txt = s.substr(pos_start, pos_end-pos_start); + cleaned += txt; + if (current_node->has_children()) + current_node->get_last_child()->set_tail(txt); + else + current_node->set_inner(txt); + + if (current_node != result.get()) + { + current_node->close(); + result->add_child(current_node); + current_node = result.get(); + } + + + result->close(); + Xmpp::body body_res = std::make_tuple(cleaned, std::move(result)); + return body_res; } diff --git a/src/bridge/colors.hpp b/src/bridge/colors.hpp index da4498c..82e6faf 100644 --- a/src/bridge/colors.hpp +++ b/src/bridge/colors.hpp @@ -1,20 +1,54 @@ #ifndef COLORS_INCLUDED # define COLORS_INCLUDED -#include - /** - * A module handling the conversion between IRC colors and XHTML-IM, and vice versa. + * A module handling the conversion between IRC colors and XHTML-IM, and + * vice versa. */ -#define IRC_COLOR_BOLD_CHAR '\x02' -#define IRC_COLOR_COLOR_CHAR '\x03' -#define IRC_COLOR_RESET_CHAR '\x0F' -#define IRC_COLOR_FIXED_CHAR '\x11' -#define IRC_COLOR_REVERSE_CHAR '\x12' -#define IRC_COLOR_REVERSE2_CHAR '\x16' -#define IRC_COLOR_ITALIC_CHAR '\x1D' -#define IRC_COLOR_UNDERLINE_CHAR '\x1F' +#include +#include +#include + +class XmlNode; + +namespace Xmpp +{ +// Contains: +// - an XMPP-valid UTF-8 body +// - an XML node representing the XHTML-IM body, or null + typedef std::tuple> body; +} +#define IRC_FORMAT_BOLD_CHAR '\x02' // done +#define IRC_FORMAT_COLOR_CHAR '\x03' // done +#define IRC_FORMAT_RESET_CHAR '\x0F' // done +#define IRC_FORMAT_FIXED_CHAR '\x11' // ?? +#define IRC_FORMAT_REVERSE_CHAR '\x12' // maybe one day +#define IRC_FORMAT_REVERSE2_CHAR '\x16' // wat +#define IRC_FORMAT_ITALIC_CHAR '\x1D' // done +#define IRC_FORMAT_UNDERLINE_CHAR '\x1F' // done + +static const char irc_format_char[] = { + IRC_FORMAT_BOLD_CHAR, + IRC_FORMAT_COLOR_CHAR, + IRC_FORMAT_RESET_CHAR, + IRC_FORMAT_FIXED_CHAR, + IRC_FORMAT_REVERSE_CHAR, + IRC_FORMAT_REVERSE2_CHAR, + IRC_FORMAT_ITALIC_CHAR, + IRC_FORMAT_UNDERLINE_CHAR, + '\x00' +}; + +/** + * Convert the passed string into an XML tree representing the XHTML version + * of the message, converting the IRC colors symbols into xhtml-im + * formatting. + * + * Returns the body cleaned from any IRC formatting (but without any xhtml), + * and the body as XHTML-IM + */ +Xmpp::body irc_format_to_xhtmlim(const std::string& str); #endif // COLORS_INCLUDED -- 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/bridge/bridge.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 7e6f801..2ad6af8 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -3,7 +3,7 @@ #include #include #include - +#include #include #include @@ -78,13 +78,13 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) const std::string first_line = lines[0]; if (iid.chan.empty() || iid.server.empty()) { - std::cout << "Cannot send message to channel: [" << iid.chan << "] on server [" << iid.server << "]" << std::endl; + log_warning("Cannot send message to channel: [" << iid.chan << "] on server [" << iid.server << "]"); return; } IrcClient* irc = this->get_irc_client(iid.server); if (!irc) { - std::cout << "Cannot send message: no client exist for server " << iid.server << std::endl; + log_warning("Cannot send message: no client exist for server " << iid.server); return; } if (first_line.substr(0, 6) == "/mode ") -- 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/bridge/bridge.cpp | 6 ++++-- src/bridge/bridge.hpp | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 2ad6af8..973e095 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -167,9 +167,11 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho this->xmpp->send_message(from, this->make_xmpp_body(body), this->user_jid); } -void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, const std::string nick) +void Bridge::send_user_join(const std::string& hostname, + const std::string& chan_name, + const IrcUser* user) { - this->xmpp->send_user_join(chan_name + "%" + hostname, nick, this->user_jid); + this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host, this->user_jid); } void Bridge::send_self_join(const std::string& hostname, const std::string& chan_name, const std::string nick) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 1443191..bbbca95 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -56,7 +57,9 @@ public: /** * Send the presence of a new user in the MUC. */ - void send_user_join(const std::string& hostname, const std::string& chan_name, const std::string nick); + void send_user_join(const std::string& hostname, + const std::string& chan_name, + const IrcUser* user); /** * Send the self presence of an user when the MUC is fully joined. */ -- 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/bridge/bridge.cpp | 8 ++++++++ src/bridge/bridge.hpp | 4 ++++ 2 files changed, 12 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 973e095..606cb02 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -21,6 +21,14 @@ Bridge::~Bridge() { } +void Bridge::shutdown() +{ + for (auto it = this->irc_clients.begin(); it != this->irc_clients.end(); ++it) + { + it->second->send_quit_command(); + } +} + Xmpp::body Bridge::make_xmpp_body(const std::string& str) { std::string res; diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index bbbca95..7a36b59 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -24,6 +24,10 @@ class Bridge public: explicit Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller); ~Bridge(); + /** + * QUIT all connected IRC servers. + */ + void shutdown(); static Xmpp::body make_xmpp_body(const std::string& str); /*** -- 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/bridge/bridge.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 606cb02..3a755a3 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -50,7 +50,6 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string this->irc_clients.emplace(hostname, std::make_shared(hostname, username, this)); std::shared_ptr irc = this->irc_clients.at(hostname); this->poller->add_socket_handler(irc); - irc->start(); return irc.get(); } } -- 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/bridge/bridge.cpp | 13 +++++++++++++ src/bridge/bridge.hpp | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 3a755a3..c93d710 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -29,6 +29,19 @@ void Bridge::shutdown() } } +void Bridge::clean() +{ + auto it = this->irc_clients.begin(); + while (it != this->irc_clients.end()) + { + IrcClient* client = it->second.get(); + if (!client->is_connected()) + it = this->irc_clients.erase(it); + else + ++it; + } +} + Xmpp::body Bridge::make_xmpp_body(const std::string& str) { std::string res; diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 7a36b59..1e1149b 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -28,7 +28,10 @@ public: * QUIT all connected IRC servers. */ void shutdown(); - + /** + * Remove all inactive IrcClients + */ + void clean(); static Xmpp::body make_xmpp_body(const std::string& str); /*** ** -- 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/bridge/bridge.cpp | 5 +++++ src/bridge/bridge.hpp | 1 + 2 files changed, 6 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index c93d710..7f245db 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -216,3 +216,8 @@ void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::stri { this->xmpp->kick_user(iid.chan + "%" + iid.server, target, reason, author, this->user_jid); } + +void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname) +{ + this->xmpp->send_nickname_conflict_error(iid.chan + "%" + iid.server, nickname, this->user_jid); +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 1e1149b..b5bee9e 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -89,6 +89,7 @@ public: */ void send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self); void kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author); + void send_nickname_conflict_error(const Iid& iid, const std::string& nickname); /** * Misc -- 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/bridge/bridge.cpp | 18 +++++++++++------- src/bridge/bridge.hpp | 7 ++----- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 7f245db..fb3afc7 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -189,14 +189,18 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, - const IrcUser* user) + const IrcUser* user, + const bool self) { - this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host, this->user_jid); -} - -void Bridge::send_self_join(const std::string& hostname, const std::string& chan_name, const std::string nick) -{ - this->xmpp->send_self_join(chan_name + "%" + hostname, nick, this->user_jid); + std::string affiliation = "participant"; + std::string role = "none"; + if (user->modes.find('o') != user->modes.end()) + { + affiliation = "admin"; + role = "moderator"; + } + this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host, + affiliation, role, this->user_jid, self); } void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index b5bee9e..a4eeaa4 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -66,11 +66,8 @@ public: */ void send_user_join(const std::string& hostname, const std::string& chan_name, - const IrcUser* user); - /** - * Send the self presence of an user when the MUC is fully joined. - */ - void send_self_join(const std::string& hostname, const std::string& chan_name, const std::string nick); + const IrcUser* user, + const bool self); /** * Send the topic of the MUC to the user */ -- 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/bridge/bridge.cpp | 32 ++++++++++++++++++++++++++++++++ src/bridge/bridge.hpp | 4 ++++ 2 files changed, 36 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index fb3afc7..d034bcd 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -225,3 +225,35 @@ void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nic { this->xmpp->send_nickname_conflict_error(iid.chan + "%" + iid.server, nickname, this->user_jid); } + +void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode) +{ + std::string role; + std::string affiliation; + if (mode == 0) + { + role = "participant"; + affiliation = "none"; + } + else if (mode == 'a') + { + role = "moderator"; + affiliation = "owner"; + } + else if (mode == 'o') + { + role = "moderator"; + affiliation = "admin"; + } + else if (mode == 'h') + { + role = "moderator"; + affiliation = "member"; + } + else if (mode == 'v') + { + role = "participant"; + affiliation = "member"; + } + this->xmpp->send_affiliation_role_change(iid.chan + "%" + iid.server, target, affiliation, role, this->user_jid); +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index a4eeaa4..7e881d9 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -87,6 +87,10 @@ public: void send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self); void kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author); void send_nickname_conflict_error(const Iid& iid, const std::string& nickname); + /** + * Send a role/affiliation change, matching the change of mode for that user + */ + void send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode); /** * Misc -- 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/bridge/bridge.cpp | 7 +++++++ src/bridge/bridge.hpp | 1 + 2 files changed, 8 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index d034bcd..dae5a72 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -156,6 +156,13 @@ void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std: irc->send_kick_command(iid.chan, target, reason); } +void Bridge::set_channel_topic(const Iid& iid, const std::string& subject) +{ + IrcClient* irc = this->get_irc_client(iid.server); + if (irc) + irc->send_topic_command(iid.chan, subject); +} + void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { if (muc) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 7e881d9..75708e5 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -49,6 +49,7 @@ public: void leave_irc_channel(Iid&& iid, std::string&& status_message); void send_irc_nick_change(const Iid& iid, const std::string& new_nick); void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason); + void set_channel_topic(const Iid& iid, const std::string& subject); /*** ** -- 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/bridge/bridge.cpp | 56 ++++++++++++++++++++++----------------------------- src/bridge/bridge.hpp | 1 + 2 files changed, 25 insertions(+), 32 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index dae5a72..be0d270 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -6,6 +6,7 @@ #include #include #include +#include static const char* action_prefix = "\01ACTION "; static const size_t action_prefix_len = 8; @@ -21,6 +22,22 @@ Bridge::~Bridge() { } +/** + * Return the role and affiliation, corresponding to the given irc mode */ +static std::tuple get_role_affiliation_from_irc_mode(const char mode) +{ + if (mode == 'a' || mode == 'q') + return std::make_tuple("moderator", "owner"); + else if (mode == 'o') + return std::make_tuple("moderator", "admin"); + else if (mode == 'h') + return std::make_tuple("moderator", "member"); + else if (mode == 'v') + return std::make_tuple("participant", "member"); + else + return std::make_tuple("participant", "none"); +} + void Bridge::shutdown() { for (auto it = this->irc_clients.begin(); it != this->irc_clients.end(); ++it) @@ -197,15 +214,13 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, const IrcUser* user, + const char user_mode, const bool self) { - std::string affiliation = "participant"; - std::string role = "none"; - if (user->modes.find('o') != user->modes.end()) - { - affiliation = "admin"; - role = "moderator"; - } + std::string affiliation; + std::string role; + std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); + this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host, affiliation, role, this->user_jid, self); } @@ -237,30 +252,7 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar { std::string role; std::string affiliation; - if (mode == 0) - { - role = "participant"; - affiliation = "none"; - } - else if (mode == 'a') - { - role = "moderator"; - affiliation = "owner"; - } - else if (mode == 'o') - { - role = "moderator"; - affiliation = "admin"; - } - else if (mode == 'h') - { - role = "moderator"; - affiliation = "member"; - } - else if (mode == 'v') - { - role = "participant"; - affiliation = "member"; - } + + std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(mode); this->xmpp->send_affiliation_role_change(iid.chan + "%" + iid.server, target, affiliation, role, this->user_jid); } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 75708e5..c43b049 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -68,6 +68,7 @@ public: void send_user_join(const std::string& hostname, const std::string& chan_name, const IrcUser* user, + const char user_mode, const bool self); /** * Send the topic of the MUC to the user -- 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/bridge/bridge.cpp | 12 ++++++++++-- src/bridge/bridge.hpp | 12 +++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index be0d270..6460e6b 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -195,10 +195,18 @@ void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& me this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->make_xmpp_body(message), this->user_jid, self); } -void Bridge::send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self) +void Bridge::send_nick_change(Iid&& iid, + const std::string& old_nick, + const std::string& new_nick, + const char user_mode, + const bool self) { + std::string affiliation; + std::string role; + std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); + this->xmpp->send_nick_change(std::move(iid.chan) + "%" + std::move(iid.server), - old_nick, new_nick, this->user_jid, self); + old_nick, new_nick, affiliation, role, this->user_jid, self); } void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index c43b049..b3a5d02 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -84,9 +84,15 @@ public: void send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self); /** * Send presences to indicate that an user old_nick (ourself if self == - * true) changed his nick to new_nick - */ - void send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self); + * true) changed his nick to new_nick. The user_mode is needed because + * the xmpp presence needs ton contain the role and affiliation of the + * user. + */ + void send_nick_change(Iid&& iid, + const std::string& old_nick, + const std::string& new_nick, + const char user_mode, + const bool self); void kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author); void send_nickname_conflict_error(const Iid& iid, const std::string& nickname); /** -- 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/bridge/bridge.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 6460e6b..5122a69 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -42,7 +42,7 @@ void Bridge::shutdown() { for (auto it = this->irc_clients.begin(); it != this->irc_clients.end(); ++it) { - it->second->send_quit_command(); + it->second->send_quit_command("Gateway shutdown"); } } @@ -193,6 +193,9 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self) { this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->make_xmpp_body(message), this->user_jid, self); + IrcClient* irc = this->get_irc_client(iid.server); + if (irc && irc->number_of_joined_channels() == 0) + irc->send_quit_command(""); } void Bridge::send_nick_change(Iid&& iid, -- cgit v1.2.3 From 61ca40fa0e6c819aa72f3f2364667c7b990855d4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 20 Feb 2014 02:31:16 +0100 Subject: Delete empty bridges objects --- src/bridge/bridge.cpp | 5 +++++ src/bridge/bridge.hpp | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 5122a69..bb3bfb0 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -249,6 +249,11 @@ std::string Bridge::get_own_nick(const Iid& iid) return ""; } +size_t Bridge::connected_clients() const +{ + return this->irc_clients.size(); +} + void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author) { this->xmpp->kick_user(iid.chan + "%" + iid.server, target, reason, author, this->user_jid); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index b3a5d02..58ca24c 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -104,6 +104,10 @@ public: * Misc */ std::string get_own_nick(const Iid& iid); + /** + * Get the number of server to which this bridge is connected. + */ + size_t connected_clients() 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/bridge/bridge.cpp | 4 ++-- src/bridge/bridge.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index bb3bfb0..ed685f9 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -52,7 +52,7 @@ void Bridge::clean() while (it != this->irc_clients.end()) { IrcClient* client = it->second.get(); - if (!client->is_connected()) + if (!client->is_connected() && !client->is_connecting()) it = this->irc_clients.erase(it); else ++it; @@ -249,7 +249,7 @@ std::string Bridge::get_own_nick(const Iid& iid) return ""; } -size_t Bridge::connected_clients() const +size_t Bridge::active_clients() const { return this->irc_clients.size(); } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 58ca24c..e16ea39 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -105,9 +105,9 @@ public: */ std::string get_own_nick(const Iid& iid); /** - * Get the number of server to which this bridge is connected. + * Get the number of server to which this bridge is connected or connecting. */ - size_t connected_clients() const; + size_t active_clients() const; private: /** @@ -125,7 +125,7 @@ private: * The JID of the user associated with this bridge. Messages from/to this * JID are only managed by this bridge. */ - std::string user_jid; + const std::string user_jid; /** * One IrcClient for each IRC server we need to be connected to. * The pointer is shared by the bridge and the poller. -- cgit v1.2.3 From f6029d5bcf9f529d72e0846661f555e189669b26 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 24 Feb 2014 21:03:51 +0100 Subject: Add missing stdexcept includes --- src/bridge/bridge.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index ed685f9..9b7908a 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From a20c60a0d84f2f22777e3831cac1315302b7a095 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 10 Apr 2014 20:11:17 +0200 Subject: Messages coming from the IRC server are of type "chat" --- src/bridge/bridge.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 9b7908a..277f696 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -188,7 +188,7 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st this->make_xmpp_body(body), this->user_jid); else this->xmpp->send_message(iid.chan + "%" + iid.server, - this->make_xmpp_body(body), this->user_jid); + this->make_xmpp_body(body), this->user_jid, "chat"); } void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self) @@ -220,7 +220,7 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho body = std::string("[") + author + std::string("] ") + msg; else body = msg; - this->xmpp->send_message(from, this->make_xmpp_body(body), this->user_jid); + this->xmpp->send_message(from, this->make_xmpp_body(body), this->user_jid, "chat"); } void Bridge::send_user_join(const std::string& hostname, -- 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/bridge/bridge.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 9b7908a..f4d4814 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,25 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname) bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) { IrcClient* irc = this->get_irc_client(iid.server, username); + if (iid.chan.empty()) + { // Join the dummy channel + if (irc->is_welcomed()) + { + if (irc->get_dummy_channel().joined) + return false; + // Immediately simulate a message coming from the IRC server saying that we + // joined the channel + const IrcMessage join_message(irc->get_nick(), "JOIN", {""}); + irc->on_channel_join(join_message); + const IrcMessage end_join_message(std::string(iid.server), "366", + {irc->get_nick(), + "", "End of NAMES list"}); + irc->on_channel_completely_joined(end_join_message); + } + else + irc->get_dummy_channel().joining = true; + return true; + } if (irc->is_channel_joined(iid.chan) == false) { irc->send_join_command(iid.chan); -- 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/bridge/bridge.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index da10e28..e874ccb 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -44,7 +44,9 @@ void Bridge::shutdown() { for (auto it = this->irc_clients.begin(); it != this->irc_clients.end(); ++it) { - it->second->send_quit_command("Gateway shutdown"); + const std::string exit_message("Gateway shutdown"); + it->second->send_quit_command(exit_message); + it->second->leave_dummy_channel(exit_message); } } -- cgit v1.2.3 From 14b6793d7fe78cfbab4f2686eb58e59d4f40338c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 15 Apr 2014 05:11:36 +0200 Subject: Joining the dummy channel connects to the irc server --- src/bridge/bridge.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index e874ccb..eceb22e 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -119,7 +119,10 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) 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.chan) == false) -- cgit v1.2.3 From bd7936bdfe799d6b665c4b2bd30a5210592d9ae4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 17 Apr 2014 20:37:46 +0200 Subject: No more missing text when converting IRC colors to xhtml-im fix #2496 --- src/bridge/colors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index 024121b..e42c5a3 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -71,7 +71,7 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) const std::string txt = s.substr(pos_start, pos_end-pos_start); cleaned += txt; if (current_node->has_children()) - current_node->get_last_child()->set_tail(txt); + current_node->get_last_child()->add_to_tail(txt); else current_node->set_inner(txt); -- cgit v1.2.3 From 114007f10dbc77fdc71c34689fc20ce3e3111492 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 18 Apr 2014 10:45:28 +0200 Subject: Actually do the last commit, but completely this time --- src/bridge/colors.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index e42c5a3..aff001e 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -73,7 +73,7 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) if (current_node->has_children()) current_node->get_last_child()->add_to_tail(txt); else - current_node->set_inner(txt); + current_node->add_to_inner(txt); if (s[pos_end] == IRC_FORMAT_BOLD_CHAR) styles.strong = !styles.strong; @@ -151,9 +151,9 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) const std::string txt = s.substr(pos_start, pos_end-pos_start); cleaned += txt; if (current_node->has_children()) - current_node->get_last_child()->set_tail(txt); + current_node->get_last_child()->add_to_tail(txt); else - current_node->set_inner(txt); + current_node->add_to_inner(txt); if (current_node != result.get()) { -- cgit v1.2.3 From 848b50185f25927cffc250b1885e6d47a42b4326 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 21 Apr 2014 22:46:45 +0200 Subject: Remove unused action_prefix_len variable --- src/bridge/bridge.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index eceb22e..a2f481c 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -11,7 +11,6 @@ #include static const char* action_prefix = "\01ACTION "; -static const size_t action_prefix_len = 8; Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller): user_jid(user_jid), -- cgit v1.2.3 From 4e61b0d57e4e0a127b8b8db2dab6452695ff425c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 25 Apr 2014 00:53:08 +0200 Subject: The author name from messages from the server are now nicely formated --- src/bridge/bridge.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index a2f481c..12a56d7 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -241,7 +241,12 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho { std::string body; if (!author.empty()) - body = std::string("[") + author + std::string("] ") + msg; + { + IrcUser user(author); + body = std::string("\u000303") + user.nick + (user.host.empty()? + std::string("\u0003: "): + (" (\u000310" + user.host + std::string("\u000303)\u0003: "))) + msg; + } else body = msg; this->xmpp->send_message(from, this->make_xmpp_body(body), this->user_jid, "chat"); -- 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/bridge/colors.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index aff001e..49f7a39 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -1,9 +1,7 @@ #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/bridge/bridge.cpp | 8 +++++--- src/bridge/colors.cpp | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 12a56d7..4b2d895 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -10,6 +10,8 @@ #include #include +using namespace std::string_literals; + static const char* action_prefix = "\01ACTION "; Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller): @@ -243,9 +245,9 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho if (!author.empty()) { IrcUser user(author); - body = std::string("\u000303") + user.nick + (user.host.empty()? - std::string("\u0003: "): - (" (\u000310" + user.host + std::string("\u000303)\u0003: "))) + msg; + body = "\u000303"s + user.nick + (user.host.empty()? + "\u0003: ": + (" (\u000310" + user.host + "\u000303)\u0003: ")) + msg; } else body = msg; diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index 49f7a39..6f6d7a9 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -6,6 +6,8 @@ #include +using namespace std::string_literals; + static const char IRC_NUM_COLORS = 16; static const char* irc_colors_to_css[IRC_NUM_COLORS] = { @@ -130,10 +132,10 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) if (styles.italic) styles_str += "font-style:italic;"; if (styles.fg != -1) - styles_str += std::string("color:") + + styles_str += "color:"s + irc_colors_to_css[styles.fg % IRC_NUM_COLORS] + ";"; if (styles.bg != -1) - styles_str += std::string("background-color:") + + styles_str += "background-color:"s + irc_colors_to_css[styles.bg % IRC_NUM_COLORS] + ";"; if (!styles_str.empty()) { -- cgit v1.2.3 From 65f219594d16bac119e50ac882139f5b1461b1e3 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 29 Apr 2014 21:56:05 +0200 Subject: Fix a little indentation --- src/bridge/bridge.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 4b2d895..aa88262 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -246,8 +246,8 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho { IrcUser user(author); body = "\u000303"s + user.nick + (user.host.empty()? - "\u0003: ": - (" (\u000310" + user.host + "\u000303)\u0003: ")) + msg; + "\u0003: ": + (" (\u000310" + user.host + "\u000303)\u0003: ")) + msg; } else body = msg; -- 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/bridge/bridge.cpp | 5 +++++ src/bridge/bridge.hpp | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index aa88262..6c85722 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -304,3 +304,8 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(mode); this->xmpp->send_affiliation_role_change(iid.chan + "%" + iid.server, target, affiliation, role, this->user_jid); } + +void Bridge::send_iq_version_request(const std::string& nick, const std::string& hostname) +{ + this->xmpp->send_iq_version_request(nick + "%" + hostname, this->user_jid); +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index e16ea39..f2da8d7 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -99,6 +99,10 @@ public: * Send a role/affiliation change, matching the change of mode for that user */ void send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode); + /** + * Send an iq version request coming from nick%hostname@ + */ + void send_iq_version_request(const std::string& nick, const std::string& hostname); /** * Misc -- 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/bridge/bridge.cpp | 11 +++++++++-- src/bridge/bridge.hpp | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 6c85722..f9dc9a6 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -170,13 +170,13 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) this->make_xmpp_body(body), this->user_jid); } -void Bridge::send_private_message(const Iid& iid, const std::string& body) +void Bridge::send_private_message(const Iid& iid, const std::string& body, const std::string& type) { if (iid.chan.empty() || iid.server.empty()) return ; IrcClient* irc = this->get_irc_client(iid.server); if (irc) - irc->send_private_message(iid.chan, body); + irc->send_private_message(iid.chan, body, type); } void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) @@ -207,6 +207,13 @@ void Bridge::set_channel_topic(const Iid& iid, const std::string& subject) irc->send_topic_command(iid.chan, subject); } +void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, const std::string& os) +{ + std::string result(name + " " + version + " " + os); + + this->send_private_message(iid, "\01VERSION "s + result + "\01", "NOTICE"); +} + void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { if (muc) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index f2da8d7..d0fd5bd 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -45,11 +45,12 @@ public: */ bool join_irc_channel(const Iid& iid, const std::string& username); void send_channel_message(const Iid& iid, const std::string& body); - void send_private_message(const Iid& iid, const std::string& body); + void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); void leave_irc_channel(Iid&& iid, std::string&& status_message); void send_irc_nick_change(const Iid& iid, const std::string& new_nick); void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason); void set_channel_topic(const Iid& iid, const std::string& subject); + void send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, const std::string& os); /*** ** -- cgit v1.2.3 From 12c8b1ae0b6f4c2b80d7c787b892ebcaafae6b03 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 15 May 2014 00:21:08 +0200 Subject: Disconnect the user from all its IRC servers whenever he returns an error fix #2524 --- src/bridge/bridge.cpp | 3 +-- src/bridge/bridge.hpp | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index f9dc9a6..b2563f0 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -41,11 +41,10 @@ static std::tuple get_role_affiliation_from_irc_mode(c return std::make_tuple("participant", "none"); } -void Bridge::shutdown() +void Bridge::shutdown(const std::string& exit_message) { for (auto it = this->irc_clients.begin(); it != this->irc_clients.end(); ++it) { - const std::string exit_message("Gateway shutdown"); it->second->send_quit_command(exit_message); it->second->leave_dummy_channel(exit_message); } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index d0fd5bd..f78bade 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -27,11 +27,12 @@ public: /** * QUIT all connected IRC servers. */ - void shutdown(); + void shutdown(const std::string& exit_message); /** * Remove all inactive IrcClients */ void clean(); + static Xmpp::body make_xmpp_body(const std::string& str); /*** ** -- cgit v1.2.3 From 01cd6eb5166c99a83facda804bfa3150e24e8b1e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 18 May 2014 20:23:08 +0200 Subject: Split the messages on \n when sending them back to the XMPP user --- src/bridge/bridge.cpp | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index b2563f0..7a60267 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -135,10 +135,6 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) void Bridge::send_channel_message(const Iid& iid, const std::string& body) { - std::vector lines = utils::split(body, '\n', true); - if (lines.empty()) - return ; - const std::string first_line = lines[0]; if (iid.chan.empty() || iid.server.empty()) { log_warning("Cannot send message to channel: [" << iid.chan << "] on server [" << iid.server << "]"); @@ -150,23 +146,33 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) log_warning("Cannot send message: no client exist for server " << iid.server); return; } - if (first_line.substr(0, 6) == "/mode ") + // 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 + // gateway sees what was actually sent over IRC. For example if an user + // sends “hello\n/me waves”, two messages will be generated: “hello” and + // “/me waves”. Note that the “command” handling (messages starting with + // /me, /mode, etc) is done for each message generated this way. In the + // above example, the /me will be interpreted. + std::vector lines = utils::split(body, '\n', true); + if (lines.empty()) + return ; + for (const std::string& line: lines) { - std::vector args = utils::split(first_line.substr(6), ' ', false); - irc->send_mode_command(iid.chan, args); - return; + if (line.substr(0, 6) == "/mode ") + { + std::vector args = utils::split(line.substr(6), ' ', false); + irc->send_mode_command(iid.chan, args); + continue; // We do not want to send that back to the + // XMPP user, that’s not a textual message. + } + else if (line.substr(0, 4) == "/me ") + irc->send_channel_message(iid.chan, action_prefix + line.substr(4) + "\01"); + else + irc->send_channel_message(iid.chan, line); + this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), + this->make_xmpp_body(line), this->user_jid); } - if (first_line.substr(0, 4) == "/me ") - irc->send_channel_message(iid.chan, action_prefix + first_line.substr(4) + "\01"); - else - irc->send_channel_message(iid.chan, first_line); - // Send each of the other lines of the message as a separate IRC message - for (std::vector::const_iterator it = lines.begin() + 1; it != lines.end(); ++it) - irc->send_channel_message(iid.chan, *it); - // We do not need to convert body to utf-8: it comes from our XMPP server, - // so it's ok to send it back - this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), - this->make_xmpp_body(body), this->user_jid); } void Bridge::send_private_message(const Iid& iid, const std::string& body, const std::string& type) -- cgit v1.2.3 From 7fb0b671bbe6150d60b9f1efd4d8abc885c23844 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 18 May 2014 20:48:42 +0200 Subject: Also do that cut of message on \n for private messages, and handle /me --- src/bridge/bridge.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 7a60267..d803e5e 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -180,8 +180,21 @@ void Bridge::send_private_message(const Iid& iid, const std::string& body, const if (iid.chan.empty() || iid.server.empty()) return ; IrcClient* irc = this->get_irc_client(iid.server); - if (irc) - irc->send_private_message(iid.chan, body, type); + if (!irc) + { + log_warning("Cannot send message: no client exist for server " << iid.server); + return; + } + std::vector lines = utils::split(body, '\n', true); + if (lines.empty()) + return ; + for (const std::string& line: lines) + { + if (line.substr(0, 4) == "/me ") + irc->send_private_message(iid.chan, action_prefix + line.substr(4) + "\01", type); + else + irc->send_private_message(iid.chan, line, type); + } } void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) -- 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/bridge/bridge.cpp | 5 ++--- src/bridge/bridge.hpp | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index d803e5e..78cd2d2 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -14,7 +14,7 @@ using namespace std::string_literals; static const char* action_prefix = "\01ACTION "; -Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller): +Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, std::shared_ptr poller): user_jid(user_jid), xmpp(xmpp), poller(poller) @@ -81,9 +81,8 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string } catch (const std::out_of_range& exception) { - this->irc_clients.emplace(hostname, std::make_shared(hostname, username, this)); + this->irc_clients.emplace(hostname, std::make_shared(this->poller, hostname, username, this)); std::shared_ptr irc = this->irc_clients.at(hostname); - this->poller->add_socket_handler(irc); return irc.get(); } } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index f78bade..37f5b05 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -22,7 +22,7 @@ class Poller; class Bridge { public: - explicit Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller); + explicit Bridge(const std::string& user_jid, XmppComponent* xmpp, std::shared_ptr poller); ~Bridge(); /** * QUIT all connected IRC servers. @@ -146,9 +146,8 @@ private: /** * Poller, to give it the IrcClients that we spawn, to make it manage * their sockets. - * We don't own it. */ - Poller* poller; + std::shared_ptr poller; Bridge(const Bridge&) = delete; Bridge(Bridge&& other) = delete; -- 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/bridge/bridge.cpp | 5 +++++ src/bridge/bridge.hpp | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 78cd2d2..70650a5 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -241,6 +241,11 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st this->make_xmpp_body(body), this->user_jid, "chat"); } +void Bridge::send_join_failed(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& text) +{ + this->xmpp->send_presence_error(iid.chan + "%" + iid.server, nick, this->user_jid, type, condition, text); +} + void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self) { this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->make_xmpp_body(message), this->user_jid, self); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 37f5b05..2618ca6 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -80,6 +80,11 @@ public: * Send a MUC message from some participant */ void send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc); + /** + * Send a presence of type error, from a room. This is used to indicate + * why joining a room failed. + */ + void send_join_failed(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& text); /** * Send an unavailable presence from this participant */ -- 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/bridge/bridge.cpp | 5 +++++ src/bridge/bridge.hpp | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 70650a5..3377135 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -63,6 +63,11 @@ void Bridge::clean() } } +const std::string& Bridge::get_jid() const +{ + return this->user_jid; +} + Xmpp::body Bridge::make_xmpp_body(const std::string& str) { std::string res; diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 2618ca6..9c06947 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -32,6 +32,10 @@ public: * Remove all inactive IrcClients */ void clean(); + /** + * Return the jid of the XMPP user using this bridge + */ + const std::string& get_jid() const; static Xmpp::body make_xmpp_body(const std::string& str); /*** -- cgit v1.2.3 From 3d9183557f3ad9b599c812c03a445453e7d4f703 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sun, 8 Jun 2014 05:35:36 +0200 Subject: Convert \n to
in xhtml body fix #2539 --- src/bridge/colors.cpp | 7 +++++++ src/bridge/colors.hpp | 2 ++ 2 files changed, 9 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index 6f6d7a9..3aed07c 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -77,6 +77,13 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) if (s[pos_end] == IRC_FORMAT_BOLD_CHAR) styles.strong = !styles.strong; + else if (s[pos_end] == IRC_FORMAT_NEWLINE_CHAR) + { + XmlNode* br_node = new XmlNode("br"); + br_node->close(); + current_node->add_child(br_node); + cleaned += '\n'; + } else if (s[pos_end] == IRC_FORMAT_UNDERLINE_CHAR) styles.underline = !styles.underline; else if (s[pos_end] == IRC_FORMAT_ITALIC_CHAR) diff --git a/src/bridge/colors.hpp b/src/bridge/colors.hpp index 82e6faf..b5e6e7b 100644 --- a/src/bridge/colors.hpp +++ b/src/bridge/colors.hpp @@ -28,6 +28,7 @@ namespace Xmpp #define IRC_FORMAT_REVERSE2_CHAR '\x16' // wat #define IRC_FORMAT_ITALIC_CHAR '\x1D' // done #define IRC_FORMAT_UNDERLINE_CHAR '\x1F' // done +#define IRC_FORMAT_NEWLINE_CHAR '\n' // done static const char irc_format_char[] = { IRC_FORMAT_BOLD_CHAR, @@ -38,6 +39,7 @@ static const char irc_format_char[] = { IRC_FORMAT_REVERSE2_CHAR, IRC_FORMAT_ITALIC_CHAR, IRC_FORMAT_UNDERLINE_CHAR, + IRC_FORMAT_NEWLINE_CHAR, '\x00' }; -- 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/bridge/bridge.cpp | 72 +++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 3377135..6d864c0 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -106,8 +106,8 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname) bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) { - IrcClient* irc = this->get_irc_client(iid.server, username); - if (iid.chan.empty()) + IrcClient* irc = this->get_irc_client(iid.get_server(), username); + if (iid.get_local().empty()) { // Join the dummy channel if (irc->is_welcomed()) { @@ -117,7 +117,7 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) // joined the channel const IrcMessage join_message(irc->get_nick(), "JOIN", {""}); irc->on_channel_join(join_message); - const IrcMessage end_join_message(std::string(iid.server), "366", + 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); @@ -129,9 +129,9 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) } return true; } - if (irc->is_channel_joined(iid.chan) == false) + if (irc->is_channel_joined(iid.get_local()) == false) { - irc->send_join_command(iid.chan); + irc->send_join_command(iid.get_local()); return true; } return false; @@ -139,15 +139,15 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) void Bridge::send_channel_message(const Iid& iid, const std::string& body) { - if (iid.chan.empty() || iid.server.empty()) + if (iid.get_local().empty() || iid.get_server().empty()) { - log_warning("Cannot send message to channel: [" << iid.chan << "] on server [" << iid.server << "]"); + log_warning("Cannot send message to channel: [" << iid.get_local() << "] on server [" << iid.get_server() << "]"); return; } - IrcClient* irc = this->get_irc_client(iid.server); + IrcClient* irc = this->get_irc_client(iid.get_server()); if (!irc) { - log_warning("Cannot send message: no client exist for server " << iid.server); + 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 @@ -166,27 +166,27 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) if (line.substr(0, 6) == "/mode ") { std::vector args = utils::split(line.substr(6), ' ', false); - irc->send_mode_command(iid.chan, args); + irc->send_mode_command(iid.get_local(), args); continue; // We do not want to send that back to the // XMPP user, that’s not a textual message. } else if (line.substr(0, 4) == "/me ") - irc->send_channel_message(iid.chan, action_prefix + line.substr(4) + "\01"); + irc->send_channel_message(iid.get_local(), action_prefix + line.substr(4) + "\01"); else - irc->send_channel_message(iid.chan, line); - this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(), + irc->send_channel_message(iid.get_local(), line); + this->xmpp->send_muc_message(std::to_string(iid), irc->get_own_nick(), this->make_xmpp_body(line), this->user_jid); } } void Bridge::send_private_message(const Iid& iid, const std::string& body, const std::string& type) { - if (iid.chan.empty() || iid.server.empty()) + if (iid.get_local().empty() || iid.get_server().empty()) return ; - IrcClient* irc = this->get_irc_client(iid.server); + IrcClient* irc = this->get_irc_client(iid.get_server()); if (!irc) { - log_warning("Cannot send message: no client exist for server " << iid.server); + log_warning("Cannot send message: no client exist for server " << iid.get_server()); return; } std::vector lines = utils::split(body, '\n', true); @@ -195,38 +195,38 @@ void Bridge::send_private_message(const Iid& iid, const std::string& body, const for (const std::string& line: lines) { if (line.substr(0, 4) == "/me ") - irc->send_private_message(iid.chan, action_prefix + line.substr(4) + "\01", type); + irc->send_private_message(iid.get_local(), action_prefix + line.substr(4) + "\01", type); else - irc->send_private_message(iid.chan, line, type); + irc->send_private_message(iid.get_local(), line, type); } } void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) { - IrcClient* irc = this->get_irc_client(iid.server); + IrcClient* irc = this->get_irc_client(iid.get_server()); if (irc) - irc->send_part_command(iid.chan, 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.server); + IrcClient* irc = this->get_irc_client(iid.get_server()); if (irc) irc->send_nick_command(new_nick); } void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason) { - IrcClient* irc = this->get_irc_client(iid.server); + IrcClient* irc = this->get_irc_client(iid.get_server()); if (irc) - irc->send_kick_command(iid.chan, target, reason); + irc->send_kick_command(iid.get_local(), target, reason); } void Bridge::set_channel_topic(const Iid& iid, const std::string& subject) { - IrcClient* irc = this->get_irc_client(iid.server); + IrcClient* irc = this->get_irc_client(iid.get_server()); if (irc) - irc->send_topic_command(iid.chan, 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) @@ -239,22 +239,22 @@ void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, c void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { if (muc) - this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick, + this->xmpp->send_muc_message(std::to_string(iid), nick, this->make_xmpp_body(body), this->user_jid); else - this->xmpp->send_message(iid.chan + "%" + iid.server, + this->xmpp->send_message(std::to_string(iid), this->make_xmpp_body(body), this->user_jid, "chat"); } void Bridge::send_join_failed(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& text) { - this->xmpp->send_presence_error(iid.chan + "%" + iid.server, nick, this->user_jid, type, condition, text); + this->xmpp->send_presence_error(std::to_string(iid), nick, this->user_jid, type, condition, text); } void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self) { - this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->make_xmpp_body(message), this->user_jid, self); - IrcClient* irc = this->get_irc_client(iid.server); + 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()); if (irc && irc->number_of_joined_channels() == 0) irc->send_quit_command(""); } @@ -269,7 +269,7 @@ void Bridge::send_nick_change(Iid&& iid, std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - this->xmpp->send_nick_change(std::move(iid.chan) + "%" + std::move(iid.server), + this->xmpp->send_nick_change(std::to_string(iid), old_nick, new_nick, affiliation, role, this->user_jid, self); } @@ -309,7 +309,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.server); + IrcClient* irc = this->get_irc_client(iid.get_server()); if (irc) return irc->get_own_nick(); return ""; @@ -322,12 +322,12 @@ size_t Bridge::active_clients() const void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author) { - this->xmpp->kick_user(iid.chan + "%" + iid.server, target, reason, author, this->user_jid); + this->xmpp->kick_user(std::to_string(iid), target, reason, author, this->user_jid); } void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname) { - this->xmpp->send_nickname_conflict_error(iid.chan + "%" + iid.server, nickname, this->user_jid); + this->xmpp->send_nickname_conflict_error(std::to_string(iid), nickname, this->user_jid); } void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode) @@ -336,10 +336,10 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar std::string affiliation; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(mode); - this->xmpp->send_affiliation_role_change(iid.chan + "%" + iid.server, target, affiliation, role, this->user_jid); + this->xmpp->send_affiliation_role_change(std::to_string(iid), target, affiliation, role, this->user_jid); } void Bridge::send_iq_version_request(const std::string& nick, const std::string& hostname) { - this->xmpp->send_iq_version_request(nick + "%" + hostname, this->user_jid); + this->xmpp->send_iq_version_request(nick + "!" + hostname, this->user_jid); } -- cgit v1.2.3 From 56eb5df28a1023db2039388fe6c8fc1346da1a3d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 18 Jun 2014 18:46:41 +0200 Subject: Mini comment fix --- src/bridge/bridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 9c06947..814222b 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -111,7 +111,7 @@ public: */ void send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode); /** - * Send an iq version request coming from nick%hostname@ + * Send an iq version request coming from nick!hostname@ */ void send_iq_version_request(const std::string& nick, const std::string& hostname); -- cgit v1.2.3 From 04de62a4e0af4843e84c933e16f249ba1df6874f Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 18 Jun 2014 22:42:58 +0200 Subject: Messages to room participants are forwarded to the IRC user For example, both JID #chan%server@biboumi/Toto and toto!server@biboumi are equivalent, except that if you send a message to the first one, subsequent messages coming from the user toto will come from that same JID. This is done to be consistent for the XMPP user, and respond from the same JID than the 'to' of the first message. fix #2468 --- src/bridge/bridge.cpp | 30 ++++++++++++++++++++++++++++-- src/bridge/bridge.hpp | 16 ++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 6d864c0..a0964df 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -242,8 +242,18 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st this->xmpp->send_muc_message(std::to_string(iid), nick, this->make_xmpp_body(body), this->user_jid); else - this->xmpp->send_message(std::to_string(iid), - this->make_xmpp_body(body), this->user_jid, "chat"); + { + std::string target = std::to_string(iid); + bool fulljid = false; + auto it = this->preferred_user_from.find(iid.get_local()); + if (it != this->preferred_user_from.end()) + { + target = it->second; + fulljid = true; + } + this->xmpp->send_message(target, this->make_xmpp_body(body), + this->user_jid, "chat", fulljid); + } } void Bridge::send_join_failed(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& text) @@ -343,3 +353,19 @@ void Bridge::send_iq_version_request(const std::string& nick, const std::string& { this->xmpp->send_iq_version_request(nick + "!" + hostname, this->user_jid); } + +void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid) +{ + auto it = this->preferred_user_from.find(nick); + if (it == this->preferred_user_from.end()) + this->preferred_user_from.emplace(nick, full_jid); + else + this->preferred_user_from[nick] = full_jid; +} + +void Bridge::remove_preferred_from_jid(const std::string& nick) +{ + auto it = this->preferred_user_from.find(nick); + if (it != this->preferred_user_from.end()) + this->preferred_user_from.erase(it); +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 814222b..8711829 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -123,6 +123,14 @@ public: * Get the number of server to which this bridge is connected or connecting. */ size_t active_clients() const; + /** + * Add (or replace the existing) into the preferred_user_from map + */ + void set_preferred_from_jid(const std::string& nick, const std::string& full_jid); + /** + * Remove the preferred jid for the given IRC nick + */ + void remove_preferred_from_jid(const std::string& nick); private: /** @@ -157,6 +165,14 @@ private: * their sockets. */ std::shared_ptr poller; + /** + * A map of . For example if this map contains <"toto", + * "#somechan%server@biboumi/ToTo">, whenever a private message is + * received from the user "toto", instead of forwarding it to XMPP with + * from='toto!server@biboumi', we use instead + * from='#somechan%server@biboumi/ToTo' + */ + std::unordered_map preferred_user_from; Bridge(const Bridge&) = delete; Bridge(Bridge&& other) = delete; -- 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/bridge/bridge.cpp | 18 ++++++++++++++++++ src/bridge/bridge.hpp | 26 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index a0964df..c2ac11f 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -369,3 +370,20 @@ void Bridge::remove_preferred_from_jid(const std::string& nick) if (it != this->preferred_user_from.end()) this->preferred_user_from.erase(it); } + +void Bridge::add_waiting_iq(iq_responder_callback_t&& callback) +{ + this->waiting_iq.emplace_back(std::move(callback)); +} + +void Bridge::trigger_response_iq(const std::string& irc_hostname, const IrcMessage& message) +{ + auto it = this->waiting_iq.begin(); + while (it != this->waiting_iq.end()) + { + if ((*it)(irc_hostname, message) == true) + it = this->waiting_iq.erase(it); + else + ++it; + } +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 8711829..0983595 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -7,12 +7,21 @@ #include #include +#include #include #include class XmppComponent; class Poller; +/** + * A callback called for each IrcMessage we receive. If the message triggers + * a response, it must send an iq and return true (in that case it is + * removed from the list), otherwise it must do nothing and just return + * false. + */ +typedef std::function iq_responder_callback_t; + /** * One bridge is spawned for each XMPP user that uses the component. The * bridge spawns IrcClients when needed (when the user wants to join a @@ -131,6 +140,16 @@ public: * Remove the preferred jid for the given IRC nick */ void remove_preferred_from_jid(const std::string& nick); + /** + * Add a callback to the waiting iq list. + */ + void add_waiting_iq(iq_responder_callback_t&& callback); + /** + * Iter over all the waiting_iq, call the iq_responder_filter_t for each, + * whenever one of them returns true: call the corresponding + * iq_responder_callback_t and remove the callback from the list. + */ + void trigger_response_iq(const std::string& irc_hostname, const IrcMessage& message); private: /** @@ -173,6 +192,13 @@ private: * from='#somechan%server@biboumi/ToTo' */ std::unordered_map preferred_user_from; + /** + * A list of callbacks that are waiting for some IrcMessage to trigger a + * response. We add callbacks in this list whenever we received an IQ + * request and we need a response from IRC to be able to provide the + * response iq. + */ + std::list waiting_iq; Bridge(const Bridge&) = delete; Bridge(Bridge&& other) = delete; -- cgit v1.2.3 From 2117838cf9fb083f6f74386abbb56e3b28d4db46 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 19 Jun 2014 22:22:29 +0200 Subject: =?UTF-8?q?Return=20a=20proper=20iq=20when=20the=20IRC=E2=80=AFser?= =?UTF-8?q?ver=20responds=20to=20our=20kick?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A result or an error, depending on the type of message --- src/bridge/bridge.cpp | 42 ++++++++++++++++++++++++++++++++++++++++-- src/bridge/bridge.hpp | 4 +++- 2 files changed, 43 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index c2ac11f..384131f 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -216,11 +216,49 @@ void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick) irc->send_nick_command(new_nick); } -void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason) +void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason, + const std::string& iq_id, const std::string& to_jid) { IrcClient* irc = this->get_irc_client(iid.get_server()); if (irc) - irc->send_kick_command(iid.get_local(), target, reason); + { + irc->send_kick_command(iid.get_local(), target, reason); + this->add_waiting_iq([this, target, iq_id, to_jid, iid](const std::string& irc_hostname, const IrcMessage& message){ + if (irc_hostname != iid.get_server()) + return false; + if (message.command == "KICK" && message.arguments.size() >= 2) + { + const std::string target_later = message.arguments[1]; + const std::string chan_name_later = utils::tolower(message.arguments[0]); + if (target_later != target || chan_name_later != iid.get_local()) + return false; + this->xmpp->send_iq_result(iq_id, to_jid, std::to_string(iid)); + } + else if (message.command == "401" && message.arguments.size() >= 2) + { + const std::string target_later = message.arguments[1]; + if (target_later != target) + return false; + std::string error_message = "No such nick"; + if (message.arguments.size() >= 3) + error_message = message.arguments[2]; + this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "item-not-found", + error_message, false); + } + else if (message.command == "482" && message.arguments.size() >= 2) + { + const std::string chan_name_later = utils::tolower(message.arguments[1]); + if (chan_name_later != iid.get_local()) + return false; + std::string error_message = "You're not channel operator"; + if (message.arguments.size() >= 3) + error_message = message.arguments[2]; + this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "not-allowed", + error_message, false); + } + return true; + }); + } } void Bridge::set_channel_topic(const Iid& iid, const std::string& subject) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 0983595..9eb239d 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -1,6 +1,7 @@ #ifndef BRIDGE_INCLUDED # define BRIDGE_INCLUDED +#include #include #include #include @@ -62,7 +63,8 @@ public: void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); void leave_irc_channel(Iid&& iid, std::string&& status_message); void send_irc_nick_change(const Iid& iid, const std::string& new_nick); - void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason); + void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason, + const std::string& iq_id, const std::string& to_jid); void set_channel_topic(const Iid& iid, const std::string& subject); void send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, const std::string& os); -- cgit v1.2.3 From 545ab11ff3a334b242ba2d7fc87e2b6ba0185cb5 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 18 Jun 2014 11:46:28 +0200 Subject: Support version request to IRC users --- src/bridge/bridge.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/bridge/bridge.hpp | 6 +++++- 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 384131f..9501d47 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -275,6 +275,42 @@ void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, c this->send_private_message(iid, "\01VERSION "s + result + "\01", "NOTICE"); } +void Bridge::send_irc_version_request(const std::string& irc_hostname, const std::string& target, + const std::string& iq_id, const std::string& to_jid, + const std::string& from_jid) +{ + Iid iid(target + "!" + irc_hostname); + this->send_private_message(iid, "\01VERSION\01"); + + // TODO, add a timer to remove that waiting iq if the server does not + // respond with a matching command before n seconds + this->add_waiting_iq([this, target, iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message){ + if (irc_hostname != hostname) + return false; + IrcUser user(message.prefix); + if (message.command == "NOTICE" && user.nick == target && + message.arguments.size() >= 2 && message.arguments[1].substr(0, 9) == "\01VERSION ") + { + // remove the "\01VERSION " and the "\01" parts from the string + const std::string version = message.arguments[1].substr(9, message.arguments[1].size() - 10); + this->xmpp->send_version(iq_id, to_jid, from_jid, version); + return true; + } + if (message.command == "401" && message.arguments.size() >= 2 + && message.arguments[1] == target) + { + std::string error_message = "No such nick"; + if (message.arguments.size() >= 3) + error_message = message.arguments[2]; + this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found", + error_message, true); + return true; + } + return false; + }); +} + + void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { if (muc) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 9eb239d..a75b319 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -66,7 +66,11 @@ public: void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason, const std::string& iq_id, const std::string& to_jid); void set_channel_topic(const Iid& iid, const std::string& subject); - void send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, const std::string& os); + void send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, + const std::string& os); + void send_irc_version_request(const std::string& irc_hostname, const std::string& target, + const std::string& iq_id, const std::string& to_jid, + const std::string& from_jid); /*** ** -- 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/bridge/bridge.cpp | 8 +++++--- src/bridge/bridge.hpp | 5 ++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 9501d47..ba4911a 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -331,9 +331,11 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st } } -void Bridge::send_join_failed(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& text) +void Bridge::send_presence_error(const Iid& iid, const std::string& nick, + const std::string& type, const std::string& condition, + const std::string& error_code, const std::string& text) { - this->xmpp->send_presence_error(std::to_string(iid), nick, this->user_jid, type, condition, text); + this->xmpp->send_presence_error(std::to_string(iid), nick, this->user_jid, type, condition, error_code, text); } void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self) @@ -412,7 +414,7 @@ void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::stri void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname) { - this->xmpp->send_nickname_conflict_error(std::to_string(iid), nickname, this->user_jid); + this->xmpp->send_presence_error(std::to_string(iid), nickname, this->user_jid, "cancel", "conflict", "409", ""); } void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index a75b319..b0e6a27 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -100,10 +100,9 @@ public: */ void send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc); /** - * Send a presence of type error, from a room. This is used to indicate - * why joining a room failed. + * Send a presence of type error, from a room. */ - void send_join_failed(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& text); + void send_presence_error(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& error_code, const std::string& text); /** * Send an unavailable presence from this participant */ -- 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/bridge/bridge.cpp | 98 +++++++++++++++++++++++++++------------------------ src/bridge/bridge.hpp | 14 ++++---- 2 files changed, 59 insertions(+), 53 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index ba4911a..bc89073 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -220,45 +221,49 @@ void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std: const std::string& iq_id, const std::string& to_jid) { IrcClient* irc = this->get_irc_client(iid.get_server()); - if (irc) + + 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 { - irc->send_kick_command(iid.get_local(), target, reason); - this->add_waiting_iq([this, target, iq_id, to_jid, iid](const std::string& irc_hostname, const IrcMessage& message){ - if (irc_hostname != iid.get_server()) + if (irc_hostname != iid.get_server()) + return false; + if (message.command == "KICK" && message.arguments.size() >= 2) + { + const std::string target_later = message.arguments[1]; + const std::string chan_name_later = utils::tolower(message.arguments[0]); + if (target_later != target || chan_name_later != iid.get_local()) return false; - if (message.command == "KICK" && message.arguments.size() >= 2) - { - const std::string target_later = message.arguments[1]; - const std::string chan_name_later = utils::tolower(message.arguments[0]); - if (target_later != target || chan_name_later != iid.get_local()) - return false; - this->xmpp->send_iq_result(iq_id, to_jid, std::to_string(iid)); - } - else if (message.command == "401" && message.arguments.size() >= 2) - { - const std::string target_later = message.arguments[1]; - if (target_later != target) - return false; - std::string error_message = "No such nick"; - if (message.arguments.size() >= 3) - error_message = message.arguments[2]; - this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "item-not-found", - error_message, false); - } - else if (message.command == "482" && message.arguments.size() >= 2) - { - const std::string chan_name_later = utils::tolower(message.arguments[1]); - if (chan_name_later != iid.get_local()) - return false; - std::string error_message = "You're not channel operator"; - if (message.arguments.size() >= 3) - error_message = message.arguments[2]; - this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "not-allowed", - error_message, false); - } - return true; - }); - } + this->xmpp->send_iq_result(iq_id, to_jid, std::to_string(iid)); + } + else if (message.command == "401" && message.arguments.size() >= 2) + { + const std::string target_later = message.arguments[1]; + if (target_later != target) + return false; + std::string error_message = "No such nick"; + if (message.arguments.size() >= 3) + error_message = message.arguments[2]; + this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "item-not-found", + error_message, false); + } + else if (message.command == "482" && message.arguments.size() >= 2) + { + const std::string chan_name_later = utils::tolower(message.arguments[1]); + if (chan_name_later != iid.get_local()) + return false; + std::string error_message = "You're not channel operator"; + if (message.arguments.size() >= 3) + error_message = message.arguments[2]; + this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "not-allowed", + error_message, false); + } + return true; + }; + this->add_waiting_irc(std::move(cb)); } void Bridge::set_channel_topic(const Iid& iid, const std::string& subject) @@ -284,7 +289,8 @@ void Bridge::send_irc_version_request(const std::string& irc_hostname, const std // TODO, add a timer to remove that waiting iq if the server does not // respond with a matching command before n seconds - this->add_waiting_iq([this, target, iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message){ + irc_responder_callback_t cb = [this, target, iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message) -> bool + { if (irc_hostname != hostname) return false; IrcUser user(message.prefix); @@ -307,10 +313,10 @@ void Bridge::send_irc_version_request(const std::string& irc_hostname, const std return true; } return false; - }); + }; + this->add_waiting_irc(std::move(cb)); } - void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { if (muc) @@ -447,18 +453,18 @@ void Bridge::remove_preferred_from_jid(const std::string& nick) this->preferred_user_from.erase(it); } -void Bridge::add_waiting_iq(iq_responder_callback_t&& callback) +void Bridge::add_waiting_irc(irc_responder_callback_t&& callback) { - this->waiting_iq.emplace_back(std::move(callback)); + this->waiting_irc.emplace_back(std::move(callback)); } -void Bridge::trigger_response_iq(const std::string& irc_hostname, const IrcMessage& message) +void Bridge::trigger_on_irc_message(const std::string& irc_hostname, const IrcMessage& message) { - auto it = this->waiting_iq.begin(); - while (it != this->waiting_iq.end()) + auto it = this->waiting_irc.begin(); + while (it != this->waiting_irc.end()) { if ((*it)(irc_hostname, message) == true) - it = this->waiting_iq.erase(it); + it = this->waiting_irc.erase(it); else ++it; } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index b0e6a27..1f45b27 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -17,11 +17,11 @@ class Poller; /** * A callback called for each IrcMessage we receive. If the message triggers - * a response, it must send an iq and return true (in that case it is - * removed from the list), otherwise it must do nothing and just return + * a response, it must send ore or more iq and return true (in that case it + * is removed from the list), otherwise it must do nothing and just return * false. */ -typedef std::function iq_responder_callback_t; +using irc_responder_callback_t = std::function; /** * One bridge is spawned for each XMPP user that uses the component. The @@ -146,15 +146,15 @@ public: */ void remove_preferred_from_jid(const std::string& nick); /** - * Add a callback to the waiting iq list. + * Add a callback to the waiting list of irc callbacks. */ - void add_waiting_iq(iq_responder_callback_t&& callback); + void add_waiting_irc(irc_responder_callback_t&& callback); /** * Iter over all the waiting_iq, call the iq_responder_filter_t for each, * whenever one of them returns true: call the corresponding * iq_responder_callback_t and remove the callback from the list. */ - void trigger_response_iq(const std::string& irc_hostname, const IrcMessage& message); + void trigger_on_irc_message(const std::string& irc_hostname, const IrcMessage& message); private: /** @@ -203,7 +203,7 @@ private: * request and we need a response from IRC to be able to provide the * response iq. */ - std::list waiting_iq; + std::list waiting_irc; Bridge(const Bridge&) = delete; Bridge(Bridge&& other) = delete; -- 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/bridge/bridge.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/bridge/bridge.hpp | 13 +++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index bc89073..08fd569 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -280,6 +282,50 @@ void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, c this->send_private_message(iid, "\01VERSION "s + result + "\01", "NOTICE"); } +void Bridge::send_irc_ping_result(const Iid& iid, const std::string& id) +{ + this->send_private_message(iid, "\01PING "s + utils::revstr(id), "NOTICE"); +} + +void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const std::string& nick, + const std::string& iq_id, const std::string& to_jid, + const std::string& from_jid) +{ + Iid iid(nick + "!" + irc_hostname); + this->send_private_message(iid, "\01PING " + iq_id + "\01"); + + irc_responder_callback_t cb = [this, nick, iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message) -> bool + { + if (irc_hostname != hostname) + return false; + IrcUser user(message.prefix); + const std::string body = message.arguments[1]; + if (message.command == "NOTICE" && user.nick == nick && + message.arguments.size() >= 2 && body.substr(0, 6) == "\01PING ") + { + const std::string id = body.substr(6, body.size() - 6); + if (id != iq_id) + return false; + Jid jid(from_jid); + this->xmpp->send_iq_result(iq_id, to_jid, jid.local); + return true; + } + if (message.command == "401" && message.arguments.size() >= 2 + && message.arguments[1] == nick) + { + std::string error_message = "No such nick"; + if (message.arguments.size() >= 3) + error_message = message.arguments[2]; + this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "service-unavailable", + error_message, true); + return true; + } + + return false; + }; + this->add_waiting_irc(std::move(cb)); +} + void Bridge::send_irc_version_request(const std::string& irc_hostname, const std::string& target, const std::string& iq_id, const std::string& to_jid, const std::string& from_jid) @@ -437,6 +483,15 @@ void Bridge::send_iq_version_request(const std::string& nick, const std::string& this->xmpp->send_iq_version_request(nick + "!" + hostname, this->user_jid); } +void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& hostname, + const std::string& id) +{ + // Use revstr because the forwarded ping to target XMPP user must not be + // the same that the request iq, but we also need to get it back easily + // (revstr again) + this->xmpp->send_ping_request(nick + "!" + hostname, this->user_jid, utils::revstr(id)); +} + void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid) { auto it = this->preferred_user_from.find(nick); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 1f45b27..f7edfaa 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -68,9 +68,16 @@ public: void set_channel_topic(const Iid& iid, const std::string& subject); void send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version, const std::string& os); + void send_irc_ping_result(const Iid& iid, const std::string& id); void send_irc_version_request(const std::string& irc_hostname, const std::string& target, const std::string& iq_id, const std::string& to_jid, const std::string& from_jid); + /** + * Directly send a CTCP PING request to the IRC user + */ + void send_irc_user_ping_request(const std::string& irc_hostname, const std::string& nick, + const std::string& iq_id, const std::string& to_jid, + const std::string& from_jid); /*** ** @@ -128,7 +135,11 @@ public: * Send an iq version request coming from nick!hostname@ */ void send_iq_version_request(const std::string& nick, const std::string& hostname); - + /** + * Send an iq ping request coming from nick!hostname@ + */ + void send_xmpp_ping_request(const std::string& nick, const std::string& hostname, + const std::string& id); /** * Misc */ -- cgit v1.2.3 From 4a8bcd3cbde0a41902999db7acc346de020cf564 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 12 Nov 2014 07:51:10 +0100 Subject: Implement PING to in-room participant ref #2575 --- src/bridge/bridge.cpp | 30 +++++++++++++++++++++++++++++- src/bridge/bridge.hpp | 7 +++++++ 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 08fd569..ed61c6b 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -326,13 +326,41 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s this->add_waiting_irc(std::move(cb)); } +void Bridge::send_irc_participant_ping_request(const Iid& iid, const std::string& nick, + const std::string& iq_id, const std::string& to_jid, + 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) + { + this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "not-allowed", + "", true); + return; + } + if (chan->get_self()->nick != nick && !chan->find_user(nick)) + { + this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found", + "Recipient not in room", true); + return; + } + + // The user is in the room, send it a direct PING + this->send_irc_user_ping_request(iid.get_server(), nick, iq_id, to_jid, from_jid); +} + void Bridge::send_irc_version_request(const std::string& irc_hostname, const std::string& target, const std::string& iq_id, const std::string& to_jid, const std::string& from_jid) { Iid iid(target + "!" + irc_hostname); this->send_private_message(iid, "\01VERSION\01"); - // TODO, add a timer to remove that waiting iq if the server does not // respond with a matching command before n seconds irc_responder_callback_t cb = [this, target, iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message) -> bool diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index f7edfaa..6d09fff 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -78,6 +78,13 @@ public: void send_irc_user_ping_request(const std::string& irc_hostname, const std::string& nick, const std::string& iq_id, const std::string& to_jid, const std::string& from_jid); + /** + * First check if the participant is in the room, before sending a direct + * CTCP PING request to the IRC user + */ + void send_irc_participant_ping_request(const Iid& iid, const std::string& nick, + const std::string& iq_id, const std::string& to_jid, + const std::string& from_jid); /*** ** -- cgit v1.2.3 From 12eeb4d11eee5b8e6514f0ce8bf7508cc2d6d7a1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 12 Nov 2014 08:10:46 +0100 Subject: Implement the PING on a server or the gateway itself fix #2575 --- src/bridge/bridge.cpp | 11 +++++++++++ src/bridge/bridge.hpp | 6 ++++++ 2 files changed, 17 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index ed61c6b..a7d8fe6 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -355,6 +355,17 @@ void Bridge::send_irc_participant_ping_request(const Iid& iid, const std::string this->send_irc_user_ping_request(iid.get_server(), nick, iq_id, to_jid, from_jid); } +void Bridge::on_gateway_ping(const std::string& irc_hostname, const std::string& iq_id, const std::string& to_jid, + const std::string& from_jid) +{ + Jid jid(from_jid); + if (irc_hostname.empty() || this->get_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", + "", true); +} + void Bridge::send_irc_version_request(const std::string& irc_hostname, const std::string& target, const std::string& iq_id, const std::string& to_jid, const std::string& from_jid) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 6d09fff..cf39545 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -85,6 +85,12 @@ public: void send_irc_participant_ping_request(const Iid& iid, const std::string& nick, const std::string& iq_id, const std::string& to_jid, const std::string& from_jid); + /** + * Directly send back a result if it's a gateway ping or if we are + * connected to the given IRC server, an error otherwise. + */ + void on_gateway_ping(const std::string& irc_hostname, const std::string& iq_id, const std::string& to_jid, + const std::string& from_jid); /*** ** -- 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/bridge/bridge.cpp | 2 +- src/bridge/bridge.hpp | 2 +- src/bridge/colors.cpp | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index a7d8fe6..c925f9e 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -480,7 +480,7 @@ void Bridge::send_user_join(const std::string& hostname, affiliation, role, this->user_jid, self); } -void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic) +void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic) { this->xmpp->send_topic(chan_name + "%" + hostname, this->make_xmpp_body(topic), this->user_jid); } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index cf39545..c20bba2 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -114,7 +114,7 @@ public: /** * Send the topic of the MUC to the user */ - void send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic); + void send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic); /** * Send a MUC message from some participant */ diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index 3aed07c..3d40ac4 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -166,10 +166,8 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) { current_node->close(); result->add_child(current_node); - current_node = result.get(); } - result->close(); Xmpp::body body_res = std::make_tuple(cleaned, std::move(result)); return body_res; -- 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/bridge/bridge.cpp | 4 ++-- src/bridge/bridge.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index c925f9e..5fa96c8 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -108,7 +108,7 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname) } } -bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) +bool Bridge::join_irc_channel(const Iid& iid, const std::string& username, const std::string& password) { IrcClient* irc = this->get_irc_client(iid.get_server(), username); if (iid.get_local().empty()) @@ -135,7 +135,7 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& username) } if (irc->is_channel_joined(iid.get_local()) == false) { - irc->send_join_command(iid.get_local()); + irc->send_join_command(iid.get_local(), password); return true; } return false; diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index c20bba2..698a017 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -58,7 +58,7 @@ 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& username); + bool join_irc_channel(const Iid& iid, const std::string& username, const std::string& password = ""); void send_channel_message(const Iid& iid, const std::string& body); void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); void leave_irc_channel(Iid&& iid, std::string&& status_message); -- cgit v1.2.3 From f9e259c266e5e9247562f899bafd5ddd2aa46099 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 14 Jan 2015 13:36:42 +0100 Subject: Fix a little bit of style stuf from previous commit --- src/bridge/bridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 698a017..13cac23 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -58,7 +58,7 @@ 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& username, const std::string& password = ""); + bool join_irc_channel(const Iid& iid, const std::string& username, const std::string& password); void send_channel_message(const Iid& iid, const std::string& body); void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); void leave_irc_channel(Iid&& iid, std::string&& status_message); -- cgit v1.2.3 From 2c5d3d89b0eb1e6b8d888b4d37ceca6f23c2e314 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 24 Jan 2015 16:19:13 +0100 Subject: Change IRC modes when receiving an affiliation/role change request fix #2946 --- src/bridge/bridge.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/bridge/bridge.hpp | 2 ++ 2 files changed, 68 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 5fa96c8..fc00c8c 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -183,6 +183,72 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) } } +void Bridge::forward_affiliation_role_change(const Iid& iid, const std::string& nick, + const std::string& affiliation, + 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; + IrcUser* user = chan->find_user(nick); + if (!user) + return; + // For each affiliation or role, we have a “maximal” mode that we want to + // set. We must remove any superior mode at the same time. For example if + // the user already has +o mode, and we set its affiliation to member, we + // remove the +o mode, and add +v. For each “superior” mode (for example, + // for +v, the superior modes are 'h', 'a', 'o' and 'q') we check if that + // user has it, and if yes we remove that mode + + std::size_t nb = 1; // the number of times the nick must be + // repeated in the argument list + std::string modes; // The string of modes to + // add/remove. For example "+v-aoh" + std::vector modes_to_remove; // List of modes to check for removal + if (affiliation == "none") + { + modes = ""; + nb = 0; + modes_to_remove = {'v', 'h', 'o', 'a', 'q'}; + } + else if (affiliation == "member") + { + modes = "+v"; + modes_to_remove = {'h', 'o', 'a', 'q'}; + } + else if (role == "moderator") + { + modes = "+h"; + modes_to_remove = {'o', 'a', 'q'}; + } + else if (affiliation == "admin") + { + modes = "+o"; + modes_to_remove = {'a', 'q'}; + } + else if (affiliation == "owner") + { + modes = "+a"; + modes_to_remove = {'q'}; + } + else + return; + for (const char mode: modes_to_remove) + if (user->modes.find(mode) != user->modes.end()) + { + modes += "-"s + mode; + nb++; + } + if (modes.empty()) + return; + std::vector args(nb, nick); + args.insert(args.begin(), modes); + irc->send_mode_command(iid.get_local(), args); +} + 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()) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 13cac23..b1f79d5 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -72,6 +72,8 @@ public: void send_irc_version_request(const std::string& irc_hostname, const std::string& target, const std::string& iq_id, const std::string& to_jid, const std::string& from_jid); + void forward_affiliation_role_change(const Iid& iid, const std::string& nick, + const std::string& affiliation, const std::string& role); /** * Directly send a CTCP PING request to the IRC user */ -- 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/bridge/bridge.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index fc00c8c..e312345 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -542,13 +543,13 @@ void Bridge::send_user_join(const std::string& hostname, std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host, + this->xmpp->send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, affiliation, role, this->user_jid, self); } void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic) { - this->xmpp->send_topic(chan_name + "%" + hostname, this->make_xmpp_body(topic), this->user_jid); + this->xmpp->send_topic(chan_name + utils::empty_if_fixed_server("%" + hostname), this->make_xmpp_body(topic), this->user_jid); } std::string Bridge::get_own_nick(const Iid& iid) @@ -585,7 +586,7 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar void Bridge::send_iq_version_request(const std::string& nick, const std::string& hostname) { - this->xmpp->send_iq_version_request(nick + "!" + hostname, this->user_jid); + this->xmpp->send_iq_version_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid); } void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& hostname, @@ -594,7 +595,7 @@ void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& // Use revstr because the forwarded ping to target XMPP user must not be // the same that the request iq, but we also need to get it back easily // (revstr again) - this->xmpp->send_ping_request(nick + "!" + hostname, this->user_jid, utils::revstr(id)); + this->xmpp->send_ping_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid, utils::revstr(id)); } void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid) -- 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/bridge/bridge.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/bridge/bridge.hpp | 2 ++ src/bridge/list_element.hpp | 19 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 src/bridge/list_element.hpp (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index fc00c8c..2e3520d 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -285,6 +286,43 @@ void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick) irc->send_nick_command(new_nick); } +void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq_id, + const std::string& to_jid) +{ + 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 + { + static std::vector list; + + if (irc_hostname != iid.get_server()) + return false; + if (message.command == "263" || message.command == "RPL_TRYAGAIN") + { // TODO send an error iq + return true; + } + else if (message.command == "322" || message.command == "RPL_LIST") + { // Add element to list + if (message.arguments.size() == 4) + list.emplace_back(message.arguments[1], message.arguments[2], + message.arguments[3]); + return false; + } + else if (message.command == "323" || message.command == "RPL_LISTEND") + { // Send the iq response with the content of the list + this->xmpp->send_iq_room_list_result(iq_id, to_jid, std::to_string(iid), list); + return true; + } + return false; + }; + this->add_waiting_irc(std::move(cb)); +} + void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason, const std::string& iq_id, const std::string& to_jid) { diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index b1f79d5..8f71846 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -72,6 +72,8 @@ public: void send_irc_version_request(const std::string& irc_hostname, const std::string& target, const std::string& iq_id, const std::string& to_jid, const std::string& from_jid); + void send_irc_channel_list_request(const Iid& iid, const std::string& iq_id, + const std::string& to_jid); void forward_affiliation_role_change(const Iid& iid, const std::string& nick, const std::string& affiliation, const std::string& role); /** diff --git a/src/bridge/list_element.hpp b/src/bridge/list_element.hpp new file mode 100644 index 0000000..bd28185 --- /dev/null +++ b/src/bridge/list_element.hpp @@ -0,0 +1,19 @@ +#ifndef LIST_ELEMENT_HPP_INCLUDED +#define LIST_ELEMENT_HPP_INCLUDED + +#include + +struct ListElement +{ + ListElement(const std::string& channel, const std::string& nb_users, + const std::string& topic): + channel(channel), + nb_users(nb_users), + topic(topic){} + + std::string channel; + std::string nb_users; + std::string topic; +}; + +#endif /* LIST_ELEMENT_HPP_INCLUDED */ -- 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/bridge/bridge.cpp | 4 ++-- src/bridge/bridge.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 1a205bd..85049b9 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include @@ -20,7 +20,7 @@ using namespace std::string_literals; static const char* action_prefix = "\01ACTION "; -Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, std::shared_ptr poller): +Bridge::Bridge(const std::string& user_jid, BiboumiComponent* xmpp, std::shared_ptr poller): user_jid(user_jid), xmpp(xmpp), poller(poller) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 8f71846..c50b7ab 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -12,7 +12,7 @@ #include #include -class XmppComponent; +class BiboumiComponent; class Poller; /** @@ -32,7 +32,7 @@ using irc_responder_callback_t = std::function poller); + explicit Bridge(const std::string& user_jid, BiboumiComponent* xmpp, std::shared_ptr poller); ~Bridge(); /** * QUIT all connected IRC servers. @@ -211,7 +211,7 @@ private: * but we still need to communicate with it, when sending messages from * IRC to XMPP. */ - XmppComponent* xmpp; + BiboumiComponent* xmpp; /** * Poller, to give it the IrcClients that we spawn, to make it manage * their sockets. -- 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/bridge/bridge.cpp | 11 +++++++++++ src/bridge/bridge.hpp | 1 + 2 files changed, 12 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 85049b9..45cdc01 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -273,6 +273,17 @@ 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()); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index c50b7ab..cc9d042 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -61,6 +61,7 @@ public: bool join_irc_channel(const Iid& iid, const std::string& username, const std::string& password); void send_channel_message(const Iid& iid, const std::string& body); 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, std::string&& status_message); void send_irc_nick_change(const Iid& iid, const std::string& new_nick); void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason, -- cgit v1.2.3 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 ++++++++++-- 2 files changed, 46 insertions(+), 41 deletions(-) (limited to 'src/bridge') 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 -- 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/bridge/bridge.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 16264d4..4bfd1b2 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -409,13 +409,13 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s Iid iid(nick + "!" + irc_hostname); this->send_private_message(iid, "\01PING " + iq_id + "\01"); - irc_responder_callback_t cb = [this, nick, iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message) -> bool + irc_responder_callback_t cb = [this, nick=utils::tolower(nick), iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message) -> bool { if (irc_hostname != hostname) return false; IrcUser user(message.prefix); const std::string body = message.arguments[1]; - if (message.command == "NOTICE" && user.nick == nick && + if (message.command == "NOTICE" && utils::tolower(user.nick) == nick && message.arguments.size() >= 2 && body.substr(0, 6) == "\01PING ") { const std::string id = body.substr(6, body.size() - 6); -- cgit v1.2.3 From cc1255d216bf7ac6029a5dd3bc8aadae06df446b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 11 May 2015 05:31:47 +0200 Subject: Fix the way we check for the PING id --- src/bridge/bridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 4bfd1b2..8c364ee 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -418,7 +418,7 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s if (message.command == "NOTICE" && utils::tolower(user.nick) == nick && message.arguments.size() >= 2 && body.substr(0, 6) == "\01PING ") { - const std::string id = body.substr(6, body.size() - 6); + const std::string id = body.substr(6, body.size() - 7); if (id != iq_id) return false; Jid jid(from_jid); -- cgit v1.2.3 From 763be827c9349d39adbdd8cf731565bef316a01a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 11 May 2015 05:43:32 +0200 Subject: Fix a message.arguments size check --- src/bridge/bridge.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 8c364ee..ef20351 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -411,13 +411,14 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s irc_responder_callback_t cb = [this, nick=utils::tolower(nick), iq_id, to_jid, irc_hostname, from_jid](const std::string& hostname, const IrcMessage& message) -> bool { - if (irc_hostname != hostname) + if (irc_hostname != hostname || message.arguments.size() < 2) return false; IrcUser user(message.prefix); const std::string body = message.arguments[1]; - if (message.command == "NOTICE" && utils::tolower(user.nick) == nick && - message.arguments.size() >= 2 && body.substr(0, 6) == "\01PING ") + if (message.command == "NOTICE" && utils::tolower(user.nick) == nick + && body.substr(0, 6) == "\01PING ") { + return false; const std::string id = body.substr(6, body.size() - 7); if (id != iq_id) return false; @@ -425,8 +426,7 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s this->xmpp->send_iq_result(iq_id, to_jid, jid.local); return true; } - if (message.command == "401" && message.arguments.size() >= 2 - && message.arguments[1] == nick) + if (message.command == "401" && message.arguments[1] == nick) { std::string error_message = "No such nick"; if (message.arguments.size() >= 3) -- cgit v1.2.3 From 501a3f7be25f4dbb4526bf645d7df8d29f6a54a5 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 19 May 2015 05:13:55 +0200 Subject: Fix the way we we forward an XMPP ping result to the IRC server Our CTCP notice didn't include a \01 char at the end. We thus failed to check the PING id when we received it ourself, because one char was missing --- src/bridge/bridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index ef20351..6081986 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -399,7 +399,7 @@ void Bridge::send_xmpp_version_to_irc(const Iid& iid, const std::string& name, c void Bridge::send_irc_ping_result(const Iid& iid, const std::string& id) { - this->send_private_message(iid, "\01PING "s + utils::revstr(id), "NOTICE"); + this->send_private_message(iid, "\01PING "s + utils::revstr(id) + "\01", "NOTICE"); } void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const std::string& nick, -- cgit v1.2.3 From 2195292919110bad41f507f45fa1b7d86a369539 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 19 May 2015 05:15:49 +0200 Subject: Remove a debug line (breaking our PING stuf) that should not have been commited --- src/bridge/bridge.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 6081986..467923b 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -418,7 +418,6 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s if (message.command == "NOTICE" && utils::tolower(user.nick) == nick && body.substr(0, 6) == "\01PING ") { - return false; const std::string id = body.substr(6, body.size() - 7); if (id != iq_id) return false; -- cgit v1.2.3 From e8d7965115fe6abe25d76bccedd450532549891e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 19 May 2015 06:16:49 +0200 Subject: Handle errors for the LIST irc command ref #2472 --- src/bridge/bridge.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 467923b..c63b3da 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -317,8 +317,14 @@ void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq if (irc_hostname != iid.get_server()) return false; - if (message.command == "263" || message.command == "RPL_TRYAGAIN") - { // TODO send an error iq + if (message.command == "263" || message.command == "RPL_TRYAGAIN" || + message.command == "ERR_TOOMANYMATCHES" || message.command == "ERR_NOSUCHSERVER") + { + std::string text; + if (message.arguments.size() >= 2) + text = message.arguments[1]; + this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, + "wait", "service-unavailable", text, false); return true; } else if (message.command == "322" || message.command == "RPL_LIST") -- cgit v1.2.3 From df006a191603c4a9f0bb364affa3731c2944fef5 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 19 Aug 2015 21:21:42 +0200 Subject: //mode with no argument should work The server will respond with the current channel mode, in private or something --- src/bridge/bridge.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index c63b3da..1d46e07 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -181,9 +181,9 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) return ; for (const std::string& line: lines) { - if (line.substr(0, 6) == "/mode ") + if (line.substr(0, 5) == "/mode") { - std::vector args = utils::split(line.substr(6), ' ', false); + std::vector args = utils::split(line.substr(5), ' ', false); irc->send_mode_command(iid.get_local(), args); continue; // We do not want to send that back to the // XMPP user, that’s not a textual message. -- cgit v1.2.3 From e8f22efe34415db0e1e5cb94635b089b18efe055 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 1 Sep 2015 04:42:12 +0200 Subject: XmlNodes are now always closed Remove the close() method and closed attribute. Remove all the calls to close(). (Save one bool per XmlNode, yay, and save a few ifs and some useless function calls. At best it should be unnoticeably faster and lighter and save a few keystrokes in the future) --- src/bridge/colors.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index 3d40ac4..bdc34bf 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -80,7 +80,6 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) else if (s[pos_end] == IRC_FORMAT_NEWLINE_CHAR) { XmlNode* br_node = new XmlNode("br"); - br_node->close(); current_node->add_child(br_node); cleaned += '\n'; } @@ -126,7 +125,6 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) // close opened span, if any if (current_node != result.get()) { - current_node->close(); result->add_child(current_node); current_node = result.get(); } @@ -163,12 +161,8 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) current_node->add_to_inner(txt); if (current_node != result.get()) - { - current_node->close(); - result->add_child(current_node); - } + result->add_child(current_node); - result->close(); Xmpp::body body_res = std::make_tuple(cleaned, std::move(result)); return body_res; } -- cgit v1.2.3 From f3b3d937ae274d0eec4a737d11ba19a7f4ceef03 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 1 Sep 2015 14:47:57 +0200 Subject: =?UTF-8?q?Use=20unique=5Fptr=20to=20store=20the=20XmlNode?= =?UTF-8?q?=E2=80=99s=20children?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also fix some constness things --- src/bridge/colors.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/colors.cpp b/src/bridge/colors.cpp index bdc34bf..66f51ee 100644 --- a/src/bridge/colors.cpp +++ b/src/bridge/colors.cpp @@ -62,7 +62,9 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) std::unique_ptr result = std::make_unique("body"); (*result)["xmlns"] = XHTML_NS; + std::unique_ptr current_node_up; XmlNode* current_node = result.get(); + std::string::size_type pos_start = 0; std::string::size_type pos_end; @@ -79,8 +81,7 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) styles.strong = !styles.strong; else if (s[pos_end] == IRC_FORMAT_NEWLINE_CHAR) { - XmlNode* br_node = new XmlNode("br"); - current_node->add_child(br_node); + current_node->add_child(std::make_unique("br")); cleaned += '\n'; } else if (s[pos_end] == IRC_FORMAT_UNDERLINE_CHAR) @@ -125,7 +126,7 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) // close opened span, if any if (current_node != result.get()) { - result->add_child(current_node); + result->add_child(std::move(current_node_up)); current_node = result.get(); } // Take all currently-applied style and create a new span with it @@ -144,7 +145,8 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) irc_colors_to_css[styles.bg % IRC_NUM_COLORS] + ";"; if (!styles_str.empty()) { - current_node = new XmlNode("span"); + current_node_up = std::make_unique("span"); + current_node = current_node_up.get(); (*current_node)["style"] = styles_str; } @@ -161,7 +163,7 @@ Xmpp::body irc_format_to_xhtmlim(const std::string& s) current_node->add_to_inner(txt); if (current_node != result.get()) - result->add_child(current_node); + result->add_child(std::move(current_node_up)); Xmpp::body body_res = std::make_tuple(cleaned, std::move(result)); return body_res; -- cgit v1.2.3 From f1de6d032091bd141e12e8345969495d6f23c3e6 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 18 Sep 2015 21:58:05 +0200 Subject: Add Bridge::get_bare_jid --- src/bridge/bridge.cpp | 6 ++++++ src/bridge/bridge.hpp | 1 + 2 files changed, 7 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 1d46e07..ba70069 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -74,6 +74,12 @@ const std::string& Bridge::get_jid() const return this->user_jid; } +std::string Bridge::get_bare_jid() const +{ + Jid jid(this->user_jid); + return jid.local + "@" + jid.domain; +} + Xmpp::body Bridge::make_xmpp_body(const std::string& str) { std::string res; diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 72a8e90..dfe0aa7 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -47,6 +47,7 @@ public: * Return the jid of the XMPP user using this bridge */ const std::string& get_jid() const; + std::string get_bare_jid() const; static Xmpp::body make_xmpp_body(const std::string& str); /*** -- 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/bridge/bridge.cpp | 19 +++++++++++++++---- src/bridge/bridge.hpp | 5 +++-- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index ba70069..ec143f0 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -90,7 +90,7 @@ Xmpp::body Bridge::make_xmpp_body(const std::string& str) return irc_format_to_xhtmlim(res); } -IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string& username) +IrcClient* Bridge::make_irc_client(const std::string& hostname, const std::string& nickname) { try { @@ -98,7 +98,18 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string } catch (const std::out_of_range& exception) { - this->irc_clients.emplace(hostname, std::make_shared(this->poller, hostname, username, this)); + auto username = nickname; + auto realname = nickname; + if (Config::get("realname_from_jid", "false") == "true") + { + Jid jid(this->user_jid); + username = jid.local; + realname = this->get_bare_jid(); + } + this->irc_clients.emplace(hostname, + std::make_shared(this->poller, hostname, + nickname, username, + realname, this)); std::shared_ptr irc = this->irc_clients.at(hostname); return irc.get(); } @@ -128,9 +139,9 @@ IrcClient* Bridge::find_irc_client(const std::string& hostname) } } -bool Bridge::join_irc_channel(const Iid& iid, const std::string& username, const std::string& password) +bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password) { - IrcClient* irc = this->get_irc_client(iid.get_server(), username); + IrcClient* irc = this->make_irc_client(iid.get_server(), nickname); if (iid.get_local().empty()) { // Join the dummy channel if (irc->is_welcomed()) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index dfe0aa7..f1ecf25 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -60,7 +60,8 @@ 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& username, const std::string& password); + bool join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password); + void send_channel_message(const Iid& iid, const std::string& body); 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); @@ -193,7 +194,7 @@ private: * username in this case) if none is found, and connect that newly-created * client immediately. */ - IrcClient* get_irc_client(const std::string& hostname, const std::string& username); + IrcClient* make_irc_client(const std::string& hostname, const std::string& nickname); /** * This version does not create the IrcClient if it does not exist, throws * a IRCServerNotConnected error in that case. -- cgit v1.2.3 From e7a91badcdd421e04eea8235debc8ae582919744 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 24 Oct 2015 15:21:05 +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/bridge/colors.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/colors.hpp b/src/bridge/colors.hpp index b5e6e7b..2ba80ee 100644 --- a/src/bridge/colors.hpp +++ b/src/bridge/colors.hpp @@ -17,7 +17,7 @@ namespace Xmpp // Contains: // - an XMPP-valid UTF-8 body // - an XML node representing the XHTML-IM body, or null - typedef std::tuple> body; + using body = std::tuple>; } #define IRC_FORMAT_BOLD_CHAR '\x02' // done -- cgit v1.2.3 From 6c42286109fceddd70eacc467811b102b41a831e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 31 Oct 2015 05:36:18 +0100 Subject: Remove some useless includes --- src/bridge/bridge.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index ec143f0..18a8d92 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1,9 +1,6 @@ #include -#include #include #include -#include -#include #include #include #include @@ -12,9 +9,6 @@ #include #include #include -#include -#include -#include using namespace std::string_literals; -- 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/bridge/bridge.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 18a8d92..5badb18 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -56,7 +56,8 @@ void Bridge::clean() while (it != this->irc_clients.end()) { IrcClient* client = it->second.get(); - if (!client->is_connected() && !client->is_connecting()) + if (!client->is_connected() && !client->is_connecting() && + !client->get_resolver().is_resolving()) it = this->irc_clients.erase(it); else ++it; @@ -94,16 +95,17 @@ IrcClient* Bridge::make_irc_client(const std::string& hostname, const std::strin { auto username = nickname; auto realname = nickname; + Jid jid(this->user_jid); if (Config::get("realname_from_jid", "false") == "true") { - Jid jid(this->user_jid); username = jid.local; realname = this->get_bare_jid(); } this->irc_clients.emplace(hostname, std::make_shared(this->poller, hostname, nickname, username, - realname, this)); + realname, jid.domain, + this)); std::shared_ptr irc = this->irc_clients.at(hostname); return irc.get(); } -- 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/bridge/bridge.cpp | 5 +++++ src/bridge/bridge.hpp | 1 + 2 files changed, 6 insertions(+) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 5badb18..a1ba71a 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -690,3 +690,8 @@ void Bridge::trigger_on_irc_message(const std::string& irc_hostname, const IrcMe ++it; } } + +std::unordered_map>& Bridge::get_irc_clients() +{ + return this->irc_clients; +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index f1ecf25..7b8df8f 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -187,6 +187,7 @@ public: * iq_responder_callback_t and remove the callback from the list. */ void trigger_on_irc_message(const std::string& irc_hostname, const IrcMessage& message); + std::unordered_map>& get_irc_clients(); private: /** -- 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/bridge/bridge.cpp | 62 +++++++++++++++++++++++++-------------------------- src/bridge/bridge.hpp | 8 +++---- 2 files changed, 34 insertions(+), 36 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index a1ba71a..55f4c51 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -14,7 +14,7 @@ using namespace std::string_literals; static const char* action_prefix = "\01ACTION "; -Bridge::Bridge(const std::string& user_jid, BiboumiComponent* xmpp, std::shared_ptr poller): +Bridge::Bridge(const std::string& user_jid, BiboumiComponent& xmpp, std::shared_ptr poller): user_jid(user_jid), xmpp(xmpp), poller(poller) @@ -105,7 +105,7 @@ IrcClient* Bridge::make_irc_client(const std::string& hostname, const std::strin std::make_shared(this->poller, hostname, nickname, username, realname, jid.domain, - this)); + *this)); std::shared_ptr irc = this->irc_clients.at(hostname); return irc.get(); } @@ -172,7 +172,7 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) { if (iid.get_server().empty()) { - this->xmpp->send_stanza_error("message", this->user_jid, std::to_string(iid), "", + 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: #%", @@ -205,7 +205,7 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) irc->send_channel_message(iid.get_local(), action_prefix + line.substr(4) + "\01"); else irc->send_channel_message(iid.get_local(), line); - this->xmpp->send_muc_message(std::to_string(iid), irc->get_own_nick(), + this->xmpp.send_muc_message(std::to_string(iid), irc->get_own_nick(), this->make_xmpp_body(line), this->user_jid); } } @@ -278,7 +278,7 @@ void Bridge::send_private_message(const Iid& iid, const std::string& body, const { if (iid.get_local().empty() || iid.get_server().empty()) { - this->xmpp->send_stanza_error("message", this->user_jid, std::to_string(iid), "", + 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: #%", @@ -336,7 +336,7 @@ void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq std::string text; if (message.arguments.size() >= 2) text = message.arguments[1]; - this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, + this->xmpp.send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "wait", "service-unavailable", text, false); return true; } @@ -349,7 +349,7 @@ void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq } else if (message.command == "323" || message.command == "RPL_LISTEND") { // Send the iq response with the content of the list - this->xmpp->send_iq_room_list_result(iq_id, to_jid, std::to_string(iid), list); + this->xmpp.send_iq_room_list_result(iq_id, to_jid, std::to_string(iid), list); return true; } return false; @@ -374,7 +374,7 @@ void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std: const std::string chan_name_later = utils::tolower(message.arguments[0]); if (target_later != target || chan_name_later != iid.get_local()) return false; - this->xmpp->send_iq_result(iq_id, to_jid, std::to_string(iid)); + this->xmpp.send_iq_result(iq_id, to_jid, std::to_string(iid)); } else if (message.command == "401" && message.arguments.size() >= 2) { @@ -384,7 +384,7 @@ void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std: std::string error_message = "No such nick"; if (message.arguments.size() >= 3) error_message = message.arguments[2]; - this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "item-not-found", + this->xmpp.send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "item-not-found", error_message, false); } else if (message.command == "482" && message.arguments.size() >= 2) @@ -395,7 +395,7 @@ void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std: std::string error_message = "You're not channel operator"; if (message.arguments.size() >= 3) error_message = message.arguments[2]; - this->xmpp->send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "not-allowed", + this->xmpp.send_stanza_error("iq", to_jid, std::to_string(iid), iq_id, "cancel", "not-allowed", error_message, false); } return true; @@ -441,7 +441,7 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s if (id != iq_id) return false; Jid jid(from_jid); - this->xmpp->send_iq_result(iq_id, to_jid, jid.local); + this->xmpp.send_iq_result(iq_id, to_jid, jid.local); return true; } if (message.command == "401" && message.arguments[1] == nick) @@ -449,7 +449,7 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s std::string error_message = "No such nick"; if (message.arguments.size() >= 3) error_message = message.arguments[2]; - this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "service-unavailable", + this->xmpp.send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "service-unavailable", error_message, true); return true; } @@ -467,13 +467,13 @@ void Bridge::send_irc_participant_ping_request(const Iid& iid, const std::string IrcChannel* chan = irc->get_channel(iid.get_local()); if (!chan->joined) { - this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "not-allowed", + this->xmpp.send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "not-allowed", "", true); return; } if (chan->get_self()->nick != nick && !chan->find_user(nick)) { - this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found", + this->xmpp.send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found", "Recipient not in room", true); return; } @@ -487,9 +487,9 @@ void Bridge::on_gateway_ping(const std::string& irc_hostname, const std::string& { Jid jid(from_jid); if (irc_hostname.empty() || this->find_irc_client(irc_hostname)) - this->xmpp->send_iq_result(iq_id, to_jid, jid.local); + 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", + this->xmpp.send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "service-unavailable", "", true); } @@ -511,7 +511,7 @@ void Bridge::send_irc_version_request(const std::string& irc_hostname, const std { // remove the "\01VERSION " and the "\01" parts from the string const std::string version = message.arguments[1].substr(9, message.arguments[1].size() - 10); - this->xmpp->send_version(iq_id, to_jid, from_jid, version); + this->xmpp.send_version(iq_id, to_jid, from_jid, version); return true; } if (message.command == "401" && message.arguments.size() >= 2 @@ -520,7 +520,7 @@ void Bridge::send_irc_version_request(const std::string& irc_hostname, const std std::string error_message = "No such nick"; if (message.arguments.size() >= 3) error_message = message.arguments[2]; - this->xmpp->send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found", + this->xmpp.send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found", error_message, true); return true; } @@ -532,7 +532,7 @@ 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) { if (muc) - this->xmpp->send_muc_message(std::to_string(iid), nick, + this->xmpp.send_muc_message(std::to_string(iid), nick, this->make_xmpp_body(body), this->user_jid); else { @@ -544,7 +544,7 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st target = it->second; fulljid = true; } - this->xmpp->send_message(target, this->make_xmpp_body(body), + this->xmpp.send_message(target, this->make_xmpp_body(body), this->user_jid, "chat", fulljid); } } @@ -553,12 +553,12 @@ void Bridge::send_presence_error(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& error_code, const std::string& text) { - this->xmpp->send_presence_error(std::to_string(iid), nick, this->user_jid, type, condition, error_code, text); + this->xmpp.send_presence_error(std::to_string(iid), nick, this->user_jid, type, condition, error_code, text); } 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); + this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message), this->user_jid, self); IrcClient* irc = this->find_irc_client(iid.get_server()); if (irc && irc->number_of_joined_channels() == 0) irc->send_quit_command(""); @@ -574,7 +574,7 @@ void Bridge::send_nick_change(Iid&& iid, std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - this->xmpp->send_nick_change(std::to_string(iid), + this->xmpp.send_nick_change(std::to_string(iid), old_nick, new_nick, affiliation, role, this->user_jid, self); } @@ -590,7 +590,7 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho } else body = msg; - this->xmpp->send_message(from, this->make_xmpp_body(body), this->user_jid, "chat"); + this->xmpp.send_message(from, this->make_xmpp_body(body), this->user_jid, "chat"); } void Bridge::send_user_join(const std::string& hostname, @@ -603,13 +603,13 @@ void Bridge::send_user_join(const std::string& hostname, std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - this->xmpp->send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, + this->xmpp.send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, affiliation, role, this->user_jid, self); } void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic) { - this->xmpp->send_topic(chan_name + utils::empty_if_fixed_server("%" + hostname), this->make_xmpp_body(topic), this->user_jid); + this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server("%" + hostname), this->make_xmpp_body(topic), this->user_jid); } std::string Bridge::get_own_nick(const Iid& iid) @@ -627,12 +627,12 @@ size_t Bridge::active_clients() const void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author) { - this->xmpp->kick_user(std::to_string(iid), target, reason, author, this->user_jid); + this->xmpp.kick_user(std::to_string(iid), target, reason, author, this->user_jid); } void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname) { - this->xmpp->send_presence_error(std::to_string(iid), nickname, this->user_jid, "cancel", "conflict", "409", ""); + this->xmpp.send_presence_error(std::to_string(iid), nickname, this->user_jid, "cancel", "conflict", "409", ""); } void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode) @@ -641,12 +641,12 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar std::string affiliation; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(mode); - this->xmpp->send_affiliation_role_change(std::to_string(iid), target, affiliation, role, this->user_jid); + this->xmpp.send_affiliation_role_change(std::to_string(iid), target, affiliation, role, this->user_jid); } void Bridge::send_iq_version_request(const std::string& nick, const std::string& hostname) { - this->xmpp->send_iq_version_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid); + this->xmpp.send_iq_version_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid); } void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& hostname, @@ -655,7 +655,7 @@ void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& // Use revstr because the forwarded ping to target XMPP user must not be // the same that the request iq, but we also need to get it back easily // (revstr again) - this->xmpp->send_ping_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid, utils::revstr(id)); + this->xmpp.send_ping_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid, utils::revstr(id)); } void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 7b8df8f..e73bd19 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -33,7 +33,7 @@ using irc_responder_callback_t = std::function poller); + explicit Bridge(const std::string& user_jid, BiboumiComponent& xmpp, std::shared_ptr poller); ~Bridge(); /** * QUIT all connected IRC servers. @@ -216,11 +216,9 @@ private: */ std::unordered_map> irc_clients; /** - * A raw pointer, because we do not own it, the XMPP component owns us, - * but we still need to communicate with it, when sending messages from - * IRC to XMPP. + * To communicate back with the XMPP component */ - BiboumiComponent* xmpp; + BiboumiComponent& xmpp; /** * Poller, to give it the IrcClients that we spawn, to make it manage * their sockets. -- cgit v1.2.3 From 79cdf170d2ab6c5378cfbf61d5c8888a4c666190 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 28 Dec 2015 21:25:48 +0100 Subject: Use the configured encoding value when decoding received messages --- src/bridge/bridge.cpp | 40 ++++++++++++++++++++++++++++++++++------ src/bridge/bridge.hpp | 4 ++-- 2 files changed, 36 insertions(+), 8 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 55f4c51..4c97a91 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -9,11 +9,35 @@ #include #include #include +#include using namespace std::string_literals; static const char* action_prefix = "\01ACTION "; + +static std::string out_encoding_for(const Bridge& bridge, const Iid& iid) +{ +#ifdef USE_DATABASE + const auto jid = bridge.get_bare_jid(); + auto options = Database::get_irc_channel_options_with_server_default(jid, iid.get_server(), iid.get_local()); + return options.encodingOut.value(); +#else + return {"ISO-8859-1"}; +#endif +} + +static std::string in_encoding_for(const Bridge& bridge, const Iid& iid) +{ +#ifdef USE_DATABASE + const auto jid = bridge.get_bare_jid(); + auto options = Database::get_irc_channel_options_with_server_default(jid, iid.get_server(), iid.get_local()); + return options.encodingIn.value(); +#else + return {"ISO-8859-1"}; +#endif +} + Bridge::Bridge(const std::string& user_jid, BiboumiComponent& xmpp, std::shared_ptr poller): user_jid(user_jid), xmpp(xmpp), @@ -75,13 +99,13 @@ std::string Bridge::get_bare_jid() const return jid.local + "@" + jid.domain; } -Xmpp::body Bridge::make_xmpp_body(const std::string& str) +Xmpp::body Bridge::make_xmpp_body(const std::string& str, const std::string& encoding) { std::string res; if (utils::is_valid_utf8(str.c_str())) res = str; else - res = utils::convert_to_utf8(str, "ISO-8859-1"); + res = utils::convert_to_utf8(str, encoding.data()); return irc_format_to_xhtmlim(res); } @@ -531,9 +555,10 @@ 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); if (muc) this->xmpp.send_muc_message(std::to_string(iid), nick, - this->make_xmpp_body(body), this->user_jid); + this->make_xmpp_body(body, encoding), this->user_jid); else { std::string target = std::to_string(iid); @@ -544,7 +569,7 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st target = it->second; fulljid = true; } - this->xmpp.send_message(target, this->make_xmpp_body(body), + this->xmpp.send_message(target, this->make_xmpp_body(body, encoding), this->user_jid, "chat", fulljid); } } @@ -590,7 +615,9 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho } else body = msg; - this->xmpp.send_message(from, this->make_xmpp_body(body), this->user_jid, "chat"); + + const auto encoding = in_encoding_for(*this, {from}); + this->xmpp.send_message(from, this->make_xmpp_body(body, encoding), this->user_jid, "chat"); } void Bridge::send_user_join(const std::string& hostname, @@ -609,7 +636,8 @@ void Bridge::send_user_join(const std::string& hostname, void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic) { - this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server("%" + hostname), this->make_xmpp_body(topic), this->user_jid); + const auto encoding = in_encoding_for(*this, {chan_name + '%' + hostname}); + this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server("%" + hostname), this->make_xmpp_body(topic, encoding), this->user_jid); } std::string Bridge::get_own_nick(const Iid& iid) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index e73bd19..c030ed8 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -49,7 +49,7 @@ public: const std::string& get_jid() const; std::string get_bare_jid() const; - static Xmpp::body make_xmpp_body(const std::string& str); + static Xmpp::body make_xmpp_body(const std::string& str, const std::string& encodin = "ISO-8859-1"); /*** ** ** From XMPP to IRC. @@ -108,7 +108,7 @@ public: /** * Send a message corresponding to a server NOTICE, the from attribute - * should be juste the server hostname@irc.component. + * should be juste the server hostname. */ void send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg); /** -- 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/bridge/bridge.cpp | 5 +++-- src/bridge/bridge.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 4c97a91..2815da9 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -634,10 +634,11 @@ void Bridge::send_user_join(const std::string& hostname, affiliation, role, this->user_jid, self); } -void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic) +void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic, const std::string& who) { const auto encoding = in_encoding_for(*this, {chan_name + '%' + hostname}); - this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server("%" + hostname), this->make_xmpp_body(topic, encoding), this->user_jid); + this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server( + "%" + hostname), this->make_xmpp_body(topic, encoding), this->user_jid, who); } std::string Bridge::get_own_nick(const Iid& iid) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index c030ed8..6222ef0 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -122,7 +122,7 @@ public: /** * Send the topic of the MUC to the user */ - void send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic); + void send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic, const std::string& who); /** * Send a MUC message from some participant */ -- 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/bridge/bridge.cpp | 4 ---- src/bridge/bridge.hpp | 12 ++++++------ 2 files changed, 6 insertions(+), 10 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 2815da9..6008dfc 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -45,10 +45,6 @@ Bridge::Bridge(const std::string& user_jid, BiboumiComponent& xmpp, std::shared_ { } -Bridge::~Bridge() -{ -} - /** * Return the role and affiliation, corresponding to the given irc mode */ static std::tuple get_role_affiliation_from_irc_mode(const char mode) diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 6222ef0..2676d1d 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -34,7 +34,12 @@ class Bridge { public: explicit Bridge(const std::string& user_jid, BiboumiComponent& xmpp, std::shared_ptr poller); - ~Bridge(); + ~Bridge() = default; + + Bridge(const Bridge&) = delete; + Bridge(Bridge&& other) = delete; + Bridge& operator=(const Bridge&) = delete; + Bridge& operator=(Bridge&&) = delete; /** * QUIT all connected IRC servers. */ @@ -239,11 +244,6 @@ private: * response iq. */ std::list waiting_irc; - - Bridge(const Bridge&) = delete; - Bridge(Bridge&& other) = delete; - Bridge& operator=(const Bridge&) = delete; - Bridge& operator=(Bridge&&) = delete; }; struct IRCNotConnected: public std::exception -- cgit v1.2.3 From 711861d40e365564e3828a251066c16e924d30f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 22 May 2016 12:54:18 +0200 Subject: Add methods to know which resource is on which server or channel --- src/bridge/bridge.cpp | 36 +++++++++++++++++++++++++++++++++--- src/bridge/bridge.hpp | 11 +++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 6008dfc..484c860 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -46,11 +46,12 @@ Bridge::Bridge(const std::string& user_jid, BiboumiComponent& xmpp, std::shared_ } /** - * Return the role and affiliation, corresponding to the given irc mode */ + * Return the role and affiliation, corresponding to the given irc mode + */ static std::tuple get_role_affiliation_from_irc_mode(const char mode) { - if (mode == 'a' || mode == 'q') - return std::make_tuple("moderator", "owner"); + if (mode == 'a' || mode == 'q'){ + return std::make_tuple("moderator", "owner");} else if (mode == 'o') return std::make_tuple("moderator", "admin"); else if (mode == 'h') @@ -720,3 +721,32 @@ std::unordered_map>& Bridge::get_irc_cli { return this->irc_clients; } + +void Bridge::add_resource_to_chan(const std::string& channel, const std::string& resource) +{ + auto it = this->resources_in_chan.find(channel); + if (it == this->resources_in_chan.end()) + this->resources_in_chan[channel] = {resource}; + else + it->second.insert(resource); +} + +void Bridge::remove_resource_from_chan(const std::string& channel, const std::string& resource) +{ + auto it = this->resources_in_chan.find(channel); + if (it != this->resources_in_chan.end()) + { + it->second.erase(resource); + if (it->second.empty()) + this->resources_in_chan.erase(it); + } +} + +bool Bridge::is_resource_in_chan(const std::string& channel, const std::string& resource) const +{ + auto it = this->resources_in_chan.find(channel); + if (it != this->resources_in_chan.end()) + if (it->second.count(resource) == 1) + return true; + return false; +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 2676d1d..b852a30 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -194,6 +194,13 @@ public: void trigger_on_irc_message(const std::string& irc_hostname, const IrcMessage& message); std::unordered_map>& get_irc_clients(); + /** + * Manage which resource is in which channel + */ + void add_resource_to_chan(const std::string& channel, const std::string& resource); + void remove_resource_from_chan(const std::string& channel, const std::string& resource); + bool is_resource_in_chan(const std::string& channel, const std::string& resource) const; + private: /** * Returns the client for the given hostname, create one (and use the @@ -244,6 +251,10 @@ private: * response iq. */ std::list waiting_irc; + /** + * Keep track of which resource is in which channel. + */ + std::map> resources_in_chan; }; struct IRCNotConnected: public std::exception -- cgit v1.2.3 From 66609cfba2b581be52de6096193751d1bb4ec3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 22 May 2016 12:52:05 +0200 Subject: Remove all usage of std::list --- src/bridge/bridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index b852a30..469a959 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -250,7 +250,7 @@ private: * request and we need a response from IRC to be able to provide the * response iq. */ - std::list waiting_irc; + std::vector waiting_irc; /** * Keep track of which resource is in which channel. */ -- 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/bridge/bridge.cpp | 128 +++++++++++++++++++++++++++++++++++++++----------- src/bridge/bridge.hpp | 37 +++++++++++---- 2 files changed, 129 insertions(+), 36 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 484c860..bfd5d68 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -156,9 +156,15 @@ IrcClient* Bridge::find_irc_client(const std::string& hostname) } } -bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password) -{ - IrcClient* irc = this->make_irc_client(iid.get_server(), nickname); +bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, + const std::string& resource) +{ + const auto hostname = iid.get_server(); + IrcClient* irc = this->make_irc_client(hostname, nickname); + 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()) @@ -185,6 +191,8 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const { irc->send_join_command(iid.get_local(), password); return true; + } else if (!res_in_chan) { + this->generate_channel_join_for_resource(iid, resource); } return false; } @@ -193,11 +201,12 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) { if (iid.get_server().empty()) { - 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); + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + this->xmpp.send_stanza_error("message", this->user_jid + "/" + resource, 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()); @@ -226,8 +235,9 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) irc->send_channel_message(iid.get_local(), action_prefix + line.substr(4) + "\01"); else irc->send_channel_message(iid.get_local(), line); - this->xmpp.send_muc_message(std::to_string(iid), irc->get_own_nick(), - this->make_xmpp_body(line), this->user_jid); + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + this->xmpp.send_muc_message(std::to_string(iid), irc->get_own_nick(), + this->make_xmpp_body(line), this->user_jid + "/" + resource); } } @@ -554,8 +564,13 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st { const auto encoding = in_encoding_for(*this, iid); if (muc) - this->xmpp.send_muc_message(std::to_string(iid), nick, - this->make_xmpp_body(body, encoding), this->user_jid); + { + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + { + this->xmpp.send_muc_message(std::to_string(iid), nick, + this->make_xmpp_body(body, encoding), this->user_jid + "/" + resource); + } + } else { std::string target = std::to_string(iid); @@ -566,8 +581,11 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st target = it->second; fulljid = true; } - this->xmpp.send_message(target, this->make_xmpp_body(body, encoding), - this->user_jid, "chat", fulljid); + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + { + this->xmpp.send_message(target, this->make_xmpp_body(body, encoding), + this->user_jid + "/" + resource, "chat", fulljid); + } } } @@ -580,7 +598,8 @@ 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); + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message), this->user_jid + "/" + resource, self); IrcClient* irc = this->find_irc_client(iid.get_server()); if (irc && irc->number_of_joined_channels() == 0) irc->send_quit_command(""); @@ -596,8 +615,9 @@ void Bridge::send_nick_change(Iid&& iid, std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - this->xmpp.send_nick_change(std::to_string(iid), - old_nick, new_nick, affiliation, role, this->user_jid, self); + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + this->xmpp.send_nick_change(std::to_string(iid), + old_nick, new_nick, affiliation, role, this->user_jid + "/" + resource, self); } void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg) @@ -614,7 +634,10 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho body = msg; const auto encoding = in_encoding_for(*this, {from}); - this->xmpp.send_message(from, this->make_xmpp_body(body, encoding), this->user_jid, "chat"); + for (const auto& resource: this->resources_in_server[from]) + { + this->xmpp.send_message(from, this->make_xmpp_body(body, encoding), this->user_jid + "/" + resource, "chat"); + } } void Bridge::send_user_join(const std::string& hostname, @@ -627,15 +650,21 @@ void Bridge::send_user_join(const std::string& hostname, std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - this->xmpp.send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, - affiliation, role, this->user_jid, self); + for (const auto& resource: this->resources_in_chan[ChannelKey{chan_name, hostname}]) + { + this->xmpp.send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, + affiliation, role, this->user_jid + "/" + resource, self); + } } void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic, const std::string& who) { const auto encoding = in_encoding_for(*this, {chan_name + '%' + hostname}); - this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server( - "%" + hostname), this->make_xmpp_body(topic, encoding), this->user_jid, who); + for (const auto& resource: this->resources_in_chan[ChannelKey{chan_name, hostname}]) + { + this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server( + "%" + hostname), this->make_xmpp_body(topic, encoding), this->user_jid + "/" + resource, who); + } } std::string Bridge::get_own_nick(const Iid& iid) @@ -653,12 +682,14 @@ size_t Bridge::active_clients() const void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author) { - this->xmpp.kick_user(std::to_string(iid), target, reason, author, this->user_jid); + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + this->xmpp.kick_user(std::to_string(iid), target, reason, author, this->user_jid + "/" + resource); } void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname) { - this->xmpp.send_presence_error(std::to_string(iid), nickname, this->user_jid, "cancel", "conflict", "409", ""); + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + this->xmpp.send_presence_error(std::to_string(iid), nickname, this->user_jid + "/" + resource, "cancel", "conflict", "409", ""); } void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode) @@ -667,7 +698,8 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar std::string affiliation; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(mode); - this->xmpp.send_affiliation_role_change(std::to_string(iid), target, affiliation, role, this->user_jid); + for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + this->xmpp.send_affiliation_role_change(std::to_string(iid), target, affiliation, role, this->user_jid + "/" + resource); } void Bridge::send_iq_version_request(const std::string& nick, const std::string& hostname) @@ -722,7 +754,7 @@ std::unordered_map>& Bridge::get_irc_cli return this->irc_clients; } -void Bridge::add_resource_to_chan(const std::string& channel, const std::string& resource) +void Bridge::add_resource_to_chan(const Bridge::ChannelKey& channel, const std::string& resource) { auto it = this->resources_in_chan.find(channel); if (it == this->resources_in_chan.end()) @@ -731,7 +763,7 @@ void Bridge::add_resource_to_chan(const std::string& channel, const std::string& it->second.insert(resource); } -void Bridge::remove_resource_from_chan(const std::string& channel, const std::string& resource) +void Bridge::remove_resource_from_chan(const Bridge::ChannelKey& channel, const std::string& resource) { auto it = this->resources_in_chan.find(channel); if (it != this->resources_in_chan.end()) @@ -742,7 +774,7 @@ void Bridge::remove_resource_from_chan(const std::string& channel, const std::st } } -bool Bridge::is_resource_in_chan(const std::string& channel, const std::string& resource) const +bool Bridge::is_resource_in_chan(const Bridge::ChannelKey& channel, const std::string& resource) const { auto it = this->resources_in_chan.find(channel); if (it != this->resources_in_chan.end()) @@ -750,3 +782,43 @@ bool Bridge::is_resource_in_chan(const std::string& channel, const std::string& return true; return false; } + +void Bridge::add_resource_to_server(const Bridge::IrcHostname& irc_hostname, const std::string& resource) +{ + auto it = this->resources_in_server.find(irc_hostname); + if (it == this->resources_in_server.end()) + this->resources_in_server[irc_hostname] = {resource}; + else + it->second.insert(resource); +} + +void Bridge::remove_resource_from_server(const Bridge::IrcHostname& irc_hostname, const std::string& resource) +{ + auto it = this->resources_in_server.find(irc_hostname); + if (it != this->resources_in_server.end()) + { + it->second.erase(resource); + if (it->second.empty()) + this->resources_in_server.erase(it); + } +} + +bool Bridge::is_resource_in_server(const Bridge::IrcHostname& irc_hostname, const std::string& resource) const +{ + auto it = this->resources_in_server.find(irc_hostname); + if (it != this->resources_in_server.end()) + if (it->second.count(resource) == 1) + return true; + return false; +} + +void Bridge::generate_channel_join_for_resource(const Iid& iid, const std::string& resource) +{ + IrcClient* irc = this->get_irc_client(iid.get_server()); + IrcChannel* channel = irc->get_channel(iid.get_local()); + // Send the occupant list + for (const auto& user: channel->get_users()) + { + + } +} diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 469a959..e614779 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -65,7 +65,7 @@ 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); + bool join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, const std::string& resource); void send_channel_message(const Iid& iid, const std::string& body); void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); @@ -195,11 +195,9 @@ public: std::unordered_map>& get_irc_clients(); /** - * Manage which resource is in which channel + * Manage which resource is connected to which IRC server */ - void add_resource_to_chan(const std::string& channel, const std::string& resource); - void remove_resource_from_chan(const std::string& channel, const std::string& resource); - bool is_resource_in_chan(const std::string& channel, const std::string& resource) const; + private: /** @@ -218,7 +216,7 @@ private: */ IrcClient* find_irc_client(const std::string& hostname); /** - * The JID of the user associated with this bridge. Messages from/to this + * The bare JID of the user associated with this bridge. Messages from/to this * JID are only managed by this bridge. */ const std::string user_jid; @@ -251,10 +249,33 @@ private: * response iq. */ std::vector waiting_irc; + + /** + * Resources to IRC channel/server mapping: + */ + using Resource = std::string; + using ChannelName = std::string; + using IrcHostname = std::string; + using ChannelKey = std::tuple; + std::map> resources_in_chan; + std::map> resources_in_server; + /** + * Manage which resource is in which channel + */ + void add_resource_to_chan(const ChannelKey& channel_key, const std::string& resource); + void remove_resource_from_chan(const ChannelKey& channel_key, const std::string& resource); + bool is_resource_in_chan(const ChannelKey& channel_key, const std::string& resource) const; + + void add_resource_to_server(const IrcHostname& irc_hostname, const std::string& resource); + void remove_resource_from_server(const IrcHostname& irc_hostname, const std::string& resource); + bool is_resource_in_server(const IrcHostname& irc_hostname, const std::string& resource) const; + /** - * Keep track of which resource is in which channel. + * Generate all the stanzas to be sent to this resource, simulating a join on this channel. + * This means sending the whole user list, the topic, etc + * TODO: send message history */ - std::map> resources_in_chan; + void generate_channel_join_for_resource(const Iid& iid, const std::string& resource); }; struct IRCNotConnected: public std::exception -- 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/bridge/bridge.cpp | 123 ++++++++++++++++++++++++++++++++++++-------------- src/bridge/bridge.hpp | 16 ++++--- 2 files changed, 99 insertions(+), 40 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index bfd5d68..95ca68e 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -201,7 +201,7 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) { if (iid.get_server().empty()) { - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) this->xmpp.send_stanza_error("message", this->user_jid + "/" + resource, std::to_string(iid), "", "cancel", "remote-server-not-found", std::to_string(iid) + " is not a valid channel name. " @@ -235,7 +235,7 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) irc->send_channel_message(iid.get_local(), action_prefix + line.substr(4) + "\01"); else irc->send_channel_message(iid.get_local(), line); - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + 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); } @@ -335,11 +335,29 @@ void Bridge::send_raw_message(const std::string& hostname, const std::string& bo irc->send_raw(body); } -void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) +void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message, const std::string& resource) { IrcClient* irc = this->get_irc_client(iid.get_server()); - irc->send_part_command(iid.get_local(), status_message); -} + const auto key = iid.to_tuple(); + if (!this->is_resource_in_chan(key, resource)) + return ; + + const auto resources = this->number_of_resources_in_chan(key); + if (resources == 1) + irc->send_part_command(iid.get_local(), status_message); + else + { + IrcChannel* chan = irc->get_channel(iid.get_local()); + if (chan) + { + auto nick = chan->get_self()->nick; + this->remove_resource_from_chan(key, resource); + this->send_muc_leave(std::move(iid), std::move(nick), + "Biboumi note: "s + std::to_string(resources - 1) + " resources are still in this channel.", + true, resource); + } + } + } void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick) { @@ -565,7 +583,7 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st const auto encoding = in_encoding_for(*this, iid); if (muc) { - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + 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); @@ -574,17 +592,19 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st else { std::string target = std::to_string(iid); - bool fulljid = false; - auto it = this->preferred_user_from.find(iid.get_local()); + const auto it = this->preferred_user_from.find(iid.get_local()); if (it != this->preferred_user_from.end()) { - target = it->second; - fulljid = true; + const auto chan_name = Iid(Jid(it->second).local).get_local(); + for (const auto& resource: this->resources_in_chan[ChannelKey{chan_name, iid.get_server()}]) + this->xmpp.send_message(it->second, this->make_xmpp_body(body, encoding), + this->user_jid + "/" + resource, "chat", true); } - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + else { - this->xmpp.send_message(target, this->make_xmpp_body(body, encoding), - this->user_jid + "/" + resource, "chat", fulljid); + for (const auto& resource: this->resources_in_server[iid.get_server()]) + this->xmpp.send_message(std::to_string(iid), this->make_xmpp_body(body, encoding), + this->user_jid + "/" + resource, "chat", false); } } } @@ -596,10 +616,15 @@ 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(Iid&& iid, std::string&& nick, const std::string& message, const bool self) +void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self, const std::string& resource) { - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) - this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message), this->user_jid + "/" + resource, self); + if (!resource.empty()) + this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message), this->user_jid + "/" + resource, + self); + else + for (const auto& res: this->resources_in_chan[iid.to_tuple()]) + this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message), this->user_jid + "/" + res, + self); IrcClient* irc = this->find_irc_client(iid.get_server()); if (irc && irc->number_of_joined_channels() == 0) irc->send_quit_command(""); @@ -615,7 +640,7 @@ void Bridge::send_nick_change(Iid&& iid, std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) this->xmpp.send_nick_change(std::to_string(iid), old_nick, new_nick, affiliation, role, this->user_jid + "/" + resource, self); } @@ -640,33 +665,43 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho } } -void Bridge::send_user_join(const std::string& hostname, - const std::string& chan_name, - const IrcUser* user, - const char user_mode, - const bool self) +void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, + const IrcUser* user, const char user_mode, const bool self) +{ + for (const auto& resource: this->resources_in_chan[ChannelKey{chan_name, hostname}]) + this->send_user_join(hostname, chan_name, user, user_mode, self, resource); +} + +void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, + const IrcUser* user, const char user_mode, + const bool self, const std::string& resource) { std::string affiliation; std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - for (const auto& resource: this->resources_in_chan[ChannelKey{chan_name, hostname}]) - { - this->xmpp.send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, - affiliation, role, this->user_jid + "/" + resource, self); - } + this->xmpp.send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, + affiliation, role, this->user_jid + "/" + resource, self); } void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic, const std::string& who) { - const auto encoding = in_encoding_for(*this, {chan_name + '%' + hostname}); for (const auto& resource: this->resources_in_chan[ChannelKey{chan_name, hostname}]) { - this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server( - "%" + hostname), this->make_xmpp_body(topic, encoding), this->user_jid + "/" + resource, who); + this->send_topic(hostname, chan_name, topic, who, resource); } } +void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, + const std::string& topic, const std::string& who, + const std::string& resource) +{ + const auto encoding = in_encoding_for(*this, {chan_name + '%' + hostname}); + this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server( + "%" + hostname), this->make_xmpp_body(topic, encoding), this->user_jid + "/" + resource, who); + +} + std::string Bridge::get_own_nick(const Iid& iid) { IrcClient* irc = this->find_irc_client(iid.get_server()); @@ -682,13 +717,13 @@ size_t Bridge::active_clients() const void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author) { - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) this->xmpp.kick_user(std::to_string(iid), target, reason, author, this->user_jid + "/" + resource); } void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname) { - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) this->xmpp.send_presence_error(std::to_string(iid), nickname, this->user_jid + "/" + resource, "cancel", "conflict", "409", ""); } @@ -698,7 +733,7 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar std::string affiliation; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(mode); - for (const auto& resource: this->resources_in_chan[ChannelKey{iid.get_local(), iid.get_server()}]) + for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) this->xmpp.send_affiliation_role_change(std::to_string(iid), target, affiliation, role, this->user_jid + "/" + resource); } @@ -812,13 +847,33 @@ bool Bridge::is_resource_in_server(const Bridge::IrcHostname& irc_hostname, cons return false; } +std::size_t Bridge::number_of_resources_in_chan(const Bridge::ChannelKey& channel_key) const +{ + auto it = this->resources_in_chan.find(channel_key); + if (it == this->resources_in_chan.end()) + return 0; + return it->second.size(); +} + void Bridge::generate_channel_join_for_resource(const Iid& iid, const std::string& resource) { IrcClient* irc = this->get_irc_client(iid.get_server()); IrcChannel* channel = irc->get_channel(iid.get_local()); + const auto self = channel->get_self(); + // Send the occupant list for (const auto& user: channel->get_users()) { - + if (user->nick != self->nick) + { + log_debug(user->nick); + this->send_user_join(iid.get_server(), iid.get_local(), + user.get(), user->get_most_significant_mode(irc->get_sorted_user_modes()), + false, resource); + } } + this->send_user_join(iid.get_server(), iid.get_local(), + self, self->get_most_significant_mode(irc->get_sorted_user_modes()), + true, resource); + this->send_topic(iid.get_server(), iid.get_local(), channel->topic, channel->topic_author, resource); } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index e614779..eabd9af 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -70,7 +70,7 @@ public: void send_channel_message(const Iid& iid, const std::string& body); 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, std::string&& status_message); + void leave_irc_channel(Iid&& iid, std::string&& status_message, const std::string& resource); void send_irc_nick_change(const Iid& iid, const std::string& new_nick); void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason, const std::string& iq_id, const std::string& to_jid); @@ -119,15 +119,18 @@ public: /** * Send the presence of a new user in the MUC. */ - void send_user_join(const std::string& hostname, - const std::string& chan_name, - const IrcUser* user, - const char user_mode, + void send_user_join(const std::string& hostname, const std::string& chan_name, + const IrcUser* user, const char user_mode, + const bool self, const std::string& resource); + void send_user_join(const std::string& hostname, const std::string& chan_name, + const IrcUser* user, const char user_mode, const bool self); + /** * Send the topic of the MUC to the user */ void send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic, const std::string& who); + void send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic, const std::string& who, const std::string& resource); /** * Send a MUC message from some participant */ @@ -139,7 +142,7 @@ public: /** * Send an unavailable presence from this participant */ - void send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self); + void send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self, const std::string& resource=""); /** * 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 @@ -265,6 +268,7 @@ private: void add_resource_to_chan(const ChannelKey& channel_key, const std::string& resource); void remove_resource_from_chan(const ChannelKey& channel_key, const std::string& resource); bool is_resource_in_chan(const ChannelKey& channel_key, const std::string& resource) const; + std::size_t number_of_resources_in_chan(const ChannelKey& channel_key) const; void add_resource_to_server(const IrcHostname& irc_hostname, const std::string& resource); void remove_resource_from_server(const IrcHostname& irc_hostname, const std::string& resource); -- cgit v1.2.3 From 272c0e4995f2fe94fb2366c15453fdada341861a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 10 Jun 2016 10:00:48 +0200 Subject: Reset the preferred private JID when all resources leave a room MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For example if we are talking in private with nick Joe from room #foo, and then we leave that room, we start receiving Joe’s message from the server-wide JID e2e tests included!!! --- src/bridge/bridge.cpp | 19 ++++++++++++++++++- src/bridge/bridge.hpp | 5 +++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 95ca68e..3a7a147 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -344,7 +344,12 @@ void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message, const st const auto resources = this->number_of_resources_in_chan(key); if (resources == 1) - irc->send_part_command(iid.get_local(), status_message); + { + irc->send_part_command(iid.get_local(), status_message); + // Since there are no resources left in that channel, we don't + // want to receive private messages using this room's JID + this->remove_all_preferred_from_jid_of_room(iid.get_local()); + } else { IrcChannel* chan = irc->get_channel(iid.get_local()); @@ -767,6 +772,18 @@ void Bridge::remove_preferred_from_jid(const std::string& nick) this->preferred_user_from.erase(it); } +void Bridge::remove_all_preferred_from_jid_of_room(const std::string& channel_name) +{ + for (auto it = this->preferred_user_from.begin(); it != this->preferred_user_from.end();) + { + Iid iid(Jid(it->second).local); + if (iid.get_local() == channel_name) + it = this->preferred_user_from.erase(it); + else + ++it; + } +} + void Bridge::add_waiting_irc(irc_responder_callback_t&& callback) { this->waiting_irc.emplace_back(std::move(callback)); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index eabd9af..01f8f78 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -185,6 +185,11 @@ public: * Remove the preferred jid for the given IRC nick */ void remove_preferred_from_jid(const std::string& nick); + /** + * Given a channel_name, remove all preferred from_jid that come + * from this chan. + */ + void remove_all_preferred_from_jid_of_room(const std::string& channel_name); /** * Add a callback to the waiting list of irc callbacks. */ -- cgit v1.2.3 From 350d48a5bf2412f5eee347fc832d9257b2ba3fbc Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 15 Jun 2016 21:54:22 +0100 Subject: Fix typo in bridge.hpp --- src/bridge/bridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 01f8f78..6feb282 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -54,7 +54,7 @@ public: const std::string& get_jid() const; std::string get_bare_jid() const; - static Xmpp::body make_xmpp_body(const std::string& str, const std::string& encodin = "ISO-8859-1"); + static Xmpp::body make_xmpp_body(const std::string& str, const std::string& encoding = "ISO-8859-1"); /*** ** ** From XMPP to IRC. -- 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/bridge/bridge.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 3a7a147..87667db 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -685,7 +685,10 @@ void Bridge::send_user_join(const std::string& hostname, const std::string& chan std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user_mode); - this->xmpp.send_user_join(chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, + std::string encoded_chan_name(chan_name); + xep0106::encode(encoded_chan_name); + + this->xmpp.send_user_join(encoded_chan_name + utils::empty_if_fixed_server("%" + hostname), user->nick, user->host, affiliation, role, this->user_jid + "/" + resource, self); } @@ -701,8 +704,10 @@ void Bridge::send_topic(const std::string& hostname, const std::string& chan_nam const std::string& topic, const std::string& who, const std::string& resource) { - const auto encoding = in_encoding_for(*this, {chan_name + '%' + hostname}); - this->xmpp.send_topic(chan_name + utils::empty_if_fixed_server( + std::string encoded_chan_name(chan_name); + xep0106::encode(encoded_chan_name); + const auto encoding = in_encoding_for(*this, {encoded_chan_name + '%' + hostname}); + this->xmpp.send_topic(encoded_chan_name + utils::empty_if_fixed_server( "%" + hostname), this->make_xmpp_body(topic, encoding), this->user_jid + "/" + resource, who); } @@ -884,13 +889,13 @@ void Bridge::generate_channel_join_for_resource(const Iid& iid, const std::strin if (user->nick != self->nick) { log_debug(user->nick); - this->send_user_join(iid.get_server(), iid.get_local(), + this->send_user_join(iid.get_server(), iid.get_encoded_local(), user.get(), user->get_most_significant_mode(irc->get_sorted_user_modes()), false, resource); } } - this->send_user_join(iid.get_server(), iid.get_local(), + this->send_user_join(iid.get_server(), iid.get_encoded_local(), self, self->get_most_significant_mode(irc->get_sorted_user_modes()), true, resource); - this->send_topic(iid.get_server(), iid.get_local(), channel->topic, channel->topic_author, resource); + this->send_topic(iid.get_server(), iid.get_encoded_local(), channel->topic, channel->topic_author, resource); } -- cgit v1.2.3 From 6bd9b1ec1429024a49cf8b6d7be29f90f35110fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Jun 2016 22:18:42 +0200 Subject: Remove unused function --- src/bridge/bridge.cpp | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 87667db..4976ed2 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -16,17 +16,6 @@ using namespace std::string_literals; static const char* action_prefix = "\01ACTION "; -static std::string out_encoding_for(const Bridge& bridge, const Iid& iid) -{ -#ifdef USE_DATABASE - const auto jid = bridge.get_bare_jid(); - auto options = Database::get_irc_channel_options_with_server_default(jid, iid.get_server(), iid.get_local()); - return options.encodingOut.value(); -#else - return {"ISO-8859-1"}; -#endif -} - static std::string in_encoding_for(const Bridge& bridge, const Iid& iid) { #ifdef USE_DATABASE -- cgit v1.2.3 From b2e7edeea8bf08b6b7e75d60af3af0c30fdaa4f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 24 Jun 2016 11:23:01 +0200 Subject: =?UTF-8?q?Properly=20set=20the=20=E2=80=9Cfrom=E2=80=9D=20of=20th?= =?UTF-8?q?e=20ping=20results=20to=20the=20correct=20full=20JID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bridge/bridge.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 4976ed2..eee4bd2 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -483,8 +483,7 @@ void Bridge::send_irc_user_ping_request(const std::string& irc_hostname, const s const std::string id = body.substr(6, body.size() - 7); if (id != iq_id) return false; - Jid jid(from_jid); - this->xmpp.send_iq_result(iq_id, to_jid, jid.local); + this->xmpp.send_iq_result_full_jid(iq_id, to_jid, from_jid); return true; } if (message.command == "401" && message.arguments[1] == nick) -- cgit v1.2.3 From 7d2a2dc8cc9d2d9bcd83fb1bd869c29322855fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 24 Jun 2016 11:23:51 +0200 Subject: Forward ping requests from IRC to XMPP, to one single resource --- src/bridge/bridge.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index eee4bd2..6de2516 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -746,7 +746,10 @@ void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& // Use revstr because the forwarded ping to target XMPP user must not be // the same that the request iq, but we also need to get it back easily // (revstr again) - this->xmpp.send_ping_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid, utils::revstr(id)); + // Forward to the first resource (arbitrary, based on the “order” of the std::set) only + const auto resources = this->resources_in_server[hostname]; + if (resources.begin() != resources.end()) + this->xmpp.send_ping_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid + "/" + *resources.begin(), utils::revstr(id)); } void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid) -- cgit v1.2.3 From 0ce75ab52111ba27ca99961057b36b68f0a135a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 3 Jul 2016 15:43:11 +0200 Subject: Properly remove the resource from the server when we leave the last channel --- src/bridge/bridge.cpp | 15 ++++++++++++++- src/bridge/bridge.hpp | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 6de2516..613e0e2 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -349,9 +349,11 @@ void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message, const st this->send_muc_leave(std::move(iid), std::move(nick), "Biboumi note: "s + std::to_string(resources - 1) + " resources are still in this channel.", true, resource); + if (this->number_of_channels_the_resource_is_in(iid.get_server(), resource) == 0) + this->remove_resource_from_server(iid.get_server(), resource); } } - } +} void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick) { @@ -868,6 +870,17 @@ std::size_t Bridge::number_of_resources_in_chan(const Bridge::ChannelKey& channe return it->second.size(); } +std::size_t Bridge::number_of_channels_the_resource_is_in(const std::string& irc_hostname, const std::string& resource) const +{ + std::size_t res = 0; + for (auto pair: this->resources_in_chan) + { + if (std::get<0>(pair.first) == irc_hostname && pair.second.count(resource) != 0) + res++; + } + return res; +} + void Bridge::generate_channel_join_for_resource(const Iid& iid, const std::string& resource) { IrcClient* irc = this->get_irc_client(iid.get_server()); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 6feb282..3430b06 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -278,6 +278,7 @@ private: void add_resource_to_server(const IrcHostname& irc_hostname, const std::string& resource); void remove_resource_from_server(const IrcHostname& irc_hostname, const std::string& resource); bool is_resource_in_server(const IrcHostname& irc_hostname, const std::string& resource) const; + size_t number_of_channels_the_resource_is_in(const std::string& irc_hostname, const std::string& resource) const; /** * Generate all the stanzas to be sent to this resource, simulating a join on this channel. -- cgit v1.2.3 From 964784497a7dd1278789f63322cb8acc8ed419ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 4 Jul 2016 10:20:16 +0200 Subject: Remove forgotten comment --- src/bridge/bridge.hpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 3430b06..f8eea94 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -202,11 +202,6 @@ public: void trigger_on_irc_message(const std::string& irc_hostname, const IrcMessage& message); std::unordered_map>& get_irc_clients(); - /** - * Manage which resource is connected to which IRC server - */ - - private: /** * Returns the client for the given hostname, create one (and use the -- cgit v1.2.3 From 5321d29cbda7d69d306f36d0f84d2c599c85c90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 4 Jul 2016 17:00:05 +0200 Subject: List of channels are saved per-request and not globally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list would keep the previous results in memory, forever, and the list would grow each time a new request was made (even with results from unrelated servers)… --- src/bridge/bridge.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 613e0e2..1ca611a 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -368,11 +368,11 @@ void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq irc->send_list_command(); - irc_responder_callback_t cb = [this, iid, iq_id, to_jid](const std::string& irc_hostname, - const IrcMessage& message) -> bool - { - static std::vector list; + std::vector list; + irc_responder_callback_t cb = [this, iid, iq_id, to_jid, list=std::move(list)](const std::string& irc_hostname, + const IrcMessage& message) mutable -> bool + { if (irc_hostname != iid.get_server()) return false; if (message.command == "263" || message.command == "RPL_TRYAGAIN" || -- 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/bridge/bridge.hpp | 6 +++--- src/bridge/colors.hpp | 6 +++--- src/bridge/list_element.hpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index f8eea94..69b7bd5 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -1,5 +1,5 @@ -#ifndef BRIDGE_INCLUDED -# define BRIDGE_INCLUDED +#pragma once + #include #include @@ -290,4 +290,4 @@ struct IRCNotConnected: public std::exception const std::string hostname; }; -#endif // BRIDGE_INCLUDED + diff --git a/src/bridge/colors.hpp b/src/bridge/colors.hpp index 2ba80ee..e2c8a87 100644 --- a/src/bridge/colors.hpp +++ b/src/bridge/colors.hpp @@ -1,5 +1,5 @@ -#ifndef COLORS_INCLUDED -# define COLORS_INCLUDED +#pragma once + /** * A module handling the conversion between IRC colors and XHTML-IM, and @@ -53,4 +53,4 @@ static const char irc_format_char[] = { */ Xmpp::body irc_format_to_xhtmlim(const std::string& str); -#endif // COLORS_INCLUDED + diff --git a/src/bridge/list_element.hpp b/src/bridge/list_element.hpp index bd28185..1eff2ee 100644 --- a/src/bridge/list_element.hpp +++ b/src/bridge/list_element.hpp @@ -1,5 +1,5 @@ -#ifndef LIST_ELEMENT_HPP_INCLUDED -#define LIST_ELEMENT_HPP_INCLUDED +#pragma once + #include @@ -16,4 +16,4 @@ struct ListElement std::string topic; }; -#endif /* LIST_ELEMENT_HPP_INCLUDED */ + -- cgit v1.2.3 From 03feb403f8fc702481f4e7a0ec0264aa2912ae51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 3 Jul 2016 16:06:52 +0200 Subject: Send the iq requests to one random resource instead of the bare JID --- src/bridge/bridge.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 1ca611a..edf1700 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -739,7 +739,9 @@ void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& tar void Bridge::send_iq_version_request(const std::string& nick, const std::string& hostname) { - this->xmpp.send_iq_version_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid); + const auto resources = this->resources_in_server[hostname]; + if (resources.begin() != resources.end()) + this->xmpp.send_iq_version_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid + "/" + *resources.begin()); } void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& hostname, -- cgit v1.2.3 From f0a25ccda4526f5132b459e7e6a48ea08733fb79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 3 Aug 2016 11:46:13 +0200 Subject: Lower case the nick, when forwarding a version or ping request --- src/bridge/bridge.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/bridge') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index edf1700..17d3ec6 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -741,7 +741,7 @@ void Bridge::send_iq_version_request(const std::string& nick, const std::string& { const auto resources = this->resources_in_server[hostname]; if (resources.begin() != resources.end()) - this->xmpp.send_iq_version_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid + "/" + *resources.begin()); + this->xmpp.send_iq_version_request(utils::tolower(nick) + "!" + utils::empty_if_fixed_server(hostname), this->user_jid + "/" + *resources.begin()); } void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& hostname, @@ -753,7 +753,7 @@ void Bridge::send_xmpp_ping_request(const std::string& nick, const std::string& // Forward to the first resource (arbitrary, based on the “order” of the std::set) only const auto resources = this->resources_in_server[hostname]; if (resources.begin() != resources.end()) - this->xmpp.send_ping_request(nick + "!" + utils::empty_if_fixed_server(hostname), this->user_jid + "/" + *resources.begin(), utils::revstr(id)); + this->xmpp.send_ping_request(utils::tolower(nick) + "!" + utils::empty_if_fixed_server(hostname), this->user_jid + "/" + *resources.begin(), utils::revstr(id)); } void Bridge::set_preferred_from_jid(const std::string& nick, const std::string& full_jid) -- cgit v1.2.3