diff --git a/include/transport/User.h b/include/transport/User.h index d0bd7f7b..e65e6a4d 100644 --- a/include/transport/User.h +++ b/include/transport/User.h @@ -76,6 +76,7 @@ class User { UserManager *getUserManager() { return m_userManager; } virtual void disconnectUser(const std::string &error, Swift::SpectrumErrorPayload::Error e) = 0; + virtual void requestVCard() {} void setData(void *data) { m_data = data; } void *getData() { return m_data; } @@ -138,6 +139,10 @@ class User { m_reconnectLimit = limit; } + void setStorageBackend(StorageBackend *storageBackend) { + m_storageBackend = storageBackend; + } + void leaveRoom(const std::string &room); boost::signal onReadyToConnect; @@ -172,6 +177,7 @@ class User { std::map m_settings; bool m_cacheMessages; int m_reconnectLimit; + StorageBackend *m_storageBackend; }; } diff --git a/libtransport/NetworkPluginServer.cpp b/libtransport/NetworkPluginServer.cpp index 6871eded..b4a9e5eb 100644 --- a/libtransport/NetworkPluginServer.cpp +++ b/libtransport/NetworkPluginServer.cpp @@ -1842,6 +1842,11 @@ void NetworkPluginServer::handleBlockToggled(Buddy *b) { void NetworkPluginServer::handleVCardUpdated(User *user, boost::shared_ptr v) { + if (!v) { + LOG4CXX_INFO(logger, user->getJID().toString() << ": Received empty VCard"); + return; + } + pbnetwork::VCard vcard; vcard.set_username(user->getJID().toBare()); vcard.set_buddyname(""); diff --git a/libtransport/User.cpp b/libtransport/User.cpp index b92981fc..ee35157c 100644 --- a/libtransport/User.cpp +++ b/libtransport/User.cpp @@ -34,6 +34,7 @@ #include "Swiften/Elements/MUCPayload.h" #include "Swiften/Elements/SpectrumErrorPayload.h" #include "Swiften/Elements/CapsInfo.h" +#include "Swiften/Elements/VCardUpdate.h" #include #include #include @@ -67,6 +68,7 @@ User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component, User m_rosterManager = component->getFrontend()->createRosterManager(this, m_component); m_conversationManager = new ConversationManager(this, m_component); + LOG4CXX_INFO(logger, m_jid.toString() << ": Created"); updateLastActivity(); } @@ -170,6 +172,21 @@ void User::leaveRoom(const std::string &room) { void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { LOG4CXX_INFO(logger, "PRESENCE " << presence->getFrom().toString() << " " << presence->getTo().toString()); + + if (m_storageBackend) { + boost::shared_ptr vcardUpdate = presence->getPayload(); + if (vcardUpdate) { + std::string value = ""; + int type = (int) TYPE_STRING; + m_storageBackend->getUserSetting(m_userInfo.id, "photohash", type, value); + if (value != vcardUpdate->getPhotoHash()) { + LOG4CXX_INFO(logger, m_jid.toString() << ": Requesting VCard") + m_storageBackend->updateUserSetting(m_userInfo.id, "photohash", vcardUpdate->getPhotoHash()); + requestVCard(); + } + } + } + if (!m_connected) { // we are not connected to legacy network, so we should do it when disco#info arrive :) if (m_readyForConnect == false) { diff --git a/spectrum/src/frontends/xmpp/XMPPUser.cpp b/spectrum/src/frontends/xmpp/XMPPUser.cpp index e0353b6d..ba0f113a 100644 --- a/spectrum/src/frontends/xmpp/XMPPUser.cpp +++ b/spectrum/src/frontends/xmpp/XMPPUser.cpp @@ -26,6 +26,7 @@ #include "Swiften/Server/ServerStanzaChannel.h" #include "Swiften/Elements/StreamError.h" #include "Swiften/Elements/SpectrumErrorPayload.h" +#include "Swiften/Queries/IQRouter.h" #include #include #include @@ -54,6 +55,15 @@ XMPPUser::~XMPPUser(){ dynamic_cast(static_cast(m_component->getFrontend())->getStanzaChannel())->finishSession(m_jid, boost::shared_ptr()); #endif } + + if (m_vcardRequests.size() != 0) { + LOG4CXX_INFO(logger, m_jid.toString() << ": Removing " << m_vcardRequests.size() << " unresponded IQs"); + BOOST_FOREACH(Swift::GetVCardRequest::ref request, m_vcardRequests) { + request->onResponse.disconnect_all_slots(); + static_cast(m_component->getFrontend())->getIQRouter()->removeHandler(request); + } + m_vcardRequests.clear(); + } } void XMPPUser::disconnectUser(const std::string &error, Swift::SpectrumErrorPayload::Error e) { @@ -73,5 +83,20 @@ void XMPPUser::disconnectUser(const std::string &error, Swift::SpectrumErrorPayl } } +void XMPPUser::handleVCardReceived(boost::shared_ptr vcard, Swift::ErrorPayload::ref error, Swift::GetVCardRequest::ref request) { + m_vcardRequests.remove(request); + request->onResponse.disconnect_all_slots(); + m_component->getFrontend()->onVCardUpdated(this, vcard); +} + +void XMPPUser::requestVCard() { + LOG4CXX_INFO(logger, m_jid.toString() << ": Requesting VCard"); + + Swift::GetVCardRequest::ref request = Swift::GetVCardRequest::create(m_jid, static_cast(m_component->getFrontend())->getIQRouter()); + request->onResponse.connect(boost::bind(&XMPPUser::handleVCardReceived, this, _1, _2, request)); + request->send(); + m_vcardRequests.push_back(request); +} + } diff --git a/spectrum/src/frontends/xmpp/XMPPUser.h b/spectrum/src/frontends/xmpp/XMPPUser.h index 9ecdc0ba..29e62432 100644 --- a/spectrum/src/frontends/xmpp/XMPPUser.h +++ b/spectrum/src/frontends/xmpp/XMPPUser.h @@ -29,6 +29,7 @@ #include "Swiften/Elements/SpectrumErrorPayload.h" #include "Swiften/Network/Timer.h" #include "Swiften/Network/Connection.h" +#include "Swiften/VCards/GetVCardRequest.h" namespace Transport { @@ -54,15 +55,17 @@ class XMPPUser : public User { void disconnectUser(const std::string &error, Swift::SpectrumErrorPayload::Error e); - + void requestVCard(); private: void onConnectingTimeout(); + void handleVCardReceived(boost::shared_ptr vcard, Swift::ErrorPayload::ref error, Swift::GetVCardRequest::ref request); Swift::JID m_jid; Component *m_component; UserManager *m_userManager; UserInfo m_userInfo; + std::list m_vcardRequests; }; } diff --git a/tests/libtransport/user.cpp b/tests/libtransport/user.cpp index 8d40f277..9c7191e9 100644 --- a/tests/libtransport/user.cpp +++ b/tests/libtransport/user.cpp @@ -30,12 +30,14 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST(handleDisconnectedReconnect); CPPUNIT_TEST(joinRoomHandleDisconnectedRejoin); CPPUNIT_TEST(joinRoomAfterFlagNotAuthorized); + CPPUNIT_TEST(requestVCard); CPPUNIT_TEST_SUITE_END(); public: std::string room; std::string roomNickname; std::string roomPassword; + std::string photo; bool readyToConnect; bool disconnected; Swift::Presence::ref changedPresence; @@ -47,11 +49,14 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { room = ""; roomNickname = ""; roomPassword = ""; + photo = ""; setMeUp(); userManager->onUserCreated.connect(boost::bind(&UserTest::handleUserCreated, this, _1)); connectUser(); received.clear(); + + frontend->onVCardUpdated.connect(boost::bind(&UserTest::handleVCardUpdated, this, _1, _2)); } void tearDown (void) { @@ -63,6 +68,10 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { tearMeDown(); } + void handleVCardUpdated(User *user, boost::shared_ptr v) { + photo = Swift::byteArrayToString(v->getPhoto()); + } + void handleUserCreated(User *user) { user->onReadyToConnect.connect(boost::bind(&UserTest::handleUserReadyToConnect, this, user)); user->onPresenceChanged.connect(boost::bind(&UserTest::handleUserPresenceChanged, this, user, _1)); @@ -472,6 +481,36 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { handlePresenceJoinRoom(); } + void requestVCard() { + User *user = userManager->getUser("user@localhost"); + user->setStorageBackend(storage); + + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("localhost"); + response->setFrom("user@localhost/resource"); + response->addPayload(boost::shared_ptr(new Swift::VCardUpdate("hash"))); + + injectPresence(response); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + Swift::VCard::ref payload1 = getStanza(received[1])->getPayload(); + CPPUNIT_ASSERT(payload1); + + boost::shared_ptr vcard(new Swift::VCard()); + vcard->setPhoto(Swift::createByteArray("photo")); + injectIQ(Swift::IQ::createResult(getStanza(received[1])->getFrom(), getStanza(received[1])->getTo(), getStanza(received[1])->getID(), vcard)); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(std::string("photo"), photo); + + received.clear(); + injectPresence(response); + loop->processEvents(); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION (UserTest);