From 703a1c28c3c87ac0fb365ff0683d7c64fcdd2210 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Tue, 20 Sep 2011 22:38:30 +0200
Subject: Added ClientBlockListManager.


diff --git a/Swiften/Client/BlockList.cpp b/Swiften/Client/BlockList.cpp
new file mode 100644
index 0000000..0b2fc12
--- /dev/null
+++ b/Swiften/Client/BlockList.cpp
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Client/BlockList.h>
+
+using namespace Swift;
+
+BlockList::~BlockList() {
+
+}
diff --git a/Swiften/Client/BlockList.h b/Swiften/Client/BlockList.h
new file mode 100644
index 0000000..39a211d
--- /dev/null
+++ b/Swiften/Client/BlockList.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <set>
+
+#include <Swiften/JID/JID.h>
+#include <Swiften/Base/boost_bsignals.h>
+
+namespace Swift {
+	class BlockList {
+		public:
+			enum State {
+				Requesting,
+				Available,
+				Error,
+			};
+			virtual ~BlockList();
+
+			virtual State getState() const = 0;
+
+			virtual const std::set<JID>& getItems() const = 0;
+
+		public:
+			boost::signal<void ()> onStateChanged;
+			boost::signal<void (const JID&)> onItemAdded;
+			boost::signal<void (const JID&)> onItemRemoved;
+	};
+}
diff --git a/Swiften/Client/BlockListImpl.cpp b/Swiften/Client/BlockListImpl.cpp
new file mode 100644
index 0000000..dfaaaf1
--- /dev/null
+++ b/Swiften/Client/BlockListImpl.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Client/BlockListImpl.h>
+
+#include <Swiften/Base/foreach.h>
+
+using namespace Swift;
+
+BlockListImpl::BlockListImpl() {
+
+}
+
+void BlockListImpl::setItems(const std::vector<JID>& items) {
+	this->items = std::set<JID>(items.begin(), items.end());
+}
+
+void BlockListImpl::addItem(const JID& item) {
+	if (items.insert(item).second) {
+		onItemAdded(item);
+	}
+}
+
+void BlockListImpl::removeItem(const JID& item) {
+	if (items.erase(item)) {
+		onItemRemoved(item);
+	}
+}
+
+void BlockListImpl::setState(State state) {
+	if (this->state != state) {
+		onStateChanged();
+	}
+}
+
+void BlockListImpl::addItems(const std::vector<JID>& items) {
+	foreach (const JID& item, items) {
+		addItem(item);
+	}
+}
+
+void BlockListImpl::removeItems(const std::vector<JID>& items) {
+	foreach (const JID& item, items) {
+		removeItem(item);
+	}
+}
+
+void BlockListImpl::removeAllItems() {
+	foreach (const JID& item, items) {
+		removeItem(item);
+	}
+}
+
diff --git a/Swiften/Client/BlockListImpl.h b/Swiften/Client/BlockListImpl.h
new file mode 100644
index 0000000..ef08340
--- /dev/null
+++ b/Swiften/Client/BlockListImpl.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Client/BlockList.h>
+
+namespace Swift {
+	class BlockListImpl : public BlockList {
+		public:
+			BlockListImpl();
+
+			virtual State getState() const {
+				return state;
+			}
+
+			void setState(State state);
+
+			virtual const std::set<JID>& getItems() const {
+				return items;
+			}
+
+			void setItems(const std::vector<JID>& items);
+			void addItem(const JID& item);
+			void removeItem(const JID& item);
+			void addItems(const std::vector<JID>& items);
+			void removeItems(const std::vector<JID>& items);
+			void removeAllItems();
+
+		private:
+			State state;
+			std::set<JID> items;
+	};
+}
diff --git a/Swiften/Client/ClientBlockListManager.cpp b/Swiften/Client/ClientBlockListManager.cpp
new file mode 100644
index 0000000..7222cea
--- /dev/null
+++ b/Swiften/Client/ClientBlockListManager.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Client/ClientBlockListManager.h>
+
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <cassert>
+
+#include <Swiften/Client/BlockListImpl.h>
+
+using namespace Swift;
+
+namespace {
+	class BlockResponder : public SetResponder<BlockPayload> {
+		public:
+			BlockResponder(boost::shared_ptr<BlockListImpl> blockList, IQRouter* iqRouter) : SetResponder<BlockPayload>(iqRouter), blockList(blockList) {
+			}
+
+			virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, boost::shared_ptr<BlockPayload> payload) {
+				if (getIQRouter()->isAccountJID(from)) {
+						if (payload) {
+							blockList->addItems(payload->getItems());
+						}
+						sendResponse(from, id, boost::shared_ptr<BlockPayload>());
+				}
+				else {
+					sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Cancel);
+				}
+				return true;
+			}
+
+		private:
+			boost::shared_ptr<BlockListImpl> blockList;
+	};
+
+	class UnblockResponder : public SetResponder<UnblockPayload> {
+		public:
+			UnblockResponder(boost::shared_ptr<BlockListImpl> blockList, IQRouter* iqRouter) : SetResponder<UnblockPayload>(iqRouter), blockList(blockList) {
+			}
+
+			virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, boost::shared_ptr<UnblockPayload> payload) {
+				if (getIQRouter()->isAccountJID(from)) {
+					if (payload) {
+						if (payload->getItems().empty()) {
+							blockList->removeAllItems();
+						}
+						else {
+							blockList->removeItems(payload->getItems());
+						}
+					}
+					sendResponse(from, id, boost::shared_ptr<UnblockPayload>());
+				}
+				else {
+					sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Cancel);
+				}
+				return true;
+			}
+
+		private:
+			boost::shared_ptr<BlockListImpl> blockList;
+	};
+}
+
+ClientBlockListManager::ClientBlockListManager(IQRouter* iqRouter) : iqRouter(iqRouter) {
+}
+
+ClientBlockListManager::~ClientBlockListManager() {
+	unblockResponder->stop();
+	blockResponder->stop();
+	if (getRequest) {
+		getRequest->onResponse.disconnect(boost::bind(&ClientBlockListManager::handleBlockListReceived, this, _1, _2));
+	}
+}
+
+boost::shared_ptr<BlockList> ClientBlockListManager::getBlockList() {
+	if (!blockList) {
+		blockList = boost::make_shared<BlockListImpl>();
+		blockList->setState(BlockList::Requesting);
+		assert(!getRequest);
+		getRequest = boost::make_shared< GenericRequest<BlockListPayload> >(IQ::Get, JID(), boost::make_shared<BlockListPayload>(), iqRouter);
+		getRequest->onResponse.connect(boost::bind(&ClientBlockListManager::handleBlockListReceived, this, _1, _2));
+		getRequest->send();
+	}
+	return blockList;
+}
+
+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());
+		blockResponder = boost::make_shared<BlockResponder>(blockList, iqRouter);
+		blockResponder->start();
+		unblockResponder = boost::make_shared<UnblockResponder>(blockList, iqRouter);
+		unblockResponder->start();
+	}
+}
+
diff --git a/Swiften/Client/ClientBlockListManager.h b/Swiften/Client/ClientBlockListManager.h
new file mode 100644
index 0000000..21d35e3
--- /dev/null
+++ b/Swiften/Client/ClientBlockListManager.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/Elements/BlockPayload.h>
+#include <Swiften/Elements/BlockListPayload.h>
+#include <Swiften/Elements/UnblockPayload.h>
+#include <Swiften/Queries/SetResponder.h>
+#include <Swiften/Queries/GenericRequest.h>
+#include <Swiften/Client/BlockList.h>
+#include <Swiften/Client/BlockListImpl.h>
+
+namespace Swift {
+	class IQRouter;
+
+	class ClientBlockListManager {
+		public:
+			ClientBlockListManager(IQRouter *iqRouter);
+			~ClientBlockListManager();
+
+			bool isSupported() const;
+
+			/**
+			 * Returns the blocklist.
+			 */
+			boost::shared_ptr<BlockList> getBlockList();
+
+		private:
+			void handleBlockListReceived(boost::shared_ptr<BlockListPayload> payload, ErrorPayload::ref);
+
+		private:
+			IQRouter* iqRouter;
+			boost::shared_ptr<GenericRequest<BlockListPayload> > getRequest;
+			boost::shared_ptr<SetResponder<BlockPayload> > blockResponder;
+			boost::shared_ptr<SetResponder<UnblockPayload> > unblockResponder;
+			boost::shared_ptr<BlockListImpl> blockList;
+	};
+}
+
diff --git a/Swiften/Queries/IQRouter.h b/Swiften/Queries/IQRouter.h
index 167cb8f..8dba334 100644
--- a/Swiften/Queries/IQRouter.h
+++ b/Swiften/Queries/IQRouter.h
@@ -63,6 +63,16 @@ namespace Swift {
 			
 			bool isAvailable();
 
+			/**
+			 * Checks whether the given jid is the account JID (i.e. it is either
+			 * the bare JID, or it is the empty JID).
+			 * Can be used to check whether a stanza is sent by the server on behalf
+			 * of the user's account.
+			 */
+			bool isAccountJID(const JID& jid) {
+				return jid.isValid() ? jid_.toBare().equals(jid, JID::WithResource) : true;
+			}
+
 		private:
 			void handleIQ(boost::shared_ptr<IQ> iq);
 			void processPendingRemoves();
diff --git a/Swiften/Queries/Request.cpp b/Swiften/Queries/Request.cpp
index 0126d62..382e44c 100644
--- a/Swiften/Queries/Request.cpp
+++ b/Swiften/Queries/Request.cpp
@@ -67,16 +67,13 @@ bool Request::handleIQ(boost::shared_ptr<IQ> iq) {
 }
 
 bool Request::isCorrectSender(const JID& jid) {
-	if (isAccountJID(receiver_)) {
-		return isAccountJID(jid);
+	if (router_->isAccountJID(receiver_)) {
+		return router_->isAccountJID(jid);
 	}
 	else {
 		return jid.equals(receiver_, JID::WithResource);
 	}
 }
 
-bool Request::isAccountJID(const JID& jid) {
-	return jid.isValid() ? router_->getJID().toBare().equals(jid, JID::WithResource) : true;
-}
 
 }
diff --git a/Swiften/Queries/Request.h b/Swiften/Queries/Request.h
index a7139cf..677a758 100644
--- a/Swiften/Queries/Request.h
+++ b/Swiften/Queries/Request.h
@@ -60,7 +60,6 @@ namespace Swift {
 		private:
 			bool handleIQ(boost::shared_ptr<IQ>);
 			bool isCorrectSender(const JID& jid);
-			bool isAccountJID(const JID& jid);
 
 		private:
 			IQRouter* router_;
diff --git a/Swiften/Queries/Responder.h b/Swiften/Queries/Responder.h
index a9aab17..2ba9c24 100644
--- a/Swiften/Queries/Responder.h
+++ b/Swiften/Queries/Responder.h
@@ -94,6 +94,10 @@ namespace Swift {
 				router_->sendIQ(IQ::createError(to, from, id, condition, type));
 			}
 
+			IQRouter* getIQRouter() const {
+				return router_;
+			}
+
 		private:
 			virtual bool handleIQ(boost::shared_ptr<IQ> iq) {
 				if (iq->getType() == IQ::Set || iq->getType() == IQ::Get) {
diff --git a/Swiften/SConscript b/Swiften/SConscript
index f55485a..0144ddb 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -79,6 +79,9 @@ if env["SCONS_STAGE"] == "build" :
 			"Client/Client.cpp",
 			"Client/ClientXMLTracer.cpp",
 			"Client/ClientSession.cpp",
+			"Client/BlockList.cpp",
+			"Client/BlockListImpl.cpp",
+			"Client/ClientBlockListManager.cpp",
 			"Client/MemoryStorages.cpp",
 			"Client/NickResolver.cpp",
 			"Client/NickManager.cpp",
-- 
cgit v0.10.2-6-g49f6