From e2f5588d089e4d2148762ea092e032976254a467 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Wed, 10 Jun 2009 19:23:57 +0200
Subject: Moved Swiften/Controllers to Swift/Controllers.


diff --git a/Makefile b/Makefile
index d93ac2b..0cddb30 100644
--- a/Makefile
+++ b/Makefile
@@ -43,7 +43,8 @@ include 3rdParty/ZLib/Makefile.inc
 include 3rdParty/Expat/Makefile.inc
 include 3rdParty/SQLite/Makefile.inc
 include Swiften/Makefile.inc
-include Swift/QtUI/Makefile.inc
+include Swift/Makefile.inc
+include Swiften/QA/Makefile.inc
 
 ################################################################################
 # Main targets
diff --git a/Swift/Controllers/ChatController.cpp b/Swift/Controllers/ChatController.cpp
new file mode 100644
index 0000000..8c0b8bb
--- /dev/null
+++ b/Swift/Controllers/ChatController.cpp
@@ -0,0 +1,38 @@
+#include "Swift/Controllers/ChatController.h"
+
+#include "Swift/Controllers/ChatWindow.h"
+#include "Swift/Controllers/ChatWindowFactory.h"
+#include "Swift/Controllers/NickResolver.h"
+
+namespace Swift {
+	
+/**
+ * The controller does not gain ownership of the stanzaChannel, nor the factory.
+ */
+ChatController::ChatController(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle)
+ : ChatControllerBase(stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle) {
+	nickResolver_ = nickResolver;
+}
+
+bool ChatController::isIncomingMessageFromMe(boost::shared_ptr<Message>) {
+	return false;
+}
+
+void ChatController::preHandleIncomingMessage(boost::shared_ptr<Message> message) {
+	JID from = message->getFrom();
+	if (!from.equals(toJID_, JID::WithResource)) {
+		if (toJID_.equals(from, JID::WithoutResource)  && toJID_.isBare()){
+			toJID_ = from;
+		}
+	}
+}
+
+void ChatController::postSendMessage(const String& body) {
+	chatWindow_->addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>());
+}
+
+String ChatController::senderDisplayNameFromMessage(JID from) {
+	return nickResolver_->jidToNick(from);
+}
+
+}
diff --git a/Swift/Controllers/ChatController.h b/Swift/Controllers/ChatController.h
new file mode 100644
index 0000000..98e66bc
--- /dev/null
+++ b/Swift/Controllers/ChatController.h
@@ -0,0 +1,24 @@
+#ifndef SWIFTEN_ChatController_H
+#define SWIFTEN_ChatController_H
+
+#include "Swift/Controllers/ChatControllerBase.h"
+
+namespace Swift {
+	class NickResolver;
+	class ChatController : public ChatControllerBase {
+		public:
+			ChatController(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle);
+			~ChatController() {};
+			//boost::signal<void (const JID&, const JID&)> onJIDChanged;
+		protected:
+			bool isIncomingMessageFromMe(boost::shared_ptr<Message> message);
+			void postSendMessage(const String &body);
+			void preHandleIncomingMessage(boost::shared_ptr<Message> message);
+			String senderDisplayNameFromMessage(JID from);
+		private:
+			NickResolver* nickResolver_;
+			JID contact_;
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/ChatControllerBase.cpp b/Swift/Controllers/ChatControllerBase.cpp
new file mode 100644
index 0000000..3b3ddb7
--- /dev/null
+++ b/Swift/Controllers/ChatControllerBase.cpp
@@ -0,0 +1,171 @@
+#include "Swift/Controllers/ChatControllerBase.h"
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Client/StanzaChannel.h"
+#include "Swiften/Base/foreach.h"
+#include "Swift/Controllers/ChatWindow.h"
+#include "Swift/Controllers/ChatWindowFactory.h"
+#include "Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h"
+
+namespace Swift {
+
+ChatControllerBase::ChatControllerBase(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle) : stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle) {
+	chatWindow_ = chatWindowFactory_->createChatWindow(toJID);
+	chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
+	chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1));
+	presenceOracle_->onPresenceChange.connect(boost::bind(&ChatControllerBase::handlePresenceChange, this, _1, _2));
+}
+
+ChatControllerBase::~ChatControllerBase() {
+	delete chatWindow_;
+}
+	
+void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info) {
+	if (info->hasFeature(DiscoInfo::SecurityLabels)) {
+		chatWindow_->setSecurityLabelsEnabled(true);
+		chatWindow_->setSecurityLabelsError();
+		GetSecurityLabelsCatalogRequest* request = new GetSecurityLabelsCatalogRequest(JID(toJID_.toBare()), iqRouter_, Request::AutoDeleteAfterResponse);
+		request->onResponse.connect(boost::bind(&ChatControllerBase::handleSecurityLabelsCatalogResponse, this, _1, _2));
+		request->send();
+		labelsEnabled_ = true;
+	} else {
+		chatWindow_->setSecurityLabelsEnabled(false);
+		labelsEnabled_ = false;
+	}
+}
+
+String ChatControllerBase::getStatusChangeString(boost::shared_ptr<Presence> presence) {
+	String nick = senderDisplayNameFromMessage(presence->getFrom());
+	if (presence->getType() == Presence::Unavailable) {
+		return nick + " has gone offline.";
+	} else if (presence->getType() == Presence::Available) {
+		StatusShow::Type show = presence->getShow();
+		if (show == StatusShow::Online || show == StatusShow::FFC) {
+			return nick + " has become available.";
+		} else if (show == StatusShow::Away || show == StatusShow::XA) {
+			return nick + " has gone away.";
+		} else if (show == StatusShow::DND) {
+			return nick + " is now busy.";
+		} 
+	}
+
+	return "";
+}
+
+void ChatControllerBase::handlePresenceChange(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> previousPresence) {
+	if (!(toJID_.isBare() && newPresence->getFrom().equals(toJID_, JID::WithoutResource)) && newPresence->getFrom() != toJID_) {
+		return;
+	}
+	String newStatusChangeString = getStatusChangeString(newPresence);
+	if (previousPresence.get() == NULL || newStatusChangeString != getStatusChangeString(previousPresence)) {
+		chatWindow_->addSystemMessage(newStatusChangeString);
+	}
+}
+
+void ChatControllerBase::handleAllMessagesRead() {
+	foreach (boost::shared_ptr<MessageEvent> messageEvent, unreadMessages_) {
+		messageEvent->read();
+	}
+	unreadMessages_.clear();
+	chatWindow_->setUnreadMessageCount(0);
+}
+
+void ChatControllerBase::handleSendMessageRequest(const String &body) {
+	if (body.isEmpty()) {
+		return;
+	}
+	boost::shared_ptr<Message> message(new Message());
+	message->setTo(toJID_);
+	message->setType(Swift::Message::Chat);
+	message->setBody(body);
+	boost::optional<SecurityLabel> label;
+	if (labelsEnabled_) {
+		message->addPayload(boost::shared_ptr<SecurityLabel>(new SecurityLabel(chatWindow_->getSelectedSecurityLabel())));
+		label = boost::optional<SecurityLabel>(chatWindow_->getSelectedSecurityLabel());
+	}
+	preSendMessageRequest(message);
+	stanzaChannel_->sendMessage(message);
+	postSendMessage(message->getBody());
+}
+
+void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog> catalog, const boost::optional<Error>& error) {
+	if (!error) {
+		if (catalog->getLabels().size() == 0) {
+			chatWindow_->setSecurityLabelsEnabled(false);
+			labelsEnabled_ = false;
+		} else {
+			chatWindow_->setAvailableSecurityLabels(catalog->getLabels());
+			chatWindow_->setSecurityLabelsEnabled(true);
+		}
+	} else {
+		chatWindow_->setSecurityLabelsError();
+	}
+}
+
+void ChatControllerBase::showChatWindow() {
+	chatWindow_->show();
+}
+
+String ChatControllerBase::senderDisplayNameFromMessage(JID from) {
+	return from;
+}
+
+
+
+void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) {
+	unreadMessages_.push_back(messageEvent);
+	chatWindow_->setUnreadMessageCount(unreadMessages_.size());
+
+	boost::shared_ptr<Message> message = messageEvent->getStanza();
+	preHandleIncomingMessage(message);	
+	String body = message->getBody();
+	if (message->isError()) {
+		String errorMessage = getErrorMessage(message->getPayload<Error>());
+		chatWindow_->addErrorMessage(errorMessage);
+	}
+	else {
+		showChatWindow();
+		boost::shared_ptr<SecurityLabel> label = message->getPayload<SecurityLabel>();
+		boost::optional<SecurityLabel> maybeLabel = label ? boost::optional<SecurityLabel>(*label) : boost::optional<SecurityLabel>();
+		JID from = message->getFrom();
+		chatWindow_->addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), maybeLabel);
+	}
+}
+
+String ChatControllerBase::getErrorMessage(boost::shared_ptr<Error> error) {
+	String defaultMessage = "Error sending message";
+	if (!error->getText().isEmpty()) {
+		return error->getText();
+	}
+	else {
+		switch (error->getCondition()) {
+			case Error::BadRequest: return defaultMessage; break;
+			case Error::Conflict: return defaultMessage; break;
+			case Error::FeatureNotImplemented: return defaultMessage; break;
+			case Error::Forbidden: return defaultMessage; break;
+			case Error::Gone: return "Recipient can no longer be contacted"; break;
+			case Error::InternalServerError: return "Internal server error"; break;
+			case Error::ItemNotFound: return defaultMessage; break;
+			case Error::JIDMalformed: return defaultMessage; break;
+			case Error::NotAcceptable: return "Message was rejected"; break;
+			case Error::NotAllowed: return defaultMessage; break;
+			case Error::NotAuthorized: return defaultMessage; break;
+			case Error::PaymentRequired: return defaultMessage; break;
+			case Error::RecipientUnavailable: return "Recipient is unavailable."; break;
+			case Error::Redirect: return defaultMessage; break;
+			case Error::RegistrationRequired: return defaultMessage; break;
+			case Error::RemoteServerNotFound: return "Recipient's server not found."; break;
+			case Error::RemoteServerTimeout: return defaultMessage; break;
+			case Error::ResourceConstraint: return defaultMessage; break;
+			case Error::ServiceUnavailable: return defaultMessage; break;
+			case Error::SubscriptionRequired: return defaultMessage; break;
+			case Error::UndefinedCondition: return defaultMessage; break;
+			case Error::UnexpectedRequest: return defaultMessage; break;
+		}
+	}
+	return defaultMessage;
+}
+
+}
diff --git a/Swift/Controllers/ChatControllerBase.h b/Swift/Controllers/ChatControllerBase.h
new file mode 100644
index 0000000..1967977
--- /dev/null
+++ b/Swift/Controllers/ChatControllerBase.h
@@ -0,0 +1,57 @@
+#ifndef SWIFTEN_ChatControllerBase_H
+#define SWIFTEN_ChatControllerBase_H
+
+#include <map>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/signals.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/Elements/DiscoInfo.h"
+#include "Swiften/Events/MessageEvent.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/Elements/SecurityLabelsCatalog.h"
+#include "Swiften/Elements/Error.h"
+#include "Swiften/Presence/PresenceOracle.h"
+
+namespace Swift {
+	class IQRouter;
+	class StanzaChannel;
+	class ChatWindow;
+	class ChatWindowFactory;
+
+	class ChatControllerBase  {
+		public:
+			virtual ~ChatControllerBase();
+			void showChatWindow();
+			void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
+			void handleIncomingMessage(boost::shared_ptr<MessageEvent> message);
+
+		protected:
+			ChatControllerBase(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle);
+			virtual void postSendMessage(const String&) {};
+			virtual String senderDisplayNameFromMessage(JID from);
+			void handlePresenceChange(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> previousPresence);
+			virtual bool isIncomingMessageFromMe(boost::shared_ptr<Message>) = 0;
+			virtual void preHandleIncomingMessage(boost::shared_ptr<Message>) {};
+			virtual void preSendMessageRequest(boost::shared_ptr<Message>) {};
+
+			std::vector<boost::shared_ptr<MessageEvent> > unreadMessages_;
+			StanzaChannel* stanzaChannel_;
+			IQRouter* iqRouter_;
+			ChatWindowFactory* chatWindowFactory_;
+			ChatWindow* chatWindow_;
+			JID toJID_;
+			bool labelsEnabled_;
+			PresenceOracle* presenceOracle_;
+
+		private:
+			void handleSendMessageRequest(const String &body);
+			String getStatusChangeString(boost::shared_ptr<Presence> presence);
+			void handleAllMessagesRead();
+			void handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog>, const boost::optional<Error>& error);
+			String getErrorMessage(boost::shared_ptr<Error>);
+	};
+}
+
+#endif
diff --git a/Swift/Controllers/ChatWindow.h b/Swift/Controllers/ChatWindow.h
new file mode 100644
index 0000000..04d0007
--- /dev/null
+++ b/Swift/Controllers/ChatWindow.h
@@ -0,0 +1,37 @@
+#ifndef SWIFTEN_CHATWINDOW_H
+#define SWIFTEN_CHATWINDOW_H
+
+#include <boost/optional.hpp>
+#include <boost/signals.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/Elements/SecurityLabel.h"
+
+namespace Swift {
+	class TreeWidget;
+	class ChatWindow {
+		public:
+			virtual ~ChatWindow() {};
+
+			virtual void addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label) = 0;
+			virtual void addSystemMessage(const String& message) = 0;
+			virtual void addErrorMessage(const String& message) = 0;
+
+			virtual void show() = 0;
+			virtual void setAvailableSecurityLabels(const std::vector<SecurityLabel>& labels) = 0;
+			virtual void setSecurityLabelsEnabled(bool enabled) = 0;
+			virtual void setUnreadMessageCount(int count) = 0;
+			virtual void convertToMUC() = 0;
+			virtual TreeWidget *getTreeWidget() = 0;
+			virtual void setSecurityLabelsError() = 0;
+			virtual SecurityLabel getSelectedSecurityLabel() = 0;
+
+			boost::signal<void ()> onClosed;
+			boost::signal<void ()> onAllMessagesRead;
+			boost::signal<void (const String&)> onSendMessageRequest;
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/ChatWindowFactory.h b/Swift/Controllers/ChatWindowFactory.h
new file mode 100644
index 0000000..c55ddba
--- /dev/null
+++ b/Swift/Controllers/ChatWindowFactory.h
@@ -0,0 +1,20 @@
+#ifndef SWIFTEN_CHATWINDOWFACTORY_H
+#define SWIFTEN_CHATWINDOWFACTORY_H
+
+#include "Swiften/JID/JID.h"
+
+namespace Swift {
+	class ChatWindow;
+
+	class ChatWindowFactory {
+		public:
+			virtual ~ChatWindowFactory() {};
+			/**
+			 * Transfers ownership of result.
+			 */
+			virtual ChatWindow* createChatWindow(const JID &contact) = 0;
+
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/EventController.cpp b/Swift/Controllers/EventController.cpp
new file mode 100644
index 0000000..9b143dd
--- /dev/null
+++ b/Swift/Controllers/EventController.cpp
@@ -0,0 +1,21 @@
+#include "Swift/Controllers/EventController.h"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+namespace Swift {
+
+void EventController::handleIncomingEvent(boost::shared_ptr<MessageEvent> event) {
+	if (event->isReadable()) {
+		events_.push_back(event);
+		event->onRead.connect(boost::bind(&EventController::handleEventRead, this, event));
+		onEventQueueLengthChange(events_.size());
+	}
+}
+
+void EventController::handleEventRead(boost::shared_ptr<MessageEvent> event) {
+	events_.erase(std::remove(events_.begin(), events_.end(), event), events_.end());
+	onEventQueueLengthChange(events_.size());
+}
+
+}
diff --git a/Swift/Controllers/EventController.h b/Swift/Controllers/EventController.h
new file mode 100644
index 0000000..ab161af
--- /dev/null
+++ b/Swift/Controllers/EventController.h
@@ -0,0 +1,24 @@
+#ifndef SWIFTEN_EventController_H
+#define SWIFTEN_EventController_H
+
+
+#include <boost/signals.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+#include "Swiften/Events/MessageEvent.h"
+
+namespace Swift {
+	class EventController {
+		public:
+			void handleIncomingEvent(boost::shared_ptr<MessageEvent> event);
+			boost::signal<void (int)> onEventQueueLengthChange;
+
+		private:
+			void handleEventRead(boost::shared_ptr<MessageEvent> event);
+			std::vector<boost::shared_ptr<MessageEvent> > events_;
+	};
+}
+#endif
+
+
diff --git a/Swift/Controllers/LoginWindow.h b/Swift/Controllers/LoginWindow.h
new file mode 100644
index 0000000..44855c0
--- /dev/null
+++ b/Swift/Controllers/LoginWindow.h
@@ -0,0 +1,22 @@
+#ifndef SWIFTEN_LoginWindow_H
+#define SWIFTEN_LoginWindow_H
+
+#include "Swiften/Base/String.h"
+
+#include <boost/signals.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class MainWindow;
+	class LoginWindow {
+		public:
+			virtual ~LoginWindow() {};
+			virtual void morphInto(MainWindow *mainWindow) = 0;
+			virtual void loggedOut() = 0;
+			virtual void setMessage(const String&) = 0;
+
+			boost::signal<void (const String&, const String&, const String& /* certificateFile */, bool)> onLoginRequest;
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/LoginWindowFactory.h b/Swift/Controllers/LoginWindowFactory.h
new file mode 100644
index 0000000..d52325e
--- /dev/null
+++ b/Swift/Controllers/LoginWindowFactory.h
@@ -0,0 +1,22 @@
+#ifndef SWIFTEN_LoginWindowFactory_H
+#define SWIFTEN_LoginWindowFactory_H
+
+
+
+namespace Swift {
+	class LoginWindow;
+    class String;
+    
+	class LoginWindowFactory {
+		public:
+			virtual ~LoginWindowFactory() {};
+
+			/**
+			 * Transfers ownership of result.
+			 */
+			virtual LoginWindow* createLoginWindow(const String& defaultJID, const String& defaultPassword, const String& defaultCertificate) = 0;
+
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/MUCController.cpp b/Swift/Controllers/MUCController.cpp
new file mode 100644
index 0000000..93880c4
--- /dev/null
+++ b/Swift/Controllers/MUCController.cpp
@@ -0,0 +1,76 @@
+#include "Swift/Controllers/MUCController.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/Base/foreach.h"
+#include "Swift/Controllers/ChatWindow.h"
+#include "Swift/Controllers/ChatWindowFactory.h"
+#include "Swiften/MUC/MUC.h"
+#include "Swiften/Client/StanzaChannel.h"
+#include "Swiften/Roster/Roster.h"
+#include "Swiften/Roster/SetPresence.h"
+#include "Swiften/Roster/TreeWidgetFactory.h"
+
+namespace Swift {
+	
+/**
+ * The controller does not gain ownership of the stanzaChannel, nor the factory.
+ */
+MUCController::MUCController (
+		const JID &muc, 
+		const String &nick, 
+		StanzaChannel* stanzaChannel, 
+		IQRouter* iqRouter, 
+		ChatWindowFactory* chatWindowFactory, 
+		TreeWidgetFactory *treeWidgetFactory,
+		PresenceOracle* presenceOracle) : 
+			ChatControllerBase(stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle),
+			muc_(new MUC(stanzaChannel, muc)), 
+			nick_(nick), 
+			treeWidgetFactory_(treeWidgetFactory) { 
+	roster_ = new Roster(chatWindow_->getTreeWidget(), treeWidgetFactory_);
+	chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this));
+	muc_->joinAs(nick);
+	muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
+	muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
+	muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
+	chatWindow_->convertToMUC();
+	chatWindow_->show();
+}
+
+MUCController::~MUCController() {
+	delete muc_;
+	//don't crash on exit by masking this. FIXME.
+	//delete roster_;
+}
+
+void MUCController::handleWindowClosed() {
+	muc_->part();
+}
+
+void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
+	roster_->addContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick()), occupant.getNick(), "Occupants");
+}
+
+void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType, const String& /*reason*/) {
+	roster_->removeContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick()));
+}
+
+void MUCController::handleOccupantPresenceChange(boost::shared_ptr<Presence> presence) {
+	roster_->applyOnItems(SetPresence(presence, JID::WithResource));
+}
+
+bool MUCController::isIncomingMessageFromMe(boost::shared_ptr<Message> message) {
+	JID from = message->getFrom();
+	return nick_ == from.getResource();
+}
+
+String MUCController::senderDisplayNameFromMessage(JID from) {
+	return from.getResource();
+}
+
+void MUCController::preSendMessageRequest(boost::shared_ptr<Message> message) {
+	message->setType(Swift::Message::Groupchat);
+}
+
+}
diff --git a/Swift/Controllers/MUCController.h b/Swift/Controllers/MUCController.h
new file mode 100644
index 0000000..c87695e
--- /dev/null
+++ b/Swift/Controllers/MUCController.h
@@ -0,0 +1,43 @@
+#ifndef SWIFTEN_MUCController_H
+#define SWIFTEN_MUCController_H
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swift/Controllers/ChatControllerBase.h"
+#include "Swiften/Elements/Message.h"
+#include "Swiften/Elements/DiscoInfo.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/MUC/MUC.h"
+#include "Swiften/MUC/MUCOccupant.h"
+
+namespace Swift {
+	class StanzaChannel;
+	class IQRouter;
+	class ChatWindow;
+	class ChatWindowFactory;
+	class Roster;
+	class TreeWidgetFactory;
+
+	class MUCController : public ChatControllerBase {
+		public:
+			MUCController(const JID &muc, const String &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle);
+			~MUCController();
+		
+		protected:
+			void preSendMessageRequest(boost::shared_ptr<Message> message);
+			bool isIncomingMessageFromMe(boost::shared_ptr<Message> message);
+			String senderDisplayNameFromMessage(JID from);
+		private:
+			void handleWindowClosed();
+			void handleOccupantJoined(const MUCOccupant& occupant);
+			void handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType type, const String& reason);
+			void handleOccupantPresenceChange(boost::shared_ptr<Presence> presence);
+			MUC *muc_;
+			String nick_;
+			TreeWidgetFactory *treeWidgetFactory_;
+			Roster *roster_;
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
new file mode 100644
index 0000000..e5036a5
--- /dev/null
+++ b/Swift/Controllers/MainController.cpp
@@ -0,0 +1,260 @@
+#include "Swift/Controllers/MainController.h"
+
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
+#include <stdlib.h>
+
+#include "Swiften/Application/Application.h"
+#include "Swiften/Application/ApplicationMessageDisplay.h"
+#include "Swift/Controllers/ChatController.h"
+#include "Swift/Controllers/ChatWindowFactory.h"
+#include "Swift/Controllers/EventController.h"
+#include "Swift/Controllers/LoginWindow.h"
+#include "Swift/Controllers/LoginWindowFactory.h"
+#include "Swift/Controllers/MainWindow.h"
+#include "Swift/Controllers/MainWindowFactory.h"
+#include "Swift/Controllers/MUCController.h"
+#include "Swift/Controllers/NickResolver.h"
+#include "Swift/Controllers/RosterController.h"
+#include "Swift/Controllers/XMPPRosterController.h"
+#include "Swiften/Base/foreach.h"
+#include "Swiften/Base/String.h"
+#include "Swiften/Client/Client.h"
+#include "Swiften/Elements/Presence.h"
+#include "Swiften/Roster/XMPPRoster.h"
+#include "Swiften/Queries/Responders/SoftwareVersionResponder.h"
+#include "Swiften/Roster/TreeWidgetFactory.h"
+#include "Swiften/Settings/SettingsProvider.h"
+#include "Swiften/Elements/DiscoInfo.h"
+#include "Swiften/Queries/Responders/DiscoInfoResponder.h"
+#include "Swiften/Disco/CapsInfoGenerator.h"
+#include "Swiften/Queries/Requests/GetDiscoInfoRequest.h"
+
+namespace Swift {
+
+static const String CLIENT_NAME = "Swift";
+static const String CLIENT_VERSION = "0.3";
+static const String CLIENT_NODE = "http://swift.im";
+
+typedef std::pair<JID, ChatController*> JIDChatControllerPair;
+typedef std::pair<JID, MUCController*> JIDMUCControllerPair;
+
+MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory *treeWidgetFactory, SettingsProvider *settings, Application* application)
+		: client_(NULL), chatWindowFactory_(chatWindowFactory), mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), treeWidgetFactory_(treeWidgetFactory), settings_(settings),
+		xmppRosterController_(NULL), rosterController_(NULL), loginWindow_(NULL), clientVersionResponder_(NULL), nickResolver_(NULL), discoResponder_(NULL), 
+		serverDiscoInfo_(new DiscoInfo()), presenceOracle_(NULL) {
+	application_ = application;
+	eventController_ = new EventController();
+	eventController_->onEventQueueLengthChange.connect(boost::bind(&MainController::handleEventQueueLengthChange, this, _1));
+	loginWindow_ = loginWindowFactory_->createLoginWindow(settings->getStringSetting("jid"), settings->getStringSetting("pass"), settings->getStringSetting("certificate"));
+	loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4));
+}
+
+MainController::~MainController() {
+	delete discoResponder_;
+	delete clientVersionResponder_;
+	delete xmppRosterController_;
+	delete rosterController_;
+	foreach (JIDChatControllerPair controllerPair, chatControllers_) {
+		delete controllerPair.second;
+	}
+	foreach (JIDMUCControllerPair controllerPair, mucControllers_) {
+		delete controllerPair.second;
+	}
+	delete presenceOracle_;
+	delete nickResolver_;
+	delete client_;
+}
+
+void MainController::handleConnected() {
+	delete presenceOracle_;
+	presenceOracle_ = new PresenceOracle(client_);
+
+	client_->onPresenceReceived.connect(boost::bind(&MainController::handleIncomingPresence, this, _1));
+
+	boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
+
+
+	delete nickResolver_;
+	nickResolver_ = new NickResolver(xmppRoster);
+
+	delete rosterController_;
+	rosterController_ = new RosterController(xmppRoster, mainWindowFactory_, treeWidgetFactory_);
+	rosterController_->onStartChatRequest.connect(boost::bind(&MainController::handleChatRequest, this, _1));
+	rosterController_->onJoinMUCRequest.connect(boost::bind(&MainController::handleJoinMUCRequest, this, _1, _2));
+	rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
+
+	delete xmppRosterController_;
+	xmppRosterController_ = new XMPPRosterController(client_, xmppRoster);
+	xmppRosterController_->requestRoster();
+
+	delete clientVersionResponder_;
+	clientVersionResponder_ = new SoftwareVersionResponder(CLIENT_NAME, CLIENT_VERSION, client_);
+	loginWindow_->morphInto(rosterController_->getWindow());
+
+	DiscoInfo discoInfo;
+	discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc"));
+	capsInfo_ = boost::shared_ptr<CapsInfo>(new CapsInfo(CapsInfoGenerator(CLIENT_NODE).generateCapsInfo(discoInfo)));
+	discoResponder_ = new DiscoInfoResponder(client_);
+	discoResponder_->setDiscoInfo(discoInfo);
+	discoResponder_->setDiscoInfo(capsInfo_->getNode() + "#" + capsInfo_->getVersion(), discoInfo);
+
+	serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo());
+	GetDiscoInfoRequest* discoInfoRequest = new GetDiscoInfoRequest(JID(), client_, Request::AutoDeleteAfterResponse);
+	discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2));
+	discoInfoRequest->send();
+	
+	//Send presence last to catch all the incoming presences.
+	boost::shared_ptr<Presence> initialPresence(new Presence());
+	initialPresence->addPayload(capsInfo_);
+	client_->sendPresence(initialPresence);
+}
+
+void MainController::handleEventQueueLengthChange(int count) {
+	application_->getApplicationMessageDisplay()->setMessage(count == 0 ? "" : boost::lexical_cast<std::string>(count).c_str());
+}
+
+void MainController::handleChangeStatusRequest(StatusShow::Type show, const String &statusText) {
+	boost::shared_ptr<Presence> presence(new Presence());
+	presence->addPayload(capsInfo_);
+	presence->setShow(show);
+	presence->setStatus(statusText);
+	// FIXME: This is wrong. None doesn't mean unavailable
+	if (show == StatusShow::None) {
+		presence->setType(Presence::Unavailable);
+	}
+	client_->sendPresence(presence);
+	if (presence->getType() == Presence::Unavailable) {
+		logout();
+	}
+}
+
+void MainController::handleIncomingPresence(boost::shared_ptr<Presence> presence) {
+	rosterController_->handleIncomingPresence(presence);
+}
+
+void MainController::handleLoginRequest(const String &username, const String &password, const String& certificateFile, bool remember) {
+	loginWindow_->setMessage("");
+
+	settings_->storeString("jid", username);
+	settings_->storeString("certificate", certificateFile);
+	settings_->storeString("pass", remember ? password : "");
+
+	delete client_;
+	client_ = new Swift::Client(JID(username), password);
+	if (!certificateFile.isEmpty()) {
+		client_->setCertificate(certificateFile);
+	}
+	client_->onError.connect(boost::bind(&MainController::handleError, this, _1));
+	client_->onConnected.connect(boost::bind(&MainController::handleConnected, this));
+	client_->onMessageReceived.connect(boost::bind(&MainController::handleIncomingMessage, this, _1));
+	client_->connect();
+}
+
+void MainController::handleError(const ClientError& error) {
+	String message;
+	switch(error.getType()) {
+		case ClientError::NoError: assert(false); break;
+		case ClientError::DomainNameResolveError: message = "Unable to find server"; break;
+		case ClientError::ConnectionError: message = "Error connecting to server"; break;
+		case ClientError::ConnectionReadError: message = "Error while receiving server data"; break;
+		case ClientError::XMLError: message = "Error parsing server data"; break;
+		case ClientError::AuthenticationFailedError: message = "Login/password invalid"; break;
+		case ClientError::NoSupportedAuthMechanismsError: message = "Authentication mechanisms not supported"; break;
+		case ClientError::UnexpectedElementError: message = "Unexpected response"; break;
+		case ClientError::ResourceBindError: message = "Error binding resource"; break;
+		case ClientError::SessionStartError: message = "Error starting session"; break;
+		case ClientError::TLSError: message = "Encryption error"; break;
+		case ClientError::ClientCertificateLoadError: message = "Error loading certificate (Invalid password?)"; break;
+		case ClientError::ClientCertificateError: message = "Certificate not authorized"; break;
+	}
+	loginWindow_->setMessage(message);
+	logout();
+}
+
+void MainController::logout() {
+	loginWindow_->loggedOut();
+
+	delete discoResponder_;
+	discoResponder_ = NULL;
+	delete clientVersionResponder_;
+	clientVersionResponder_ = NULL;
+	foreach (JIDChatControllerPair controllerPair, chatControllers_) {
+		delete controllerPair.second;
+	}
+	client_->disconnect();
+	chatControllers_.clear();
+	foreach (JIDMUCControllerPair controllerPair, mucControllers_) {
+		delete controllerPair.second;
+	}
+	mucControllers_.clear();
+}
+
+
+void MainController::handleChatRequest(const String &contact) {
+	getChatController(JID(contact))->showChatWindow();
+}
+
+ChatController* MainController::getChatController(const JID &contact) {
+	JID lookupContact(contact);
+	if (chatControllers_.find(lookupContact) == chatControllers_.end()) {
+		lookupContact = JID(contact.toBare());
+	}
+	if (chatControllers_.find(lookupContact) == chatControllers_.end()) {
+		chatControllers_[contact] = new ChatController(client_, client_, chatWindowFactory_, contact, nickResolver_, presenceOracle_);
+		chatControllers_[contact]->setAvailableServerFeatures(serverDiscoInfo_);
+		lookupContact = contact;
+	}
+	return chatControllers_[lookupContact];
+}
+
+void MainController::handleChatControllerJIDChanged(const JID& from, const JID& to) {
+	chatControllers_[to] = chatControllers_[from];
+	chatControllers_.erase(from);
+}
+
+void MainController::handleJoinMUCRequest(const JID &muc, const String &nick) {
+	mucControllers_[muc] = new MUCController(muc, nick, client_, client_, chatWindowFactory_, treeWidgetFactory_, presenceOracle_);
+	mucControllers_[muc]->setAvailableServerFeatures(serverDiscoInfo_);
+}
+
+void MainController::handleIncomingMessage(boost::shared_ptr<Message> message) {
+	JID jid = message->getFrom();
+	boost::shared_ptr<MessageEvent> event(new MessageEvent(message));
+
+	// Try to deliver it to a MUC
+	if (message->getType() == Message::Groupchat || message->getType() == Message::Error) {
+		std::map<JID, MUCController*>::iterator i = mucControllers_.find(jid.toBare());
+		if (i != mucControllers_.end()) {
+			i->second->handleIncomingMessage(event);
+			return;
+		}
+		else if (message->getType() == Message::Groupchat) {
+			//FIXME: Error handling - groupchat messages from an unknown muc.
+			return;
+		}
+	}
+	
+	//if not a mucroom
+	eventController_->handleIncomingEvent(event);
+
+	// FIXME: This logic should go into a chat manager
+	if (event->isReadable()) {
+		getChatController(jid)->handleIncomingMessage(event);
+	}
+}
+
+void MainController::handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, const boost::optional<Error>& error) {
+	if (!error) {
+		serverDiscoInfo_ = info;
+		foreach (JIDChatControllerPair pair, chatControllers_) {
+			pair.second->setAvailableServerFeatures(info);
+		}
+		foreach (JIDMUCControllerPair pair, mucControllers_) {
+			pair.second->setAvailableServerFeatures(info);
+		}
+	}
+}
+
+}
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
new file mode 100644
index 0000000..e09d4fa
--- /dev/null
+++ b/Swift/Controllers/MainController.h
@@ -0,0 +1,85 @@
+#ifndef SWIFTEN_MainController_H
+#define SWIFTEN_MainController_H
+
+
+#include "Swiften/Base/String.h"
+#include "Swiften/Client/ClientError.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/Elements/DiscoInfo.h"
+#include "Swiften/Elements/Error.h"
+#include "Swiften/Elements/Presence.h"
+#include "Swiften/Elements/Message.h"
+#include "Swiften/Settings/SettingsProvider.h"
+#include "Swiften/Elements/CapsInfo.h"
+
+
+#include <boost/signals.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+
+namespace Swift {
+	class Application;
+	class Client;
+	class ChatWindowFactory;
+	class ChatController;
+	class EventController;
+	class MainWindowFactory;
+	class MainWindow;
+	class NickResolver;
+	class RosterController;
+	class XMPPRosterController;
+	class DiscoInfoResponder;
+	class LoginWindow;
+	class EventLoop;
+	class SoftwareVersionResponder;
+	class LoginWindowFactory;
+	class TreeWidgetFactory;
+	class MUCController;
+	class PresenceOracle;
+
+	class MainController {
+		public:
+			MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory* treeWidgetFactory, SettingsProvider *settings, Application* application);
+			~MainController();
+
+
+		private:
+			void handleConnected();
+			void handleLoginRequest(const String& username, const String& password, const String& certificateFile, bool remember);
+			void handleChatRequest(const String& contact);
+			void handleJoinMUCRequest(const JID& muc, const String& nick);
+			void handleIncomingPresence(boost::shared_ptr<Presence> presence);
+			void handleChatControllerJIDChanged(const JID& from, const JID& to);
+			void handleIncomingMessage(boost::shared_ptr<Message> message);
+			void handleChangeStatusRequest(StatusShow::Type show, const String &statusText);
+			void handleError(const ClientError& error);
+			void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, const boost::optional<Error>&);
+			void handleEventQueueLengthChange(int count);
+			ChatController* getChatController(const JID &contact);
+			void logout();
+			
+			Client* client_;
+			ChatWindowFactory* chatWindowFactory_;
+			MainWindowFactory* mainWindowFactory_;
+			LoginWindowFactory* loginWindowFactory_;
+			TreeWidgetFactory* treeWidgetFactory_;
+			SettingsProvider *settings_;
+			Application* application_;
+			ChatController* chatController_;
+			XMPPRosterController* xmppRosterController_;
+			RosterController* rosterController_;
+			EventController* eventController_;
+			LoginWindow* loginWindow_;
+			SoftwareVersionResponder* clientVersionResponder_;
+			NickResolver* nickResolver_;
+			DiscoInfoResponder* discoResponder_;
+			boost::shared_ptr<CapsInfo> capsInfo_;
+			std::map<JID, MUCController*> mucControllers_;
+			std::map<JID, ChatController*> chatControllers_;
+			boost::shared_ptr<DiscoInfo> serverDiscoInfo_;
+			PresenceOracle* presenceOracle_;
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/MainWindow.h b/Swift/Controllers/MainWindow.h
new file mode 100644
index 0000000..081fe6e
--- /dev/null
+++ b/Swift/Controllers/MainWindow.h
@@ -0,0 +1,26 @@
+#ifndef SWIFTEN_MainWindow_H
+#define SWIFTEN_MainWindow_H
+
+#include "Swiften/Base/String.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/Elements/StatusShow.h"
+
+#include <boost/signals.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class TreeWidget;
+
+	class MainWindow {
+		public:
+			virtual ~MainWindow() {};
+			virtual TreeWidget* getTreeWidget() = 0;
+			
+			boost::signal<void (const JID&)> onStartChatRequest;
+			boost::signal<void (const JID&, const String&)> onJoinMUCRequest;
+			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;
+			boost::signal<void (bool)> onShowOfflineToggled;
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/MainWindowFactory.h b/Swift/Controllers/MainWindowFactory.h
new file mode 100644
index 0000000..cf5a061
--- /dev/null
+++ b/Swift/Controllers/MainWindowFactory.h
@@ -0,0 +1,20 @@
+#ifndef SWIFTEN_MainWindowFactory_H
+#define SWIFTEN_MainWindowFactory_H
+
+#include "Swiften/JID/JID.h"
+
+namespace Swift {
+	class MainWindow;
+
+	class MainWindowFactory {
+		public:
+			virtual ~MainWindowFactory() {};
+			/**
+			 * Transfers ownership of result.
+			 */
+			virtual MainWindow* createMainWindow() = 0;
+
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/Makefile.inc b/Swift/Controllers/Makefile.inc
new file mode 100644
index 0000000..ff3192e
--- /dev/null
+++ b/Swift/Controllers/Makefile.inc
@@ -0,0 +1,22 @@
+SWIFT_CONTROLLERS_SOURCES += \
+	Swift/Controllers/ChatController.cpp \
+	Swift/Controllers/ChatControllerBase.cpp \
+	Swift/Controllers/MainController.cpp \
+	Swift/Controllers/NickResolver.cpp \
+	Swift/Controllers/RosterController.cpp \
+	Swift/Controllers/XMPPRosterController.cpp \
+	Swift/Controllers/MUCController.cpp \
+	Swift/Controllers/EventController.cpp
+
+include Swift/Controllers/UnitTest/Makefile.inc
+
+SWIFT_CONTROLLERS_TARGET = Swift/Controllers/Controllers.a
+SWIFT_CONTROLLERS_OBJECTS = \
+	$(SWIFT_CONTROLLERS_SOURCES:.cpp=.o)
+
+TARGETS += $(SWIFT_CONTROLLERS_TARGET)
+UNITTEST_LIBS += $(SWIFT_CONTROLLERS_TARGET)
+CLEANFILES += $(SWIFT_CONTROLLERS_TARGET) $(SWIFT_CONTROLLERS_OBJECTS)
+
+$(SWIFT_CONTROLLERS_TARGET): $(SWIFT_CONTROLLERS_OBJECTS)
+	$(QUIET_AR)$(AR) $(ARFLAGS) $@ $(SWIFT_CONTROLLERS_OBJECTS)
diff --git a/Swift/Controllers/NickResolver.cpp b/Swift/Controllers/NickResolver.cpp
new file mode 100644
index 0000000..db1d2b4
--- /dev/null
+++ b/Swift/Controllers/NickResolver.cpp
@@ -0,0 +1,22 @@
+#include "Swift/Controllers/NickResolver.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Roster/XMPPRoster.h"
+
+namespace Swift {
+
+NickResolver::NickResolver(boost::shared_ptr<XMPPRoster> xmppRoster) {
+	xmppRoster_ = xmppRoster;
+}
+
+String NickResolver::jidToNick(const JID& jid) {
+	if (xmppRoster_->containsJID(jid)) {
+		return xmppRoster_->getNameForJID(jid);
+	}
+	std::map<JID, String>::iterator it = map_.find(jid);
+	return (it == map_.end()) ? jid.toBare() : it->second;
+}
+
+}
+
diff --git a/Swift/Controllers/NickResolver.h b/Swift/Controllers/NickResolver.h
new file mode 100644
index 0000000..b7dc005
--- /dev/null
+++ b/Swift/Controllers/NickResolver.h
@@ -0,0 +1,24 @@
+#ifndef SWIFTEN_NickResolver_H
+#define SWIFTEN_NickResolver_H
+
+#include <map>
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/JID/JID.h"
+
+namespace Swift {
+	class XMPPRoster;
+	class NickResolver {
+		public:
+			NickResolver(boost::shared_ptr<XMPPRoster> xmppRoster);
+			String jidToNick(const JID& jid);
+		
+		private:
+			std::map<JID, String> map_;
+			boost::shared_ptr<XMPPRoster> xmppRoster_;
+	};
+}
+#endif
+
+
diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp
new file mode 100644
index 0000000..c447602
--- /dev/null
+++ b/Swift/Controllers/RosterController.cpp
@@ -0,0 +1,83 @@
+#include "Swift/Controllers/RosterController.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/Base/foreach.h"
+#include "Swift/Controllers/MainWindow.h"
+#include "Swift/Controllers/MainWindowFactory.h"
+#include "Swiften/Queries/Requests/GetRosterRequest.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+#include "Swiften/Roster/Roster.h"
+#include "Swiften/Roster/SetPresence.h"
+#include "Swiften/Roster/OfflineRosterFilter.h"
+#include "Swiften/Roster/OpenChatRosterAction.h"
+#include "Swiften/Roster/TreeWidgetFactory.h"
+#include "Swiften/Roster/XMPPRoster.h"
+
+namespace Swift {
+	
+/**
+ * The controller does not gain ownership of these parameters.
+ */
+RosterController::RosterController(boost::shared_ptr<XMPPRoster> xmppRoster, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory)
+ : xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), treeWidgetFactory_(treeWidgetFactory), mainWindow_(mainWindowFactory_->createMainWindow()), roster_(new Roster(mainWindow_->getTreeWidget(), treeWidgetFactory_)), offlineFilter_(new OfflineRosterFilter()) {
+	roster_->addFilter(offlineFilter_);
+	mainWindow_->onStartChatRequest.connect(boost::bind(&RosterController::handleStartChatRequest, this, _1));
+	mainWindow_->onJoinMUCRequest.connect(boost::bind(&RosterController::handleJoinMUCRequest, this, _1, _2));
+	mainWindow_->onChangeStatusRequest.connect(boost::bind(&RosterController::handleChangeStatusRequest, this, _1, _2));
+	mainWindow_->onShowOfflineToggled.connect(boost::bind(&RosterController::handleShowOfflineToggled, this, _1));
+	roster_->onUserAction.connect(boost::bind(&RosterController::handleUserAction, this, _1));
+	xmppRoster_->onJIDAdded.connect(boost::bind(&RosterController::handleOnJIDAdded, this, _1));
+}
+
+RosterController::~RosterController() {
+	delete offlineFilter_;
+
+}
+
+void RosterController::handleShowOfflineToggled(bool state) {
+	if (state) {
+		roster_->removeFilter(offlineFilter_);
+	} else {
+		roster_->addFilter(offlineFilter_);
+	}
+}
+
+void RosterController::handleChangeStatusRequest(StatusShow::Type show, const String &statusText) {
+	onChangeStatusRequest(show, statusText);
+}
+
+void RosterController::handleUserAction(boost::shared_ptr<UserRosterAction> action) {
+	boost::shared_ptr<OpenChatRosterAction> chatAction = boost::dynamic_pointer_cast<OpenChatRosterAction>(action);
+	if (chatAction.get() != NULL) {
+		ContactRosterItem *contactItem = dynamic_cast<ContactRosterItem*>(chatAction->getRosterItem());
+		assert(contactItem);
+		onStartChatRequest(contactItem->getJID().toBare());
+	}
+}
+
+void RosterController::handleOnJIDAdded(const JID& jid) {
+	std::vector<String> groups = xmppRoster_->getGroupsForJID(jid);
+	String name = xmppRoster_->getNameForJID(jid);
+	if (!groups.empty()) {
+		foreach(const String& group, groups) {
+			roster_->addContact(jid, name, group);
+		}
+	} else {
+		roster_->addContact(jid, name, "Contacts");
+	}
+}
+
+void RosterController::handleIncomingPresence(boost::shared_ptr<Presence> presence) {
+	roster_->applyOnItems(SetPresence(presence));
+}
+
+void RosterController::handleStartChatRequest(const JID& contact) {
+	onStartChatRequest(contact);
+}
+
+void RosterController::handleJoinMUCRequest(const JID &muc, const String &nick) {
+	onJoinMUCRequest(JID(muc), nick);
+}
+
+}
diff --git a/Swift/Controllers/RosterController.h b/Swift/Controllers/RosterController.h
new file mode 100644
index 0000000..945b068
--- /dev/null
+++ b/Swift/Controllers/RosterController.h
@@ -0,0 +1,48 @@
+#ifndef SWIFTEN_RosterController_H
+#define SWIFTEN_RosterController_H
+
+#include "Swiften/JID/JID.h"
+#include "Swiften/Base/String.h"
+#include "Swiften/Elements/Presence.h"
+#include "Swiften/Roster/UserRosterAction.h"
+
+#include <boost/signals.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class IQRouter;
+	class Roster;
+	class XMPPRoster;
+	class MainWindow;
+	class MainWindowFactory;
+	class TreeWidgetFactory;
+	class OfflineRosterFilter;
+
+	class RosterController {
+		public:
+			RosterController(boost::shared_ptr<XMPPRoster> xmppRoster, MainWindowFactory *mainWindowFactory, TreeWidgetFactory *treeWidgetFactory);
+			~RosterController();
+			void showRosterWindow();
+			MainWindow* getWindow() {return mainWindow_;};
+			boost::signal<void (const JID&)> onStartChatRequest;
+			boost::signal<void (const JID&, const String&)> onJoinMUCRequest;
+			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;
+			void handleIncomingPresence(boost::shared_ptr<Presence> presence);
+
+		private:
+			void handleOnJIDAdded(const JID &jid);
+			void handleStartChatRequest(const JID& contact);
+			void handleJoinMUCRequest(const JID &muc, const String &nick);
+			void handleUserAction(boost::shared_ptr<UserRosterAction> action);
+			void handleChangeStatusRequest(StatusShow::Type show, const String &statusText);
+			void handleShowOfflineToggled(bool state);
+			boost::shared_ptr<XMPPRoster> xmppRoster_;
+			MainWindowFactory* mainWindowFactory_;
+			TreeWidgetFactory* treeWidgetFactory_;
+			MainWindow* mainWindow_;
+			Roster* roster_;
+			OfflineRosterFilter* offlineFilter_;
+	};
+}
+#endif
+
diff --git a/Swift/Controllers/UnitTest/Makefile.inc b/Swift/Controllers/UnitTest/Makefile.inc
new file mode 100644
index 0000000..254f35d
--- /dev/null
+++ b/Swift/Controllers/UnitTest/Makefile.inc
@@ -0,0 +1,4 @@
+UNITTEST_SOURCES += \
+	Swift/Controllers/UnitTest/NickResolverTest.cpp \
+	Swift/Controllers/UnitTest/XMPPRosterControllerTest.cpp
+
diff --git a/Swift/Controllers/UnitTest/NickResolverTest.cpp b/Swift/Controllers/UnitTest/NickResolverTest.cpp
new file mode 100644
index 0000000..947d3d8
--- /dev/null
+++ b/Swift/Controllers/UnitTest/NickResolverTest.cpp
@@ -0,0 +1,62 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swift/Controllers/NickResolver.h"
+#include "Swiften/Roster/XMPPRoster.h"
+
+using namespace Swift;
+
+class NickResolverTest : public CppUnit::TestFixture
+{
+		CPPUNIT_TEST_SUITE(NickResolverTest);
+		CPPUNIT_TEST(testNoMatch);
+		CPPUNIT_TEST(testMatch);
+		CPPUNIT_TEST(testOverwrittenMatch);
+		CPPUNIT_TEST(testRemovedMatch);
+		CPPUNIT_TEST_SUITE_END();
+
+		std::vector<String> groups_;
+
+	public:
+		NickResolverTest() {}
+
+		void testNoMatch() {
+			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
+			NickResolver resolver(xmppRoster);
+			JID testling("foo@bar/baz");
+
+			CPPUNIT_ASSERT_EQUAL(String("foo@bar"), resolver.jidToNick(testling));
+		}
+
+		void testMatch() {
+			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
+			NickResolver resolver(xmppRoster);
+			JID testling("foo@bar/baz");
+			xmppRoster->addContact(testling, "Test", groups_);
+
+			CPPUNIT_ASSERT_EQUAL(String("Test"), resolver.jidToNick(testling));
+		}
+
+		void testOverwrittenMatch() {
+			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
+			NickResolver resolver(xmppRoster);
+			JID testling("foo@bar/baz");
+			xmppRoster->addContact(testling, "FailTest", groups_);
+			xmppRoster->addContact(testling, "Test", groups_);
+
+			CPPUNIT_ASSERT_EQUAL(String("Test"), resolver.jidToNick(testling));
+		}
+
+		void testRemovedMatch() {
+			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
+			NickResolver resolver(xmppRoster);
+			JID testling("foo@bar/baz");
+			xmppRoster->addContact(testling, "FailTest", groups_);
+			xmppRoster->removeContact(testling);
+			CPPUNIT_ASSERT_EQUAL(String("foo@bar"), resolver.jidToNick(testling));
+		}
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(NickResolverTest);
+
diff --git a/Swift/Controllers/UnitTest/XMPPRosterControllerTest.cpp b/Swift/Controllers/UnitTest/XMPPRosterControllerTest.cpp
new file mode 100644
index 0000000..c1d53c6
--- /dev/null
+++ b/Swift/Controllers/UnitTest/XMPPRosterControllerTest.cpp
@@ -0,0 +1,88 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swift/Controllers/XMPPRosterController.h"
+#include "Swiften/Elements/Payload.h"
+#include "Swiften/Elements/RosterItemPayload.h"
+#include "Swiften/Elements/RosterPayload.h"
+#include "Swiften/Queries/DummyIQChannel.h"
+#include "Swiften/Queries/IQRouter.h"
+#include "Swiften/Roster/XMPPRoster.h"
+
+using namespace Swift;
+
+class XMPPRosterControllerTest : public CppUnit::TestFixture
+{
+		CPPUNIT_TEST_SUITE(XMPPRosterControllerTest);
+		CPPUNIT_TEST(testAdd);
+		CPPUNIT_TEST(testModify);
+		CPPUNIT_TEST(testRemove);
+		CPPUNIT_TEST_SUITE_END();
+
+		DummyIQChannel* channel_;
+		IQRouter* router_;
+	public:
+		XMPPRosterControllerTest() {}
+
+		void setUp() {
+			channel_ = new DummyIQChannel();
+			router_ = new IQRouter(channel_);
+		}
+
+		void tearDown() {
+			delete channel_;
+			delete router_;
+		}
+
+		void testAdd() {
+			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
+			XMPPRosterController controller(router_, xmppRoster);
+			JID testling("foo@bar");
+			CPPUNIT_ASSERT(!xmppRoster->containsJID(testling));
+			boost::shared_ptr<Payload> payload(new RosterPayload());
+			RosterItemPayload item(testling, "Bob", RosterItemPayload::Both);
+			dynamic_cast<RosterPayload*>(payload.get())->addItem(item);
+			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload));
+			CPPUNIT_ASSERT(xmppRoster->containsJID(testling));
+		}
+
+		void testModify() {
+			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
+			XMPPRosterController controller(router_, xmppRoster);
+			JID testling("foo@bar");
+			CPPUNIT_ASSERT(!xmppRoster->containsJID(testling));
+			boost::shared_ptr<Payload> payload1(new RosterPayload());
+			RosterItemPayload item1(testling, "Bob", RosterItemPayload::Both);
+			dynamic_cast<RosterPayload*>(payload1.get())->addItem(item1);
+			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload1));
+			CPPUNIT_ASSERT(xmppRoster->containsJID(testling));
+			CPPUNIT_ASSERT_EQUAL(String("Bob"), xmppRoster->getNameForJID(testling));
+			boost::shared_ptr<Payload> payload2(new RosterPayload());
+			RosterItemPayload item2(testling, "Bob2", RosterItemPayload::Both);
+			dynamic_cast<RosterPayload*>(payload2.get())->addItem(item2);
+			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload2));
+			CPPUNIT_ASSERT_EQUAL(String("Bob2"), xmppRoster->getNameForJID(testling));
+		}
+
+		void testRemove() {
+			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
+			XMPPRosterController controller(router_, xmppRoster);
+			JID testling("foo@bar");
+			CPPUNIT_ASSERT(!xmppRoster->containsJID(testling));
+			boost::shared_ptr<Payload> payload1(new RosterPayload());
+			RosterItemPayload item1(testling, "Bob", RosterItemPayload::Both);
+			dynamic_cast<RosterPayload*>(payload1.get())->addItem(item1);
+			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload1));
+			CPPUNIT_ASSERT(xmppRoster->containsJID(testling));
+			boost::shared_ptr<Payload> payload2(new RosterPayload());
+			RosterItemPayload item2(testling, "Bob", RosterItemPayload::Remove);
+			dynamic_cast<RosterPayload*>(payload2.get())->addItem(item2);
+			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload2));
+			CPPUNIT_ASSERT(!xmppRoster->containsJID(testling));
+		}
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(XMPPRosterControllerTest);
+
+
diff --git a/Swift/Controllers/XMPPRosterController.cpp b/Swift/Controllers/XMPPRosterController.cpp
new file mode 100644
index 0000000..6bbc964
--- /dev/null
+++ b/Swift/Controllers/XMPPRosterController.cpp
@@ -0,0 +1,57 @@
+#include "Swift/Controllers/XMPPRosterController.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/Base/foreach.h"
+#include "Swift/Controllers/MainWindow.h"
+#include "Swift/Controllers/MainWindowFactory.h"
+#include "Swiften/Elements/RosterItemPayload.h"
+#include "Swiften/Queries/IQRouter.h"
+#include "Swiften/Queries/Requests/GetRosterRequest.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+#include "Swiften/Roster/Roster.h"
+#include "Swiften/Roster/SetPresence.h"
+#include "Swiften/Roster/OfflineRosterFilter.h"
+#include "Swiften/Roster/OpenChatRosterAction.h"
+#include "Swiften/Roster/TreeWidgetFactory.h"
+#include "Swiften/Roster/XMPPRoster.h"
+
+namespace Swift {
+	
+/**
+ * The controller does not gain ownership of these parameters.
+ */
+XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, boost::shared_ptr<XMPPRoster> xmppRoster)
+ : IQHandler(iqRouter), iqRouter_(iqRouter), xmppRoster_(xmppRoster) {
+}
+
+XMPPRosterController::~XMPPRosterController() {
+
+}
+
+void XMPPRosterController::requestRoster() {
+	GetRosterRequest* rosterRequest = new GetRosterRequest(iqRouter_, Request::AutoDeleteAfterResponse);
+	rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1));
+	rosterRequest->send();
+}
+
+void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload) {
+	foreach(const RosterItemPayload& item, rosterPayload->getItems()) {
+		if (item.getSubscription() == RosterItemPayload::Remove) {
+			xmppRoster_->removeContact(item.getJID());
+		} else {
+			xmppRoster_->addContact(item.getJID(), item.getName(), item.getGroups());
+		}
+	}
+}
+
+bool XMPPRosterController::handleIQ(boost::shared_ptr<IQ> iq) {
+	if (iq->getType() != IQ::Set || iq->getPayload<RosterPayload>().get() == NULL || iq->getFrom().isValid()) {
+		return false;
+	}
+	handleRosterReceived(iq->getPayload<RosterPayload>());
+	return true;
+}
+
+}
+
diff --git a/Swift/Controllers/XMPPRosterController.h b/Swift/Controllers/XMPPRosterController.h
new file mode 100644
index 0000000..7695ff5
--- /dev/null
+++ b/Swift/Controllers/XMPPRosterController.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "Swiften/JID/JID.h"
+#include "Swiften/Base/String.h"
+#include "Swiften/Elements/IQ.h"
+#include "Swiften/Elements/RosterPayload.h"
+#include "Swiften/Queries/IQHandler.h"
+
+#include <boost/signals.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class IQRouter;
+	class XMPPRoster;
+
+	class XMPPRosterController : public IQHandler {
+		public:
+			XMPPRosterController(IQRouter *iqRouter, boost::shared_ptr<XMPPRoster> xmppRoster);
+			~XMPPRosterController();
+
+			void requestRoster();
+
+			boost::shared_ptr<XMPPRoster> getXMPPRoster() {return xmppRoster_;};
+			bool handleIQ(boost::shared_ptr<IQ>);
+
+		private:
+			IQRouter* iqRouter_;
+			void handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload);
+			boost::shared_ptr<XMPPRoster> xmppRoster_;
+	};
+}
+
diff --git a/Swift/Makefile.inc b/Swift/Makefile.inc
new file mode 100644
index 0000000..1a88144
--- /dev/null
+++ b/Swift/Makefile.inc
@@ -0,0 +1,2 @@
+include Swift/Controllers/Makefile.inc
+include Swift/QtUI/Makefile.inc
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index ef091e3..8b830d1 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -1,7 +1,7 @@
 #ifndef SWIFT_QtChatWindow_H
 #define SWIFT_QtChatWindow_H
 
-#include "Swiften/Controllers/ChatWindow.h"
+#include "Swift/Controllers/ChatWindow.h"
 
 #include <QWidget>
 
diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h
index 9e5004e..bda4c01 100644
--- a/Swift/QtUI/QtChatWindowFactory.h
+++ b/Swift/QtUI/QtChatWindowFactory.h
@@ -1,7 +1,7 @@
 #ifndef SWIFT_QtChatWindowFactory_H
 #define SWIFT_QtChatWindowFactory_H
 
-#include "Swiften/Controllers/ChatWindowFactory.h"
+#include "Swift/Controllers/ChatWindowFactory.h"
 #include "Swiften/JID/JID.h"
 
 namespace Swift {
diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h
index 5a14202..173a6b9 100644
--- a/Swift/QtUI/QtLoginWindow.h
+++ b/Swift/QtUI/QtLoginWindow.h
@@ -7,8 +7,8 @@
 #include <QCheckBox>
 #include <QStackedWidget>
 
-#include "Swiften/Controllers/LoginWindow.h"
-#include "Swiften/Controllers/MainWindow.h"
+#include "Swift/Controllers/LoginWindow.h"
+#include "Swift/Controllers/MainWindow.h"
 
 class QLabel;
 class QToolButton;
diff --git a/Swift/QtUI/QtLoginWindowFactory.h b/Swift/QtUI/QtLoginWindowFactory.h
index 52f92c8..17f2453 100644
--- a/Swift/QtUI/QtLoginWindowFactory.h
+++ b/Swift/QtUI/QtLoginWindowFactory.h
@@ -1,7 +1,7 @@
 #ifndef SWIFT_QtLoginWindowFactory_H
 #define SWIFT_QtLoginWindowFactory_H
 
-#include "Swiften/Controllers/LoginWindowFactory.h"
+#include "Swift/Controllers/LoginWindowFactory.h"
 
 namespace Swift {
 	class QtLoginWindowFactory : public LoginWindowFactory{
diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h
index fe5c8b4..6f4b5f7 100644
--- a/Swift/QtUI/QtMainWindow.h
+++ b/Swift/QtUI/QtMainWindow.h
@@ -3,7 +3,7 @@
 
 #include <QWidget>
 #include <QMenu>
-#include "Swiften/Controllers/MainWindow.h"
+#include "Swift/Controllers/MainWindow.h"
 
 #include <vector>
 
diff --git a/Swift/QtUI/QtMainWindowFactory.h b/Swift/QtUI/QtMainWindowFactory.h
index 86fc02f..1e45b23 100644
--- a/Swift/QtUI/QtMainWindowFactory.h
+++ b/Swift/QtUI/QtMainWindowFactory.h
@@ -1,7 +1,7 @@
 #ifndef SWIFT_QtMainWindowFactory_H
 #define SWIFT_QtMainWindowFactory_H
 
-#include "Swiften/Controllers/MainWindowFactory.h"
+#include "Swift/Controllers/MainWindowFactory.h"
 
 namespace Swift {
 	class QtTreeWidgetFactory;
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index e7d4152..b8b45a1 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -12,8 +12,8 @@
 #include "Swiften/Base/String.h"
 #include "Swiften/Elements/Presence.h"
 #include "Swiften/Client/Client.h"
-#include "Swiften/Controllers/ChatController.h"
-#include "Swiften/Controllers/MainController.h"
+#include "Swift/Controllers/ChatController.h"
+#include "Swift/Controllers/MainController.h"
 
 namespace Swift{
 
diff --git a/Swift/QtUI/Swift.pro b/Swift/QtUI/Swift.pro
index 16db0d1..1c860b4 100644
--- a/Swift/QtUI/Swift.pro
+++ b/Swift/QtUI/Swift.pro
@@ -27,7 +27,7 @@ win32 {
 else {
 	DEPENDPATH += . ../.. ../../3rdParty/Boost
 	INCLUDEPATH += . ../.. ../../3rdParty/Boost
-	LIBS += ../../Swiften/Swiften.a -lexpat -lssl -lcrypto
+	LIBS += ../Controllers/Controllers.a ../../Swiften/Swiften.a -lexpat -lssl -lcrypto
 	unix {
 		LIBS += -lresolv
 	}
diff --git a/Swift/QtUI/qmakeish.py b/Swift/QtUI/qmakeish.py
index 72a5f62..178696d 100755
--- a/Swift/QtUI/qmakeish.py
+++ b/Swift/QtUI/qmakeish.py
@@ -80,7 +80,7 @@ for line in makefile :
       continue
     
     match = re.match("(\w+)_SOURCES (\+?)= (.*)", line) 
-    if match and match.group(1) in ["SWIFTEN", "ZLIB", "LIBIDN", "BOOST", "EXPAT"] :
+    if match and match.group(1) in ["SWIFTEN", "ZLIB", "LIBIDN", "BOOST", "EXPAT", "SWIFT_CONTROLLERS"] :
       inSources = processSourcesLine(match.group(3))
       continue
 
diff --git a/Swiften/Controllers/ChatController.cpp b/Swiften/Controllers/ChatController.cpp
deleted file mode 100644
index bac73d4..0000000
--- a/Swiften/Controllers/ChatController.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "Swiften/Controllers/ChatController.h"
-
-#include "Swiften/Controllers/ChatWindow.h"
-#include "Swiften/Controllers/ChatWindowFactory.h"
-#include "Swiften/Controllers/NickResolver.h"
-
-namespace Swift {
-	
-/**
- * The controller does not gain ownership of the stanzaChannel, nor the factory.
- */
-ChatController::ChatController(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle)
- : ChatControllerBase(stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle) {
-	nickResolver_ = nickResolver;
-}
-
-bool ChatController::isIncomingMessageFromMe(boost::shared_ptr<Message>) {
-	return false;
-}
-
-void ChatController::preHandleIncomingMessage(boost::shared_ptr<Message> message) {
-	JID from = message->getFrom();
-	if (!from.equals(toJID_, JID::WithResource)) {
-		if (toJID_.equals(from, JID::WithoutResource)  && toJID_.isBare()){
-			toJID_ = from;
-		}
-	}
-}
-
-void ChatController::postSendMessage(const String& body) {
-	chatWindow_->addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>());
-}
-
-String ChatController::senderDisplayNameFromMessage(JID from) {
-	return nickResolver_->jidToNick(from);
-}
-
-}
diff --git a/Swiften/Controllers/ChatController.h b/Swiften/Controllers/ChatController.h
deleted file mode 100644
index 314bd70..0000000
--- a/Swiften/Controllers/ChatController.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef SWIFTEN_ChatController_H
-#define SWIFTEN_ChatController_H
-
-#include "Swiften/Controllers/ChatControllerBase.h"
-
-namespace Swift {
-	class NickResolver;
-	class ChatController : public ChatControllerBase {
-		public:
-			ChatController(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle);
-			~ChatController() {};
-			//boost::signal<void (const JID&, const JID&)> onJIDChanged;
-		protected:
-			bool isIncomingMessageFromMe(boost::shared_ptr<Message> message);
-			void postSendMessage(const String &body);
-			void preHandleIncomingMessage(boost::shared_ptr<Message> message);
-			String senderDisplayNameFromMessage(JID from);
-		private:
-			NickResolver* nickResolver_;
-			JID contact_;
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/ChatControllerBase.cpp b/Swiften/Controllers/ChatControllerBase.cpp
deleted file mode 100644
index 5f8535e..0000000
--- a/Swiften/Controllers/ChatControllerBase.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-#include "Swiften/Controllers/ChatControllerBase.h"
-
-#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include "Swiften/Client/StanzaChannel.h"
-#include "Swiften/Base/foreach.h"
-#include "Swiften/Controllers/ChatWindow.h"
-#include "Swiften/Controllers/ChatWindowFactory.h"
-#include "Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h"
-
-namespace Swift {
-
-ChatControllerBase::ChatControllerBase(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle) : stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle) {
-	chatWindow_ = chatWindowFactory_->createChatWindow(toJID);
-	chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
-	chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1));
-	presenceOracle_->onPresenceChange.connect(boost::bind(&ChatControllerBase::handlePresenceChange, this, _1, _2));
-}
-
-ChatControllerBase::~ChatControllerBase() {
-	delete chatWindow_;
-}
-	
-void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info) {
-	if (info->hasFeature(DiscoInfo::SecurityLabels)) {
-		chatWindow_->setSecurityLabelsEnabled(true);
-		chatWindow_->setSecurityLabelsError();
-		GetSecurityLabelsCatalogRequest* request = new GetSecurityLabelsCatalogRequest(JID(toJID_.toBare()), iqRouter_, Request::AutoDeleteAfterResponse);
-		request->onResponse.connect(boost::bind(&ChatControllerBase::handleSecurityLabelsCatalogResponse, this, _1, _2));
-		request->send();
-		labelsEnabled_ = true;
-	} else {
-		chatWindow_->setSecurityLabelsEnabled(false);
-		labelsEnabled_ = false;
-	}
-}
-
-String ChatControllerBase::getStatusChangeString(boost::shared_ptr<Presence> presence) {
-	String nick = senderDisplayNameFromMessage(presence->getFrom());
-	if (presence->getType() == Presence::Unavailable) {
-		return nick + " has gone offline.";
-	} else if (presence->getType() == Presence::Available) {
-		StatusShow::Type show = presence->getShow();
-		if (show == StatusShow::Online || show == StatusShow::FFC) {
-			return nick + " has become available.";
-		} else if (show == StatusShow::Away || show == StatusShow::XA) {
-			return nick + " has gone away.";
-		} else if (show == StatusShow::DND) {
-			return nick + " is now busy.";
-		} 
-	}
-
-	return "";
-}
-
-void ChatControllerBase::handlePresenceChange(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> previousPresence) {
-	if (!(toJID_.isBare() && newPresence->getFrom().equals(toJID_, JID::WithoutResource)) && newPresence->getFrom() != toJID_) {
-		return;
-	}
-	String newStatusChangeString = getStatusChangeString(newPresence);
-	if (previousPresence.get() == NULL || newStatusChangeString != getStatusChangeString(previousPresence)) {
-		chatWindow_->addSystemMessage(newStatusChangeString);
-	}
-}
-
-void ChatControllerBase::handleAllMessagesRead() {
-	foreach (boost::shared_ptr<MessageEvent> messageEvent, unreadMessages_) {
-		messageEvent->read();
-	}
-	unreadMessages_.clear();
-	chatWindow_->setUnreadMessageCount(0);
-}
-
-void ChatControllerBase::handleSendMessageRequest(const String &body) {
-	if (body.isEmpty()) {
-		return;
-	}
-	boost::shared_ptr<Message> message(new Message());
-	message->setTo(toJID_);
-	message->setType(Swift::Message::Chat);
-	message->setBody(body);
-	boost::optional<SecurityLabel> label;
-	if (labelsEnabled_) {
-		message->addPayload(boost::shared_ptr<SecurityLabel>(new SecurityLabel(chatWindow_->getSelectedSecurityLabel())));
-		label = boost::optional<SecurityLabel>(chatWindow_->getSelectedSecurityLabel());
-	}
-	preSendMessageRequest(message);
-	stanzaChannel_->sendMessage(message);
-	postSendMessage(message->getBody());
-}
-
-void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog> catalog, const boost::optional<Error>& error) {
-	if (!error) {
-		if (catalog->getLabels().size() == 0) {
-			chatWindow_->setSecurityLabelsEnabled(false);
-			labelsEnabled_ = false;
-		} else {
-			chatWindow_->setAvailableSecurityLabels(catalog->getLabels());
-			chatWindow_->setSecurityLabelsEnabled(true);
-		}
-	} else {
-		chatWindow_->setSecurityLabelsError();
-	}
-}
-
-void ChatControllerBase::showChatWindow() {
-	chatWindow_->show();
-}
-
-String ChatControllerBase::senderDisplayNameFromMessage(JID from) {
-	return from;
-}
-
-
-
-void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) {
-	unreadMessages_.push_back(messageEvent);
-	chatWindow_->setUnreadMessageCount(unreadMessages_.size());
-
-	boost::shared_ptr<Message> message = messageEvent->getStanza();
-	preHandleIncomingMessage(message);	
-	String body = message->getBody();
-	if (message->isError()) {
-		String errorMessage = getErrorMessage(message->getPayload<Error>());
-		chatWindow_->addErrorMessage(errorMessage);
-	}
-	else {
-		showChatWindow();
-		boost::shared_ptr<SecurityLabel> label = message->getPayload<SecurityLabel>();
-		boost::optional<SecurityLabel> maybeLabel = label ? boost::optional<SecurityLabel>(*label) : boost::optional<SecurityLabel>();
-		JID from = message->getFrom();
-		chatWindow_->addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), maybeLabel);
-	}
-}
-
-String ChatControllerBase::getErrorMessage(boost::shared_ptr<Error> error) {
-	String defaultMessage = "Error sending message";
-	if (!error->getText().isEmpty()) {
-		return error->getText();
-	}
-	else {
-		switch (error->getCondition()) {
-			case Error::BadRequest: return defaultMessage; break;
-			case Error::Conflict: return defaultMessage; break;
-			case Error::FeatureNotImplemented: return defaultMessage; break;
-			case Error::Forbidden: return defaultMessage; break;
-			case Error::Gone: return "Recipient can no longer be contacted"; break;
-			case Error::InternalServerError: return "Internal server error"; break;
-			case Error::ItemNotFound: return defaultMessage; break;
-			case Error::JIDMalformed: return defaultMessage; break;
-			case Error::NotAcceptable: return "Message was rejected"; break;
-			case Error::NotAllowed: return defaultMessage; break;
-			case Error::NotAuthorized: return defaultMessage; break;
-			case Error::PaymentRequired: return defaultMessage; break;
-			case Error::RecipientUnavailable: return "Recipient is unavailable."; break;
-			case Error::Redirect: return defaultMessage; break;
-			case Error::RegistrationRequired: return defaultMessage; break;
-			case Error::RemoteServerNotFound: return "Recipient's server not found."; break;
-			case Error::RemoteServerTimeout: return defaultMessage; break;
-			case Error::ResourceConstraint: return defaultMessage; break;
-			case Error::ServiceUnavailable: return defaultMessage; break;
-			case Error::SubscriptionRequired: return defaultMessage; break;
-			case Error::UndefinedCondition: return defaultMessage; break;
-			case Error::UnexpectedRequest: return defaultMessage; break;
-		}
-	}
-	return defaultMessage;
-}
-
-}
diff --git a/Swiften/Controllers/ChatControllerBase.h b/Swiften/Controllers/ChatControllerBase.h
deleted file mode 100644
index 1967977..0000000
--- a/Swiften/Controllers/ChatControllerBase.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef SWIFTEN_ChatControllerBase_H
-#define SWIFTEN_ChatControllerBase_H
-
-#include <map>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/signals.hpp>
-
-#include "Swiften/Base/String.h"
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swiften/Events/MessageEvent.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/Elements/SecurityLabelsCatalog.h"
-#include "Swiften/Elements/Error.h"
-#include "Swiften/Presence/PresenceOracle.h"
-
-namespace Swift {
-	class IQRouter;
-	class StanzaChannel;
-	class ChatWindow;
-	class ChatWindowFactory;
-
-	class ChatControllerBase  {
-		public:
-			virtual ~ChatControllerBase();
-			void showChatWindow();
-			void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
-			void handleIncomingMessage(boost::shared_ptr<MessageEvent> message);
-
-		protected:
-			ChatControllerBase(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle);
-			virtual void postSendMessage(const String&) {};
-			virtual String senderDisplayNameFromMessage(JID from);
-			void handlePresenceChange(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> previousPresence);
-			virtual bool isIncomingMessageFromMe(boost::shared_ptr<Message>) = 0;
-			virtual void preHandleIncomingMessage(boost::shared_ptr<Message>) {};
-			virtual void preSendMessageRequest(boost::shared_ptr<Message>) {};
-
-			std::vector<boost::shared_ptr<MessageEvent> > unreadMessages_;
-			StanzaChannel* stanzaChannel_;
-			IQRouter* iqRouter_;
-			ChatWindowFactory* chatWindowFactory_;
-			ChatWindow* chatWindow_;
-			JID toJID_;
-			bool labelsEnabled_;
-			PresenceOracle* presenceOracle_;
-
-		private:
-			void handleSendMessageRequest(const String &body);
-			String getStatusChangeString(boost::shared_ptr<Presence> presence);
-			void handleAllMessagesRead();
-			void handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog>, const boost::optional<Error>& error);
-			String getErrorMessage(boost::shared_ptr<Error>);
-	};
-}
-
-#endif
diff --git a/Swiften/Controllers/ChatWindow.h b/Swiften/Controllers/ChatWindow.h
deleted file mode 100644
index 04d0007..0000000
--- a/Swiften/Controllers/ChatWindow.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef SWIFTEN_CHATWINDOW_H
-#define SWIFTEN_CHATWINDOW_H
-
-#include <boost/optional.hpp>
-#include <boost/signals.hpp>
-#include <boost/shared_ptr.hpp>
-#include <vector>
-
-#include "Swiften/Base/String.h"
-#include "Swiften/Elements/SecurityLabel.h"
-
-namespace Swift {
-	class TreeWidget;
-	class ChatWindow {
-		public:
-			virtual ~ChatWindow() {};
-
-			virtual void addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label) = 0;
-			virtual void addSystemMessage(const String& message) = 0;
-			virtual void addErrorMessage(const String& message) = 0;
-
-			virtual void show() = 0;
-			virtual void setAvailableSecurityLabels(const std::vector<SecurityLabel>& labels) = 0;
-			virtual void setSecurityLabelsEnabled(bool enabled) = 0;
-			virtual void setUnreadMessageCount(int count) = 0;
-			virtual void convertToMUC() = 0;
-			virtual TreeWidget *getTreeWidget() = 0;
-			virtual void setSecurityLabelsError() = 0;
-			virtual SecurityLabel getSelectedSecurityLabel() = 0;
-
-			boost::signal<void ()> onClosed;
-			boost::signal<void ()> onAllMessagesRead;
-			boost::signal<void (const String&)> onSendMessageRequest;
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/ChatWindowFactory.h b/Swiften/Controllers/ChatWindowFactory.h
deleted file mode 100644
index c55ddba..0000000
--- a/Swiften/Controllers/ChatWindowFactory.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef SWIFTEN_CHATWINDOWFACTORY_H
-#define SWIFTEN_CHATWINDOWFACTORY_H
-
-#include "Swiften/JID/JID.h"
-
-namespace Swift {
-	class ChatWindow;
-
-	class ChatWindowFactory {
-		public:
-			virtual ~ChatWindowFactory() {};
-			/**
-			 * Transfers ownership of result.
-			 */
-			virtual ChatWindow* createChatWindow(const JID &contact) = 0;
-
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/EventController.cpp b/Swiften/Controllers/EventController.cpp
deleted file mode 100644
index a87f79a..0000000
--- a/Swiften/Controllers/EventController.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "Swiften/Controllers/EventController.h"
-
-#include <boost/bind.hpp>
-#include <algorithm>
-
-namespace Swift {
-
-void EventController::handleIncomingEvent(boost::shared_ptr<MessageEvent> event) {
-	if (event->isReadable()) {
-		events_.push_back(event);
-		event->onRead.connect(boost::bind(&EventController::handleEventRead, this, event));
-		onEventQueueLengthChange(events_.size());
-	}
-}
-
-void EventController::handleEventRead(boost::shared_ptr<MessageEvent> event) {
-	events_.erase(std::remove(events_.begin(), events_.end(), event), events_.end());
-	onEventQueueLengthChange(events_.size());
-}
-
-}
diff --git a/Swiften/Controllers/EventController.h b/Swiften/Controllers/EventController.h
deleted file mode 100644
index ab161af..0000000
--- a/Swiften/Controllers/EventController.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef SWIFTEN_EventController_H
-#define SWIFTEN_EventController_H
-
-
-#include <boost/signals.hpp>
-#include <boost/shared_ptr.hpp>
-#include <vector>
-
-#include "Swiften/Events/MessageEvent.h"
-
-namespace Swift {
-	class EventController {
-		public:
-			void handleIncomingEvent(boost::shared_ptr<MessageEvent> event);
-			boost::signal<void (int)> onEventQueueLengthChange;
-
-		private:
-			void handleEventRead(boost::shared_ptr<MessageEvent> event);
-			std::vector<boost::shared_ptr<MessageEvent> > events_;
-	};
-}
-#endif
-
-
diff --git a/Swiften/Controllers/LoginWindow.h b/Swiften/Controllers/LoginWindow.h
deleted file mode 100644
index 44855c0..0000000
--- a/Swiften/Controllers/LoginWindow.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef SWIFTEN_LoginWindow_H
-#define SWIFTEN_LoginWindow_H
-
-#include "Swiften/Base/String.h"
-
-#include <boost/signals.hpp>
-#include <boost/shared_ptr.hpp>
-
-namespace Swift {
-	class MainWindow;
-	class LoginWindow {
-		public:
-			virtual ~LoginWindow() {};
-			virtual void morphInto(MainWindow *mainWindow) = 0;
-			virtual void loggedOut() = 0;
-			virtual void setMessage(const String&) = 0;
-
-			boost::signal<void (const String&, const String&, const String& /* certificateFile */, bool)> onLoginRequest;
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/LoginWindowFactory.h b/Swiften/Controllers/LoginWindowFactory.h
deleted file mode 100644
index d52325e..0000000
--- a/Swiften/Controllers/LoginWindowFactory.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef SWIFTEN_LoginWindowFactory_H
-#define SWIFTEN_LoginWindowFactory_H
-
-
-
-namespace Swift {
-	class LoginWindow;
-    class String;
-    
-	class LoginWindowFactory {
-		public:
-			virtual ~LoginWindowFactory() {};
-
-			/**
-			 * Transfers ownership of result.
-			 */
-			virtual LoginWindow* createLoginWindow(const String& defaultJID, const String& defaultPassword, const String& defaultCertificate) = 0;
-
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/MUCController.cpp b/Swiften/Controllers/MUCController.cpp
deleted file mode 100644
index 8137fe1..0000000
--- a/Swiften/Controllers/MUCController.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "Swiften/Controllers/MUCController.h"
-
-#include <boost/bind.hpp>
-
-#include "Swiften/Base/foreach.h"
-#include "Swiften/Controllers/ChatWindow.h"
-#include "Swiften/Controllers/ChatWindowFactory.h"
-#include "Swiften/MUC/MUC.h"
-#include "Swiften/Client/StanzaChannel.h"
-#include "Swiften/Roster/Roster.h"
-#include "Swiften/Roster/SetPresence.h"
-#include "Swiften/Roster/TreeWidgetFactory.h"
-
-namespace Swift {
-	
-/**
- * The controller does not gain ownership of the stanzaChannel, nor the factory.
- */
-MUCController::MUCController (
-		const JID &muc, 
-		const String &nick, 
-		StanzaChannel* stanzaChannel, 
-		IQRouter* iqRouter, 
-		ChatWindowFactory* chatWindowFactory, 
-		TreeWidgetFactory *treeWidgetFactory,
-		PresenceOracle* presenceOracle) : 
-			ChatControllerBase(stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle),
-			muc_(new MUC(stanzaChannel, muc)), 
-			nick_(nick), 
-			treeWidgetFactory_(treeWidgetFactory) { 
-	roster_ = new Roster(chatWindow_->getTreeWidget(), treeWidgetFactory_);
-	chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this));
-	muc_->joinAs(nick);
-	muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
-	muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
-	muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
-	chatWindow_->convertToMUC();
-	chatWindow_->show();
-}
-
-MUCController::~MUCController() {
-	delete muc_;
-	//don't crash on exit by masking this. FIXME.
-	//delete roster_;
-}
-
-void MUCController::handleWindowClosed() {
-	muc_->part();
-}
-
-void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
-	roster_->addContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick()), occupant.getNick(), "Occupants");
-}
-
-void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType, const String& /*reason*/) {
-	roster_->removeContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick()));
-}
-
-void MUCController::handleOccupantPresenceChange(boost::shared_ptr<Presence> presence) {
-	roster_->applyOnItems(SetPresence(presence, JID::WithResource));
-}
-
-bool MUCController::isIncomingMessageFromMe(boost::shared_ptr<Message> message) {
-	JID from = message->getFrom();
-	return nick_ == from.getResource();
-}
-
-String MUCController::senderDisplayNameFromMessage(JID from) {
-	return from.getResource();
-}
-
-void MUCController::preSendMessageRequest(boost::shared_ptr<Message> message) {
-	message->setType(Swift::Message::Groupchat);
-}
-
-}
diff --git a/Swiften/Controllers/MUCController.h b/Swiften/Controllers/MUCController.h
deleted file mode 100644
index a7859cf..0000000
--- a/Swiften/Controllers/MUCController.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef SWIFTEN_MUCController_H
-#define SWIFTEN_MUCController_H
-
-#include <boost/shared_ptr.hpp>
-
-#include "Swiften/Base/String.h"
-#include "Swiften/Controllers/ChatControllerBase.h"
-#include "Swiften/Elements/Message.h"
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/MUC/MUC.h"
-#include "Swiften/MUC/MUCOccupant.h"
-
-namespace Swift {
-	class StanzaChannel;
-	class IQRouter;
-	class ChatWindow;
-	class ChatWindowFactory;
-	class Roster;
-	class TreeWidgetFactory;
-
-	class MUCController : public ChatControllerBase {
-		public:
-			MUCController(const JID &muc, const String &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle);
-			~MUCController();
-		
-		protected:
-			void preSendMessageRequest(boost::shared_ptr<Message> message);
-			bool isIncomingMessageFromMe(boost::shared_ptr<Message> message);
-			String senderDisplayNameFromMessage(JID from);
-		private:
-			void handleWindowClosed();
-			void handleOccupantJoined(const MUCOccupant& occupant);
-			void handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType type, const String& reason);
-			void handleOccupantPresenceChange(boost::shared_ptr<Presence> presence);
-			MUC *muc_;
-			String nick_;
-			TreeWidgetFactory *treeWidgetFactory_;
-			Roster *roster_;
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/MainController.cpp b/Swiften/Controllers/MainController.cpp
deleted file mode 100644
index 5535bf8..0000000
--- a/Swiften/Controllers/MainController.cpp
+++ /dev/null
@@ -1,260 +0,0 @@
-#include "Swiften/Controllers/MainController.h"
-
-#include <boost/bind.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/shared_ptr.hpp>
-#include <stdlib.h>
-
-#include "Swiften/Application/Application.h"
-#include "Swiften/Application/ApplicationMessageDisplay.h"
-#include "Swiften/Controllers/ChatController.h"
-#include "Swiften/Controllers/ChatWindowFactory.h"
-#include "Swiften/Controllers/EventController.h"
-#include "Swiften/Controllers/LoginWindow.h"
-#include "Swiften/Controllers/LoginWindowFactory.h"
-#include "Swiften/Controllers/MainWindow.h"
-#include "Swiften/Controllers/MainWindowFactory.h"
-#include "Swiften/Controllers/MUCController.h"
-#include "Swiften/Controllers/NickResolver.h"
-#include "Swiften/Controllers/RosterController.h"
-#include "Swiften/Controllers/XMPPRosterController.h"
-#include "Swiften/Base/foreach.h"
-#include "Swiften/Base/String.h"
-#include "Swiften/Client/Client.h"
-#include "Swiften/Elements/Presence.h"
-#include "Swiften/Roster/XMPPRoster.h"
-#include "Swiften/Queries/Responders/SoftwareVersionResponder.h"
-#include "Swiften/Roster/TreeWidgetFactory.h"
-#include "Swiften/Settings/SettingsProvider.h"
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swiften/Queries/Responders/DiscoInfoResponder.h"
-#include "Swiften/Disco/CapsInfoGenerator.h"
-#include "Swiften/Queries/Requests/GetDiscoInfoRequest.h"
-
-namespace Swift {
-
-static const String CLIENT_NAME = "Swift";
-static const String CLIENT_VERSION = "0.3";
-static const String CLIENT_NODE = "http://swift.im";
-
-typedef std::pair<JID, ChatController*> JIDChatControllerPair;
-typedef std::pair<JID, MUCController*> JIDMUCControllerPair;
-
-MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory *treeWidgetFactory, SettingsProvider *settings, Application* application)
-		: client_(NULL), chatWindowFactory_(chatWindowFactory), mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), treeWidgetFactory_(treeWidgetFactory), settings_(settings),
-		xmppRosterController_(NULL), rosterController_(NULL), loginWindow_(NULL), clientVersionResponder_(NULL), nickResolver_(NULL), discoResponder_(NULL), 
-		serverDiscoInfo_(new DiscoInfo()), presenceOracle_(NULL) {
-	application_ = application;
-	eventController_ = new EventController();
-	eventController_->onEventQueueLengthChange.connect(boost::bind(&MainController::handleEventQueueLengthChange, this, _1));
-	loginWindow_ = loginWindowFactory_->createLoginWindow(settings->getStringSetting("jid"), settings->getStringSetting("pass"), settings->getStringSetting("certificate"));
-	loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4));
-}
-
-MainController::~MainController() {
-	delete discoResponder_;
-	delete clientVersionResponder_;
-	delete xmppRosterController_;
-	delete rosterController_;
-	foreach (JIDChatControllerPair controllerPair, chatControllers_) {
-		delete controllerPair.second;
-	}
-	foreach (JIDMUCControllerPair controllerPair, mucControllers_) {
-		delete controllerPair.second;
-	}
-	delete presenceOracle_;
-	delete nickResolver_;
-	delete client_;
-}
-
-void MainController::handleConnected() {
-	delete presenceOracle_;
-	presenceOracle_ = new PresenceOracle(client_);
-
-	client_->onPresenceReceived.connect(boost::bind(&MainController::handleIncomingPresence, this, _1));
-
-	boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
-
-
-	delete nickResolver_;
-	nickResolver_ = new NickResolver(xmppRoster);
-
-	delete rosterController_;
-	rosterController_ = new RosterController(xmppRoster, mainWindowFactory_, treeWidgetFactory_);
-	rosterController_->onStartChatRequest.connect(boost::bind(&MainController::handleChatRequest, this, _1));
-	rosterController_->onJoinMUCRequest.connect(boost::bind(&MainController::handleJoinMUCRequest, this, _1, _2));
-	rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
-
-	delete xmppRosterController_;
-	xmppRosterController_ = new XMPPRosterController(client_, xmppRoster);
-	xmppRosterController_->requestRoster();
-
-	delete clientVersionResponder_;
-	clientVersionResponder_ = new SoftwareVersionResponder(CLIENT_NAME, CLIENT_VERSION, client_);
-	loginWindow_->morphInto(rosterController_->getWindow());
-
-	DiscoInfo discoInfo;
-	discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc"));
-	capsInfo_ = boost::shared_ptr<CapsInfo>(new CapsInfo(CapsInfoGenerator(CLIENT_NODE).generateCapsInfo(discoInfo)));
-	discoResponder_ = new DiscoInfoResponder(client_);
-	discoResponder_->setDiscoInfo(discoInfo);
-	discoResponder_->setDiscoInfo(capsInfo_->getNode() + "#" + capsInfo_->getVersion(), discoInfo);
-
-	serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo());
-	GetDiscoInfoRequest* discoInfoRequest = new GetDiscoInfoRequest(JID(), client_, Request::AutoDeleteAfterResponse);
-	discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2));
-	discoInfoRequest->send();
-	
-	//Send presence last to catch all the incoming presences.
-	boost::shared_ptr<Presence> initialPresence(new Presence());
-	initialPresence->addPayload(capsInfo_);
-	client_->sendPresence(initialPresence);
-}
-
-void MainController::handleEventQueueLengthChange(int count) {
-	application_->getApplicationMessageDisplay()->setMessage(count == 0 ? "" : boost::lexical_cast<std::string>(count).c_str());
-}
-
-void MainController::handleChangeStatusRequest(StatusShow::Type show, const String &statusText) {
-	boost::shared_ptr<Presence> presence(new Presence());
-	presence->addPayload(capsInfo_);
-	presence->setShow(show);
-	presence->setStatus(statusText);
-	// FIXME: This is wrong. None doesn't mean unavailable
-	if (show == StatusShow::None) {
-		presence->setType(Presence::Unavailable);
-	}
-	client_->sendPresence(presence);
-	if (presence->getType() == Presence::Unavailable) {
-		logout();
-	}
-}
-
-void MainController::handleIncomingPresence(boost::shared_ptr<Presence> presence) {
-	rosterController_->handleIncomingPresence(presence);
-}
-
-void MainController::handleLoginRequest(const String &username, const String &password, const String& certificateFile, bool remember) {
-	loginWindow_->setMessage("");
-
-	settings_->storeString("jid", username);
-	settings_->storeString("certificate", certificateFile);
-	settings_->storeString("pass", remember ? password : "");
-
-	delete client_;
-	client_ = new Swift::Client(JID(username), password);
-	if (!certificateFile.isEmpty()) {
-		client_->setCertificate(certificateFile);
-	}
-	client_->onError.connect(boost::bind(&MainController::handleError, this, _1));
-	client_->onConnected.connect(boost::bind(&MainController::handleConnected, this));
-	client_->onMessageReceived.connect(boost::bind(&MainController::handleIncomingMessage, this, _1));
-	client_->connect();
-}
-
-void MainController::handleError(const ClientError& error) {
-	String message;
-	switch(error.getType()) {
-		case ClientError::NoError: assert(false); break;
-		case ClientError::DomainNameResolveError: message = "Unable to find server"; break;
-		case ClientError::ConnectionError: message = "Error connecting to server"; break;
-		case ClientError::ConnectionReadError: message = "Error while receiving server data"; break;
-		case ClientError::XMLError: message = "Error parsing server data"; break;
-		case ClientError::AuthenticationFailedError: message = "Login/password invalid"; break;
-		case ClientError::NoSupportedAuthMechanismsError: message = "Authentication mechanisms not supported"; break;
-		case ClientError::UnexpectedElementError: message = "Unexpected response"; break;
-		case ClientError::ResourceBindError: message = "Error binding resource"; break;
-		case ClientError::SessionStartError: message = "Error starting session"; break;
-		case ClientError::TLSError: message = "Encryption error"; break;
-		case ClientError::ClientCertificateLoadError: message = "Error loading certificate (Invalid password?)"; break;
-		case ClientError::ClientCertificateError: message = "Certificate not authorized"; break;
-	}
-	loginWindow_->setMessage(message);
-	logout();
-}
-
-void MainController::logout() {
-	loginWindow_->loggedOut();
-
-	delete discoResponder_;
-	discoResponder_ = NULL;
-	delete clientVersionResponder_;
-	clientVersionResponder_ = NULL;
-	foreach (JIDChatControllerPair controllerPair, chatControllers_) {
-		delete controllerPair.second;
-	}
-	client_->disconnect();
-	chatControllers_.clear();
-	foreach (JIDMUCControllerPair controllerPair, mucControllers_) {
-		delete controllerPair.second;
-	}
-	mucControllers_.clear();
-}
-
-
-void MainController::handleChatRequest(const String &contact) {
-	getChatController(JID(contact))->showChatWindow();
-}
-
-ChatController* MainController::getChatController(const JID &contact) {
-	JID lookupContact(contact);
-	if (chatControllers_.find(lookupContact) == chatControllers_.end()) {
-		lookupContact = JID(contact.toBare());
-	}
-	if (chatControllers_.find(lookupContact) == chatControllers_.end()) {
-		chatControllers_[contact] = new ChatController(client_, client_, chatWindowFactory_, contact, nickResolver_, presenceOracle_);
-		chatControllers_[contact]->setAvailableServerFeatures(serverDiscoInfo_);
-		lookupContact = contact;
-	}
-	return chatControllers_[lookupContact];
-}
-
-void MainController::handleChatControllerJIDChanged(const JID& from, const JID& to) {
-	chatControllers_[to] = chatControllers_[from];
-	chatControllers_.erase(from);
-}
-
-void MainController::handleJoinMUCRequest(const JID &muc, const String &nick) {
-	mucControllers_[muc] = new MUCController(muc, nick, client_, client_, chatWindowFactory_, treeWidgetFactory_, presenceOracle_);
-	mucControllers_[muc]->setAvailableServerFeatures(serverDiscoInfo_);
-}
-
-void MainController::handleIncomingMessage(boost::shared_ptr<Message> message) {
-	JID jid = message->getFrom();
-	boost::shared_ptr<MessageEvent> event(new MessageEvent(message));
-
-	// Try to deliver it to a MUC
-	if (message->getType() == Message::Groupchat || message->getType() == Message::Error) {
-		std::map<JID, MUCController*>::iterator i = mucControllers_.find(jid.toBare());
-		if (i != mucControllers_.end()) {
-			i->second->handleIncomingMessage(event);
-			return;
-		}
-		else if (message->getType() == Message::Groupchat) {
-			//FIXME: Error handling - groupchat messages from an unknown muc.
-			return;
-		}
-	}
-	
-	//if not a mucroom
-	eventController_->handleIncomingEvent(event);
-
-	// FIXME: This logic should go into a chat manager
-	if (event->isReadable()) {
-		getChatController(jid)->handleIncomingMessage(event);
-	}
-}
-
-void MainController::handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, const boost::optional<Error>& error) {
-	if (!error) {
-		serverDiscoInfo_ = info;
-		foreach (JIDChatControllerPair pair, chatControllers_) {
-			pair.second->setAvailableServerFeatures(info);
-		}
-		foreach (JIDMUCControllerPair pair, mucControllers_) {
-			pair.second->setAvailableServerFeatures(info);
-		}
-	}
-}
-
-}
diff --git a/Swiften/Controllers/MainController.h b/Swiften/Controllers/MainController.h
deleted file mode 100644
index e09d4fa..0000000
--- a/Swiften/Controllers/MainController.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef SWIFTEN_MainController_H
-#define SWIFTEN_MainController_H
-
-
-#include "Swiften/Base/String.h"
-#include "Swiften/Client/ClientError.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swiften/Elements/Error.h"
-#include "Swiften/Elements/Presence.h"
-#include "Swiften/Elements/Message.h"
-#include "Swiften/Settings/SettingsProvider.h"
-#include "Swiften/Elements/CapsInfo.h"
-
-
-#include <boost/signals.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <vector>
-
-namespace Swift {
-	class Application;
-	class Client;
-	class ChatWindowFactory;
-	class ChatController;
-	class EventController;
-	class MainWindowFactory;
-	class MainWindow;
-	class NickResolver;
-	class RosterController;
-	class XMPPRosterController;
-	class DiscoInfoResponder;
-	class LoginWindow;
-	class EventLoop;
-	class SoftwareVersionResponder;
-	class LoginWindowFactory;
-	class TreeWidgetFactory;
-	class MUCController;
-	class PresenceOracle;
-
-	class MainController {
-		public:
-			MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory* treeWidgetFactory, SettingsProvider *settings, Application* application);
-			~MainController();
-
-
-		private:
-			void handleConnected();
-			void handleLoginRequest(const String& username, const String& password, const String& certificateFile, bool remember);
-			void handleChatRequest(const String& contact);
-			void handleJoinMUCRequest(const JID& muc, const String& nick);
-			void handleIncomingPresence(boost::shared_ptr<Presence> presence);
-			void handleChatControllerJIDChanged(const JID& from, const JID& to);
-			void handleIncomingMessage(boost::shared_ptr<Message> message);
-			void handleChangeStatusRequest(StatusShow::Type show, const String &statusText);
-			void handleError(const ClientError& error);
-			void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, const boost::optional<Error>&);
-			void handleEventQueueLengthChange(int count);
-			ChatController* getChatController(const JID &contact);
-			void logout();
-			
-			Client* client_;
-			ChatWindowFactory* chatWindowFactory_;
-			MainWindowFactory* mainWindowFactory_;
-			LoginWindowFactory* loginWindowFactory_;
-			TreeWidgetFactory* treeWidgetFactory_;
-			SettingsProvider *settings_;
-			Application* application_;
-			ChatController* chatController_;
-			XMPPRosterController* xmppRosterController_;
-			RosterController* rosterController_;
-			EventController* eventController_;
-			LoginWindow* loginWindow_;
-			SoftwareVersionResponder* clientVersionResponder_;
-			NickResolver* nickResolver_;
-			DiscoInfoResponder* discoResponder_;
-			boost::shared_ptr<CapsInfo> capsInfo_;
-			std::map<JID, MUCController*> mucControllers_;
-			std::map<JID, ChatController*> chatControllers_;
-			boost::shared_ptr<DiscoInfo> serverDiscoInfo_;
-			PresenceOracle* presenceOracle_;
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/MainWindow.h b/Swiften/Controllers/MainWindow.h
deleted file mode 100644
index 081fe6e..0000000
--- a/Swiften/Controllers/MainWindow.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef SWIFTEN_MainWindow_H
-#define SWIFTEN_MainWindow_H
-
-#include "Swiften/Base/String.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/Elements/StatusShow.h"
-
-#include <boost/signals.hpp>
-#include <boost/shared_ptr.hpp>
-
-namespace Swift {
-	class TreeWidget;
-
-	class MainWindow {
-		public:
-			virtual ~MainWindow() {};
-			virtual TreeWidget* getTreeWidget() = 0;
-			
-			boost::signal<void (const JID&)> onStartChatRequest;
-			boost::signal<void (const JID&, const String&)> onJoinMUCRequest;
-			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;
-			boost::signal<void (bool)> onShowOfflineToggled;
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/MainWindowFactory.h b/Swiften/Controllers/MainWindowFactory.h
deleted file mode 100644
index cf5a061..0000000
--- a/Swiften/Controllers/MainWindowFactory.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef SWIFTEN_MainWindowFactory_H
-#define SWIFTEN_MainWindowFactory_H
-
-#include "Swiften/JID/JID.h"
-
-namespace Swift {
-	class MainWindow;
-
-	class MainWindowFactory {
-		public:
-			virtual ~MainWindowFactory() {};
-			/**
-			 * Transfers ownership of result.
-			 */
-			virtual MainWindow* createMainWindow() = 0;
-
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/Makefile.inc b/Swiften/Controllers/Makefile.inc
deleted file mode 100644
index c51b0f3..0000000
--- a/Swiften/Controllers/Makefile.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-SWIFTEN_SOURCES += \
-	Swiften/Controllers/ChatController.cpp \
-	Swiften/Controllers/ChatControllerBase.cpp \
-	Swiften/Controllers/MainController.cpp \
-	Swiften/Controllers/NickResolver.cpp \
-	Swiften/Controllers/RosterController.cpp \
-	Swiften/Controllers/XMPPRosterController.cpp \
-	Swiften/Controllers/MUCController.cpp \
-	Swiften/Controllers/EventController.cpp
-
-include Swiften/Controllers/UnitTest/Makefile.inc
diff --git a/Swiften/Controllers/NickResolver.cpp b/Swiften/Controllers/NickResolver.cpp
deleted file mode 100644
index 1c51cb7..0000000
--- a/Swiften/Controllers/NickResolver.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "Swiften/Controllers/NickResolver.h"
-
-#include <boost/shared_ptr.hpp>
-
-#include "Swiften/Roster/XMPPRoster.h"
-
-namespace Swift {
-
-NickResolver::NickResolver(boost::shared_ptr<XMPPRoster> xmppRoster) {
-	xmppRoster_ = xmppRoster;
-}
-
-String NickResolver::jidToNick(const JID& jid) {
-	if (xmppRoster_->containsJID(jid)) {
-		return xmppRoster_->getNameForJID(jid);
-	}
-	std::map<JID, String>::iterator it = map_.find(jid);
-	return (it == map_.end()) ? jid.toBare() : it->second;
-}
-
-}
-
diff --git a/Swiften/Controllers/NickResolver.h b/Swiften/Controllers/NickResolver.h
deleted file mode 100644
index b7dc005..0000000
--- a/Swiften/Controllers/NickResolver.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef SWIFTEN_NickResolver_H
-#define SWIFTEN_NickResolver_H
-
-#include <map>
-#include <boost/shared_ptr.hpp>
-
-#include "Swiften/Base/String.h"
-#include "Swiften/JID/JID.h"
-
-namespace Swift {
-	class XMPPRoster;
-	class NickResolver {
-		public:
-			NickResolver(boost::shared_ptr<XMPPRoster> xmppRoster);
-			String jidToNick(const JID& jid);
-		
-		private:
-			std::map<JID, String> map_;
-			boost::shared_ptr<XMPPRoster> xmppRoster_;
-	};
-}
-#endif
-
-
diff --git a/Swiften/Controllers/RosterController.cpp b/Swiften/Controllers/RosterController.cpp
deleted file mode 100644
index 1efbeea..0000000
--- a/Swiften/Controllers/RosterController.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-#include "Swiften/Controllers/RosterController.h"
-
-#include <boost/bind.hpp>
-
-#include "Swiften/Base/foreach.h"
-#include "Swiften/Controllers/MainWindow.h"
-#include "Swiften/Controllers/MainWindowFactory.h"
-#include "Swiften/Queries/Requests/GetRosterRequest.h"
-#include "Swiften/EventLoop/MainEventLoop.h"
-#include "Swiften/Roster/Roster.h"
-#include "Swiften/Roster/SetPresence.h"
-#include "Swiften/Roster/OfflineRosterFilter.h"
-#include "Swiften/Roster/OpenChatRosterAction.h"
-#include "Swiften/Roster/TreeWidgetFactory.h"
-#include "Swiften/Roster/XMPPRoster.h"
-
-namespace Swift {
-	
-/**
- * The controller does not gain ownership of these parameters.
- */
-RosterController::RosterController(boost::shared_ptr<XMPPRoster> xmppRoster, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory)
- : xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), treeWidgetFactory_(treeWidgetFactory), mainWindow_(mainWindowFactory_->createMainWindow()), roster_(new Roster(mainWindow_->getTreeWidget(), treeWidgetFactory_)), offlineFilter_(new OfflineRosterFilter()) {
-	roster_->addFilter(offlineFilter_);
-	mainWindow_->onStartChatRequest.connect(boost::bind(&RosterController::handleStartChatRequest, this, _1));
-	mainWindow_->onJoinMUCRequest.connect(boost::bind(&RosterController::handleJoinMUCRequest, this, _1, _2));
-	mainWindow_->onChangeStatusRequest.connect(boost::bind(&RosterController::handleChangeStatusRequest, this, _1, _2));
-	mainWindow_->onShowOfflineToggled.connect(boost::bind(&RosterController::handleShowOfflineToggled, this, _1));
-	roster_->onUserAction.connect(boost::bind(&RosterController::handleUserAction, this, _1));
-	xmppRoster_->onJIDAdded.connect(boost::bind(&RosterController::handleOnJIDAdded, this, _1));
-}
-
-RosterController::~RosterController() {
-	delete offlineFilter_;
-
-}
-
-void RosterController::handleShowOfflineToggled(bool state) {
-	if (state) {
-		roster_->removeFilter(offlineFilter_);
-	} else {
-		roster_->addFilter(offlineFilter_);
-	}
-}
-
-void RosterController::handleChangeStatusRequest(StatusShow::Type show, const String &statusText) {
-	onChangeStatusRequest(show, statusText);
-}
-
-void RosterController::handleUserAction(boost::shared_ptr<UserRosterAction> action) {
-	boost::shared_ptr<OpenChatRosterAction> chatAction = boost::dynamic_pointer_cast<OpenChatRosterAction>(action);
-	if (chatAction.get() != NULL) {
-		ContactRosterItem *contactItem = dynamic_cast<ContactRosterItem*>(chatAction->getRosterItem());
-		assert(contactItem);
-		onStartChatRequest(contactItem->getJID().toBare());
-	}
-}
-
-void RosterController::handleOnJIDAdded(const JID& jid) {
-	std::vector<String> groups = xmppRoster_->getGroupsForJID(jid);
-	String name = xmppRoster_->getNameForJID(jid);
-	if (!groups.empty()) {
-		foreach(const String& group, groups) {
-			roster_->addContact(jid, name, group);
-		}
-	} else {
-		roster_->addContact(jid, name, "Contacts");
-	}
-}
-
-void RosterController::handleIncomingPresence(boost::shared_ptr<Presence> presence) {
-	roster_->applyOnItems(SetPresence(presence));
-}
-
-void RosterController::handleStartChatRequest(const JID& contact) {
-	onStartChatRequest(contact);
-}
-
-void RosterController::handleJoinMUCRequest(const JID &muc, const String &nick) {
-	onJoinMUCRequest(JID(muc), nick);
-}
-
-}
diff --git a/Swiften/Controllers/RosterController.h b/Swiften/Controllers/RosterController.h
deleted file mode 100644
index 945b068..0000000
--- a/Swiften/Controllers/RosterController.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef SWIFTEN_RosterController_H
-#define SWIFTEN_RosterController_H
-
-#include "Swiften/JID/JID.h"
-#include "Swiften/Base/String.h"
-#include "Swiften/Elements/Presence.h"
-#include "Swiften/Roster/UserRosterAction.h"
-
-#include <boost/signals.hpp>
-#include <boost/shared_ptr.hpp>
-
-namespace Swift {
-	class IQRouter;
-	class Roster;
-	class XMPPRoster;
-	class MainWindow;
-	class MainWindowFactory;
-	class TreeWidgetFactory;
-	class OfflineRosterFilter;
-
-	class RosterController {
-		public:
-			RosterController(boost::shared_ptr<XMPPRoster> xmppRoster, MainWindowFactory *mainWindowFactory, TreeWidgetFactory *treeWidgetFactory);
-			~RosterController();
-			void showRosterWindow();
-			MainWindow* getWindow() {return mainWindow_;};
-			boost::signal<void (const JID&)> onStartChatRequest;
-			boost::signal<void (const JID&, const String&)> onJoinMUCRequest;
-			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;
-			void handleIncomingPresence(boost::shared_ptr<Presence> presence);
-
-		private:
-			void handleOnJIDAdded(const JID &jid);
-			void handleStartChatRequest(const JID& contact);
-			void handleJoinMUCRequest(const JID &muc, const String &nick);
-			void handleUserAction(boost::shared_ptr<UserRosterAction> action);
-			void handleChangeStatusRequest(StatusShow::Type show, const String &statusText);
-			void handleShowOfflineToggled(bool state);
-			boost::shared_ptr<XMPPRoster> xmppRoster_;
-			MainWindowFactory* mainWindowFactory_;
-			TreeWidgetFactory* treeWidgetFactory_;
-			MainWindow* mainWindow_;
-			Roster* roster_;
-			OfflineRosterFilter* offlineFilter_;
-	};
-}
-#endif
-
diff --git a/Swiften/Controllers/UnitTest/Makefile.inc b/Swiften/Controllers/UnitTest/Makefile.inc
deleted file mode 100644
index 163da01..0000000
--- a/Swiften/Controllers/UnitTest/Makefile.inc
+++ /dev/null
@@ -1,4 +0,0 @@
-UNITTEST_SOURCES += \
-	Swiften/Controllers/UnitTest/NickResolverTest.cpp \
-	Swiften/Controllers/UnitTest/XMPPRosterControllerTest.cpp
-
diff --git a/Swiften/Controllers/UnitTest/NickResolverTest.cpp b/Swiften/Controllers/UnitTest/NickResolverTest.cpp
deleted file mode 100644
index 9c89d4d..0000000
--- a/Swiften/Controllers/UnitTest/NickResolverTest.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
-
-#include "Swiften/Controllers/NickResolver.h"
-#include "Swiften/Roster/XMPPRoster.h"
-
-using namespace Swift;
-
-class NickResolverTest : public CppUnit::TestFixture
-{
-		CPPUNIT_TEST_SUITE(NickResolverTest);
-		CPPUNIT_TEST(testNoMatch);
-		CPPUNIT_TEST(testMatch);
-		CPPUNIT_TEST(testOverwrittenMatch);
-		CPPUNIT_TEST(testRemovedMatch);
-		CPPUNIT_TEST_SUITE_END();
-
-		std::vector<String> groups_;
-
-	public:
-		NickResolverTest() {}
-
-		void testNoMatch() {
-			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
-			NickResolver resolver(xmppRoster);
-			JID testling("foo@bar/baz");
-
-			CPPUNIT_ASSERT_EQUAL(String("foo@bar"), resolver.jidToNick(testling));
-		}
-
-		void testMatch() {
-			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
-			NickResolver resolver(xmppRoster);
-			JID testling("foo@bar/baz");
-			xmppRoster->addContact(testling, "Test", groups_);
-
-			CPPUNIT_ASSERT_EQUAL(String("Test"), resolver.jidToNick(testling));
-		}
-
-		void testOverwrittenMatch() {
-			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
-			NickResolver resolver(xmppRoster);
-			JID testling("foo@bar/baz");
-			xmppRoster->addContact(testling, "FailTest", groups_);
-			xmppRoster->addContact(testling, "Test", groups_);
-
-			CPPUNIT_ASSERT_EQUAL(String("Test"), resolver.jidToNick(testling));
-		}
-
-		void testRemovedMatch() {
-			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
-			NickResolver resolver(xmppRoster);
-			JID testling("foo@bar/baz");
-			xmppRoster->addContact(testling, "FailTest", groups_);
-			xmppRoster->removeContact(testling);
-			CPPUNIT_ASSERT_EQUAL(String("foo@bar"), resolver.jidToNick(testling));
-		}
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(NickResolverTest);
-
diff --git a/Swiften/Controllers/UnitTest/XMPPRosterControllerTest.cpp b/Swiften/Controllers/UnitTest/XMPPRosterControllerTest.cpp
deleted file mode 100644
index 17cc31c..0000000
--- a/Swiften/Controllers/UnitTest/XMPPRosterControllerTest.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
-
-#include "Swiften/Controllers/XMPPRosterController.h"
-#include "Swiften/Elements/Payload.h"
-#include "Swiften/Elements/RosterItemPayload.h"
-#include "Swiften/Elements/RosterPayload.h"
-#include "Swiften/Queries/DummyIQChannel.h"
-#include "Swiften/Queries/IQRouter.h"
-#include "Swiften/Roster/XMPPRoster.h"
-
-using namespace Swift;
-
-class XMPPRosterControllerTest : public CppUnit::TestFixture
-{
-		CPPUNIT_TEST_SUITE(XMPPRosterControllerTest);
-		CPPUNIT_TEST(testAdd);
-		CPPUNIT_TEST(testModify);
-		CPPUNIT_TEST(testRemove);
-		CPPUNIT_TEST_SUITE_END();
-
-		DummyIQChannel* channel_;
-		IQRouter* router_;
-	public:
-		XMPPRosterControllerTest() {}
-
-		void setUp() {
-			channel_ = new DummyIQChannel();
-			router_ = new IQRouter(channel_);
-		}
-
-		void tearDown() {
-			delete channel_;
-			delete router_;
-		}
-
-		void testAdd() {
-			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
-			XMPPRosterController controller(router_, xmppRoster);
-			JID testling("foo@bar");
-			CPPUNIT_ASSERT(!xmppRoster->containsJID(testling));
-			boost::shared_ptr<Payload> payload(new RosterPayload());
-			RosterItemPayload item(testling, "Bob", RosterItemPayload::Both);
-			dynamic_cast<RosterPayload*>(payload.get())->addItem(item);
-			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload));
-			CPPUNIT_ASSERT(xmppRoster->containsJID(testling));
-		}
-
-		void testModify() {
-			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
-			XMPPRosterController controller(router_, xmppRoster);
-			JID testling("foo@bar");
-			CPPUNIT_ASSERT(!xmppRoster->containsJID(testling));
-			boost::shared_ptr<Payload> payload1(new RosterPayload());
-			RosterItemPayload item1(testling, "Bob", RosterItemPayload::Both);
-			dynamic_cast<RosterPayload*>(payload1.get())->addItem(item1);
-			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload1));
-			CPPUNIT_ASSERT(xmppRoster->containsJID(testling));
-			CPPUNIT_ASSERT_EQUAL(String("Bob"), xmppRoster->getNameForJID(testling));
-			boost::shared_ptr<Payload> payload2(new RosterPayload());
-			RosterItemPayload item2(testling, "Bob2", RosterItemPayload::Both);
-			dynamic_cast<RosterPayload*>(payload2.get())->addItem(item2);
-			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload2));
-			CPPUNIT_ASSERT_EQUAL(String("Bob2"), xmppRoster->getNameForJID(testling));
-		}
-
-		void testRemove() {
-			boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
-			XMPPRosterController controller(router_, xmppRoster);
-			JID testling("foo@bar");
-			CPPUNIT_ASSERT(!xmppRoster->containsJID(testling));
-			boost::shared_ptr<Payload> payload1(new RosterPayload());
-			RosterItemPayload item1(testling, "Bob", RosterItemPayload::Both);
-			dynamic_cast<RosterPayload*>(payload1.get())->addItem(item1);
-			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload1));
-			CPPUNIT_ASSERT(xmppRoster->containsJID(testling));
-			boost::shared_ptr<Payload> payload2(new RosterPayload());
-			RosterItemPayload item2(testling, "Bob", RosterItemPayload::Remove);
-			dynamic_cast<RosterPayload*>(payload2.get())->addItem(item2);
-			controller.handleIQ(IQ::createRequest(IQ::Set, JID(), "eou", payload2));
-			CPPUNIT_ASSERT(!xmppRoster->containsJID(testling));
-		}
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(XMPPRosterControllerTest);
-
-
diff --git a/Swiften/Controllers/XMPPRosterController.cpp b/Swiften/Controllers/XMPPRosterController.cpp
deleted file mode 100644
index d1e6f80..0000000
--- a/Swiften/Controllers/XMPPRosterController.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "Swiften/Controllers/XMPPRosterController.h"
-
-#include <boost/bind.hpp>
-
-#include "Swiften/Base/foreach.h"
-#include "Swiften/Controllers/MainWindow.h"
-#include "Swiften/Controllers/MainWindowFactory.h"
-#include "Swiften/Elements/RosterItemPayload.h"
-#include "Swiften/Queries/IQRouter.h"
-#include "Swiften/Queries/Requests/GetRosterRequest.h"
-#include "Swiften/EventLoop/MainEventLoop.h"
-#include "Swiften/Roster/Roster.h"
-#include "Swiften/Roster/SetPresence.h"
-#include "Swiften/Roster/OfflineRosterFilter.h"
-#include "Swiften/Roster/OpenChatRosterAction.h"
-#include "Swiften/Roster/TreeWidgetFactory.h"
-#include "Swiften/Roster/XMPPRoster.h"
-
-namespace Swift {
-	
-/**
- * The controller does not gain ownership of these parameters.
- */
-XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, boost::shared_ptr<XMPPRoster> xmppRoster)
- : IQHandler(iqRouter), iqRouter_(iqRouter), xmppRoster_(xmppRoster) {
-}
-
-XMPPRosterController::~XMPPRosterController() {
-
-}
-
-void XMPPRosterController::requestRoster() {
-	GetRosterRequest* rosterRequest = new GetRosterRequest(iqRouter_, Request::AutoDeleteAfterResponse);
-	rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1));
-	rosterRequest->send();
-}
-
-void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload) {
-	foreach(const RosterItemPayload& item, rosterPayload->getItems()) {
-		if (item.getSubscription() == RosterItemPayload::Remove) {
-			xmppRoster_->removeContact(item.getJID());
-		} else {
-			xmppRoster_->addContact(item.getJID(), item.getName(), item.getGroups());
-		}
-	}
-}
-
-bool XMPPRosterController::handleIQ(boost::shared_ptr<IQ> iq) {
-	if (iq->getType() != IQ::Set || iq->getPayload<RosterPayload>().get() == NULL || iq->getFrom().isValid()) {
-		return false;
-	}
-	handleRosterReceived(iq->getPayload<RosterPayload>());
-	return true;
-}
-
-}
-
diff --git a/Swiften/Controllers/XMPPRosterController.h b/Swiften/Controllers/XMPPRosterController.h
deleted file mode 100644
index 7695ff5..0000000
--- a/Swiften/Controllers/XMPPRosterController.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include "Swiften/JID/JID.h"
-#include "Swiften/Base/String.h"
-#include "Swiften/Elements/IQ.h"
-#include "Swiften/Elements/RosterPayload.h"
-#include "Swiften/Queries/IQHandler.h"
-
-#include <boost/signals.hpp>
-#include <boost/shared_ptr.hpp>
-
-namespace Swift {
-	class IQRouter;
-	class XMPPRoster;
-
-	class XMPPRosterController : public IQHandler {
-		public:
-			XMPPRosterController(IQRouter *iqRouter, boost::shared_ptr<XMPPRoster> xmppRoster);
-			~XMPPRosterController();
-
-			void requestRoster();
-
-			boost::shared_ptr<XMPPRoster> getXMPPRoster() {return xmppRoster_;};
-			bool handleIQ(boost::shared_ptr<IQ>);
-
-		private:
-			IQRouter* iqRouter_;
-			void handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload);
-			boost::shared_ptr<XMPPRoster> xmppRoster_;
-	};
-}
-
diff --git a/Swiften/Makefile.inc b/Swiften/Makefile.inc
index 7eca8a5..bb93bf8 100644
--- a/Swiften/Makefile.inc
+++ b/Swiften/Makefile.inc
@@ -15,7 +15,6 @@ include Swiften/TLS/Makefile.inc
 include Swiften/SASL/Makefile.inc
 include Swiften/Compress/Makefile.inc
 include Swiften/Queries/Makefile.inc
-include Swiften/Controllers/Makefile.inc
 include Swiften/Roster/Makefile.inc
 include Swiften/Disco/Makefile.inc
 include Swiften/Presence/Makefile.inc
@@ -34,6 +33,7 @@ SWIFTEN_OBJECTS = \
 	$(SQLITE_OBJECTS)
 
 TARGETS += $(SWIFTEN_TARGET)
+UNITTEST_LIBS += $(SWIFTEN_TARGET)
 CLEANFILES += $(SWIFTEN_TARGET) $(SWIFTEN_OBJECTS)
 
 .PHONY: lib
@@ -43,4 +43,3 @@ $(SWIFTEN_TARGET): $(SWIFTEN_OBJECTS)
 	$(QUIET_AR)$(AR) $(ARFLAGS) $@ $(SWIFTEN_OBJECTS)
 
 include Swiften/Examples/Makefile.inc
-include Swiften/QA/Makefile.inc
diff --git a/Swiften/QA/UnitTest/Makefile.inc b/Swiften/QA/UnitTest/Makefile.inc
index 7f31da3..5bdbec9 100644
--- a/Swiften/QA/UnitTest/Makefile.inc
+++ b/Swiften/QA/UnitTest/Makefile.inc
@@ -12,6 +12,6 @@ CLEANFILES += $(UNITTEST_OBJECTS) $(UNITTEST_TARGET)
 check: $(UNITTEST_TARGET)
 	$(TEST_RUNNER) ./$(UNITTEST_TARGET)
 
-$(UNITTEST_TARGET): $(SWIFTEN_TARGET) $(CPPUNIT_TARGET) $(UNITTEST_OBJECTS) $(BUNDLED_LIBS)
-	$(QUIET_LINK)$(CXX) -o $(UNITTEST_TARGET) $(UNITTEST_OBJECTS) $(LDFLAGS) $(SWIFTEN_TARGET) $(CPPUNIT_TARGET) $(BUNDLED_LIBS) $(LIBS)
+$(UNITTEST_TARGET): $(CPPUNIT_TARGET) $(UNITTEST_OBJECTS) $(UNITTEST_LIBS) $(BUNDLED_LIBS)
+	$(QUIET_LINK)$(CXX) -o $(UNITTEST_TARGET) $(UNITTEST_OBJECTS) $(LDFLAGS) $(CPPUNIT_TARGET) $(UNITTEST_LIBS) $(BUNDLED_LIBS) $(LIBS)
 
-- 
cgit v0.10.2-6-g49f6