From 53f132042a6d470f94a9721a31c86514aba11c4f Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Fri, 25 Jun 2010 22:20:28 +0100
Subject: Simplify presence handling for auto-away and reconnections.

Resolves: #405

diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index ec339b0..9e4eb00 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -32,6 +32,7 @@
 #include "Swift/Controllers/RosterController.h"
 #include "Swift/Controllers/SoundEventController.h"
 #include "Swift/Controllers/SoundPlayer.h"
+#include "Swift/Controllers/StatusTracker.h"
 #include "Swift/Controllers/SystemTray.h"
 #include "Swift/Controllers/SystemTrayController.h"
 #include "Swift/Controllers/XMLConsoleController.h"
@@ -94,6 +95,7 @@ MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowF
 	systemTrayController_ = new SystemTrayController(eventController_, systemTray);
 	loginWindow_ = loginWindowFactory_->createLoginWindow(uiEventStream_);
 	soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings, uiEventStream_);
+	statusTracker_  = new StatusTracker();
 
 	String selectedLoginJID = settings_->getStringSetting("lastLoginJID");
 	bool loginAutomatically = settings_->getBoolSetting("loginAutomatically", false);
@@ -164,6 +166,8 @@ void MainController::resetClient() {
 	client_ = NULL;
 	delete mucSearchController_;
 	mucSearchController_ = NULL;
+	delete statusTracker_;
+	statusTracker_ = NULL;
 }
 
 void MainController::resetPendingReconnects() {
@@ -172,7 +176,6 @@ void MainController::resetPendingReconnects() {
 		reconnectTimer_->stop();
 		reconnectTimer_.reset();
 	}
-
 }
 
 void MainController::resetCurrentError() {
@@ -193,7 +196,6 @@ void MainController::handleConnected() {
 		xmppRoster_ = boost::shared_ptr<XMPPRoster>(new XMPPRoster());
 		presenceOracle_ = new PresenceOracle(client_);
 		nickResolver_ = new NickResolver(xmppRoster_);		
-		lastSentPresence_ = boost::shared_ptr<Presence>();
 
 		avatarManager_ = new AvatarManager(client_, client_, avatarStorage_);
 
@@ -237,15 +239,10 @@ void MainController::handleConnected() {
 	vCardRequest->onResponse.connect(boost::bind(&MainController::handleOwnVCardReceived, this, _1, _2));
 	vCardRequest->send();
 
-	//Send presence last to catch all the incoming presences.
-	boost::shared_ptr<Presence> initialPresence;
-	if (queuedPresence_.get() != NULL) {
-		initialPresence = queuedPresence_;
-	} else {
-		initialPresence = boost::shared_ptr<Presence>(new Presence());
-	}
+	
 	setManagersEnabled(true);
-	sendPresence(initialPresence);
+	//Send presence last to catch all the incoming presences.
+	sendPresence(statusTracker_->getNextPresence());
 }
 
 void MainController::handleEventQueueLengthChange(int count) {
@@ -257,7 +254,6 @@ void MainController::reconnectAfterError() {
 		reconnectTimer_->stop();
 	}
 	performLoginFromCachedCredentials();
-	//sendPresence(queuedPresence_);
 }
 
 void MainController::handleChangeStatusRequest(StatusShow::Type show, const String &statusText) {
@@ -270,11 +266,10 @@ void MainController::handleChangeStatusRequest(StatusShow::Type show, const Stri
 		presence->setShow(show);
 	}
 	presence->setStatus(statusText);
+	statusTracker_->setRequestedPresence(presence);
 	if (presence->getType() != Presence::Unavailable && !client_->isAvailable()) {
 		performLoginFromCachedCredentials();
-		queuedPresence_ = presence;
-	} 
-	else {
+	} else {
 		sendPresence(presence);
 	}
 }
@@ -283,9 +278,6 @@ void MainController::sendPresence(boost::shared_ptr<Presence> presence) {
 	rosterController_->getWindow()->setMyStatusType(presence->getShow());
 	rosterController_->getWindow()->setMyStatusText(presence->getStatus());
 
-	// Copy presence before adding extra information
-	lastSentPresence_ = presence->clone();
-
 	// Add information and send
 	if (!vCardPhotoHash_.isEmpty()) {
 		presence->addPayload(boost::shared_ptr<VCardUpdate>(new VCardUpdate(vCardPhotoHash_)));
@@ -299,28 +291,16 @@ void MainController::sendPresence(boost::shared_ptr<Presence> presence) {
 
 void MainController::handleInputIdleChanged(bool idle) {
 	if (idle) {
-		if (lastSentPresence_->getShow() != StatusShow::Online) {
-			return;
+		if (statusTracker_->goAutoAway()) {
+			if (client_ && client_->isAvailable()) {
+				sendPresence(statusTracker_->getNextPresence());
+			}
 		}
-		preIdlePresence_ = lastSentPresence_;
-		boost::shared_ptr<Presence> presence(new Presence());
-		presence->setShow(StatusShow::Away);
-		presence->setStatus(lastSentPresence_->getStatus());
-		if (client_ && client_->isAvailable()) {
-			sendPresence(presence);
-		} else {
-			queuedPresence_ = presence;
-		}
-	}
-	else {
-		if (!preIdlePresence_) {
-			/* We didn't go autoaway (the user was already away when the timer ticked */
-			return;
-		}
-		if (client_ && client_->isAvailable()) {
-			sendPresence(preIdlePresence_);
-		} else {
-			queuedPresence_ = preIdlePresence_;
+	} else {
+		if (statusTracker_->goAutoUnAway()) {
+			if (client_ && client_->isAvailable()) {
+				sendPresence(statusTracker_->getNextPresence());
+			}
 		}
 	}
 }
@@ -463,8 +443,8 @@ void MainController::handleOwnVCardReceived(boost::shared_ptr<VCard> vCard, cons
 	}
 	if (!error && !vCard->getPhoto().isEmpty()) {
 		vCardPhotoHash_ = Hexify::hexify(SHA1::getHash(vCard->getPhoto()));
-		if (lastSentPresence_) {
-			sendPresence(lastSentPresence_);
+		if (client_ && client_->isAvailable()) {
+			sendPresence(statusTracker_->getNextPresence());
 		}
 		avatarManager_->setAvatar(jid_, vCard->getPhoto());
 	}
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 2f489a8..f17bc9b 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -60,6 +60,7 @@ namespace Swift {
 	class EventWindowController;
 	class MUCSearchController;
 	class MUCSearchWindowFactory;
+	class StatusTracker;
 
 	class MainController {
 		public:
@@ -122,10 +123,7 @@ namespace Swift {
 			SystemTrayController* systemTrayController_;
 			SoundEventController* soundEventController_;
 			AvatarManager* avatarManager_;
-			boost::shared_ptr<Presence> lastSentPresence_;
-			boost::shared_ptr<Presence> preIdlePresence_;
 			String vCardPhotoHash_;
-			boost::shared_ptr<Presence> queuedPresence_;
 			String password_;
 			String certificateFile_;
 			ChatListWindowFactory* chatListWindowFactory_;
@@ -135,5 +133,6 @@ namespace Swift {
 			MUCSearchWindowFactory* mucSearchWindowFactory_;
 			int timeBeforeNextReconnect_;
 			Timer::ref reconnectTimer_;
+			StatusTracker* statusTracker_;
 	};
 }
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index ad03a5a..ea0dc3a 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -35,6 +35,7 @@ if env["SCONS_STAGE"] == "build" :
 			"SoundEventController.cpp",
 			"SystemTrayController.cpp",
 			"XMLConsoleController.cpp",
+			"StatusTracker.cpp",
 			"UIEvents/UIEvent.cpp",
 			"UIInterfaces/XMLConsoleWidget.cpp",
 			"UIInterfaces/ChatListWindow.cpp",
diff --git a/Swift/Controllers/StatusTracker.cpp b/Swift/Controllers/StatusTracker.cpp
new file mode 100644
index 0000000..8f67b9f
--- /dev/null
+++ b/Swift/Controllers/StatusTracker.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swift/Controllers/StatusTracker.h"
+
+namespace Swift {
+
+StatusTracker::StatusTracker() {
+	isAutoAway_ = false;
+	queuedPresence_ = boost::shared_ptr<Presence>(new Presence());
+}
+
+boost::shared_ptr<Presence> StatusTracker::getNextPresence() {
+	boost::shared_ptr<Presence> presence;
+	if (isAutoAway_) {
+		presence = boost::shared_ptr<Presence>(new Presence());
+		presence->setShow(StatusShow::Away);
+		presence->setStatus(queuedPresence_->getStatus());
+	} else {
+		presence = queuedPresence_;
+	}
+	return presence;
+}
+
+void StatusTracker::setRequestedPresence(boost::shared_ptr<Presence> presence) {
+	isAutoAway_ = false;
+	queuedPresence_ = presence;
+//	if (presence->getType() == Presence::Unavailable) {
+//		queuedPresence_ = boost::shared_ptr<Presence>(new Presence());
+//	}
+}
+
+bool StatusTracker::goAutoAway() {
+	if (queuedPresence_->getShow() != StatusShow::Online) {
+		return false;
+	}
+	isAutoAway_ = true;
+	return true;
+}
+
+bool StatusTracker::goAutoUnAway() {
+	if (!isAutoAway_) {
+		return false;
+	}
+	isAutoAway_ = false;
+	return true;
+}
+
+}
diff --git a/Swift/Controllers/StatusTracker.h b/Swift/Controllers/StatusTracker.h
new file mode 100644
index 0000000..4f4e880
--- /dev/null
+++ b/Swift/Controllers/StatusTracker.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Elements/Presence.h"
+
+namespace Swift {
+
+	class StatusTracker {
+		public:
+			StatusTracker();
+			boost::shared_ptr<Presence> getNextPresence();
+			void setRequestedPresence(boost::shared_ptr<Presence> presence);
+			bool goAutoAway();
+			bool goAutoUnAway();
+		private:
+			boost::shared_ptr<Presence> queuedPresence_;
+			bool isAutoAway_;
+	};
+}
-- 
cgit v0.10.2-6-g49f6