From f7dc91ccb482617d6faee11048fa068fe47ca56d Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 22 Dec 2012 21:07:29 +0100 Subject: [PATCH 1/4] Set adhoc settings according to config even when storage backend is not set --- backends/frotz/main.cpp | 2 +- backends/libcommuni/ircnetworkplugin.cpp | 2 +- backends/libcommuni/ircnetworkplugin.h | 2 +- backends/libpurple/main.cpp | 2 +- backends/libyahoo2/main.cpp | 2 +- backends/skype/main.cpp | 2 +- backends/smstools3/main.cpp | 2 +- backends/swiften/main.cpp | 2 +- backends/template/plugin.cpp | 2 +- backends/template/plugin.h | 2 +- backends/twitter/TwitterPlugin.cpp | 2 +- backends/twitter/TwitterPlugin.h | 2 +- include/transport/config.h | 1 + include/transport/networkplugin.h | 4 ++- include/transport/networkpluginserver.h | 1 + include/transport/protocol.proto | 2 ++ plugin/cpp/networkplugin.cpp | 17 +++++++++++- src/adhocmanager.cpp | 10 +++---- src/config.cpp | 3 +++ src/discoinforesponder.cpp | 32 +++++++++++++++------- src/discoinforesponder.h | 3 ++- src/networkpluginserver.cpp | 34 ++++++++++++++++++++++++ src/tests/discoitemsresponder.cpp | 27 +++++++++++++++++++ 23 files changed, 127 insertions(+), 31 deletions(-) diff --git a/backends/frotz/main.cpp b/backends/frotz/main.cpp index 01f67245..77e4d191 100644 --- a/backends/frotz/main.cpp +++ b/backends/frotz/main.cpp @@ -245,7 +245,7 @@ class FrotzNetworkPlugin : public NetworkPlugin { return games; } - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "") { std::cout << "aaa\n"; if (message.find("start") == 0) { std::string game = message.substr(6); diff --git a/backends/libcommuni/ircnetworkplugin.cpp b/backends/libcommuni/ircnetworkplugin.cpp index 486a8bcd..2eea86cb 100644 --- a/backends/libcommuni/ircnetworkplugin.cpp +++ b/backends/libcommuni/ircnetworkplugin.cpp @@ -144,7 +144,7 @@ std::string IRCNetworkPlugin::getTargetName(const std::string &legacyName) { return r; } -void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/) { +void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/, const std::string &/*id*/) { std::string session = getSessionName(user, legacyName); if (m_sessions[session] == NULL) { LOG4CXX_WARN(logger, user << ": Session name: " << session << ", No session for user"); diff --git a/backends/libcommuni/ircnetworkplugin.h b/backends/libcommuni/ircnetworkplugin.h index 12ae0ba3..9c4cdca7 100644 --- a/backends/libcommuni/ircnetworkplugin.h +++ b/backends/libcommuni/ircnetworkplugin.h @@ -20,7 +20,7 @@ class IRCNetworkPlugin : public QObject, public NetworkPlugin { void handleLogoutRequest(const std::string &user, const std::string &legacyName); - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/); + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &/*xhtml*/, const std::string &/*id*/); void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password); diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 06df61ee..04cd980b 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -427,7 +427,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } } - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml) { + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &id) { PurpleAccount *account = m_sessions[user]; if (account) { PurpleConversation *conv = purple_find_conversation_with_account_wrapped(PURPLE_CONV_TYPE_CHAT, legacyName.c_str(), account); diff --git a/backends/libyahoo2/main.cpp b/backends/libyahoo2/main.cpp index 9c133839..df88ab8b 100644 --- a/backends/libyahoo2/main.cpp +++ b/backends/libyahoo2/main.cpp @@ -145,7 +145,7 @@ class YahooPlugin : public NetworkPlugin { } } - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "") { YahooLocalAccount *account = m_users[user]; if (account) { LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << ": " << message << "."); diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 7cb7c59f..d8bfd295 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -207,7 +207,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } } - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml) { + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "") { Skype *skype = m_sessions[user]; if (skype) { skype->send_command("MESSAGE " + legacyName + " " + message); diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 31a22b78..9e5600ff 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -193,7 +193,7 @@ class SMSNetworkPlugin : public NetworkPlugin { void handleLogoutRequest(const std::string &user, const std::string &legacyName) { } - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "") { // Remove trailing +, because smstools doesn't use it in "From: " field for received messages. std::string n = legacyName; if (n.find("+") == 0) { diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index 6db0d86c..97368436 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -202,7 +202,7 @@ class SwiftenPlugin : public NetworkPlugin { } } - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "") { + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") { LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << "."); boost::shared_ptr client = m_users[user]; if (client) { diff --git a/backends/template/plugin.cpp b/backends/template/plugin.cpp index 9b2b7866..ec4e86ca 100644 --- a/backends/template/plugin.cpp +++ b/backends/template/plugin.cpp @@ -45,7 +45,7 @@ void Plugin::handleLoginRequest(const std::string &user, const std::string &lega void Plugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) { } -void Plugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml) { +void Plugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &id) { LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << "."); if (legacyName == "echo") { handleMessage(user, legacyName, message); diff --git a/backends/template/plugin.h b/backends/template/plugin.h index e017c811..6260ff97 100644 --- a/backends/template/plugin.h +++ b/backends/template/plugin.h @@ -16,7 +16,7 @@ class Plugin : public Transport::NetworkPlugin { void handleLogoutRequest(const std::string &user, const std::string &legacyName); - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = ""); + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = ""); void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups); diff --git a/backends/twitter/TwitterPlugin.cpp b/backends/twitter/TwitterPlugin.cpp index 9163b680..b0ffba6f 100644 --- a/backends/twitter/TwitterPlugin.cpp +++ b/backends/twitter/TwitterPlugin.cpp @@ -194,7 +194,7 @@ void TwitterPlugin::handleLeaveRoomRequest(const std::string &user, const std::s } // Messages to be sent to Twitter -void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml) +void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &/*id*/) { LOG4CXX_INFO(logger, "Received " << user << " --> " << legacyName << " - " << message) diff --git a/backends/twitter/TwitterPlugin.h b/backends/twitter/TwitterPlugin.h index 7ab17300..fee4b84d 100644 --- a/backends/twitter/TwitterPlugin.h +++ b/backends/twitter/TwitterPlugin.h @@ -74,7 +74,7 @@ class TwitterPlugin : public NetworkPlugin { void handleLeaveRoomRequest(const std::string &/*user*/, const std::string &/*room*/); - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = ""); + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = ""); void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups); diff --git a/include/transport/config.h b/include/transport/config.h index aa55cd9a..8f760fea 100644 --- a/include/transport/config.h +++ b/include/transport/config.h @@ -126,6 +126,7 @@ class Config { boost::signal onConfigReloaded; void updateBackendConfig(const std::string &backendConfig); + boost::signal onBackendConfigUpdated; static Config *createFromArgs(int argc, char **argv, std::string &error, std::string &host, int &port); diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index bd37a189..c8e238c6 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -113,6 +113,8 @@ class NetworkPlugin { /// \param xhtml XHTML message. void handleMessage(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &nickname = "", const std::string &xhtml = "", const std::string ×tamp = "", bool headline = false); + void handleMessageAck(const std::string &user, const std::string &legacyName, const std::string &id); + /// Call this function when subject in room changed. /// \param user XMPP JID of user for which this event occurs. You can get it from NetworkPlugin::handleLoginRequest(). (eg. "user%gmail.com@xmpp.domain.tld") /// \param legacyName Name of room. (eg. "#spectrum") @@ -199,7 +201,7 @@ class NetworkPlugin { /// \param legacyName Legacy network name of buddy or room. /// \param message Plain text message. /// \param xhtml XHTML message. - virtual void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") = 0; + virtual void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "") = 0; /// Called when XMPP user requests VCard of buddy. /// \param user XMPP JID of user for which this event occurs. diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index b0d742b8..563d7080 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -100,6 +100,7 @@ class NetworkPluginServer { void handleBuddyChangedPayload(const std::string &payload); void handleBuddyRemovedPayload(const std::string &payload); void handleConvMessagePayload(const std::string &payload, bool subject = false); + void handleConvMessageAckPayload(const std::string &payload); void handleParticipantChangedPayload(const std::string &payload); void handleRoomChangedPayload(const std::string &payload); void handleVCardPayload(const std::string &payload); diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 5a1afd92..316b164e 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -71,6 +71,7 @@ message ConversationMessage { optional string xhtml = 5; optional string timestamp = 6; optional bool headline = 7; + optional string id = 8; } message Room { @@ -167,6 +168,7 @@ message WrapperMessage { TYPE_BACKEND_CONFIG = 30; TYPE_QUERY = 31; TYPE_ROOM_LIST = 32; + TYPE_CONV_MESSAGE_ACK = 33; } required Type type = 1; optional bytes payload = 2; diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index 3502894c..06393bf4 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -100,6 +100,21 @@ void NetworkPlugin::handleMessage(const std::string &user, const std::string &le send(message); } +void NetworkPlugin::handleMessageAck(const std::string &user, const std::string &legacyName, const std::string &id) { + pbnetwork::ConversationMessage m; + m.set_username(user); + m.set_buddyname(legacyName); + m.set_message(""); + m.set_id(id); + + std::string message; + m.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_CONV_MESSAGE_ACK); + + send(message); +} + void NetworkPlugin::handleAttention(const std::string &user, const std::string &buddyName, const std::string &msg) { pbnetwork::ConversationMessage m; m.set_username(user); @@ -391,7 +406,7 @@ void NetworkPlugin::handleConvMessagePayload(const std::string &data) { return; } - handleMessageSendRequest(payload.username(), payload.buddyname(), payload.message(), payload.xhtml()); + handleMessageSendRequest(payload.username(), payload.buddyname(), payload.message(), payload.xhtml(), payload.id()); } void NetworkPlugin::handleRoomSubjectChangedPayload(const std::string &data) { diff --git a/src/adhocmanager.cpp b/src/adhocmanager.cpp index 4ee20cfc..33133201 100644 --- a/src/adhocmanager.cpp +++ b/src/adhocmanager.cpp @@ -69,15 +69,13 @@ void AdHocManager::stop() { } void AdHocManager::handleUserCreated(User *user) { - if (!m_storageBackend) { - return; - } - for (std::map::const_iterator it = m_factories.begin(); it != m_factories.end(); it++) { for (std::map::const_iterator it2 = it->second->getUserSettings().begin(); it2 != it->second->getUserSettings().end(); it2++) { std::string value = CONFIG_STRING_DEFAULTED(m_component->getConfig(), it->second->getNode() + "." + it2->first, it2->second); - int type = (int) TYPE_BOOLEAN; - m_storageBackend->getUserSetting(user->getUserInfo().id, it2->first, type, value); + if (m_storageBackend) { + int type = (int) TYPE_BOOLEAN; + m_storageBackend->getUserSetting(user->getUserInfo().id, it2->first, type, value); + } user->addUserSetting(it2->first, value); } } diff --git a/src/config.cpp b/src/config.cpp index c37048fd..73b14d09 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -312,6 +312,7 @@ void Config::updateBackendConfig(const std::string &backendConfig) { ("registration.needPassword", value()->default_value(true), "") ("registration.needRegistration", value()->default_value(false), "") ("registration.extraField", value >()->multitoken(), "") + ("features.receipts", value()->default_value(false), "") ; std::stringstream ifs(backendConfig); @@ -319,6 +320,8 @@ void Config::updateBackendConfig(const std::string &backendConfig) { store(parsed, m_backendConfig); notify(m_backendConfig); + + onBackendConfigUpdated(); } Config *Config::createFromArgs(int argc, char **argv, std::string &error, std::string &host, int &port) { diff --git a/src/discoinforesponder.cpp b/src/discoinforesponder.cpp index 91f6b494..15ce1544 100644 --- a/src/discoinforesponder.cpp +++ b/src/discoinforesponder.cpp @@ -39,11 +39,12 @@ namespace Transport { DiscoInfoResponder::DiscoInfoResponder(Swift::IQRouter *router, Config *config) : Swift::GetResponder(router) { m_config = config; + m_config->onBackendConfigUpdated.connect(boost::bind(&DiscoInfoResponder::updateBuddyFeatures, this)); + m_buddyInfo = NULL; m_transportInfo.addIdentity(DiscoInfo::Identity(CONFIG_STRING(m_config, "identity.name"), CONFIG_STRING(m_config, "identity.category"), CONFIG_STRING(m_config, "identity.type"))); - m_buddyInfo.addIdentity(DiscoInfo::Identity(CONFIG_STRING(m_config, "identity.name"), "client", "pc")); std::list features; features.push_back("jabber:iq:register"); features.push_back("jabber:iq:gateway"); @@ -52,18 +53,25 @@ DiscoInfoResponder::DiscoInfoResponder(Swift::IQRouter *router, Config *config) features.push_back("http://jabber.org/protocol/commands"); setTransportFeatures(features); - features.clear(); + updateBuddyFeatures(); +} + +DiscoInfoResponder::~DiscoInfoResponder() { + delete m_buddyInfo; +} + +void DiscoInfoResponder::updateBuddyFeatures() { + std::list features; features.push_back("http://jabber.org/protocol/disco#items"); features.push_back("http://jabber.org/protocol/disco#info"); features.push_back("http://jabber.org/protocol/chatstates"); features.push_back("http://jabber.org/protocol/xhtml-im"); + if (CONFIG_BOOL_DEFAULTED(m_config, "features.receipts", false)) { + features.push_back("urn:xmpp:receipts"); + } setBuddyFeatures(features); } -DiscoInfoResponder::~DiscoInfoResponder() { - -} - void DiscoInfoResponder::setTransportFeatures(std::list &features) { for (std::list::iterator it = features.begin(); it != features.end(); it++) { if (!m_transportInfo.hasFeature(*it)) { @@ -73,14 +81,18 @@ void DiscoInfoResponder::setTransportFeatures(std::list &features) } void DiscoInfoResponder::setBuddyFeatures(std::list &f) { + delete m_buddyInfo; + m_buddyInfo = new Swift::DiscoInfo; + m_buddyInfo->addIdentity(DiscoInfo::Identity(CONFIG_STRING(m_config, "identity.name"), "client", "pc")); + for (std::list::iterator it = f.begin(); it != f.end(); it++) { - if (!m_buddyInfo.hasFeature(*it)) { - m_buddyInfo.addFeature(*it); + if (!m_buddyInfo->hasFeature(*it)) { + m_buddyInfo->addFeature(*it); } } CapsInfoGenerator caps("spectrum"); - m_capsInfo = caps.generateCapsInfo(m_buddyInfo); + m_capsInfo = caps.generateCapsInfo(*m_buddyInfo); onBuddyCapsInfoChanged(m_capsInfo); } @@ -136,7 +148,7 @@ bool DiscoInfoResponder::handleGetRequest(const Swift::JID& from, const Swift::J } // disco#info for buddy else { - boost::shared_ptr res(new DiscoInfo(m_buddyInfo)); + boost::shared_ptr res(new DiscoInfo(*m_buddyInfo)); res->setNode(info->getNode()); sendResponse(from, to, id, res); } diff --git a/src/discoinforesponder.h b/src/discoinforesponder.h index 12f93f1e..0ce5883b 100644 --- a/src/discoinforesponder.h +++ b/src/discoinforesponder.h @@ -51,9 +51,10 @@ class DiscoInfoResponder : public Swift::GetResponder { private: virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); + void updateBuddyFeatures(); Swift::DiscoInfo m_transportInfo; - Swift::DiscoInfo m_buddyInfo; + Swift::DiscoInfo *m_buddyInfo; Config *m_config; Swift::CapsInfo m_capsInfo; std::map m_rooms; diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 830d065e..55f3b335 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -686,6 +686,33 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool m_userManager->messageToXMPPSent(); } +void NetworkPluginServer::handleConvMessageAckPayload(const std::string &data) { + pbnetwork::ConversationMessage payload; + + if (payload.ParseFromString(data) == false) { + // TODO: ERROR + return; + } + + User *user = m_userManager->getUser(payload.username()); + if (!user) + return; + + + boost::shared_ptr msg(new Swift::Message()); + msg->addPayload(boost::make_shared(payload.id())); + + NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.buddyname()); + + // Receipts don't create conversation + if (!conv) { + return; + } + + // Forward it + conv->handleMessage(msg); +} + void NetworkPluginServer::handleAttentionPayload(const std::string &data) { pbnetwork::ConversationMessage payload; if (payload.ParseFromString(data) == false) { @@ -1023,6 +1050,9 @@ void NetworkPluginServer::handleDataRead(Backend *c, boost::shared_ptrgetLegacyName()); m.set_message(msg->getBody()); m.set_xhtml(xhtml); + boost::shared_ptr receiptPayload = msg->getPayload(); + if (receiptPayload && !msg->getID().empty()) { + m.set_id(msg->getID()); + } std::string message; m.SerializeToString(&message); diff --git a/src/tests/discoitemsresponder.cpp b/src/tests/discoitemsresponder.cpp index dfdf3619..73c9c8aa 100644 --- a/src/tests/discoitemsresponder.cpp +++ b/src/tests/discoitemsresponder.cpp @@ -28,6 +28,7 @@ class DiscoItemsResponderTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_TEST(roomList); CPPUNIT_TEST(roomInfo); CPPUNIT_TEST(clearRooms); + CPPUNIT_TEST(receipts); CPPUNIT_TEST_SUITE_END(); public: @@ -94,6 +95,32 @@ class DiscoItemsResponderTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT(getStanza(received[0])->getPayload()->getItems().empty()); } + void receipts() { + boost::shared_ptr payload(new Swift::DiscoInfo()); + boost::shared_ptr iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload); + iq->setFrom("user@localhost"); + iq->setTo("buddy@localhost"); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT(!getStanza(received[0])->getPayload()->hasFeature("urn:xmpp:receipts")); + received.clear(); + + cfg->updateBackendConfig("[features]\nreceipts=1\n"); + + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()->hasFeature("urn:xmpp:receipts")); + received.clear(); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION (DiscoItemsResponderTest); From 984a075019420c92f540eb85f5524cd5287983c8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 26 Dec 2012 09:59:09 +0100 Subject: [PATCH 2/4] Send RIE to all resources --- include/transport/user.h | 2 +- src/rostermanager.cpp | 17 +++++++++-------- src/user.cpp | 10 ++++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/transport/user.h b/include/transport/user.h index d164852f..f7752f07 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -57,7 +57,7 @@ class User : public Swift::EntityCapsProvider { /// Returns full JID which supports particular feature or invalid JID. /// \param feature disco#info feature. /// \return full JID which supports particular feature or invalid JID. - Swift::JID getJIDWithFeature(const std::string &feature); + std::vector getJIDWithFeature(const std::string &feature); Swift::DiscoInfo::ref getCaps(const Swift::JID &jid) const; diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 34a2d690..ebb7c456 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -232,8 +232,8 @@ void RosterManager::setBuddyCallback(Buddy *buddy) { } else { // Send RIE only if there's resource which supports it. - Swift::JID jidWithRIE = m_user->getJIDWithFeature("http://jabber.org/protocol/rosterx"); - if (jidWithRIE.isValid()) { + std::vector jidWithRIE = m_user->getJIDWithFeature("http://jabber.org/protocol/rosterx"); + if (!jidWithRIE.empty()) { m_RIETimer->start(); } else { @@ -317,10 +317,10 @@ void RosterManager::sendRIE() { m_RIETimer->stop(); // Check the feature, because proper resource could logout during RIETimer. - Swift::JID jidWithRIE = m_user->getJIDWithFeature("http://jabber.org/protocol/rosterx"); + std::vector jidWithRIE = m_user->getJIDWithFeature("http://jabber.org/protocol/rosterx"); // fallback to normal subscribe - if (!jidWithRIE.isValid()) { + if (jidWithRIE.empty()) { for (std::map, boost::pool_allocator< std::pair > >::iterator it = m_buddies.begin(); it != m_buddies.end(); it++) { Buddy *buddy = (*it).second; if (!buddy) { @@ -331,8 +331,6 @@ void RosterManager::sendRIE() { return; } - LOG4CXX_INFO(logger, "Sending RIE stanza to " << jidWithRIE.toString()); - Swift::RosterItemExchangePayload::ref payload = Swift::RosterItemExchangePayload::ref(new Swift::RosterItemExchangePayload()); for (std::map, boost::pool_allocator< std::pair > >::iterator it = m_buddies.begin(); it != m_buddies.end(); it++) { Buddy *buddy = (*it).second; @@ -348,8 +346,11 @@ void RosterManager::sendRIE() { payload->addItem(item); } - boost::shared_ptr > request(new Swift::GenericRequest(Swift::IQ::Set, jidWithRIE, payload, m_component->getIQRouter())); - request->send(); + BOOST_FOREACH(Swift::JID &jid, jidWithRIE) { + LOG4CXX_INFO(logger, "Sending RIE stanza to " << jid.toString()); + boost::shared_ptr > request(new Swift::GenericRequest(Swift::IQ::Set, jid, payload, m_component->getIQRouter())); + request->send(); + } } void RosterManager::handleSubscription(Swift::Presence::ref presence) { diff --git a/src/user.cpp b/src/user.cpp index 86f908bd..82a45bdd 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -83,8 +83,8 @@ const Swift::JID &User::getJID() { return m_jid; } -Swift::JID User::getJIDWithFeature(const std::string &feature) { - Swift::JID jid; +std::vector User::getJIDWithFeature(const std::string &feature) { + std::vector jid; std::vector presences = m_presenceOracle->getAllPresence(m_jid); foreach(Swift::Presence::ref presence, presences) { @@ -111,11 +111,13 @@ Swift::JID User::getJIDWithFeature(const std::string &feature) { if (discoInfo->hasFeature(feature)) { LOG4CXX_INFO(logger, m_jid.toString() << ": Found JID with " << feature << " feature: " << presence->getFrom().toString()); - return presence->getFrom(); + jid.push_back(presence->getFrom()); } } - LOG4CXX_INFO(logger, m_jid.toString() << ": No JID with " << feature << " feature " << m_legacyCaps.size()); + if (jid.empty()) { + LOG4CXX_INFO(logger, m_jid.toString() << ": No JID with " << feature << " feature " << m_legacyCaps.size()); + } return jid; } From 2ae5cba932b17fbc7400eb9d9be9b7593dc4effa Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 27 Dec 2012 15:02:21 +0100 Subject: [PATCH 3/4] service.login_delay --- include/transport/networkpluginserver.h | 6 ++- src/config.cpp | 1 + src/networkpluginserver.cpp | 67 +++++++++++++++++-------- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 563d7080..738a0cc8 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -141,7 +141,9 @@ class NetworkPluginServer { void pingTimeout(); void sendPing(Backend *c); - Backend *getFreeClient(bool acceptUsers = true, bool longRun = false); + Backend *getFreeClient(bool acceptUsers = true, bool longRun = false, bool check = false); + void connectWaitingUsers(); + void loginDelayFinished(); UserManager *m_userManager; VCardResponder *m_vcardResponder; @@ -152,6 +154,7 @@ class NetworkPluginServer { std::list m_clients; Swift::Timer::ref m_pingTimer; Swift::Timer::ref m_collectTimer; + Swift::Timer::ref m_loginTimer; Component *m_component; std::list m_waitingUsers; bool m_isNextLongRun; @@ -161,6 +164,7 @@ class NetworkPluginServer { AdminInterface *m_adminInterface; bool m_startingBackend; DiscoItemsResponder *m_discoItemsResponder; + time_t m_lastLogin; }; } diff --git a/src/config.cpp b/src/config.cpp index 73b14d09..8873c862 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -98,6 +98,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("service.enable_privacy_lists", value()->default_value(true), "") ("service.enable_xhtml", value()->default_value(true), "") ("service.max_room_list_size", value()->default_value(100), "") + ("service.login_delay", value()->default_value(0), "") ("service.jid_escaping", value()->default_value(true), "") ("service.vip_only", value()->default_value(false), "") ("service.vip_message", value()->default_value(""), "") diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 55f3b335..a012ee87 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -258,6 +258,7 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U m_isNextLongRun = false; m_adminInterface = NULL; m_startingBackend = false; + m_lastLogin = 0; m_discoItemsResponder = discoItemsResponder; m_component->m_factory = new NetworkFactory(this); m_userManager->onUserCreated.connect(boost::bind(&NetworkPluginServer::handleUserCreated, this, _1)); @@ -267,6 +268,10 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U m_pingTimer->onTick.connect(boost::bind(&NetworkPluginServer::pingTimeout, this)); m_pingTimer->start(); + m_loginTimer = component->getNetworkFactories()->getTimerFactory()->createTimer(CONFIG_INT(config, "service.login_delay") * 1000); + m_loginTimer->onTick.connect(boost::bind(&NetworkPluginServer::loginDelayFinished, this)); + m_loginTimer->start(); + if (CONFIG_INT(m_config, "service.memory_collector_time") != 0) { m_collectTimer = component->getNetworkFactories()->getTimerFactory()->createTimer(CONFIG_INT(m_config, "service.memory_collector_time")); m_collectTimer->onTick.connect(boost::bind(&NetworkPluginServer::collectBackend, this)); @@ -355,6 +360,11 @@ void NetworkPluginServer::start() { } } +void NetworkPluginServer::loginDelayFinished() { + m_loginTimer->stop(); + connectWaitingUsers(); +} + void NetworkPluginServer::handleNewClientConnection(boost::shared_ptr c) { // Create new Backend instance Backend *client = new Backend; @@ -857,6 +867,29 @@ void NetworkPluginServer::handleFTDataNeeded(Backend *b, unsigned long ftid) { send(b->connection, message); } +void NetworkPluginServer::connectWaitingUsers() { + // some users are in queue waiting for this backend + while(!m_waitingUsers.empty()) { + // There's no new backend, so stop associating users and wait for new backend, + // which has been already spawned in getFreeClient() call. + if (getFreeClient(true, false, true) == NULL) + break; + + User *u = m_waitingUsers.front(); + m_waitingUsers.pop_front(); + + LOG4CXX_INFO(logger, "Associating " << u->getJID().toString() << " with this backend"); + + // associate backend with user + handleUserCreated(u); + + // connect user if it's ready + if (u->isReadyToConnect()) { + handleUserReadyToConnect(u); + } + } +} + void NetworkPluginServer::handlePongReceived(Backend *c) { // This could be first PONG from the backend if (c->pongReceived == -1) { @@ -868,26 +901,7 @@ void NetworkPluginServer::handlePongReceived(Backend *c) { m_component->start(); } - // some users are in queue waiting for this backend - while(!m_waitingUsers.empty()) { - // There's no new backend, so stop associating users and wait for new backend, - // which has been already spawned in getFreeClient() call. - if (getFreeClient() == NULL) - break; - - User *u = m_waitingUsers.front(); - m_waitingUsers.pop_front(); - - LOG4CXX_INFO(logger, "Associating " << u->getJID().toString() << " with this backend"); - - // associate backend with user - handleUserCreated(u); - - // connect user if it's ready - if (u->isReadyToConnect()) { - handleUserReadyToConnect(u); - } - } + connectWaitingUsers(); } c->pongReceived = true; @@ -1642,9 +1656,20 @@ void NetworkPluginServer::sendPing(Backend *c) { // LOG4CXX_INFO(logger, "PING to " << c); } -NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUsers, bool longRun) { +NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUsers, bool longRun, bool check) { NetworkPluginServer::Backend *c = NULL; + unsigned long diff = CONFIG_INT(m_config, "service.login_delay"); + time_t now = time(NULL); + if (diff && (now - m_lastLogin < diff)) { + m_loginTimer->start(); + return NULL; + } + + if (!check) { + m_lastLogin = time(NULL); + } + // Check all backends and find free one for (std::list::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) { if ((*it)->willDie == false && (*it)->acceptUsers == acceptUsers && (*it)->users.size() < CONFIG_INT(m_config, "service.users_per_backend") && (*it)->connection && (*it)->longRun == longRun) { From 9c48437b09d7bbccd43170b28c521af36b7b2b70 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 28 Dec 2012 08:55:29 +0100 Subject: [PATCH 4/4] support for XEP-0172 --- src/rostermanager.cpp | 13 ++++--------- src/tests/rostermanager.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index ebb7c456..88b69971 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -204,7 +204,9 @@ void RosterManager::sendBuddySubscribePresence(Buddy *buddy) { response->setTo(m_user->getJID()); response->setFrom(buddy->getJID()); response->setType(Swift::Presence::Subscribe); -// TODO: NICKNAME + if (!buddy->getAlias().empty()) { + response->addPayload(boost::make_shared(buddy->getAlias())); + } m_component->getStanzaChannel()->sendPresence(response); } @@ -231,14 +233,7 @@ void RosterManager::setBuddyCallback(Buddy *buddy) { sendBuddyRosterPush(buddy); } else { - // Send RIE only if there's resource which supports it. - std::vector jidWithRIE = m_user->getJIDWithFeature("http://jabber.org/protocol/rosterx"); - if (!jidWithRIE.empty()) { - m_RIETimer->start(); - } - else { - sendBuddySubscribePresence(buddy); - } + m_RIETimer->start(); } } diff --git a/src/tests/rostermanager.cpp b/src/tests/rostermanager.cpp index 774212cf..e9e5f903 100644 --- a/src/tests/rostermanager.cpp +++ b/src/tests/rostermanager.cpp @@ -25,6 +25,7 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST(setBuddy); CPPUNIT_TEST(sendCurrentPresences); CPPUNIT_TEST(sendCurrentPresence); + CPPUNIT_TEST(sendBuddySubscribePresence); CPPUNIT_TEST(removeBuddy); CPPUNIT_TEST(subscribeExistingBuddy); CPPUNIT_TEST(subscribeNewBuddy); @@ -59,6 +60,17 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { m_buddy = buddy->getName(); } + void sendBuddySubscribePresence() { + add2Buddies(); + received.clear(); + User *user = userManager->getUser("user@localhost"); + user->getRosterManager()->sendBuddySubscribePresence(user->getRosterManager()->getBuddy("buddy1")); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("Buddy 1"), getStanza(received[0])->getPayload()->getNickname()); + + } + void setBuddy() { add2Buddies(); CPPUNIT_ASSERT_EQUAL(2, (int) received.size());