From ba333999576d89f3340c271b2a3331d6a3e64ac7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 30 Oct 2010 19:46:24 +0200
Subject: Disconnect client cleanly before quitting.

Resolves: #671, #420

diff --git a/BuildTools/Eclipse/Swift (Windows).launch b/BuildTools/Eclipse/Swift (Windows).launch
index bb27678..900a9e1 100644
--- a/BuildTools/Eclipse/Swift (Windows).launch	
+++ b/BuildTools/Eclipse/Swift (Windows).launch	
@@ -17,7 +17,7 @@
 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/>
 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="Swift/QtUI/Swift.exe"/>
 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="swift"/>
-<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="0.980756260"/>
+<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="0.980756260.1834106966.226646757"/>
 <booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/>
 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
 <listEntry value="/swift"/>
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index eb03e50..92a3f2a 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -100,6 +100,7 @@ MainController::MainController(
 	eventWindowController_ = NULL;
 	discoResponder_ = NULL;
 	mucSearchController_ = NULL;
+	quitRequested_ = false;
 
 	timeBeforeNextReconnect_ = -1;
 	mucSearchWindowFactory_ = mucSearchWindowFactory;
@@ -136,6 +137,7 @@ MainController::MainController(
 	loginWindow_->setLoginAutomatically(loginAutomatically);
 	loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4, _5));
 	loginWindow_->onCancelLoginRequest.connect(boost::bind(&MainController::handleCancelLoginRequest, this));
+	loginWindow_->onQuitRequest.connect(boost::bind(&MainController::handleQuitRequest, this));
 
 	idleDetector_.setIdleTimeSeconds(600);
 	idleDetector_.onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1));
@@ -401,7 +403,11 @@ void MainController::performLoginFromCachedCredentials() {
 }
 
 void MainController::handleDisconnected(const boost::optional<ClientError>& error) {
-	if (error) {
+	if (quitRequested_) {
+		resetClient();
+		loginWindow_->quit();
+	}
+	else if (error) {
 		String message;
 		switch(error->getType()) {
 			case ClientError::UnknownError: message = "Unknown Error"; break;
@@ -506,5 +512,15 @@ void MainController::handleNotificationClicked(const JID& jid) {
 	uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(jid)));
 }
 
+void MainController::handleQuitRequest() {
+	if (client_ && client_->isActive()) {
+		quitRequested_ = true;
+		client_->disconnect();
+	}
+	else {
+		resetClient();
+		loginWindow_->quit();
+	}
+}
 
 }
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index da65567..c36c136 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -89,6 +89,7 @@ namespace Swift {
 			void handleConnected();
 			void handleLoginRequest(const String& username, const String& password, const String& certificateFile, bool remember, bool loginAutomatically);
 			void handleCancelLoginRequest();
+			void handleQuitRequest();
 			void handleChangeStatusRequest(StatusShow::Type show, const String &statusText);
 			void handleDisconnected(const boost::optional<ClientError>& error);
 			void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, const boost::optional<ErrorPayload>&);
@@ -152,5 +153,6 @@ namespace Swift {
 			Timer::ref reconnectTimer_;
 			StatusTracker* statusTracker_;
 			bool myStatusLooksOnline_;
+			bool quitRequested_;
 	};
 }
diff --git a/Swift/Controllers/UIInterfaces/LoginWindow.h b/Swift/Controllers/UIInterfaces/LoginWindow.h
index c752d0a..54d8099 100644
--- a/Swift/Controllers/UIInterfaces/LoginWindow.h
+++ b/Swift/Controllers/UIInterfaces/LoginWindow.h
@@ -25,7 +25,10 @@ namespace Swift {
 			virtual void addAvailableAccount(const String& defaultJID, const String& defaultPassword, const String& defaultCertificate) = 0;
 			boost::signal<void (const String&, const String&, const String& /* certificateFile */, bool /* remember password*/, bool /* login automatically */)> onLoginRequest;
 			virtual void setLoginAutomatically(bool loginAutomatically) = 0;
+			virtual void quit() = 0;
+
 			boost::signal<void ()> onCancelLoginRequest;
+			boost::signal<void ()> onQuitRequest;
 	};
 }
 #endif
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index 4206a4b..bcadc3a 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.cpp
@@ -321,6 +321,10 @@ void QtLoginWindow::handleToggleNotifications(bool enabled) {
 }
 
 void QtLoginWindow::handleQuit() {
+	onQuitRequest();
+}
+
+void QtLoginWindow::quit() {
 	QApplication::quit();
 }
 
diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h
index 1a4343e..242b5b4 100644
--- a/Swift/QtUI/QtLoginWindow.h
+++ b/Swift/QtUI/QtLoginWindow.h
@@ -39,6 +39,8 @@ namespace Swift {
 			static QRect defaultPosition();
 			void setGentleGeometry(const QRect&);
 			void selectUser(const String& user);
+			virtual void quit();
+
 		signals:
 			void geometryChanged();
 
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp
index 9511dfb..d9b21bc 100644
--- a/Swiften/Client/CoreClient.cpp
+++ b/Swiften/Client/CoreClient.cpp
@@ -62,6 +62,7 @@ void CoreClient::connect(const JID& jid) {
 }
 
 void CoreClient::connect(const String& host) {
+	disconnectRequested_ = false;
 	assert(!connector_);
 	connector_ = Connector::create(host, &resolver_, connectionFactory_, timerFactory_);
 	connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1));
@@ -105,12 +106,7 @@ void CoreClient::disconnect() {
 	}
 	else if (connector_) {
 		connector_->stop();
-		assert(!session_);
 	}
-	assert(!session_);
-	assert(!sessionStream_);
-	assert(!connector_);
-	disconnectRequested_ = false;
 }
 
 void CoreClient::setCertificate(const String& certificate) {
@@ -214,4 +210,8 @@ void CoreClient::sendPresence(boost::shared_ptr<Presence> presence) {
 	stanzaChannel_->sendPresence(presence);
 }
 
+bool CoreClient::isActive() const {
+	return session_ || connector_;
+}
+
 }
diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h
index e9e81ec..2b7113f 100644
--- a/Swiften/Client/CoreClient.h
+++ b/Swiften/Client/CoreClient.h
@@ -96,6 +96,13 @@ namespace Swift {
 			}
 
 			/**
+			 * Checks whether the client is active.
+			 *
+			 * A client is active when it is connected or connecting to the server.
+			 */
+			bool isActive() const;
+
+			/**
 			 * Returns the JID of the client. 
 			 * After the session was initialized, this returns the bound JID.
 			 */
-- 
cgit v0.10.2-6-g49f6