summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/MUC/MUCImpl.cpp')
-rw-r--r--Swiften/MUC/MUCImpl.cpp41
1 files changed, 32 insertions, 9 deletions
diff --git a/Swiften/MUC/MUCImpl.cpp b/Swiften/MUC/MUCImpl.cpp
index a1854e3..ab5faf4 100644
--- a/Swiften/MUC/MUCImpl.cpp
+++ b/Swiften/MUC/MUCImpl.cpp
@@ -1,37 +1,37 @@
/*
- * 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.
*/
#include <Swiften/MUC/MUCImpl.h>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#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/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>
#include <Swiften/Elements/MUCDestroyPayload.h>
#include <Swiften/Elements/MUCInvitationPayload.h>
#include <Swiften/MUC/MUCRegistry.h>
#include <Swiften/Queries/GenericRequest.h>
namespace Swift {
typedef std::pair<std::string, MUCOccupant> StringMUCOccupantPair;
MUCImpl::MUCImpl(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry) : ownMUCJID(muc), stanzaChannel(stanzaChannel), iqRouter_(iqRouter), presenceSender(presenceSender), mucRegistry(mucRegistry), createAsReservedIfNew(false), unlocking(false), isUnlocked_(false) {
scopedConnection_ = stanzaChannel->onPresenceReceived.connect(boost::bind(&MUCImpl::handleIncomingPresence, this, _1));
}
MUCImpl::~MUCImpl()
{
@@ -58,162 +58,185 @@ void MUCImpl::setPassword(const boost::optional<std::string>& newPassword) {
* Join the MUC with context since date.
*/
void MUCImpl::joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since) {
joinSince_ = since;
internalJoin(nick);
}
std::map<std::string, MUCOccupant> MUCImpl::getOccupants() const {
return occupants;
}
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());
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);
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);
+ presenceSender->sendPresence(changeNicknamePresence);
+}
+
void MUCImpl::part() {
presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence);
mucRegistry->removeMUC(getJID());
}
void MUCImpl::handleUserLeft(LeavingType type) {
std::map<std::string,MUCOccupant>::iterator i = occupants.find(ownMUCJID.getResource());
if (i != occupants.end()) {
MUCOccupant me = i->second;
occupants.erase(i);
onOccupantLeft(me, type, "");
}
occupants.clear();
joinComplete_ = false;
joinSucceeded_ = false;
isUnlocked_ = false;
presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence);
}
void MUCImpl::handleIncomingPresence(Presence::ref presence) {
if (!isFromMUC(presence->getFrom())) {
return;
}
MUCUserPayload::ref mucPayload;
foreach (MUCUserPayload::ref payload, presence->getPayloads<MUCUserPayload>()) {
if (!payload->getItems().empty() || !payload->getStatusCodes().empty()) {
mucPayload = payload;
}
}
// On the first incoming presence, check if our join has succeeded
// (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 {
joinSucceeded_ = true;
presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence);
}
}
std::string nick = presence->getFrom().getResource();
if (nick.empty()) {
return;
}
MUCOccupant::Role role(MUCOccupant::NoRole);
MUCOccupant::Affiliation affiliation(MUCOccupant::NoAffiliation);
boost::optional<JID> realJID;
if (mucPayload && mucPayload->getItems().size() > 0) {
role = mucPayload->getItems()[0].role ? mucPayload->getItems()[0].role.get() : MUCOccupant::NoRole;
affiliation = mucPayload->getItems()[0].affiliation ? mucPayload->getItems()[0].affiliation.get() : MUCOccupant::NoAffiliation;
realJID = mucPayload->getItems()[0].realJID;
}
//100 is non-anonymous
//TODO: 100 may also be specified in a <message/>
//170 is room logging to http
//TODO: Nick changes
if (presence->getType() == Presence::Unavailable) {
LeavingType type = LeavePart;
+ boost::optional<std::string> newNickname;
if (mucPayload) {
if (boost::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;
+ }
+ }
}
}
-
- if (presence->getFrom() == ownMUCJID) {
- handleUserLeft(type);
- return;
- }
- else {
+ if (newNickname) {
std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick);
if (i != occupants.end()) {
- //TODO: part type
MUCOccupant occupant = i->second;
occupants.erase(i);
- onOccupantLeft(occupant, type, "");
+ occupant.setNick(newNickname.get());
+ occupants.insert(std::make_pair(newNickname.get(), occupant));
+ onOccupantNicknameChanged(nick, newNickname.get());
+ }
+ }
+ else {
+ if (presence->getFrom() == ownMUCJID) {
+ handleUserLeft(type);
+ return;
+ }
+ else {
+ std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick);
+ if (i != occupants.end()) {
+ //TODO: part type
+ MUCOccupant occupant = i->second;
+ occupants.erase(i);
+ onOccupantLeft(occupant, type, "");
+ }
}
}
}
else if (presence->getType() == Presence::Available) {
std::map<std::string, MUCOccupant>::iterator it = occupants.find(nick);
MUCOccupant occupant(nick, role, affiliation);
bool isJoin = true;
if (realJID) {
occupant.setRealJID(realJID.get());
}
if (it != occupants.end()) {
isJoin = false;
MUCOccupant oldOccupant = it->second;
if (oldOccupant.getRole() != role) {
onOccupantRoleChanged(nick, occupant, oldOccupant.getRole());
}
if (oldOccupant.getAffiliation() != affiliation) {
onOccupantAffiliationChanged(nick, affiliation, oldOccupant.getAffiliation());
}
occupants.erase(it);
}
std::pair<std::map<std::string, MUCOccupant>::iterator, bool> result = occupants.insert(std::make_pair(nick, occupant));
if (isJoin) {
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);