/* * Copyright (c) 2013 Tobias Markmann * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ /* * Copyright (c) 2014-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swift/Controllers/BlockListController.h> #include <boost/bind.hpp> #include <Swiften/Base/foreach.h> #include <Swiften/Base/format.h> #include <Swiften/Client/ClientBlockListManager.h> #include <Swift/Controllers/Intl.h> #include <Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h> #include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h> #include <Swift/Controllers/UIInterfaces/BlockListEditorWidget.h> #include <Swift/Controllers/XMPPEvents/ErrorEvent.h> #include <Swift/Controllers/XMPPEvents/EventController.h> namespace Swift { BlockListController::BlockListController(ClientBlockListManager* blockListManager, UIEventStream* uiEventStream, BlockListEditorWidgetFactory* blockListEditorWidgetFactory, EventController* eventController) : blockListManager_(blockListManager), blockListEditorWidgetFactory_(blockListEditorWidgetFactory), blockListEditorWidget_(nullptr), eventController_(eventController), remainingRequests_(0), uiEventStream_(uiEventStream) { uiEventStream->onUIEvent.connect(boost::bind(&BlockListController::handleUIEvent, this, _1)); blockListManager_->getBlockList()->onItemAdded.connect(boost::bind(&BlockListController::handleBlockListChanged, this)); blockListManager_->getBlockList()->onItemRemoved.connect(boost::bind(&BlockListController::handleBlockListChanged, this)); } BlockListController::~BlockListController() { uiEventStream_->onUIEvent.disconnect(boost::bind(&BlockListController::handleUIEvent, this, _1)); blockListManager_->getBlockList()->onItemAdded.disconnect(boost::bind(&BlockListController::handleBlockListChanged, this)); blockListManager_->getBlockList()->onItemRemoved.disconnect(boost::bind(&BlockListController::handleBlockListChanged, this)); } void BlockListController::blockListDifferences(const std::vector<JID> &newBlockList, std::vector<JID> &jidsToUnblock, std::vector<JID> &jidsToBlock) const { foreach (const JID& jid, blockListBeforeEdit) { if (std::find(newBlockList.begin(), newBlockList.end(), jid) == newBlockList.end()) { jidsToUnblock.push_back(jid); } } foreach (const JID& jid, newBlockList) { if (std::find(blockListBeforeEdit.begin(), blockListBeforeEdit.end(), jid) == blockListBeforeEdit.end()) { jidsToBlock.push_back(jid); } } } void BlockListController::handleUIEvent(std::shared_ptr<UIEvent> rawEvent) { // handle UI dialog std::shared_ptr<RequestBlockListDialogUIEvent> requestDialogEvent = std::dynamic_pointer_cast<RequestBlockListDialogUIEvent>(rawEvent); if (requestDialogEvent != nullptr) { if (blockListEditorWidget_ == nullptr) { blockListEditorWidget_ = blockListEditorWidgetFactory_->createBlockListEditorWidget(); blockListEditorWidget_->onSetNewBlockList.connect(boost::bind(&BlockListController::handleSetNewBlockList, this, _1)); } blockListBeforeEdit = blockListManager_->getBlockList()->getItems(); blockListEditorWidget_->setCurrentBlockList(blockListBeforeEdit); blockListEditorWidget_->setError(""); blockListEditorWidget_->show(); return; } // handle block state change std::shared_ptr<RequestChangeBlockStateUIEvent> changeStateEvent = std::dynamic_pointer_cast<RequestChangeBlockStateUIEvent>(rawEvent); if (changeStateEvent != nullptr) { if (changeStateEvent->getBlockState() == RequestChangeBlockStateUIEvent::Blocked) { GenericRequest<BlockPayload>::ref blockRequest = blockListManager_->createBlockJIDRequest(changeStateEvent->getContact()); blockRequest->onResponse.connect(boost::bind(&BlockListController::handleBlockResponse, this, blockRequest, _1, _2, std::vector<JID>(1, changeStateEvent->getContact()), false)); blockRequest->send(); } else if (changeStateEvent->getBlockState() == RequestChangeBlockStateUIEvent::Unblocked) { GenericRequest<UnblockPayload>::ref unblockRequest = blockListManager_->createUnblockJIDRequest(changeStateEvent->getContact()); unblockRequest->onResponse.connect(boost::bind(&BlockListController::handleUnblockResponse, this, unblockRequest, _1, _2, std::vector<JID>(1, changeStateEvent->getContact()), false)); unblockRequest->send(); } return; } } void BlockListController::handleBlockResponse(GenericRequest<BlockPayload>::ref request, std::shared_ptr<BlockPayload>, ErrorPayload::ref error, const std::vector<JID>& jids, bool originEditor) { if (error) { std::string errorMessage; // FIXME: Handle reporting of list of JIDs in a translatable way. errorMessage = str(format(QT_TRANSLATE_NOOP("", "Failed to block %1%.")) % jids.at(0).toString()); if (!error->getText().empty()) { errorMessage = str(format(QT_TRANSLATE_NOOP("", "%1%: %2%.")) % errorMessage % error->getText()); } if (blockListEditorWidget_ && originEditor) { blockListEditorWidget_->setError(errorMessage); blockListEditorWidget_->setBusy(false); } else { eventController_->handleIncomingEvent(std::make_shared<ErrorEvent>(request->getReceiver(), errorMessage)); } } if (originEditor) { remainingRequests_--; if (blockListEditorWidget_ && (remainingRequests_ == 0) && !error) { blockListEditorWidget_->setBusy(false); blockListEditorWidget_->hide(); } } } void BlockListController::handleUnblockResponse(GenericRequest<UnblockPayload>::ref request, std::shared_ptr<UnblockPayload>, ErrorPayload::ref error, const std::vector<JID>& jids, bool originEditor) { if (error) { std::string errorMessage; // FIXME: Handle reporting of list of JIDs in a translatable way. errorMessage = str(format(QT_TRANSLATE_NOOP("", "Failed to unblock %1%.")) % jids.at(0).toString()); if (!error->getText().empty()) { errorMessage = str(format(QT_TRANSLATE_NOOP("", "%1%: %2%.")) % errorMessage % error->getText()); } if (blockListEditorWidget_ && originEditor) { blockListEditorWidget_->setError(errorMessage); blockListEditorWidget_->setBusy(false); } else { eventController_->handleIncomingEvent(std::make_shared<ErrorEvent>(request->getReceiver(), errorMessage)); } } if (originEditor) { remainingRequests_--; if (blockListEditorWidget_ && (remainingRequests_ == 0) && !error) { blockListEditorWidget_->setBusy(false); blockListEditorWidget_->hide(); } } } void BlockListController::handleSetNewBlockList(const std::vector<JID> &newBlockList) { std::vector<JID> jidsToBlock; std::vector<JID> jidsToUnblock; blockListDifferences(newBlockList, jidsToUnblock, jidsToBlock); if (!jidsToBlock.empty()) { remainingRequests_++; GenericRequest<BlockPayload>::ref blockRequest = blockListManager_->createBlockJIDsRequest(jidsToBlock); blockRequest->onResponse.connect(boost::bind(&BlockListController::handleBlockResponse, this, blockRequest, _1, _2, jidsToBlock, true)); blockRequest->send(); } if (!jidsToUnblock.empty()) { remainingRequests_++; GenericRequest<UnblockPayload>::ref unblockRequest = blockListManager_->createUnblockJIDsRequest(jidsToUnblock); unblockRequest->onResponse.connect(boost::bind(&BlockListController::handleUnblockResponse, this, unblockRequest, _1, _2, jidsToUnblock, true)); unblockRequest->send(); } if (!jidsToBlock.empty() || !jidsToUnblock.empty()) { assert(blockListEditorWidget_); blockListEditorWidget_->setBusy(true); blockListEditorWidget_->setError(""); } else { blockListEditorWidget_->hide(); } } void BlockListController::handleBlockListChanged() { if (blockListEditorWidget_) { std::vector<JID> jidsToBlock; std::vector<JID> jidsToUnblock; blockListDifferences(blockListEditorWidget_->getCurrentBlockList(), jidsToUnblock, jidsToBlock); blockListBeforeEdit = blockListManager_->getBlockList()->getItems(); foreach (const JID& jid, jidsToBlock) { if (std::find(blockListBeforeEdit.begin(), blockListBeforeEdit.end(), jid) == blockListBeforeEdit.end()) { blockListBeforeEdit.push_back(jid); } } foreach (const JID& jid, jidsToUnblock) { blockListBeforeEdit.erase(std::remove(blockListBeforeEdit.begin(), blockListBeforeEdit.end(), jid), blockListBeforeEdit.end()); } blockListEditorWidget_->setCurrentBlockList(blockListBeforeEdit); } } }