From 5f04f459038b7e15c3e335f0c1d3b0faf2165a51 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Sat, 6 Feb 2016 15:50:53 +0100 Subject: [PATCH] Libtransport: Fix #85 - Add iconhash field to Participant type. When backend uses that field, Frontends will ask for VCards with name set to 'room/user' format. --- include/transport/Conversation.h | 4 +- include/transport/protocol.proto | 1 + libtransport/Conversation.cpp | 13 ++-- libtransport/NetworkPluginServer.cpp | 2 +- .../src/frontends/xmpp/vcardresponder.cpp | 4 ++ tests/libtransport/VCardResponder.cpp | 63 +++++++++++++++++++ tests/libtransport/conversationmanager.cpp | 28 +++++++++ 7 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 tests/libtransport/VCardResponder.cpp diff --git a/include/transport/Conversation.h b/include/transport/Conversation.h index ec8fa2c6..94ae77d4 100644 --- a/include/transport/Conversation.h +++ b/include/transport/Conversation.h @@ -81,7 +81,7 @@ class Conversation { /// \param status Current status of this participant. /// \param statusMessage Current status message of this participant. /// \param newname If participant was renamed, this variable contains his new name. - void handleParticipantChanged(const std::string &nickname, ParticipantFlag flag, int status = Swift::StatusShow::None, const std::string &statusMessage = "", const std::string &newname = ""); + void handleParticipantChanged(const std::string &nickname, ParticipantFlag flag, int status = Swift::StatusShow::None, const std::string &statusMessage = "", const std::string &newname = "", const std::string &iconhash = ""); /// Sets XMPP user nickname in MUC rooms. @@ -154,7 +154,7 @@ class Conversation { void setMUCEscaping(bool mucEscaping); private: - Swift::Presence::ref generatePresence(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname = ""); + Swift::Presence::ref generatePresence(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname = "", const std::string &iconhash = ""); void cacheMessage(boost::shared_ptr &message); private: diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index d7bd76a9..48f11bf7 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -110,6 +110,7 @@ message Participant { required StatusType status = 5; optional string statusMessage = 6; optional string newname = 7; + optional string iconHash = 8; } message VCard { diff --git a/libtransport/Conversation.cpp b/libtransport/Conversation.cpp index bda7f39b..d1bfef72 100644 --- a/libtransport/Conversation.cpp +++ b/libtransport/Conversation.cpp @@ -34,6 +34,7 @@ #include "Swiften/Elements/MUCUserPayload.h" #include "Swiften/Elements/Delay.h" #include "Swiften/Elements/MUCPayload.h" +#include "Swiften/Elements/VCardUpdate.h" namespace Transport { @@ -252,7 +253,7 @@ void Conversation::sendCachedMessages(const Swift::JID &to) { m_cachedMessages.clear(); } -Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) { +Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname, const std::string &iconhash) { std::string nickname = nick; Swift::Presence::ref presence = Swift::Presence::create(); std::string legacyName = m_legacyName; @@ -330,6 +331,10 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int p->addStatusCode(c); presence->setType(Swift::Presence::Unavailable); } + + if (!iconhash.empty()) { + presence->addPayload(boost::shared_ptr(new Swift::VCardUpdate (iconhash))); + } p->addItem(item); presence->addPayload(boost::shared_ptr(p)); @@ -350,8 +355,8 @@ void Conversation::handleRawPresence(Swift::Presence::ref presence) { m_participants[presence->getFrom().getResource()] = presence; } -void Conversation::handleParticipantChanged(const std::string &nick, Conversation::ParticipantFlag flag, int status, const std::string &statusMessage, const std::string &newname) { - Swift::Presence::ref presence = generatePresence(nick, flag, status, statusMessage, newname); +void Conversation::handleParticipantChanged(const std::string &nick, Conversation::ParticipantFlag flag, int status, const std::string &statusMessage, const std::string &newname, const std::string &iconhash) { + Swift::Presence::ref presence = generatePresence(nick, flag, status, statusMessage, newname, iconhash); if (presence->getType() == Swift::Presence::Unavailable) { m_participants.erase(nick); @@ -366,7 +371,7 @@ void Conversation::handleParticipantChanged(const std::string &nick, Conversatio m_conversationManager->getComponent()->getFrontend()->sendPresence(presence); } if (!newname.empty()) { - handleParticipantChanged(newname, flag, status, statusMessage); + handleParticipantChanged(newname, flag, status, statusMessage, "", iconhash); } if (m_sentInitialPresence && m_subject) { diff --git a/libtransport/NetworkPluginServer.cpp b/libtransport/NetworkPluginServer.cpp index ab18b261..8a5242f6 100644 --- a/libtransport/NetworkPluginServer.cpp +++ b/libtransport/NetworkPluginServer.cpp @@ -636,7 +636,7 @@ void NetworkPluginServer::handleParticipantChangedPayload(const std::string &dat return; } - conv->handleParticipantChanged(payload.nickname(), (Conversation::ParticipantFlag) payload.flag(), payload.status(), payload.statusmessage(), payload.newname()); + conv->handleParticipantChanged(payload.nickname(), (Conversation::ParticipantFlag) payload.flag(), payload.status(), payload.statusmessage(), payload.newname(), payload.iconhash()); } void NetworkPluginServer::handleRoomChangedPayload(const std::string &data) { diff --git a/spectrum/src/frontends/xmpp/vcardresponder.cpp b/spectrum/src/frontends/xmpp/vcardresponder.cpp index 5085af0a..951a26f3 100644 --- a/spectrum/src/frontends/xmpp/vcardresponder.cpp +++ b/spectrum/src/frontends/xmpp/vcardresponder.cpp @@ -95,6 +95,10 @@ bool VCardResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& } name = Buddy::JIDToLegacyName(to_, user); + // If the resource is not empty, it is probably VCard for room participant + if (!to.getResource().empty()) { + name += "/" + to.getResource(); + } LOG4CXX_INFO(logger, from.toBare().toString() << ": Requested VCard of " << name); diff --git a/tests/libtransport/VCardResponder.cpp b/tests/libtransport/VCardResponder.cpp new file mode 100644 index 00000000..6c6355d5 --- /dev/null +++ b/tests/libtransport/VCardResponder.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" +#include "vcardresponder.h" + +using namespace Transport; + +class VCardResponderTest : public CPPUNIT_NS :: TestFixture, public BasicTest { + CPPUNIT_TEST_SUITE(VCardResponderTest); + CPPUNIT_TEST(handleGetRequestMUC); + CPPUNIT_TEST_SUITE_END(); + + public: + std::string vcardName; + unsigned int vcardId; + + void setUp (void) { + setMeUp(); + connectUser(); + received.clear(); + component->getFrontend()->onVCardRequired.connect(boost::bind(&VCardResponderTest::handleVCardRequired, this, _1, _2, _3)); + } + + void tearDown (void) { + tearMeDown(); + } + + void handleVCardRequired(User *user, const std::string &name, unsigned int id) { + vcardName = name; + vcardId = id; + } + + void handleGetRequestMUC() { + boost::shared_ptr payload(new Swift::VCard()); + boost::shared_ptr iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "foobar", payload); + iq->setFrom("user@localhost/me"); + iq->setTo("#room@localhost/user"); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(std::string("#room/user"), vcardName); + + userManager->sendVCard(vcardId, payload); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (VCardResponderTest); diff --git a/tests/libtransport/conversationmanager.cpp b/tests/libtransport/conversationmanager.cpp index 2f711094..e2724e7d 100644 --- a/tests/libtransport/conversationmanager.cpp +++ b/tests/libtransport/conversationmanager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "Swiften/Server/ServerStanzaChannel.h" #include "Swiften/Server/ServerFromClientSession.h" #include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" @@ -28,6 +29,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_TEST(handleParticipantChangedEscaped); CPPUNIT_TEST(handleParticipantChangedEscaped2); CPPUNIT_TEST(handleParticipantChangedTwoResources); + CPPUNIT_TEST(handleParticipantChangedIconHash); CPPUNIT_TEST(handlePMFromXMPP); CPPUNIT_TEST(handleGroupchatRemoved); CPPUNIT_TEST(handleNicknameConflict); @@ -595,6 +597,32 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received[0])->getPayload()->getItems()[0].role); } + void handleParticipantChangedIconHash() { + User *user = userManager->getUser("user@localhost"); + TestingConversation *conv = new TestingConversation(user->getConversationManager(), "19:70027094a9c84c518535a610766bed65@thread.skype", true); + conv->setMUCEscaping(true); + + conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); + conv->setNickname("nickname"); + conv->addJID("user@localhost/resource"); + + // normal presence + conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message", "", "hash"); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[0]))->getShow()); + CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[0]))->getTo().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("19\\3a70027094a9c84c518535a610766bed65\\40thread.skype@localhost/anotheruser"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Member, *getStanza(received[0])->getPayload()->getItems()[0].affiliation); + CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received[0])->getPayload()->getItems()[0].role); + + Swift::VCardUpdate::ref payload = getStanza(received[0])->getPayload(); + CPPUNIT_ASSERT(payload); + } + void handleParticipantChangedTwoResources() { connectSecondResource(); received2.clear();