diff options
author | Tobias Markmann <tm@ayena.de> | 2016-05-09 09:22:29 (GMT) |
---|---|---|
committer | Tobias Markmann <tm@ayena.de> | 2016-07-11 18:34:34 (GMT) |
commit | d508ac6ac41918d2c831b47b29761980989dd7f6 (patch) | |
tree | 3a93dd6f93727a4d74fbafb4ca0912bbe64e7a87 /Swiften | |
parent | bcd1c925eb2ef4af0f759366d7c5476cfc670366 (diff) | |
download | swift-d508ac6ac41918d2c831b47b29761980989dd7f6.zip swift-d508ac6ac41918d2c831b47b29761980989dd7f6.tar.bz2 |
Fix handling of incorrect MUC component behavior
Swift used to crash when a MUC component returned multiple
unavailable presences on rejoin of a room hosted on a
restarting buggy MUC component.
Test-Information:
Added test case that used to crash Swift. Tests pass without
crash on OS X 10.11.4
Change-Id: I52280976944170c6e143197d4b3dc517dc13ecbb
Diffstat (limited to 'Swiften')
-rw-r--r-- | Swiften/MUC/MUCImpl.cpp | 125 |
1 files changed, 66 insertions, 59 deletions
diff --git a/Swiften/MUC/MUCImpl.cpp b/Swiften/MUC/MUCImpl.cpp index 4bab39d..ba8d03e 100644 --- a/Swiften/MUC/MUCImpl.cpp +++ b/Swiften/MUC/MUCImpl.cpp @@ -10,7 +10,6 @@ #include <boost/bind.hpp> -#include <Swiften/Base/foreach.h> #include <Swiften/Client/StanzaChannel.h> #include <Swiften/Elements/CapsInfo.h> #include <Swiften/Elements/Form.h> @@ -138,7 +137,7 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { } MUCUserPayload::ref mucPayload; - foreach (MUCUserPayload::ref payload, presence->getPayloads<MUCUserPayload>()) { + for (MUCUserPayload::ref payload : presence->getPayloads<MUCUserPayload>()) { if (!payload->getItems().empty() || !payload->getStatusCodes().empty()) { mucPayload = payload; } @@ -148,11 +147,10 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { // (i.e. we start getting non-error presence from the MUC) or not if (!joinSucceeded_) { if (presence->getType() == Presence::Error) { - std::string reason; onJoinFailed(presence->getPayload<ErrorPayload>()); return; } - else { + else if (presence->getType() == Presence::Available) { joinSucceeded_ = true; presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); if (presenceSender->getLastSentUndirectedPresence() && !isEqualExceptID(**(presenceSender->getLastSentUndirectedPresence()), *joinRequestPresence_)) { @@ -162,6 +160,10 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { presenceSender->sendPresence(latestPresence); } } + else if (presence->getType() == Presence::Unavailable) { + onJoinFailed(std::shared_ptr<ErrorPayload>()); + return; + } } std::string nick = presence->getFrom().getResource(); @@ -188,19 +190,21 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { if (std::dynamic_pointer_cast<MUCDestroyPayload>(mucPayload->getPayload())) { type = LeaveDestroy; } - else foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { - if (status.code == 307) { - type = LeaveKick; - } - else if (status.code == 301) { - type = LeaveBan; - } - else if (status.code == 321) { - type = LeaveNotMember; - } - else if (status.code == 303) { - if (mucPayload->getItems().size() == 1) { - newNickname = mucPayload->getItems()[0].nick; + else { + for (MUCUserPayload::StatusCode status : mucPayload->getStatusCodes()) { + if (status.code == 307) { + type = LeaveKick; + } + else if (status.code == 301) { + type = LeaveBan; + } + else if (status.code == 321) { + type = LeaveNotMember; + } + else if (status.code == 303) { + if (mucPayload->getItems().size() == 1) { + newNickname = mucPayload->getItems()[0].nick; + } } } } @@ -254,50 +258,53 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { onOccupantJoined(result.first->second); } onOccupantPresenceChange(presence); - } - if (mucPayload && !joinComplete_) { - bool isLocked = false; - foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { - if (status.code == 110) { - /* Simply knowing this is your presence is enough, 210 doesn't seem to be necessary. */ - joinComplete_ = true; - if (ownMUCJID != presence->getFrom()) { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); - ownMUCJID = presence->getFrom(); - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - } - } - // 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); - ownMUCJID = presence->getFrom(); - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - } - if (createAsReservedIfNew) { - unlocking = true; - requestConfigurationForm(); + + if (mucPayload && !joinComplete_) { + bool isLocked = false; + for (MUCUserPayload::StatusCode status : mucPayload->getStatusCodes()) { + if (status.code == 110) { + /* Simply knowing this is your presence is enough, 210 doesn't seem to be necessary. */ + joinComplete_ = true; + if (ownMUCJID != presence->getFrom()) { + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + ownMUCJID = presence->getFrom(); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + } } - 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(std::make_shared<Form>(Form::SubmitType)); - std::shared_ptr< GenericRequest<MUCOwnerPayload> > request = std::make_shared< GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); - request->send(); + // 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); + ownMUCJID = presence->getFrom(); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + } + 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(std::make_shared<Form>(Form::SubmitType)); + std::shared_ptr< GenericRequest<MUCOwnerPayload> > request = std::make_shared< GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); + request->send(); + } } } - } - if (joinComplete_ && !isLocked) { - onJoinComplete(getOwnNick()); - } - if (!isLocked && !isUnlocked_ && (presence->getFrom() == ownMUCJID)) { - isUnlocked_ = true; - onUnlocked(); + + if (joinComplete_ && !isLocked) { + assert(hasOccupant(getOwnNick())); + onJoinComplete(getOwnNick()); + } + if (!isLocked && !isUnlocked_ && (presence->getFrom() == ownMUCJID)) { + isUnlocked_ = true; + onUnlocked(); + } } } } @@ -377,7 +384,7 @@ void MUCImpl::handleAffiliationListResponse(MUCAdminPayload::ref payload, ErrorP } else { std::vector<JID> jids; - foreach (MUCItem item, payload->getItems()) { + for (MUCItem item : payload->getItems()) { if (item.realJID) { jids.push_back(*item.realJID); } |