diff options
| author | Kevin Smith <git@kismith.co.uk> | 2010-05-22 20:45:53 (GMT) | 
|---|---|---|
| committer | Kevin Smith <git@kismith.co.uk> | 2010-05-23 08:15:20 (GMT) | 
| commit | a68530cbbfeb17e01fd684b1ef41b960bc173f66 (patch) | |
| tree | 98b5cd195f04d781164cf1394cee9092bb7b2497 /Swift/Controllers/Chat | |
| parent | c9659b556b932e2f887cf1d8ab6c5a0bead835eb (diff) | |
| download | swift-contrib-a68530cbbfeb17e01fd684b1ef41b960bc173f66.zip swift-contrib-a68530cbbfeb17e01fd684b1ef41b960bc173f66.tar.bz2 | |
Implement XEP-0045 joining, and appropriate error handling.
Resolves: #211
Diffstat (limited to 'Swift/Controllers/Chat')
| -rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 120 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/MUCController.h | 14 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp | 2 | 
3 files changed, 116 insertions, 20 deletions
| diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index a8a6747..dbf03c9 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -45,7 +45,6 @@ MUCController::MUCController (  	ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle, avatarManager, useDelayForLatency, uiEventStream),  			muc_(new MUC(stanzaChannel, presenceSender, muc)),   	nick_(nick) { -	loginCheckTimer_ = boost::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS));  	parting_ = false;  	events_ = uiEventStream; @@ -53,11 +52,16 @@ MUCController::MUCController (  	chatWindow_->setRosterModel(roster_);  	chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this));  	muc_->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1)); +	muc_->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1));  	muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));  	muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));  	muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3)); -	loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this)); -	loginCheckTimer_->start(); +	muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3)); +	if (timerFactory) { +		loginCheckTimer_ = boost::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS)); +		loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this)); +		loginCheckTimer_->start(); +	}  	muc_->joinAs(nick);  	chatWindow_->convertToMUC(); @@ -72,21 +76,51 @@ MUCController::~MUCController() {  	delete muc_;  	chatWindow_->setRosterModel(NULL);  	delete roster_; -	loginCheckTimer_->stop(); +	if (loginCheckTimer_) { +		loginCheckTimer_->stop(); +	}  }  void MUCController::handleJoinTimeoutTick() { -	loginCheckTimer_->stop(); +	receivedActivity();  	chatWindow_->addSystemMessage("Room " + toJID_.toString() + " is not responding. This operation may never complete");  } -void MUCController::handleJoinComplete(MUC::JoinResult result) { -	loginCheckTimer_->stop(); -	if (result == MUC::JoinFailed) { -		chatWindow_->addErrorMessage("Unable to join this room"); -	}  +void MUCController::receivedActivity() { +	if (loginCheckTimer_) { +		loginCheckTimer_->stop(); +	} +} + +void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) { +	receivedActivity(); +	String errorMessage = "Unable to join this room"; +	String rejoinNick; +	if (error) { +		switch (error->getCondition()) { +		case ErrorPayload::Conflict: rejoinNick = nick_ + "_"; errorMessage += " as " + nick_ + ", retrying as " + rejoinNick; break; +		case ErrorPayload::JIDMalformed: errorMessage += ", no nickname specified";break; +		case ErrorPayload::NotAuthorized: errorMessage += ", a password needed";break; +		case ErrorPayload::RegistrationRequired: errorMessage += ", only members may join"; break; +		case ErrorPayload::Forbidden: errorMessage += ", you are banned from the room"; break; +		case ErrorPayload::ServiceUnavailable: errorMessage += ", the room is full";break; +		case ErrorPayload::ItemNotFound: errorMessage += ", the room does not exist";break; +			 +		default: break; +		} +	} +	errorMessage += "."; +	chatWindow_->addErrorMessage(errorMessage); +	if (!rejoinNick.isEmpty()) { +		muc_->joinAs(rejoinNick); +	} +} + +void MUCController::handleJoinComplete(const String& nick) { +	receivedActivity();  	joined_ = true; -	String joinMessage = "You have joined room " + toJID_.toString() + " as " + nick_; +	String joinMessage = "You have joined room " + toJID_.toString() + " as " + nick; +	nick_ = nick;  	chatWindow_->addSystemMessage(joinMessage);  } @@ -105,18 +139,76 @@ void MUCController::handleWindowClosed() {  }  void MUCController::handleOccupantJoined(const MUCOccupant& occupant) { -	JID jid(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick())); -	roster_->addContact(jid, occupant.getNick(), "Occupants"); +	receivedActivity(); +	JID jid(nickToJID(occupant.getNick())); +	roster_->addContact(jid, occupant.getNick(), roleToGroupName(occupant.getRole())); +	if (joined_) { +		String joinString = occupant.getNick() + " has joined the room"; +		MUCOccupant::Role role = occupant.getRole(); +		if (role != MUCOccupant::NoRole && role != MUCOccupant::Participant) { +			joinString += " as a " + roleToFriendlyName(role); + +		} +		joinString += "."; +		chatWindow_->addSystemMessage(joinString); +	}  	if (avatarManager_ != NULL) {  		handleAvatarChanged(jid, "dummy");  	}  } -void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType, const String& /*reason*/) { +String MUCController::roleToFriendlyName(MUCOccupant::Role role) { +	switch (role) { +	case MUCOccupant::Moderator: return "moderator"; +	case MUCOccupant::Participant: return "participant"; +	case MUCOccupant::Visitor: return "visitor"; +	case MUCOccupant::NoRole: return ""; +	} +	return ""; +} + +JID MUCController::nickToJID(const String& nick) { +	return JID(toJID_.getNode(), toJID_.getDomain(), nick); +} + +void MUCController::preHandleIncomingMessage(boost::shared_ptr<Message>) { +	/*Buggy implementations never send the status code, so use an incoming message as a hint that joining's done (e.g. the old ejabberd on psi-im.org).*/ +	receivedActivity(); +	joined_ = true; +} + +void MUCController::handleOccupantRoleChanged(const String& nick, const MUCOccupant::Role& newRole, const MUCOccupant::Role& oldRole) { +	receivedActivity(); +	JID jid(nickToJID(nick)); +	roster_->removeContactFromGroup(jid, roleToGroupName(oldRole)); +	roster_->addContact(jid, nick, roleToGroupName(newRole)); +	chatWindow_->addSystemMessage(nick + " is now a " + roleToFriendlyName(newRole)); +} + +String MUCController::roleToGroupName(MUCOccupant::Role role) { +	String result; +	switch (role) { +	case MUCOccupant::Moderator: result = "Moderators"; break; +	case MUCOccupant::Participant: result = "Participants"; break; +	case MUCOccupant::Visitor: result = "Visitors"; break; +	case MUCOccupant::NoRole: result = "Occupants"; break; +	default: assert(false); +	} +	return result; +} + +void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType, const String& reason) { +	String partMessage = occupant.getNick() + " has left the room"; +	if (!reason.isEmpty()) { +		partMessage += " (" + reason + ")"; +	} +	partMessage += "."; +	chatWindow_->addSystemMessage(partMessage);  	roster_->removeContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick()));  }  void MUCController::handleOccupantPresenceChange(boost::shared_ptr<Presence> presence) { +	receivedActivity();  	roster_->applyOnItems(SetPresence(presence, JID::WithResource));  } diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index 9e79835..247a942 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -4,8 +4,7 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#ifndef SWIFTEN_MUCController_H -#define SWIFTEN_MUCController_H +#pragma once  #include <boost/shared_ptr.hpp>  #include <boost/signals.hpp> @@ -47,9 +46,15 @@ namespace Swift {  			void handleOccupantJoined(const MUCOccupant& occupant);  			void handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType type, const String& reason);  			void handleOccupantPresenceChange(boost::shared_ptr<Presence> presence); -			void handleJoinComplete(MUC::JoinResult result); +			void handleOccupantRoleChanged(const String& nick, const MUCOccupant::Role& newRole, const MUCOccupant::Role& oldRole); +			void handleJoinComplete(const String& nick); +			void handleJoinFailed(boost::shared_ptr<ErrorPayload> error);  			void handleJoinTimeoutTick(); - +			String roleToGroupName(MUCOccupant::Role role); +			JID nickToJID(const String& nick); +			String roleToFriendlyName(MUCOccupant::Role role); +			void receivedActivity(); +			void preHandleIncomingMessage(boost::shared_ptr<Message>);  		private:  			MUC* muc_;  			UIEventStream* events_; @@ -61,5 +66,4 @@ namespace Swift {  			boost::shared_ptr<Timer> loginCheckTimer_;  	};  } -#endif diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index 99b2f90..2204366 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -64,7 +64,7 @@ public:  		uiEventStream_ = new UIEventStream();  		chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>();  		mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createWindow).With(uiEventStream_).Return(NULL); -		manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_, chatListWindowFactory_, true); +		manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL);  		avatarManager_ = new MockAvatarManager();  		manager_->setAvatarManager(avatarManager_);  	}; | 
 Swift
 Swift