From d46ebaac1cf7161fd0a551c34cf80f441f6d19ab Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Wed, 20 Oct 2010 08:58:12 +0100
Subject: Tell MUCController to handle disconnect/reconnect rejoins.

This causes the MUCController to deal with reconnects by requesting
a rejoin. It also prepares for doing time-based context requests.

Although I've traced the code down, and confirmed that
presenceSender->sendPresence(joinPresence);
is being called, the stanza is never sent. This needs further
investigation, as currently it prevents the rejoins working.

Resolves: #625

diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 9046dc3..0247c0e 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -127,8 +127,8 @@ void ChatController::handleStanzaAcked(boost::shared_ptr<Stanza> stanza) {
 	unackedStanzas_.erase(unackedStanzas_.find(stanza));
 }
 
-void ChatController::setEnabled(bool enabled) {
-	if (!enabled) {
+void ChatController::setOnline(bool online) {
+	if (!online) {
 		std::map<boost::shared_ptr<Stanza>, String>::iterator it = unackedStanzas_.begin();
 		for ( ; it != unackedStanzas_.end(); it++) {
 			chatWindow_->setAckState(it->second, ChatWindow::Failed);
@@ -140,7 +140,7 @@ void ChatController::setEnabled(bool enabled) {
 		fakeOffline->setType(Presence::Unavailable);
 		chatStateTracker_->handlePresenceChange(fakeOffline);
 	}
-	ChatControllerBase::setEnabled(enabled);
+	ChatControllerBase::setOnline(online);
 }
 
 String ChatController::senderDisplayNameFromMessage(const JID& from) {
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index 1e530ac..26686ff 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -21,7 +21,7 @@ namespace Swift {
 			ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsManager* entityCapsManager);
 			virtual ~ChatController();
 			virtual void setToJID(const JID& jid);
-			virtual void setEnabled(bool enabled);
+			virtual void setOnline(bool online);
 
 		private:
 			void handlePresenceChange(boost::shared_ptr<Presence> newPresence);
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index de74150..bbc04f6 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -27,7 +27,7 @@ ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaCha
 	chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream);
 	chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
 	chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1));
-	setEnabled(stanzaChannel->isAvailable() && iqRouter->isAvailable());
+	setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable());
 	createDayChangeTimer();
 }
 
@@ -58,6 +58,10 @@ void ChatControllerBase::setEnabled(bool enabled) {
 	chatWindow_->setInputEnabled(enabled);
 }
 
+void ChatControllerBase::setOnline(bool online) {
+	setEnabled(online);
+}
+
 void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info) {
 	if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::SecurityLabels)) {
 		//chatWindow_->setSecurityLabelsEnabled(true);
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index fba173d..efbf7b4 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -44,6 +44,7 @@ namespace Swift {
 			void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
 			void handleIncomingMessage(boost::shared_ptr<MessageEvent> message);
 			String addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time);
+			virtual void setOnline(bool online);
 			virtual void setEnabled(bool enabled);
 			virtual void setToJID(const JID& jid) {toJID_ = jid;};
 		protected:
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index bbc9609..0353cb9 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -153,10 +153,10 @@ void ChatsManager::setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info) {
  */ 
 void ChatsManager::setOnline(bool enabled) {
 	foreach (JIDChatControllerPair controllerPair, chatControllers_) {
-		controllerPair.second->setEnabled(enabled);
+		controllerPair.second->setOnline(enabled);
 	}
 	foreach (JIDMUCControllerPair controllerPair, mucControllers_) {
-		controllerPair.second->setEnabled(enabled);
+		controllerPair.second->setOnline(enabled);
 		if (enabled) {
 			controllerPair.second->rejoin();
 		}
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index c4b4086..9cf235e 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -52,6 +52,7 @@ MUCController::MUCController (
 	parting_ = true;
 	joined_ = false;
 	lastWasPresence_ = false;
+	shouldJoinOnReconnect_ = true;
 	events_ = uiEventStream;
 	
 	roster_ = new Roster(false, true);
@@ -72,8 +73,7 @@ MUCController::MUCController (
 		loginCheckTimer_->start();
 	}
 	chatWindow_->convertToMUC();
-	chatWindow_->addSystemMessage("Trying to join room " + toJID_.toString());
-	rejoin();
+	setOnline(true);
 	if (avatarManager_ != NULL) {
 		avatarChangedConnection_ = (avatarManager_->onAvatarChanged.connect(boost::bind(&MUCController::handleAvatarChanged, this, _1)));
 	} 
@@ -97,7 +97,12 @@ void MUCController::rejoin() {
 	if (parting_) {
 		joined_ = false;
 		parting_ = false;
-		muc_->joinAs(nick_);
+		//FIXME: check for received activity
+		if (/*lastActivityDate_ == none*/true) {
+			muc_->joinAs(nick_);
+		} else {
+			muc_->joinWithContextSince(nick_);
+		}
 	}
 }
 
@@ -145,6 +150,7 @@ void MUCController::handleJoinComplete(const String& nick) {
 	nick_ = nick;
 	chatWindow_->addSystemMessage(joinMessage);
 	clearPresenceQueue();
+	shouldJoinOnReconnect_ = true;
 	setEnabled(true);
 }
 
@@ -158,6 +164,7 @@ void MUCController::handleAvatarChanged(const JID& jid) {
 
 void MUCController::handleWindowClosed() {
 	parting_ = true;
+	shouldJoinOnReconnect_ = false;
 	muc_->part();
 	onUserLeft();
 }
@@ -273,18 +280,32 @@ String MUCController::roleToGroupName(MUCOccupant::Role role) {
 	return result;
 }
 
-void MUCController::setEnabled(bool enabled) {
-	ChatControllerBase::setEnabled(enabled);
-	if (!enabled) {
-		roster_->removeAll();
-		/* handleUserLeft won't throw a part back up unless this is called
-		   when it doesn't yet know we've left - which only happens on
-		   disconnect, so call with disconnect here so if the signal does
-		   bubble back up, it'll be with the right type.*/
-		muc_->handleUserLeft(MUC::Disconnect);
+void MUCController::setOnline(bool online) {
+	ChatControllerBase::setOnline(online);
+	if (!online) {
+		parting_ = true;
+		processUserPart();
+	} else {
+		if (shouldJoinOnReconnect_) {
+			chatWindow_->addSystemMessage("Trying to join room " + toJID_.toString());
+			if (loginCheckTimer_) {
+				loginCheckTimer_->start();
+			}
+			rejoin();
+		}
 	}
 }
 
+void MUCController::processUserPart() {
+	roster_->removeAll();
+	/* handleUserLeft won't throw a part back up unless this is called
+	   when it doesn't yet know we've left - which only happens on
+	   disconnect, so call with disconnect here so if the signal does
+	   bubble back up, it'll be with the right type.*/
+	muc_->handleUserLeft(MUC::Disconnect);
+	setEnabled(false);
+}
+
 bool MUCController::shouldUpdateJoinParts() {
 	return lastWasPresence_;
 }
@@ -310,7 +331,7 @@ void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::Leaving
 	} else {
 		addPresenceMessage(partMessage);
 		parting_ = true;
-		setEnabled(false);
+		processUserPart();
 	}
 }
 
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 3f226ef..6924b48 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -44,7 +44,7 @@ namespace Swift {
 			MUCController(const JID& self, const JID &muc, const String &nick, StanzaChannel* stanzaChannel, PresenceSender* presenceSender, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController);
 			~MUCController();
 			boost::signal<void ()> onUserLeft;
-			virtual void setEnabled(bool enabled);
+			virtual void setOnline(bool online);
 			void rejoin();
 			static void appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent);
 			static String generateJoinPartString(std::vector<NickJoinPart> joinParts);
@@ -76,6 +76,7 @@ namespace Swift {
 			void updateJoinParts();
 			bool shouldUpdateJoinParts();
 			void dayTicked() {lastWasPresence_ = false;}
+			void processUserPart();
 		private:
 			MUC* muc_;
 			UIEventStream* events_;
@@ -85,6 +86,7 @@ namespace Swift {
 			bool parting_;
 			bool joined_;
 			bool lastWasPresence_;
+			bool shouldJoinOnReconnect_;
 			boost::bsignals::scoped_connection avatarChangedConnection_;
 			boost::shared_ptr<Timer> loginCheckTimer_;
 			std::set<String> currentOccupants_;
diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp
index 8f04308..cfd468c 100644
--- a/Swiften/MUC/MUC.cpp
+++ b/Swiften/MUC/MUC.cpp
@@ -28,19 +28,33 @@ MUC::MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, PresenceSender* prese
 
 //FIXME: discover reserved nickname
 
+/**
+ * Join the MUC with default context.
+ */
 void MUC::joinAs(const String &nick) {
+	internalJoin(nick);
+}
+
+void MUC::internalJoin(const String &nick) {
 	//TODO: password
 	//TODO: history request
 	joinComplete_ = false;
-
 	ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick);
-
 	boost::shared_ptr<Presence> joinPresence(presenceSender->getLastSentUndirectedPresence());
+	//FIXME: use date
 	joinPresence->setTo(ownMUCJID);
 	joinPresence->addPayload(boost::shared_ptr<Payload>(new MUCPayload()));
 	presenceSender->sendPresence(joinPresence);
 }
 
+/**
+ * Join the MUC with context since date.
+ */
+void MUC::joinWithContextSince(const String &nick) {
+	//FIXME: add date
+	internalJoin(nick);
+}
+
 void MUC::part() {
 	presenceSender->removeDirectedPresenceReceiver(ownMUCJID);
 }
diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h
index af3daa8..ea20ac4 100644
--- a/Swiften/MUC/MUC.h
+++ b/Swiften/MUC/MUC.h
@@ -32,6 +32,7 @@ namespace Swift {
 			MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, PresenceSender* presenceSender, const JID &muc);
 
 			void joinAs(const String &nick);
+			void joinWithContextSince(const String &nick);
 			/*void queryRoomInfo(); */
 			/*void queryRoomItems(); */
 			String getCurrentNick();
@@ -63,6 +64,7 @@ namespace Swift {
 
 		private:
 			void handleIncomingPresence(boost::shared_ptr<Presence> presence);
+			void internalJoin(const String& nick);
 
 		private:
 			JID ownMUCJID;
-- 
cgit v0.10.2-6-g49f6