From 16a895e7d64b71d1aa7a971d77e8daf6591e9c56 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Wed, 5 Oct 2011 14:39:47 +0100
Subject: Allow role changing in MUCs.

Resolves: #987

diff --git a/.subl/swift.sublime-project b/.subl/swift.sublime-project
index 464eaf3..5746207 100644
--- a/.subl/swift.sublime-project
+++ b/.subl/swift.sublime-project
@@ -4,7 +4,7 @@
 	[
 		{
 			"path": "..",
-			"folder_exclude_patterns": ["tmp", ".sconf_temp", ".settings", "Swift.app"],
+			"folder_exclude_patterns": ["tmp", ".sconf_temp", ".settings", "Swift.app", "3rdParty"],
 			"file_exclude_patterns": [".cproject", ".project", ".sconsign.dblite", "*~", "config.log", "*.o"]
 		}
 	],
@@ -12,5 +12,18 @@
 	{
 		"tab_size": 4,
 		"translate_tabs_to_spaces": false
-	}
+	},
+	"build_systems":
+	[
+		{
+			"name": "Scons",
+			"cmd" : ["./scons"],
+			"working_dir": ".."
+		},
+		{
+			"name": "Scons test",
+			"cmd" : ["./scons", "check=1"],
+			"working_dir": ".."
+		}
+	]
 }
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index 2b8a8b7..e413d92 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -85,6 +85,7 @@ MUCController::MUCController (
 	muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
 	muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
 	muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1));
+	muc_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, 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));
@@ -110,16 +111,22 @@ MUCController::~MUCController() {
 
 void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item) {
 	std::vector<ChatWindow::OccupantAction> actions;
-	//FIXME
+	/* FIXME: all of these should be conditional */
 	if (item) {
 		actions.push_back(ChatWindow::Kick);
+		actions.push_back(ChatWindow::MakeModerator);
+		actions.push_back(ChatWindow::MakeParticipant);
+		actions.push_back(ChatWindow::MakeVisitor);
 	}
 	chatWindow_->setAvailableOccupantActions(actions);
 }
 
 void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction action, ContactRosterItem* item) {
 	switch (action) {
-		case ChatWindow::Kick: muc_->kickUser(item->getJID());break;
+		case ChatWindow::Kick: muc_->kickOccupant(item->getJID());break;
+		case ChatWindow::MakeModerator: muc_->changeOccupantRole(item->getJID(), MUCOccupant::Moderator);break;
+		case ChatWindow::MakeParticipant: muc_->changeOccupantRole(item->getJID(), MUCOccupant::Participant);break;
+		case ChatWindow::MakeVisitor: muc_->changeOccupantRole(item->getJID(), MUCOccupant::Visitor);break;
 	}
 }
 
@@ -601,6 +608,12 @@ void MUCController::handleConfigurationFailed(ErrorPayload::ref error) {
 	chatWindow_->addErrorMessage(errorMessage);
 }
 
+void MUCController::handleOccupantRoleChangeFailed(ErrorPayload::ref error, const JID&, MUCOccupant::Role) {
+	std::string errorMessage = getErrorMessage(error);
+	errorMessage = str(format(QT_TRANSLATE_NOOP("", "Occupant role change failed: %1%.")) % errorMessage);
+	chatWindow_->addErrorMessage(errorMessage);
+}
+
 void MUCController::handleConfigurationFormReceived(Form::ref form) {
 	chatWindow_->showRoomConfigurationForm(form);
 }
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index d22d2ca..19d3f66 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -94,6 +94,7 @@ namespace Swift {
 			void handleDestroyRoomRequest();
 			void handleInvitePersonToThisMUCRequest(const JID& jid, const std::string& reason);
 			void handleConfigurationCancelled();
+			void handleOccupantRoleChangeFailed(ErrorPayload::ref, const JID&, MUCOccupant::Role);
 
 		private:
 			MUC::ref muc_;
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 836a330..4a93b42 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -32,7 +32,7 @@ namespace Swift {
 		public:
 			enum AckState {Pending, Received, Failed};
 			enum Tristate {Yes, No, Maybe};
-			enum OccupantAction {Kick};
+			enum OccupantAction {Kick, MakeModerator, MakeParticipant, MakeVisitor};
 			enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed};
 			ChatWindow() {}
 			virtual ~ChatWindow() {};
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 10daa68..7e47f4d 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -341,6 +341,7 @@ void QtChatWindow::setCorrectionEnabled(Tristate enabled) {
 
 SecurityLabelsCatalog::Item QtChatWindow::getSelectedSecurityLabel() {
 	assert(labelsWidget_->isEnabled());
+	assert(labelsWidget_->currentIndex() >= 0 && labelsWidget_->currentIndex() < availableLabels_.size());
 	return availableLabels_[labelsWidget_->currentIndex()];
 }
 
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
index cbda0f1..3ee0b7d 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
@@ -45,6 +45,9 @@ void QtOccupantListWidget::contextMenuEvent(QContextMenuEvent* event) {
 			QString text = "Error: missing string";
 			switch (availableAction) {
 				case ChatWindow::Kick: text = tr("Kick user"); break;
+				case ChatWindow::MakeModerator: text = tr("Make moderator"); break;
+				case ChatWindow::MakeParticipant: text = tr("Make participant"); break;
+				case ChatWindow::MakeVisitor: text = tr("Remove voice"); break;
 			}
 			QAction* action = contextMenu.addAction(text);
 			actions[action] = availableAction;
diff --git a/Swiften/Elements/SecurityLabelsCatalog.h b/Swiften/Elements/SecurityLabelsCatalog.h
index b9419a9..5498fcf 100644
--- a/Swiften/Elements/SecurityLabelsCatalog.h
+++ b/Swiften/Elements/SecurityLabelsCatalog.h
@@ -21,11 +21,11 @@ namespace Swift {
 			class Item {
 				public:
 					Item() : default_(false) {}
-					const boost::shared_ptr<SecurityLabel> getLabel() const {
+					SecurityLabel::ref getLabel() const {
 						return label_;
 					}
 
-					void setLabel(boost::shared_ptr<SecurityLabel> label) {
+					void setLabel(SecurityLabel::ref label) {
 						label_ = label;
 					}
 
@@ -41,7 +41,7 @@ namespace Swift {
 						default_ = isDefault;
 					}
 				private:
-					boost::shared_ptr<SecurityLabel> label_;
+					SecurityLabel::ref label_;
 					std::string selector_;
 					bool default_;
 			};
diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp
index 15355ad..204fdcc 100644
--- a/Swiften/MUC/MUC.cpp
+++ b/Swiften/MUC/MUC.cpp
@@ -237,20 +237,25 @@ MUCOccupant MUC::getOccupant(const std::string& nick) {
 	return occupants.find(nick)->second;
 }
 
-void MUC::kickUser(const JID& jid) {
+void MUC::kickOccupant(const JID& jid) {
+	changeOccupantRole(jid, MUCOccupant::NoRole);
+}
+
+void MUC::changeOccupantRole(const JID& jid, MUCOccupant::Role role) {
 	MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>();
 	MUCItem item;
-	item.role = MUCOccupant::NoRole;
+	item.role = role;
 	item.nick = jid.getResource();
 	mucPayload->addItem(item);
 	GenericRequest<MUCAdminPayload>* request = new GenericRequest<MUCAdminPayload>(IQ::Set, getJID(), mucPayload, iqRouter_);
-	request->onResponse.connect(boost::bind(&MUC::handleKickResponse, this, _1, _2, jid));
+	request->onResponse.connect(boost::bind(&MUC::handleOccupantRoleChangeResponse, this, _1, _2, jid, role));
 	request->send();
+	
 }
 
-void MUC::handleKickResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid) {
+void MUC::handleOccupantRoleChangeResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid, MUCOccupant::Role role) {
 	if (error) {
-		onKickFailed(error, jid);
+		onRoleChangeFailed(error, jid, role);
 	}
 }
 
diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h
index a9b42b8..d855033 100644
--- a/Swiften/MUC/MUC.h
+++ b/Swiften/MUC/MUC.h
@@ -56,7 +56,8 @@ namespace Swift {
 			/** Get occupant information*/
 			MUCOccupant getOccupant(const std::string& nick);
 			bool hasOccupant(const std::string& nick);
-			void kickUser(const JID& jid);
+			void kickOccupant(const JID& jid);
+			void changeOccupantRole(const JID& jid, MUCOccupant::Role role);
 			void changeSubject(const std::string& subject);
 			void requestConfigurationForm();
 			void configureRoom(Form::ref);
@@ -69,7 +70,7 @@ namespace Swift {
 		public:
 			boost::signal<void (const std::string& /*nick*/)> onJoinComplete;
 			boost::signal<void (ErrorPayload::ref)> onJoinFailed;
-			boost::signal<void (ErrorPayload::ref, const JID&)> onKickFailed;
+			boost::signal<void (ErrorPayload::ref, const JID&, MUCOccupant::Role)> onRoleChangeFailed;
 			boost::signal<void (ErrorPayload::ref)> onConfigurationFailed;
 			boost::signal<void (Presence::ref)> onOccupantPresenceChange;
 			boost::signal<void (const std::string&, const MUCOccupant& /*now*/, const MUCOccupant::Role& /*old*/)> onOccupantRoleChanged;
@@ -94,7 +95,7 @@ namespace Swift {
 			void handleIncomingPresence(Presence::ref presence);
 			void internalJoin(const std::string& nick);
 			void handleCreationConfigResponse(MUCOwnerPayload::ref, ErrorPayload::ref);
-			void handleKickResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&);
+			void handleOccupantRoleChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Role);
 			void handleConfigurationFormReceived(MUCOwnerPayload::ref, ErrorPayload::ref);
 			void handleConfigurationResultReceived(MUCOwnerPayload::ref, ErrorPayload::ref);
 
-- 
cgit v0.10.2-6-g49f6