summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/Elements/Presence.cpp1
-rw-r--r--Swiften/MUC/MUCImpl.cpp31
-rw-r--r--Swiften/MUC/MUCImpl.h9
-rw-r--r--Swiften/MUC/UnitTest/MUCTest.cpp14
-rw-r--r--Swiften/Presence/DirectedPresenceSender.cpp12
-rw-r--r--Swiften/Presence/DirectedPresenceSender.h8
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;
};
}