From 5b4a0ba19ae6994db6a193a231fd2486bff6f0ec Mon Sep 17 00:00:00 2001
From: Thanos Doukoudakis <thanos.doukoudakis@isode.com>
Date: Thu, 19 Jul 2018 18:13:55 +0100
Subject: Rename MainController to AccountController

Change-Id: I9c006a2435294f2afb95a95bd856ad64274a8752
Test-Information:
None.

diff --git a/Swift/Controllers/AccountController.cpp b/Swift/Controllers/AccountController.cpp
new file mode 100644
index 0000000..048d140
--- /dev/null
+++ b/Swift/Controllers/AccountController.cpp
@@ -0,0 +1,870 @@
+/*
+ * Copyright (c) 2010-2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/AccountController.h>
+
+#include <cstdlib>
+#include <memory>
+
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <Swiften/Base/Algorithm.h>
+#include <Swiften/Base/Log.h>
+#include <Swiften/Base/String.h>
+#include <Swiften/Base/format.h>
+#include <Swiften/Client/Client.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Client/ClientXMLTracer.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Client/StanzaChannel.h>
+#include <Swiften/Client/Storages.h>
+#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/Disco/CapsInfoGenerator.h>
+#include <Swiften/Disco/ClientDiscoManager.h>
+#include <Swiften/Disco/GetDiscoInfoRequest.h>
+#include <Swiften/Elements/ChatState.h>
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/Elements/VCardUpdate.h>
+#include <Swiften/FileTransfer/FileTransferManager.h>
+#include <Swiften/Network/NetworkFactories.h>
+#include <Swiften/Network/TimerFactory.h>
+#include <Swiften/Presence/PresenceSender.h>
+#include <Swiften/Queries/Requests/EnableCarbonsRequest.h>
+#include <Swiften/StringCodecs/Base64.h>
+#include <Swiften/StringCodecs/Hexify.h>
+#include <Swiften/VCards/GetVCardRequest.h>
+#include <Swiften/VCards/VCardManager.h>
+
+#ifdef SWIFTEN_PLATFORM_WIN32
+#include <Swiften/SASL/WindowsAuthentication.h>
+#endif
+
+#include <Swift/Controllers/AdHocManager.h>
+#include <Swift/Controllers/BlockListController.h>
+#include <Swift/Controllers/BuildVersion.h>
+#include <Swift/Controllers/Chat/Chattables.h>
+#include <Swift/Controllers/Chat/ChatsManager.h>
+#include <Swift/Controllers/Chat/MUCController.h>
+#include <Swift/Controllers/Chat/UserSearchController.h>
+#include <Swift/Controllers/ContactEditController.h>
+#include <Swift/Controllers/ContactSuggester.h>
+#include <Swift/Controllers/ContactsFromXMPPRoster.h>
+#include <Swift/Controllers/EventNotifier.h>
+#include <Swift/Controllers/EventWindowController.h>
+#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
+#include <Swift/Controllers/FileTransferListController.h>
+#include <Swift/Controllers/Highlighting/HighlightEditorController.h>
+#include <Swift/Controllers/Highlighting/HighlightManager.h>
+#include <Swift/Controllers/HistoryController.h>
+#include <Swift/Controllers/HistoryViewController.h>
+#include <Swift/Controllers/Intl.h>
+#include <Swift/Controllers/PresenceNotifier.h>
+#include <Swift/Controllers/ProfileController.h>
+#include <Swift/Controllers/Roster/RosterController.h>
+#include <Swift/Controllers/SettingConstants.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/ShowProfileController.h>
+#include <Swift/Controllers/SoundEventController.h>
+#include <Swift/Controllers/SoundPlayer.h>
+#include <Swift/Controllers/StatusTracker.h>
+#include <Swift/Controllers/Storages/CertificateStorageFactory.h>
+#include <Swift/Controllers/Storages/CertificateStorageTrustChecker.h>
+#include <Swift/Controllers/Storages/StoragesFactory.h>
+#include <Swift/Controllers/SystemTray.h>
+#include <Swift/Controllers/SystemTrayController.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/LoginWindow.h>
+#include <Swift/Controllers/UIInterfaces/LoginWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/MainWindow.h>
+#include <Swift/Controllers/UIInterfaces/UIFactory.h>
+#include <Swift/Controllers/WhiteboardManager.h>
+#include <Swift/Controllers/XMLConsoleController.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/XMPPURIController.h>
+
+#include <SwifTools/Dock/Dock.h>
+#include <SwifTools/Idle/IdleDetector.h>
+#include <SwifTools/Notifier/TogglableNotifier.h>
+
+namespace Swift {
+
+static const std::string CLIENT_NAME = "Swift";
+static const std::string CLIENT_NODE = "http://swift.im";
+
+
+AccountController::AccountController(
+        EventLoop* eventLoop,
+        NetworkFactories* networkFactories,
+        UIFactory* uiFactories,
+        SettingsProvider* settings,
+        SystemTray* systemTray,
+        SoundPlayer* soundPlayer,
+        StoragesFactory* storagesFactory,
+        CertificateStorageFactory* certificateStorageFactory,
+        Dock* dock,
+        Notifier* notifier,
+        URIHandler* uriHandler,
+        IdleDetector* idleDetector,
+        const std::map<std::string, std::string>& emoticons,
+        bool useDelayForLatency) :
+            eventLoop_(eventLoop),
+            networkFactories_(networkFactories),
+            uiFactory_(uiFactories),
+            storagesFactory_(storagesFactory),
+            certificateStorageFactory_(certificateStorageFactory),
+            settings_(settings),
+            uriHandler_(uriHandler),
+            idleDetector_(idleDetector),
+            loginWindow_(nullptr) ,
+            useDelayForLatency_(useDelayForLatency),
+            ftOverview_(nullptr),
+            emoticons_(emoticons) {
+    storages_ = nullptr;
+    certificateStorage_ = nullptr;
+    certificateTrustChecker_ = nullptr;
+    statusTracker_ = nullptr;
+    presenceNotifier_ = nullptr;
+    eventNotifier_ = nullptr;
+    rosterController_ = nullptr;
+    chatsManager_ = nullptr;
+    historyController_ = nullptr;
+    historyViewController_ = nullptr;
+    eventWindowController_ = nullptr;
+    profileController_ = nullptr;
+    blockListController_ = nullptr;
+    showProfileController_ = nullptr;
+    contactEditController_ = nullptr;
+    userSearchControllerChat_ = nullptr;
+    userSearchControllerAdd_ = nullptr;
+    userSearchControllerInvite_ = nullptr;
+    contactsFromRosterProvider_ = nullptr;
+    contactSuggesterWithoutRoster_ = nullptr;
+    contactSuggesterWithRoster_ = nullptr;
+    whiteboardManager_ = nullptr;
+    adHocManager_ = nullptr;
+    quitRequested_ = false;
+    clientInitialized_ = false;
+    offlineRequested_ = false;
+
+    timeBeforeNextReconnect_ = -1;
+    dock_ = dock;
+    uiEventStream_ = new UIEventStream();
+
+    notifier_ = new TogglableNotifier(notifier);
+    notifier_->setPersistentEnabled(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS));
+    eventController_ = new EventController();
+    eventController_->onEventQueueLengthChange.connect(boost::bind(&AccountController::handleEventQueueLengthChange, this, _1));
+
+    systemTrayController_ = new SystemTrayController(eventController_, systemTray);
+    loginWindow_ = uiFactory_->createLoginWindow(uiEventStream_);
+    loginWindow_->setShowNotificationToggle(!notifier->isExternallyConfigured());
+
+    highlightManager_ = new HighlightManager(settings_);
+    highlightEditorController_ = new HighlightEditorController(uiEventStream_, uiFactory_, highlightManager_);
+
+    soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings, highlightManager_);
+
+    xmppURIController_ = new XMPPURIController(uriHandler_, uiEventStream_);
+
+    loginWindow_->onLoginRequest.connect(boost::bind(&AccountController::handleLoginRequest, this, _1, _2, _3, _4, _5, _6, _7));
+    loginWindow_->onPurgeSavedLoginRequest.connect(boost::bind(&AccountController::handlePurgeSavedLoginRequest, this, _1));
+    loginWindow_->onCancelLoginRequest.connect(boost::bind(&AccountController::handleCancelLoginRequest, this));
+    loginWindow_->onQuitRequest.connect(boost::bind(&AccountController::handleQuitRequest, this));
+
+    idleDetector_->setIdleTimeSeconds(settings->getSetting(SettingConstants::IDLE_TIMEOUT));
+    idleDetector_->onIdleChanged.connect(boost::bind(&AccountController::handleInputIdleChanged, this, _1));
+
+    xmlConsoleController_ = new XMLConsoleController(uiEventStream_, uiFactory_);
+
+    fileTransferListController_ = new FileTransferListController(uiEventStream_, uiFactory_);
+
+    settings_->onSettingChanged.connect(boost::bind(&AccountController::handleSettingChanged, this, _1));
+
+}
+
+AccountController::~AccountController() {
+    idleDetector_->onIdleChanged.disconnect(boost::bind(&AccountController::handleInputIdleChanged, this, _1));
+
+    purgeCachedCredentials();
+    //setManagersOffline();
+    eventController_->disconnectAll();
+
+    resetClient();
+    delete highlightEditorController_;
+    delete highlightManager_;
+    delete fileTransferListController_;
+    delete xmlConsoleController_;
+    delete xmppURIController_;
+    delete soundEventController_;
+    delete systemTrayController_;
+    delete eventController_;
+    delete notifier_;
+    delete uiEventStream_;
+}
+
+void AccountController::purgeCachedCredentials() {
+    safeClear(password_);
+}
+
+void AccountController::resetClient() {
+    purgeCachedCredentials();
+    resetCurrentError();
+    resetPendingReconnects();
+    vCardPhotoHash_.clear();
+    delete contactEditController_;
+    contactEditController_ = nullptr;
+    delete profileController_;
+    profileController_ = nullptr;
+    delete showProfileController_;
+    showProfileController_ = nullptr;
+    delete eventWindowController_;
+    eventWindowController_ = nullptr;
+    delete chatsManager_;
+    chatsManager_ = nullptr;
+#ifdef SWIFT_EXPERIMENTAL_HISTORY
+    delete historyViewController_;
+    historyViewController_ = nullptr;
+    delete historyController_;
+    historyController_ = nullptr;
+#endif
+    fileTransferListController_->setFileTransferOverview(nullptr);
+    delete ftOverview_;
+    ftOverview_ = nullptr;
+    delete blockListController_;
+    blockListController_ = nullptr;
+    delete rosterController_;
+    rosterController_ = nullptr;
+    chattables_.reset();
+    delete eventNotifier_;
+    eventNotifier_ = nullptr;
+    delete presenceNotifier_;
+    presenceNotifier_ = nullptr;
+    delete certificateTrustChecker_;
+    certificateTrustChecker_ = nullptr;
+    delete certificateStorage_;
+    certificateStorage_ = nullptr;
+    delete storages_;
+    storages_ = nullptr;
+    delete statusTracker_;
+    statusTracker_ = nullptr;
+    delete profileSettings_;
+    profileSettings_ = nullptr;
+    delete userSearchControllerChat_;
+    userSearchControllerChat_ = nullptr;
+    delete userSearchControllerAdd_;
+    userSearchControllerAdd_ = nullptr;
+    delete userSearchControllerInvite_;
+    userSearchControllerInvite_ = nullptr;
+    delete contactSuggesterWithoutRoster_;
+    contactSuggesterWithoutRoster_ = nullptr;
+    delete contactSuggesterWithRoster_;
+    contactSuggesterWithRoster_ = nullptr;
+    delete contactsFromRosterProvider_;
+    contactsFromRosterProvider_ = nullptr;
+    delete adHocManager_;
+    adHocManager_ = nullptr;
+    delete whiteboardManager_;
+    whiteboardManager_ = nullptr;
+    clientInitialized_ = false;
+}
+
+void AccountController::handleSettingChanged(const std::string& settingPath) {
+    if (settingPath == SettingConstants::SHOW_NOTIFICATIONS.getKey()) {
+        notifier_->setPersistentEnabled(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS));
+    }
+}
+
+void AccountController::resetPendingReconnects() {
+    timeBeforeNextReconnect_ = -1;
+    if (reconnectTimer_) {
+        reconnectTimer_->stop();
+        reconnectTimer_.reset();
+    }
+    resetCurrentError();
+}
+
+void AccountController::resetCurrentError() {
+    if (lastDisconnectError_) {
+        lastDisconnectError_->conclude();
+        lastDisconnectError_ = std::shared_ptr<ErrorEvent>();
+    }
+}
+
+void AccountController::handleConnected() {
+    boundJID_ = client_->getJID();
+    resetCurrentError();
+    resetPendingReconnects();
+
+    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+        purgeCachedCredentials();
+    }
+
+    bool freshLogin = rosterController_ == nullptr;
+    myStatusLooksOnline_ = true;
+    if (freshLogin) {
+        profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
+        showProfileController_ = new ShowProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
+        ftOverview_ = new FileTransferOverview(client_->getFileTransferManager());
+        fileTransferListController_->setFileTransferOverview(ftOverview_);
+        chattables_ = std::make_unique<Chattables>();
+        rosterController_ = new RosterController(boundJID_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), client_->getClientBlockListManager(), client_->getVCardManager(), *chattables_);
+        rosterController_->onChangeStatusRequest.connect(boost::bind(&AccountController::handleChangeStatusRequest, this, _1, _2));
+        rosterController_->onSignOutRequest.connect(boost::bind(&AccountController::signOut, this));
+        rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&AccountController::handleShowCertificateRequest, this));
+
+        blockListController_ = new BlockListController(client_->getClientBlockListManager(), uiEventStream_, uiFactory_, eventController_);
+
+        contactEditController_ = new ContactEditController(rosterController_, client_->getVCardManager(), uiFactory_, uiEventStream_);
+        whiteboardManager_ = new WhiteboardManager(uiFactory_, uiEventStream_, client_->getNickResolver(), client_->getWhiteboardSessionManager());
+
+        /* Doing this early as an ordering fix. Various things later will
+         * want to have the user's nick available and this means it will
+         * be before they receive stanzas that need it (e.g. bookmarks).*/
+        client_->getVCardManager()->requestOwnVCard();
+
+        contactSuggesterWithoutRoster_ = new ContactSuggester();
+        contactSuggesterWithRoster_ = new ContactSuggester();
+
+        userSearchControllerInvite_ = new UserSearchController(UserSearchController::Type::InviteToChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle(), profileSettings_);
+#ifdef SWIFT_EXPERIMENTAL_HISTORY
+        historyController_ = new HistoryController(storages_->getHistoryStorage());
+        historyViewController_ = new HistoryViewController(jid_, uiEventStream_, historyController_, client_->getNickResolver(), client_->getAvatarManager(), client_->getPresenceOracle(), uiFactory_);
+        chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, client_->getVCardManager());
+#else
+        chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, nullptr, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, client_->getVCardManager(), *chattables_);
+#endif
+        contactsFromRosterProvider_ = new ContactsFromXMPPRoster(client_->getRoster(), client_->getAvatarManager(), client_->getPresenceOracle());
+        contactSuggesterWithoutRoster_->addContactProvider(chatsManager_);
+        contactSuggesterWithRoster_->addContactProvider(chatsManager_);
+        contactSuggesterWithRoster_->addContactProvider(contactsFromRosterProvider_);
+        highlightEditorController_->setContactSuggester(contactSuggesterWithoutRoster_);
+
+        client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
+        chatsManager_->setAvatarManager(client_->getAvatarManager());
+
+        eventWindowController_ = new EventWindowController(eventController_, uiFactory_);
+
+        loginWindow_->morphInto(rosterController_->getWindow());
+
+        DiscoInfo discoInfo;
+        discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc"));
+        discoInfo.addFeature(DiscoInfo::ChatStatesFeature);
+        discoInfo.addFeature(DiscoInfo::SecurityLabelsFeature);
+        discoInfo.addFeature(DiscoInfo::MessageCorrectionFeature);
+#ifdef SWIFT_EXPERIMENTAL_FT
+        discoInfo.addFeature(DiscoInfo::JingleFeature);
+        discoInfo.addFeature(DiscoInfo::JingleFTFeature);
+        discoInfo.addFeature(DiscoInfo::JingleTransportsIBBFeature);
+        discoInfo.addFeature(DiscoInfo::JingleTransportsS5BFeature);
+#endif
+#ifdef SWIFT_EXPERIMENTAL_WB
+        discoInfo.addFeature(DiscoInfo::WhiteboardFeature);
+#endif
+        discoInfo.addFeature(DiscoInfo::MessageDeliveryReceiptsFeature);
+        client_->getDiscoManager()->setCapsNode(CLIENT_NODE);
+        client_->getDiscoManager()->setDiscoInfo(discoInfo);
+
+        userSearchControllerChat_ = new UserSearchController(UserSearchController::Type::StartChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle(), profileSettings_);
+        userSearchControllerAdd_ = new UserSearchController(UserSearchController::Type::AddContact, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithoutRoster_, client_->getAvatarManager(), client_->getPresenceOracle(), profileSettings_);
+        adHocManager_ = new AdHocManager(JID(boundJID_.getDomain()), uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow());
+
+        chatsManager_->onImpromptuMUCServiceDiscovered.connect(boost::bind(&UserSearchController::setCanInitiateImpromptuMUC, userSearchControllerChat_, _1));
+    }
+    loginWindow_->setIsLoggingIn(false);
+
+    client_->requestRoster();
+
+    GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(boundJID_.getDomain()), client_->getIQRouter());
+    discoInfoRequest->onResponse.connect(boost::bind(&AccountController::handleServerDiscoInfoResponse, this, _1, _2));
+    discoInfoRequest->send();
+
+    client_->getVCardManager()->requestOwnVCard();
+
+    rosterController_->setJID(boundJID_);
+    rosterController_->setEnabled(true);
+    rosterController_->getWindow()->setStreamEncryptionStatus(client_->isStreamEncrypted());
+    profileController_->setAvailable(true);
+    contactEditController_->setAvailable(true);
+    /* Send presence later to catch all the incoming presences. */
+    sendPresence(statusTracker_->getNextPresence());
+
+    /* Enable chats last of all, so rejoining MUCs has the right sent presence */
+    assert(chatsManager_);
+    chatsManager_->setOnline(true);
+    adHocManager_->setOnline(true);
+}
+
+void AccountController::handleEventQueueLengthChange(int count) {
+    dock_->setNumberOfPendingMessages(count);
+}
+
+void AccountController::reconnectAfterError() {
+    if (reconnectTimer_) {
+        reconnectTimer_->stop();
+    }
+    performLoginFromCachedCredentials();
+}
+
+void AccountController::handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText) {
+    std::shared_ptr<Presence> presence(new Presence());
+    if (show == StatusShow::None) {
+        // Note: this is misleading, None doesn't mean unavailable on the wire.
+        presence->setType(Presence::Unavailable);
+        resetPendingReconnects();
+        myStatusLooksOnline_ = false;
+        offlineRequested_ = true;
+    }
+    else {
+        offlineRequested_ = false;
+        presence->setShow(show);
+    }
+    presence->setStatus(statusText);
+    statusTracker_->setRequestedPresence(presence);
+    if (presence->getType() != Presence::Unavailable) {
+        profileSettings_->storeInt("lastShow", presence->getShow());
+        profileSettings_->storeString("lastStatus", presence->getStatus());
+    }
+    if (presence->getType() != Presence::Unavailable && !client_->isAvailable()) {
+        performLoginFromCachedCredentials();
+    } else {
+        sendPresence(presence);
+    }
+}
+
+void AccountController::sendPresence(std::shared_ptr<Presence> presence) {
+    rosterController_->getWindow()->setMyStatusType(presence->getShow());
+    rosterController_->getWindow()->setMyStatusText(presence->getStatus());
+    systemTrayController_->setMyStatusType(presence->getShow());
+    notifier_->setTemporarilyDisabled(presence->getShow() == StatusShow::DND);
+
+    // Add information and send
+    presence->updatePayload(std::make_shared<VCardUpdate>(vCardPhotoHash_));
+    client_->getPresenceSender()->sendPresence(presence);
+    if (presence->getType() == Presence::Unavailable) {
+        logout();
+    }
+}
+
+void AccountController::handleInputIdleChanged(bool idle) {
+    if (!statusTracker_) {
+        //Haven't logged in yet.
+        return;
+    }
+
+    if (settings_->getSetting(SettingConstants::IDLE_GOES_OFFLINE)) {
+        if (idle) {
+            logout();
+        }
+    }
+    else {
+        if (idle) {
+            if (statusTracker_->goAutoAway(idleDetector_->getIdleTimeSeconds())) {
+                if (client_ && client_->isAvailable()) {
+                    sendPresence(statusTracker_->getNextPresence());
+                }
+            }
+        } else {
+            if (statusTracker_->goAutoUnAway()) {
+                if (client_ && client_->isAvailable()) {
+                    sendPresence(statusTracker_->getNextPresence());
+                }
+            }
+        }
+    }
+}
+
+void AccountController::handleShowCertificateRequest() {
+    std::vector<Certificate::ref> chain = client_->getStanzaChannel()->getPeerCertificateChain();
+    rosterController_->getWindow()->openCertificateDialog(chain);
+}
+
+void AccountController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificatePath, CertificateWithKey::ref certificate, const ClientOptions& options, bool remember, bool loginAutomatically) {
+    jid_ = JID(username);
+    if (options.singleSignOn && (!jid_.isValid() || !jid_.getNode().empty())) {
+        loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'wonderland.lit'"));
+        loginWindow_->setIsLoggingIn(false);
+    } else if (!options.singleSignOn && (!jid_.isValid() || jid_.getNode().empty())) {
+        loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'alice@wonderland.lit'"));
+        loginWindow_->setIsLoggingIn(false);
+    } else {
+#ifdef SWIFTEN_PLATFORM_WIN32
+        if (options.singleSignOn) {
+            std::string userName;
+            std::string clientName;
+            std::string serverName;
+            std::shared_ptr<boost::system::error_code> errorCode = getUserNameEx(userName, clientName, serverName);
+
+            if (!errorCode) {
+                /* Create JID using the Windows logon name and user provided domain name */
+                jid_ = JID(clientName, username);
+            }
+            else {
+                loginWindow_->setMessage(str(format(QT_TRANSLATE_NOOP("", "Error obtaining Windows user name (%1%)")) % errorCode->message()));
+                loginWindow_->setIsLoggingIn(false);
+                return;
+            }
+        }
+#endif
+
+        loginWindow_->setMessage("");
+        loginWindow_->setIsLoggingIn(true);
+        profileSettings_ = new ProfileSettingsProvider(username, settings_);
+        if (!settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+            profileSettings_->storeString("jid", username);
+            profileSettings_->storeString("certificate", certificatePath);
+            profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : "");
+            std::string optionString = serializeClientOptions(options);
+            profileSettings_->storeString("options", optionString);
+            profileSettings_->storeInt("enabled", 1);
+            loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate"), options);
+        }
+
+        password_ = password;
+        certificate_ = certificate;
+        clientOptions_ = options;
+        performLoginFromCachedCredentials();
+    }
+}
+
+void AccountController::handlePurgeSavedLoginRequest(const std::string& username) {
+    settings_->removeProfile(username);
+    loginWindow_->removeAvailableAccount(username);
+}
+
+void AccountController::performLoginFromCachedCredentials() {
+    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS) && password_.empty()) {
+        /* Then we can't try to login again. */
+        return;
+    }
+    /* If we logged in with a bare JID, and we have a full bound JID, re-login with the
+     * bound JID to try and keep dynamically assigned resources */
+    JID clientJID = jid_;
+    if (boundJID_.isValid() && jid_.isBare() && boundJID_.toBare() == jid_) {
+        clientJID = boundJID_;
+    }
+
+    if (!statusTracker_) {
+        statusTracker_  = new StatusTracker();
+    }
+    if (!clientInitialized_) {
+        storages_ = storagesFactory_->createStorages(jid_.toBare());
+        certificateStorage_ = certificateStorageFactory_->createCertificateStorage(jid_.toBare());
+        certificateTrustChecker_ = new CertificateStorageTrustChecker(certificateStorage_);
+
+        client_ = std::make_shared<Swift::Client>(clientJID, createSafeByteArray(password_.c_str()), networkFactories_, storages_);
+        clientInitialized_ = true;
+        client_->setCertificateTrustChecker(certificateTrustChecker_);
+        client_->onDataRead.connect(boost::bind(&XMLConsoleController::handleDataRead, xmlConsoleController_, _1));
+        client_->onDataWritten.connect(boost::bind(&XMLConsoleController::handleDataWritten, xmlConsoleController_, _1));
+        client_->onDisconnected.connect(boost::bind(&AccountController::handleDisconnected, this, _1));
+        client_->onConnected.connect(boost::bind(&AccountController::handleConnected, this));
+
+        client_->setSoftwareVersion(CLIENT_NAME, buildVersion);
+
+        client_->getVCardManager()->onVCardChanged.connect(boost::bind(&AccountController::handleVCardReceived, this, _1, _2));
+        presenceNotifier_ = new PresenceNotifier(client_->getStanzaChannel(), notifier_, client_->getMUCRegistry(), client_->getAvatarManager(), client_->getNickResolver(), client_->getPresenceOracle(), networkFactories_->getTimerFactory());
+        presenceNotifier_->onNotificationActivated.connect(boost::bind(&AccountController::handleNotificationClicked, this, _1));
+        eventNotifier_ = new EventNotifier(eventController_, notifier_, client_->getAvatarManager(), client_->getNickResolver());
+        eventNotifier_->onNotificationActivated.connect(boost::bind(&AccountController::handleNotificationClicked, this, _1));
+        if (certificate_) {
+            client_->setCertificate(certificate_);
+        }
+        std::shared_ptr<Presence> presence(new Presence());
+        presence->setShow(static_cast<StatusShow::Type>(profileSettings_->getIntSetting("lastShow", StatusShow::Online)));
+        presence->setStatus(profileSettings_->getStringSetting("lastStatus"));
+        statusTracker_->setRequestedPresence(presence);
+    } else {
+        /* In case we're in the middle of another login, make sure they don't overlap */
+        client_->disconnect();
+    }
+    systemTrayController_->setConnecting();
+    if (rosterController_) {
+        rosterController_->getWindow()->setConnecting();
+    }
+    ClientOptions clientOptions = clientOptions_;
+    bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
+    clientOptions.forgetPassword = eagle;
+    clientOptions.useTLS = eagle ? ClientOptions::RequireTLS : clientOptions_.useTLS;
+    client_->connect(clientOptions);
+}
+
+void AccountController::handleDisconnected(const boost::optional<ClientError>& error) {
+    if (rosterController_) {
+        rosterController_->getWindow()->setStreamEncryptionStatus(false);
+    }
+    if (adHocManager_) {
+        adHocManager_->setOnline(false);
+    }
+    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+        purgeCachedCredentials();
+    }
+    if (quitRequested_) {
+        resetClient();
+        loginWindow_->quit();
+    }
+    else if (error) {
+        std::string message;
+        std::string certificateErrorMessage;
+        bool forceSignout = false;
+        switch(error->getType()) {
+            case ClientError::UnknownError: message = QT_TRANSLATE_NOOP("", "Unknown Error"); break;
+            case ClientError::DomainNameResolveError: message = QT_TRANSLATE_NOOP("", "Unable to find server"); break;
+            case ClientError::ConnectionError: message = QT_TRANSLATE_NOOP("", "Error connecting to server"); break;
+            case ClientError::ConnectionReadError: message = QT_TRANSLATE_NOOP("", "Error while receiving server data"); break;
+            case ClientError::ConnectionWriteError: message = QT_TRANSLATE_NOOP("", "Error while sending data to the server"); break;
+            case ClientError::XMLError: message = QT_TRANSLATE_NOOP("", "Error parsing server data"); break;
+            case ClientError::AuthenticationFailedError: message = QT_TRANSLATE_NOOP("", "Login/password invalid"); break;
+            case ClientError::CompressionFailedError: message = QT_TRANSLATE_NOOP("", "Error while compressing stream"); break;
+            case ClientError::ServerVerificationFailedError: message = QT_TRANSLATE_NOOP("", "Server verification failed"); break;
+            case ClientError::NoSupportedAuthMechanismsError: message = QT_TRANSLATE_NOOP("", "Authentication mechanisms not supported"); break;
+            case ClientError::UnexpectedElementError: message = QT_TRANSLATE_NOOP("", "Unexpected response"); break;
+            case ClientError::ResourceBindError: message = QT_TRANSLATE_NOOP("", "Error binding resource"); break;
+            case ClientError::SessionStartError: message = QT_TRANSLATE_NOOP("", "Error starting session"); break;
+            case ClientError::StreamError: message = QT_TRANSLATE_NOOP("", "Stream error"); break;
+            case ClientError::TLSError: message = QT_TRANSLATE_NOOP("", "Encryption error"); break;
+            case ClientError::ClientCertificateLoadError: message = QT_TRANSLATE_NOOP("", "Error loading certificate (Invalid file or password?)"); break;
+            case ClientError::ClientCertificateError: message = QT_TRANSLATE_NOOP("", "Certificate not authorized"); break;
+            case ClientError::CertificateCardRemoved: message = QT_TRANSLATE_NOOP("", "Certificate card removed"); forceSignout = true; break;
+
+            case ClientError::UnknownCertificateError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Unknown certificate"); break;
+            case ClientError::CertificateExpiredError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has expired"); break;
+            case ClientError::CertificateNotYetValidError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is not yet valid"); break;
+            case ClientError::CertificateSelfSignedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is self-signed"); break;
+            case ClientError::CertificateRejectedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has been rejected"); break;
+            case ClientError::CertificateUntrustedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is not trusted"); break;
+            case ClientError::InvalidCertificatePurposeError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate cannot be used for encrypting your connection"); break;
+            case ClientError::CertificatePathLengthExceededError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate path length constraint exceeded"); break;
+            case ClientError::InvalidCertificateSignatureError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Invalid certificate signature"); break;
+            case ClientError::InvalidCAError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Invalid Certificate Authority"); break;
+            case ClientError::InvalidServerIdentityError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate does not match the host identity"); break;
+            case ClientError::RevokedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has been revoked"); break;
+            case ClientError::RevocationCheckFailedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Unable to determine certificate revocation state"); break;
+        }
+        bool forceReconnectAfterCertificateTrust = false;
+        if (!certificateErrorMessage.empty()) {
+            std::vector<Certificate::ref> certificates = certificateTrustChecker_->getLastCertificateChain();
+            if (!certificates.empty() && loginWindow_->askUserToTrustCertificatePermanently(certificateErrorMessage, certificates)) {
+                certificateStorage_->addCertificate(certificates[0]);
+                forceReconnectAfterCertificateTrust = true;
+            }
+            else {
+                message = QT_TRANSLATE_NOOP("", "Certificate error");
+            }
+        }
+
+        if (!message.empty() && error->getErrorCode()) {
+            message = str(format(QT_TRANSLATE_NOOP("", "%1% (%2%)")) % message % error->getErrorCode()->message());
+        }
+
+        if (forceReconnectAfterCertificateTrust && settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+            forceReconnectAfterCertificateTrust = false;
+            forceSignout = true;
+            message = QT_TRANSLATE_NOOP("", "Re-enter credentials and retry");
+        }
+
+        if (forceReconnectAfterCertificateTrust) {
+            performLoginFromCachedCredentials();
+        }
+        else if (forceSignout || !rosterController_) { //hasn't been logged in yet or permanent error
+            signOut();
+            loginWindow_->setMessage(message);
+            loginWindow_->setIsLoggingIn(false);
+        } else {
+            logout();
+            if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+                message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%. To reconnect, Sign Out and provide your password again.")) % jid_.getDomain() % message);
+            } else {
+                if (!offlineRequested_) {
+                    setReconnectTimer();
+                }
+                if (lastDisconnectError_) {
+                    message = str(format(QT_TRANSLATE_NOOP("", "Reconnect to %1% failed: %2%. Will retry in %3% seconds.")) % jid_.getDomain() % message % boost::lexical_cast<std::string>(timeBeforeNextReconnect_));
+                    lastDisconnectError_->conclude();
+                } else {
+                    message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%.")) % jid_.getDomain() % message);
+                }
+                lastDisconnectError_ = std::make_shared<ErrorEvent>(JID(jid_.getDomain()), message);
+                eventController_->handleIncomingEvent(lastDisconnectError_);
+            }
+        }
+    }
+    else if (!rosterController_) { //hasn't been logged in yet
+        loginWindow_->setIsLoggingIn(false);
+    }
+}
+
+void AccountController::setReconnectTimer() {
+    if (timeBeforeNextReconnect_ < 0) {
+        timeBeforeNextReconnect_ = 1;
+    } else {
+        timeBeforeNextReconnect_ = timeBeforeNextReconnect_ >= 150 ? 300 : timeBeforeNextReconnect_ * 2; // Randomly selected by roll of a die, as required by 3920bis
+    }
+    if (reconnectTimer_) {
+        reconnectTimer_->stop();
+    }
+    reconnectTimer_ = networkFactories_->getTimerFactory()->createTimer(timeBeforeNextReconnect_ * 1000);
+    reconnectTimer_->onTick.connect(boost::bind(&AccountController::reconnectAfterError, this));
+    reconnectTimer_->start();
+}
+
+void AccountController::handleCancelLoginRequest() {
+    signOut();
+}
+
+void AccountController::signOut() {
+    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+        purgeCachedCredentials();
+    }
+    profileSettings_->storeInt("enabled", 0);
+    eventController_->clear();
+    logout();
+    loginWindow_->loggedOut();
+    resetClient();
+}
+
+void AccountController::logout() {
+    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+        purgeCachedCredentials();
+    }
+    systemTrayController_->setMyStatusType(StatusShow::None);
+    if (clientInitialized_ /*&& client_->isAvailable()*/) {
+        client_->disconnect();
+    }
+    if (rosterController_ && myStatusLooksOnline_) {
+        rosterController_->getWindow()->setMyStatusType(StatusShow::None);
+        rosterController_->getWindow()->setMyStatusText("");
+        myStatusLooksOnline_ = false;
+    }
+    setManagersOffline();
+}
+
+void AccountController::setManagersOffline() {
+    if (chatsManager_) {
+        chatsManager_->setOnline(false);
+    }
+    if (rosterController_) {
+        rosterController_->setEnabled(false);
+    }
+    if (profileController_) {
+        profileController_->setAvailable(false);
+    }
+    if (contactEditController_) {
+        contactEditController_->setAvailable(false);
+    }
+}
+
+void AccountController::handleServerDiscoInfoResponse(std::shared_ptr<DiscoInfo> info, ErrorPayload::ref error) {
+    if (!error) {
+        chatsManager_->setServerDiscoInfo(info);
+        adHocManager_->setServerDiscoInfo(info);
+        if (info->hasFeature(DiscoInfo::BlockingCommandFeature)) {
+            rosterController_->getWindow()->setBlockingCommandAvailable(true);
+            rosterController_->initBlockingCommand();
+        }
+        if (info->hasFeature(DiscoInfo::MessageCarbonsFeature)) {
+            enableMessageCarbons();
+        }
+    }
+}
+
+void AccountController::enableMessageCarbons() {
+    auto enableCarbonsRequest = EnableCarbonsRequest::create(client_->getIQRouter());
+    enableCarbonsRequestHandlerConnection_ = enableCarbonsRequest->onResponse.connect([&](Payload::ref /*payload*/, ErrorPayload::ref error) {
+        if (error) {
+            SWIFT_LOG(warning) << "Failed to enable carbons." << std::endl;
+        }
+        else {
+            SWIFT_LOG(debug) << "Successfully enabled carbons." << std::endl;
+        }
+        enableCarbonsRequestHandlerConnection_.disconnect();
+    });
+    enableCarbonsRequest->send();
+}
+
+void AccountController::handleVCardReceived(const JID& jid, VCard::ref vCard) {
+    if (!jid.equals(jid_, JID::WithoutResource) || !vCard) {
+        return;
+    }
+    std::string hash;
+    if (!vCard->getPhoto().empty()) {
+        hash = Hexify::hexify(networkFactories_->getCryptoProvider()->getSHA1Hash(vCard->getPhoto()));
+    }
+    if (hash != vCardPhotoHash_) {
+        vCardPhotoHash_ = hash;
+        if (client_ && client_->isAvailable()) {
+            sendPresence(statusTracker_->getNextPresence());
+        }
+    }
+}
+
+void AccountController::handleNotificationClicked(const JID& jid) {
+    assert(chatsManager_);
+    if (clientInitialized_) {
+        if (client_->getMUCRegistry()->isMUC(jid)) {
+            uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(jid));
+        }
+        else {
+            uiEventStream_->send(std::make_shared<RequestChatUIEvent>(jid));
+        }
+    }
+}
+
+void AccountController::handleQuitRequest() {
+    if (client_ && client_->isActive()) {
+        quitRequested_ = true;
+        client_->disconnect();
+    }
+    else {
+        resetClient();
+        loginWindow_->quit();
+    }
+}
+
+//FIXME: Switch all this to boost::serialise
+
+#define SERIALIZE_BOOL(option) result += options.option ? "1" : "0"; result += ",";
+#define SERIALIZE_INT(option) result += boost::lexical_cast<std::string>(options.option); result += ",";
+#define SERIALIZE_STRING(option) result += Base64::encode(createByteArray(options.option)); result += ",";
+#define SERIALIZE_SAFE_STRING(option) result += safeByteArrayToString(Base64::encode(options.option)); result += ",";
+#define SERIALIZE_URL(option) SERIALIZE_STRING(option.toString())
+
+std::string AccountController::serializeClientOptions(const ClientOptions& options) {
+    std::string result;
+    SERIALIZE_BOOL(useStreamCompression);
+    switch (options.useTLS) {
+        case ClientOptions::NeverUseTLS: result += "1";break;
+        case ClientOptions::UseTLSWhenAvailable: result += "2";break;
+        case ClientOptions::RequireTLS: result += "3";break;
+    }
+    result += ",";
+    SERIALIZE_BOOL(allowPLAINWithoutTLS);
+    SERIALIZE_BOOL(useStreamResumption);
+    SERIALIZE_BOOL(useAcks);
+    SERIALIZE_STRING(manualHostname);
+    SERIALIZE_INT(manualPort);
+    switch (options.proxyType) {
+        case ClientOptions::NoProxy: result += "1";break;
+        case ClientOptions::SystemConfiguredProxy: result += "2";break;
+        case ClientOptions::SOCKS5Proxy: result += "3";break;
+        case ClientOptions::HTTPConnectProxy: result += "4";break;
+    }
+    result += ",";
+    SERIALIZE_STRING(manualProxyHostname);
+    SERIALIZE_INT(manualProxyPort);
+    SERIALIZE_URL(boshURL);
+    SERIALIZE_URL(boshHTTPConnectProxyURL);
+    SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthID);
+    SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthPassword);
+    SERIALIZE_BOOL(tlsOptions.schannelTLS1_0Workaround);
+    SERIALIZE_BOOL(singleSignOn);
+    return result;
+}
+
+}
diff --git a/Swift/Controllers/AccountController.h b/Swift/Controllers/AccountController.h
new file mode 100644
index 0000000..30ae265
--- /dev/null
+++ b/Swift/Controllers/AccountController.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2010-2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <boost/signals2.hpp>
+
+#include <Swiften/Client/ClientError.h>
+#include <Swiften/Client/ClientXMLTracer.h>
+#include <Swiften/Elements/CapsInfo.h>
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Elements/ErrorPayload.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/Elements/VCard.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Network/Timer.h>
+
+#include <Swift/Controllers/ProfileSettingsProvider.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+#include <Swift/Controllers/XMPPEvents/ErrorEvent.h>
+
+namespace Swift {
+    class IdleDetector;
+    class UIFactory;
+    class EventLoop;
+    class Client;
+    class Chattables;
+    class ChatController;
+    class ChatsManager;
+    class CertificateStorageFactory;
+    class CertificateStorage;
+    class CertificateStorageTrustChecker;
+    class EventController;
+    class MainWindow;
+    class RosterController;
+    class LoginWindow;
+    class EventLoop;
+    class MUCController;
+    class Notifier;
+    class ProfileController;
+    class ShowProfileController;
+    class ContactEditController;
+    class TogglableNotifier;
+    class PresenceNotifier;
+    class EventNotifier;
+    class SystemTray;
+    class SystemTrayController;
+    class SoundEventController;
+    class SoundPlayer;
+    class XMLConsoleController;
+    class HistoryViewController;
+    class HistoryController;
+    class FileTransferListController;
+    class UIEventStream;
+    class EventWindowFactory;
+    class EventWindowController;
+    class MUCSearchController;
+    class UserSearchController;
+    class StatusTracker;
+    class Dock;
+    class Storages;
+    class StoragesFactory;
+    class NetworkFactories;
+    class URIHandler;
+    class XMPPURIController;
+    class AdHocManager;
+    class AdHocCommandWindowFactory;
+    class FileTransferOverview;
+    class WhiteboardManager;
+    class HighlightManager;
+    class HighlightEditorController;
+    class BlockListController;
+    class ContactSuggester;
+    class ContactsFromXMPPRoster;
+
+    class AccountController {
+        public:
+            AccountController(
+                    EventLoop* eventLoop,
+                    NetworkFactories* networkFactories,
+                    UIFactory* uiFactories,
+                    SettingsProvider *settings,
+                    SystemTray* systemTray,
+                    SoundPlayer* soundPlayer,
+                    StoragesFactory* storagesFactory,
+                    CertificateStorageFactory* certificateStorageFactory,
+                    Dock* dock,
+                    Notifier* notifier,
+                    URIHandler* uriHandler,
+                    IdleDetector* idleDetector,
+                    const std::map<std::string, std::string>& emoticons,
+                    bool useDelayForLatency);
+            ~AccountController();
+
+        private:
+            void resetClient();
+            void handleConnected();
+            void handleLoginRequest(const std::string& username, const std::string& password, const std::string& certificatePath, CertificateWithKey::ref certificate, const ClientOptions& options, bool remember, bool loginAutomatically);
+            void handleCancelLoginRequest();
+            void handleQuitRequest();
+            void handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText);
+            void handleDisconnected(const boost::optional<ClientError>& error);
+            void handleServerDiscoInfoResponse(std::shared_ptr<DiscoInfo>, ErrorPayload::ref);
+            void handleEventQueueLengthChange(int count);
+            void handleVCardReceived(const JID& j, VCard::ref vCard);
+            void handleSettingChanged(const std::string& settingPath);
+            void handlePurgeSavedLoginRequest(const std::string& username);
+            void sendPresence(std::shared_ptr<Presence> presence);
+            void handleInputIdleChanged(bool);
+            void handleShowCertificateRequest();
+            void logout();
+            void signOut();
+            void setReconnectTimer();
+            void resetPendingReconnects();
+            void resetCurrentError();
+            void enableMessageCarbons();
+
+            void performLoginFromCachedCredentials();
+            void reconnectAfterError();
+            void setManagersOffline();
+            void handleNotificationClicked(const JID& jid);
+            void handleForceQuit();
+            void purgeCachedCredentials();
+            std::string serializeClientOptions(const ClientOptions& options);
+
+        private:
+            EventLoop* eventLoop_;
+            NetworkFactories* networkFactories_;
+            UIFactory* uiFactory_;
+            StoragesFactory* storagesFactory_;
+            Storages* storages_;
+            CertificateStorageFactory* certificateStorageFactory_;
+            CertificateStorage* certificateStorage_;
+            CertificateStorageTrustChecker* certificateTrustChecker_;
+            bool clientInitialized_;
+            std::shared_ptr<Client> client_;
+            SettingsProvider *settings_;
+            ProfileSettingsProvider* profileSettings_ = nullptr;
+            Dock* dock_;
+            URIHandler* uriHandler_;
+            IdleDetector* idleDetector_;
+            TogglableNotifier* notifier_;
+            PresenceNotifier* presenceNotifier_;
+            EventNotifier* eventNotifier_;
+            std::unique_ptr<Chattables> chattables_;
+            RosterController* rosterController_;
+            EventController* eventController_;
+            EventWindowController* eventWindowController_;
+            AdHocManager* adHocManager_;
+            LoginWindow* loginWindow_;
+            UIEventStream* uiEventStream_;
+            XMLConsoleController* xmlConsoleController_;
+            HistoryViewController* historyViewController_;
+            HistoryController* historyController_;
+            FileTransferListController* fileTransferListController_;
+            BlockListController* blockListController_;
+            ChatsManager* chatsManager_;
+            ProfileController* profileController_;
+            ShowProfileController* showProfileController_;
+            ContactEditController* contactEditController_;
+            ContactsFromXMPPRoster* contactsFromRosterProvider_;
+            ContactSuggester* contactSuggesterWithoutRoster_;
+            ContactSuggester* contactSuggesterWithRoster_;
+            JID jid_;
+            JID boundJID_;
+            SystemTrayController* systemTrayController_;
+            SoundEventController* soundEventController_;
+            XMPPURIController* xmppURIController_;
+            std::string vCardPhotoHash_;
+            std::string password_;
+            CertificateWithKey::ref certificate_;
+            ClientOptions clientOptions_;
+            std::shared_ptr<ErrorEvent> lastDisconnectError_;
+            bool useDelayForLatency_;
+            UserSearchController* userSearchControllerChat_;
+            UserSearchController* userSearchControllerAdd_;
+            UserSearchController* userSearchControllerInvite_;
+            int timeBeforeNextReconnect_;
+            Timer::ref reconnectTimer_;
+            StatusTracker* statusTracker_;
+            bool myStatusLooksOnline_ = false;
+            bool quitRequested_;
+            bool offlineRequested_;
+            static const int SecondsToWaitBeforeForceQuitting;
+            FileTransferOverview* ftOverview_;
+            WhiteboardManager* whiteboardManager_;
+            HighlightManager* highlightManager_;
+            HighlightEditorController* highlightEditorController_;
+            std::map<std::string, std::string> emoticons_;
+            boost::signals2::connection enableCarbonsRequestHandlerConnection_;
+    };
+}
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
deleted file mode 100644
index 91140c2..0000000
--- a/Swift/Controllers/MainController.cpp
+++ /dev/null
@@ -1,870 +0,0 @@
-/*
- * Copyright (c) 2010-2018 Isode Limited.
- * All rights reserved.
- * See the COPYING file for more information.
- */
-
-#include <Swift/Controllers/MainController.h>
-
-#include <cstdlib>
-#include <memory>
-
-#include <boost/bind.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <Swiften/Base/Algorithm.h>
-#include <Swiften/Base/Log.h>
-#include <Swiften/Base/String.h>
-#include <Swiften/Base/format.h>
-#include <Swiften/Client/Client.h>
-#include <Swiften/Client/ClientBlockListManager.h>
-#include <Swiften/Client/ClientXMLTracer.h>
-#include <Swiften/Client/NickResolver.h>
-#include <Swiften/Client/StanzaChannel.h>
-#include <Swiften/Client/Storages.h>
-#include <Swiften/Crypto/CryptoProvider.h>
-#include <Swiften/Disco/CapsInfoGenerator.h>
-#include <Swiften/Disco/ClientDiscoManager.h>
-#include <Swiften/Disco/GetDiscoInfoRequest.h>
-#include <Swiften/Elements/ChatState.h>
-#include <Swiften/Elements/DiscoInfo.h>
-#include <Swiften/Elements/Presence.h>
-#include <Swiften/Elements/VCardUpdate.h>
-#include <Swiften/FileTransfer/FileTransferManager.h>
-#include <Swiften/Network/NetworkFactories.h>
-#include <Swiften/Network/TimerFactory.h>
-#include <Swiften/Presence/PresenceSender.h>
-#include <Swiften/Queries/Requests/EnableCarbonsRequest.h>
-#include <Swiften/StringCodecs/Base64.h>
-#include <Swiften/StringCodecs/Hexify.h>
-#include <Swiften/VCards/GetVCardRequest.h>
-#include <Swiften/VCards/VCardManager.h>
-
-#ifdef SWIFTEN_PLATFORM_WIN32
-#include <Swiften/SASL/WindowsAuthentication.h>
-#endif
-
-#include <Swift/Controllers/AdHocManager.h>
-#include <Swift/Controllers/BlockListController.h>
-#include <Swift/Controllers/BuildVersion.h>
-#include <Swift/Controllers/Chat/Chattables.h>
-#include <Swift/Controllers/Chat/ChatsManager.h>
-#include <Swift/Controllers/Chat/MUCController.h>
-#include <Swift/Controllers/Chat/UserSearchController.h>
-#include <Swift/Controllers/ContactEditController.h>
-#include <Swift/Controllers/ContactSuggester.h>
-#include <Swift/Controllers/ContactsFromXMPPRoster.h>
-#include <Swift/Controllers/EventNotifier.h>
-#include <Swift/Controllers/EventWindowController.h>
-#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
-#include <Swift/Controllers/FileTransferListController.h>
-#include <Swift/Controllers/Highlighting/HighlightEditorController.h>
-#include <Swift/Controllers/Highlighting/HighlightManager.h>
-#include <Swift/Controllers/HistoryController.h>
-#include <Swift/Controllers/HistoryViewController.h>
-#include <Swift/Controllers/Intl.h>
-#include <Swift/Controllers/PresenceNotifier.h>
-#include <Swift/Controllers/ProfileController.h>
-#include <Swift/Controllers/Roster/RosterController.h>
-#include <Swift/Controllers/SettingConstants.h>
-#include <Swift/Controllers/Settings/SettingsProvider.h>
-#include <Swift/Controllers/ShowProfileController.h>
-#include <Swift/Controllers/SoundEventController.h>
-#include <Swift/Controllers/SoundPlayer.h>
-#include <Swift/Controllers/StatusTracker.h>
-#include <Swift/Controllers/Storages/CertificateStorageFactory.h>
-#include <Swift/Controllers/Storages/CertificateStorageTrustChecker.h>
-#include <Swift/Controllers/Storages/StoragesFactory.h>
-#include <Swift/Controllers/SystemTray.h>
-#include <Swift/Controllers/SystemTrayController.h>
-#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
-#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
-#include <Swift/Controllers/UIEvents/UIEventStream.h>
-#include <Swift/Controllers/UIInterfaces/LoginWindow.h>
-#include <Swift/Controllers/UIInterfaces/LoginWindowFactory.h>
-#include <Swift/Controllers/UIInterfaces/MainWindow.h>
-#include <Swift/Controllers/UIInterfaces/UIFactory.h>
-#include <Swift/Controllers/WhiteboardManager.h>
-#include <Swift/Controllers/XMLConsoleController.h>
-#include <Swift/Controllers/XMPPEvents/EventController.h>
-#include <Swift/Controllers/XMPPURIController.h>
-
-#include <SwifTools/Dock/Dock.h>
-#include <SwifTools/Idle/IdleDetector.h>
-#include <SwifTools/Notifier/TogglableNotifier.h>
-
-namespace Swift {
-
-static const std::string CLIENT_NAME = "Swift";
-static const std::string CLIENT_NODE = "http://swift.im";
-
-
-MainController::MainController(
-        EventLoop* eventLoop,
-        NetworkFactories* networkFactories,
-        UIFactory* uiFactories,
-        SettingsProvider* settings,
-        SystemTray* systemTray,
-        SoundPlayer* soundPlayer,
-        StoragesFactory* storagesFactory,
-        CertificateStorageFactory* certificateStorageFactory,
-        Dock* dock,
-        Notifier* notifier,
-        URIHandler* uriHandler,
-        IdleDetector* idleDetector,
-        const std::map<std::string, std::string>& emoticons,
-        bool useDelayForLatency) :
-            eventLoop_(eventLoop),
-            networkFactories_(networkFactories),
-            uiFactory_(uiFactories),
-            storagesFactory_(storagesFactory),
-            certificateStorageFactory_(certificateStorageFactory),
-            settings_(settings),
-            uriHandler_(uriHandler),
-            idleDetector_(idleDetector),
-            loginWindow_(nullptr) ,
-            useDelayForLatency_(useDelayForLatency),
-            ftOverview_(nullptr),
-            emoticons_(emoticons) {
-    storages_ = nullptr;
-    certificateStorage_ = nullptr;
-    certificateTrustChecker_ = nullptr;
-    statusTracker_ = nullptr;
-    presenceNotifier_ = nullptr;
-    eventNotifier_ = nullptr;
-    rosterController_ = nullptr;
-    chatsManager_ = nullptr;
-    historyController_ = nullptr;
-    historyViewController_ = nullptr;
-    eventWindowController_ = nullptr;
-    profileController_ = nullptr;
-    blockListController_ = nullptr;
-    showProfileController_ = nullptr;
-    contactEditController_ = nullptr;
-    userSearchControllerChat_ = nullptr;
-    userSearchControllerAdd_ = nullptr;
-    userSearchControllerInvite_ = nullptr;
-    contactsFromRosterProvider_ = nullptr;
-    contactSuggesterWithoutRoster_ = nullptr;
-    contactSuggesterWithRoster_ = nullptr;
-    whiteboardManager_ = nullptr;
-    adHocManager_ = nullptr;
-    quitRequested_ = false;
-    clientInitialized_ = false;
-    offlineRequested_ = false;
-
-    timeBeforeNextReconnect_ = -1;
-    dock_ = dock;
-    uiEventStream_ = new UIEventStream();
-
-    notifier_ = new TogglableNotifier(notifier);
-    notifier_->setPersistentEnabled(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS));
-    eventController_ = new EventController();
-    eventController_->onEventQueueLengthChange.connect(boost::bind(&MainController::handleEventQueueLengthChange, this, _1));
-
-    systemTrayController_ = new SystemTrayController(eventController_, systemTray);
-    loginWindow_ = uiFactory_->createLoginWindow(uiEventStream_);
-    loginWindow_->setShowNotificationToggle(!notifier->isExternallyConfigured());
-
-    highlightManager_ = new HighlightManager(settings_);
-    highlightEditorController_ = new HighlightEditorController(uiEventStream_, uiFactory_, highlightManager_);
-
-    soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings, highlightManager_);
-
-    xmppURIController_ = new XMPPURIController(uriHandler_, uiEventStream_);
-
-    loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4, _5, _6, _7));
-    loginWindow_->onPurgeSavedLoginRequest.connect(boost::bind(&MainController::handlePurgeSavedLoginRequest, this, _1));
-    loginWindow_->onCancelLoginRequest.connect(boost::bind(&MainController::handleCancelLoginRequest, this));
-    loginWindow_->onQuitRequest.connect(boost::bind(&MainController::handleQuitRequest, this));
-
-    idleDetector_->setIdleTimeSeconds(settings->getSetting(SettingConstants::IDLE_TIMEOUT));
-    idleDetector_->onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1));
-
-    xmlConsoleController_ = new XMLConsoleController(uiEventStream_, uiFactory_);
-
-    fileTransferListController_ = new FileTransferListController(uiEventStream_, uiFactory_);
-
-    settings_->onSettingChanged.connect(boost::bind(&MainController::handleSettingChanged, this, _1));
-
-}
-
-MainController::~MainController() {
-    idleDetector_->onIdleChanged.disconnect(boost::bind(&MainController::handleInputIdleChanged, this, _1));
-
-    purgeCachedCredentials();
-    //setManagersOffline();
-    eventController_->disconnectAll();
-
-    resetClient();
-    delete highlightEditorController_;
-    delete highlightManager_;
-    delete fileTransferListController_;
-    delete xmlConsoleController_;
-    delete xmppURIController_;
-    delete soundEventController_;
-    delete systemTrayController_;
-    delete eventController_;
-    delete notifier_;
-    delete uiEventStream_;
-}
-
-void MainController::purgeCachedCredentials() {
-    safeClear(password_);
-}
-
-void MainController::resetClient() {
-    purgeCachedCredentials();
-    resetCurrentError();
-    resetPendingReconnects();
-    vCardPhotoHash_.clear();
-    delete contactEditController_;
-    contactEditController_ = nullptr;
-    delete profileController_;
-    profileController_ = nullptr;
-    delete showProfileController_;
-    showProfileController_ = nullptr;
-    delete eventWindowController_;
-    eventWindowController_ = nullptr;
-    delete chatsManager_;
-    chatsManager_ = nullptr;
-#ifdef SWIFT_EXPERIMENTAL_HISTORY
-    delete historyViewController_;
-    historyViewController_ = nullptr;
-    delete historyController_;
-    historyController_ = nullptr;
-#endif
-    fileTransferListController_->setFileTransferOverview(nullptr);
-    delete ftOverview_;
-    ftOverview_ = nullptr;
-    delete blockListController_;
-    blockListController_ = nullptr;
-    delete rosterController_;
-    rosterController_ = nullptr;
-    chattables_.reset();
-    delete eventNotifier_;
-    eventNotifier_ = nullptr;
-    delete presenceNotifier_;
-    presenceNotifier_ = nullptr;
-    delete certificateTrustChecker_;
-    certificateTrustChecker_ = nullptr;
-    delete certificateStorage_;
-    certificateStorage_ = nullptr;
-    delete storages_;
-    storages_ = nullptr;
-    delete statusTracker_;
-    statusTracker_ = nullptr;
-    delete profileSettings_;
-    profileSettings_ = nullptr;
-    delete userSearchControllerChat_;
-    userSearchControllerChat_ = nullptr;
-    delete userSearchControllerAdd_;
-    userSearchControllerAdd_ = nullptr;
-    delete userSearchControllerInvite_;
-    userSearchControllerInvite_ = nullptr;
-    delete contactSuggesterWithoutRoster_;
-    contactSuggesterWithoutRoster_ = nullptr;
-    delete contactSuggesterWithRoster_;
-    contactSuggesterWithRoster_ = nullptr;
-    delete contactsFromRosterProvider_;
-    contactsFromRosterProvider_ = nullptr;
-    delete adHocManager_;
-    adHocManager_ = nullptr;
-    delete whiteboardManager_;
-    whiteboardManager_ = nullptr;
-    clientInitialized_ = false;
-}
-
-void MainController::handleSettingChanged(const std::string& settingPath) {
-    if (settingPath == SettingConstants::SHOW_NOTIFICATIONS.getKey()) {
-        notifier_->setPersistentEnabled(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS));
-    }
-}
-
-void MainController::resetPendingReconnects() {
-    timeBeforeNextReconnect_ = -1;
-    if (reconnectTimer_) {
-        reconnectTimer_->stop();
-        reconnectTimer_.reset();
-    }
-    resetCurrentError();
-}
-
-void MainController::resetCurrentError() {
-    if (lastDisconnectError_) {
-        lastDisconnectError_->conclude();
-        lastDisconnectError_ = std::shared_ptr<ErrorEvent>();
-    }
-}
-
-void MainController::handleConnected() {
-    boundJID_ = client_->getJID();
-    resetCurrentError();
-    resetPendingReconnects();
-
-    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
-        purgeCachedCredentials();
-    }
-
-    bool freshLogin = rosterController_ == nullptr;
-    myStatusLooksOnline_ = true;
-    if (freshLogin) {
-        profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
-        showProfileController_ = new ShowProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
-        ftOverview_ = new FileTransferOverview(client_->getFileTransferManager());
-        fileTransferListController_->setFileTransferOverview(ftOverview_);
-        chattables_ = std::make_unique<Chattables>();
-        rosterController_ = new RosterController(boundJID_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), client_->getClientBlockListManager(), client_->getVCardManager(), *chattables_);
-        rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
-        rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this));
-        rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&MainController::handleShowCertificateRequest, this));
-
-        blockListController_ = new BlockListController(client_->getClientBlockListManager(), uiEventStream_, uiFactory_, eventController_);
-
-        contactEditController_ = new ContactEditController(rosterController_, client_->getVCardManager(), uiFactory_, uiEventStream_);
-        whiteboardManager_ = new WhiteboardManager(uiFactory_, uiEventStream_, client_->getNickResolver(), client_->getWhiteboardSessionManager());
-
-        /* Doing this early as an ordering fix. Various things later will
-         * want to have the user's nick available and this means it will
-         * be before they receive stanzas that need it (e.g. bookmarks).*/
-        client_->getVCardManager()->requestOwnVCard();
-
-        contactSuggesterWithoutRoster_ = new ContactSuggester();
-        contactSuggesterWithRoster_ = new ContactSuggester();
-
-        userSearchControllerInvite_ = new UserSearchController(UserSearchController::Type::InviteToChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle(), profileSettings_);
-#ifdef SWIFT_EXPERIMENTAL_HISTORY
-        historyController_ = new HistoryController(storages_->getHistoryStorage());
-        historyViewController_ = new HistoryViewController(jid_, uiEventStream_, historyController_, client_->getNickResolver(), client_->getAvatarManager(), client_->getPresenceOracle(), uiFactory_);
-        chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, client_->getVCardManager());
-#else
-        chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, nullptr, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, client_->getVCardManager(), *chattables_);
-#endif
-        contactsFromRosterProvider_ = new ContactsFromXMPPRoster(client_->getRoster(), client_->getAvatarManager(), client_->getPresenceOracle());
-        contactSuggesterWithoutRoster_->addContactProvider(chatsManager_);
-        contactSuggesterWithRoster_->addContactProvider(chatsManager_);
-        contactSuggesterWithRoster_->addContactProvider(contactsFromRosterProvider_);
-        highlightEditorController_->setContactSuggester(contactSuggesterWithoutRoster_);
-
-        client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
-        chatsManager_->setAvatarManager(client_->getAvatarManager());
-
-        eventWindowController_ = new EventWindowController(eventController_, uiFactory_);
-
-        loginWindow_->morphInto(rosterController_->getWindow());
-
-        DiscoInfo discoInfo;
-        discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc"));
-        discoInfo.addFeature(DiscoInfo::ChatStatesFeature);
-        discoInfo.addFeature(DiscoInfo::SecurityLabelsFeature);
-        discoInfo.addFeature(DiscoInfo::MessageCorrectionFeature);
-#ifdef SWIFT_EXPERIMENTAL_FT
-        discoInfo.addFeature(DiscoInfo::JingleFeature);
-        discoInfo.addFeature(DiscoInfo::JingleFTFeature);
-        discoInfo.addFeature(DiscoInfo::JingleTransportsIBBFeature);
-        discoInfo.addFeature(DiscoInfo::JingleTransportsS5BFeature);
-#endif
-#ifdef SWIFT_EXPERIMENTAL_WB
-        discoInfo.addFeature(DiscoInfo::WhiteboardFeature);
-#endif
-        discoInfo.addFeature(DiscoInfo::MessageDeliveryReceiptsFeature);
-        client_->getDiscoManager()->setCapsNode(CLIENT_NODE);
-        client_->getDiscoManager()->setDiscoInfo(discoInfo);
-
-        userSearchControllerChat_ = new UserSearchController(UserSearchController::Type::StartChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle(), profileSettings_);
-        userSearchControllerAdd_ = new UserSearchController(UserSearchController::Type::AddContact, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithoutRoster_, client_->getAvatarManager(), client_->getPresenceOracle(), profileSettings_);
-        adHocManager_ = new AdHocManager(JID(boundJID_.getDomain()), uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow());
-
-        chatsManager_->onImpromptuMUCServiceDiscovered.connect(boost::bind(&UserSearchController::setCanInitiateImpromptuMUC, userSearchControllerChat_, _1));
-    }
-    loginWindow_->setIsLoggingIn(false);
-
-    client_->requestRoster();
-
-    GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(boundJID_.getDomain()), client_->getIQRouter());
-    discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2));
-    discoInfoRequest->send();
-
-    client_->getVCardManager()->requestOwnVCard();
-
-    rosterController_->setJID(boundJID_);
-    rosterController_->setEnabled(true);
-    rosterController_->getWindow()->setStreamEncryptionStatus(client_->isStreamEncrypted());
-    profileController_->setAvailable(true);
-    contactEditController_->setAvailable(true);
-    /* Send presence later to catch all the incoming presences. */
-    sendPresence(statusTracker_->getNextPresence());
-
-    /* Enable chats last of all, so rejoining MUCs has the right sent presence */
-    assert(chatsManager_);
-    chatsManager_->setOnline(true);
-    adHocManager_->setOnline(true);
-}
-
-void MainController::handleEventQueueLengthChange(int count) {
-    dock_->setNumberOfPendingMessages(count);
-}
-
-void MainController::reconnectAfterError() {
-    if (reconnectTimer_) {
-        reconnectTimer_->stop();
-    }
-    performLoginFromCachedCredentials();
-}
-
-void MainController::handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText) {
-    std::shared_ptr<Presence> presence(new Presence());
-    if (show == StatusShow::None) {
-        // Note: this is misleading, None doesn't mean unavailable on the wire.
-        presence->setType(Presence::Unavailable);
-        resetPendingReconnects();
-        myStatusLooksOnline_ = false;
-        offlineRequested_ = true;
-    }
-    else {
-        offlineRequested_ = false;
-        presence->setShow(show);
-    }
-    presence->setStatus(statusText);
-    statusTracker_->setRequestedPresence(presence);
-    if (presence->getType() != Presence::Unavailable) {
-        profileSettings_->storeInt("lastShow", presence->getShow());
-        profileSettings_->storeString("lastStatus", presence->getStatus());
-    }
-    if (presence->getType() != Presence::Unavailable && !client_->isAvailable()) {
-        performLoginFromCachedCredentials();
-    } else {
-        sendPresence(presence);
-    }
-}
-
-void MainController::sendPresence(std::shared_ptr<Presence> presence) {
-    rosterController_->getWindow()->setMyStatusType(presence->getShow());
-    rosterController_->getWindow()->setMyStatusText(presence->getStatus());
-    systemTrayController_->setMyStatusType(presence->getShow());
-    notifier_->setTemporarilyDisabled(presence->getShow() == StatusShow::DND);
-
-    // Add information and send
-    presence->updatePayload(std::make_shared<VCardUpdate>(vCardPhotoHash_));
-    client_->getPresenceSender()->sendPresence(presence);
-    if (presence->getType() == Presence::Unavailable) {
-        logout();
-    }
-}
-
-void MainController::handleInputIdleChanged(bool idle) {
-    if (!statusTracker_) {
-        //Haven't logged in yet.
-        return;
-    }
-
-    if (settings_->getSetting(SettingConstants::IDLE_GOES_OFFLINE)) {
-        if (idle) {
-            logout();
-        }
-    }
-    else {
-        if (idle) {
-            if (statusTracker_->goAutoAway(idleDetector_->getIdleTimeSeconds())) {
-                if (client_ && client_->isAvailable()) {
-                    sendPresence(statusTracker_->getNextPresence());
-                }
-            }
-        } else {
-            if (statusTracker_->goAutoUnAway()) {
-                if (client_ && client_->isAvailable()) {
-                    sendPresence(statusTracker_->getNextPresence());
-                }
-            }
-        }
-    }
-}
-
-void MainController::handleShowCertificateRequest() {
-    std::vector<Certificate::ref> chain = client_->getStanzaChannel()->getPeerCertificateChain();
-    rosterController_->getWindow()->openCertificateDialog(chain);
-}
-
-void MainController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificatePath, CertificateWithKey::ref certificate, const ClientOptions& options, bool remember, bool loginAutomatically) {
-    jid_ = JID(username);
-    if (options.singleSignOn && (!jid_.isValid() || !jid_.getNode().empty())) {
-        loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'wonderland.lit'"));
-        loginWindow_->setIsLoggingIn(false);
-    } else if (!options.singleSignOn && (!jid_.isValid() || jid_.getNode().empty())) {
-        loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'alice@wonderland.lit'"));
-        loginWindow_->setIsLoggingIn(false);
-    } else {
-#ifdef SWIFTEN_PLATFORM_WIN32
-        if (options.singleSignOn) {
-            std::string userName;
-            std::string clientName;
-            std::string serverName;
-            std::shared_ptr<boost::system::error_code> errorCode = getUserNameEx(userName, clientName, serverName);
-
-            if (!errorCode) {
-                /* Create JID using the Windows logon name and user provided domain name */
-                jid_ = JID(clientName, username);
-            }
-            else {
-                loginWindow_->setMessage(str(format(QT_TRANSLATE_NOOP("", "Error obtaining Windows user name (%1%)")) % errorCode->message()));
-                loginWindow_->setIsLoggingIn(false);
-                return;
-            }
-        }
-#endif
-
-        loginWindow_->setMessage("");
-        loginWindow_->setIsLoggingIn(true);
-        profileSettings_ = new ProfileSettingsProvider(username, settings_);
-        if (!settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
-            profileSettings_->storeString("jid", username);
-            profileSettings_->storeString("certificate", certificatePath);
-            profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : "");
-            std::string optionString = serializeClientOptions(options);
-            profileSettings_->storeString("options", optionString);
-            profileSettings_->storeInt("enabled", 1);
-            loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate"), options);
-        }
-
-        password_ = password;
-        certificate_ = certificate;
-        clientOptions_ = options;
-        performLoginFromCachedCredentials();
-    }
-}
-
-void MainController::handlePurgeSavedLoginRequest(const std::string& username) {
-    settings_->removeProfile(username);
-    loginWindow_->removeAvailableAccount(username);
-}
-
-void MainController::performLoginFromCachedCredentials() {
-    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS) && password_.empty()) {
-        /* Then we can't try to login again. */
-        return;
-    }
-    /* If we logged in with a bare JID, and we have a full bound JID, re-login with the
-     * bound JID to try and keep dynamically assigned resources */
-    JID clientJID = jid_;
-    if (boundJID_.isValid() && jid_.isBare() && boundJID_.toBare() == jid_) {
-        clientJID = boundJID_;
-    }
-
-    if (!statusTracker_) {
-        statusTracker_  = new StatusTracker();
-    }
-    if (!clientInitialized_) {
-        storages_ = storagesFactory_->createStorages(jid_.toBare());
-        certificateStorage_ = certificateStorageFactory_->createCertificateStorage(jid_.toBare());
-        certificateTrustChecker_ = new CertificateStorageTrustChecker(certificateStorage_);
-
-        client_ = std::make_shared<Swift::Client>(clientJID, createSafeByteArray(password_.c_str()), networkFactories_, storages_);
-        clientInitialized_ = true;
-        client_->setCertificateTrustChecker(certificateTrustChecker_);
-        client_->onDataRead.connect(boost::bind(&XMLConsoleController::handleDataRead, xmlConsoleController_, _1));
-        client_->onDataWritten.connect(boost::bind(&XMLConsoleController::handleDataWritten, xmlConsoleController_, _1));
-        client_->onDisconnected.connect(boost::bind(&MainController::handleDisconnected, this, _1));
-        client_->onConnected.connect(boost::bind(&MainController::handleConnected, this));
-
-        client_->setSoftwareVersion(CLIENT_NAME, buildVersion);
-
-        client_->getVCardManager()->onVCardChanged.connect(boost::bind(&MainController::handleVCardReceived, this, _1, _2));
-        presenceNotifier_ = new PresenceNotifier(client_->getStanzaChannel(), notifier_, client_->getMUCRegistry(), client_->getAvatarManager(), client_->getNickResolver(), client_->getPresenceOracle(), networkFactories_->getTimerFactory());
-        presenceNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1));
-        eventNotifier_ = new EventNotifier(eventController_, notifier_, client_->getAvatarManager(), client_->getNickResolver());
-        eventNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1));
-        if (certificate_) {
-            client_->setCertificate(certificate_);
-        }
-        std::shared_ptr<Presence> presence(new Presence());
-        presence->setShow(static_cast<StatusShow::Type>(profileSettings_->getIntSetting("lastShow", StatusShow::Online)));
-        presence->setStatus(profileSettings_->getStringSetting("lastStatus"));
-        statusTracker_->setRequestedPresence(presence);
-    } else {
-        /* In case we're in the middle of another login, make sure they don't overlap */
-        client_->disconnect();
-    }
-    systemTrayController_->setConnecting();
-    if (rosterController_) {
-        rosterController_->getWindow()->setConnecting();
-    }
-    ClientOptions clientOptions = clientOptions_;
-    bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
-    clientOptions.forgetPassword = eagle;
-    clientOptions.useTLS = eagle ? ClientOptions::RequireTLS : clientOptions_.useTLS;
-    client_->connect(clientOptions);
-}
-
-void MainController::handleDisconnected(const boost::optional<ClientError>& error) {
-    if (rosterController_) {
-        rosterController_->getWindow()->setStreamEncryptionStatus(false);
-    }
-    if (adHocManager_) {
-        adHocManager_->setOnline(false);
-    }
-    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
-        purgeCachedCredentials();
-    }
-    if (quitRequested_) {
-        resetClient();
-        loginWindow_->quit();
-    }
-    else if (error) {
-        std::string message;
-        std::string certificateErrorMessage;
-        bool forceSignout = false;
-        switch(error->getType()) {
-            case ClientError::UnknownError: message = QT_TRANSLATE_NOOP("", "Unknown Error"); break;
-            case ClientError::DomainNameResolveError: message = QT_TRANSLATE_NOOP("", "Unable to find server"); break;
-            case ClientError::ConnectionError: message = QT_TRANSLATE_NOOP("", "Error connecting to server"); break;
-            case ClientError::ConnectionReadError: message = QT_TRANSLATE_NOOP("", "Error while receiving server data"); break;
-            case ClientError::ConnectionWriteError: message = QT_TRANSLATE_NOOP("", "Error while sending data to the server"); break;
-            case ClientError::XMLError: message = QT_TRANSLATE_NOOP("", "Error parsing server data"); break;
-            case ClientError::AuthenticationFailedError: message = QT_TRANSLATE_NOOP("", "Login/password invalid"); break;
-            case ClientError::CompressionFailedError: message = QT_TRANSLATE_NOOP("", "Error while compressing stream"); break;
-            case ClientError::ServerVerificationFailedError: message = QT_TRANSLATE_NOOP("", "Server verification failed"); break;
-            case ClientError::NoSupportedAuthMechanismsError: message = QT_TRANSLATE_NOOP("", "Authentication mechanisms not supported"); break;
-            case ClientError::UnexpectedElementError: message = QT_TRANSLATE_NOOP("", "Unexpected response"); break;
-            case ClientError::ResourceBindError: message = QT_TRANSLATE_NOOP("", "Error binding resource"); break;
-            case ClientError::SessionStartError: message = QT_TRANSLATE_NOOP("", "Error starting session"); break;
-            case ClientError::StreamError: message = QT_TRANSLATE_NOOP("", "Stream error"); break;
-            case ClientError::TLSError: message = QT_TRANSLATE_NOOP("", "Encryption error"); break;
-            case ClientError::ClientCertificateLoadError: message = QT_TRANSLATE_NOOP("", "Error loading certificate (Invalid file or password?)"); break;
-            case ClientError::ClientCertificateError: message = QT_TRANSLATE_NOOP("", "Certificate not authorized"); break;
-            case ClientError::CertificateCardRemoved: message = QT_TRANSLATE_NOOP("", "Certificate card removed"); forceSignout = true; break;
-
-            case ClientError::UnknownCertificateError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Unknown certificate"); break;
-            case ClientError::CertificateExpiredError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has expired"); break;
-            case ClientError::CertificateNotYetValidError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is not yet valid"); break;
-            case ClientError::CertificateSelfSignedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is self-signed"); break;
-            case ClientError::CertificateRejectedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has been rejected"); break;
-            case ClientError::CertificateUntrustedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is not trusted"); break;
-            case ClientError::InvalidCertificatePurposeError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate cannot be used for encrypting your connection"); break;
-            case ClientError::CertificatePathLengthExceededError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate path length constraint exceeded"); break;
-            case ClientError::InvalidCertificateSignatureError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Invalid certificate signature"); break;
-            case ClientError::InvalidCAError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Invalid Certificate Authority"); break;
-            case ClientError::InvalidServerIdentityError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate does not match the host identity"); break;
-            case ClientError::RevokedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has been revoked"); break;
-            case ClientError::RevocationCheckFailedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Unable to determine certificate revocation state"); break;
-        }
-        bool forceReconnectAfterCertificateTrust = false;
-        if (!certificateErrorMessage.empty()) {
-            std::vector<Certificate::ref> certificates = certificateTrustChecker_->getLastCertificateChain();
-            if (!certificates.empty() && loginWindow_->askUserToTrustCertificatePermanently(certificateErrorMessage, certificates)) {
-                certificateStorage_->addCertificate(certificates[0]);
-                forceReconnectAfterCertificateTrust = true;
-            }
-            else {
-                message = QT_TRANSLATE_NOOP("", "Certificate error");
-            }
-        }
-
-        if (!message.empty() && error->getErrorCode()) {
-            message = str(format(QT_TRANSLATE_NOOP("", "%1% (%2%)")) % message % error->getErrorCode()->message());
-        }
-
-        if (forceReconnectAfterCertificateTrust && settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
-            forceReconnectAfterCertificateTrust = false;
-            forceSignout = true;
-            message = QT_TRANSLATE_NOOP("", "Re-enter credentials and retry");
-        }
-
-        if (forceReconnectAfterCertificateTrust) {
-            performLoginFromCachedCredentials();
-        }
-        else if (forceSignout || !rosterController_) { //hasn't been logged in yet or permanent error
-            signOut();
-            loginWindow_->setMessage(message);
-            loginWindow_->setIsLoggingIn(false);
-        } else {
-            logout();
-            if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
-                message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%. To reconnect, Sign Out and provide your password again.")) % jid_.getDomain() % message);
-            } else {
-                if (!offlineRequested_) {
-                    setReconnectTimer();
-                }
-                if (lastDisconnectError_) {
-                    message = str(format(QT_TRANSLATE_NOOP("", "Reconnect to %1% failed: %2%. Will retry in %3% seconds.")) % jid_.getDomain() % message % boost::lexical_cast<std::string>(timeBeforeNextReconnect_));
-                    lastDisconnectError_->conclude();
-                } else {
-                    message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%.")) % jid_.getDomain() % message);
-                }
-                lastDisconnectError_ = std::make_shared<ErrorEvent>(JID(jid_.getDomain()), message);
-                eventController_->handleIncomingEvent(lastDisconnectError_);
-            }
-        }
-    }
-    else if (!rosterController_) { //hasn't been logged in yet
-        loginWindow_->setIsLoggingIn(false);
-    }
-}
-
-void MainController::setReconnectTimer() {
-    if (timeBeforeNextReconnect_ < 0) {
-        timeBeforeNextReconnect_ = 1;
-    } else {
-        timeBeforeNextReconnect_ = timeBeforeNextReconnect_ >= 150 ? 300 : timeBeforeNextReconnect_ * 2; // Randomly selected by roll of a die, as required by 3920bis
-    }
-    if (reconnectTimer_) {
-        reconnectTimer_->stop();
-    }
-    reconnectTimer_ = networkFactories_->getTimerFactory()->createTimer(timeBeforeNextReconnect_ * 1000);
-    reconnectTimer_->onTick.connect(boost::bind(&MainController::reconnectAfterError, this));
-    reconnectTimer_->start();
-}
-
-void MainController::handleCancelLoginRequest() {
-    signOut();
-}
-
-void MainController::signOut() {
-    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
-        purgeCachedCredentials();
-    }
-    profileSettings_->storeInt("enabled", 0);
-    eventController_->clear();
-    logout();
-    loginWindow_->loggedOut();
-    resetClient();
-}
-
-void MainController::logout() {
-    if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
-        purgeCachedCredentials();
-    }
-    systemTrayController_->setMyStatusType(StatusShow::None);
-    if (clientInitialized_ /*&& client_->isAvailable()*/) {
-        client_->disconnect();
-    }
-    if (rosterController_ && myStatusLooksOnline_) {
-        rosterController_->getWindow()->setMyStatusType(StatusShow::None);
-        rosterController_->getWindow()->setMyStatusText("");
-        myStatusLooksOnline_ = false;
-    }
-    setManagersOffline();
-}
-
-void MainController::setManagersOffline() {
-    if (chatsManager_) {
-        chatsManager_->setOnline(false);
-    }
-    if (rosterController_) {
-        rosterController_->setEnabled(false);
-    }
-    if (profileController_) {
-        profileController_->setAvailable(false);
-    }
-    if (contactEditController_) {
-        contactEditController_->setAvailable(false);
-    }
-}
-
-void MainController::handleServerDiscoInfoResponse(std::shared_ptr<DiscoInfo> info, ErrorPayload::ref error) {
-    if (!error) {
-        chatsManager_->setServerDiscoInfo(info);
-        adHocManager_->setServerDiscoInfo(info);
-        if (info->hasFeature(DiscoInfo::BlockingCommandFeature)) {
-            rosterController_->getWindow()->setBlockingCommandAvailable(true);
-            rosterController_->initBlockingCommand();
-        }
-        if (info->hasFeature(DiscoInfo::MessageCarbonsFeature)) {
-            enableMessageCarbons();
-        }
-    }
-}
-
-void MainController::enableMessageCarbons() {
-    auto enableCarbonsRequest = EnableCarbonsRequest::create(client_->getIQRouter());
-    enableCarbonsRequestHandlerConnection_ = enableCarbonsRequest->onResponse.connect([&](Payload::ref /*payload*/, ErrorPayload::ref error) {
-        if (error) {
-            SWIFT_LOG(warning) << "Failed to enable carbons." << std::endl;
-        }
-        else {
-            SWIFT_LOG(debug) << "Successfully enabled carbons." << std::endl;
-        }
-        enableCarbonsRequestHandlerConnection_.disconnect();
-    });
-    enableCarbonsRequest->send();
-}
-
-void MainController::handleVCardReceived(const JID& jid, VCard::ref vCard) {
-    if (!jid.equals(jid_, JID::WithoutResource) || !vCard) {
-        return;
-    }
-    std::string hash;
-    if (!vCard->getPhoto().empty()) {
-        hash = Hexify::hexify(networkFactories_->getCryptoProvider()->getSHA1Hash(vCard->getPhoto()));
-    }
-    if (hash != vCardPhotoHash_) {
-        vCardPhotoHash_ = hash;
-        if (client_ && client_->isAvailable()) {
-            sendPresence(statusTracker_->getNextPresence());
-        }
-    }
-}
-
-void MainController::handleNotificationClicked(const JID& jid) {
-    assert(chatsManager_);
-    if (clientInitialized_) {
-        if (client_->getMUCRegistry()->isMUC(jid)) {
-            uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(jid));
-        }
-        else {
-            uiEventStream_->send(std::make_shared<RequestChatUIEvent>(jid));
-        }
-    }
-}
-
-void MainController::handleQuitRequest() {
-    if (client_ && client_->isActive()) {
-        quitRequested_ = true;
-        client_->disconnect();
-    }
-    else {
-        resetClient();
-        loginWindow_->quit();
-    }
-}
-
-//FIXME: Switch all this to boost::serialise
-
-#define SERIALIZE_BOOL(option) result += options.option ? "1" : "0"; result += ",";
-#define SERIALIZE_INT(option) result += boost::lexical_cast<std::string>(options.option); result += ",";
-#define SERIALIZE_STRING(option) result += Base64::encode(createByteArray(options.option)); result += ",";
-#define SERIALIZE_SAFE_STRING(option) result += safeByteArrayToString(Base64::encode(options.option)); result += ",";
-#define SERIALIZE_URL(option) SERIALIZE_STRING(option.toString())
-
-std::string MainController::serializeClientOptions(const ClientOptions& options) {
-    std::string result;
-    SERIALIZE_BOOL(useStreamCompression);
-    switch (options.useTLS) {
-        case ClientOptions::NeverUseTLS: result += "1";break;
-        case ClientOptions::UseTLSWhenAvailable: result += "2";break;
-        case ClientOptions::RequireTLS: result += "3";break;
-    }
-    result += ",";
-    SERIALIZE_BOOL(allowPLAINWithoutTLS);
-    SERIALIZE_BOOL(useStreamResumption);
-    SERIALIZE_BOOL(useAcks);
-    SERIALIZE_STRING(manualHostname);
-    SERIALIZE_INT(manualPort);
-    switch (options.proxyType) {
-        case ClientOptions::NoProxy: result += "1";break;
-        case ClientOptions::SystemConfiguredProxy: result += "2";break;
-        case ClientOptions::SOCKS5Proxy: result += "3";break;
-        case ClientOptions::HTTPConnectProxy: result += "4";break;
-    }
-    result += ",";
-    SERIALIZE_STRING(manualProxyHostname);
-    SERIALIZE_INT(manualProxyPort);
-    SERIALIZE_URL(boshURL);
-    SERIALIZE_URL(boshHTTPConnectProxyURL);
-    SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthID);
-    SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthPassword);
-    SERIALIZE_BOOL(tlsOptions.schannelTLS1_0Workaround);
-    SERIALIZE_BOOL(singleSignOn);
-    return result;
-}
-
-}
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
deleted file mode 100644
index b345e0e..0000000
--- a/Swift/Controllers/MainController.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2010-2018 Isode Limited.
- * All rights reserved.
- * See the COPYING file for more information.
- */
-
-#pragma once
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <boost/signals2.hpp>
-
-#include <Swiften/Client/ClientError.h>
-#include <Swiften/Client/ClientXMLTracer.h>
-#include <Swiften/Elements/CapsInfo.h>
-#include <Swiften/Elements/DiscoInfo.h>
-#include <Swiften/Elements/ErrorPayload.h>
-#include <Swiften/Elements/Presence.h>
-#include <Swiften/Elements/VCard.h>
-#include <Swiften/JID/JID.h>
-#include <Swiften/Network/Timer.h>
-
-#include <Swift/Controllers/ProfileSettingsProvider.h>
-#include <Swift/Controllers/Settings/SettingsProvider.h>
-#include <Swift/Controllers/UIEvents/UIEvent.h>
-#include <Swift/Controllers/XMPPEvents/ErrorEvent.h>
-
-namespace Swift {
-    class IdleDetector;
-    class UIFactory;
-    class EventLoop;
-    class Client;
-    class Chattables;
-    class ChatController;
-    class ChatsManager;
-    class CertificateStorageFactory;
-    class CertificateStorage;
-    class CertificateStorageTrustChecker;
-    class EventController;
-    class MainWindow;
-    class RosterController;
-    class LoginWindow;
-    class EventLoop;
-    class MUCController;
-    class Notifier;
-    class ProfileController;
-    class ShowProfileController;
-    class ContactEditController;
-    class TogglableNotifier;
-    class PresenceNotifier;
-    class EventNotifier;
-    class SystemTray;
-    class SystemTrayController;
-    class SoundEventController;
-    class SoundPlayer;
-    class XMLConsoleController;
-    class HistoryViewController;
-    class HistoryController;
-    class FileTransferListController;
-    class UIEventStream;
-    class EventWindowFactory;
-    class EventWindowController;
-    class MUCSearchController;
-    class UserSearchController;
-    class StatusTracker;
-    class Dock;
-    class Storages;
-    class StoragesFactory;
-    class NetworkFactories;
-    class URIHandler;
-    class XMPPURIController;
-    class AdHocManager;
-    class AdHocCommandWindowFactory;
-    class FileTransferOverview;
-    class WhiteboardManager;
-    class HighlightManager;
-    class HighlightEditorController;
-    class BlockListController;
-    class ContactSuggester;
-    class ContactsFromXMPPRoster;
-
-    class MainController {
-        public:
-            MainController(
-                    EventLoop* eventLoop,
-                    NetworkFactories* networkFactories,
-                    UIFactory* uiFactories,
-                    SettingsProvider *settings,
-                    SystemTray* systemTray,
-                    SoundPlayer* soundPlayer,
-                    StoragesFactory* storagesFactory,
-                    CertificateStorageFactory* certificateStorageFactory,
-                    Dock* dock,
-                    Notifier* notifier,
-                    URIHandler* uriHandler,
-                    IdleDetector* idleDetector,
-                    const std::map<std::string, std::string>& emoticons,
-                    bool useDelayForLatency);
-            ~MainController();
-
-        private:
-            void resetClient();
-            void handleConnected();
-            void handleLoginRequest(const std::string& username, const std::string& password, const std::string& certificatePath, CertificateWithKey::ref certificate, const ClientOptions& options, bool remember, bool loginAutomatically);
-            void handleCancelLoginRequest();
-            void handleQuitRequest();
-            void handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText);
-            void handleDisconnected(const boost::optional<ClientError>& error);
-            void handleServerDiscoInfoResponse(std::shared_ptr<DiscoInfo>, ErrorPayload::ref);
-            void handleEventQueueLengthChange(int count);
-            void handleVCardReceived(const JID& j, VCard::ref vCard);
-            void handleSettingChanged(const std::string& settingPath);
-            void handlePurgeSavedLoginRequest(const std::string& username);
-            void sendPresence(std::shared_ptr<Presence> presence);
-            void handleInputIdleChanged(bool);
-            void handleShowCertificateRequest();
-            void logout();
-            void signOut();
-            void setReconnectTimer();
-            void resetPendingReconnects();
-            void resetCurrentError();
-            void enableMessageCarbons();
-
-            void performLoginFromCachedCredentials();
-            void reconnectAfterError();
-            void setManagersOffline();
-            void handleNotificationClicked(const JID& jid);
-            void handleForceQuit();
-            void purgeCachedCredentials();
-            std::string serializeClientOptions(const ClientOptions& options);
-
-        private:
-            EventLoop* eventLoop_;
-            NetworkFactories* networkFactories_;
-            UIFactory* uiFactory_;
-            StoragesFactory* storagesFactory_;
-            Storages* storages_;
-            CertificateStorageFactory* certificateStorageFactory_;
-            CertificateStorage* certificateStorage_;
-            CertificateStorageTrustChecker* certificateTrustChecker_;
-            bool clientInitialized_;
-            std::shared_ptr<Client> client_;
-            SettingsProvider *settings_;
-            ProfileSettingsProvider* profileSettings_ = nullptr;
-            Dock* dock_;
-            URIHandler* uriHandler_;
-            IdleDetector* idleDetector_;
-            TogglableNotifier* notifier_;
-            PresenceNotifier* presenceNotifier_;
-            EventNotifier* eventNotifier_;
-            std::unique_ptr<Chattables> chattables_;
-            RosterController* rosterController_;
-            EventController* eventController_;
-            EventWindowController* eventWindowController_;
-            AdHocManager* adHocManager_;
-            LoginWindow* loginWindow_;
-            UIEventStream* uiEventStream_;
-            XMLConsoleController* xmlConsoleController_;
-            HistoryViewController* historyViewController_;
-            HistoryController* historyController_;
-            FileTransferListController* fileTransferListController_;
-            BlockListController* blockListController_;
-            ChatsManager* chatsManager_;
-            ProfileController* profileController_;
-            ShowProfileController* showProfileController_;
-            ContactEditController* contactEditController_;
-            ContactsFromXMPPRoster* contactsFromRosterProvider_;
-            ContactSuggester* contactSuggesterWithoutRoster_;
-            ContactSuggester* contactSuggesterWithRoster_;
-            JID jid_;
-            JID boundJID_;
-            SystemTrayController* systemTrayController_;
-            SoundEventController* soundEventController_;
-            XMPPURIController* xmppURIController_;
-            std::string vCardPhotoHash_;
-            std::string password_;
-            CertificateWithKey::ref certificate_;
-            ClientOptions clientOptions_;
-            std::shared_ptr<ErrorEvent> lastDisconnectError_;
-            bool useDelayForLatency_;
-            UserSearchController* userSearchControllerChat_;
-            UserSearchController* userSearchControllerAdd_;
-            UserSearchController* userSearchControllerInvite_;
-            int timeBeforeNextReconnect_;
-            Timer::ref reconnectTimer_;
-            StatusTracker* statusTracker_;
-            bool myStatusLooksOnline_ = false;
-            bool quitRequested_;
-            bool offlineRequested_;
-            static const int SecondsToWaitBeforeForceQuitting;
-            FileTransferOverview* ftOverview_;
-            WhiteboardManager* whiteboardManager_;
-            HighlightManager* highlightManager_;
-            HighlightEditorController* highlightEditorController_;
-            std::map<std::string, std::string> emoticons_;
-            boost::signals2::connection enableCarbonsRequestHandlerConnection_;
-    };
-}
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index 31b4541..cbd3bf3 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -51,7 +51,7 @@ if env["SCONS_STAGE"] == "build" :
             "Highlighting/Highlighter.cpp",
             "HistoryController.cpp",
             "HistoryViewController.cpp",
-            "MainController.cpp",
+            "AccountController.cpp",
             "PresenceNotifier.cpp",
             "PreviousStatusStore.cpp",
             "ProfileController.cpp",
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index 28c7044..8de5d70 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -35,7 +35,7 @@
 
 #include <Swift/Controllers/ApplicationInfo.h>
 #include <Swift/Controllers/BuildVersion.h>
-#include <Swift/Controllers/MainController.h>
+#include <Swift/Controllers/AccountController.h>
 #include <Swift/Controllers/SettingConstants.h>
 #include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
 #include <Swift/Controllers/Settings/XMLSettingsProvider.h>
@@ -299,7 +299,7 @@ QtSwift::~QtSwift() {
     for (auto* factory : uiFactories_) {
         delete factory;
     }
-    for (auto* controller : mainControllers_) {
+    for (auto* controller : accountControllers_) {
         delete controller;
     }
     delete notifier_;
@@ -403,7 +403,7 @@ QtLoginWindow* QtSwift::addAccount() {
     auto tabs = new QtChatTabs(settingsHierarchy_, true);
     QtUIFactory* uiFactory = new QtUIFactory(settingsHierarchy_, qtSettings_, tabs, splitter_, systemTrays_[systemTrays_.size() - 1], networkFactories_.getTimerFactory(), statusCache_, autoUpdater_, emoticons_, enableAdHocCommandOnJID_);
     uiFactories_.push_back(uiFactory);
-    MainController* mainController = new MainController(
+    AccountController* accountController = new AccountController(
         &clientMainThreadCaller_,
         &networkFactories_,
         uiFactory,
@@ -418,9 +418,9 @@ QtLoginWindow* QtSwift::addAccount() {
         &idleDetector_,
         emoticons_,
         useDelayForLatency_);
-    mainControllers_.push_back(mainController);
+    accountControllers_.push_back(accountController);
 
-    //FIXME - mainController has already created the window, so we can pass null here and get the old one
+    //FIXME - accountController has already created the window, so we can pass null here and get the old one
     auto loginWindow = uiFactory->createLoginWindow(nullptr);
 
     return dynamic_cast<QtLoginWindow*>(loginWindow);
diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h
index d876cd8..811b6e4 100644
--- a/Swift/QtUI/QtSwift.h
+++ b/Swift/QtUI/QtSwift.h
@@ -43,7 +43,7 @@ namespace Swift {
     class CertificateStorageFactory;
     class Dock;
     class EventLoop;
-    class MainController;
+    class AccountController;
     class Notifier;
     class QtChatTabs;
     class QtChatWindowFactory;
@@ -89,7 +89,7 @@ namespace Swift {
             PlatformTLSFactories tlsFactories_;
             BoostNetworkFactories networkFactories_;
             QtChatWindowFactory* chatWindowFactory_;
-            std::vector<MainController*> mainControllers_;
+            std::vector<AccountController*> accountControllers_;
             std::vector<QtSystemTray*> systemTrays_;
             std::vector<QtUIFactory*> uiFactories_;
             QtSettingsProvider* qtSettings_;
-- 
cgit v0.10.2-6-g49f6