diff options
-rw-r--r-- | Swiften/Elements/Presence.cpp | 1 | ||||
-rw-r--r-- | Swiften/MUC/MUCImpl.cpp | 31 | ||||
-rw-r--r-- | Swiften/MUC/MUCImpl.h | 9 | ||||
-rw-r--r-- | Swiften/MUC/UnitTest/MUCTest.cpp | 14 | ||||
-rw-r--r-- | Swiften/Presence/DirectedPresenceSender.cpp | 12 | ||||
-rw-r--r-- | Swiften/Presence/DirectedPresenceSender.h | 8 |
6 files changed, 61 insertions, 14 deletions
diff --git a/Swiften/Elements/Presence.cpp b/Swiften/Elements/Presence.cpp index 38b8a4c..0e8d400 100644 --- a/Swiften/Elements/Presence.cpp +++ b/Swiften/Elements/Presence.cpp @@ -39,8 +39,7 @@ std::string Presence::getStatus() const { } void Presence::setStatus(const std::string& status) { updatePayload(boost::make_shared<Status>(status)); } - } diff --git a/Swiften/MUC/MUCImpl.cpp b/Swiften/MUC/MUCImpl.cpp index ab5faf4..778c290 100644 --- a/Swiften/MUC/MUCImpl.cpp +++ b/Swiften/MUC/MUCImpl.cpp @@ -11,12 +11,13 @@ #include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Base/foreach.h> #include <Swiften/Presence/DirectedPresenceSender.h> #include <Swiften/Client/StanzaChannel.h> #include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/CapsInfo.h> #include <Swiften/Elements/Form.h> #include <Swiften/Elements/Message.h> #include <Swiften/Elements/IQ.h> #include <Swiften/Elements/MUCUserPayload.h> #include <Swiften/Elements/MUCAdminPayload.h> #include <Swiften/Elements/MUCPayload.h> @@ -63,33 +64,49 @@ void MUCImpl::joinWithContextSince(const std::string &nick, const boost::posix_t } std::map<std::string, MUCOccupant> MUCImpl::getOccupants() const { return occupants; } +bool MUCImpl::isEqualExceptID(const Presence& lhs, const Presence& rhs) { + bool isEqual = false; + if (lhs.getFrom() == rhs.getFrom() && lhs.getTo() == rhs.getTo() && lhs.getStatus() == rhs.getStatus() && lhs.getShow() == rhs.getShow()) { + CapsInfo::ref lhsCaps = lhs.getPayload<CapsInfo>(); + CapsInfo::ref rhsCaps = rhs.getPayload<CapsInfo>(); + + if (!!lhsCaps && !!rhsCaps) { + isEqual = (*lhsCaps == *rhsCaps); + } + else { + isEqual = (!lhsCaps && !rhsCaps); + } + } + return isEqual; +} + void MUCImpl::internalJoin(const std::string &nick) { //TODO: history request joinComplete_ = false; joinSucceeded_ = false; mucRegistry->addMUC(getJID()); ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick); - Presence::ref joinPresence = boost::make_shared<Presence>(*presenceSender->getLastSentUndirectedPresence()); + Presence::ref joinPresence = presenceSender->getLastSentUndirectedPresence() ? (*presenceSender->getLastSentUndirectedPresence())->clone() : boost::make_shared<Presence>(); assert(joinPresence->getType() == Presence::Available); joinPresence->setTo(ownMUCJID); MUCPayload::ref mucPayload = boost::make_shared<MUCPayload>(); if (joinSince_ != boost::posix_time::not_a_date_time) { mucPayload->setSince(joinSince_); } if (password) { mucPayload->setPassword(*password); } joinPresence->addPayload(mucPayload); - + joinRequestPresence_ = joinPresence; presenceSender->sendPresence(joinPresence); } void MUCImpl::changeNickname(const std::string& newNickname) { Presence::ref changeNicknamePresence = boost::make_shared<Presence>(); changeNicknamePresence->setTo(ownMUCJID.toBare().toString() + std::string("/") + newNickname); @@ -134,13 +151,19 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { std::string reason; onJoinFailed(presence->getPayload<ErrorPayload>()); return; } else { joinSucceeded_ = true; - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + if (presenceSender->getLastSentUndirectedPresence() && !isEqualExceptID(**(presenceSender->getLastSentUndirectedPresence()), *joinRequestPresence_)) { + // our presence changed between join request and join complete, send current presence to MUC + Presence::ref latestPresence = boost::make_shared<Presence>(**presenceSender->getLastSentUndirectedPresence()); + latestPresence->setTo(ownMUCJID); + presenceSender->sendPresence(latestPresence); + } } } std::string nick = presence->getFrom().getResource(); if (nick.empty()) { return; @@ -242,12 +265,13 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); ownMUCJID = presence->getFrom(); presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); } onJoinComplete(getOwnNick()); } + // MUC status 201: a new room has been created if (status.code == 201) { isLocked = true; /* Room is created and locked */ /* Currently deal with this by making an instant room */ if (ownMUCJID != presence->getFrom()) { presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); @@ -256,12 +280,13 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { } if (createAsReservedIfNew) { unlocking = true; requestConfigurationForm(); } else { + // Accept default room configuration and create an instant room http://xmpp.org/extensions/xep-0045.html#createroom-instant MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); mucPayload->setPayload(boost::make_shared<Form>(Form::SubmitType)); boost::shared_ptr< GenericRequest<MUCOwnerPayload> > request = boost::make_shared< GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); request->send(); diff --git a/Swiften/MUC/MUCImpl.h b/Swiften/MUC/MUCImpl.h index 8eabb80..2979d70 100644 --- a/Swiften/MUC/MUCImpl.h +++ b/Swiften/MUC/MUCImpl.h @@ -1,8 +1,8 @@ /* - * Copyright (c) 2010-2013 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once @@ -91,12 +91,18 @@ namespace Swift { } const std::string& getOwnNick() const { return ownMUCJID.getResource(); } + /** + * This function compares two Presence elements for equality based on to, from, status, show and entity capability information. + * @return True if equal; else otherwise. + */ + static bool isEqualExceptID(const Presence& lhs, const Presence& rhs); + private: void handleIncomingPresence(Presence::ref presence); void internalJoin(const std::string& nick); void handleCreationConfigResponse(MUCOwnerPayload::ref, ErrorPayload::ref); void handleOccupantRoleChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Role); void handleAffiliationChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Affiliation); @@ -116,8 +122,9 @@ namespace Swift { boost::bsignals::scoped_connection scopedConnection_; boost::posix_time::ptime joinSince_; bool createAsReservedIfNew; bool unlocking; bool isUnlocked_; boost::optional<std::string> password; + Presence::ref joinRequestPresence_; }; } diff --git a/Swiften/MUC/UnitTest/MUCTest.cpp b/Swiften/MUC/UnitTest/MUCTest.cpp index 773edb6..e6f4608 100644 --- a/Swiften/MUC/UnitTest/MUCTest.cpp +++ b/Swiften/MUC/UnitTest/MUCTest.cpp @@ -25,12 +25,13 @@ using namespace Swift; class MUCTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(MUCTest); CPPUNIT_TEST(testJoin); CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinDoesNotSendPresenceBeforeJoinSuccess); CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinResendsPresenceAfterJoinSuccess); + CPPUNIT_TEST(testJoin_NoPresenceChangeDuringJoinDoesNotResendAfterJoinSuccess); CPPUNIT_TEST(testCreateInstant); CPPUNIT_TEST(testReplicateBug); CPPUNIT_TEST(testNicknameChange); /*CPPUNIT_TEST(testJoin_Success); CPPUNIT_TEST(testJoin_Fail);*/ CPPUNIT_TEST_SUITE_END(); @@ -82,12 +83,25 @@ class MUCTest : public CppUnit::TestFixture { Presence::ref p = channel->getStanzaAtIndex<Presence>(2); CPPUNIT_ASSERT(p); CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo()); CPPUNIT_ASSERT_EQUAL(std::string("Test"), p->getStatus()); } + void testJoin_NoPresenceChangeDuringJoinDoesNotResendAfterJoinSuccess() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + testling->joinAs("Alice"); + + receivePresence(JID("foo@bar.com/Rabbit"), "Here"); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); + Presence::ref p = channel->getStanzaAtIndex<Presence>(0); + CPPUNIT_ASSERT(p); + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo()); + CPPUNIT_ASSERT_EQUAL(std::string(""), p->getStatus()); + } + void testCreateInstant() { MUC::ref testling = createMUC(JID("rabbithole@wonderland.lit")); testling->joinAs("Alice"); Presence::ref serverRespondsLocked = boost::make_shared<Presence>(); serverRespondsLocked->setFrom(JID("rabbithole@wonderland.lit/Alice")); MUCUserPayload::ref mucPayload(new MUCUserPayload()); diff --git a/Swiften/Presence/DirectedPresenceSender.cpp b/Swiften/Presence/DirectedPresenceSender.cpp index ec0bd3f..c6cddbd 100644 --- a/Swiften/Presence/DirectedPresenceSender.cpp +++ b/Swiften/Presence/DirectedPresenceSender.cpp @@ -1,8 +1,8 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <Swiften/Presence/DirectedPresenceSender.h> #include <Swiften/Base/foreach.h> @@ -28,29 +28,29 @@ void DirectedPresenceSender::sendPresence(boost::shared_ptr<Presence> presence) lastSentUndirectedPresence = presence; } } /** - * Gets either the last broadcast presence, or an empty stanza if none has been sent. + * Gets the last broadcast presence, if none has been send the returned optional is not set. */ -boost::shared_ptr<Presence> DirectedPresenceSender::getLastSentUndirectedPresence() { - boost::shared_ptr<Presence> presenceCopy(lastSentUndirectedPresence ? new Presence(*lastSentUndirectedPresence) : new Presence()); +boost::optional<Presence::ref> DirectedPresenceSender::getLastSentUndirectedPresence() const { + boost::optional<Presence::ref> presenceCopy = lastSentUndirectedPresence ? boost::optional<Presence::ref>((*lastSentUndirectedPresence)->clone()) : boost::optional<Presence::ref>(); return presenceCopy; } /** * Send future broadcast presence also to this JID. * @param jid Non-roster JID to receive global presence updates. * @param sendPresence Also send the current global presence immediately. */ void DirectedPresenceSender::addDirectedPresenceReceiver(const JID& jid, SendPresence sendPresence) { directedPresenceReceivers.insert(jid); if (sendPresence == AndSendPresence && sender->isAvailable()) { - if (lastSentUndirectedPresence && lastSentUndirectedPresence->getType() == Presence::Available) { - boost::shared_ptr<Presence> presenceCopy(new Presence(*lastSentUndirectedPresence)); + if (lastSentUndirectedPresence && (*lastSentUndirectedPresence)->getType() == Presence::Available) { + boost::shared_ptr<Presence> presenceCopy((*lastSentUndirectedPresence)->clone()); presenceCopy->setTo(jid); sender->sendPresence(presenceCopy); } } } diff --git a/Swiften/Presence/DirectedPresenceSender.h b/Swiften/Presence/DirectedPresenceSender.h index 0eb16a4..511e177 100644 --- a/Swiften/Presence/DirectedPresenceSender.h +++ b/Swiften/Presence/DirectedPresenceSender.h @@ -1,16 +1,18 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <set> +#include <boost/optional.hpp> + #include <Swiften/Elements/Presence.h> #include <Swiften/Presence/PresenceSender.h> #include <Swiften/Base/API.h> namespace Swift { class SWIFTEN_API DirectedPresenceSender : public PresenceSender { @@ -20,16 +22,16 @@ namespace Swift { void addDirectedPresenceReceiver(const JID&, SendPresence); void removeDirectedPresenceReceiver(const JID&, SendPresence); void sendPresence(Presence::ref); - Presence::ref getLastSentUndirectedPresence(); + boost::optional<Presence::ref> getLastSentUndirectedPresence() const; bool isAvailable() const; private: - Presence::ref lastSentUndirectedPresence; + boost::optional<Presence::ref> lastSentUndirectedPresence; PresenceSender* sender; std::set<JID> directedPresenceReceivers; }; } |