From db7f15df68cda2850c3d8a7ffcc59fc136de6f95 Mon Sep 17 00:00:00 2001
From: "Mark Palange (Mani)" <palange@lindenlab.com>
Date: Wed, 22 Jul 2009 14:53:55 -0700
Subject: [PATCH] Adding LLLoginInstance unit test

---
 indra/llui/llnotificationslistener.cpp |  29 +++-
 indra/llui/llnotificationslistener.h   |   5 +-
 indra/newview/CMakeLists.txt           |   1 +
 indra/newview/llappviewer.cpp          | 110 ++++++++++++++-
 indra/newview/llappviewer.h            |   4 +-
 indra/newview/llfloatertos.cpp         |   2 +
 indra/newview/lllogininstance.cpp      | 183 +++++++------------------
 indra/newview/lllogininstance.h        |  33 +++--
 indra/newview/llpanellogin.cpp         |   3 +-
 indra/newview/llstartup.cpp            |  10 +-
 indra/newview/llviewermenu.cpp         |   2 +-
 11 files changed, 230 insertions(+), 152 deletions(-)

diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index d6e552ca5c3..6ebbee68acc 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -24,5 +24,32 @@ LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications
 
 void LLNotificationsListener::requestAdd(const LLSD& event_data) const
 {
-    mNotifications.add(event_data["name"], event_data["substitutions"], event_data["payload"]);
+	if(event_data.has("reply"))
+	{
+		mNotifications.add(event_data["name"], 
+						   event_data["substitutions"], 
+						   event_data["payload"],
+						   boost::bind(&LLNotificationListener::Responder, 
+									   this, 
+									   event_data["reply"].asString(), 
+									   _1, _2
+									   )
+						   );
+	}
+	else
+	{
+		mNotifications.add(event_data["name"], 
+						   event_data["substitutions"], 
+						   event_data["payload"]);
+	}
+}
+
+void LLNotificationsListener::Responder(const std::string& reply_pump, 
+										const LLSD& notification, 
+										const LLSD& response)
+{
+	LLSD reponse_event;
+	reponse_event["notification"] = notification;
+	reponse_event["response"] = response;
+	mEventPumps.obtain(reply_pump).post(reponse_event);
 }
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
index 3576cacbdbd..d11aed1b52c 100644
--- a/indra/llui/llnotificationslistener.h
+++ b/indra/llui/llnotificationslistener.h
@@ -25,7 +25,10 @@ class LLNotificationsListener : public LLDispatchListener
     void requestAdd(LLSD const & event_data) const;
 
 private:
-    LLNotifications & mNotifications;
+	void NotificationResponder(const std::string& replypump, 
+							   const LLSD& notification, 
+							   const LLSD& response);
+	LLNotifications & mNotifications;
 };
 
 #endif // LL_LLNOTIFICATIONSLISTENER_H
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 0836a4b016f..a908b058f07 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1480,6 +1480,7 @@ endif (INSTALL)
 include(LLAddBuildTest)
 SET(viewer_TEST_SOURCE_FILES
   llagentaccess.cpp
+  lllogininstance.cpp
   # Not *actually* a unit test, it's an integration test.
   # Because it won't work in the new unit test iface, i've commented out
   # and notified Nat. Delete this when it's replaced!
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 8492644b2d4..17984b8eae5 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3986,7 +3986,7 @@ void LLAppViewer::forceErrorBadMemoryAccess()
     return;
 }
 
-void LLAppViewer::forceErrorInifiniteLoop()
+void LLAppViewer::forceErrorInfiniteLoop()
 {
     while(true)
     {
@@ -4152,3 +4152,111 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)
 
 	mPlugins.insert(eventhost_dso_handle);
 }
+
+void LLAppViewer::launchUpdater()
+{
+		LLSD query_map = LLSD::emptyMap();
+	// *TODO place os string in a global constant
+#if LL_WINDOWS  
+	query_map["os"] = "win";
+#elif LL_DARWIN
+	query_map["os"] = "mac";
+#elif LL_LINUX
+	query_map["os"] = "lnx";
+#elif LL_SOLARIS
+	query_map["os"] = "sol";
+#endif
+	// *TODO change userserver to be grid on both viewer and sim, since
+	// userserver no longer exists.
+	query_map["userserver"] = LLViewerLogin::getInstance()->getGridLabel();
+	query_map["channel"] = gSavedSettings.getString("VersionChannelName");
+	// *TODO constantize this guy
+	// *NOTE: This URL is also used in win_setup/lldownloader.cpp
+	LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
+	
+	if(LLAppViewer::sUpdaterInfo)
+	{
+		delete LLAppViewer::sUpdaterInfo;
+	}
+	LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;
+	
+#if LL_WINDOWS
+	LLAppViewer::sUpdaterInfo->mUpdateExePath = gDirUtilp->getTempFilename();
+	if (LLAppViewer::sUpdaterInfo->mUpdateExePath.empty())
+	{
+		delete LLAppViewer::sUpdaterInfo ;
+		LLAppViewer::sUpdaterInfo = NULL ;
+
+		// We're hosed, bail
+		LL_WARNS("AppInit") << "LLDir::getTempFilename() failed" << LL_ENDL;
+		return;
+	}
+
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += ".exe";
+
+	std::string updater_source = gDirUtilp->getAppRODataDir();
+	updater_source += gDirUtilp->getDirDelimiter();
+	updater_source += "updater.exe";
+
+	LL_DEBUGS("AppInit") << "Calling CopyFile source: " << updater_source
+			<< " dest: " << LLAppViewer::sUpdaterInfo->mUpdateExePath
+			<< LL_ENDL;
+
+
+	if (!CopyFileA(updater_source.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), FALSE))
+	{
+		delete LLAppViewer::sUpdaterInfo ;
+		LLAppViewer::sUpdaterInfo = NULL ;
+
+		LL_WARNS("AppInit") << "Unable to copy the updater!" << LL_ENDL;
+
+		return;
+	}
+
+	// if a sim name was passed in via command line parameter (typically through a SLURL)
+	if ( LLURLSimString::sInstance.mSimString.length() )
+	{
+		// record the location to start at next time
+		gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); 
+	};
+
+	LLAppViewer::sUpdaterInfo->mParams << "-url \"" << update_url.asString() << "\"";
+
+	LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << " " << LLAppViewer::sUpdaterInfo->mParams.str() << LL_ENDL;
+
+	//Explicitly remove the marker file, otherwise we pass the lock onto the child process and things get weird.
+	LLAppViewer::instance()->removeMarkerFile(); // In case updater fails
+
+	// *NOTE:Mani The updater is spawned as the last thing before the WinMain exit.
+	// see LLAppViewerWin32.cpp
+	
+#elif LL_DARWIN
+	// if a sim name was passed in via command line parameter (typically through a SLURL)
+	if ( LLURLSimString::sInstance.mSimString.length() )
+	{
+		// record the location to start at next time
+		gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); 
+	};
+	
+	LLAppViewer::sUpdaterInfo->mUpdateExePath = "'";
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += gDirUtilp->getAppRODataDir();
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += "/mac-updater.app/Contents/MacOS/mac-updater' -url \"";
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString();
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \"";
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &";
+
+	LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
+
+	// Run the auto-updater.
+	system(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str()); /* Flawfinder: ignore */
+
+#elif LL_LINUX || LL_SOLARIS
+	OSMessageBox("Automatic updating is not yet implemented for Linux.\n"
+		"Please download the latest version from www.secondlife.com.",
+		LLStringUtil::null, OSMB_OK);
+#endif
+
+	// *REMOVE:Mani - Saving for reference...
+	// LLAppViewer::instance()->forceQuit();
+}
\ No newline at end of file
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 69f2a074aac..08bd94563d6 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -126,7 +126,7 @@ class LLAppViewer : public LLApp
     virtual void forceErrorLLError();
     virtual void forceErrorBreakpoint();
     virtual void forceErrorBadMemoryAccess();
-    virtual void forceErrorInifiniteLoop();
+    virtual void forceErrorInfiniteLoop();
     virtual void forceErrorSoftwareException();
     virtual void forceErrorDriverCrash();
 
@@ -262,6 +262,8 @@ class LLAppViewer : public LLApp
 		std::ostringstream mParams;
 	}LLUpdaterInfo ;
 	static LLUpdaterInfo *sUpdaterInfo ;
+
+	void launchUpdater();
 };
 
 // consts from viewer.h
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index c79e96a5e5a..d75640ccb48 100644
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -74,6 +74,8 @@ LLFloaterTOS* LLFloaterTOS::show(ETOSType type,
 		LLUICtrlFactory::getInstance()->buildFloater(LLFloaterTOS::sInstance, "floater_critical.xml");
 	}
 
+	sInstance->startModal();
+
 	return LLFloaterTOS::sInstance;
 }
 
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 22497ed2911..bf42129fc1b 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -47,7 +47,6 @@
 
 // newview
 #include "llviewernetwork.h"
-#include "llappviewer.h" // Wish I didn't have to, but...
 #include "llviewercontrol.h"
 #include "llurlsimstring.h"
 #include "llfloatertos.h"
@@ -74,7 +73,6 @@ LLLoginInstance::~LLLoginInstance()
 {
 }
 
-
 void LLLoginInstance::connect(const LLSD& credentials)
 {
 	std::vector<std::string> uris;
@@ -84,6 +82,7 @@ void LLLoginInstance::connect(const LLSD& credentials)
 
 void LLLoginInstance::connect(const std::string& uri, const LLSD& credentials)
 {
+	mAttemptComplete = false; // Reset attempt complete at this point!
 	constructAuthParams(credentials);
 	mLoginModule->connect(uri, mRequestData);
 }
@@ -99,6 +98,7 @@ void LLLoginInstance::reconnect()
 
 void LLLoginInstance::disconnect()
 {
+	mAttemptComplete = false; // Reset attempt complete at this point!
 	mRequestData.clear();
 	mLoginModule->disconnect();
 }
@@ -162,12 +162,13 @@ void LLLoginInstance::constructAuthParams(const LLSD& credentials)
 	request_params["skipoptional"] = mSkipOptionalUpdate;
 	request_params["agree_to_tos"] = false; // Always false here. Set true in 
 	request_params["read_critical"] = false; // handleTOSResponse
-	request_params["last_exec_event"] = gLastExecEvent;
+	request_params["last_exec_event"] = mLastExecEvent;
 	request_params["mac"] = hashed_mac_string;
 	request_params["version"] = gCurrentVersion; // Includes channel name
 	request_params["channel"] = gSavedSettings.getString("VersionChannelName");
-	request_params["id0"] = LLAppViewer::instance()->getSerialNumber();
+	request_params["id0"] = mSerialNumber;
 
+	mRequestData.clear();
 	mRequestData["method"] = "login_to_simulator";
 	mRequestData["params"] = request_params;
 	mRequestData["options"] = requested_options;
@@ -219,21 +220,18 @@ bool LLLoginInstance::handleLoginFailure(const LLSD& event)
 		// to reconnect or to end the attempt in failure.
 		if(reason_response == "tos")
 		{
-			LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,
-											message_response,
-											boost::bind(&LLLoginInstance::handleTOSResponse, 
-														this, _1, "agree_to_tos")
-											);
-			tos_dialog->startModal();
+			LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,
+								message_response,
+								boost::bind(&LLLoginInstance::handleTOSResponse, 
+											this, _1, "agree_to_tos"));
 		}
 		else if(reason_response == "critical")
 		{
-			LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_CRITICAL_MESSAGE,
-											message_response,
-											boost::bind(&LLLoginInstance::handleTOSResponse, 
-														this, _1, "read_critical")
+			LLFloaterTOS::show(LLFloaterTOS::TOS_CRITICAL_MESSAGE,
+								message_response,
+								boost::bind(&LLLoginInstance::handleTOSResponse, 
+												this, _1, "read_critical")
 											);
-			tos_dialog->startModal();
 		}
 		else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate"))
 		{
@@ -259,12 +257,14 @@ bool LLLoginInstance::handleLoginFailure(const LLSD& event)
 
 bool LLLoginInstance::handleLoginSuccess(const LLSD& event)
 {
-	LLSD response = event["data"];
-	std::string message_response = response["message"].asString();
 	if(gSavedSettings.getBOOL("ForceMandatoryUpdate"))
 	{
+		LLSD response = event["data"];
+		std::string message_response = response["message"].asString();
+
 		// Testing update...
 		gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
+
 		// Don't confuse startup by leaving login "online".
 		mLoginModule->disconnect(); 
 		updateApp(true, message_response);
@@ -281,7 +281,7 @@ void LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
 	if(accepted)
 	{	
 		// Set the request data to true and retry login.
-		mRequestData[key] = true; 
+		mRequestData["params"][key] = true; 
 		reconnect();
 	}
 	else
@@ -344,13 +344,36 @@ void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg)
 		notification_name += "ReleaseForDownload";
 #endif
 	}
-	
-	LLNotifications::instance().add(notification_name, args, payload, 
-		boost::bind(&LLLoginInstance::updateDialogCallback, this, _1, _2));
+
+	// *NOTE:Mani - for reference
+//	LLNotifications::instance().add(notification_name, args, payload, 
+//		boost::bind(&LLLoginInstance::updateDialogCallback, this, _1, _2));
+
+	if(!mUpdateAppResponse)
+	{
+		bool make_unique = true;
+		mUpdateAppResponse.reset(new LLEventStream("logininstance_updateapp", make_unique));
+		mUpdateAppResponse->listen("diaupdateDialogCallback", 
+								   boost::bind(&LLLoginInstance::updateDialogCallback,
+								 			   this, _1
+											   )
+								   );
+	}
+
+	LLSD event;
+	event["op"] = "requestAdd";
+	event["name"] = notification_name;
+	event["substitutions"] = args;
+	event["payload"] = payload;
+	event["reply"] = mUpdateAppResponse->getName();
+
+	LLEventPumps::getInstance()->obtain("LLNotifications").post(event);
 }
 
-bool LLLoginInstance::updateDialogCallback(const LLSD& notification, const LLSD& response)
+bool LLLoginInstance::updateDialogCallback(const LLSD& event)
 {
+	LLSD notification = event["notification"];
+	LLSD response = event["response"];
 	S32 option = LLNotification::getSelectedOption(notification, response);
 	std::string update_exe_path;
 	bool mandatory = notification["payload"]["mandatory"].asBoolean();
@@ -395,114 +418,12 @@ bool LLLoginInstance::updateDialogCallback(const LLSD& notification, const LLSD&
 		return false;
 	}
 	
-	LLSD query_map = LLSD::emptyMap();
-	// *TODO place os string in a global constant
-#if LL_WINDOWS  
-	query_map["os"] = "win";
-#elif LL_DARWIN
-	query_map["os"] = "mac";
-#elif LL_LINUX
-	query_map["os"] = "lnx";
-#elif LL_SOLARIS
-	query_map["os"] = "sol";
-#endif
-	// *TODO change userserver to be grid on both viewer and sim, since
-	// userserver no longer exists.
-	query_map["userserver"] = LLViewerLogin::getInstance()->getGridLabel();
-	query_map["channel"] = gSavedSettings.getString("VersionChannelName");
-	// *TODO constantize this guy
-	// *NOTE: This URL is also used in win_setup/lldownloader.cpp
-	LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
-	
-	if(LLAppViewer::sUpdaterInfo)
-	{
-		delete LLAppViewer::sUpdaterInfo;
-	}
-	LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;
-	
-#if LL_WINDOWS
-	LLAppViewer::sUpdaterInfo->mUpdateExePath = gDirUtilp->getTempFilename();
-	if (LLAppViewer::sUpdaterInfo->mUpdateExePath.empty())
-	{
-		delete LLAppViewer::sUpdaterInfo ;
-		LLAppViewer::sUpdaterInfo = NULL ;
-
-		// We're hosed, bail
-		LL_WARNS("AppInit") << "LLDir::getTempFilename() failed" << LL_ENDL;
-
-		attemptComplete();
-		// *REMOVE:Mani - Saving for reference...
-		// LLAppViewer::instance()->forceQuit();
-		return false;
-	}
-
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += ".exe";
-
-	std::string updater_source = gDirUtilp->getAppRODataDir();
-	updater_source += gDirUtilp->getDirDelimiter();
-	updater_source += "updater.exe";
-
-	LL_DEBUGS("AppInit") << "Calling CopyFile source: " << updater_source
-			<< " dest: " << LLAppViewer::sUpdaterInfo->mUpdateExePath
-			<< LL_ENDL;
-
-
-	if (!CopyFileA(updater_source.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), FALSE))
-	{
-		delete LLAppViewer::sUpdaterInfo ;
-		LLAppViewer::sUpdaterInfo = NULL ;
-
-		LL_WARNS("AppInit") << "Unable to copy the updater!" << LL_ENDL;
-		attemptComplete();
-		// *REMOVE:Mani - Saving for reference...
-		// LLAppViewer::instance()->forceQuit();
-		return false;
-	}
-
-	// if a sim name was passed in via command line parameter (typically through a SLURL)
-	if ( LLURLSimString::sInstance.mSimString.length() )
-	{
-		// record the location to start at next time
-		gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); 
-	};
-
-	LLAppViewer::sUpdaterInfo->mParams << "-url \"" << update_url.asString() << "\"";
-
-	LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << " " << LLAppViewer::sUpdaterInfo->mParams.str() << LL_ENDL;
-
-	//Explicitly remove the marker file, otherwise we pass the lock onto the child process and things get weird.
-	LLAppViewer::instance()->removeMarkerFile(); // In case updater fails
-
-	// *NOTE:Mani The updater is spawned as the last thing before the WinMain exit.
-	// see LLAppViewerWin32.cpp
-	
-#elif LL_DARWIN
-	// if a sim name was passed in via command line parameter (typically through a SLURL)
-	if ( LLURLSimString::sInstance.mSimString.length() )
-	{
-		// record the location to start at next time
-		gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); 
-	};
-	
-	LLAppViewer::sUpdaterInfo->mUpdateExePath = "'";
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += gDirUtilp->getAppRODataDir();
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += "/mac-updater.app/Contents/MacOS/mac-updater' -url \"";
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString();
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \"";
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &";
-
-	LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
-
-	// Run the auto-updater.
-	system(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str()); /* Flawfinder: ignore */
-
-#elif LL_LINUX || LL_SOLARIS
-	OSMessageBox(LLTrans::getString("MBNoAutoUpdate"), LLStringUtil::null, OSMB_OK);
-#endif
-
-	// *REMOVE:Mani - Saving for reference...
-	// LLAppViewer::instance()->forceQuit();
+ 	if(mUpdaterLauncher)
+  	{
+ 		mUpdaterLauncher();
+  	}
+  
+ 	attemptComplete();
 
 	return false;
 }
@@ -526,4 +447,4 @@ std::string construct_start_string()
 		start = gSavedSettings.getString("LoginLocation");
 	}
 	return start;
-}
+}
\ No newline at end of file
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index da70fec40e5..afe96acd1e7 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -34,7 +34,9 @@
 #define LL_LLLOGININSTANCE_H
 
 #include <boost/scoped_ptr.hpp>
+#include <boost/function.hpp>
 class LLLogin;
+class LLEventStream;
 
 // This class hosts the login module and is used to 
 // negotiate user authentication attempts.
@@ -49,16 +51,6 @@ class LLLoginInstance : public LLSingleton<LLLoginInstance>
 	void reconnect(); // reconnect using the current credentials.
 	void disconnect();
 
-	// Set whether this class will drive user interaction.
-	// If not, login failures like 'need tos agreement' will 
-	// end the login attempt.
-	void setUserInteraction(bool state) { mUserInteraction = state; } 
-	bool getUserInteraction() { return mUserInteraction; }
-
-	// Whether to tell login to skip optional update request.
-	// False by default.
-	void setSkipOptionalUpdate(bool state) { mSkipOptionalUpdate = state; }
-	
 	bool authFailure() { return mAttemptComplete && mLoginState == "offline"; }
 	bool authSuccess() { return mAttemptComplete && mLoginState == "online"; }
 
@@ -69,10 +61,25 @@ class LLLoginInstance : public LLSingleton<LLLoginInstance>
 	// Only valid when authSuccess == true.
 	const F64 getLastTransferRateBPS() { return mTransferRate; }
 
+		// Set whether this class will drive user interaction.
+	// If not, login failures like 'need tos agreement' will 
+	// end the login attempt.
+	void setUserInteraction(bool state) { mUserInteraction = state; } 
+	bool getUserInteraction() { return mUserInteraction; }
+
+	// Whether to tell login to skip optional update request.
+	// False by default.
+	void setSkipOptionalUpdate(bool state) { mSkipOptionalUpdate = state; }
+	void setSerialNumber(const std::string& sn) { mSerialNumber = sn; }
+	void setLastExecEvent(int lee) { mLastExecEvent = lee; }
+
+	typedef boost::function<void()> UpdaterLauncherCallback;
+	void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; }
+
 private:
 	void constructAuthParams(const LLSD& credentials); 
 	void updateApp(bool mandatory, const std::string& message);
-	bool updateDialogCallback(const LLSD& notification, const LLSD& response);
+	bool updateDialogCallback(const LLSD& event);
 
 	bool handleLoginEvent(const LLSD& event);
 	bool handleLoginFailure(const LLSD& event);
@@ -90,6 +97,10 @@ class LLLoginInstance : public LLSingleton<LLLoginInstance>
 	bool mSkipOptionalUpdate;
 	bool mAttemptComplete;
 	F64 mTransferRate;
+	std::string mSerialNumber;
+	int mLastExecEvent;
+	UpdaterLauncherCallback mUpdaterLauncher;
+	boost::scoped_ptr<LLEventStream> mUpdateAppResponse;
 };
 
 #endif
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 9afb8468eff..7af1cbf51fd 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -432,8 +432,7 @@ BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask)
 	if ( KEY_F2 == key )
 	{
 		llinfos << "Spawning floater TOS window" << llendl;
-		LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,"", 0);
-		tos_dialog->startModal();
+		LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,"", NULL);
 		return TRUE;
 	}
 #endif
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index f0f056652a3..dac6f8423a7 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -965,13 +965,17 @@ bool idle_startup()
 		display_startup();
 
 		// Setting initial values...
+		LLLoginInstance* login = LLLoginInstance::getInstance();
 		if(gNoRender)
 		{
 			// HACK, skip optional updates if you're running drones
-			LLLoginInstance::getInstance()->setSkipOptionalUpdate(true);
+			login->setSkipOptionalUpdate(true);
 		}
 
-		LLLoginInstance::getInstance()->setUserInteraction(show_connect_box);
+		login->setUserInteraction(show_connect_box);
+		login->setSerialNumber(LLAppViewer::instance()->getSerialNumber());
+		login->setLastExecEvent(gLastExecEvent);
+		login->setUpdaterLauncher(boost::bind(LLAppViewer::launchUpdater, LLAppViewer::instance()));
 
 		// This call to LLLoginInstance::connect() starts the 
 		// authentication process.
@@ -979,7 +983,7 @@ bool idle_startup()
 		credentials["first"] = gFirstname;
 		credentials["last"] = gLastname;
 		credentials["passwd"] = gPassword;
-		LLLoginInstance::getInstance()->connect(credentials);
+		login->connect(credentials);
 
 		LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE );
 		return FALSE;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 826aca5e64b..1ab10b2f273 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7103,7 +7103,7 @@ void force_error_bad_memory_access(void *)
 
 void force_error_infinite_loop(void *)
 {
-    LLAppViewer::instance()->forceErrorInifiniteLoop();
+    LLAppViewer::instance()->forceErrorInfiniteLoop();
 }
 
 void force_error_software_exception(void *)
-- 
GitLab