From 645a7a47c8105e7cad3fecd7bb66c8c16757eafe Mon Sep 17 00:00:00 2001 From: Tobias Markmann <tm@ayena.de> Date: Thu, 22 Jan 2015 23:24:16 +0100 Subject: Show a warning notice when trying to enter a blocked room When the user tries to enter a blocked room, we now show a warning notice and describing how the room can be unblocked. Swift will not send the joining presence when trying to enter a blocked room. Test-Information: Tested on Mac OS X 10.9.5 against a popular open source server and its MUC and Blocking Command implementation. Change-Id: I875db056f21f97845c5a9a43167b0f2a16bdaa36 diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index f69ce6f..fe098de 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -811,7 +811,7 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti chatWindowFactoryAdapter = new SingleChatWindowFactoryAdapter(reuseChatwindow); } boost::shared_ptr<ChatMessageParser> chatMessageParser = boost::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getRules(), true); /* a message parser that knows this is a room/MUC (not a chat) */ - controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_); + controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_); if (chatWindowFactoryAdapter) { /* The adapters are only passed to chat windows, which are deleted in their * controllers' dtor, which are deleted in ChatManager's dtor. The adapters diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 10d63a7..b5a8d2c 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -11,10 +11,12 @@ #include <boost/algorithm/string.hpp> #include <Swiften/Avatars/AvatarManager.h> +#include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> #include <Swiften/Base/foreach.h> #include <Swiften/Base/format.h> -#include <Swiften/Base/Log.h> +#include <Swiften/Client/BlockList.h> +#include <Swiften/Client/ClientBlockListManager.h> #include <Swiften/Client/StanzaChannel.h> #include <Swiften/Disco/EntityCapsProvider.h> #include <Swiften/Elements/Delay.h> @@ -39,6 +41,7 @@ #include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h> #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> #include <Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h> #include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIInterfaces/ChatWindow.h> @@ -71,11 +74,12 @@ MUCController::MUCController ( HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, + ClientBlockListManager* clientBlockListManager, 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) { + 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), clientBlockListManager_(clientBlockListManager) { parting_ = true; joined_ = false; lastWasPresence_ = false; @@ -100,6 +104,7 @@ MUCController::MUCController ( 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)); + chatWindow_->onUnblockUserRequest.connect(boost::bind(&MUCController::handleUnblockUserRequest, 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)); @@ -605,16 +610,23 @@ void MUCController::setOnline(bool online) { } else { if (shouldJoinOnReconnect_) { renameCounter_ = 0; - if (isImpromptu_) { - lastJoinMessageUID_ = chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(QT_TRANSLATE_NOOP("", "Trying to join chat")), ChatWindow::DefaultDirection); - } else { - lastJoinMessageUID_ = chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "Trying to enter room %1%")) % toJID_.toString())), ChatWindow::DefaultDirection); + boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList(); + if (blockList && blockList->isBlocked(muc_->getJID())) { + handleBlockingStateChanged(); + lastJoinMessageUID_ = chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(QT_TRANSLATE_NOOP("", "You've blocked this room. To enter the room, first unblock it using the cog menu and try again")), ChatWindow::DefaultDirection); } - if (loginCheckTimer_) { - loginCheckTimer_->start(); + else { + if (isImpromptu_) { + lastJoinMessageUID_ = chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(QT_TRANSLATE_NOOP("", "Trying to join chat")), ChatWindow::DefaultDirection); + } else { + lastJoinMessageUID_ = chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "Trying to enter room %1%")) % toJID_.toString())), ChatWindow::DefaultDirection); + } + if (loginCheckTimer_) { + loginCheckTimer_->start(); + } + setNick(desiredNick_); + rejoin(); } - setNick(desiredNick_); - rejoin(); } } } @@ -970,6 +982,28 @@ void MUCController::handleChangeAffiliationsRequest(const std::vector<std::pair< } } +void MUCController::handleUnblockUserRequest() { + eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, muc_->getJID())); +} + +void MUCController::handleBlockingStateChanged() { + boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList(); + if (blockList->getState() == BlockList::Available) { + if (blockList->isBlocked(toJID_)) { + if (!blockedContactAlert_) { + blockedContactAlert_ = chatWindow_->addAlert(QT_TRANSLATE_NOOP("", "You've blocked this room. To enter the room, first unblock it using the cog menu and try again")); + } + chatWindow_->setBlockingState(ChatWindow::IsBlocked); + } else { + if (blockedContactAlert_) { + chatWindow_->removeAlert(*blockedContactAlert_); + blockedContactAlert_.reset(); + } + chatWindow_->setBlockingState(ChatWindow::IsUnblocked); + } + } +} + void MUCController::handleAffiliationListReceived(MUCOccupant::Affiliation affiliation, const std::vector<JID>& jids) { chatWindow_->setAffiliations(affiliation, jids); } @@ -1095,4 +1129,17 @@ void MUCController::handleRoomUnlocked() { } } +void MUCController::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info) { + ChatControllerBase::setAvailableServerFeatures(info); + if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::BlockingCommandFeature)) { + boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList(); + + blockingOnStateChangedConnection_ = blockList->onStateChanged.connect(boost::bind(&MUCController::handleBlockingStateChanged, this)); + blockingOnItemAddedConnection_ = blockList->onItemAdded.connect(boost::bind(&MUCController::handleBlockingStateChanged, this)); + blockingOnItemRemovedConnection_ = blockList->onItemRemoved.connect(boost::bind(&MUCController::handleBlockingStateChanged, this)); + + handleBlockingStateChanged(); + } +} + } diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index 5e033ed..7c24ae2 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -39,6 +39,7 @@ namespace Swift { class UIEvent; class VCardManager; class RosterVCardProvider; + class ClientBlockListManager; enum JoinPart {Join, Part, JoinThenPart, PartThenJoin}; @@ -50,13 +51,14 @@ namespace Swift { class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, boost::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager); + MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, boost::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager); virtual ~MUCController(); boost::signal<void ()> onUserLeft; boost::signal<void ()> onUserJoined; boost::signal<void ()> onImpromptuConfigCompleted; boost::signal<void (const std::string&, const std::string& )> onUserNicknameChanged; virtual void setOnline(bool online); + virtual void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info); void rejoin(); static void appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent); static std::string generateJoinPartString(const std::vector<NickJoinPart>& joinParts, bool isImpromptu); @@ -132,6 +134,9 @@ namespace Swift { void configureAsImpromptuRoom(Form::ref form); Form::ref buildImpromptuRoomConfiguration(Form::ref roomConfigurationForm); + void handleUnblockUserRequest(); + void handleBlockingStateChanged(); + private: MUC::ref muc_; UIEventStream* events_; @@ -157,6 +162,13 @@ namespace Swift { bool isImpromptuAlreadyConfigured_; RosterVCardProvider* rosterVCardProvider_; std::string lastJoinMessageUID_; + + ClientBlockListManager* clientBlockListManager_; + boost::bsignals::scoped_connection blockingOnStateChangedConnection_; + boost::bsignals::scoped_connection blockingOnItemAddedConnection_; + boost::bsignals::scoped_connection blockingOnItemRemovedConnection_; + + boost::optional<ChatWindow::AlertID> blockedContactAlert_; }; } diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index 5a4d3b8..0b7b793 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -7,37 +7,40 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/algorithm/string.hpp> + #include <hippomocks.h> -#include "Swiften/Base/foreach.h" -#include "Swift/Controllers/XMPPEvents/EventController.h" -#include "Swiften/Presence/DirectedPresenceSender.h" -#include "Swiften/Presence/StanzaChannelPresenceSender.h" -#include "Swiften/Avatars/NullAvatarManager.h" -#include "Swift/Controllers/Chat/MUCController.h" -#include "Swift/Controllers/UIInterfaces/ChatWindow.h" -#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" -#include "Swiften/Client/NickResolver.h" -#include "Swiften/Roster/XMPPRoster.h" -#include "Swift/Controllers/UIEvents/UIEventStream.h" -#include "Swift/Controllers/UnitTest/MockChatWindow.h" -#include "Swiften/MUC/UnitTest/MockMUC.h" -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/Queries/DummyIQChannel.h" -#include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Elements/MUCUserPayload.h" -#include "Swiften/Disco/DummyEntityCapsProvider.h" -#include <Swiften/VCards/VCardMemoryStorage.h> +#include <Swiften/Avatars/NullAvatarManager.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Client/ClientBlockListManager.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Client/NickResolver.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/Crypto/PlatformCryptoProvider.h> +#include <Swiften/Disco/DummyEntityCapsProvider.h> +#include <Swiften/Elements/MUCUserPayload.h> +#include <Swiften/MUC/UnitTest/MockMUC.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Presence/DirectedPresenceSender.h> +#include <Swiften/Presence/PresenceOracle.h> +#include <Swiften/Presence/StanzaChannelPresenceSender.h> +#include <Swiften/Queries/DummyIQChannel.h> +#include <Swiften/Roster/XMPPRoster.h> #include <Swiften/VCards/VCardManager.h> -#include <Swift/Controllers/Settings/DummySettingsProvider.h> +#include <Swiften/VCards/VCardMemoryStorage.h> + #include <Swift/Controllers/Chat/ChatMessageParser.h> +#include <Swift/Controllers/Chat/MUCController.h> #include <Swift/Controllers/Chat/UserSearchController.h> -#include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h> -#include <Swift/Controllers/Roster/Roster.h> #include <Swift/Controllers/Roster/GroupRosterItem.h> -#include <Swiften/Crypto/CryptoProvider.h> +#include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/Settings/DummySettingsProvider.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h> +#include <Swift/Controllers/UnitTest/MockChatWindow.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> using namespace Swift; @@ -84,11 +87,13 @@ public: chatMessageParser_ = boost::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getRules(), true); vcardStorage_ = new VCardMemoryStorage(crypto_.get()); vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_); - controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_, highlightManager_, chatMessageParser_, false, NULL, vcardManager_); + clientBlockListManager_ = new ClientBlockListManager(iqRouter_); + controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, false, NULL, vcardManager_); } void tearDown() { delete controller_; + delete clientBlockListManager_; delete vcardManager_; delete vcardStorage_; delete highlightManager_; @@ -432,6 +437,7 @@ private: boost::shared_ptr<CryptoProvider> crypto_; VCardManager* vcardManager_; VCardMemoryStorage* vcardStorage_; + ClientBlockListManager* clientBlockListManager_; }; CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest); diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index 6324e9d..33bec75 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -653,7 +653,7 @@ void QtChatWindow::handleActionButtonClicked() { unblock = contextMenu.addAction(tr("Unblock")); unblock->setEnabled(isOnline_); } - else if (blockingState_ == IsUnblocked) { + else if (!isMUC_ && blockingState_ == IsUnblocked) { block = contextMenu.addAction(tr("Block")); block->setEnabled(isOnline_); } -- cgit v0.10.2-6-g49f6