summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Smith <git@kismith.co.uk>2011-10-05 13:39:47 (GMT)
committerKevin Smith <git@kismith.co.uk>2011-10-05 13:39:47 (GMT)
commit16a895e7d64b71d1aa7a971d77e8daf6591e9c56 (patch)
tree9c1c71eb1a80dd0fd813ea6ba42d1d4c7d4889ed
parent8159071adb232b68c2ce79479145fbcd04979245 (diff)
downloadswift-contrib-16a895e7d64b71d1aa7a971d77e8daf6591e9c56.zip
swift-contrib-16a895e7d64b71d1aa7a971d77e8daf6591e9c56.tar.bz2
Allow role changing in MUCs.
Resolves: #987
-rw-r--r--.subl/swift.sublime-project17
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp17
-rw-r--r--Swift/Controllers/Chat/MUCController.h1
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h2
-rw-r--r--Swift/QtUI/QtChatWindow.cpp1
-rw-r--r--Swift/QtUI/Roster/QtOccupantListWidget.cpp3
-rw-r--r--Swiften/Elements/SecurityLabelsCatalog.h6
-rw-r--r--Swiften/MUC/MUC.cpp15
-rw-r--r--Swiften/MUC/MUC.h7
9 files changed, 53 insertions, 16 deletions
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
@@ -1,16 +1,29 @@
/* http://www.sublimetext.com/docs/2/projects.html */
{
"folders":
[
{
"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"]
}
],
"settings":
{
"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
@@ -53,105 +53,112 @@ MUCController::MUCController (
AvatarManager* avatarManager,
UIEventStream* uiEventStream,
bool useDelayForLatency,
TimerFactory* timerFactory,
EventController* eventController,
EntityCapsProvider* entityCapsProvider) :
ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password) {
parting_ = true;
joined_ = false;
lastWasPresence_ = false;
shouldJoinOnReconnect_ = true;
doneGettingHistory_ = false;
events_ = uiEventStream;
roster_ = new Roster(false, true);
completer_ = new TabComplete();
chatWindow_->setRosterModel(roster_);
chatWindow_->setTabComplete(completer_);
chatWindow_->setName(muc->getJID().getNode());
chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this));
chatWindow_->onOccupantSelectionChanged.connect(boost::bind(&MUCController::handleWindowOccupantSelectionChanged, this, _1));
chatWindow_->onOccupantActionSelected.connect(boost::bind(&MUCController::handleActionRequestedOnOccupant, this, _1, _2));
chatWindow_->onChangeSubjectRequest.connect(boost::bind(&MUCController::handleChangeSubjectRequest, this, _1));
chatWindow_->onConfigureRequest.connect(boost::bind(&MUCController::handleConfigureRequest, this, _1));
chatWindow_->onConfigurationFormCancelled.connect(boost::bind(&MUCController::handleConfigurationCancelled, this));
chatWindow_->onDestroyRequest.connect(boost::bind(&MUCController::handleDestroyRoomRequest, this));
chatWindow_->onInvitePersonToThisMUCRequest.connect(boost::bind(&MUCController::handleInvitePersonToThisMUCRequest, this, _1, _2));
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));
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));
loginCheckTimer_->start();
}
chatWindow_->convertToMUC();
setOnline(true);
if (avatarManager_ != NULL) {
avatarChangedConnection_ = (avatarManager_->onAvatarChanged.connect(boost::bind(&MUCController::handleAvatarChanged, this, _1)));
}
handleBareJIDCapsChanged(muc->getJID());
}
MUCController::~MUCController() {
chatWindow_->setRosterModel(NULL);
delete roster_;
if (loginCheckTimer_) {
loginCheckTimer_->stop();
}
chatWindow_->setTabComplete(NULL);
delete completer_;
}
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;
}
}
void MUCController::handleBareJIDCapsChanged(const JID& /*jid*/) {
ChatWindow::Tristate support = ChatWindow::Yes;
bool any = false;
foreach (const std::string& nick, currentOccupants_) {
DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_.toBare().toString() + "/" + nick);
if (disco && disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) {
any = true;
} else {
support = ChatWindow::Maybe;
}
}
if (!any) {
support = ChatWindow::No;
}
chatWindow_->setCorrectionEnabled(support);
}
/**
* Join the MUC if not already in it.
*/
void MUCController::rejoin() {
if (parting_) {
joined_ = false;
parting_ = false;
if (password_) {
muc_->setPassword(*password_);
}
//FIXME: check for received activity
if (lastActivity_ == boost::posix_time::not_a_date_time) {
muc_->joinAs(nick_);
} else {
muc_->joinWithContextSince(nick_, lastActivity_);
@@ -569,52 +576,58 @@ std::string MUCController::generateJoinPartString(const std::vector<NickJoinPart
eventStrings[i] = str(boost::format(eventString) % names);
}
}
for (size_t i = 0; i < populatedEvents.size(); i++) {
if (i > 0) {
if (i < populatedEvents.size() - 1) {
result += ", ";
} else {
result += QT_TRANSLATE_NOOP("", " and ");
}
}
result += eventStrings[populatedEvents[i]];
}
return result;
}
void MUCController::handleChangeSubjectRequest(const std::string& subject) {
muc_->changeSubject(subject);
}
void MUCController::handleConfigureRequest(Form::ref form) {
if (form) {
muc_->configureRoom(form);
}
else {
muc_->requestConfigurationForm();
}
}
void MUCController::handleConfigurationFailed(ErrorPayload::ref error) {
std::string errorMessage = getErrorMessage(error);
errorMessage = str(format(QT_TRANSLATE_NOOP("", "Room configuration failed: %1%.")) % errorMessage);
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);
}
void MUCController::handleConfigurationCancelled() {
muc_->cancelConfigureRoom();
}
void MUCController::handleDestroyRoomRequest() {
muc_->destroyRoom();
}
void MUCController::handleInvitePersonToThisMUCRequest(const JID& jid, const std::string& reason) {
muc_->invitePerson(jid, reason);
}
}
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
@@ -62,57 +62,58 @@ namespace Swift {
void preHandleIncomingMessage(boost::shared_ptr<MessageEvent>);
void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>);
private:
void clearPresenceQueue();
void addPresenceMessage(const std::string& message);
void handleWindowOccupantSelectionChanged(ContactRosterItem* item);
void handleActionRequestedOnOccupant(ChatWindow::OccupantAction, ContactRosterItem* item);
void handleWindowClosed();
void handleAvatarChanged(const JID& jid);
void handleOccupantJoined(const MUCOccupant& occupant);
void handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType type, const std::string& reason);
void handleOccupantPresenceChange(boost::shared_ptr<Presence> presence);
void handleOccupantRoleChanged(const std::string& nick, const MUCOccupant& occupant,const MUCOccupant::Role& oldRole);
void handleJoinComplete(const std::string& nick);
void handleJoinFailed(boost::shared_ptr<ErrorPayload> error);
void handleJoinTimeoutTick();
void handleChangeSubjectRequest(const std::string&);
std::string roleToGroupName(MUCOccupant::Role role);
std::string roleToSortName(MUCOccupant::Role role);
JID nickToJID(const std::string& nick);
std::string roleToFriendlyName(MUCOccupant::Role role);
void receivedActivity();
bool messageTargetsMe(boost::shared_ptr<Message> message);
void updateJoinParts();
bool shouldUpdateJoinParts();
void dayTicked() {lastWasPresence_ = false;}
void processUserPart();
void handleBareJIDCapsChanged(const JID& jid);
void handleConfigureRequest(Form::ref);
void handleConfigurationFailed(ErrorPayload::ref);
void handleConfigurationFormReceived(Form::ref);
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_;
UIEventStream* events_;
std::string nick_;
std::string desiredNick_;
Roster* roster_;
TabComplete* completer_;
bool parting_;
bool joined_;
bool lastWasPresence_;
bool shouldJoinOnReconnect_;
bool doneGettingHistory_;
boost::bsignals::scoped_connection avatarChangedConnection_;
boost::shared_ptr<Timer> loginCheckTimer_;
std::set<std::string> currentOccupants_;
std::vector<NickJoinPart> joinParts_;
boost::posix_time::ptime lastActivity_;
boost::optional<std::string> password_;
};
}
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
@@ -1,70 +1,70 @@
/*
* Copyright (c) 2010 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#ifndef SWIFTEN_CHATWINDOW_H
#define SWIFTEN_CHATWINDOW_H
#include <boost/optional.hpp>
#include "Swiften/Base/boost_bsignals.h"
#include <boost/shared_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <vector>
#include <string>
#include <Swiften/Elements/SecurityLabelsCatalog.h>
#include <Swiften/Elements/ChatState.h>
#include <Swiften/Elements/Form.h>
namespace Swift {
class AvatarManager;
class TreeWidget;
class Roster;
class TabComplete;
class RosterItem;
class ContactRosterItem;
class FileTransferController;
class ChatWindow {
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() {};
/** Add message to window.
* @return id of added message (for acks).
*/
virtual std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
/** Adds action to window.
* @return id of added message (for acks);
*/
virtual std::string addAction(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
virtual void addSystemMessage(const std::string& message) = 0;
virtual void addPresenceMessage(const std::string& message) = 0;
virtual void addErrorMessage(const std::string& message) = 0;
virtual void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) = 0;
// File transfer related stuff
virtual std::string addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes) = 0;
virtual void setFileTransferProgress(std::string, const int percentageDone) = 0;
virtual void setFileTransferStatus(std::string, const FileTransferState state, const std::string& msg = "") = 0;
virtual void addMUCInvitation(const JID& jid, const std::string& reason, const std::string& password) = 0;
virtual void setContactChatState(ChatState::ChatStateType state) = 0;
virtual void setName(const std::string& name) = 0;
virtual void show() = 0;
virtual void activate() = 0;
virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) = 0;
virtual void setSecurityLabelsEnabled(bool enabled) = 0;
virtual void setCorrectionEnabled(Tristate enabled) = 0;
virtual void setUnreadMessageCount(int count) = 0;
virtual void convertToMUC() = 0;
// virtual TreeWidget *getTreeWidget() = 0;
virtual void setSecurityLabelsError() = 0;
virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() = 0;
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
@@ -309,70 +309,71 @@ void QtChatWindow::setAvailableSecurityLabels(const std::vector<SecurityLabelsCa
int i = 0;
int defaultIndex = 0;
foreach (SecurityLabelsCatalog::Item label, labels) {
std::string selector = label.getSelector();
std::string displayMarking = label.getLabel() ? label.getLabel()->getDisplayMarking() : "";
QString labelName = selector.empty() ? displayMarking.c_str() : selector.c_str();
labelsWidget_->addItem(labelName, QVariant(i));
if (label.getIsDefault()) {
defaultIndex = i;
}
i++;
}
labelsWidget_->setCurrentIndex(defaultIndex);
}
void QtChatWindow::setSecurityLabelsError() {
labelsWidget_->setEnabled(false);
}
void QtChatWindow::setSecurityLabelsEnabled(bool enabled) {
if (enabled) {
labelsWidget_->setEnabled(true);
labelsWidget_->show();
} else {
labelsWidget_->hide();
}
}
void QtChatWindow::setCorrectionEnabled(Tristate enabled) {
correctionEnabled_ = enabled;
}
SecurityLabelsCatalog::Item QtChatWindow::getSelectedSecurityLabel() {
assert(labelsWidget_->isEnabled());
+ assert(labelsWidget_->currentIndex() >= 0 && labelsWidget_->currentIndex() < availableLabels_.size());
return availableLabels_[labelsWidget_->currentIndex()];
}
void QtChatWindow::closeEvent(QCloseEvent* event) {
event->accept();
emit windowClosing();
onClosed();
}
void QtChatWindow::convertToMUC() {
setAcceptDrops(false);
treeWidget_->show();
subject_->show();
actionButton_->show();
}
void QtChatWindow::qAppFocusChanged(QWidget* /*old*/, QWidget* /*now*/) {
if (isWidgetSelected()) {
lastLineTracker_.setHasFocus(true);
input_->setFocus();
onAllMessagesRead();
}
else {
lastLineTracker_.setHasFocus(false);
}
}
void QtChatWindow::setInputEnabled(bool enabled) {
inputEnabled_ = enabled;
if (!enabled && mucConfigurationWindow) {
delete mucConfigurationWindow.data();
}
}
void QtChatWindow::showEvent(QShowEvent* event) {
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
@@ -13,48 +13,51 @@
#include <QInputDialog>
#include "Swift/Controllers/Roster/ContactRosterItem.h"
#include "Swift/Controllers/Roster/GroupRosterItem.h"
#include "Swift/Controllers/UIEvents/UIEventStream.h"
#include "QtSwiftUtil.h"
namespace Swift {
QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, QWidget* parent) : QtTreeWidget(eventStream, parent) {
}
QtOccupantListWidget::~QtOccupantListWidget() {
}
void QtOccupantListWidget::setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions) {
availableOccupantActions_ = actions;
}
void QtOccupantListWidget::contextMenuEvent(QContextMenuEvent* event) {
QModelIndex index = indexAt(event->pos());
if (!index.isValid()) {
return;
}
RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (contact) {
QMenu contextMenu;
std::map<QAction*, ChatWindow::OccupantAction> actions;
foreach (ChatWindow::OccupantAction availableAction, availableOccupantActions_) {
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;
}
QAction* result = contextMenu.exec(event->globalPos());
if (result) {
onOccupantActionSelected(actions[result], contact);
}
}
}
}
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
@@ -1,79 +1,79 @@
/*
* Copyright (c) 2010 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
#include <Swiften/JID/JID.h>
#include <Swiften/Elements/Payload.h>
#include <Swiften/Elements/SecurityLabel.h>
namespace Swift {
class SecurityLabelsCatalog : public Payload {
public:
typedef boost::shared_ptr<SecurityLabelsCatalog> ref;
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;
}
const std::string& getSelector() const { return selector_; }
void setSelector(const std::string& selector) {
selector_ = selector;
}
bool getIsDefault() const { return default_; }
void setIsDefault(bool isDefault) {
default_ = isDefault;
}
private:
- boost::shared_ptr<SecurityLabel> label_;
+ SecurityLabel::ref label_;
std::string selector_;
bool default_;
};
SecurityLabelsCatalog(const JID& to = JID()) : to_(to) {}
const std::vector<Item>& getItems() const {
return items_;
}
void addItem(const Item& item) {
items_.push_back(item);
}
const JID& getTo() const {
return to_;
}
void setTo(const JID& to) {
to_ = to;
}
const std::string& getName() const {
return name_;
}
void setName(const std::string& name) {
name_ = name;
}
const std::string& getDescription() const {
return description_;
}
void setDescription(const std::string& description) {
description_ = description;
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
@@ -205,84 +205,89 @@ void MUC::handleIncomingPresence(Presence::ref presence) {
if (createAsReservedIfNew) {
unlocking = true;
requestConfigurationForm();
}
else {
MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload());
presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence);
mucPayload->setPayload(boost::make_shared<Form>(Form::SubmitType));
GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_);
request->onResponse.connect(boost::bind(&MUC::handleCreationConfigResponse, this, _1, _2));
request->send();
}
}
}
}
}
void MUC::handleCreationConfigResponse(MUCOwnerPayload::ref /*unused*/, ErrorPayload::ref error) {
unlocking = false;
if (error) {
presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence);
onJoinFailed(error);
} else {
onJoinComplete(getOwnNick()); /* Previously, this wasn't needed here, as the presence duplication bug caused an emit elsewhere. */
}
}
bool MUC::hasOccupant(const std::string& nick) {
return occupants.find(nick) != occupants.end();
}
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);
}
}
void MUC::changeSubject(const std::string& subject) {
Message::ref message = boost::make_shared<Message>();
message->setSubject(subject);
message->setType(Message::Groupchat);
message->setTo(ownMUCJID.toBare());
stanzaChannel->sendMessage(message);
}
void MUC::requestConfigurationForm() {
MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload());
GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Get, getJID(), mucPayload, iqRouter_);
request->onResponse.connect(boost::bind(&MUC::handleConfigurationFormReceived, this, _1, _2));
request->send();
}
void MUC::cancelConfigureRoom() {
MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload());
mucPayload->setPayload(boost::make_shared<Form>(Form::CancelType));
GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_);
request->send();
}
void MUC::handleConfigurationFormReceived(MUCOwnerPayload::ref payload, ErrorPayload::ref error) {
Form::ref form;
if (payload) {
form = payload->getForm();
}
if (error || !form) {
onConfigurationFailed(error);
} else {
onConfigurationFormReceived(form);
}
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
@@ -24,93 +24,94 @@
namespace Swift {
class StanzaChannel;
class IQRouter;
class DirectedPresenceSender;
class MUC {
public:
typedef boost::shared_ptr<MUC> ref;
enum JoinResult { JoinSucceeded, JoinFailed };
enum LeavingType { Part, Disconnect };
public:
MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry);
/**
* Returns the (bare) JID of the MUC.
*/
JID getJID() const {
return ownMUCJID.toBare();
}
void joinAs(const std::string &nick);
void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since);
/*void queryRoomInfo(); */
/*void queryRoomItems(); */
std::string getCurrentNick();
void part();
void handleIncomingMessage(Message::ref message);
/** Expose public so it can be called when e.g. user goes offline */
void handleUserLeft(LeavingType);
/** 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);
void cancelConfigureRoom();
void destroyRoom();
/** Send an invite for the person to join the MUC */
void invitePerson(const JID& person, const std::string& reason = "");
void setCreateAsReservedIfNew() {createAsReservedIfNew = true;}
void setPassword(const boost::optional<std::string>& password);
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;
boost::signal<void (const std::string&, const MUCOccupant::Affiliation& /*new*/, const MUCOccupant::Affiliation& /*old*/)> onOccupantAffiliationChanged;
boost::signal<void (const MUCOccupant&)> onOccupantJoined;
boost::signal<void (const MUCOccupant&, LeavingType, const std::string& /*reason*/)> onOccupantLeft;
boost::signal<void (Form::ref)> onConfigurationFormReceived;
/* boost::signal<void (const MUCInfo&)> onInfoResult; */
/* boost::signal<void (const blah&)> onItemsResult; */
private:
bool isFromMUC(const JID& j) const {
return ownMUCJID.equals(j, JID::WithoutResource);
}
const std::string& getOwnNick() const {
return ownMUCJID.getResource();
}
private:
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);
private:
JID ownMUCJID;
StanzaChannel* stanzaChannel;
IQRouter* iqRouter_;
DirectedPresenceSender* presenceSender;
MUCRegistry* mucRegistry;
std::map<std::string, MUCOccupant> occupants;
bool joinSucceeded_;
bool joinComplete_;
boost::bsignals::scoped_connection scopedConnection_;
boost::posix_time::ptime joinSince_;
bool createAsReservedIfNew;
bool unlocking;
boost::optional<std::string> password;
};
}