From 24d902983a17c9ae554456ffa11b5c6945e230f2 2015-12-07 18:17:04 From: Jan Kaluza Date: 2015-12-07 18:17:04 Subject: [PATCH] Send list of online users to Slack channel when transporting to 3rd-party network room. --- diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 145517e96c3fdc224a1f1dc16a552c55ad4a0f27..922cc7c953fe84776c36687d0480786340cee4c7 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -670,7 +670,11 @@ class SpectrumNetworkPlugin : public NetworkPlugin { comps = purple_chat_get_components_wrapped(chat); } else if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) { - comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, room.c_str()); + if (CONFIG_STRING(config, "service.protocol") == "prpl-jabber") { + comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, (room + "/" + nickname).c_str()); + } else { + comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, room.c_str()); + } } LOG4CXX_INFO(logger, user << ": Joining the room " << room); diff --git a/include/transport/Conversation.h b/include/transport/Conversation.h index 380e813a8fd7ef992f84fabcb8522f220dd5096f..9c268139ce61a52791d3d9e41212726c46fcac3c 100644 --- a/include/transport/Conversation.h +++ b/include/transport/Conversation.h @@ -146,6 +146,7 @@ class Conversation { void destroyRoom(); + std::string getParticipants(); void sendParticipants(const Swift::JID &to); void sendCachedMessages(const Swift::JID &to = Swift::JID()); diff --git a/include/transport/ConversationManager.h b/include/transport/ConversationManager.h index 7aa606bfaa0c236089b28cd88dc78d06c7a6915a..68c88d9ddf75ef78e4e8c89f1f172e354df635f1 100644 --- a/include/transport/ConversationManager.h +++ b/include/transport/ConversationManager.h @@ -78,6 +78,10 @@ class ConversationManager { void removeJID(const Swift::JID &jid); void clearJIDs(); + std::map &getConversations() { + return m_convs; + } + private: void handleMessageReceived(Swift::Message::ref message); diff --git a/spectrum/src/frontends/slack/SlackRTM.cpp b/spectrum/src/frontends/slack/SlackRTM.cpp index 8f344faff4a597342b645a4e8a57c6a5f2c3da5c..4bd807107d47d691482d55d5eaa282b94e1e8be4 100644 --- a/spectrum/src/frontends/slack/SlackRTM.cpp +++ b/spectrum/src/frontends/slack/SlackRTM.cpp @@ -110,6 +110,14 @@ void SlackRTM::sendPing() { m_pingTimer->start(); } +const std::string &SlackRTM::getUserName(const std::string &id) { + if (m_users.find(id) == m_users.end()) { + return id; + } + + return m_users[id].name; +} + void SlackRTM::handleRTMStart(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) { if (!ok) { LOG4CXX_ERROR(logger, req->getError()); @@ -124,6 +132,22 @@ void SlackRTM::handleRTMStart(HTTPRequest *req, bool ok, rapidjson::Document &re return; } + rapidjson::Value &self = resp["self"]; + if (!self.IsObject()) { + LOG4CXX_ERROR(logger, "No 'self' object in the reply."); + LOG4CXX_ERROR(logger, data); + return; + } + + rapidjson::Value &selfName = self["name"]; + if (!selfName.IsString()) { + LOG4CXX_ERROR(logger, "No 'name' string in the reply."); + LOG4CXX_ERROR(logger, data); + return; + } + + m_selfName = selfName.GetString(); + SlackAPI::getSlackChannelInfo(req, ok, resp, data, m_channels); SlackAPI::getSlackImInfo(req, ok, resp, data, m_ims); SlackAPI::getSlackUserInfo(req, ok, resp, data, m_users); diff --git a/spectrum/src/frontends/slack/SlackRTM.h b/spectrum/src/frontends/slack/SlackRTM.h index d2bdacb392abc5ade28c2581d63ad8370017ab41..c8cc7e25901d8ea35704ac20c099b23f9fdd1269 100644 --- a/spectrum/src/frontends/slack/SlackRTM.h +++ b/spectrum/src/frontends/slack/SlackRTM.h @@ -82,6 +82,12 @@ class SlackRTM { boost::signal onMessageReceived; + const std::string &getUserName(const std::string &id); + + const std::string &getSelfName() { + return m_selfName; + } + private: void handlePayloadReceived(const std::string &payload); void handleRTMStart(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data); @@ -91,6 +97,7 @@ class SlackRTM { std::map m_channels; std::map m_ims; std::map m_users; + std::string m_selfName; private: Component *m_component; diff --git a/spectrum/src/frontends/slack/SlackSession.cpp b/spectrum/src/frontends/slack/SlackSession.cpp index b8465cb5440dd7ae31cb314ac47c3c60da7a3e0b..ab3e8acc8704a41fafd83ea57fcb66a79b759fbd 100644 --- a/spectrum/src/frontends/slack/SlackSession.cpp +++ b/spectrum/src/frontends/slack/SlackSession.cpp @@ -29,6 +29,8 @@ #include "transport/Util.h" #include "transport/Buddy.h" #include "transport/Config.h" +#include "transport/ConversationManager.h" +#include "transport/Conversation.h" #include #include @@ -52,16 +54,57 @@ SlackSession::SlackSession(Component *component, StorageBackend *storageBackend, m_rtm->onRTMStarted.connect(boost::bind(&SlackSession::handleRTMStarted, this)); m_rtm->onMessageReceived.connect(boost::bind(&SlackSession::handleMessageReceived, this, _1, _2, _3, _4, false)); + m_onlineBuddiesTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(20000); + m_onlineBuddiesTimer->onTick.connect(boost::bind(&SlackSession::sendOnlineBuddies, this)); } SlackSession::~SlackSession() { delete m_rtm; + m_onlineBuddiesTimer->stop(); } -void SlackSession::sendMessage(boost::shared_ptr message) { - if (message->getFrom().getResource() == m_uinfo.uin) { +void SlackSession::sendOnlineBuddies() { + if (!m_user) { return; } + std::map convs = m_user->getConversationManager()->getConversations(); + for (std::map ::const_iterator it = convs.begin(); it != convs.end(); it++) { + Conversation *conv = it->second; + if (!conv) { + continue; + } + + std::string onlineBuddies = "Online users: " + conv->getParticipants(); + + if (m_onlineBuddies[it->first] != onlineBuddies) { + m_onlineBuddies[it->first] = onlineBuddies; + std::string legacyName = it->first; + if (legacyName.find_last_of("@") != std::string::npos) { + legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK + } + + + std::string to = legacyName + "@" + m_component->getJID().toBare().toString(); + setPurpose(onlineBuddies, m_jid2channel[to]); + } + } + m_onlineBuddiesTimer->start(); +} + +void SlackSession::sendMessage(boost::shared_ptr message) { + if (m_user) { + std::map convs = m_user->getConversationManager()->getConversations(); + for (std::map ::const_iterator it = convs.begin(); it != convs.end(); it++) { + Conversation *conv = it->second; + if (!conv) { + continue; + } + + if (conv->getNickname() == message->getFrom().getResource()) { + return; + } + } + } std::string from = message->getFrom().getResource(); std::string channel = m_jid2channel[message->getFrom().toBare().toString()]; @@ -84,13 +127,17 @@ void SlackSession::sendMessage(boost::shared_ptr message) { m_rtm->getAPI()->sendMessage(from, channel, message->getBody()); } -void SlackSession::setPurpose(const std::string &purpose) { - if (m_slackChannel.empty()) { +void SlackSession::setPurpose(const std::string &purpose, const std::string &channel) { + std::string ch = channel; + if (ch.empty()) { + ch = m_slackChannel; + } + if (ch.empty()) { return; } - LOG4CXX_INFO(logger, "Setting channel purppose: " << m_slackChannel << " " << purpose); - m_rtm->getAPI()->setPurpose(m_slackChannel, purpose); + LOG4CXX_INFO(logger, "Setting channel purppose: " << ch << " " << purpose); + m_rtm->getAPI()->setPurpose(ch, purpose); } void SlackSession::handleJoinMessage(const std::string &message, std::vector &args, bool quiet) { @@ -114,11 +161,13 @@ void SlackSession::handleJoinMessage(const std::string &message, std::vectorgetUserSetting(m_uinfo.id, "rooms", type, rooms); - rooms += message + "\n"; - m_storageBackend->updateUserSetting(m_uinfo.id, "rooms", rooms); + if (!quiet) { + std::string rooms = ""; + int type = (int) TYPE_STRING; + m_storageBackend->getUserSetting(m_uinfo.id, "rooms", type, rooms); + rooms += message + "\n"; + m_storageBackend->updateUserSetting(m_uinfo.id, "rooms", rooms); + } Swift::Presence::ref presence = Swift::Presence::create(); presence->setFrom(Swift::JID("", m_uinfo.jid, "default")); @@ -127,6 +176,8 @@ void SlackSession::handleJoinMessage(const std::string &message, std::vectoraddPayload(boost::shared_ptr(new Swift::MUCPayload())); m_component->getFrontend()->onPresenceReceived(presence); + m_onlineBuddiesTimer->start(); + if (!quiet) { std::string msg; msg += "Spectrum 2 is now joining the room. To leave the room later to disable transporting, you can use `.spectrum2 leave.room #" + SlackAPI::SlackObjectToPlainText(args[5], true, true) + "`."; @@ -200,12 +251,16 @@ void SlackSession::handleRegisterMessage(const std::string &message, std::vector void SlackSession::handleMessageReceived(const std::string &channel, const std::string &user, const std::string &message, const std::string &ts, bool quiet) { if (m_ownerChannel != channel) { std::string to = m_channel2jid[channel]; + if (m_rtm->getUserName(user) == m_rtm->getSelfName()) { + return; + } + if (!to.empty()) { boost::shared_ptr msg(new Swift::Message()); msg->setType(Swift::Message::Groupchat); msg->setTo(to); msg->setFrom(Swift::JID("", m_uinfo.jid, "default")); - msg->setBody("<" + user + "> " + message); + msg->setBody("<" + m_rtm->getUserName(user) + "> " + message); m_component->getFrontend()->onMessageReceived(msg); } else { @@ -241,7 +296,7 @@ void SlackSession::handleMessageReceived(const std::string &channel, const std:: boost::shared_ptr msg(new Swift::Message()); msg->setTo(b->getJID()); msg->setFrom(Swift::JID("", m_uinfo.jid, "default")); - msg->setBody("<" + user + "> " + message); + msg->setBody("<" + m_rtm->getUserName(user) + "> " + message); m_component->getFrontend()->onMessageReceived(msg); } } diff --git a/spectrum/src/frontends/slack/SlackSession.h b/spectrum/src/frontends/slack/SlackSession.h index e9fa34059ba037c9ec54fb52a30ba75dbec09135..e8bfa77ca6c4bb8305c343eea8d1200d7685d4c7 100644 --- a/spectrum/src/frontends/slack/SlackSession.h +++ b/spectrum/src/frontends/slack/SlackSession.h @@ -28,6 +28,7 @@ #include #include "Swiften/Elements/Message.h" +#include "Swiften/Network/Timer.h" #include @@ -50,7 +51,7 @@ class SlackSession { void sendMessage(boost::shared_ptr message); - void setPurpose(const std::string &purpose); + void setPurpose(const std::string &purpose, const std::string &channel = ""); void setUser(User *user) { m_user = user; @@ -65,6 +66,8 @@ class SlackSession { void handleLeaveMessage(const std::string &message, std::vector &args, bool quiet = false); void handleRegisterMessage(const std::string &message, std::vector &args, bool quiet = false); + void sendOnlineBuddies(); + private: Component *m_component; StorageBackend *m_storageBackend; @@ -76,6 +79,8 @@ class SlackSession { std::map m_channel2jid; std::string m_slackChannel; User *m_user; + Swift::Timer::ref m_onlineBuddiesTimer; + std::map m_onlineBuddies; }; } diff --git a/src/Conversation.cpp b/src/Conversation.cpp index 3a7174879822126a0a83caa20286be058c600dad..24656509cd933ef37af3b73df3073bcb422fe3ed 100644 --- a/src/Conversation.cpp +++ b/src/Conversation.cpp @@ -204,6 +204,14 @@ void Conversation::handleMessage(boost::shared_ptr &message, con handleRawMessage(message); } +std::string Conversation::getParticipants() { + std::string ret; + for (std::map::iterator it = m_participants.begin(); it != m_participants.end(); it++) { + ret += (*it).second->getFrom().getResource() + ", "; + } + return ret; +} + void Conversation::sendParticipants(const Swift::JID &to) { for (std::map::iterator it = m_participants.begin(); it != m_participants.end(); it++) { (*it).second->setTo(to);