PageRenderTime 68ms CodeModel.GetById 15ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/lllogininstance.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 918 lines | 645 code | 162 blank | 111 comment | 52 complexity | 6024b5a77d604a97ceb71915e83f0746 MD5 | raw file
  1/** 
  2 * @file lllogininstance.cpp
  3 * @brief Viewer's host for a login connection.
  4 *
  5 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "llviewerprecompiledheaders.h"
 28
 29#include "lllogininstance.h"
 30
 31// llcommon
 32#include "llevents.h"
 33#include "llmd5.h"
 34#include "stringize.h"
 35
 36// llmessage (!)
 37#include "llfiltersd2xmlrpc.h" // for xml_escape_string()
 38
 39// login
 40#include "lllogin.h"
 41
 42// newview
 43#include "llviewernetwork.h"
 44#include "llviewercontrol.h"
 45#include "llversioninfo.h"
 46#include "llslurl.h"
 47#include "llstartup.h"
 48#include "llfloaterreg.h"
 49#include "llnotifications.h"
 50#include "llwindow.h"
 51#include "llviewerwindow.h"
 52#include "llprogressview.h"
 53#if LL_LINUX || LL_SOLARIS
 54#include "lltrans.h"
 55#endif
 56#include "llsecapi.h"
 57#include "llstartup.h"
 58#include "llmachineid.h"
 59#include "llupdaterservice.h"
 60#include "llevents.h"
 61#include "llnotificationsutil.h"
 62#include "llappviewer.h"
 63
 64#include <boost/scoped_ptr.hpp>
 65#include <sstream>
 66
 67class LLLoginInstance::Disposable {
 68public:
 69	virtual ~Disposable() {}
 70};
 71
 72namespace {
 73	class MandatoryUpdateMachine:
 74		public LLLoginInstance::Disposable
 75	{
 76	public:
 77		MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService);
 78		
 79		void start(void);
 80		
 81	private:
 82		class State;
 83		class CheckingForUpdate;
 84		class Error;
 85		class ReadyToInstall; 
 86		class StartingUpdaterService;
 87		class WaitingForDownload;
 88		
 89		LLLoginInstance & mLoginInstance;
 90		boost::scoped_ptr<State> mState;
 91		LLUpdaterService & mUpdaterService;
 92		
 93		void setCurrentState(State * newState);
 94	};
 95
 96	
 97	class MandatoryUpdateMachine::State {
 98	public:
 99		virtual ~State() {}
100		virtual void enter(void) {}
101		virtual void exit(void) {}
102	};
103	
104	
105	class MandatoryUpdateMachine::CheckingForUpdate:
106	public MandatoryUpdateMachine::State
107	{
108	public:
109		CheckingForUpdate(MandatoryUpdateMachine & machine);
110		
111		virtual void enter(void);
112		virtual void exit(void);
113		
114	private:
115		LLTempBoundListener mConnection;
116		MandatoryUpdateMachine & mMachine;
117		LLProgressView * mProgressView;
118		
119		bool onEvent(LLSD const & event);
120	};
121	
122	
123	class MandatoryUpdateMachine::Error:
124	public MandatoryUpdateMachine::State
125	{
126	public:
127		Error(MandatoryUpdateMachine & machine);
128		
129		virtual void enter(void);
130		virtual void exit(void);
131		void onButtonClicked(const LLSD &, const LLSD &);
132		
133	private:
134		MandatoryUpdateMachine & mMachine;
135	};
136	
137	
138	class MandatoryUpdateMachine::ReadyToInstall:
139	public MandatoryUpdateMachine::State
140	{
141	public:
142		ReadyToInstall(MandatoryUpdateMachine & machine);
143		
144		virtual void enter(void);
145		virtual void exit(void);
146		
147	private:
148		MandatoryUpdateMachine & mMachine;
149	};
150	
151	
152	class MandatoryUpdateMachine::StartingUpdaterService:
153	public MandatoryUpdateMachine::State
154	{
155	public:
156		StartingUpdaterService(MandatoryUpdateMachine & machine);
157		
158		virtual void enter(void);
159		virtual void exit(void);
160		void onButtonClicked(const LLSD & uiform, const LLSD & result);
161	private:
162		MandatoryUpdateMachine & mMachine;
163	};
164	
165	
166	class MandatoryUpdateMachine::WaitingForDownload:
167		public MandatoryUpdateMachine::State
168	{
169	public:
170		WaitingForDownload(MandatoryUpdateMachine & machine);
171		
172		virtual void enter(void);
173		virtual void exit(void);
174		
175	private:
176		LLTempBoundListener mConnection;
177		MandatoryUpdateMachine & mMachine;
178		LLProgressView * mProgressView;
179		
180		bool onEvent(LLSD const & event);
181	};
182}
183
184static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
185static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
186
187std::string construct_start_string();
188
189
190
191// MandatoryUpdateMachine
192//-----------------------------------------------------------------------------
193
194
195MandatoryUpdateMachine::MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService):
196	mLoginInstance(loginInstance),
197	mUpdaterService(updaterService)
198{
199	; // No op.
200}
201
202
203void MandatoryUpdateMachine::start(void)
204{
205	llinfos << "starting manditory update machine" << llendl;
206	
207	if(mUpdaterService.isChecking()) {
208		switch(mUpdaterService.getState()) {
209			case LLUpdaterService::UP_TO_DATE:
210				mUpdaterService.stopChecking();
211				mUpdaterService.startChecking();
212				// Fall through.
213			case LLUpdaterService::INITIAL:
214			case LLUpdaterService::CHECKING_FOR_UPDATE:
215				setCurrentState(new CheckingForUpdate(*this));
216				break;
217			case LLUpdaterService::TEMPORARY_ERROR:
218				setCurrentState(new Error(*this));
219				break;
220			case LLUpdaterService::DOWNLOADING:
221				setCurrentState(new WaitingForDownload(*this));
222				break;
223			case LLUpdaterService::TERMINAL:
224				if(LLUpdaterService::updateReadyToInstall()) {
225					setCurrentState(new ReadyToInstall(*this));
226				} else {
227					setCurrentState(new Error(*this));
228				}
229				break;
230			case LLUpdaterService::FAILURE:
231				setCurrentState(new Error(*this));
232				break;
233			default:
234				llassert(!"unpossible case");
235				break;
236		}
237	} else {
238		setCurrentState(new StartingUpdaterService(*this));
239	}
240}
241
242
243void MandatoryUpdateMachine::setCurrentState(State * newStatePointer)
244{
245	{
246		boost::scoped_ptr<State> newState(newStatePointer);
247		if(mState != 0) mState->exit();
248		mState.swap(newState);
249		
250		// Old state will be deleted on exit from this block before the new state
251		// is entered.
252	}
253	if(mState != 0) mState->enter();
254}
255
256
257
258// MandatoryUpdateMachine::CheckingForUpdate
259//-----------------------------------------------------------------------------
260
261
262MandatoryUpdateMachine::CheckingForUpdate::CheckingForUpdate(MandatoryUpdateMachine & machine):
263	mMachine(machine)
264{
265	; // No op.
266}
267
268
269void MandatoryUpdateMachine::CheckingForUpdate::enter(void)
270{
271	llinfos << "entering checking for update" << llendl;
272	
273	mProgressView = gViewerWindow->getProgressView();
274	mProgressView->setMessage("Looking for update...");
275	mProgressView->setText("There is a required update for your Second Life installation.");
276	mProgressView->setPercent(0);
277	mProgressView->setVisible(true);
278	mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).
279		listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::CheckingForUpdate::onEvent, this, _1));
280}
281
282
283void MandatoryUpdateMachine::CheckingForUpdate::exit(void)
284{
285}
286
287
288bool MandatoryUpdateMachine::CheckingForUpdate::onEvent(LLSD const & event)
289{
290	if(event["type"].asInteger() == LLUpdaterService::STATE_CHANGE) {
291		switch(event["state"].asInteger()) {
292			case LLUpdaterService::DOWNLOADING:
293				mMachine.setCurrentState(new WaitingForDownload(mMachine));
294				break;
295			case LLUpdaterService::TEMPORARY_ERROR:
296			case LLUpdaterService::UP_TO_DATE:
297			case LLUpdaterService::TERMINAL:
298			case LLUpdaterService::FAILURE:
299				mProgressView->setVisible(false);
300				mMachine.setCurrentState(new Error(mMachine));
301				break;
302			case LLUpdaterService::INSTALLING:
303				llassert(!"can't possibly be installing");
304				break;
305			default:
306				break;
307		}
308	} else {
309		; // Ignore.
310	}
311	
312	return false;
313}
314
315
316
317// MandatoryUpdateMachine::Error
318//-----------------------------------------------------------------------------
319
320
321MandatoryUpdateMachine::Error::Error(MandatoryUpdateMachine & machine):
322	mMachine(machine)
323{
324	; // No op.
325}
326
327
328void MandatoryUpdateMachine::Error::enter(void)
329{
330	llinfos << "entering error" << llendl;
331	LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2));
332}
333
334
335void MandatoryUpdateMachine::Error::exit(void)
336{
337	LLAppViewer::instance()->forceQuit();
338}
339
340
341void MandatoryUpdateMachine::Error::onButtonClicked(const LLSD &, const LLSD &)
342{
343	mMachine.setCurrentState(0);
344}
345
346
347
348// MandatoryUpdateMachine::ReadyToInstall
349//-----------------------------------------------------------------------------
350
351
352MandatoryUpdateMachine::ReadyToInstall::ReadyToInstall(MandatoryUpdateMachine & machine):
353	mMachine(machine)
354{
355	; // No op.
356}
357
358
359void MandatoryUpdateMachine::ReadyToInstall::enter(void)
360{
361	llinfos << "entering ready to install" << llendl;
362	// Open update ready dialog.
363}
364
365
366void MandatoryUpdateMachine::ReadyToInstall::exit(void)
367{
368	// Restart viewer.
369}
370
371
372
373// MandatoryUpdateMachine::StartingUpdaterService
374//-----------------------------------------------------------------------------
375
376
377MandatoryUpdateMachine::StartingUpdaterService::StartingUpdaterService(MandatoryUpdateMachine & machine):
378	mMachine(machine)
379{
380	; // No op.
381}
382
383
384void MandatoryUpdateMachine::StartingUpdaterService::enter(void)
385{
386	llinfos << "entering start update service" << llendl;
387	LLNotificationsUtil::add("UpdaterServiceNotRunning", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked, this, _1, _2));
388}
389
390
391void MandatoryUpdateMachine::StartingUpdaterService::exit(void)
392{
393	; // No op.
394}
395
396
397void MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked(const LLSD & uiform, const LLSD & result)
398{
399	if(result["OK_okcancelbuttons"].asBoolean()) {
400		mMachine.mUpdaterService.startChecking(false);
401		mMachine.setCurrentState(new CheckingForUpdate(mMachine));
402	} else {
403		LLAppViewer::instance()->forceQuit();
404	}
405}
406
407
408
409// MandatoryUpdateMachine::WaitingForDownload
410//-----------------------------------------------------------------------------
411
412
413MandatoryUpdateMachine::WaitingForDownload::WaitingForDownload(MandatoryUpdateMachine & machine):
414	mMachine(machine),
415	mProgressView(0)
416{
417	; // No op.
418}
419
420
421void MandatoryUpdateMachine::WaitingForDownload::enter(void)
422{
423	llinfos << "entering waiting for download" << llendl;
424	mProgressView = gViewerWindow->getProgressView();
425	mProgressView->setMessage("Downloading update...");
426	std::ostringstream stream;
427	stream << "There is a required update for your Second Life installation." << std::endl <<
428		"Version " << mMachine.mUpdaterService.updatedVersion();
429	mProgressView->setText(stream.str());
430	mProgressView->setPercent(0);
431	mProgressView->setVisible(true);
432	mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).
433		listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::WaitingForDownload::onEvent, this, _1));
434}
435
436
437void MandatoryUpdateMachine::WaitingForDownload::exit(void)
438{
439	mProgressView->setVisible(false);
440}
441
442
443bool MandatoryUpdateMachine::WaitingForDownload::onEvent(LLSD const & event)
444{
445	switch(event["type"].asInteger()) {
446		case LLUpdaterService::DOWNLOAD_COMPLETE:
447			mMachine.setCurrentState(new ReadyToInstall(mMachine));
448			break;
449		case LLUpdaterService::DOWNLOAD_ERROR:
450			mMachine.setCurrentState(new Error(mMachine));
451			break;
452		case LLUpdaterService::PROGRESS: {
453			double downloadSize = event["download_size"].asReal();
454			double bytesDownloaded = event["bytes_downloaded"].asReal();
455			mProgressView->setPercent(100. * bytesDownloaded / downloadSize);
456			break;
457		}
458		default:
459			break;
460	}
461
462	return false;
463}
464
465
466
467// LLLoginInstance
468//-----------------------------------------------------------------------------
469
470
471LLLoginInstance::LLLoginInstance() :
472	mLoginModule(new LLLogin()),
473	mNotifications(NULL),
474	mLoginState("offline"),
475	mSkipOptionalUpdate(false),
476	mAttemptComplete(false),
477	mTransferRate(0.0f),
478	mDispatcher("LLLoginInstance", "change"),
479	mUpdaterService(0)
480{
481	mLoginModule->getEventPump().listen("lllogininstance", 
482		boost::bind(&LLLoginInstance::handleLoginEvent, this, _1));
483	// This internal use of LLEventDispatcher doesn't really need
484	// per-function descriptions.
485	mDispatcher.add("fail.login", "", boost::bind(&LLLoginInstance::handleLoginFailure, this, _1));
486	mDispatcher.add("connect",    "", boost::bind(&LLLoginInstance::handleLoginSuccess, this, _1));
487	mDispatcher.add("disconnect", "", boost::bind(&LLLoginInstance::handleDisconnect, this, _1));
488	mDispatcher.add("indeterminate", "", boost::bind(&LLLoginInstance::handleIndeterminate, this, _1));
489}
490
491LLLoginInstance::~LLLoginInstance()
492{
493}
494
495void LLLoginInstance::connect(LLPointer<LLCredential> credentials)
496{
497	std::vector<std::string> uris;
498	LLGridManager::getInstance()->getLoginURIs(uris);
499	connect(uris.front(), credentials);
500}
501
502void LLLoginInstance::connect(const std::string& uri, LLPointer<LLCredential> credentials)
503{
504	mAttemptComplete = false; // Reset attempt complete at this point!
505	constructAuthParams(credentials);
506	mLoginModule->connect(uri, mRequestData);
507}
508
509void LLLoginInstance::reconnect()
510{
511	// Sort of like connect, only using the pre-existing
512	// request params.
513	std::vector<std::string> uris;
514	LLGridManager::getInstance()->getLoginURIs(uris);
515	mLoginModule->connect(uris.front(), mRequestData);
516	gViewerWindow->setShowProgress(true);
517}
518
519void LLLoginInstance::disconnect()
520{
521	mAttemptComplete = false; // Reset attempt complete at this point!
522	mRequestData.clear();
523	mLoginModule->disconnect();
524}
525
526LLSD LLLoginInstance::getResponse() 
527{
528	return mResponseData; 
529}
530
531void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credential)
532{
533	// Set up auth request options.
534//#define LL_MINIMIAL_REQUESTED_OPTIONS
535	LLSD requested_options;
536	// *Note: this is where gUserAuth used to be created.
537	requested_options.append("inventory-root");
538	requested_options.append("inventory-skeleton");
539	//requested_options.append("inventory-meat");
540	//requested_options.append("inventory-skel-targets");
541#if (!defined LL_MINIMIAL_REQUESTED_OPTIONS)
542	if(FALSE == gSavedSettings.getBOOL("NoInventoryLibrary"))
543	{
544		requested_options.append("inventory-lib-root");
545		requested_options.append("inventory-lib-owner");
546		requested_options.append("inventory-skel-lib");
547	//	requested_options.append("inventory-meat-lib");
548	}
549
550	requested_options.append("initial-outfit");
551	requested_options.append("gestures");
552	requested_options.append("display_names");
553	requested_options.append("event_categories");
554	requested_options.append("event_notifications");
555	requested_options.append("classified_categories");
556	requested_options.append("adult_compliant"); 
557	//requested_options.append("inventory-targets");
558	requested_options.append("buddy-list");
559	requested_options.append("newuser-config");
560	requested_options.append("ui-config");
561
562	//send this info to login.cgi for stats gathering 
563	//since viewerstats isn't reliable enough
564	requested_options.append("advanced-mode");
565
566#endif
567	requested_options.append("max-agent-groups");	
568	requested_options.append("map-server-url");	
569	requested_options.append("voice-config");
570	requested_options.append("tutorial_setting");
571	requested_options.append("login-flags");
572	requested_options.append("global-textures");
573	if(gSavedSettings.getBOOL("ConnectAsGod"))
574	{
575		gSavedSettings.setBOOL("UseDebugMenus", TRUE);
576		requested_options.append("god-connect");
577	}
578	
579	// (re)initialize the request params with creds.
580	LLSD request_params = user_credential->getLoginParams();
581
582	char hashed_unique_id_string[MD5HEX_STR_SIZE];		/* Flawfinder: ignore */
583	LLMD5 hashed_unique_id;
584	unsigned char unique_id[MAC_ADDRESS_BYTES];
585	if(LLUUID::getNodeID(unique_id) == 0) {
586		if(LLMachineID::getUniqueID(unique_id, sizeof(unique_id)) == 0) {
587			llerrs << "Failed to get an id; cannot uniquely identify this machine." << llendl;
588		}
589	}
590	hashed_unique_id.update(unique_id, MAC_ADDRESS_BYTES);
591	hashed_unique_id.finalize();
592	hashed_unique_id.hex_digest(hashed_unique_id_string);
593	
594	request_params["start"] = construct_start_string();
595	request_params["skipoptional"] = mSkipOptionalUpdate;
596	request_params["agree_to_tos"] = false; // Always false here. Set true in 
597	request_params["read_critical"] = false; // handleTOSResponse
598	request_params["last_exec_event"] = mLastExecEvent;
599	request_params["mac"] = hashed_unique_id_string;
600	request_params["version"] = LLVersionInfo::getChannelAndVersion(); // Includes channel name
601	request_params["channel"] = LLVersionInfo::getChannel();
602	request_params["id0"] = mSerialNumber;
603	request_params["host_id"] = gSavedSettings.getString("HostID");
604	request_params["extended_errors"] = true; // request message_id and message_args
605
606	mRequestData.clear();
607	mRequestData["method"] = "login_to_simulator";
608	mRequestData["params"] = request_params;
609	mRequestData["options"] = requested_options;
610
611	mRequestData["cfg_srv_timeout"] = gSavedSettings.getF32("LoginSRVTimeout");
612	mRequestData["cfg_srv_pump"] = gSavedSettings.getString("LoginSRVPump");
613}
614
615bool LLLoginInstance::handleLoginEvent(const LLSD& event)
616{
617	LL_DEBUGS("LLLogin") << "LoginListener called!: \n" << event << LL_ENDL;
618
619	if(!(event.has("state") && event.has("change") && event.has("progress")))
620	{
621		llerrs << "Unknown message from LLLogin: " << event << llendl;
622	}
623
624	mLoginState = event["state"].asString();
625	mResponseData = event["data"];
626	
627	if(event.has("transfer_rate"))
628	{
629		mTransferRate = event["transfer_rate"].asReal();
630	}
631
632	
633
634	// Call the method registered in constructor, if any, for more specific
635	// handling
636	mDispatcher.try_call(event);
637	return false;
638}
639
640void LLLoginInstance::handleLoginFailure(const LLSD& event)
641{
642	// Login has failed. 
643	// Figure out why and respond...
644	LLSD response = event["data"];
645	std::string reason_response = response["reason"].asString();
646	std::string message_response = response["message"].asString();
647	// For the cases of critical message or TOS agreement,
648	// start the TOS dialog. The dialog response will be handled
649	// by the LLLoginInstance::handleTOSResponse() callback.
650	// The callback intiates the login attempt next step, either 
651	// to reconnect or to end the attempt in failure.
652	if(reason_response == "tos")
653	{
654		LLSD data(LLSD::emptyMap());
655		data["message"] = message_response;
656		data["reply_pump"] = TOS_REPLY_PUMP;
657		gViewerWindow->setShowProgress(FALSE);
658		LLFloaterReg::showInstance("message_tos", data);
659		LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
660			.listen(TOS_LISTENER_NAME,
661					boost::bind(&LLLoginInstance::handleTOSResponse, 
662								this, _1, "agree_to_tos"));
663	}
664	else if(reason_response == "critical")
665	{
666		LLSD data(LLSD::emptyMap());
667		data["message"] = message_response;
668		data["reply_pump"] = TOS_REPLY_PUMP;
669		if(response.has("error_code"))
670		{
671			data["error_code"] = response["error_code"];
672		}
673		if(response.has("certificate"))
674		{
675			data["certificate"] = response["certificate"];
676		}
677		
678		gViewerWindow->setShowProgress(FALSE);
679		LLFloaterReg::showInstance("message_critical", data);
680		LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
681			.listen(TOS_LISTENER_NAME,
682					boost::bind(&LLLoginInstance::handleTOSResponse, 
683								this, _1, "read_critical"));
684	}
685	else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate"))
686	{
687		gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
688		updateApp(true, message_response);
689	}
690	else if(reason_response == "optional")
691	{
692		updateApp(false, message_response);
693	}
694	else
695	{	
696		attemptComplete();
697	}	
698}
699
700void LLLoginInstance::handleLoginSuccess(const LLSD& event)
701{
702	if(gSavedSettings.getBOOL("ForceMandatoryUpdate"))
703	{
704		LLSD response = event["data"];
705		std::string message_response = response["message"].asString();
706
707		// Testing update...
708		gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
709
710		// Don't confuse startup by leaving login "online".
711		mLoginModule->disconnect(); 
712		updateApp(true, message_response);
713	}
714	else
715	{
716		attemptComplete();
717	}
718}
719
720void LLLoginInstance::handleDisconnect(const LLSD& event)
721{
722    // placeholder
723}
724
725void LLLoginInstance::handleIndeterminate(const LLSD& event)
726{
727	// The indeterminate response means that the server
728	// gave the viewer a new url and params to try.
729	// The login module handles the retry, but it gives us the
730	// server response so that we may show
731	// the user some status.
732	LLSD message = event.get("data").get("message");
733	if(message.isDefined())
734	{
735		LLSD progress_update;
736		progress_update["desc"] = message;
737		LLEventPumps::getInstance()->obtain("LLProgressView").post(progress_update);
738	}
739}
740
741bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
742{
743	if(accepted)
744	{	
745		// Set the request data to true and retry login.
746		mRequestData["params"][key] = true; 
747		reconnect();
748	}
749	else
750	{
751		attemptComplete();
752	}
753
754	LLEventPumps::instance().obtain(TOS_REPLY_PUMP).stopListening(TOS_LISTENER_NAME);
755	return true;
756}
757
758
759void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg)
760{
761	if(mandatory)
762	{
763		gViewerWindow->setShowProgress(false);
764		MandatoryUpdateMachine * machine = new MandatoryUpdateMachine(*this, *mUpdaterService);
765		mUpdateStateMachine.reset(machine);
766		machine->start();
767		return;
768	}
769	
770	// store off config state, as we might quit soon
771	gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);	
772	LLUIColorTable::instance().saveUserSettings();
773
774	std::ostringstream message;
775	std::string msg;
776	if (!auth_msg.empty())
777	{
778		msg = "(" + auth_msg + ") \n";
779	}
780
781	LLSD args;
782	args["MESSAGE"] = msg;
783	
784	LLSD payload;
785	payload["mandatory"] = mandatory;
786
787/*
788 We're constructing one of the following 9 strings here:
789	 "DownloadWindowsMandatory"
790	 "DownloadWindowsReleaseForDownload"
791	 "DownloadWindows"
792	 "DownloadMacMandatory"
793	 "DownloadMacReleaseForDownload"
794	 "DownloadMac"
795	 "DownloadLinuxMandatory"
796	 "DownloadLinuxReleaseForDownload"
797	 "DownloadLinux"
798 
799 I've called them out explicitly in this comment so that they can be grepped for.
800 */
801	std::string notification_name = "Download";
802	
803#if LL_WINDOWS
804	notification_name += "Windows";
805#elif LL_DARWIN
806	notification_name += "Mac";
807#else
808	notification_name += "Linux";
809#endif
810	
811	if (mandatory)
812	{
813		notification_name += "Mandatory";
814	}
815	else
816	{
817#if LL_RELEASE_FOR_DOWNLOAD
818		notification_name += "ReleaseForDownload";
819#endif
820	}
821
822	if(mNotifications)
823	{
824		mNotifications->add(notification_name, args, payload, 
825			boost::bind(&LLLoginInstance::updateDialogCallback, this, _1, _2));
826
827		gViewerWindow->setShowProgress(false);
828	}
829}
830
831bool LLLoginInstance::updateDialogCallback(const LLSD& notification, const LLSD& response)
832{
833	S32 option = LLNotification::getSelectedOption(notification, response);
834	std::string update_exe_path;
835	bool mandatory = notification["payload"]["mandatory"].asBoolean();
836
837#if !LL_RELEASE_FOR_DOWNLOAD
838	if (option == 2)
839	{
840		// This condition attempts to skip the 
841		// update if using a dev build.
842		// The relog probably won't work if the 
843		// update is mandatory. :)
844
845	    // *REMOVE:Mani - Saving for reference...
846		//LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); 
847		mSkipOptionalUpdate = true;
848		reconnect();
849		return false;
850	}
851#endif
852
853	if (option == 1)
854	{
855		// ...user doesn't want to do it
856		if (mandatory)
857		{
858			// Mandatory update, user chose to not to update...
859			// The login attemp is complete, startup should 
860			// quit when detecting this.
861			attemptComplete();
862
863			// *REMOVE:Mani - Saving for reference...
864			//LLAppViewer::instance()->forceQuit();
865			// // Bump them back to the login screen.
866			// //reset_login();
867		}
868		else
869		{
870			// Optional update, user chose to skip
871			mSkipOptionalUpdate = true;
872			reconnect();
873		}
874		return false;
875	}
876	
877 	if(mUpdaterLauncher)
878  	{
879 		mUpdaterLauncher();
880  	}
881  
882 	attemptComplete();
883
884	return false;
885}
886
887std::string construct_start_string()
888{
889	std::string start;
890	LLSLURL start_slurl = LLStartUp::getStartSLURL();
891	switch(start_slurl.getType())
892	{
893		case LLSLURL::LOCATION:
894		{
895			// a startup URL was specified
896			LLVector3 position = start_slurl.getPosition();
897			std::string unescaped_start = 
898			STRINGIZE(  "uri:" 
899					  << start_slurl.getRegion() << "&" 
900						<< position[VX] << "&" 
901						<< position[VY] << "&" 
902						<< position[VZ]);
903			start = xml_escape_string(unescaped_start);
904			break;
905		}
906		case LLSLURL::HOME_LOCATION:
907		{
908			start = "home";
909			break;
910		}
911		default:
912		{
913			start = "last";
914		}
915	}
916	return start;
917}
918