summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2013-03-08 15:17:30 (GMT)
committerTobias Markmann <tm@ayena.de>2013-03-27 14:12:26 (GMT)
commit497b647fe034a3d2cdc6d75ce0ff70e3df3aaf04 (patch)
treedc81e56199f54cf20f834c78bda7fc26ffbc38f9
parent20ead0a84fdd8c9e870e98ee6a2712bfa263d7fb (diff)
downloadswift-contrib-497b647fe034a3d2cdc6d75ce0ff70e3df3aaf04.zip
swift-contrib-497b647fe034a3d2cdc6d75ce0ff70e3df3aaf04.tar.bz2
Adding support for Blocking Command (XEP-0191) to Swift(-en).
Change-Id: I7c92518dc389474d520d4cf96f96a11459f73d26 License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.
-rw-r--r--Swift/Controllers/BlockListController.cpp159
-rw-r--r--Swift/Controllers/BlockListController.h48
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp48
-rw-r--r--Swift/Controllers/Chat/ChatController.h13
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h2
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp9
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h4
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp80
-rw-r--r--Swift/Controllers/MainController.cpp15
-rw-r--r--Swift/Controllers/MainController.h2
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.cpp10
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.h10
-rw-r--r--Swift/Controllers/Roster/Roster.cpp27
-rw-r--r--Swift/Controllers/Roster/Roster.h2
-rw-r--r--Swift/Controllers/Roster/RosterController.cpp31
-rw-r--r--Swift/Controllers/Roster/RosterController.h15
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp6
-rw-r--r--Swift/Controllers/SConscript1
-rw-r--r--Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h16
-rw-r--r--Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h37
-rw-r--r--Swift/Controllers/UIInterfaces/BlockListEditorWidget.h32
-rw-r--r--Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h20
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/MainWindow.h1
-rw-r--r--Swift/Controllers/UIInterfaces/UIFactory.h4
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h2
-rw-r--r--Swift/Controllers/UnitTest/MockMainWindow.h1
-rw-r--r--Swift/QtUI/QtBlockListEditorWindow.cpp162
-rw-r--r--Swift/QtUI/QtBlockListEditorWindow.h42
-rw-r--r--Swift/QtUI/QtBlockListEditorWindow.ui89
-rw-r--r--Swift/QtUI/QtChatWindow.cpp65
-rw-r--r--Swift/QtUI/QtChatWindow.h6
-rw-r--r--Swift/QtUI/QtMainWindow.cpp13
-rw-r--r--Swift/QtUI/QtMainWindow.h3
-rw-r--r--Swift/QtUI/QtUIFactory.cpp49
-rw-r--r--Swift/QtUI/QtUIFactory.h1
-rw-r--r--Swift/QtUI/Roster/QtRosterWidget.cpp43
-rw-r--r--Swift/QtUI/Roster/RosterModel.cpp4
-rw-r--r--Swift/QtUI/SConscript2
-rw-r--r--Swift/QtUI/Swift.qrc1
-rw-r--r--Swift/resources/icons/stop.pngbin0 -> 454 bytes
-rw-r--r--Swift/resources/icons/stop.svg74
-rw-r--r--Swift/resources/icons/stop.txt2
-rw-r--r--Swiften/Client/BlockList.cpp9
-rw-r--r--Swiften/Client/BlockList.h7
-rw-r--r--Swiften/Client/BlockListImpl.cpp32
-rw-r--r--Swiften/Client/BlockListImpl.h4
-rw-r--r--Swiften/Client/Client.cpp2
-rw-r--r--Swiften/Client/Client.h8
-rw-r--r--Swiften/Client/ClientBlockListManager.cpp32
-rw-r--r--Swiften/Client/ClientBlockListManager.h10
-rw-r--r--Swiften/Client/UnitTest/ClientBlockListManagerTest.cpp190
-rw-r--r--Swiften/Elements/BlockListPayload.h2
-rw-r--r--Swiften/Elements/BlockPayload.h2
-rw-r--r--Swiften/Elements/DiscoInfo.cpp1
-rw-r--r--Swiften/Elements/DiscoInfo.h1
-rw-r--r--Swiften/Elements/UnblockPayload.h2
-rw-r--r--Swiften/Parser/PayloadParsers/BlockParser.h3
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/BlockParserTest.cpp72
-rw-r--r--Swiften/Queries/GenericRequest.h5
-rw-r--r--Swiften/SConscript3
-rw-r--r--Swiften/Serializer/PayloadSerializers/BlockSerializer.h2
-rw-r--r--Swiften/Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp55
63 files changed, 1458 insertions, 137 deletions
diff --git a/Swift/Controllers/BlockListController.cpp b/Swift/Controllers/BlockListController.cpp
new file mode 100644
index 0000000..e7bc45d
--- /dev/null
+++ b/Swift/Controllers/BlockListController.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swift/Controllers/BlockListController.h>
+
+#include <boost/bind.hpp>
+
+#include <Swiften/Client/ClientBlockListManager.h>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/format.h>
+#include <Swift/Controllers/Intl.h>
+#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h>
+#include <Swift/Controllers/XMPPEvents/ErrorEvent.h>
+#include <Swift/Controllers/UIInterfaces/BlockListEditorWidget.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+
+namespace Swift {
+
+BlockListController::BlockListController(ClientBlockListManager* blockListManager, UIEventStream* uiEventStream, BlockListEditorWidgetFactory* blockListEditorWidgetFactory, EventController* eventController) : blockListManager_(blockListManager), blockListEditorWidgetFactory_(blockListEditorWidgetFactory), blockListEditorWidget_(0), eventController_(eventController), remainingRequests_(0) {
+ 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() {
+ 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(boost::shared_ptr<UIEvent> rawEvent) {
+ // handle UI dialog
+ boost::shared_ptr<RequestBlockListDialogUIEvent> requestDialogEvent = boost::dynamic_pointer_cast<RequestBlockListDialogUIEvent>(rawEvent);
+ if (requestDialogEvent != NULL) {
+ if (blockListEditorWidget_ == NULL) {
+ blockListEditorWidget_ = blockListEditorWidgetFactory_->createBlockListEditorWidget();
+ blockListEditorWidget_->onSetNewBlockList.connect(boost::bind(&BlockListController::handleSetNewBlockList, this, _1));
+ }
+ blockListBeforeEdit = blockListManager_->getBlockList()->getItems();
+ blockListEditorWidget_->setCurrentBlockList(blockListBeforeEdit);
+ blockListEditorWidget_->show();
+ return;
+ }
+
+ // handle block state change
+ boost::shared_ptr<RequestChangeBlockStateUIEvent> changeStateEvent = boost::dynamic_pointer_cast<RequestChangeBlockStateUIEvent>(rawEvent);
+ if (changeStateEvent != NULL) {
+ 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, boost::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());
+ }
+ eventController_->handleIncomingEvent(boost::make_shared<ErrorEvent>(request->getReceiver(), errorMessage));
+ }
+ if (originEditor) {
+ remainingRequests_--;
+ if (blockListEditorWidget_ && (remainingRequests_ == 0)) {
+ blockListEditorWidget_->setBusy(false);
+ }
+ }
+}
+
+void BlockListController::handleUnblockResponse(GenericRequest<UnblockPayload>::ref request, boost::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());
+ }
+ eventController_->handleIncomingEvent(boost::make_shared<ErrorEvent>(request->getReceiver(), errorMessage));
+ }
+ if (originEditor) {
+ remainingRequests_--;
+ if (blockListEditorWidget_ && (remainingRequests_ == 0)) {
+ blockListEditorWidget_->setBusy(false);
+ }
+ }
+}
+
+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);
+ }
+}
+
+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) {
+ blockListBeforeEdit.push_back(jid);
+ }
+
+ foreach (const JID& jid, jidsToUnblock) {
+ blockListBeforeEdit.erase(std::remove(blockListBeforeEdit.begin(), blockListBeforeEdit.end(), jid), blockListBeforeEdit.end());;
+ }
+
+ blockListEditorWidget_->setCurrentBlockList(blockListBeforeEdit);
+ }
+}
+
+}
diff --git a/Swift/Controllers/BlockListController.h b/Swift/Controllers/BlockListController.h
new file mode 100644
index 0000000..4c9caad
--- /dev/null
+++ b/Swift/Controllers/BlockListController.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Queries/GenericRequest.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h>
+
+namespace Swift {
+
+class BlockPayload;
+class UnblockPayload;
+class ClientBlockListManager;
+class EventController;
+
+class BlockListController {
+public:
+ BlockListController(ClientBlockListManager* blockListManager, UIEventStream* uiEventStream, BlockListEditorWidgetFactory* blockListEditorWidgetFactory, EventController* eventController);
+ ~BlockListController();
+
+private:
+ void blockListDifferences(const std::vector<JID> &newBlockList, std::vector<JID>& jidsToUnblock, std::vector<JID>& jidsToBlock) const;
+
+ void handleUIEvent(boost::shared_ptr<UIEvent> event);
+
+ void handleBlockResponse(GenericRequest<BlockPayload>::ref, boost::shared_ptr<BlockPayload>, ErrorPayload::ref error, const std::vector<JID>& jids, bool originEditor);
+ void handleUnblockResponse(GenericRequest<UnblockPayload>::ref, boost::shared_ptr<UnblockPayload>, ErrorPayload::ref error, const std::vector<JID>& jids, bool originEditor);
+
+ void handleSetNewBlockList(const std::vector<JID>& newBlockList);
+
+ void handleBlockListChanged();
+
+private:
+ ClientBlockListManager* blockListManager_;
+ BlockListEditorWidgetFactory* blockListEditorWidgetFactory_;
+ BlockListEditorWidget* blockListEditorWidget_;
+ EventController* eventController_;
+ std::vector<JID> blockListBeforeEdit;
+ int remainingRequests_;
+};
+
+}
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 3c0e933..f0de59c 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -36,14 +36,15 @@
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/Highlighter.h>
#include <Swiften/Base/Log.h>
+#include <Swiften/Client/ClientBlockListManager.h>
namespace Swift {
/**
* The controller does not gain ownership of the stanzaChannel, nor the factory.
*/
-ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager)
- : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings) {
+ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager)
+ : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) {
isInMUC_ = isInMUC;
lastWasPresence_ = false;
chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider);
@@ -145,6 +146,19 @@ void ChatController::setToJID(const JID& jid) {
handleBareJIDCapsChanged(toJID_);
}
+void ChatController::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(&ChatController::handleBlockingStateChanged, this));
+ blockingOnItemAddedConnection_ = blockList->onItemAdded.connect(boost::bind(&ChatController::handleBlockingItemAdded, this, _1));
+ blockingOnItemRemovedConnection_ = blockList->onItemRemoved.connect(boost::bind(&ChatController::handleBlockingItemRemoved, this, _1));
+
+ handleBlockingStateChanged();
+ }
+}
+
bool ChatController::isIncomingMessageFromMe(boost::shared_ptr<Message>) {
return false;
}
@@ -216,6 +230,36 @@ void ChatController::checkForDisplayingDisplayReceiptsAlert() {
}
}
+void ChatController::handleBlockingStateChanged() {
+ boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList();
+ if (blockList->getState() == BlockList::Available) {
+ if (blockList->isBlocked(toJID_.toBare())) {
+ chatWindow_->setAlert(QT_TRANSLATE_NOOP("", "You've currently blocked this contact. To continue your conversation you have to unblock the contact first."));
+ chatWindow_->setInputEnabled(false);
+ chatWindow_->setBlockingState(ChatWindow::IsBlocked);
+ } else {
+ chatWindow_->setBlockingState(ChatWindow::IsUnblocked);
+ }
+ }
+}
+
+void ChatController::handleBlockingItemAdded(const JID& jid) {
+ if (jid == toJID_.toBare()) {
+ chatWindow_->setAlert(QT_TRANSLATE_NOOP("", "You've currently blocked this contact. To continue your conversation you have to unblock the contact first."));
+ chatWindow_->setInputEnabled(false);
+ chatWindow_->setBlockingState(ChatWindow::IsBlocked);
+ }
+}
+
+void ChatController::handleBlockingItemRemoved(const JID& jid) {
+ if (jid == toJID_.toBare()) {
+ // FIXME: Support for different types of alerts.
+ chatWindow_->cancelAlert();
+ chatWindow_->setInputEnabled(true);
+ chatWindow_->setBlockingState(ChatWindow::IsUnblocked);
+ }
+}
+
void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<Stanza> sentStanza) {
boost::shared_ptr<Replace> replace = sentStanza->getPayload<Replace>();
if (replace) {
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index 6021ec1..4322240 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -23,12 +23,14 @@ namespace Swift {
class SettingsProvider;
class HistoryController;
class HighlightManager;
+ class ClientBlockListManager;
class ChatController : public ChatControllerBase {
public:
- ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager);
+ ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager);
virtual ~ChatController();
virtual void setToJID(const JID& jid);
+ virtual void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
virtual void setOnline(bool online);
virtual void handleNewFileTransferController(FileTransferController* ftc);
virtual void handleWhiteboardSessionRequest(bool senderIsSelf);
@@ -67,6 +69,10 @@ namespace Swift {
void handleSettingChanged(const std::string& settingPath);
void checkForDisplayingDisplayReceiptsAlert();
+ void handleBlockingStateChanged();
+ void handleBlockingItemAdded(const JID&);
+ void handleBlockingItemRemoved(const JID&);
+
private:
NickResolver* nickResolver_;
ChatStateNotifier* chatStateNotifier_;
@@ -86,6 +92,11 @@ namespace Swift {
std::map<std::string, FileTransferController*> ftControllers;
SettingsProvider* settings_;
std::string lastWbID_;
+
+ ClientBlockListManager* clientBlockListManager_;
+ boost::bsignals::scoped_connection blockingOnStateChangedConnection_;
+ boost::bsignals::scoped_connection blockingOnItemAddedConnection_;
+ boost::bsignals::scoped_connection blockingOnItemRemovedConnection_;
};
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index baef9e6..84bd06a 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -48,7 +48,7 @@ namespace Swift {
virtual ~ChatControllerBase();
void showChatWindow();
void activateChatWindow();
- void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
+ virtual void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
void handleIncomingMessage(boost::shared_ptr<MessageEvent> message);
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, const HighlightAction& highlight);
void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight);
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index dba8565..d6010e9 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -43,6 +43,7 @@
#include <Swift/Controllers/SettingConstants.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swift/Controllers/WhiteboardManager.h>
+#include <Swiften/Client/ClientBlockListManager.h>
namespace Swift {
@@ -75,7 +76,8 @@ ChatsManager::ChatsManager(
SettingsProvider* settings,
HistoryController* historyController,
WhiteboardManager* whiteboardManager,
- HighlightManager* highlightManager) :
+ HighlightManager* highlightManager,
+ ClientBlockListManager* clientBlockListManager) :
jid_(jid),
joinMUCWindowFactory_(joinMUCWindowFactory),
useDelayForLatency_(useDelayForLatency),
@@ -88,7 +90,8 @@ ChatsManager::ChatsManager(
settings_(settings),
historyController_(historyController),
whiteboardManager_(whiteboardManager),
- highlightManager_(highlightManager) {
+ highlightManager_(highlightManager),
+ clientBlockListManager_(clientBlockListManager) {
timerFactory_ = timerFactory;
eventController_ = eventController;
stanzaChannel_ = stanzaChannel;
@@ -523,7 +526,7 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact)
ChatController* ChatsManager::createNewChatController(const JID& contact) {
assert(chatControllers_.find(contact) == chatControllers_.end());
- ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_, highlightManager_);
+ ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_);
chatControllers_[contact] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false));
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 55e62b9..4d7e9a8 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -51,10 +51,11 @@ namespace Swift {
class WhiteboardManager;
class HistoryController;
class HighlightManager;
+ class ClientBlockListManager;
class ChatsManager {
public:
- ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager, HighlightManager* highlightManager);
+ ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager);
virtual ~ChatsManager();
void setAvatarManager(AvatarManager* avatarManager);
void setOnline(bool enabled);
@@ -138,5 +139,6 @@ namespace Swift {
HistoryController* historyController_;
WhiteboardManager* whiteboardManager_;
HighlightManager* highlightManager_;
+ ClientBlockListManager* clientBlockListManager_;
};
}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index dd90d66..84a407c 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -10,48 +10,49 @@
#include <boost/bind.hpp>
-#include "Swift/Controllers/Chat/ChatsManager.h"
-
-#include "Swift/Controllers/Chat/UnitTest/MockChatListWindow.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
-#include "Swift/Controllers/Settings/DummySettingsProvider.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/ChatListWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h"
-#include "Swiften/Client/Client.h"
-#include "Swiften/Disco/EntityCapsManager.h"
-#include "Swiften/Disco/CapsProvider.h"
-#include "Swiften/MUC/MUCManager.h"
-#include "Swift/Controllers/Chat/ChatController.h"
-#include "Swift/Controllers/XMPPEvents/EventController.h"
-#include "Swift/Controllers/Chat/MUCController.h"
-#include "Swiften/Presence/StanzaChannelPresenceSender.h"
-#include "Swiften/Avatars/NullAvatarManager.h"
-#include "Swiften/Avatars/AvatarMemoryStorage.h"
-#include "Swiften/VCards/VCardManager.h"
-#include "Swiften/VCards/VCardMemoryStorage.h"
-#include "Swiften/Client/NickResolver.h"
-#include "Swiften/Presence/DirectedPresenceSender.h"
-#include "Swiften/Roster/XMPPRosterImpl.h"
-#include "Swift/Controllers/UnitTest/MockChatWindow.h"
-#include "Swiften/Client/DummyStanzaChannel.h"
-#include "Swiften/Queries/DummyIQChannel.h"
-#include "Swiften/Presence/PresenceOracle.h"
-#include "Swiften/Jingle/JingleSessionManager.h"
-#include "Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h"
-#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
-#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
+#include <Swift/Controllers/Chat/ChatsManager.h>
+
+#include <Swift/Controllers/Chat/UnitTest/MockChatListWindow.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h>
+#include <Swiften/Client/Client.h>
+#include <Swiften/Disco/EntityCapsManager.h>
+#include <Swiften/Disco/CapsProvider.h>
+#include <Swiften/MUC/MUCManager.h>
+#include <Swift/Controllers/Chat/ChatController.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/Chat/MUCController.h>
+#include <Swiften/Presence/StanzaChannelPresenceSender.h>
+#include <Swiften/Avatars/NullAvatarManager.h>
+#include <Swiften/Avatars/AvatarMemoryStorage.h>
+#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/VCards/VCardMemoryStorage.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Presence/DirectedPresenceSender.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
+#include <Swift/Controllers/UnitTest/MockChatWindow.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Jingle/JingleSessionManager.h>
+#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/ProfileSettingsProvider.h>
-#include "Swift/Controllers/FileTransfer/FileTransferOverview.h"
-#include "Swiften/Elements/DeliveryReceiptRequest.h"
-#include "Swiften/Elements/DeliveryReceipt.h"
+#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
+#include <Swiften/Elements/DeliveryReceiptRequest.h>
+#include <Swiften/Elements/DeliveryReceipt.h>
#include <Swiften/Base/Algorithm.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/WhiteboardManager.h>
#include <Swiften/Whiteboard/WhiteboardSessionManager.h>
+#include <Swiften/Client/ClientBlockListManager.h>
using namespace Swift;
@@ -109,7 +110,8 @@ public:
highlightManager_ = new HighlightManager(settings_);
mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_);
- manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_, highlightManager_);
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_, highlightManager_, clientBlockListManager_);
manager_->setAvatarManager(avatarManager_);
}
@@ -120,6 +122,7 @@ public:
delete profileSettings_;
delete avatarManager_;
delete manager_;
+ delete clientBlockListManager_;
delete ftOverview_;
delete ftManager_;
delete wbSessionManager_;
@@ -484,6 +487,7 @@ private:
WhiteboardSessionManager* wbSessionManager_;
WhiteboardManager* wbManager_;
HighlightManager* highlightManager_;
+ ClientBlockListManager* clientBlockListManager_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest);
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 0c9c09c..32d045d 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -87,6 +87,8 @@
#include <Swiften/Client/StanzaChannel.h>
#include <Swift/Controllers/HighlightManager.h>
#include <Swift/Controllers/HighlightEditorController.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swift/Controllers/BlockListController.h>
namespace Swift {
@@ -130,6 +132,7 @@ MainController::MainController(
historyViewController_ = NULL;
eventWindowController_ = NULL;
profileController_ = NULL;
+ blockListController_ = NULL;
showProfileController_ = NULL;
contactEditController_ = NULL;
userSearchControllerChat_ = NULL;
@@ -321,11 +324,13 @@ void MainController::handleConnected() {
client_->getFileTransferManager()->startListeningOnPort(randomPort);
ftOverview_ = new FileTransferOverview(client_->getFileTransferManager());
fileTransferListController_->setFileTransferOverview(ftOverview_);
- rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_);
+ rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_, client_->getClientBlockListManager());
rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this));
rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&MainController::handleShowCertificateRequest, this));
+ blockListController_ = new BlockListController(client_->getClientBlockListManager(), uiEventStream_, uiFactory_, eventController_);
+
contactEditController_ = new ContactEditController(rosterController_, client_->getVCardManager(), uiFactory_, uiEventStream_);
whiteboardManager_ = new WhiteboardManager(uiFactory_, uiEventStream_, client_->getNickResolver(), client_->getWhiteboardSessionManager());
@@ -337,9 +342,9 @@ void MainController::handleConnected() {
#ifdef SWIFT_EXPERIMENTAL_HISTORY
historyController_ = new HistoryController(storages_->getHistoryStorage());
historyViewController_ = new HistoryViewController(jid_, uiEventStream_, historyController_, client_->getNickResolver(), client_->getAvatarManager(), client_->getPresenceOracle(), uiFactory_);
- chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_, highlightManager_);
+ chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_, highlightManager_, client_->getClientBlockListManager());
#else
- chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_, highlightManager_);
+ chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_, highlightManager_, client_->getClientBlockListManager());
#endif
client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
@@ -731,6 +736,10 @@ void MainController::handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>
if (!error) {
chatsManager_->setServerDiscoInfo(info);
adHocManager_->setServerDiscoInfo(info);
+ if (info->hasFeature(DiscoInfo::BlockingCommandFeature)) {
+ rosterController_->getWindow()->setBlockingCommandAvailable(true);
+ rosterController_->initBlockingCommand();
+ }
}
}
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 4f37e12..d60805a 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -74,6 +74,7 @@ namespace Swift {
class WhiteboardManager;
class HighlightManager;
class HighlightEditorController;
+ class BlockListController;
class MainController {
public:
@@ -154,6 +155,7 @@ namespace Swift {
HistoryViewController* historyViewController_;
HistoryController* historyController_;
FileTransferListController* fileTransferListController_;
+ BlockListController* blockListController_;
ChatsManager* chatsManager_;
ProfileController* profileController_;
ShowProfileController* showProfileController_;
diff --git a/Swift/Controllers/Roster/ContactRosterItem.cpp b/Swift/Controllers/Roster/ContactRosterItem.cpp
index f301552..bf85167 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.cpp
+++ b/Swift/Controllers/Roster/ContactRosterItem.cpp
@@ -16,7 +16,7 @@
namespace Swift {
-ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, const std::string& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid), displayJID_(displayJID) {
+ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, const std::string& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid), displayJID_(displayJID), blockState_(BlockingNotSupported) {
}
ContactRosterItem::~ContactRosterItem() {
@@ -134,6 +134,14 @@ bool ContactRosterItem::supportsFeature(const Feature feature) const {
return features_.find(feature) != features_.end();
}
+void ContactRosterItem::setBlockState(BlockState state) {
+ blockState_ = state;
+}
+
+ContactRosterItem::BlockState ContactRosterItem::blockState() const {
+ return blockState_;
+}
+
}
diff --git a/Swift/Controllers/Roster/ContactRosterItem.h b/Swift/Controllers/Roster/ContactRosterItem.h
index 247c606..fc65d6d 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.h
+++ b/Swift/Controllers/Roster/ContactRosterItem.h
@@ -28,6 +28,12 @@ class ContactRosterItem : public RosterItem {
FileTransferFeature,
WhiteboardFeature
};
+
+ enum BlockState {
+ BlockingNotSupported,
+ IsBlocked,
+ IsUnblocked
+ };
public:
ContactRosterItem(const JID& jid, const JID& displayJID, const std::string& name, GroupRosterItem* parent);
@@ -53,6 +59,9 @@ class ContactRosterItem : public RosterItem {
void setSupportedFeatures(const std::set<Feature>& features);
bool supportsFeature(Feature feature) const;
+ void setBlockState(BlockState state);
+ BlockState blockState() const;
+
private:
JID jid_;
JID displayJID_;
@@ -63,6 +72,7 @@ class ContactRosterItem : public RosterItem {
boost::shared_ptr<Presence> shownPresence_;
std::vector<std::string> groups_;
std::set<Feature> features_;
+ BlockState blockState_;
};
}
diff --git a/Swift/Controllers/Roster/Roster.cpp b/Swift/Controllers/Roster/Roster.cpp
index b5c5998..3d0ca2e 100644
--- a/Swift/Controllers/Roster/Roster.cpp
+++ b/Swift/Controllers/Roster/Roster.cpp
@@ -22,7 +22,7 @@
namespace Swift {
-Roster::Roster(bool sortByStatus, bool fullJIDMapping) {
+Roster::Roster(bool sortByStatus, bool fullJIDMapping) : blockingSupported_(false) {
sortByStatus_ = sortByStatus;
fullJIDMapping_ = fullJIDMapping;
root_ = new GroupRosterItem("Dummy-Root", NULL, sortByStatus_);
@@ -71,6 +71,28 @@ void Roster::setAvailableFeatures(const JID& jid, const std::set<ContactRosterIt
}
}
+void Roster::setBlockedState(const std::vector<JID> &jids, ContactRosterItem::BlockState state) {
+ if (!blockingSupported_ ) {
+ foreach(ItemMap::value_type i, itemMap_) {
+ foreach(ContactRosterItem* item, i.second) {
+ item->setBlockState(ContactRosterItem::IsUnblocked);
+ }
+ }
+ }
+
+ foreach(const JID& jid, jids) {
+ ItemMap::const_iterator i = itemMap_.find(fullJIDMapping_ ? jid : jid.toBare());
+ if (i == itemMap_.end()) {
+ continue;
+ }
+ foreach(ContactRosterItem* item, i->second) {
+ item->setBlockState(state);
+ }
+ }
+
+ blockingSupported_ = true;
+}
+
void Roster::removeGroup(const std::string& group) {
root_->removeGroupChild(group);
}
@@ -87,6 +109,9 @@ void Roster::addContact(const JID& jid, const JID& displayJID, const std::string
GroupRosterItem* group(getGroup(groupName));
ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group);
item->setAvatarPath(avatarPath);
+ if (blockingSupported_) {
+ item->setBlockState(ContactRosterItem::IsUnblocked);
+ }
group->addChild(item);
ItemMap::iterator i = itemMap_.insert(std::make_pair(fullJIDMapping_ ? jid : jid.toBare(), std::vector<ContactRosterItem*>())).first;
if (!i->second.empty()) {
diff --git a/Swift/Controllers/Roster/Roster.h b/Swift/Controllers/Roster/Roster.h
index 74547d6..91a152f 100644
--- a/Swift/Controllers/Roster/Roster.h
+++ b/Swift/Controllers/Roster/Roster.h
@@ -45,6 +45,7 @@ class Roster {
boost::signal<void (RosterItem*)> onDataChanged;
GroupRosterItem* getGroup(const std::string& groupName);
void setAvailableFeatures(const JID& jid, const std::set<ContactRosterItem::Feature>& features);
+ void setBlockedState(const std::vector<JID>& jids, ContactRosterItem::BlockState state);
private:
void handleDataChanged(RosterItem* item);
@@ -58,6 +59,7 @@ class Roster {
ItemMap itemMap_;
bool fullJIDMapping_;
bool sortByStatus_;
+ bool blockingSupported_;
};
}
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index ec52993..d09ef4c 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -44,14 +44,15 @@
#include <Swiften/Disco/EntityCapsManager.h>
#include <Swiften/Jingle/JingleSessionManager.h>
#include <Swift/Controllers/SettingConstants.h>
+#include <Swiften/Client/ClientBlockListManager.h>
namespace Swift {
/**
* The controller does not gain ownership of these parameters.
*/
-RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview)
- : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview) {
+RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager)
+ : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview), clientBlockListManager_(clientBlockListManager) {
assert(fileTransferOverview);
iqRouter_ = iqRouter;
presenceOracle_ = presenceOracle;
@@ -183,6 +184,20 @@ void RosterController::handleSettingChanged(const std::string& settingPath) {
}
}
+void RosterController::handleBlockingStateChanged() {
+ if (clientBlockListManager_->getBlockList()->getState() == BlockList::Available) {
+ roster_->setBlockedState(clientBlockListManager_->getBlockList()->getItems(), ContactRosterItem::IsBlocked);
+ }
+}
+
+void RosterController::handleBlockingItemAdded(const JID& jid) {
+ roster_->setBlockedState(std::vector<JID>(1, jid), ContactRosterItem::IsBlocked);
+}
+
+void RosterController::handleBlockingItemRemoved(const JID& jid) {
+ roster_->setBlockedState(std::vector<JID>(1, jid), ContactRosterItem::IsUnblocked);
+}
+
void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
if (boost::shared_ptr<AddContactUIEvent> addContactEvent = boost::dynamic_pointer_cast<AddContactUIEvent>(event)) {
RosterItemPayload item;
@@ -256,6 +271,18 @@ void RosterController::updateItem(const XMPPRosterItem& item) {
request->send();
}
+void RosterController::initBlockingCommand() {
+ boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList();
+
+ blockingOnStateChangedConnection_ = blockList->onStateChanged.connect(boost::bind(&RosterController::handleBlockingStateChanged, this));
+ blockingOnItemAddedConnection_ = blockList->onItemAdded.connect(boost::bind(&RosterController::handleBlockingItemAdded, this, _1));
+ blockingOnItemRemovedConnection_ = blockList->onItemRemoved.connect(boost::bind(&RosterController::handleBlockingItemRemoved, this, _1));
+
+ if (blockList->getState() == BlockList::Available) {
+ roster_->setBlockedState(blockList->getItems(), ContactRosterItem::IsBlocked);
+ }
+}
+
void RosterController::handleRosterSetError(ErrorPayload::ref error, boost::shared_ptr<RosterPayload> rosterPayload) {
if (!error) {
return;
diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h
index ec07574..06b551e 100644
--- a/Swift/Controllers/Roster/RosterController.h
+++ b/Swift/Controllers/Roster/RosterController.h
@@ -39,10 +39,11 @@ namespace Swift {
class NickManager;
class EntityCapsProvider;
class FileTransferManager;
-
+ class ClientBlockListManager;
+
class RosterController {
public:
- RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview);
+ RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager);
~RosterController();
void showRosterWindow();
MainWindow* getWindow() {return mainWindow_;}
@@ -57,6 +58,8 @@ namespace Swift {
void setContactGroups(const JID& jid, const std::vector<std::string>& groups);
void updateItem(const XMPPRosterItem&);
+ void initBlockingCommand();
+
private:
void handleOnJIDAdded(const JID &jid);
void handleRosterCleared();
@@ -76,6 +79,10 @@ namespace Swift {
void handleOnCapsChanged(const JID& jid);
void handleSettingChanged(const std::string& settingPath);
+ void handleBlockingStateChanged();
+ void handleBlockingItemAdded(const JID& jid);
+ void handleBlockingItemRemoved(const JID& jid);
+
JID myJID_;
XMPPRoster* xmppRoster_;
MainWindowFactory* mainWindowFactory_;
@@ -94,7 +101,11 @@ namespace Swift {
UIEventStream* uiEventStream_;
EntityCapsProvider* entityCapsManager_;
FileTransferOverview* ftOverview_;
+ ClientBlockListManager* clientBlockListManager_;
+ boost::bsignals::scoped_connection blockingOnStateChangedConnection_;
+ boost::bsignals::scoped_connection blockingOnItemAddedConnection_;
+ boost::bsignals::scoped_connection blockingOnItemRemovedConnection_;
boost::bsignals::scoped_connection changeStatusConnection_;
boost::bsignals::scoped_connection signOutConnection_;
boost::bsignals::scoped_connection uiEventConnection_;
diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
index e439c78..b0034e6 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
@@ -37,6 +37,7 @@
#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
#include <Swiften/Base/Algorithm.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
+#include <Swiften/Client/ClientBlockListManager.h>
using namespace Swift;
@@ -82,12 +83,14 @@ class RosterControllerTest : public CppUnit::TestFixture {
ftManager_ = new DummyFileTransferManager();
ftOverview_ = new FileTransferOverview(ftManager_);
- rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, ftOverview_);
+ clientBlockListManager_ = new ClientBlockListManager(router_);
+ rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, ftOverview_, clientBlockListManager_);
mainWindow_ = mainWindowFactory_->last;
}
void tearDown() {
delete rosterController_;
+ delete clientBlockListManager_;
delete ftManager_;
delete jingleSessionManager_;
@@ -337,6 +340,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
JingleSessionManager* jingleSessionManager_;
FileTransferManager* ftManager_;
FileTransferOverview* ftOverview_;
+ ClientBlockListManager* clientBlockListManager_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(RosterControllerTest);
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index 26b9334..6f36a52 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -49,6 +49,7 @@ if env["SCONS_STAGE"] == "build" :
"HistoryViewController.cpp",
"HistoryController.cpp",
"FileTransferListController.cpp",
+ "BlockListController.cpp",
"StatusTracker.cpp",
"PresenceNotifier.cpp",
"EventNotifier.cpp",
diff --git a/Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h b/Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h
new file mode 100644
index 0000000..d29cb4f
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+
+class RequestBlockListDialogUIEvent : public UIEvent {
+};
+
+}
diff --git a/Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h b/Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h
new file mode 100644
index 0000000..9b7abcb
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+
+class RequestChangeBlockStateUIEvent : public UIEvent {
+ public:
+ enum BlockState {
+ Blocked,
+ Unblocked
+ };
+
+ public:
+ RequestChangeBlockStateUIEvent(BlockState newState, const JID& contact) : state_(newState), contact_(contact) {}
+
+ BlockState getBlockState() const {
+ return state_;
+ }
+
+ JID getContact() const {
+ return contact_;
+ }
+ private:
+ BlockState state_;
+ JID contact_;
+};
+
+}
diff --git a/Swift/Controllers/UIInterfaces/BlockListEditorWidget.h b/Swift/Controllers/UIInterfaces/BlockListEditorWidget.h
new file mode 100644
index 0000000..60a1c11
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/BlockListEditorWidget.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <Swiften/JID/JID.h>
+#include <Swiften/Base/boost_bsignals.h>
+
+namespace Swift {
+
+ class ClientBlockListManager;
+
+ class BlockListEditorWidget {
+ public:
+ virtual ~BlockListEditorWidget() {}
+
+ virtual void show() = 0;
+
+ virtual void setCurrentBlockList(const std::vector<JID>& blockedJIDs) = 0;
+ virtual void setBusy(bool isBusy) = 0;
+
+ virtual std::vector<JID> getCurrentBlockList() const = 0;
+
+ boost::signal<void (const std::vector<JID>& /* blockedJID */)> onSetNewBlockList;
+ };
+
+}
diff --git a/Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h b/Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h
new file mode 100644
index 0000000..eb91ac1
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+
+ class BlockListEditorWidget;
+
+ class BlockListEditorWidgetFactory {
+ public:
+ virtual ~BlockListEditorWidgetFactory() {}
+
+ virtual BlockListEditorWidget* createBlockListEditorWidget() = 0;
+ };
+
+}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index d6b3656..b8e6722 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -39,6 +39,7 @@ namespace Swift {
enum RoomAction {ChangeSubject, Configure, Affiliations, Destroy, Invite};
enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed};
enum WhiteboardSessionState {WhiteboardAccepted, WhiteboardTerminated, WhiteboardRejected};
+ enum BlockingState {BlockingUnsupported, IsBlocked, IsUnblocked};
ChatWindow() {}
virtual ~ChatWindow() {}
@@ -89,6 +90,7 @@ namespace Swift {
virtual void setSubject(const std::string& subject) = 0;
virtual void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&) = 0;
virtual void setAvailableRoomActions(const std::vector<RoomAction> &actions) = 0;
+ virtual void setBlockingState(BlockingState state) = 0;
/**
* Set an alert on the window.
* @param alertText Description of alert (required).
diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h
index 2df2c10..3b10041 100644
--- a/Swift/Controllers/UIInterfaces/MainWindow.h
+++ b/Swift/Controllers/UIInterfaces/MainWindow.h
@@ -34,6 +34,7 @@ namespace Swift {
/** Must be able to cope with NULL to clear the roster */
virtual void setRosterModel(Roster* roster) = 0;
virtual void setConnecting() = 0;
+ virtual void setBlockingCommandAvailable(bool isAvailable) = 0;
virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) = 0;
virtual void setStreamEncryptionStatus(bool tlsInPlaceAndValid) = 0;
virtual void openCertificateDialog(const std::vector<Certificate::ref>& chain) = 0;
diff --git a/Swift/Controllers/UIInterfaces/UIFactory.h b/Swift/Controllers/UIInterfaces/UIFactory.h
index dcd1779..990dc98 100644
--- a/Swift/Controllers/UIInterfaces/UIFactory.h
+++ b/Swift/Controllers/UIInterfaces/UIFactory.h
@@ -22,6 +22,7 @@
#include <Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h>
#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h>
+#include <Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h>
namespace Swift {
class UIFactory :
@@ -40,7 +41,8 @@ namespace Swift {
public AdHocCommandWindowFactory,
public FileTransferListWidgetFactory,
public WhiteboardWindowFactory,
- public HighlightEditorWidgetFactory {
+ public HighlightEditorWidgetFactory,
+ public BlockListEditorWidgetFactory {
public:
virtual ~UIFactory() {}
};
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 84aaa04..8af65f7 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -60,6 +60,8 @@ namespace Swift {
virtual void setAvailableRoomActions(const std::vector<RoomAction> &) {}
virtual InviteToChatWindow* createInviteToChatWindow() {return NULL;}
+ virtual void setBlockingState(BlockingState) {}
+
std::string name_;
std::string lastMessageBody_;
std::vector<SecurityLabelsCatalog::Item> labels_;
diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h
index 19ab522..69a4e25 100644
--- a/Swift/Controllers/UnitTest/MockMainWindow.h
+++ b/Swift/Controllers/UnitTest/MockMainWindow.h
@@ -24,6 +24,7 @@ namespace Swift {
virtual void setConnecting() {}
virtual void setStreamEncryptionStatus(bool /*tlsInPlaceAndValid*/) {}
virtual void openCertificateDialog(const std::vector<Certificate::ref>& /*chain*/) {}
+ virtual void setBlockingCommandAvailable(bool /*isAvailable*/) {}
Roster* roster;
};
diff --git a/Swift/QtUI/QtBlockListEditorWindow.cpp b/Swift/QtUI/QtBlockListEditorWindow.cpp
new file mode 100644
index 0000000..63e8d1f
--- /dev/null
+++ b/Swift/QtUI/QtBlockListEditorWindow.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <QtBlockListEditorWindow.h>
+#include <ui_QtBlockListEditorWindow.h>
+
+#include <boost/bind.hpp>
+
+#include <QLineEdit>
+#include <QMovie>
+#include <QShortcut>
+#include <QStyledItemDelegate>
+#include <QValidator>
+
+#include <Swift/QtUI/QtUtilities.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Base/foreach.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+
+class QtJIDValidator : public QValidator {
+ public:
+ QtJIDValidator(QObject* parent) : QValidator(parent) {}
+ virtual ~QtJIDValidator() {}
+ virtual QValidator::State validate(QString& input, int&) const {
+ return JID(Q2PSTRING(input)).isValid() ? Acceptable : Intermediate;
+ }
+};
+
+class QtJIDValidatedItemDelegate : public QItemDelegate {
+ public:
+ QtJIDValidatedItemDelegate(QObject* parent) : QItemDelegate(parent) {}
+ virtual ~QtJIDValidatedItemDelegate() {}
+
+ virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex&) const {
+ QLineEdit *editor = new QLineEdit(parent);
+ editor->setValidator(new QtJIDValidator(editor));
+ return editor;
+ }
+
+ void setEditorData(QWidget *editor, const QModelIndex &index) const {
+ QString value = index.model()->data(index, Qt::EditRole).toString();
+
+ QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
+ lineEdit->setText(value);
+ }
+
+ void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
+ QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
+ QString currentValue = lineEdit->text();
+ int pos = 0;
+ if (lineEdit->validator()->validate(currentValue, pos) == QValidator::Acceptable) {
+ model->setData(index, lineEdit->text(), Qt::EditRole);
+ } else {
+ model->setData(index, QString(), Qt::EditRole);
+ }
+ }
+
+ void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const {
+ editor->setGeometry(option.rect);
+ }
+};
+
+QtBlockListEditorWindow::QtBlockListEditorWindow() : QWidget(), ui(new Ui::QtBlockListEditorWindow) {
+ ui->setupUi(this);
+ new QShortcut(QKeySequence::Close, this, SLOT(close()));
+ ui->throbberLabel->setMovie(new QMovie(":/icons/throbber.gif", QByteArray(), this));
+
+ itemDelegate = new QtRemovableItemDelegate(style());
+
+ connect(ui->savePushButton, SIGNAL(clicked()), SLOT(applyChanges()));
+
+ ui->blockListTreeWidget->setColumnCount(2);
+ ui->blockListTreeWidget->header()->setStretchLastSection(false);
+ int closeIconWidth = ui->blockListTreeWidget->fontMetrics().height();
+ ui->blockListTreeWidget->header()->resizeSection(1, closeIconWidth);
+
+#if QT_VERSION >= 0x050000
+ ui->blockListTreeWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch);
+#else
+ ui->blockListTreeWidget->header()->setResizeMode(0, QHeaderView::Stretch);
+#endif
+
+ ui->blockListTreeWidget->setHeaderHidden(true);
+ ui->blockListTreeWidget->setRootIsDecorated(false);
+ ui->blockListTreeWidget->setEditTriggers(QAbstractItemView::DoubleClicked);
+ ui->blockListTreeWidget->setItemDelegateForColumn(0, new QtJIDValidatedItemDelegate(this));
+ ui->blockListTreeWidget->setItemDelegateForColumn(1, itemDelegate);
+ connect(ui->blockListTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), SLOT(handleItemChanged(QTreeWidgetItem*,int)));
+
+ QTreeWidgetItem* item = new QTreeWidgetItem(QStringList("") << "");
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ ui->blockListTreeWidget->addTopLevelItem(item);
+}
+
+QtBlockListEditorWindow::~QtBlockListEditorWindow() {
+}
+
+void QtBlockListEditorWindow::show() {
+ QWidget::show();
+ QWidget::activateWindow();
+}
+
+void QtBlockListEditorWindow::handleItemChanged(QTreeWidgetItem *, int) {
+ bool hasEmptyRow = false;
+ QList<QTreeWidgetItem*> rows = ui->blockListTreeWidget->findItems("", Qt::MatchFixedString);
+ foreach(QTreeWidgetItem* row, rows) {
+ if (row->text(0).isEmpty()) {
+ hasEmptyRow = true;
+ }
+ }
+
+ if (!hasEmptyRow) {
+ QTreeWidgetItem* item = new QTreeWidgetItem(QStringList("") << "");
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ ui->blockListTreeWidget->addTopLevelItem(item);
+ }
+}
+
+void QtBlockListEditorWindow::applyChanges() {
+ onSetNewBlockList(getCurrentBlockList());
+}
+
+void Swift::QtBlockListEditorWindow::setCurrentBlockList(const std::vector<JID> &blockedJIDs) {
+ ui->blockListTreeWidget->clear();
+
+ foreach(const JID& jid, blockedJIDs) {
+ QTreeWidgetItem* item = new QTreeWidgetItem(QStringList(P2QSTRING(jid.toString())) << "");
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ ui->blockListTreeWidget->addTopLevelItem(item);
+ }
+ handleItemChanged(0,0);
+}
+
+void Swift::QtBlockListEditorWindow::setBusy(bool isBusy) {
+ if (isBusy) {
+ ui->throbberLabel->movie()->start();
+ ui->throbberLabel->show();
+ } else {
+ ui->throbberLabel->movie()->stop();
+ ui->throbberLabel->hide();
+ }
+}
+
+std::vector<JID> Swift::QtBlockListEditorWindow::getCurrentBlockList() const {
+ std::vector<JID> futureBlockedJIDs;
+
+ for(int i=0; i < ui->blockListTreeWidget->topLevelItemCount(); ++i) {
+ QTreeWidgetItem* row = ui->blockListTreeWidget->topLevelItem(i);
+ if (!row->text(0).isEmpty()) {
+ futureBlockedJIDs.push_back(JID(Q2PSTRING(row->text(0))));
+ }
+ }
+ return futureBlockedJIDs;
+}
+
+}
diff --git a/Swift/QtUI/QtBlockListEditorWindow.h b/Swift/QtUI/QtBlockListEditorWindow.h
new file mode 100644
index 0000000..4b124a3
--- /dev/null
+++ b/Swift/QtUI/QtBlockListEditorWindow.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIInterfaces/BlockListEditorWidget.h>
+#include <Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.h>
+
+#include <QWidget>
+#include <QTreeWidgetItem>
+
+namespace Ui {
+ class QtBlockListEditorWindow;
+}
+
+namespace Swift {
+
+class QtBlockListEditorWindow : public QWidget, public BlockListEditorWidget {
+ Q_OBJECT
+
+ public:
+ QtBlockListEditorWindow();
+ virtual ~QtBlockListEditorWindow();
+
+ virtual void show();
+ virtual void setCurrentBlockList(const std::vector<JID>& blockedJIDs);
+ virtual void setBusy(bool isBusy);
+ virtual std::vector<JID> getCurrentBlockList() const;
+
+ private slots:
+ void handleItemChanged(QTreeWidgetItem*, int);
+ void applyChanges();
+
+ private:
+ Ui::QtBlockListEditorWindow* ui;
+ QtRemovableItemDelegate* itemDelegate;
+};
+
+}
diff --git a/Swift/QtUI/QtBlockListEditorWindow.ui b/Swift/QtUI/QtBlockListEditorWindow.ui
new file mode 100644
index 0000000..f71bbae
--- /dev/null
+++ b/Swift/QtUI/QtBlockListEditorWindow.ui
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtBlockListEditorWindow</class>
+ <widget class="QWidget" name="QtBlockListEditorWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>348</width>
+ <height>262</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Edit Block List</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="margin">
+ <number>5</number>
+ </property>
+ <item>
+ <widget class="QTreeWidget" name="blockListTreeWidget">
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="errorLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="throbberLabel">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::NoTextInteraction</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="savePushButton">
+ <property name="text">
+ <string>Save</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 11e64ab..efdab99 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -24,6 +24,7 @@
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
#include "QtChatWindowJSBridge.h"
#include "QtUtilities.h"
@@ -47,6 +48,7 @@
#include <QTextEdit>
#include <QTime>
#include <QUrl>
+#include <QToolButton>
#include <QPushButton>
#include <QFileDialog>
#include <QMenu>
@@ -66,7 +68,7 @@ const QString QtChatWindow::ButtonFileTransferAcceptRequest = QString("filetrans
const QString QtChatWindow::ButtonMUCInvite = QString("mucinvite");
-QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, QMap<QString, QString> emoticons) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageKind_(PreviosuMessageWasNone), eventStream_(eventStream), emoticons_(emoticons) {
+QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, QMap<QString, QString> emoticons) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageKind_(PreviosuMessageWasNone), eventStream_(eventStream), emoticons_(emoticons), blockingState_(BlockingUnsupported) {
settings_ = settings;
unreadCount_ = 0;
idCounter_ = 0;
@@ -105,21 +107,18 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
alertLabel_->setStyleSheet(alertStyleSheet_);
alertWidget_->hide();
- QBoxLayout* subjectLayout = new QBoxLayout(QBoxLayout::LeftToRight);
+ subjectLayout_ = new QBoxLayout(QBoxLayout::LeftToRight);
subject_ = new QLineEdit(this);
- subjectLayout->addWidget(subject_);
+ subjectLayout_->addWidget(subject_);
setSubject("");
subject_->setReadOnly(true);
- actionButton_ = new QPushButton(this);
+ QPushButton* actionButton_ = new QPushButton(this);
actionButton_->setIcon(QIcon(":/icons/actions.png"));
connect(actionButton_, SIGNAL(clicked()), this, SLOT(handleActionButtonClicked()));
- subjectLayout->addWidget(actionButton_);
-
subject_->hide();
- actionButton_->hide();
- layout->addLayout(subjectLayout);
+ layout->addLayout(subjectLayout_);
logRosterSplitter_ = new QSplitter(this);
logRosterSplitter_->setAutoFillBackground(true);
@@ -159,6 +158,12 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
correctingLabel_ = new QLabel(tr("Correcting"), this);
inputBarLayout->addWidget(correctingLabel_);
correctingLabel_->hide();
+
+ // using an extra layout to work around Qt margin glitches on OS X
+ QHBoxLayout* actionLayout = new QHBoxLayout();
+ actionLayout->addWidget(actionButton_);
+
+ inputBarLayout->addLayout(actionLayout);
layout->addLayout(inputBarLayout);
inputClearing_ = false;
@@ -415,7 +420,6 @@ void QtChatWindow::convertToMUC() {
setAcceptDrops(false);
treeWidget_->show();
subject_->show();
- actionButton_->show();
}
void QtChatWindow::qAppFocusChanged(QWidget* /*old*/, QWidget* /*now*/) {
@@ -504,8 +508,7 @@ QString QtChatWindow::linkimoticonify(const QString& message) const {
return messageHTML;
}
-QString QtChatWindow::getHighlightSpanStart(const HighlightAction& highlight)
-{
+QString QtChatWindow::getHighlightSpanStart(const HighlightAction& highlight) {
QString color = QtUtilities::htmlEscape(P2QSTRING(highlight.getTextColor()));
QString background = QtUtilities::htmlEscape(P2QSTRING(highlight.getTextBackground()));
if (color.isEmpty()) {
@@ -922,15 +925,26 @@ void QtChatWindow::handleActionButtonClicked() {
QAction* destroy = NULL;
QAction* invite = NULL;
- foreach(ChatWindow::RoomAction availableAction, availableRoomActions_)
- {
- switch(availableAction)
+ QAction* block = NULL;
+ QAction* unblock = NULL;
+
+ if (availableRoomActions_.empty()) {
+ if (blockingState_ == IsBlocked) {
+ unblock = contextMenu.addAction(tr("Unblock"));
+ } else if (blockingState_ == IsUnblocked) {
+ block = contextMenu.addAction(tr("Block"));
+ }
+ } else {
+ foreach(ChatWindow::RoomAction availableAction, availableRoomActions_)
{
- case ChatWindow::ChangeSubject: changeSubject = contextMenu.addAction(tr("Change subject…")); break;
- case ChatWindow::Configure: configure = contextMenu.addAction(tr("Configure room…")); break;
- case ChatWindow::Affiliations: affiliations = contextMenu.addAction(tr("Edit affiliations…")); break;
- case ChatWindow::Destroy: destroy = contextMenu.addAction(tr("Destroy room")); break;
- case ChatWindow::Invite: invite = contextMenu.addAction(tr("Invite person to this room…")); break;
+ switch(availableAction)
+ {
+ case ChatWindow::ChangeSubject: changeSubject = contextMenu.addAction(tr("Change subject…")); break;
+ case ChatWindow::Configure: configure = contextMenu.addAction(tr("Configure room…")); break;
+ case ChatWindow::Affiliations: affiliations = contextMenu.addAction(tr("Edit affiliations…")); break;
+ case ChatWindow::Destroy: destroy = contextMenu.addAction(tr("Destroy room")); break;
+ case ChatWindow::Invite: invite = contextMenu.addAction(tr("Invite person to this room…")); break;
+ }
}
}
@@ -970,6 +984,12 @@ void QtChatWindow::handleActionButtonClicked() {
else if (result == invite) {
onInvitePersonToThisMUCRequest();
}
+ else if (result == block) {
+ eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Blocked, JID(Q2PSTRING(contact_))));
+ }
+ else if (result == unblock) {
+ eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, JID(Q2PSTRING(contact_))));
+ }
}
void QtChatWindow::handleAffiliationEditorAccepted() {
@@ -981,11 +1001,14 @@ void QtChatWindow::setAffiliations(MUCOccupant::Affiliation affiliation, const s
affiliationEditor_->setAffiliations(affiliation, jids);
}
-void QtChatWindow::setAvailableRoomActions(const std::vector<RoomAction> &actions)
-{
+void QtChatWindow::setAvailableRoomActions(const std::vector<RoomAction>& actions) {
availableRoomActions_ = actions;
}
+void QtChatWindow::setBlockingState(BlockingState state) {
+ blockingState_ = state;
+}
+
void QtChatWindow::showRoomConfigurationForm(Form::ref form) {
if (mucConfigurationWindow_) {
delete mucConfigurationWindow_.data();
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 4abd456..3ccea31 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -132,7 +132,8 @@ namespace Swift {
void showRoomConfigurationForm(Form::ref);
void addMUCInvitation(const std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct = true);
void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&);
- void setAvailableRoomActions(const std::vector<RoomAction> &actions);
+ void setAvailableRoomActions(const std::vector<RoomAction>& actions);
+ void setBlockingState(BlockingState state);
InviteToChatWindow* createInviteToChatWindow();
@@ -209,6 +210,7 @@ namespace Swift {
QtChatTheme* theme_;
QtTextEdit* input_;
QWidget* midBar_;
+ QBoxLayout* subjectLayout_;
QComboBox* labelsWidget_;
QtOccupantListWidget* treeWidget_;
QLabel* correctingLabel_;
@@ -217,7 +219,6 @@ namespace Swift {
QPushButton* alertButton_;
TabComplete* completer_;
QLineEdit* subject_;
- QPushButton* actionButton_;
bool isCorrection_;
bool previousMessageWasSelf_;
PreviousMessageKind previousMessageKind_;
@@ -240,5 +241,6 @@ namespace Swift {
bool showEmoticons_;
QPalette defaultLabelsPalette_;
LabelModel* labelModel_;
+ BlockingState blockingState_;
};
}
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 9749397..572b06f 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -33,6 +33,7 @@
#include <Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h>
#include <Swift/QtUI/QtUISettingConstants.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swiften/Base/Platform.h>
@@ -138,6 +139,10 @@ QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStr
connect(viewLogsAction, SIGNAL(triggered()), SLOT(handleViewLogsAction()));
actionsMenu->addAction(viewLogsAction);
#endif
+ openBlockingListEditor_ = new QAction(tr("Edit &Blocking List…"), this);
+ connect(openBlockingListEditor_, SIGNAL(triggered()), SLOT(handleEditBlockingList()));
+ actionsMenu->addAction(openBlockingListEditor_);
+ openBlockingListEditor_->setVisible(false);
addUserAction_ = new QAction(tr("&Add Contact…"), this);
connect(addUserAction_, SIGNAL(triggered(bool)), this, SLOT(handleAddUserActionTriggered(bool)));
actionsMenu->addAction(addUserAction_);
@@ -190,6 +195,10 @@ void QtMainWindow::handleShowCertificateInfo() {
onShowCertificateRequest();
}
+void QtMainWindow::handleEditBlockingList() {
+ uiEventStream_->send(boost::make_shared<RequestBlockListDialogUIEvent>());
+}
+
QtEventWindow* QtMainWindow::getEventWindow() {
return eventWindow_;
}
@@ -359,5 +368,9 @@ void QtMainWindow::setAvailableAdHocCommands(const std::vector<DiscoItems::Item>
}
}
+void QtMainWindow::setBlockingCommandAvailable(bool isAvailable) {
+ openBlockingListEditor_->setVisible(isAvailable);
+}
+
}
diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h
index 99bc675..3e6e1d3 100644
--- a/Swift/QtUI/QtMainWindow.h
+++ b/Swift/QtUI/QtMainWindow.h
@@ -53,6 +53,7 @@ namespace Swift {
QtChatListWindow* getChatListWindow();
void setRosterModel(Roster* roster);
void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands);
+ void setBlockingCommandAvailable(bool isAvailable);
private slots:
void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage);
void handleSettingChanged(const std::string& settingPath);
@@ -72,6 +73,7 @@ namespace Swift {
void handleTabChanged(int index);
void handleToggleRequestDeliveryReceipts(bool enabled);
void handleShowCertificateInfo();
+ void handleEditBlockingList();
private:
SettingsProvider* settings_;
@@ -85,6 +87,7 @@ namespace Swift {
QAction* showOfflineAction_;
QAction* compactRosterAction_;
QAction* showEmoticonsAction_;
+ QAction* openBlockingListEditor_;
QAction* toggleRequestDeliveryReceipts_;
QMenu* serverAdHocMenu_;
QtTabWidget* tabs_;
diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp
index 7ec25df..0c7fbc2 100644
--- a/Swift/QtUI/QtUIFactory.cpp
+++ b/Swift/QtUI/QtUIFactory.cpp
@@ -4,34 +4,35 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "QtUIFactory.h"
+#include <Swift/QtUI/QtUIFactory.h>
#include <QSplitter>
-#include "QtXMLConsoleWidget.h"
-#include "QtChatTabs.h"
-#include "QtMainWindow.h"
-#include "QtLoginWindow.h"
-#include "QtSystemTray.h"
-#include "QtSettingsProvider.h"
-#include "QtMainWindow.h"
-#include "QtChatWindow.h"
-#include "QtJoinMUCWindow.h"
-#include "QtChatWindowFactory.h"
-#include "QtSwiftUtil.h"
-#include "MUCSearch/QtMUCSearchWindow.h"
-#include "UserSearch/QtUserSearchWindow.h"
-#include "QtProfileWindow.h"
-#include "QtContactEditWindow.h"
-#include "QtAdHocCommandWindow.h"
-#include "QtFileTransferListWidget.h"
-#include <QtHighlightEditorWidget.h>
-#include "Whiteboard/QtWhiteboardWindow.h"
+#include <Swift/QtUI/QtXMLConsoleWidget.h>
+#include <Swift/QtUI/QtChatTabs.h>
+#include <Swift/QtUI/QtMainWindow.h>
+#include <Swift/QtUI/QtLoginWindow.h>
+#include <Swift/QtUI/QtSystemTray.h>
+#include <Swift/QtUI/QtSettingsProvider.h>
+#include <Swift/QtUI/QtMainWindow.h>
+#include <Swift/QtUI/QtChatWindow.h>
+#include <Swift/QtUI/QtJoinMUCWindow.h>
+#include <Swift/QtUI/QtChatWindowFactory.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swift/QtUI/MUCSearch/QtMUCSearchWindow.h>
+#include <Swift/QtUI/UserSearch/QtUserSearchWindow.h>
+#include <Swift/QtUI/QtProfileWindow.h>
+#include <Swift/QtUI/QtContactEditWindow.h>
+#include <Swift/QtUI/QtAdHocCommandWindow.h>
+#include <Swift/QtUI/QtFileTransferListWidget.h>
+#include <Swift/QtUI/QtHighlightEditorWidget.h>
+#include <Swift/QtUI/Whiteboard/QtWhiteboardWindow.h>
#include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
#include <Swift/QtUI/QtUISettingConstants.h>
-#include <QtHistoryWindow.h>
+#include <Swift/QtUI/QtHistoryWindow.h>
#include <Swiften/Whiteboard/WhiteboardSession.h>
-#include <QtSingleWindow.h>
+#include <Swift/QtUI/QtSingleWindow.h>
+#include <Swift/QtUI/QtBlockListEditorWindow.h>
namespace Swift {
@@ -167,6 +168,10 @@ HighlightEditorWidget* QtUIFactory::createHighlightEditorWidget() {
return new QtHighlightEditorWidget();
}
+BlockListEditorWidget *QtUIFactory::createBlockListEditorWidget() {
+ return new QtBlockListEditorWindow();
+}
+
void QtUIFactory::createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) {
new QtAdHocCommandWindow(command);
}
diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h
index a1baa82..662c78e 100644
--- a/Swift/QtUI/QtUIFactory.h
+++ b/Swift/QtUI/QtUIFactory.h
@@ -49,6 +49,7 @@ namespace Swift {
virtual FileTransferListWidget* createFileTransferListWidget();
virtual WhiteboardWindow* createWhiteboardWindow(boost::shared_ptr<WhiteboardSession> whiteboardSession);
virtual HighlightEditorWidget* createHighlightEditorWidget();
+ virtual BlockListEditorWidget* createBlockListEditorWidget();
virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command);
private slots:
diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp
index b783ff6..6bf3989 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.cpp
+++ b/Swift/QtUI/Roster/QtRosterWidget.cpp
@@ -4,24 +4,25 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Roster/QtRosterWidget.h"
+#include <Swift/QtUI/Roster/QtRosterWidget.h>
#include <QContextMenuEvent>
#include <QMenu>
#include <QInputDialog>
#include <QFileDialog>
-#include "Swift/Controllers/UIEvents/RequestContactEditorUIEvent.h"
-#include "Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h"
-#include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h"
-#include "Swift/Controllers/UIEvents/SendFileUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h"
-#include "Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h"
-#include "QtContactEditWindow.h"
-#include "Swift/Controllers/Roster/ContactRosterItem.h"
-#include "Swift/Controllers/Roster/GroupRosterItem.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "QtSwiftUtil.h"
+#include <Swift/Controllers/UIEvents/RequestContactEditorUIEvent.h>
+#include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h>
+#include <Swift/Controllers/UIEvents/RenameGroupUIEvent.h>
+#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h>
+#include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
+#include <Swift/QtUI/QtContactEditWindow.h>
+#include <Swift/Controllers/Roster/ContactRosterItem.h>
+#include <Swift/Controllers/Roster/GroupRosterItem.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
@@ -59,6 +60,17 @@ void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) {
QAction* editContact = contextMenu.addAction(tr("Edit…"));
QAction* removeContact = contextMenu.addAction(tr("Remove"));
QAction* showProfileForContact = contextMenu.addAction(tr("Show Profile"));
+
+ QAction* unblockContact = NULL;
+ if (contact->blockState() == ContactRosterItem::IsBlocked) {
+ unblockContact = contextMenu.addAction(tr("Unblock"));
+ }
+
+ QAction* blockContact = NULL;
+ if (contact->blockState() == ContactRosterItem::IsUnblocked) {
+ blockContact = contextMenu.addAction(tr("Block"));
+ }
+
#ifdef SWIFT_EXPERIMENTAL_FT
QAction* sendFile = NULL;
if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) {
@@ -71,6 +83,7 @@ void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) {
startWhiteboardChat = contextMenu.addAction(tr("Start Whiteboard Chat"));
}
#endif
+
QAction* result = contextMenu.exec(event->globalPos());
if (result == editContact) {
eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID()));
@@ -83,6 +96,12 @@ void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) {
else if (result == showProfileForContact) {
eventStream_->send(boost::make_shared<ShowProfileForRosterItemUIEvent>(contact->getJID()));
}
+ else if (unblockContact && result == unblockContact) {
+ eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Unblocked, contact->getJID()));
+ }
+ else if (blockContact && result == blockContact) {
+ eventStream_->send(boost::make_shared<RequestChangeBlockStateUIEvent>(RequestChangeBlockStateUIEvent::Blocked, contact->getJID()));
+ }
#ifdef SWIFT_EXPERIMENTAL_FT
else if (sendFile && result == sendFile) {
QString fileName = QFileDialog::getOpenFileName(this, tr("Send File"), "", tr("All Files (*);;"));
diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp
index 2909c05..8f39f35 100644
--- a/Swift/QtUI/Roster/RosterModel.cpp
+++ b/Swift/QtUI/Roster/RosterModel.cpp
@@ -162,6 +162,10 @@ QString RosterModel::getStatusText(RosterItem* item) const {
QIcon RosterModel::getPresenceIcon(RosterItem* item) const {
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (!contact) return QIcon();
+ if (contact->blockState() == ContactRosterItem::IsBlocked) {
+ return QIcon(":/icons/stop.png");
+ }
+
QString iconString;
switch (contact->getStatusShow()) {
case StatusShow::Online: iconString = "online";break;
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 0d69d6b..0bcab5e 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -94,6 +94,7 @@ sources = [
"QtLoginWindow.cpp",
"QtMainWindow.cpp",
"QtProfileWindow.cpp",
+ "QtBlockListEditorWindow.cpp",
"QtNameWidget.cpp",
"QtSettingsProvider.cpp",
"QtStatusWidget.cpp",
@@ -273,6 +274,7 @@ myenv.Uic4("QtHistoryWindow.ui")
myenv.Uic4("QtConnectionSettings.ui")
myenv.Uic4("QtHighlightRuleWidget.ui")
myenv.Uic4("QtHighlightEditorWidget.ui")
+myenv.Uic4("QtBlockListEditorWindow.ui")
myenv.Uic4("QtSpellCheckerWindow.ui")
myenv.Qrc("DefaultTheme.qrc")
myenv.Qrc("Swift.qrc")
diff --git a/Swift/QtUI/Swift.qrc b/Swift/QtUI/Swift.qrc
index f1b3140..eeef80d 100644
--- a/Swift/QtUI/Swift.qrc
+++ b/Swift/QtUI/Swift.qrc
@@ -41,5 +41,6 @@
<file alias="icons/star-checked.png">../resources/icons/star-checked2.png</file>
<file alias="icons/star-unchecked.png">../resources/icons/star-unchecked2.png</file>
<file alias="icons/zzz.png">../resources/icons/zzz.png</file>
+ <file alias="icons/stop.png">../resources/icons/stop.png</file>
</qresource>
</RCC>
diff --git a/Swift/resources/icons/stop.png b/Swift/resources/icons/stop.png
new file mode 100644
index 0000000..1574342
--- /dev/null
+++ b/Swift/resources/icons/stop.png
Binary files differ
diff --git a/Swift/resources/icons/stop.svg b/Swift/resources/icons/stop.svg
new file mode 100644
index 0000000..b6171ef
--- /dev/null
+++ b/Swift/resources/icons/stop.svg
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="601"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ height="601"
+ sodipodi:docname="Blank_stop_sign_octagon.svg"
+ inkscape:export-filename="/Users/tobias/Downloads/Blank_stop_sign_octagon.png"
+ inkscape:export-xdpi="3.29"
+ inkscape:export-ydpi="3.29">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1440"
+ inkscape:window-height="852"
+ id="namedview8"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:zoom="0.63429569"
+ inkscape:cx="102.64275"
+ inkscape:cy="390.12926"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" />
+ <path
+ d="m 0.5,424.5 v -248 l 176,-176 h 248 l 176,176 v 248 l -176,176 h -248 z"
+ id="path4"
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;stroke:#000000" />
+ <path
+ d="M 17,417 V 182 L 183,16 H 418 L 584,182 V 417 L 418,583 H 183 z"
+ id="path6"
+ inkscape:connector-curvature="0"
+ style="fill:#ff0000" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect2991"
+ width="368.91312"
+ height="96.169655"
+ x="116.04344"
+ y="249.42896" />
+</svg>
diff --git a/Swift/resources/icons/stop.txt b/Swift/resources/icons/stop.txt
new file mode 100644
index 0000000..9d4a1b1
--- /dev/null
+++ b/Swift/resources/icons/stop.txt
@@ -0,0 +1,2 @@
+License: Public Domain
+Source: https://commons.wikimedia.org/wiki/File:Blank_stop_sign_octagon.svg
diff --git a/Swiften/Client/BlockList.cpp b/Swiften/Client/BlockList.cpp
index 0b2fc12..3ee7864 100644
--- a/Swiften/Client/BlockList.cpp
+++ b/Swiften/Client/BlockList.cpp
@@ -6,8 +6,17 @@
#include <Swiften/Client/BlockList.h>
+#include <algorithm>
+
using namespace Swift;
BlockList::~BlockList() {
}
+
+bool BlockList::isBlocked(const JID& jid) const {
+ const std::vector<JID>& items = getItems();
+ return (std::find(items.begin(), items.end(), jid.toBare()) != items.end()) ||
+ (std::find(items.begin(), items.end(), JID(jid.getDomain())) != items.end()) ||
+ (std::find(items.begin(), items.end(), jid) != items.end());
+}
diff --git a/Swiften/Client/BlockList.h b/Swiften/Client/BlockList.h
index d8cff60..99c83c1 100644
--- a/Swiften/Client/BlockList.h
+++ b/Swiften/Client/BlockList.h
@@ -6,7 +6,7 @@
#pragma once
-#include <set>
+#include <vector>
#include <Swiften/JID/JID.h>
#include <Swiften/Base/boost_bsignals.h>
@@ -15,6 +15,7 @@ namespace Swift {
class BlockList {
public:
enum State {
+ Init,
Requesting,
Available,
Error
@@ -23,7 +24,9 @@ namespace Swift {
virtual State getState() const = 0;
- virtual const std::set<JID>& getItems() const = 0;
+ virtual const std::vector<JID>& getItems() const = 0;
+
+ bool isBlocked(const JID& jid) const;
public:
boost::signal<void ()> onStateChanged;
diff --git a/Swiften/Client/BlockListImpl.cpp b/Swiften/Client/BlockListImpl.cpp
index dfaaaf1..5950233 100644
--- a/Swiften/Client/BlockListImpl.cpp
+++ b/Swiften/Client/BlockListImpl.cpp
@@ -8,30 +8,47 @@
#include <Swiften/Base/foreach.h>
+#include <algorithm>
+
using namespace Swift;
-BlockListImpl::BlockListImpl() {
+BlockListImpl::BlockListImpl() : state(Init) {
}
void BlockListImpl::setItems(const std::vector<JID>& items) {
- this->items = std::set<JID>(items.begin(), items.end());
+ foreach (const JID& jid, this->items) {
+ if (std::find(items.begin(), items.end(), jid) != items.end()) {
+ onItemRemoved(jid);
+ }
+ }
+
+ foreach (const JID& jid, items) {
+ if (std::find(this->items.begin(), this->items.end(), jid) != this->items.end()) {
+ onItemAdded(jid);
+ }
+ }
+ this->items = items;
}
void BlockListImpl::addItem(const JID& item) {
- if (items.insert(item).second) {
+ if (std::find(items.begin(), items.end(), item) == items.end()) {
+ items.push_back(item);
onItemAdded(item);
}
}
void BlockListImpl::removeItem(const JID& item) {
- if (items.erase(item)) {
+ size_t oldSize = items.size();
+ items.erase(std::remove(items.begin(), items.end(), item), items.end());
+ if (items.size() != oldSize) {
onItemRemoved(item);
}
}
void BlockListImpl::setState(State state) {
if (this->state != state) {
+ this->state = state;
onStateChanged();
}
}
@@ -43,14 +60,13 @@ void BlockListImpl::addItems(const std::vector<JID>& items) {
}
void BlockListImpl::removeItems(const std::vector<JID>& items) {
- foreach (const JID& item, items) {
+ std::vector<JID> itemsToRemove = items;
+ foreach (const JID& item, itemsToRemove) {
removeItem(item);
}
}
void BlockListImpl::removeAllItems() {
- foreach (const JID& item, items) {
- removeItem(item);
- }
+ removeItems(items);
}
diff --git a/Swiften/Client/BlockListImpl.h b/Swiften/Client/BlockListImpl.h
index ef08340..2a799ae 100644
--- a/Swiften/Client/BlockListImpl.h
+++ b/Swiften/Client/BlockListImpl.h
@@ -19,7 +19,7 @@ namespace Swift {
void setState(State state);
- virtual const std::set<JID>& getItems() const {
+ virtual const std::vector<JID>& getItems() const {
return items;
}
@@ -32,6 +32,6 @@ namespace Swift {
private:
State state;
- std::set<JID> items;
+ std::vector<JID> items;
};
}
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp
index 1a6c64b..00f0f44 100644
--- a/Swiften/Client/Client.cpp
+++ b/Swiften/Client/Client.cpp
@@ -30,6 +30,7 @@
#include <Swiften/Network/NetworkFactories.h>
#include <Swiften/FileTransfer/FileTransferManagerImpl.h>
#include <Swiften/Whiteboard/WhiteboardSessionManager.h>
+#include <Swiften/Client/ClientBlockListManager.h>
#ifndef SWIFT_EXPERIMENTAL_FT
#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
#endif
@@ -68,6 +69,7 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
blindCertificateTrustChecker = new BlindCertificateTrustChecker();
jingleSessionManager = new JingleSessionManager(getIQRouter());
+ blockListManager = new ClientBlockListManager(getIQRouter());
fileTransferManager = NULL;
whiteboardSessionManager = NULL;
diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h
index 126572a..f192539 100644
--- a/Swiften/Client/Client.h
+++ b/Swiften/Client/Client.h
@@ -37,6 +37,7 @@ namespace Swift {
class JingleSessionManager;
class FileTransferManager;
class WhiteboardSessionManager;
+ class ClientBlockListManager;
/**
* Provides the core functionality for writing XMPP client software.
@@ -135,6 +136,10 @@ namespace Swift {
ClientDiscoManager* getDiscoManager() const {
return discoManager;
}
+
+ ClientBlockListManager* getClientBlockListManager() const {
+ return blockListManager;
+ }
/**
* Returns a FileTransferManager for the client. This is only available after the onConnected
@@ -188,6 +193,7 @@ namespace Swift {
JingleSessionManager* jingleSessionManager;
FileTransferManager* fileTransferManager;
BlindCertificateTrustChecker* blindCertificateTrustChecker;
- WhiteboardSessionManager* whiteboardSessionManager;
+ WhiteboardSessionManager* whiteboardSessionManager;
+ ClientBlockListManager* blockListManager;
};
}
diff --git a/Swiften/Client/ClientBlockListManager.cpp b/Swiften/Client/ClientBlockListManager.cpp
index 7222cea..6646a5c 100644
--- a/Swiften/Client/ClientBlockListManager.cpp
+++ b/Swiften/Client/ClientBlockListManager.cpp
@@ -66,11 +66,14 @@ namespace {
}
ClientBlockListManager::ClientBlockListManager(IQRouter* iqRouter) : iqRouter(iqRouter) {
+
}
ClientBlockListManager::~ClientBlockListManager() {
- unblockResponder->stop();
- blockResponder->stop();
+ if (blockList && blockList->getState() == BlockList::Available) {
+ unblockResponder->stop();
+ blockResponder->stop();
+ }
if (getRequest) {
getRequest->onResponse.disconnect(boost::bind(&ClientBlockListManager::handleBlockListReceived, this, _1, _2));
}
@@ -88,13 +91,36 @@ boost::shared_ptr<BlockList> ClientBlockListManager::getBlockList() {
return blockList;
}
+GenericRequest<BlockPayload>::ref ClientBlockListManager::createBlockJIDRequest(const JID& jid) {
+ return createBlockJIDsRequest(std::vector<JID>(1, jid));
+}
+
+GenericRequest<BlockPayload>::ref ClientBlockListManager::createBlockJIDsRequest(const std::vector<JID>& jids) {
+ boost::shared_ptr<BlockPayload> payload = boost::make_shared<BlockPayload>(jids);
+ return boost::make_shared< GenericRequest<BlockPayload> >(IQ::Set, JID(), payload, iqRouter);
+}
+
+GenericRequest<UnblockPayload>::ref ClientBlockListManager::createUnblockJIDRequest(const JID& jid) {
+ return createUnblockJIDsRequest(std::vector<JID>(1, jid));
+}
+
+GenericRequest<UnblockPayload>::ref ClientBlockListManager::createUnblockJIDsRequest(const std::vector<JID>& jids) {
+ boost::shared_ptr<UnblockPayload> payload = boost::make_shared<UnblockPayload>(jids);
+ return boost::make_shared< GenericRequest<UnblockPayload> >(IQ::Set, JID(), payload, iqRouter);
+}
+
+GenericRequest<UnblockPayload>::ref ClientBlockListManager::createUnblockAllRequest() {
+ return createUnblockJIDsRequest(std::vector<JID>());
+}
+
+
void ClientBlockListManager::handleBlockListReceived(boost::shared_ptr<BlockListPayload> payload, ErrorPayload::ref error) {
if (error || !payload) {
blockList->setState(BlockList::Error);
}
else {
- blockList->setState(BlockList::Available);
blockList->setItems(payload->getItems());
+ blockList->setState(BlockList::Available);
blockResponder = boost::make_shared<BlockResponder>(blockList, iqRouter);
blockResponder->start();
unblockResponder = boost::make_shared<UnblockResponder>(blockList, iqRouter);
diff --git a/Swiften/Client/ClientBlockListManager.h b/Swiften/Client/ClientBlockListManager.h
index 21d35e3..e8d4ac6 100644
--- a/Swiften/Client/ClientBlockListManager.h
+++ b/Swiften/Client/ClientBlockListManager.h
@@ -12,6 +12,7 @@
#include <Swiften/Elements/BlockPayload.h>
#include <Swiften/Elements/BlockListPayload.h>
#include <Swiften/Elements/UnblockPayload.h>
+#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Queries/SetResponder.h>
#include <Swiften/Queries/GenericRequest.h>
#include <Swiften/Client/BlockList.h>
@@ -25,13 +26,18 @@ namespace Swift {
ClientBlockListManager(IQRouter *iqRouter);
~ClientBlockListManager();
- bool isSupported() const;
-
/**
* Returns the blocklist.
*/
boost::shared_ptr<BlockList> getBlockList();
+ GenericRequest<BlockPayload>::ref createBlockJIDRequest(const JID& jid);
+ GenericRequest<BlockPayload>::ref createBlockJIDsRequest(const std::vector<JID>& jids);
+
+ GenericRequest<UnblockPayload>::ref createUnblockJIDRequest(const JID& jid);
+ GenericRequest<UnblockPayload>::ref createUnblockJIDsRequest(const std::vector<JID>& jids);
+ GenericRequest<UnblockPayload>::ref createUnblockAllRequest();
+
private:
void handleBlockListReceived(boost::shared_ptr<BlockListPayload> payload, ErrorPayload::ref);
diff --git a/Swiften/Client/UnitTest/ClientBlockListManagerTest.cpp b/Swiften/Client/UnitTest/ClientBlockListManagerTest.cpp
new file mode 100644
index 0000000..9010042
--- /dev/null
+++ b/Swiften/Client/UnitTest/ClientBlockListManagerTest.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <algorithm>
+
+#include <Swiften/Base/foreach.h>
+
+#include <Swiften/Client/StanzaChannel.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Queries/IQRouter.h>
+#include <Swiften/Elements/IQ.h>
+
+using namespace Swift;
+
+class ClientBlockListManagerTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(ClientBlockListManagerTest);
+ CPPUNIT_TEST(testFetchBlockList);
+ CPPUNIT_TEST(testBlockCommand);
+ CPPUNIT_TEST(testUnblockCommand);
+ CPPUNIT_TEST(testUnblockAllCommand);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ ownJID_ = JID("kev@wonderland.lit");
+ stanzaChannel_ = new DummyStanzaChannel();
+ iqRouter_ = new IQRouter(stanzaChannel_);
+ iqRouter_->setJID(ownJID_);
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ }
+
+ void testFetchBlockList() {
+ std::vector<JID> blockJids;
+ blockJids.push_back(JID("romeo@montague.net"));
+ blockJids.push_back(JID("iago@shakespeare.lit"));
+ helperInitialBlockListFetch(blockJids);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), clientBlockListManager_->getBlockList()->getItems().size());
+ }
+
+ void testBlockCommand() {
+ // start with an already fetched block list
+ helperInitialBlockListFetch(std::vector<JID>(1, JID("iago@shakespeare.lit")));
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), clientBlockListManager_->getBlockList()->getItems().size());
+ CPPUNIT_ASSERT_EQUAL(BlockList::Available, clientBlockListManager_->getBlockList()->getState());
+
+ GenericRequest<BlockPayload>::ref blockRequest = clientBlockListManager_->createBlockJIDRequest(JID("romeo@montague.net"));
+ blockRequest->send();
+ IQ::ref request = stanzaChannel_->getStanzaAtIndex<IQ>(2);
+ CPPUNIT_ASSERT(request.get() != NULL);
+ boost::shared_ptr<BlockPayload> blockPayload = request->getPayload<BlockPayload>();
+ CPPUNIT_ASSERT(blockPayload.get() != NULL);
+ CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), blockPayload->getItems().at(0));
+
+ IQ::ref blockRequestResponse = IQ::createResult(request->getFrom(), JID(), request->getID());
+ stanzaChannel_->sendIQ(blockRequestResponse);
+ stanzaChannel_->onIQReceived(blockRequestResponse);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), clientBlockListManager_->getBlockList()->getItems().size());
+
+ // send block push
+ boost::shared_ptr<BlockPayload> pushPayload = boost::make_shared<BlockPayload>();
+ pushPayload->addItem(JID("romeo@montague.net"));
+ IQ::ref blockPush = IQ::createRequest(IQ::Set, ownJID_, "push1", pushPayload);
+ stanzaChannel_->sendIQ(blockPush);
+ stanzaChannel_->onIQReceived(blockPush);
+
+ std::vector<JID> blockedJIDs = clientBlockListManager_->getBlockList()->getItems();
+ CPPUNIT_ASSERT(blockedJIDs.end() != std::find(blockedJIDs.begin(), blockedJIDs.end(), JID("romeo@montague.net")));
+ }
+
+ void testUnblockCommand() {
+ // start with an already fetched block list
+ std::vector<JID> initialBlockList = std::vector<JID>(1, JID("iago@shakespeare.lit"));
+ initialBlockList.push_back(JID("romeo@montague.net"));
+ helperInitialBlockListFetch(initialBlockList);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), clientBlockListManager_->getBlockList()->getItems().size());
+ CPPUNIT_ASSERT_EQUAL(BlockList::Available, clientBlockListManager_->getBlockList()->getState());
+
+ GenericRequest<UnblockPayload>::ref unblockRequest = clientBlockListManager_->createUnblockJIDRequest(JID("romeo@montague.net"));
+ unblockRequest->send();
+ IQ::ref request = stanzaChannel_->getStanzaAtIndex<IQ>(2);
+ CPPUNIT_ASSERT(request.get() != NULL);
+ boost::shared_ptr<UnblockPayload> unblockPayload = request->getPayload<UnblockPayload>();
+ CPPUNIT_ASSERT(unblockPayload.get() != NULL);
+ CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), unblockPayload->getItems().at(0));
+
+ IQ::ref unblockRequestResponse = IQ::createResult(request->getFrom(), JID(), request->getID());
+ stanzaChannel_->sendIQ(unblockRequestResponse);
+ stanzaChannel_->onIQReceived(unblockRequestResponse);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), clientBlockListManager_->getBlockList()->getItems().size());
+
+ // send block push
+ boost::shared_ptr<UnblockPayload> pushPayload = boost::make_shared<UnblockPayload>();
+ pushPayload->addItem(JID("romeo@montague.net"));
+ IQ::ref unblockPush = IQ::createRequest(IQ::Set, ownJID_, "push1", pushPayload);
+ stanzaChannel_->sendIQ(unblockPush);
+ stanzaChannel_->onIQReceived(unblockPush);
+
+ std::vector<JID> blockedJIDs = clientBlockListManager_->getBlockList()->getItems();
+ CPPUNIT_ASSERT(blockedJIDs.end() == std::find(blockedJIDs.begin(), blockedJIDs.end(), JID("romeo@montague.net")));
+ }
+
+ void testUnblockAllCommand() {
+ // start with an already fetched block list
+ std::vector<JID> initialBlockList = std::vector<JID>(1, JID("iago@shakespeare.lit"));
+ initialBlockList.push_back(JID("romeo@montague.net"));
+ initialBlockList.push_back(JID("benvolio@montague.net"));
+ helperInitialBlockListFetch(initialBlockList);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), clientBlockListManager_->getBlockList()->getItems().size());
+ CPPUNIT_ASSERT_EQUAL(BlockList::Available, clientBlockListManager_->getBlockList()->getState());
+
+ GenericRequest<UnblockPayload>::ref unblockRequest = clientBlockListManager_->createUnblockAllRequest();
+ unblockRequest->send();
+ IQ::ref request = stanzaChannel_->getStanzaAtIndex<IQ>(2);
+ CPPUNIT_ASSERT(request.get() != NULL);
+ boost::shared_ptr<UnblockPayload> unblockPayload = request->getPayload<UnblockPayload>();
+ CPPUNIT_ASSERT(unblockPayload.get() != NULL);
+ CPPUNIT_ASSERT_EQUAL(true, unblockPayload->getItems().empty());
+
+ IQ::ref unblockRequestResponse = IQ::createResult(request->getFrom(), JID(), request->getID());
+ stanzaChannel_->sendIQ(unblockRequestResponse);
+ stanzaChannel_->onIQReceived(unblockRequestResponse);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), clientBlockListManager_->getBlockList()->getItems().size());
+
+ // send block push
+ boost::shared_ptr<UnblockPayload> pushPayload = boost::make_shared<UnblockPayload>();
+ IQ::ref unblockPush = IQ::createRequest(IQ::Set, ownJID_, "push1", pushPayload);
+ stanzaChannel_->sendIQ(unblockPush);
+ stanzaChannel_->onIQReceived(unblockPush);
+
+ CPPUNIT_ASSERT_EQUAL(true, clientBlockListManager_->getBlockList()->getItems().empty());
+ }
+
+ void tearDown() {
+ delete clientBlockListManager_;
+ delete iqRouter_;
+ delete stanzaChannel_;
+ }
+
+ private:
+ void helperInitialBlockListFetch(const std::vector<JID>& blockedJids) {
+ boost::shared_ptr<BlockList> blockList = clientBlockListManager_->getBlockList();
+ CPPUNIT_ASSERT(blockList);
+
+ // check for IQ request
+ IQ::ref request = stanzaChannel_->getStanzaAtIndex<IQ>(0);
+ CPPUNIT_ASSERT(request.get() != NULL);
+ boost::shared_ptr<BlockListPayload> requestPayload = request->getPayload<BlockListPayload>();
+ CPPUNIT_ASSERT(requestPayload.get() != NULL);
+
+ CPPUNIT_ASSERT_EQUAL(BlockList::Requesting, blockList->getState());
+ CPPUNIT_ASSERT_EQUAL(BlockList::Requesting, clientBlockListManager_->getBlockList()->getState());
+
+ // build IQ response
+ boost::shared_ptr<BlockListPayload> responsePayload = boost::make_shared<BlockListPayload>();
+ foreach(const JID& jid, blockedJids) {
+ responsePayload->addItem(jid);
+ }
+
+ IQ::ref response = IQ::createResult(ownJID_, JID(), request->getID(), responsePayload);
+ stanzaChannel_->sendIQ(response);
+ stanzaChannel_->onIQReceived(response);
+
+ CPPUNIT_ASSERT_EQUAL(BlockList::Available, clientBlockListManager_->getBlockList()->getState());
+ CPPUNIT_ASSERT(responsePayload->getItems() == clientBlockListManager_->getBlockList()->getItems());
+ }
+
+
+ private:
+ JID ownJID_;
+ IQRouter* iqRouter_;
+ DummyStanzaChannel* stanzaChannel_;
+ ClientBlockListManager* clientBlockListManager_;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ClientBlockListManagerTest);
+
diff --git a/Swiften/Elements/BlockListPayload.h b/Swiften/Elements/BlockListPayload.h
index 25cb602..49df75f 100644
--- a/Swiften/Elements/BlockListPayload.h
+++ b/Swiften/Elements/BlockListPayload.h
@@ -14,7 +14,7 @@
namespace Swift {
class BlockListPayload : public Payload {
public:
- BlockListPayload() {
+ BlockListPayload(const std::vector<JID>& items = std::vector<JID>()) : items(items) {
}
void addItem(const JID& item) {
diff --git a/Swiften/Elements/BlockPayload.h b/Swiften/Elements/BlockPayload.h
index 6dd5170..49a0463 100644
--- a/Swiften/Elements/BlockPayload.h
+++ b/Swiften/Elements/BlockPayload.h
@@ -14,7 +14,7 @@
namespace Swift {
class BlockPayload : public Payload {
public:
- BlockPayload() {
+ BlockPayload(const std::vector<JID>& jids = std::vector<JID>()) : items(jids) {
}
void addItem(const JID& jid) {
diff --git a/Swiften/Elements/DiscoInfo.cpp b/Swiften/Elements/DiscoInfo.cpp
index 1683916..f353c42 100644
--- a/Swiften/Elements/DiscoInfo.cpp
+++ b/Swiften/Elements/DiscoInfo.cpp
@@ -23,6 +23,7 @@ const std::string DiscoInfo::JingleTransportsS5BFeature = std::string("urn:xmpp:
const std::string DiscoInfo::Bytestream = std::string("http://jabber.org/protocol/bytestreams");
const std::string DiscoInfo::MessageDeliveryReceiptsFeature = std::string("urn:xmpp:receipts");
const std::string DiscoInfo::WhiteboardFeature = std::string("http://swift.im/whiteboard");
+const std::string DiscoInfo::BlockingCommandFeature = std::string("urn:xmpp:blocking");
bool DiscoInfo::Identity::operator<(const Identity& other) const {
if (category_ == other.category_) {
diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h
index 3334ac8..3701096 100644
--- a/Swiften/Elements/DiscoInfo.h
+++ b/Swiften/Elements/DiscoInfo.h
@@ -34,6 +34,7 @@ namespace Swift {
static const std::string Bytestream;
static const std::string MessageDeliveryReceiptsFeature;
static const std::string WhiteboardFeature;
+ static const std::string BlockingCommandFeature;
class Identity {
public:
diff --git a/Swiften/Elements/UnblockPayload.h b/Swiften/Elements/UnblockPayload.h
index b6593ab..c5e7c80 100644
--- a/Swiften/Elements/UnblockPayload.h
+++ b/Swiften/Elements/UnblockPayload.h
@@ -14,7 +14,7 @@
namespace Swift {
class UnblockPayload : public Payload {
public:
- UnblockPayload() {
+ UnblockPayload(const std::vector<JID>& jids = std::vector<JID>()) : items(jids) {
}
void addItem(const JID& item) {
diff --git a/Swiften/Parser/PayloadParsers/BlockParser.h b/Swiften/Parser/PayloadParsers/BlockParser.h
index cd727ad..6ee47a2 100644
--- a/Swiften/Parser/PayloadParsers/BlockParser.h
+++ b/Swiften/Parser/PayloadParsers/BlockParser.h
@@ -7,13 +7,14 @@
#pragma once
#include <Swiften/Elements/Nickname.h>
+#include <Swiften/JID/JID.h>
#include <Swiften/Parser/GenericPayloadParser.h>
namespace Swift {
template<typename BLOCK_ELEMENT>
class BlockParser : public GenericPayloadParser<BLOCK_ELEMENT> {
public:
- BlockParser() : GenericPayloadParser<BLOCK_ELEMENT>() {
+ BlockParser() : GenericPayloadParser<BLOCK_ELEMENT>(), level(0) {
}
virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) {
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/BlockParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/BlockParserTest.cpp
new file mode 100644
index 0000000..ddd3a88
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/UnitTest/BlockParserTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swiften/Parser/PayloadParsers/BlockParser.h>
+#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h>
+
+#include <Swiften/Elements/BlockPayload.h>
+#include <Swiften/Elements/UnblockPayload.h>
+#include <Swiften/Elements/BlockListPayload.h>
+
+using namespace Swift;
+
+class BlockParserTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(BlockParserTest);
+ CPPUNIT_TEST(testExample4);
+ CPPUNIT_TEST(testExample6);
+ CPPUNIT_TEST(testExample10);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ BlockParserTest() {}
+
+ void testExample4() {
+ PayloadsParserTester parser;
+
+ CPPUNIT_ASSERT(parser.parse("<blocklist xmlns='urn:xmpp:blocking'>"
+ "<item jid='romeo@montague.net'/>"
+ "<item jid='iago@shakespeare.lit'/>"
+ "</blocklist>"));
+
+ BlockListPayload* payload = dynamic_cast<BlockListPayload*>(parser.getPayload().get());
+ CPPUNIT_ASSERT(payload);
+ CPPUNIT_ASSERT(2 == payload->getItems().size());
+ CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), payload->getItems()[0]);
+ CPPUNIT_ASSERT_EQUAL(JID("iago@shakespeare.lit"), payload->getItems()[1]);
+ }
+
+ void testExample6() {
+ PayloadsParserTester parser;
+
+ CPPUNIT_ASSERT(parser.parse("<block xmlns='urn:xmpp:blocking'>"
+ "<item jid='romeo@montague.net'/>"
+ "</block>"));
+
+ BlockPayload* payload = dynamic_cast<BlockPayload*>(parser.getPayload().get());
+ CPPUNIT_ASSERT(payload);
+ CPPUNIT_ASSERT(1 == payload->getItems().size());
+ CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), payload->getItems()[0]);
+ }
+
+ void testExample10() {
+ PayloadsParserTester parser;
+
+ CPPUNIT_ASSERT(parser.parse("<unblock xmlns='urn:xmpp:blocking'>"
+ "<item jid='romeo@montague.net'/>"
+ "</unblock>"));
+
+ UnblockPayload* payload = dynamic_cast<UnblockPayload*>(parser.getPayload().get());
+ CPPUNIT_ASSERT(payload);
+ CPPUNIT_ASSERT(1 == payload->getItems().size());
+ CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), payload->getItems()[0]);
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(BlockParserTest);
diff --git a/Swiften/Queries/GenericRequest.h b/Swiften/Queries/GenericRequest.h
index 68c86c5..b1b7f8a 100644
--- a/Swiften/Queries/GenericRequest.h
+++ b/Swiften/Queries/GenericRequest.h
@@ -22,6 +22,9 @@ namespace Swift {
template<typename PAYLOAD_TYPE>
class GenericRequest : public Request {
public:
+ typedef boost::shared_ptr<GenericRequest<PAYLOAD_TYPE> > ref;
+
+ public:
/**
* Create a request suitable for client use.
* @param type Iq type - Get or Set.
@@ -61,7 +64,7 @@ namespace Swift {
onResponse(boost::dynamic_pointer_cast<PAYLOAD_TYPE>(payload), error);
}
- protected:
+ public:
boost::shared_ptr<PAYLOAD_TYPE> getPayloadGeneric() const {
return boost::dynamic_pointer_cast<PAYLOAD_TYPE>(getPayload());
}
diff --git a/Swiften/SConscript b/Swiften/SConscript
index a62d344..b9fad17 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -318,6 +318,7 @@ if env["SCONS_STAGE"] == "build" :
# File("Chat/UnitTest/ChatStateTrackerTest.cpp"),
File("Client/UnitTest/ClientSessionTest.cpp"),
File("Client/UnitTest/NickResolverTest.cpp"),
+ File("Client/UnitTest/ClientBlockListManagerTest.cpp"),
File("Compress/UnitTest/ZLibCompressorTest.cpp"),
File("Compress/UnitTest/ZLibDecompressorTest.cpp"),
File("Component/UnitTest/ComponentHandshakeGeneratorTest.cpp"),
@@ -347,6 +348,7 @@ if env["SCONS_STAGE"] == "build" :
File("Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp"),
File("Network/UnitTest/BOSHConnectionTest.cpp"),
File("Network/UnitTest/BOSHConnectionPoolTest.cpp"),
+ File("Parser/PayloadParsers/UnitTest/BlockParserTest.cpp"),
File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"),
File("Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp"),
File("Parser/PayloadParsers/UnitTest/DiscoItemsParserTest.cpp"),
@@ -401,6 +403,7 @@ if env["SCONS_STAGE"] == "build" :
File("Roster/UnitTest/XMPPRosterControllerTest.cpp"),
File("Roster/UnitTest/XMPPRosterSignalHandler.cpp"),
File("Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp"),
+ File("Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp"),
File("Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp"),
File("Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp"),
File("Serializer/PayloadSerializers/UnitTest/DiscoInfoSerializerTest.cpp"),
diff --git a/Swiften/Serializer/PayloadSerializers/BlockSerializer.h b/Swiften/Serializer/PayloadSerializers/BlockSerializer.h
index 10ae8b0..fc628c2 100644
--- a/Swiften/Serializer/PayloadSerializers/BlockSerializer.h
+++ b/Swiften/Serializer/PayloadSerializers/BlockSerializer.h
@@ -8,6 +8,7 @@
#include <boost/smart_ptr/make_shared.hpp>
+#include <Swiften/JID/JID.h>
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Serializer/XML/XMLElement.h>
@@ -24,6 +25,7 @@ namespace Swift {
for (std::vector<JID>::const_iterator i = items.begin(); i != items.end(); ++i) {
boost::shared_ptr<XMLElement> item = boost::make_shared<XMLElement>("item");
item->setAttribute("jid", *i);
+ element.addNode(item);
}
return element.serialize();
}
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp
new file mode 100644
index 0000000..7772381
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swiften/Serializer/PayloadSerializers/BlockSerializer.h>
+#include <Swiften/Elements/BlockListPayload.h>
+#include <Swiften/Elements/BlockPayload.h>
+#include <Swiften/Elements/UnblockPayload.h>
+#include <Swiften/JID/JID.h>
+
+using namespace Swift;
+
+class BlockSerializerTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(BlockSerializerTest);
+ CPPUNIT_TEST(testExample4);
+ CPPUNIT_TEST(testExample6);
+ CPPUNIT_TEST(testExample10);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ BlockSerializerTest() {}
+
+ void testExample4() {
+ BlockSerializer<BlockListPayload> testling("blocklist");
+ boost::shared_ptr<BlockListPayload> blocklist = boost::make_shared<BlockListPayload>();
+ blocklist->addItem(JID("romeo@montague.net"));
+ blocklist->addItem(JID("iago@shakespeare.lit"));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("<blocklist xmlns=\"urn:xmpp:blocking\"><item jid=\"romeo@montague.net\"/><item jid=\"iago@shakespeare.lit\"/></blocklist>"), testling.serialize(blocklist));
+ }
+
+ void testExample6() {
+ BlockSerializer<BlockPayload> testling("block");
+ boost::shared_ptr<BlockPayload> block = boost::make_shared<BlockPayload>();
+ block->addItem(JID("romeo@montague.net"));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("<block xmlns=\"urn:xmpp:blocking\"><item jid=\"romeo@montague.net\"/></block>"), testling.serialize(block));
+ }
+
+ void testExample10() {
+ BlockSerializer<UnblockPayload> testling("unblock");
+ boost::shared_ptr<UnblockPayload> unblock = boost::make_shared<UnblockPayload>();
+ unblock->addItem(JID("romeo@montague.net"));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("<unblock xmlns=\"urn:xmpp:blocking\"><item jid=\"romeo@montague.net\"/></unblock>"), testling.serialize(unblock));
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(BlockSerializerTest);