From 2922d57bfd232f62306be697684ff972b16ce755 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 3 Dec 2015 17:19:23 +0100 Subject: [PATCH] Allow logging to legacy network from Slack --- spectrum/src/frontends/slack/SlackSession.cpp | 262 +++++++++++------- spectrum/src/frontends/slack/SlackSession.h | 5 + 2 files changed, 169 insertions(+), 98 deletions(-) diff --git a/spectrum/src/frontends/slack/SlackSession.cpp b/spectrum/src/frontends/slack/SlackSession.cpp index 82a35067..200793d9 100644 --- a/spectrum/src/frontends/slack/SlackSession.cpp +++ b/spectrum/src/frontends/slack/SlackSession.cpp @@ -27,6 +27,7 @@ #include "transport/HTTPRequest.h" #include "transport/Util.h" #include "transport/Buddy.h" +#include "transport/Config.h" #include #include @@ -61,15 +62,117 @@ void SlackSession::sendMessage(boost::shared_ptr message) { return; } - std::string channel = m_jid2channel[message->getFrom().toBare().toString()]; + std::string &channel = m_jid2channel[message->getFrom().toBare().toString()]; if (channel.empty()) { - LOG4CXX_ERROR(logger, m_uinfo.jid << ": Received message for unknown channel from " << message->getFrom().toBare().toString()); - return; + if (m_slackChannel.empty()) { + LOG4CXX_ERROR(logger, m_uinfo.jid << ": Received message for unknown channel from " << message->getFrom().toBare().toString()); + return; + } + channel = m_slackChannel; } m_rtm->getAPI()->sendMessage(message->getFrom().getResource(), channel, message->getBody()); } +void SlackSession::handleJoinMessage(const std::string &message, std::vector &args, bool quiet) { + // .spectrum2 join.room BotName #room irc.freenode.net channel + std::string &name = args[2]; + std::string legacyRoom = SlackAPI::SlackObjectToPlainText(args[3], true); + std::string legacyServer = SlackAPI::SlackObjectToPlainText(args[4]); + std::string slackChannel = SlackAPI::SlackObjectToPlainText(args[5], true); + + m_uinfo.uin = name; + m_storageBackend->setUser(m_uinfo); + + std::string to = legacyRoom + "%" + legacyServer + "@" + m_component->getJID().toString(); + m_jid2channel[to] = slackChannel; + m_channel2jid[slackChannel] = to; + + LOG4CXX_INFO(logger, "Setting transport between " << to << " and " << slackChannel); + + 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")); + presence->setTo(Swift::JID(to + "/" + name)); + presence->setType(Swift::Presence::Available); + presence->addPayload(boost::shared_ptr(new Swift::MUCPayload())); + m_component->getFrontend()->onPresenceReceived(presence); + + 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) + "`."; + m_rtm->sendMessage(m_ownerChannel, msg); + } +} + +void SlackSession::handleLeaveMessage(const std::string &message, std::vector &args, bool quiet) { + // .spectrum2 leave.room channel + std::string slackChannel = SlackAPI::SlackObjectToPlainText(args[2], true); + std::string to = m_channel2jid[slackChannel]; + if (to.empty()) { + m_rtm->sendMessage(m_ownerChannel, "Spectrum 2 is not configured to transport this Slack channel."); + return; + } + + std::string rooms = ""; + int type = (int) TYPE_STRING; + m_storageBackend->getUserSetting(m_uinfo.id, "rooms", type, rooms); + + std::vector commands; + boost::split(commands, rooms, boost::is_any_of("\n")); + rooms = ""; + + BOOST_FOREACH(const std::string &command, commands) { + if (command.size() > 5) { + std::vector args2; + boost::split(args2, command, boost::is_any_of(" ")); + if (args2.size() == 6) { + if (slackChannel != SlackAPI::SlackObjectToPlainText(args2[5], true)) { + rooms += command + "\n"; + } + } + } + } + + m_storageBackend->updateUserSetting(m_uinfo.id, "rooms", rooms); + + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(Swift::JID("", m_uinfo.jid, "default")); + presence->setTo(Swift::JID(to + "/" + m_uinfo.uin)); + presence->setType(Swift::Presence::Unavailable); + presence->addPayload(boost::shared_ptr(new Swift::MUCPayload())); + m_component->getFrontend()->onPresenceReceived(presence); +} + +void SlackSession::handleRegisterMessage(const std::string &message, std::vector &args, bool quiet) { + // .spectrum2 register test@xmpp.tld mypassword #slack_channel + m_uinfo.uin = SlackAPI::SlackObjectToPlainText(args[2]); + m_uinfo.password = args[3]; + std::string slackChannel = SlackAPI::SlackObjectToPlainText(args[4], true); + + m_storageBackend->setUser(m_uinfo); + int type = (int) TYPE_STRING; + m_storageBackend->getUserSetting(m_uinfo.id, "slack_channel", type, slackChannel); + + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(Swift::JID("", m_uinfo.jid, "default")); + presence->setTo(m_component->getJID()); + presence->setType(Swift::Presence::Available); + presence->addPayload(boost::shared_ptr(new Swift::MUCPayload())); + m_component->getFrontend()->onPresenceReceived(presence); + + if (!quiet) { + std::string msg; + msg += "You have successfully registered 3rd-party account. Spectrum 2 is now connecting to the 3rd-party network."; + m_rtm->sendMessage(m_ownerChannel, msg); + } +} + void SlackSession::handleMessageReceived(const std::string &channel, const std::string &user, const std::string &message, bool quiet) { if (m_ownerChannel != channel) { std::string to = m_channel2jid[channel]; @@ -81,6 +184,9 @@ void SlackSession::handleMessageReceived(const std::string &channel, const std:: msg->setBody("<" + user + "> " + message); m_component->getFrontend()->onMessageReceived(msg); } + else { + // TODO: MAP `user` to JID somehow and send the message to proper JID. + } return; } @@ -92,94 +198,24 @@ void SlackSession::handleMessageReceived(const std::string &channel, const std:: return; } - if (args[1] == "join.room") { - // .spectrum2 join.room BotName #room irc.freenode.net channel - if (args.size() == 6) { - std::string &name = args[2]; - std::string legacyRoom = SlackAPI::SlackObjectToPlainText(args[3], true); - std::string legacyServer = SlackAPI::SlackObjectToPlainText(args[4]); - std::string slackChannel = SlackAPI::SlackObjectToPlainText(args[5], true); - - m_uinfo.uin = name; - m_storageBackend->setUser(m_uinfo); - - std::string to = legacyRoom + "%" + legacyServer + "@" + m_component->getJID().toString(); - m_jid2channel[to] = slackChannel; - m_channel2jid[slackChannel] = to; - - LOG4CXX_INFO(logger, "Setting transport between " << to << " and " << slackChannel); - - 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")); - presence->setTo(Swift::JID(to + "/" + name)); - presence->setType(Swift::Presence::Available); - presence->addPayload(boost::shared_ptr(new Swift::MUCPayload())); - m_component->getFrontend()->onPresenceReceived(presence); - - 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) + "`."; - m_rtm->sendMessage(m_ownerChannel, msg); - } - } + if (args[1] == "join.room" && args.size() == 6) { + handleJoinMessage(message, args, quiet); } - else if (args[1] == "leave.room") { - // .spectrum2 leave.room channel - if (args.size() == 3) { - std::string slackChannel = SlackAPI::SlackObjectToPlainText(args[2], true); - std::string to = m_channel2jid[slackChannel]; - if (to.empty()) { - m_rtm->sendMessage(m_ownerChannel, "Spectrum 2 is not configured to transport this Slack channel."); - return; - } - - std::string rooms = ""; - int type = (int) TYPE_STRING; - m_storageBackend->getUserSetting(m_uinfo.id, "rooms", type, rooms); - - std::vector commands; - boost::split(commands, rooms, boost::is_any_of("\n")); - rooms = ""; - - BOOST_FOREACH(const std::string &command, commands) { - if (command.size() > 5) { - std::vector args2; - boost::split(args2, command, boost::is_any_of(" ")); - if (args2.size() == 6) { - if (slackChannel != SlackAPI::SlackObjectToPlainText(args2[5], true)) { - rooms += command + "\n"; - } - } - } - } - - m_storageBackend->updateUserSetting(m_uinfo.id, "rooms", rooms); - - Swift::Presence::ref presence = Swift::Presence::create(); - presence->setFrom(Swift::JID("", m_uinfo.jid, "default")); - presence->setTo(Swift::JID(to + "/" + m_uinfo.uin)); - presence->setType(Swift::Presence::Unavailable); - presence->addPayload(boost::shared_ptr(new Swift::MUCPayload())); - m_component->getFrontend()->onPresenceReceived(presence); - } + else if (args[1] == "leave.room" && args.size() == 3) { + handleLeaveMessage(message, args, quiet); } - else if (args[1] == "list.rooms") { + else if (args[1] == "register" && args.size() == 5) { + handleRegisterMessage(message, args, quiet); + } + else if (args[1] == "list.rooms" && args.size() == 2) { // .spectrum2 list.rooms - if (args.size() == 2) { - std::string rooms = ""; - int type = (int) TYPE_STRING; - m_storageBackend->getUserSetting(m_uinfo.id, "rooms", type, rooms); + std::string rooms = ""; + int type = (int) TYPE_STRING; + m_storageBackend->getUserSetting(m_uinfo.id, "rooms", type, rooms); - std::string msg = "Spectrum 2 is configured for following channels:\\n"; - msg += "```" + rooms + "```"; - m_rtm->sendMessage(m_ownerChannel, msg); - } + std::string msg = "Spectrum 2 is configured for following channels:\\n"; + msg += "```" + rooms + "```"; + m_rtm->sendMessage(m_ownerChannel, msg); } else if (args[1] == "help") { std::string msg; @@ -188,6 +224,7 @@ void SlackSession::handleMessageReceived(const std::string &channel, const std:: msg += "```.spectrum2 join.room <3rdPartyBotName> <#3rdPartyRoom> <3rdPartyServer> <#SlackChannel>``` Starts transport between 3rd-party room and Slack channel."; msg += "```.spectrum2 leave.room <#SlackChannel>``` Leaves the 3rd-party room connected with the given Slack channel."; msg += "```.spectrum2 list.rooms``` List all the transported rooms."; + msg += "```.spectrum2 register <3rdPartyNetworkAccount> <3rdPartyPassword> <#SlackChannel> Registers 3rd-party account for transportation."; m_rtm->sendMessage(m_ownerChannel, msg); } else { @@ -203,19 +240,48 @@ void SlackSession::handleImOpen(HTTPRequest *req, bool ok, rapidjson::Document & int type = (int) TYPE_STRING; m_storageBackend->getUserSetting(m_uinfo.id, "rooms", type, rooms); - if (rooms.empty()) { - std::string msg; - msg = "Hi, it seems you have enabled Spectrum 2 transport for your Team. As a Team owner, you should now configure it:\\n"; - msg += "1. At first, create new channel in which you want this Spectrum 2 transport to send the messages, or choose the existing one.\\n"; - msg += "2. Invite this Spectrum 2 bot into this channel.\\n"; - msg += "3. Configure the transportation between 3rd-party network and this channel by executing following command in this chat:\\n"; - msg += "```.spectrum2 join.room NameOfYourBotIn3rdPartyNetwork #3rdPartyRoom hostname_of_3rd_party_server #SlackChannel```\\n"; - msg += "For example to join #test123 channel on Freenode IRC server as MyBot and transport it into #slack_channel, the command would look like this:\\n"; - msg += "```.spectrum2 join.room MyBot #test123 adams.freenode.net #slack_channel```\\n"; - msg += "To get full list of available commands, executa `.spectrum2 help`\\n"; - m_rtm->sendMessage(m_ownerChannel, msg); + if (CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", false)) { + if (rooms.empty()) { + std::string msg; + msg = "Hi, it seems you have enabled Spectrum 2 transport for your Team. As a Team owner, you should now configure it:\\n"; + msg += "1. At first, create new channel in which you want this Spectrum 2 transport to send the messages, or choose the existing one.\\n"; + msg += "2. Invite this Spectrum 2 bot into this channel.\\n"; + msg += "3. Configure the transportation between 3rd-party network and this channel by executing following command in this chat:\\n"; + msg += "```.spectrum2 register 3rdPartyAccount 3rdPartyPassword #SlackChannel```\\n"; + msg += "For example to join XMPP account test@xmpp.tld and transport it into #slack_channel, the command would look like this:\\n"; + msg += "```.spectrum2 register test@xmpp.tld mypassword #slack_channel```\\n"; + msg += "To get full list of available commands, executa `.spectrum2 help`\\n"; + m_rtm->sendMessage(m_ownerChannel, msg); + } } else { + if (m_uinfo.uin.empty()) { + std::string msg; + msg = "Hi, it seems you have enabled Spectrum 2 transport for your Team. As a Team owner, you should now configure it:\\n"; + msg += "1. At first, create new channel in which you want this Spectrum 2 transport to send the messages, or choose the existing one.\\n"; + msg += "2. Invite this Spectrum 2 bot into this channel.\\n"; + msg += "3. Configure the transportation between 3rd-party network and this channel by executing following command in this chat:\\n"; + msg += "```.spectrum2 join.room NameOfYourBotIn3rdPartyNetwork #3rdPartyRoom hostname_of_3rd_party_server #SlackChannel```\\n"; + msg += "For example to join #test123 channel on Freenode IRC server as MyBot and transport it into #slack_channel, the command would look like this:\\n"; + msg += "```.spectrum2 join.room MyBot #test123 adams.freenode.net #slack_channel```\\n"; + msg += "To get full list of available commands, executa `.spectrum2 help`\\n"; + m_rtm->sendMessage(m_ownerChannel, msg); + } + else { + m_storageBackend->getUserSetting(m_uinfo.id, "slack_channel", type, m_slackChannel); + if (!m_slackChannel.empty()) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(Swift::JID("", m_uinfo.jid, "default")); + presence->setTo(m_component->getJID()); + presence->setType(Swift::Presence::Available); + presence->addPayload(boost::shared_ptr(new Swift::MUCPayload())); + m_component->getFrontend()->onPresenceReceived(presence); + } + } + } + + // Auto-join the rooms configured by the Slack channel owner. + if (!rooms.empty()) { std::vector commands; boost::split(commands, rooms, boost::is_any_of("\n")); diff --git a/spectrum/src/frontends/slack/SlackSession.h b/spectrum/src/frontends/slack/SlackSession.h index 46c2c771..351eb5e1 100644 --- a/spectrum/src/frontends/slack/SlackSession.h +++ b/spectrum/src/frontends/slack/SlackSession.h @@ -54,6 +54,10 @@ class SlackSession { void handleMessageReceived(const std::string &channel, const std::string &user, const std::string &message, bool quiet); void handleImOpen(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data); + void handleJoinMessage(const std::string &message, std::vector &args, bool quiet = false); + void handleLeaveMessage(const std::string &message, std::vector &args, bool quiet = false); + void handleRegisterMessage(const std::string &message, std::vector &args, bool quiet = false); + private: Component *m_component; StorageBackend *m_storageBackend; @@ -63,6 +67,7 @@ class SlackSession { std::string m_ownerChannel; std::map m_jid2channel; std::map m_channel2jid; + std::string m_slackChannel; }; }