summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers/Chat/MUCController.cpp')
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp45
1 files changed, 44 insertions, 1 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index b467227..fe90c60 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -71,70 +71,71 @@ MUCController::MUCController (
HistoryController* historyController,
MUCRegistry* mucRegistry,
HighlightManager* highlightManager,
boost::shared_ptr<ChatMessageParser> chatMessageParser,
bool isImpromptu,
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider,
VCardManager* vcardManager) :
ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false) {
parting_ = true;
joined_ = false;
lastWasPresence_ = false;
shouldJoinOnReconnect_ = true;
doneGettingHistory_ = false;
events_ = uiEventStream;
xmppRoster_ = roster;
roster_ = new Roster(false, true);
rosterVCardProvider_ = new RosterVCardProvider(roster_, vcardManager, JID::WithResource);
completer_ = new TabComplete();
chatWindow_->setRosterModel(roster_);
chatWindow_->setTabComplete(completer_);
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_->onBookmarkRequest.connect(boost::bind(&MUCController::handleBookmarkRequest, this));
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_->onInviteToChat.connect(boost::bind(&MUCController::handleInvitePersonToThisMUCRequest, this, _1));
chatWindow_->onGetAffiliationsRequest.connect(boost::bind(&MUCController::handleGetAffiliationsRequest, this));
chatWindow_->onChangeAffiliationsRequest.connect(boost::bind(&MUCController::handleChangeAffiliationsRequest, this, _1));
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_->onOccupantNicknameChanged.connect(boost::bind(&MUCController::handleOccupantNicknameChanged, this, _1, _2));
muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
muc_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, this, _1, _2, _3));
muc_->onAffiliationListReceived.connect(boost::bind(&MUCController::handleAffiliationListReceived, this, _1, _2));
muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1));
highlighter_->setMode(isImpromptu_ ? Highlighter::ChatMode : Highlighter::MUCMode);
highlighter_->setNick(nick_);
if (timerFactory) {
loginCheckTimer_ = boost::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS));
loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this));
loginCheckTimer_->start();
}
if (isImpromptu) {
muc_->onUnlocked.connect(boost::bind(&MUCController::handleRoomUnlocked, this));
chatWindow_->convertToMUC(ChatWindow::ImpromptuMUC);
} else {
muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
muc_->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
chatWindow_->convertToMUC(ChatWindow::StandardMUC);
chatWindow_->setName(muc->getJID().getNode());
}
setOnline(true);
if (avatarManager_ != NULL) {
avatarChangedConnection_ = (avatarManager_->onAvatarChanged.connect(boost::bind(&MUCController::handleAvatarChanged, this, _1)));
}
handleBareJIDCapsChanged(muc->getJID());
eventStream_->onUIEvent.connect(boost::bind(&MUCController::handleUIEvent, this, _1));
}
MUCController::~MUCController() {
eventStream_->onUIEvent.disconnect(boost::bind(&MUCController::handleUIEvent, this, _1));
chatWindow_->setRosterModel(NULL);
delete rosterVCardProvider_;
delete roster_;
@@ -451,71 +452,71 @@ void MUCController::setAvailableRoomActions(const MUCOccupant::Affiliation& affi
}
if (role <= MUCOccupant::Visitor) {
actions.push_back(ChatWindow::Invite);
}
chatWindow_->setAvailableRoomActions(actions);
}
void MUCController::clearPresenceQueue() {
lastWasPresence_ = false;
joinParts_.clear();
}
std::string MUCController::roleToFriendlyName(MUCOccupant::Role role) {
switch (role) {
case MUCOccupant::Moderator: return QT_TRANSLATE_NOOP("", "moderator");
case MUCOccupant::Participant: return QT_TRANSLATE_NOOP("", "participant");
case MUCOccupant::Visitor: return QT_TRANSLATE_NOOP("", "visitor");
case MUCOccupant::NoRole: return "";
}
assert(false);
return "";
}
std::string MUCController::roleToSortName(MUCOccupant::Role role) {
switch (role) {
case MUCOccupant::Moderator: return "1";
case MUCOccupant::Participant: return "2";
case MUCOccupant::Visitor: return "3";
case MUCOccupant::NoRole: return "4";
}
assert(false);
return "5";
}
JID MUCController::nickToJID(const std::string& nick) {
- return JID(toJID_.getNode(), toJID_.getDomain(), nick);
+ return muc_->getJID().withResource(nick);
}
bool MUCController::messageTargetsMe(boost::shared_ptr<Message> message) {
std::string stringRegexp(".*\\b" + boost::to_lower_copy(nick_) + "\\b.*");
boost::regex myRegexp(stringRegexp);
return boost::regex_match(boost::to_lower_copy(message->getBody()), myRegexp);
}
void MUCController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) {
if (messageEvent->getStanza()->getType() == Message::Groupchat) {
lastActivity_ = boost::posix_time::microsec_clock::universal_time();
}
clearPresenceQueue();
boost::shared_ptr<Message> message = messageEvent->getStanza();
if (joined_ && messageEvent->getStanza()->getFrom().getResource() != nick_ && messageTargetsMe(message) && !message->getPayload<Delay>() && messageEvent->isReadable()) {
chatWindow_->flash();
}
else {
messageEvent->setTargetsMe(false);
}
if (messageEvent->isReadable() && isImpromptu_) {
chatWindow_->flash(); /* behave like a regular char*/
}
if (joined_) {
std::string nick = message->getFrom().getResource();
if (nick != nick_ && currentOccupants_.find(nick) != currentOccupants_.end()) {
completer_->addWord(nick);
}
}
/*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;
if (message->hasSubject() && message->getBody().empty()) {
chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "The room subject is now: %1%")) % message->getSubject())), ChatWindow::DefaultDirection);;
@@ -659,70 +660,108 @@ void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::Leaving
switch (type) {
case MUC::LeaveKick: clearPresenceQueue(); clearAfter = true; partMessage = QT_TRANSLATE_NOOP("", "You have been kicked out of the room"); break;
case MUC::LeaveBan: clearPresenceQueue(); clearAfter = true; partMessage = QT_TRANSLATE_NOOP("", "You have been banned from the room"); break;
case MUC::LeaveNotMember: clearPresenceQueue(); clearAfter = true; partMessage = QT_TRANSLATE_NOOP("", "You are no longer a member of the room and have been removed"); break;
case MUC::LeaveDestroy: clearPresenceQueue(); clearAfter = true; partMessage = QT_TRANSLATE_NOOP("", "The room has been destroyed"); break;
case MUC::Disconnect:
case MUC::LeavePart: partMessage = QT_TRANSLATE_NOOP("", "You have left the room");
}
}
if (!reason.empty()) {
partMessage += " (" + reason + ")";
}
partMessage += ".";
if (occupant.getNick() != nick_) {
if (shouldUpdateJoinParts()) {
updateJoinParts();
} else {
addPresenceMessage(partMessage);
}
roster_->removeContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick()));
} else {
addPresenceMessage(partMessage);
parting_ = true;
processUserPart();
}
if (clearAfter) {
clearPresenceQueue();
}
if (isImpromptu_) {
setImpromptuWindowTitle();
}
}
+void MUCController::handleOccupantNicknameChanged(const std::string& oldNickname, const std::string& newNickname) {
+ addPresenceMessage(generateNicknameChangeString(oldNickname, newNickname));
+ JID oldJID = muc_->getJID().withResource(oldNickname);
+ JID newJID = muc_->getJID().withResource(newNickname);
+
+ // adjust occupants
+ currentOccupants_.erase(oldNickname);
+ currentOccupants_.insert(newNickname);
+
+ // adjust completer
+ completer_->removeWord(oldNickname);
+ completer_->addWord(newNickname);
+
+ // update contact
+ roster_->removeContact(oldJID);
+ MUCOccupant occupant = muc_->getOccupant(newNickname);
+
+ JID realJID;
+ if (occupant.getRealJID()) {
+ realJID = occupant.getRealJID().get();
+ }
+ MUCOccupant::Role role = MUCOccupant::Participant;
+ MUCOccupant::Affiliation affiliation = MUCOccupant::NoAffiliation;
+ if (!isImpromptu_) {
+ role = occupant.getRole();
+ affiliation = occupant.getAffiliation();
+ }
+ std::string groupName(roleToGroupName(role));
+ roster_->addContact(newJID, realJID, newNickname, groupName, avatarManager_->getAvatarPath(newJID));
+ roster_->applyOnItems(SetMUC(newJID, role, affiliation));
+ if (avatarManager_ != NULL) {
+ handleAvatarChanged(newJID);
+ }
+
+ clearPresenceQueue();
+ onUserNicknameChanged(oldNickname, newNickname);
+}
+
void MUCController::handleOccupantPresenceChange(boost::shared_ptr<Presence> presence) {
receivedActivity();
roster_->applyOnItems(SetPresence(presence, JID::WithResource));
}
bool MUCController::isIncomingMessageFromMe(boost::shared_ptr<Message> message) {
JID from = message->getFrom();
return nick_ == from.getResource();
}
std::string MUCController::senderDisplayNameFromMessage(const JID& from) {
return from.getResource();
}
void MUCController::preSendMessageRequest(boost::shared_ptr<Message> message) {
message->setType(Swift::Message::Groupchat);
}
boost::optional<boost::posix_time::ptime> MUCController::getMessageTimestamp(boost::shared_ptr<Message> message) const {
return message->getTimestampFrom(toJID_);
}
void MUCController::updateJoinParts() {
chatWindow_->replaceLastMessage(chatMessageParser_->parseMessageBody(generateJoinPartString(joinParts_, isImpromptu())), ChatWindow::UpdateTimestamp);
}
void MUCController::appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent) {
std::vector<NickJoinPart>::iterator it = joinParts.begin();
bool matched = false;
for (; it != joinParts.end(); ++it) {
if ((*it).nick == newEvent.nick) {
matched = true;
JoinPart type = (*it).type;
switch (newEvent.type) {
case Join: type = (type == Part) ? PartThenJoin : Join; break;
@@ -786,70 +825,74 @@ std::string MUCController::generateJoinPartString(const std::vector<NickJoinPart
break;
case JoinThenPart:
if (sorted[i].size() > 1) {
eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% have joined then left the chat") : QT_TRANSLATE_NOOP("", "%1% have entered then left the room"));
}
else {
eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% has joined then left the chat") : QT_TRANSLATE_NOOP("", "%1% has entered then left the room"));
}
break;
case PartThenJoin:
if (sorted[i].size() > 1) {
eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% have left then returned to the chat") : QT_TRANSLATE_NOOP("", "%1% have left then returned to the room"));
}
else {
eventString = (isImpromptu ? QT_TRANSLATE_NOOP("", "%1% has left then returned to the chat") : QT_TRANSLATE_NOOP("", "%1% has left then returned to the room"));
}
break;
}
populatedEvents.push_back(static_cast<JoinPart>(i));
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;
}
+std::string MUCController::generateNicknameChangeString(const std::string& oldNickname, const std::string& newNickname) {
+ return str(boost::format(QT_TRANSLATE_NOOP("", "%1% is now known as %2%.")) % oldNickname % newNickname);
+}
+
void MUCController::handleChangeSubjectRequest(const std::string& subject) {
muc_->changeSubject(subject);
}
void MUCController::handleBookmarkRequest() {
const JID jid = muc_->getJID();
MUCBookmark bookmark(jid, jid.toBare().toString());
bookmark.setPassword(password_);
bookmark.setNick(nick_);
chatWindow_->showBookmarkWindow(bookmark);
}
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(chatMessageParser_->parseMessageBody(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(chatMessageParser_->parseMessageBody(errorMessage));
}
void MUCController::configureAsImpromptuRoom(Form::ref form) {
muc_->configureRoom(buildImpromptuRoomConfiguration(form));