From fe71dd340ab396b93bde45df438041af5d85fd47 Mon Sep 17 00:00:00 2001
From: Roxie Linden <roxie@lindenlab.com>
Date: Mon, 1 Feb 2010 15:10:19 -0800
Subject: [PATCH] Merge giab-viewer-trunk 2497, general merge of more secapi
 stuff as well as certificate handling stuff. Grid manager as well

---
 indra/llmessage/llares.cpp                    |   1 +
 indra/llvfs/lldir.cpp                         |  39 +-
 indra/llvfs/lldir.h                           |   4 +-
 indra/newview/CMakeLists.txt                  |  18 +-
 indra/newview/app_settings/logcontrol.xml     |   8 +-
 indra/newview/app_settings/settings.xml       |  24 +-
 indra/newview/llappviewer.cpp                 |  54 +-
 indra/newview/llappviewer.h                   |   1 -
 indra/newview/llcurrencyuimanager.cpp         |   2 +-
 indra/newview/llfloaterbuyland.cpp            |   2 +-
 indra/newview/llfloaterreporter.cpp           |   2 +-
 indra/newview/llloginhandler.cpp              | 196 ++---
 indra/newview/llloginhandler.h                |  11 +-
 indra/newview/lllogininstance.cpp             |  27 +-
 indra/newview/lllogininstance.h               |   7 +-
 indra/newview/llpanellogin.cpp                | 314 ++++----
 indra/newview/llpanellogin.h                  |  14 +-
 indra/newview/llsecapi.cpp                    |  32 +-
 indra/newview/llsecapi.h                      |  68 +-
 indra/newview/llsechandler_basic.cpp          | 284 +++++++-
 indra/newview/llsechandler_basic.h            |  80 +-
 indra/newview/llstartup.cpp                   | 351 +++------
 indra/newview/llstartup.h                     |   8 -
 indra/newview/llviewermenu.cpp                |  16 +-
 indra/newview/llviewernetwork.cpp             | 683 ++++++++++++------
 indra/newview/llviewernetwork.h               | 181 +++--
 indra/newview/llviewerobject.cpp              |  12 +-
 indra/newview/llviewerstats.cpp               |   6 +-
 indra/newview/llviewerwindow.cpp              |   8 +-
 indra/newview/llvoiceclient.cpp               |  13 +-
 indra/newview/llvoiceclient.h                 |   6 +-
 indra/newview/llweb.cpp                       |   2 +-
 .../skins/default/xui/en/panel_login.xml      |  55 +-
 indra/newview/tests/lllogininstance_test.cpp  | 107 ++-
 .../newview/tests/llsechandler_basic_test.cpp | 456 ++++++++++++
 indra/newview/tests/llviewernetwork_test.cpp  | 446 ++++++++++++
 indra/viewer_components/login/lllogin.cpp     |  37 +-
 37 files changed, 2479 insertions(+), 1096 deletions(-)
 create mode 100644 indra/newview/tests/llsechandler_basic_test.cpp
 create mode 100644 indra/newview/tests/llviewernetwork_test.cpp

diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp
index 104629c157..db7ac2f154 100644
--- a/indra/llmessage/llares.cpp
+++ b/indra/llmessage/llares.cpp
@@ -171,6 +171,7 @@ void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
 	resp->mUri = LLURI(uri);
 	search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(),
 		   RES_SRV, resp);
+	llinfos << "Rewritten " << uri << llendl;
 }
 
 LLQueryResponder::LLQueryResponder()
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index b2b17fdd56..296d827a20 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -555,26 +555,23 @@ std::string LLDir::getForbiddenFileChars()
 	return "\\/:*?\"<>|";
 }
 
-void LLDir::setLindenUserDir(const std::string &first, const std::string &last)
+void LLDir::setLindenUserDir(const std::string &username)
 {
 	// if both first and last aren't set, assume we're grabbing the cached dir
-	if (!first.empty() && !last.empty())
+	if (!username.empty())
 	{
 		// some platforms have case-sensitive filesystems, so be
 		// utterly consistent with our firstname/lastname case.
-		std::string firstlower(first);
-		LLStringUtil::toLower(firstlower);
-		std::string lastlower(last);
-		LLStringUtil::toLower(lastlower);
+		std::string userlower(username);
+		LLStringUtil::toLower(userlower);
+		LLStringUtil::replaceChar(userlower, ' ', '_');
 		mLindenUserDir = getOSUserAppDir();
 		mLindenUserDir += mDirDelimiter;
-		mLindenUserDir += firstlower;
-		mLindenUserDir += "_";
-		mLindenUserDir += lastlower;
+		mLindenUserDir += userlower;
 	}
 	else
 	{
-		llerrs << "Invalid name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
+		llerrs << "NULL name for LLDir::setLindenUserDir" << llendl;
 	}
 
 	dumpCurrentDirectories();	
@@ -592,27 +589,25 @@ void LLDir::setChatLogsDir(const std::string &path)
 	}
 }
 
-void LLDir::setPerAccountChatLogsDir(const std::string &first, const std::string &last)
+void LLDir::setPerAccountChatLogsDir(const std::string &username)
 {
 	// if both first and last aren't set, assume we're grabbing the cached dir
-	if (!first.empty() && !last.empty())
+	if (!username.empty())
 	{
 		// some platforms have case-sensitive filesystems, so be
 		// utterly consistent with our firstname/lastname case.
-		std::string firstlower(first);
-		LLStringUtil::toLower(firstlower);
-		std::string lastlower(last);
-		LLStringUtil::toLower(lastlower);
-		mPerAccountChatLogsDir = getChatLogsDir();
-		mPerAccountChatLogsDir += mDirDelimiter;
-		mPerAccountChatLogsDir += firstlower;
-		mPerAccountChatLogsDir += "_";
-		mPerAccountChatLogsDir += lastlower;
+		std::string userlower(username);
+		LLStringUtil::toLower(userlower);
+		LLStringUtil::replaceChar(userlower, ' ', '_');
+		mLindenUserDir = getChatLogsDir();
+		mLindenUserDir += mDirDelimiter;
+		mLindenUserDir += userlower;
 	}
 	else
 	{
-		llwarns << "Invalid name for LLDir::setPerAccountChatLogsDir" << llendl;
+		llerrs << "NULL name for LLDir::setPerAccountChatLogsDir" << llendl;
 	}
+	
 }
 
 void LLDir::setSkinFolder(const std::string &skin_folder)
diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 206e3223e3..9c1e992eca 100644
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -137,8 +137,8 @@ class LLDir
 	static std::string getForbiddenFileChars();
 
 	virtual void setChatLogsDir(const std::string &path);		// Set the chat logs dir to this user's dir
-	virtual void setPerAccountChatLogsDir(const std::string &first, const std::string &last);		// Set the per user chat log directory.
-	virtual void setLindenUserDir(const std::string &first, const std::string &last);		// Set the linden user dir to this user's dir
+	virtual void setPerAccountChatLogsDir(const std::string &username);		// Set the per user chat log directory.
+	virtual void setLindenUserDir(const std::string &username);		// Set the linden user dir to this user's dir
 	virtual void setSkinFolder(const std::string &skin_folder);
 	virtual bool setCacheDir(const std::string &path);
 
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 9430bb1d56..4be6fb940e 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1407,11 +1407,11 @@ if (WINDOWS)
       # Note the need to specify multiple names explicitly.
       set(GOOGLE_PERF_TOOLS_SOURCE
         ${SHARED_LIB_STAGING_DIR}/Release/libtcmalloc_minimal.dll
-	${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libtcmalloc_minimal.dll
-	${SHARED_LIB_STAGING_DIR}/Debug/libtcmalloc_minimal-debug.dll
-	)
-    endif(USE_GOOGLE_PERFTOOLS)
-	  
+        ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libtcmalloc_minimal.dll
+        ${SHARED_LIB_STAGING_DIR}/Debug/libtcmalloc_minimal-debug.dll
+        )
+     endif(USE_GOOGLE_PERFTOOLS)
+ 
 
     set(COPY_INPUT_DEPENDECIES
       # The following commented dependencies are determined at variably at build time. Can't do this here.
@@ -1504,11 +1504,11 @@ if (WINDOWS)
         --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
         --grid=${GRID}
         --source=${CMAKE_CURRENT_SOURCE_DIR}
-	--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/copy_touched.bat
+        --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/copy_touched.bat
       DEPENDS 
-	${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
-	stage_third_party_libs
-	${COPY_INPUT_DEPENDECIES}
+        ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+        stage_third_party_libs
+        ${COPY_INPUT_DEPENDECIES}
       COMMENT "Performing viewer_manifest copy"
       )
     
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index d7bb64ce8a..0eb98e3311 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -20,11 +20,7 @@
 					<key>tags</key>
 						<array>
 							<string>AppInit</string>
-							<string>SystemInfo</string>
-							<string>TextureCache</string>
-							<string>AppCache</string>
-							<string>Window</string>
-							<string>RenderInit</string>
+							<string>LLLogin</string>
 						</array>
 				</map>
 				<map>
@@ -40,6 +36,8 @@
 						</array>
 					<key>tags</key>
 						<array>
+							<string>AppInit</string>
+							<string>LLLogin</string>
 						</array>
 				</map>
 			</array>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7d98a4b6ce..75ee389750 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1629,6 +1629,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>CurrentGrid</key>
+    <map>
+      <key>Comment</key>
+      <string>Currently Selected Grid</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string></string>
+    </map>
     <key>CustomServer</key>
     <map>
       <key>Comment</key>
@@ -3420,7 +3431,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>0</integer>
+      <integer>1</integer>
     </map>
     <key>ForceMandatoryUpdate</key>
     <map>
@@ -7594,6 +7605,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>SecondLifeEnterprise</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables Second Life Enterprise features</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>	
     <key>SelectMovableOnly</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index fb1bded795..cc32346441 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -191,6 +191,9 @@
 #include "llparcel.h"
 #include "llavatariconctrl.h"
 
+// Include for security api initialization
+#include "llsecapi.h"
+
 // *FIX: These extern globals should be cleaned up.
 // The globals either represent state/config/resource-storage of either 
 // this app, or another 'component' of the viewer. App globals should be 
@@ -506,35 +509,6 @@ public:
 	}
 };
 
-void LLAppViewer::initGridChoice()
-{
-	// Load	up the initial grid	choice from:
-	//	- hard coded defaults...
-	//	- command line settings...
-	//	- if dev build,	persisted settings...
-
-	// Set the "grid choice", this is specified	by command line.
-	std::string	grid_choice	= gSavedSettings.getString("CmdLineGridChoice");
-	LLViewerLogin::getInstance()->setGridChoice(grid_choice);
-
-	// Load last server choice by default 
-	// ignored if the command line grid	choice has been	set
-	if(grid_choice.empty())
-	{
-		S32	server = gSavedSettings.getS32("ServerChoice");
-		server = llclamp(server, 0,	(S32)GRID_INFO_COUNT - 1);
-		if(server == GRID_INFO_OTHER)
-		{
-			std::string custom_server = gSavedSettings.getString("CustomServer");
-			LLViewerLogin::getInstance()->setGridChoice(custom_server);
-		}
-		else if(server != (S32)GRID_INFO_NONE)
-		{
-			LLViewerLogin::getInstance()->setGridChoice((EGridInfo)server);
-		}
-	}
-}
-
 //virtual
 bool LLAppViewer::initSLURLHandler()
 {
@@ -646,7 +620,7 @@ bool LLAppViewer::init()
     LLCurl::initClass();
 
     initThreads();
-
+    initializeSecHandler();
     writeSystemInfo();
 
 	// Build a string representing the current version number.
@@ -776,10 +750,6 @@ bool LLAppViewer::init()
 		return false;
 	}
 
-	// Always fetch the Ethernet MAC address, needed both for login
-	// and password load.
-	LLUUID::getNodeID(gMACAddress);
-
 	// Prepare for out-of-memory situations, during which we will crash on
 	// purpose and save a dump.
 #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
@@ -1462,13 +1432,6 @@ bool LLAppViewer::cleanup()
 
 	llinfos << "Saving Data" << llendflush;
 	
-	// Quitting with "Remember Password" turned off should always stomp your
-	// saved password, whether or not you successfully logged in.  JC
-	if (!gSavedSettings.getBOOL("RememberPassword"))
-	{
-		LLStartUp::deletePasswordFromDisk();
-	}
-	
 	// Store the time of our current logoff
 	gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
 
@@ -2022,7 +1985,6 @@ bool LLAppViewer::initConfiguration()
         }
     }
 
-    initGridChoice();
 
 	// If we have specified crash on startup, set the global so we'll trigger the crash at the right time
 	if(clp.hasOption("crashonstartup"))
@@ -2511,7 +2473,7 @@ void LLAppViewer::writeSystemInfo()
 
 	// The user is not logged on yet, but record the current grid choice login url
 	// which may have been the intended grid. This can b
-	gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
+	gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
 
 	// *FIX:Mani - move this ddown in llappviewerwin32
 #ifdef LL_WINDOWS
@@ -2678,10 +2640,10 @@ void LLAppViewer::handleViewerCrash()
 		gMessageSystem->stopLogging();
 	}
 
-	LLWorld::getInstance()->getInfo(gDebugInfo);
+	//LLWorld::getInstance()->getInfo(gDebugInfo);
 
 	// Close the debug file
-	pApp->writeDebugInfo();
+	//pApp->writeDebugInfo();
 
 	LLError::logToFile("");
 
@@ -4271,7 +4233,7 @@ void LLAppViewer::launchUpdater()
 #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["userserver"] = LLGridManager::getInstance()->getGridLabel();
 	query_map["channel"] = gSavedSettings.getString("VersionChannelName");
 	// *TODO constantize this guy
 	// *NOTE: This URL is also used in win_setup/lldownloader.cpp
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 40e74061b5..870d47aa79 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -186,7 +186,6 @@ private:
 
 	bool initThreads(); // Initialize viewer threads, return false on failure.
 	bool initConfiguration(); // Initialize settings from the command line/config file.
-	void initGridChoice();
 
 	bool initCache(); // Initialize local client cache.
 
diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp
index 00c05445e1..207270c0ad 100644
--- a/indra/newview/llcurrencyuimanager.cpp
+++ b/indra/newview/llcurrencyuimanager.cpp
@@ -284,7 +284,7 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
 	static std::string transactionURI;
 	if (transactionURI.empty())
 	{
-		transactionURI = LLViewerLogin::getInstance()->getHelperURI() + "currency.php";
+		transactionURI = LLGridManager::getInstance()->getHelperURI() + "currency.php";
 	}
 
 	delete mTransaction;
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp
index 9b88923e7e..10a4908f3a 100644
--- a/indra/newview/llfloaterbuyland.cpp
+++ b/indra/newview/llfloaterbuyland.cpp
@@ -837,7 +837,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa
 	static std::string transaction_uri;
 	if (transaction_uri.empty())
 	{
-		transaction_uri = LLViewerLogin::getInstance()->getHelperURI() + "landtool.php";
+		transaction_uri = LLGridManager::getInstance()->getHelperURI() + "landtool.php";
 	}
 	
 	const char* method;
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index e0f2fca580..a52fe131cd 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -545,7 +545,7 @@ LLSD LLFloaterReporter::gatherReport()
 	mCopyrightWarningSeen = FALSE;
 
 	std::ostringstream summary;
-	if (!LLViewerLogin::getInstance()->isInProductionGrid())
+	if (!LLGridManager::getInstance()->isInProductionGrid())
 	{
 		summary << "Preview ";
 	}
diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp
index 1be3430e07..7d43f6a8cc 100644
--- a/indra/newview/llloginhandler.cpp
+++ b/indra/newview/llloginhandler.cpp
@@ -35,12 +35,13 @@
 #include "llloginhandler.h"
 
 // viewer includes
+#include "llsecapi.h"
 #include "llpanellogin.h"			// save_password_to_disk()
 #include "llstartup.h"				// getStartupState()
 #include "llurlsimstring.h"
 #include "llviewercontrol.h"		// gSavedSettings
 #include "llviewernetwork.h"		// EGridInfo
-#include "llviewerwindow.h"			// getWindow()
+#include "llviewerwindow.h"                    // getWindow()
 
 // library includes
 #include "llmd5.h"
@@ -59,109 +60,28 @@ bool LLLoginHandler::parseDirectLogin(std::string url)
 	LLURI uri(url);
 	parse(uri.queryMap());
 
-	if (/*mWebLoginKey.isNull() ||*/
-		mFirstName.empty() ||
-		mLastName.empty())
-	{
-		return false;
-	}
-	else
-	{
-		return true;
-	}
+	// NOTE: Need to add direct login as per identity evolution
+	return true;
 }
 
-
 void LLLoginHandler::parse(const LLSD& queryMap)
 {
-	//mWebLoginKey = queryMap["web_login_key"].asUUID();
-	mFirstName = queryMap["first_name"].asString();
-	mLastName = queryMap["last_name"].asString();
 	
-	EGridInfo grid_choice = GRID_INFO_NONE;
-	if (queryMap["grid"].asString() == "aditi")
-	{
-		grid_choice = GRID_INFO_ADITI;
-	}
-	else if (queryMap["grid"].asString() == "agni")
-	{
-		grid_choice = GRID_INFO_AGNI;
-	}
-	else if (queryMap["grid"].asString() == "siva")
-	{
-		grid_choice = GRID_INFO_SIVA;
-	}
-	else if (queryMap["grid"].asString() == "damballah")
-	{
-		grid_choice = GRID_INFO_DAMBALLAH;
-	}
-	else if (queryMap["grid"].asString() == "durga")
+	if (queryMap.has("grid"))
 	{
-		grid_choice = GRID_INFO_DURGA;
+		LLGridManager::getInstance()->setGridChoice(queryMap["grid"].asString());
 	}
-	else if (queryMap["grid"].asString() == "shakti")
-	{
-		grid_choice = GRID_INFO_SHAKTI;
-	}
-	else if (queryMap["grid"].asString() == "soma")
-	{
-		grid_choice = GRID_INFO_SOMA;
-	}
-	else if (queryMap["grid"].asString() == "ganga")
-	{
-		grid_choice = GRID_INFO_GANGA;
-	}
-	else if (queryMap["grid"].asString() == "vaak")
-	{
-		grid_choice = GRID_INFO_VAAK;
-	}
-	else if (queryMap["grid"].asString() == "uma")
-	{
-		grid_choice = GRID_INFO_UMA;
-	}
-	else if (queryMap["grid"].asString() == "mohini")
-	{
-		grid_choice = GRID_INFO_MOHINI;
-	}
-	else if (queryMap["grid"].asString() == "yami")
-	{
-		grid_choice = GRID_INFO_YAMI;
-	}
-	else if (queryMap["grid"].asString() == "nandi")
-	{
-		grid_choice = GRID_INFO_NANDI;
-	}
-	else if (queryMap["grid"].asString() == "mitra")
-	{
-		grid_choice = GRID_INFO_MITRA;
-	}
-	else if (queryMap["grid"].asString() == "radha")
-	{
-		grid_choice = GRID_INFO_RADHA;
-	}
-	else if (queryMap["grid"].asString() == "ravi")
-	{
-		grid_choice = GRID_INFO_RAVI;
-	}
-	else if (queryMap["grid"].asString() == "aruna")
-	{
-		grid_choice = GRID_INFO_ARUNA;
-	}
-
-	if(grid_choice != GRID_INFO_NONE)
-	{
-		LLViewerLogin::getInstance()->setGridChoice(grid_choice);
-	}
-
+	
+	
 	std::string startLocation = queryMap["location"].asString();
-
+	
 	if (startLocation == "specify")
 	{
-		LLURLSimString::setString(queryMap["region"].asString());
+	  LLURLSimString::setString(queryMap["region"].asString());
 	}
-	else if (!startLocation.empty()) // "last" or "home" or ??? (let LLURLSimString figure it out)
+	else if (!startLocation.empty())
 	{
-		LLURLSimString::setString(startLocation);
+	  LLURLSimString::setString(startLocation);
 	}
 }
 
@@ -212,40 +132,68 @@ bool LLLoginHandler::handle(const LLSD& tokens,
 		return true;
 	}
 	
-	std::string password = query_map["password"].asString();
-
-	if (!password.empty())
+	if  (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)  //on splash page         
 	{
-		gSavedSettings.setBOOL("RememberPassword", TRUE);
-
-		if (password.substr(0,3) != "$1$")
-		{
-			LLMD5 pass((unsigned char*)password.c_str());
-			char md5pass[33];		/* Flawfinder: ignore */
-			pass.hex_digest(md5pass);
-			std::string hashed_password = ll_safe_string(md5pass, 32);
-			LLStartUp::savePasswordToDisk(hashed_password);
-		}
+	  // as the login page may change from grid to grid, as well as
+	  // things like username/password/etc, we simply refresh the
+	  // login page to make sure everything is set up correctly
+	  LLPanelLogin::loadLoginPage();
+	  LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
 	}
-			
+	return true;
+}
+
+
 
-	if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)  //on splash page
+//  Initialize the credentials                                                                                              
+// If the passed in URL contains login info, parse                                                                          
+// that into a credential and web login key.  Otherwise                                                                     
+// check the command line.  If the command line                                                                             
+// does not contain any login creds, load the last saved                                                                    
+// ones from the protected credential store.                                                                                
+// This always returns with a credential structure set in the                                                               
+// login handler                                                                                                            
+LLPointer<LLCredential> LLLoginHandler::initializeLoginInfo(const std::string& url)                                         
+{                                                                                                                           
+	LLURI uri(url);                                                                                                      
+	LLPointer<LLCredential> result = NULL;                                                                               
+	parse(uri.queryMap());                                                                                               
+	// we weren't able to parse login info from the slurl,                                                               
+	// so try to load it from the UserLoginInfo                                                                          
+	result = loadSavedUserLoginInfo();                                                                                   
+	if (result.isNull())                                                                                                 
+	{                                                                                                                    
+		result =  gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGridName());                       
+	}                                                                                                                    
+	
+	return result;                                                                                                       
+} 
+
+
+LLPointer<LLCredential> LLLoginHandler::loadSavedUserLoginInfo()
+{
+  // load the saved user login info into a LLCredential.
+  // perhaps this should be moved.
+	LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
+	if (cmd_line_login.size() == 3) 
 	{
-		if (!mFirstName.empty() || !mLastName.empty())
-		{
-			// Fill in the name, and maybe the password
-			LLPanelLogin::setFields(mFirstName, mLastName, password);
-		}
-
-		//if (mWebLoginKey.isNull())
-		//{
-		//	LLPanelLogin::loadLoginPage();
-		//}
-		//else
-		//{
-		//	LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
-		//}
-		LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
-	}
-	return true;
+	
+		LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str());
+		char md5pass[33];               /* Flawfinder: ignore */
+		pass.hex_digest(md5pass);
+		LLSD identifier = LLSD::emptyMap();
+		identifier["type"] = "agent";
+		identifier["first_name"] = cmd_line_login[0];
+		identifier["last_name"] = cmd_line_login[1];
+		
+		LLSD authenticator = LLSD::emptyMap();
+		authenticator["type"] = "hash";
+		authenticator["algorithm"] = "md5";
+		authenticator["secret"] = md5pass;
+		// yuck, we'll fix this with mani's changes.
+		gSavedSettings.setBOOL("AutoLogin", TRUE);
+		return gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGridName(), 
+													   identifier, authenticator);
+	}
+	return NULL;
 }
diff --git a/indra/newview/llloginhandler.h b/indra/newview/llloginhandler.h
index ac4648761b..ec2459c835 100644
--- a/indra/newview/llloginhandler.h
+++ b/indra/newview/llloginhandler.h
@@ -34,6 +34,7 @@
 #define LLLOGINHANDLER_H
 
 #include "llcommandhandler.h"
+#include "llsecapi.h"
 
 class LLLoginHandler : public LLCommandHandler
 {
@@ -46,19 +47,15 @@ class LLLoginHandler : public LLCommandHandler
 	// secondlife:///app/login?first=Bob&last=Dobbs
 	bool parseDirectLogin(std::string url);
 
-	std::string getFirstName() const { return mFirstName; }
-	std::string getLastName() const { return mLastName; }
-
 	// Web-based login unsupported
 	//LLUUID getWebLoginKey() const { return mWebLoginKey; }
 
+	LLPointer<LLCredential> loadSavedUserLoginInfo();  
+	LLPointer<LLCredential> initializeLoginInfo(const std::string& url);
+
 private:
 	void parse(const LLSD& queryMap);
 
-private:
-	std::string mFirstName;
-	std::string mLastName;
-	//LLUUID mWebLoginKey;
 };
 
 extern LLLoginHandler gLoginHandler;
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 24c72c65ce..bb45cc93ea 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -55,6 +55,7 @@
 #if LL_LINUX || LL_SOLARIS
 #include "lltrans.h"
 #endif
+#include "llsecapi.h"
 
 static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
 static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
@@ -83,14 +84,14 @@ LLLoginInstance::~LLLoginInstance()
 {
 }
 
-void LLLoginInstance::connect(const LLSD& credentials)
+void LLLoginInstance::connect(LLPointer<LLCredential> credentials)
 {
 	std::vector<std::string> uris;
-	LLViewerLogin::getInstance()->getLoginURIs(uris);
+	LLGridManager::getInstance()->getLoginURIs(uris);
 	connect(uris.front(), credentials);
 }
 
-void LLLoginInstance::connect(const std::string& uri, const LLSD& credentials)
+void LLLoginInstance::connect(const std::string& uri, LLPointer<LLCredential> credentials)
 {
 	mAttemptComplete = false; // Reset attempt complete at this point!
 	constructAuthParams(credentials);
@@ -102,7 +103,7 @@ void LLLoginInstance::reconnect()
 	// Sort of like connect, only using the pre-existing
 	// request params.
 	std::vector<std::string> uris;
-	LLViewerLogin::getInstance()->getLoginURIs(uris);
+	LLGridManager::getInstance()->getLoginURIs(uris);
 	mLoginModule->connect(uris.front(), mRequestData);
 }
 
@@ -118,7 +119,7 @@ LLSD LLLoginInstance::getResponse()
 	return mResponseData; 
 }
 
-void LLLoginInstance::constructAuthParams(const LLSD& credentials)
+void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credential)
 {
 	// Set up auth request options.
 //#define LL_MINIMIAL_REQUESTED_OPTIONS
@@ -155,20 +156,18 @@ void LLLoginInstance::constructAuthParams(const LLSD& credentials)
 		gSavedSettings.setBOOL("UseDebugMenus", TRUE);
 		requested_options.append("god-connect");
 	}
+	
+	// (re)initialize the request params with creds.
+	LLSD request_params = user_credential->getLoginParams();
 
 	char hashed_mac_string[MD5HEX_STR_SIZE];		/* Flawfinder: ignore */
 	LLMD5 hashed_mac;
-	hashed_mac.update( gMACAddress, MAC_ADDRESS_BYTES );
+	unsigned char MACAddress[MAC_ADDRESS_BYTES];
+	LLUUID::getNodeID(MACAddress);	
+	hashed_mac.update( MACAddress, MAC_ADDRESS_BYTES );
 	hashed_mac.finalize();
 	hashed_mac.hex_digest(hashed_mac_string);
-
-	// prepend "$1$" to the password to indicate its the md5'd version.
-	std::string dpasswd("$1$");
-	dpasswd.append(credentials["passwd"].asString());
-
-	// (re)initialize the request params with creds.
-	LLSD request_params(credentials);
-	request_params["passwd"] = dpasswd;
+	
 	request_params["start"] = construct_start_string();
 	request_params["skipoptional"] = mSkipOptionalUpdate;
 	request_params["agree_to_tos"] = false; // Always false here. Set true in 
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index c8704eddb4..44271bb75e 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -36,6 +36,7 @@
 #include "lleventdispatcher.h"
 #include <boost/scoped_ptr.hpp>
 #include <boost/function.hpp>
+#include "llsecapi.h"
 class LLLogin;
 class LLEventStream;
 class LLNotificationsInterface;
@@ -48,8 +49,8 @@ public:
 	LLLoginInstance();
 	~LLLoginInstance();
 
-	void connect(const LLSD& credential); // Connect to the current grid choice.
-	void connect(const std::string& uri, const LLSD& credential);	// Connect to the given uri.
+	void connect(LLPointer<LLCredential> credentials); // Connect to the current grid choice.
+	void connect(const std::string& uri, LLPointer<LLCredential> credentials);	// Connect to the given uri.
 	void reconnect(); // reconnect using the current credentials.
 	void disconnect();
 
@@ -81,7 +82,7 @@ public:
 	void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; }
 
 private:
-	void constructAuthParams(const LLSD& credentials); 
+	void constructAuthParams(LLPointer<LLCredential> user_credentials);
 	void updateApp(bool mandatory, const std::string& message);
 	bool updateDialogCallback(const LLSD& notification, const LLSD& response);
 
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 87d101b00f..6978d05389 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -51,6 +51,7 @@
 #include "llfocusmgr.h"
 #include "lllineeditor.h"
 #include "llnotificationsutil.h"
+#include "llsecapi.h"
 #include "llstartup.h"
 #include "lltextbox.h"
 #include "llui.h"
@@ -77,6 +78,7 @@
 #pragma warning(disable: 4355)      // 'this' used in initializer list
 #endif  // LL_WINDOWS
 
+#include "llsdserialize.h"
 #define USE_VIEWER_AUTH 0
 
 const S32 BLACK_BORDER_HEIGHT = 160;
@@ -187,6 +189,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 		delete LLPanelLogin::sInstance;
 	}
 
+	mPasswordModified = FALSE;
 	LLPanelLogin::sInstance = this;
 
 	// add to front so we are the bottom-most child
@@ -213,10 +216,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	}
 
 #if !USE_VIEWER_AUTH
-	childSetPrevalidate("first_name_edit", LLLineEditor::prevalidateASCIIPrintableNoSpace);
-	childSetPrevalidate("last_name_edit", LLLineEditor::prevalidateASCIIPrintableNoSpace);
-
-	childSetCommitCallback("password_edit", mungePassword, this);
+	childSetPrevalidate("username_edit", LLLineEditor::prevalidateASCIIPrintableNoPipe);
 	getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);
 
 	// change z sort of clickable text to be behind buttons
@@ -248,6 +248,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
 	server_choice_combo->setCommitCallback(onSelectServer, NULL);
 	server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
+	updateServerCombo();
 
 	childSetAction("connect_btn", onClickConnect, this);
 
@@ -303,12 +304,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 
 	// kick off a request to grab the url manually
 	gResponsePtr = LLIamHereLogin::build( this );
-	std::string login_page = gSavedSettings.getString("LoginPage");
-	if (login_page.empty())
-	{
-		login_page = getString( "real_url" );
-	}
-	LLHTTPClient::head( login_page, gResponsePtr );
+
+	LLHTTPClient::head( LLGridManager::getInstance()->getLoginPage(), gResponsePtr );
 
 #if !USE_VIEWER_AUTH
 	// Initialize visibility (and don't force visibility - use prefs)
@@ -377,21 +374,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )
 	}
 }
 
-void LLPanelLogin::mungePassword(LLUICtrl* caller, void* user_data)
-{
-	LLPanelLogin* self = (LLPanelLogin*)user_data;
-	LLLineEditor* editor = (LLLineEditor*)caller;
-	std::string password = editor->getText();
-
-	// Re-md5 if we've changed at all
-	if (password != self->mIncomingPassword)
-	{
-		LLMD5 pass((unsigned char *)password.c_str());
-		char munged_password[MD5HEX_STR_SIZE];
-		pass.hex_digest(munged_password);
-		self->mMungedPassword = munged_password;
-	}
-}
 
 LLPanelLogin::~LLPanelLogin()
 {
@@ -498,14 +480,14 @@ void LLPanelLogin::giveFocus()
 	if( sInstance )
 	{
 		// Grab focus and move cursor to first blank input field
-		std::string first = sInstance->childGetText("first_name_edit");
+		std::string username = sInstance->childGetText("username_edit");
 		std::string pass = sInstance->childGetText("password_edit");
 
-		BOOL have_first = !first.empty();
+		BOOL have_username = !username.empty();
 		BOOL have_pass = !pass.empty();
 
 		LLLineEditor* edit = NULL;
-		if (have_first && !have_pass)
+		if (have_username && !have_pass)
 		{
 			// User saved his name but not his password.  Move
 			// focus to password field.
@@ -514,7 +496,7 @@ void LLPanelLogin::giveFocus()
 		else
 		{
 			// User doesn't have a name, so start there.
-			edit = sInstance->getChild<LLLineEditor>("first_name_edit");
+			edit = sInstance->getChild<LLLineEditor>("username_edit");
 		}
 
 		if (edit)
@@ -559,77 +541,120 @@ void LLPanelLogin::show(const LLRect &rect,
 }
 
 // static
-void LLPanelLogin::setFields(const std::string& firstname,
-			     const std::string& lastname,
-			     const std::string& password)
+void LLPanelLogin::setFields(LLPointer<LLCredential> credential,
+							 BOOL remember)
 {
 	if (!sInstance)
 	{
 		llwarns << "Attempted fillFields with no login view shown" << llendl;
 		return;
 	}
+	LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL;
 
-	sInstance->childSetText("first_name_edit", firstname);
-	sInstance->childSetText("last_name_edit", lastname);
-
-	// Max "actual" password length is 16 characters.
-	// Hex digests are always 32 characters.
-	if (password.length() == 32)
+	LLSD identifier = credential->getIdentifier();
+	if((std::string)identifier["type"] == "agent") 
+	{
+		sInstance->childSetText("username_edit", (std::string)identifier["first_name"] + " " + 
+								(std::string)identifier["last_name"]);	
+	}
+	else if((std::string)identifier["type"] == "account")
+	{
+		sInstance->childSetText("username_edit", (std::string)identifier["account_name"]);		
+	}
+	else
+	{
+	  sInstance->childSetText("username_edit", std::string());	
+	}
+	// if the password exists in the credential, set the password field with
+	// a filler to get some stars
+	LLSD authenticator = credential->getAuthenticator();
+	LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL;
+	if(authenticator.isMap() && 
+	   authenticator.has("secret") && 
+	   (authenticator["secret"].asString().size() > 0))
 	{
+		
 		// This is a MD5 hex digest of a password.
 		// We don't actually use the password input field, 
 		// fill it with MAX_PASSWORD characters so we get a 
 		// nice row of asterixes.
 		const std::string filler("123456789!123456");
-		sInstance->childSetText("password_edit", filler);
-		sInstance->mIncomingPassword = filler;
-		sInstance->mMungedPassword = password;
+		sInstance->childSetText("password_edit", std::string("123456789!123456"));
 	}
 	else
 	{
-		// this is a normal text password
-		sInstance->childSetText("password_edit", password);
-		sInstance->mIncomingPassword = password;
-		LLMD5 pass((unsigned char *)password.c_str());
-		char munged_password[MD5HEX_STR_SIZE];
-		pass.hex_digest(munged_password);
-		sInstance->mMungedPassword = munged_password;
+		sInstance->childSetText("password_edit", std::string());		
 	}
+	sInstance->childSetValue("remember_check", remember);
 }
 
 
 // static
-void LLPanelLogin::addServer(const std::string& server, S32 domain_name)
+void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
+							 BOOL &remember)
 {
 	if (!sInstance)
 	{
-		llwarns << "Attempted addServer with no login view shown" << llendl;
+		llwarns << "Attempted getFields with no login view shown" << llendl;
 		return;
 	}
+	
+	// load the credential so we can pass back the stored password or hash if the user did
+	// not modify the password field.
+	
+	credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGridName());
 
-	LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
-	combo->add(server, LLSD(domain_name) );
-	combo->setCurrentByIndex(0);
-}
-
-// static
-void LLPanelLogin::getFields(std::string *firstname,
-			     std::string *lastname,
-			     std::string *password)
-{
-	if (!sInstance)
+	LLSD identifier = LLSD::emptyMap();
+	LLSD authenticator = LLSD::emptyMap();
+	
+	if(credential.notNull())
 	{
-		llwarns << "Attempted getFields with no login view shown" << llendl;
-		return;
+		authenticator = credential->getAuthenticator();
 	}
 
-	*firstname = sInstance->childGetText("first_name_edit");
-	LLStringUtil::trim(*firstname);
-
-	*lastname = sInstance->childGetText("last_name_edit");
-	LLStringUtil::trim(*lastname);
+	std::string username = sInstance->childGetText("username_edit");
+	LLStringUtil::trim(username);
+	std::string password = sInstance->childGetText("password_edit");
 
-	*password = sInstance->mMungedPassword;
+	LL_INFOS2("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL;
+	// determine if the username is a first/last form or not.
+	size_t separator_index = username.find_first_of(' ');
+	if (separator_index == username.npos)
+	{
+		LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL;
+		// single username, so this is a 'clear' identifier
+		identifier["type"] = "account";
+		identifier["account_name"] = username;
+		
+		if (LLPanelLogin::sInstance->mPasswordModified)
+		{
+			authenticator = LLSD::emptyMap();
+			// password is plaintext
+			authenticator["type"] = "clear";
+			authenticator["secret"] = password;
+		}
+	}
+	else if (separator_index == username.find_last_of(' '))
+	{
+		LL_INFOS2("Credentials", "Authentication") << "agent: " << username << LL_ENDL;
+		// traditional firstname / lastname
+		identifier["type"] = "agent";
+		identifier["first_name"] = username.substr(0, separator_index);
+		identifier["last_name"] = username.substr(separator_index+1, username.npos);
+		
+		if (LLPanelLogin::sInstance->mPasswordModified)
+		{
+			authenticator = LLSD::emptyMap();
+			authenticator["type"] = "hash";
+			authenticator["algorithm"] = "md5";
+			LLMD5 pass((const U8 *)password.c_str());
+			char md5pass[33];               /* Flawfinder: ignore */
+			pass.hex_digest(md5pass);
+			authenticator["secret"] = md5pass;
+		}
+	}
+	credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGridName(), identifier, authenticator);
+	remember = sInstance->childGetValue("remember_check");
 }
 
 // static
@@ -682,6 +707,7 @@ void LLPanelLogin::refreshLocation( bool force_visible )
 	sInstance->childSetVisible("start_location_combo", show_start);
 	sInstance->childSetVisible("start_location_text", show_start);
 
+	// should be true for enterprise viewer
 	BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid");
 	sInstance->childSetVisible("server_combo", show_server);
 
@@ -721,15 +747,12 @@ void LLPanelLogin::loadLoginPage()
 	
 	std::ostringstream oStr;
 
-	std::string login_page = gSavedSettings.getString("LoginPage");
-	if (login_page.empty())
-	{
-		login_page = sInstance->getString( "real_url" );
-	}
+	std::string login_page = LLGridManager::getInstance()->getLoginPage();
 	oStr << login_page;
 	
 	// Use the right delimeter depending on how LLURI parses the URL
 	LLURI login_page_uri = LLURI(login_page);
+	
 	std::string first_query_delimiter = "&";
 	if (login_page_uri.queryMap().size() == 0)
 	{
@@ -761,11 +784,10 @@ void LLPanelLogin::loadLoginPage()
 	curl_free(curl_version);
 
 	// Grid
-	char* curl_grid = curl_escape(LLViewerLogin::getInstance()->getGridLabel().c_str(), 0);
+	char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLabel().c_str(), 0);
 	oStr << "&grid=" << curl_grid;
 	curl_free(curl_grid);
-
-	gViewerWindow->setMenuBackgroundColor(false, !LLViewerLogin::getInstance()->isInProductionGrid());
+	gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
 	gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor());
 
 
@@ -790,30 +812,20 @@ void LLPanelLogin::loadLoginPage()
 		location = gSavedSettings.getString("LoginLocation");
 	}
 	
-	std::string firstname, lastname;
+	std::string username;
 
     if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)
     {
         LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
-		firstname = cmd_line_login[0].asString();
-		lastname = cmd_line_login[1].asString();
+		username = cmd_line_login[0].asString() + " " + cmd_line_login[1];
         password = cmd_line_login[2].asString();
     }
     	
-	if (firstname.empty())
-	{
-		firstname = gSavedSettings.getString("FirstName");
-	}
-	
-	if (lastname.empty())
-	{
-		lastname = gSavedSettings.getString("LastName");
-	}
 	
 	char* curl_region = curl_escape(region.c_str(), 0);
 
-	oStr <<"firstname=" << firstname <<
-		"&lastname=" << lastname << "&location=" << location <<	"&region=" << curl_region;
+	oStr <<"username=" << username <<
+		 "&location=" << location <<	"&region=" << curl_region;
 	
 	curl_free(curl_region);
 
@@ -896,34 +908,33 @@ void LLPanelLogin::onClickConnect(void *)
 		// JC - Make sure the fields all get committed.
 		sInstance->setFocus(FALSE);
 
-		std::string first = sInstance->childGetText("first_name_edit");
-		std::string last  = sInstance->childGetText("last_name_edit");
-		LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
-		std::string combo_text = combo->getSimple();
-		
-		bool has_first_and_last = !(first.empty() || last.empty());
-		bool has_location = false;
-
-		if(combo_text=="<Type region name>" || combo_text =="")
+		LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
+		LLSD combo_val = combo->getSelectedValue();
+		if (combo_val.isUndefined())
 		{
-			// *NOTE: Mani - Location field is not always committed by this point!
-			// This may be duplicate work, but better than not doing the work!
-			LLURLSimString::sInstance.setString("");
+			combo_val = combo->getValue();
 		}
-		else 
+		if(combo_val.isUndefined())
+		{
+			LLNotificationsUtil::add("StartRegionEmpty");
+			return;
+		}		
+		try
 		{
-			// *NOTE: Mani - Location field is not always committed by this point!
-			LLURLSimString::sInstance.setString(combo_text);
-			has_location = true;
+			LLGridManager::getInstance()->setGridChoice(combo_val.asString());
 		}
-
-		if(!has_first_and_last)
+		catch (LLInvalidGridName ex)
 		{
-			LLNotificationsUtil::add("MustHaveAccountToLogIn");
+			LLSD args;
+			args["GRID"] = combo_val.asString();
+			LLNotificationsUtil::add("InvalidGrid", args);
+			return;
 		}
-		else if(!has_location)
+		
+		std::string username = sInstance->childGetText("username_edit");
+		if(username.empty())
 		{
-			LLNotificationsUtil::add("StartRegionEmpty");
+			LLNotificationsUtil::add("MustHaveAccountToLogIn");
 		}
 		else
 		{
@@ -986,6 +997,8 @@ void LLPanelLogin::onClickHelp(void*)
 // static
 void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
 {
+	LLPanelLogin *This = (LLPanelLogin *) user_data;
+	This->mPasswordModified = TRUE;
 	if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
 	{
 		LLNotificationsUtil::add("CapsKeyOn");
@@ -993,6 +1006,34 @@ void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
 	}
 }
 
+void LLPanelLogin::updateServerCombo()
+{
+	// We add all of the possible values, sorted, and then add a bar and the current value at the top
+	LLGridManager* viewer_login = LLGridManager::getInstance();
+	LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");	
+	server_choice_combo->removeall();
+	std::map<std::string, std::string> known_grids = viewer_login->getKnownGrids();
+	for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
+		 grid_choice != known_grids.end();
+		 grid_choice++)
+		{
+			//if (!grid_choice->first.empty())
+			{
+				LL_INFOS("Credentials") << "adding " << grid_choice->second << ":" << grid_choice->first << LL_ENDL;
+				server_choice_combo->add(grid_choice->second, grid_choice->first, ADD_SORTED);
+			}
+		}
+	
+	server_choice_combo->addSeparator(ADD_TOP);
+	
+	LL_INFOS("Credentials") << "adding top grid choice by " << viewer_login->getGridLabel() << LL_ENDL;
+	server_choice_combo->add(viewer_login->getGridLabel(), 
+							 viewer_login->getGridName(), 
+							 ADD_TOP);	
+	
+	server_choice_combo->selectFirstItem();	
+}
+
 // static
 void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
 {
@@ -1002,45 +1043,34 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
 
 	// The user twiddled with the grid choice ui.
 	// apply the selection to the grid setting.
-	std::string grid_label;
-	S32 grid_index;
+	LLPointer<LLCredential> credential;
+	BOOL remember = FALSE;
 
 	LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
-	LLSD combo_val = combo->getValue();
-
-	if (LLSD::TypeInteger == combo_val.type())
-	{
-		grid_index = combo->getValue().asInteger();
-
-		if ((S32)GRID_INFO_OTHER == grid_index)
-		{
-			// This happens if the user specifies a custom grid
-			// via command line.
-			grid_label = combo->getSimple();
-		}
-	}
-	else
+	LLSD combo_val = combo->getSelectedValue();
+	if (combo_val.isUndefined())
 	{
-		// no valid selection, return other
-		grid_index = (S32)GRID_INFO_OTHER;
-		grid_label = combo_val.asString();
+	  combo_val = combo->getValue();
 	}
 
-	// This new seelction will override preset uris
+	// This new selection will override preset uris
 	// from the command line.
-	LLViewerLogin* vl = LLViewerLogin::getInstance();
-	vl->resetURIs();
-	if(grid_index != GRID_INFO_OTHER)
-	{
-		vl->setGridChoice((EGridInfo)grid_index);
-	}
-	else
-	{
-		vl->setGridChoice(grid_label);
-	}
+
+	LLGridManager::getInstance()->setGridChoice(combo_val.asString());
+	updateServerCombo();
 
 	// grid changed so show new splash screen (possibly)
 	loadLoginPage();
+	
+	// if they've selected another grid, we should load the credentials
+	// for that grid and set them to the UI.
+	credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGridName());
+	
+
+	remember = sInstance->childGetValue("remember_check");
+	sInstance->setFields(credential, remember);
+
+	LL_INFOS("Credentials") << "Grid changed to:" << LLGridManager::getInstance()->getGridName() << LL_ENDL;
 }
 
 void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index 97350ce5c7..d33aa2d550 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -37,6 +37,7 @@
 #include "llpointer.h"			// LLPointer<>
 #include "llmediactrl.h"	// LLMediaCtrlObserver
 #include <boost/scoped_ptr.hpp>
+#include "llsecapi.h"
 
 class LLLineEditor;
 class LLUIImage;
@@ -65,15 +66,11 @@ public:
 		void (*callback)(S32 option, void* user_data), 
 		void* callback_data);
 
-	// Remember password checkbox is set via gSavedSettings "RememberPassword"
-	static void setFields(const std::string& firstname, const std::string& lastname, 
-		const std::string& password);
+	static void setFields(LLPointer<LLCredential> credential, BOOL remember);
 
-	static void addServer(const std::string& server, S32 domain_name);
 	static void refreshLocation( bool force_visible );
 
-	static void getFields(std::string *firstname, std::string *lastname,
-						  std::string *password);
+	static void getFields(LLPointer<LLCredential>& credential, BOOL& remember);
 
 	static BOOL isGridComboDirty();
 	static void getLocation(std::string &location);
@@ -85,7 +82,6 @@ public:
 	static void loadLoginPage();	
 	static void giveFocus();
 	static void setAlwaysRefresh(bool refresh); 
-	static void mungePassword(LLUICtrl* caller, void* user_data);
 	
 	// inherited from LLViewerMediaObserver
 	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
@@ -102,6 +98,7 @@ private:
 	static void onPassKey(LLLineEditor* caller, void* user_data);
 	static void onSelectServer(LLUICtrl*, void*);
 	static void onServerComboLostFocus(LLFocusableElement*);
+	static void updateServerCombo();
 	
 private:
 	LLPointer<LLUIImage> mLogoImage;
@@ -110,8 +107,7 @@ private:
 	void			(*mCallback)(S32 option, void *userdata);
 	void*			mCallbackData;
 
-	std::string mIncomingPassword;
-	std::string mMungedPassword;
+	BOOL            mPasswordModified;
 
 	static LLPanelLogin* sInstance;
 	static BOOL		sCapslockDidNotification;
diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp
index c2cfde0dc7..cdf4a3fe01 100644
--- a/indra/newview/llsecapi.cpp
+++ b/indra/newview/llsecapi.cpp
@@ -38,11 +38,17 @@
 
 
 std::map<std::string, LLPointer<LLSecAPIHandler> > gHandlerMap;
-
+LLPointer<LLSecAPIHandler> gSecAPIHandler;
 
 void initializeSecHandler()
 {
 	gHandlerMap[BASIC_SECHANDLER] = new LLSecAPIBasicHandler();
+	
+	// Currently, we only have the Basic handler, so we can point the main sechandler
+	// pointer to the basic handler.  Later, we'll create a wrapper handler that
+	// selects the appropriate sechandler as needed, for instance choosing the
+	// mac keyring handler, with fallback to the basic sechandler
+	gSecAPIHandler = gHandlerMap[BASIC_SECHANDLER];
 }
 // start using a given security api handler.  If the string is empty
 // the default is used
@@ -64,6 +70,28 @@ void registerSecHandler(const std::string& handler_type,
 	gHandlerMap[handler_type] = handler;
 }
 
+std::ostream& operator <<(std::ostream& s, const LLCredential& cred)
+{
+	return s << (std::string)cred;
+}
 
 
-
+LLSD LLCredential::getLoginParams()
+{
+	LLSD result = LLSD::emptyMap();
+	if (mIdentifier["type"].asString() == "agent")
+	{
+		// legacy credential
+		result["passwd"] = "$1$" + mAuthenticator["secret"].asString();
+		result["first"] = mIdentifier["first_name"];
+		result["last"] = mIdentifier["last_name"];
+	
+	}
+	else if (mIdentifier["type"].asString() == "account")
+	{
+		result["username"] = mIdentifier["username"];
+		result["passwd"] = mAuthenticator["secret"];
+                                    
+	}
+	return result;
+}
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index 743d3d6770..d456ca95b1 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -34,6 +34,7 @@
 #define LLSECAPI_H
 #include <vector>
 #include <openssl/x509.h>
+#include <ostream>
 
 // All error handling is via exceptions.
 
@@ -156,7 +157,7 @@ public:
 	LLCertificateStore() {}
 	virtual ~LLCertificateStore() {}
 	
-	virtual X509_STORE getOpenSSLX509Store()=0;  // return an openssl X509_STORE  
+	virtual X509_STORE* getOpenSSLX509Store()=0;  // return an openssl X509_STORE  
 	// for this store
 	
 	// add a copy of a cert to the store
@@ -169,7 +170,8 @@ public:
 	virtual void remove(int index)=0;
 	
 	// return a certificate at the index
-	virtual LLPointer<LLCertificate>& operator[](int index)=0;
+	virtual LLPointer<LLCertificate> operator[](int index)=0;
+	
 	// return the number of certs in the store
 	virtual int len() const =0;
 	
@@ -186,6 +188,49 @@ public:
 	virtual bool validate(const LLCertificateChain& cert_chain) const=0;
 };
 
+//
+// LLCredential - interface for credentials providing the following functionality:
+// * persistance of credential information based on grid (for saving username/password)
+// * serialization to an OGP identifier/authenticator pair
+// 
+class LLCredential  : public LLRefCount
+{
+public:
+	
+	LLCredential() {}
+	
+	LLCredential(const std::string& grid)
+	{
+		mGrid = grid;
+		mIdentifier = LLSD::emptyMap();
+		mAuthenticator = LLSD::emptyMap();
+	}
+	
+	virtual ~LLCredential() {}
+	
+	virtual void setCredentialData(const LLSD& identifier, const LLSD& authenticator) 
+	{ 
+		mIdentifier = identifier;
+		mAuthenticator = authenticator;
+	}
+	virtual LLSD getIdentifier() { return mIdentifier; }
+	virtual LLSD getAuthenticator() { return mAuthenticator; }
+	virtual LLSD getLoginParams();
+	virtual std::string getGrid() { return mGrid; }
+	
+
+	virtual void clearAuthenticator() { mAuthenticator = LLSD(); } 
+	virtual std::string userID() const { return std::string("unknown");}
+	virtual std::string asString() const { return std::string("unknown");}
+	operator std::string() const { return asString(); }
+protected:
+	LLSD mIdentifier;
+	LLSD mAuthenticator;
+	std::string mGrid;
+};
+
+std::ostream& operator <<(std::ostream& s, const LLCredential& cred);
+
 
 // LLSecAPIHandler Class
 // Interface handler class for the various security storage handlers.
@@ -219,9 +264,24 @@ public:
 	// retrieve protected data
 	virtual LLSD getProtectedData(const std::string& data_type,
 								  const std::string& data_id)=0;
+	
+	// delete a protected data item from the store
+	virtual void deleteProtectedData(const std::string& data_type,
+									 const std::string& data_id)=0;
+	
+	virtual LLPointer<LLCredential> createCredential(const std::string& grid,
+													 const LLSD& identifier, 
+													 const LLSD& authenticator)=0;
+	
+	virtual LLPointer<LLCredential> loadCredential(const std::string& grid)=0;
+	
+	virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)=0;
+	
+	virtual void deleteCredential(LLPointer<LLCredential> cred)=0;
+	
 };
 
-void secHandlerInitialize();
+void initializeSecHandler();
 				
 // retrieve a security api depending on the api type
 LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type);
@@ -229,4 +289,6 @@ LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type);
 void registerSecHandler(const std::string& handler_type, 
 						LLPointer<LLSecAPIHandler>& handler);
 
+extern LLPointer<LLSecAPIHandler> gSecAPIHandler;
+
 #endif // LL_SECAPI_H
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index ab6bf034f1..4180f578b9 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -35,8 +35,11 @@
 #include "llsecapi.h"
 #include "llsechandler_basic.h"
 #include "llsdserialize.h"
+#include "llviewernetwork.h"
+#include "llxorcipher.h"
 #include "llfile.h"
 #include "lldir.h"
+#include "llviewercontrol.h"
 #include <vector>
 #include <ios>
 #include <openssl/x509.h>
@@ -276,22 +279,94 @@ std::string cert_get_digest(const std::string& digest_type, X509 *cert)
 }
 
 
+//
+// LLBasicCertificateStore
+// 
+LLBasicCertificateStore::LLBasicCertificateStore(const std::string& filename)
+{
+}
+LLBasicCertificateStore::LLBasicCertificateStore(const X509_STORE* store)
+{
+}
+
+LLBasicCertificateStore::~LLBasicCertificateStore()
+{
+}
+
+		
+X509_STORE* LLBasicCertificateStore::getOpenSSLX509Store()
+{
+	return NULL;
+}
+		
+		// add a copy of a cert to the store
+void  LLBasicCertificateStore::append(const LLCertificate& cert)
+{
+}
+		
+		// add a copy of a cert to the store
+void LLBasicCertificateStore::insert(const int index, const LLCertificate& cert)
+{
+}
+		
+		// remove a certificate from the store
+void LLBasicCertificateStore::remove(int index)
+{
+}
+		
+		// return a certificate at the index
+LLPointer<LLCertificate> LLBasicCertificateStore::operator[](int index)
+{
+	LLPointer<LLCertificate> result = NULL;
+	return result;
+}
+		// return the number of certs in the store
+int LLBasicCertificateStore::len() const
+{
+	return 0;
+}
+		
+		// load the store from a persisted location
+void LLBasicCertificateStore::load(const std::string& store_id)
+{
+}
+		
+		// persist the store
+void LLBasicCertificateStore::save()
+{
+}
+		
+		// return the store id
+std::string LLBasicCertificateStore::storeId()
+{
+	return std::string("");
+}
+		
+		// validate a cert chain
+bool LLBasicCertificateStore::validate(const LLCertificateChain& cert_chain) const
+{
+	return FALSE;
+}
+
 // LLSecAPIBasicHandler Class
 // Interface handler class for the various security storage handlers.
 
 // We read the file on construction, and write it on destruction.  This
 // means multiple processes cannot modify the datastore.
-LLSecAPIBasicHandler::LLSecAPIBasicHandler(const std::string& protected_data_file)
+LLSecAPIBasicHandler::LLSecAPIBasicHandler(const std::string& protected_data_file,
+										   const std::string& legacy_password_path)
 {
 	mProtectedDataFilename = protected_data_file;
 	mProtectedDataMap = LLSD::emptyMap();
+	mLegacyPasswordPath = legacy_password_path;
 	_readProtectedData();
 }
 
 LLSecAPIBasicHandler::LLSecAPIBasicHandler()
 {
-	std::string mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
-														  "bin_conf.dat");
+	mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
+															"bin_conf.dat");
+	mLegacyPasswordPath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "password.dat");
 
 	mProtectedDataMap = LLSD::emptyMap();
 	_readProtectedData();
@@ -306,7 +381,6 @@ void LLSecAPIBasicHandler::_readProtectedData()
 {	
 	// attempt to load the file into our map
 	LLPointer<LLSDParser> parser = new LLSDXMLParser();
-	
 	llifstream protected_data_stream(mProtectedDataFilename.c_str(), 
 									llifstream::binary);
 	if (!protected_data_stream.fail()) {
@@ -314,21 +388,27 @@ void LLSecAPIBasicHandler::_readProtectedData()
 		U8 salt[STORE_SALT_SIZE];
 		U8 buffer[BUFFER_READ_SIZE];
 		U8 decrypted_buffer[BUFFER_READ_SIZE];
-		int decrypted_length;		
-		
+		int decrypted_length;	
+		unsigned char MACAddress[MAC_ADDRESS_BYTES];
+		LLUUID::getNodeID(MACAddress);
+		LLXORCipher cipher(MACAddress, MAC_ADDRESS_BYTES);
 
 		// read in the salt and key
 		protected_data_stream.read((char *)salt, STORE_SALT_SIZE);
 		offset = 0;
 		if (protected_data_stream.gcount() < STORE_SALT_SIZE)
 		{
-			throw LLProtectedDataException("Corrupt Protected Data Store");
+			throw LLProtectedDataException("Corrupt Protected Data Store1");
 		}
-		
+
+		cipher.decrypt(salt, STORE_SALT_SIZE);		
+
 		// totally lame.  As we're not using the OS level protected data, we need to
 		// at least obfuscate the data.  We do this by using a salt stored at the head of the file
 		// to encrypt the data, therefore obfuscating it from someone using simple existing tools.
-		// It would be better to use the password, but as this store
+		// We do include the MAC address as part of the obfuscation, which would require an
+		// attacker to get the MAC address as well as the protected store, which improves things
+		// somewhat.  It would be better to use the password, but as this store
 		// will be used to store the SL password when the user decides to have SL remember it, 
 		// so we can't use that.  OS-dependent store implementations will use the OS password/storage 
 		// mechanisms and are considered to be more secure.
@@ -369,6 +449,7 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 	U8 salt[STORE_SALT_SIZE];
 	U8 buffer[BUFFER_READ_SIZE];
 	U8 encrypted_buffer[BUFFER_READ_SIZE];
+
 	
 	if(mProtectedDataMap.isUndefined())
 	{
@@ -377,10 +458,10 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 	}
 	// create a string with the formatted data.
 	LLSDSerialize::toXML(mProtectedDataMap, formatted_data_ostream);
-	
 	std::istringstream formatted_data_istream(formatted_data_ostream.str());
 	// generate the seed
 	RAND_bytes(salt, STORE_SALT_SIZE);
+
 	
 	// write to a temp file so we don't clobber the initial file if there is
 	// an error.
@@ -394,7 +475,12 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 		EVP_CIPHER_CTX ctx;
 		EVP_CIPHER_CTX_init(&ctx);
 		EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL);
-		protected_data_stream.write((const char *)salt, STORE_SALT_SIZE);	
+		unsigned char MACAddress[MAC_ADDRESS_BYTES];
+		LLUUID::getNodeID(MACAddress);
+		LLXORCipher cipher(MACAddress, MAC_ADDRESS_BYTES);
+		cipher.encrypt(salt, STORE_SALT_SIZE);
+		protected_data_stream.write((const char *)salt, STORE_SALT_SIZE);
+
 		while (formatted_data_istream.good())
 		{
 			formatted_data_istream.read((char *)buffer, BUFFER_READ_SIZE);
@@ -423,7 +509,8 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 	}
 
 	// move the temporary file to the specified file location.
-	if((LLFile::remove(mProtectedDataFilename) != 0) || 
+	if((((LLFile::isfile(mProtectedDataFilename) != 0) && 
+		 (LLFile::remove(mProtectedDataFilename) != 0))) || 
 	   (LLFile::rename(tmp_filename, mProtectedDataFilename)))
 	{
 		LLFile::remove(tmp_filename);
@@ -477,14 +564,181 @@ LLSD LLSecAPIBasicHandler::getProtectedData(const std::string& data_type,
 	return LLSD();
 }
 
+void LLSecAPIBasicHandler::deleteProtectedData(const std::string& data_type,
+											   const std::string& data_id)
+{
+	if (mProtectedDataMap.has(data_type) &&
+		mProtectedDataMap[data_type].isMap() &&
+		mProtectedDataMap[data_type].has(data_id))
+		{
+			mProtectedDataMap[data_type].erase(data_id);
+		}
+}
+
+
+//
 // persist data in a protected store
+//
 void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type,
-									  const std::string& data_id,
-									  const LLSD& data)
+											const std::string& data_id,
+											const LLSD& data)
 {
 	if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) {
 		mProtectedDataMap[data_type] = LLSD::emptyMap();
 	}
 	
 	mProtectedDataMap[data_type][data_id] = data; 
-}
\ No newline at end of file
+}
+
+//
+// Create a credential object from an identifier and authenticator.  credentials are
+// per grid.
+LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string& grid,
+															   const LLSD& identifier, 
+															   const LLSD& authenticator)
+{
+	LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid);
+	result->setCredentialData(identifier, authenticator);
+	return result;
+}
+
+// Load a credential from the credential store, given the grid
+LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid)
+{
+	LLSD credential = getProtectedData("credential", grid);
+	LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid);
+	if(credential.isMap() && 
+	   credential.has("identifier"))
+	{
+
+		LLSD identifier = credential["identifier"];
+		LLSD authenticator;
+		if (credential.has("authenticator"))
+		{
+			authenticator = credential["authenticator"];
+		}
+		result->setCredentialData(identifier, authenticator);
+	}
+	else
+	{
+		// credential was not in protected storage, so pull the credential
+		// from the legacy store.
+		std::string first_name = gSavedSettings.getString("FirstName");
+		std::string last_name = gSavedSettings.getString("LastName");
+		
+		if ((first_name != "") &&
+			(last_name != ""))
+		{
+			LLSD identifier = LLSD::emptyMap();
+			LLSD authenticator;
+			identifier["type"] = "agent";
+			identifier["first_name"] = first_name;
+			identifier["last_name"] = last_name;
+			
+			std::string legacy_password = _legacyLoadPassword();
+			if (legacy_password.length() > 0)
+			{
+				authenticator = LLSD::emptyMap();
+				authenticator["type"] = "hash";
+				authenticator["algorithm"] = "md5";
+				authenticator["secret"] = legacy_password;
+			}
+			result->setCredentialData(identifier, authenticator);
+		}		
+	}
+	return result;
+}
+
+// Save the credential to the credential store.  Save the authenticator also if requested.
+// That feature is used to implement the 'remember password' functionality.
+void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)
+{
+	LLSD credential = LLSD::emptyMap();
+	credential["identifier"] = cred->getIdentifier(); 
+	if (save_authenticator) 
+	{
+		credential["authenticator"] = cred->getAuthenticator();
+	}
+	LL_INFOS("Credentials") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL;
+	setProtectedData("credential", cred->getGrid(), credential);
+	//*TODO: If we're saving Agni credentials, should we write the
+	// credentials to the legacy password.dat/etc?
+}
+
+// Remove a credential from the credential store.
+void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred)
+{
+	LLSD undefVal;
+	deleteProtectedData("credential", cred->getGrid());
+	cred->setCredentialData(undefVal, undefVal);
+}
+
+// load the legacy hash for agni, and decrypt it given the 
+// mac address
+std::string LLSecAPIBasicHandler::_legacyLoadPassword()
+{
+	const S32 HASHED_LENGTH = 32;	
+	std::vector<U8> buffer(HASHED_LENGTH);
+	llifstream password_file(mLegacyPasswordPath, llifstream::binary);
+	
+	if(password_file.fail())
+	{
+		return std::string("");
+	}
+	
+	password_file.read((char*)&buffer[0], buffer.size());
+	if(password_file.gcount() != buffer.size())
+	{
+		return std::string("");
+	}
+	
+	// Decipher with MAC address
+	unsigned char MACAddress[MAC_ADDRESS_BYTES];
+	LLUUID::getNodeID(MACAddress);
+	LLXORCipher cipher(MACAddress, 6);
+	cipher.decrypt(&buffer[0], buffer.size());
+	
+	return std::string((const char*)&buffer[0], buffer.size());
+}
+
+
+// return an identifier for the user
+std::string LLSecAPIBasicCredential::userID() const
+{
+	if (!mIdentifier.isMap())
+	{
+		return mGrid + "(null)";
+	}
+	else if ((std::string)mIdentifier["type"] == "agent")
+	{
+		return  (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"];
+	}
+	else if ((std::string)mIdentifier["type"] == "account")
+	{
+		return (std::string)mIdentifier["account_name"];
+	}
+
+	return "unknown";
+
+}
+
+// return a printable user identifier
+std::string LLSecAPIBasicCredential::asString() const
+{
+	if (!mIdentifier.isMap())
+	{
+		return mGrid + ":(null)";
+	}
+	else if ((std::string)mIdentifier["type"] == "agent")
+	{
+		return mGrid + ":" + (std::string)mIdentifier["first_name"] + " " + (std::string)mIdentifier["last_name"];
+	}
+	else if ((std::string)mIdentifier["type"] == "account")
+	{
+		return mGrid + ":" + (std::string)mIdentifier["account_name"];
+	}
+
+	return mGrid + ":(unknown type)";
+}
+
+
diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h
index 0ec6938583..5d81b6e190 100644
--- a/indra/newview/llsechandler_basic.h
+++ b/indra/newview/llsechandler_basic.h
@@ -68,13 +68,69 @@ protected:
 	X509* mCert;
 };
 
+// class LLCertificateStore
+// represents a store of certificates, typically a store of root CA
+// certificates.  The store can be persisted, and can be used to validate
+// a cert chain
+//
+class LLBasicCertificateStore : public LLCertificateStore
+{
+public:
+	LLBasicCertificateStore(const std::string& filename);
+	LLBasicCertificateStore(const X509_STORE* store);
+	virtual ~LLBasicCertificateStore();
+	
+	virtual X509_STORE* getOpenSSLX509Store();  // return an openssl X509_STORE  
+	// for this store
+	
+	// add a copy of a cert to the store
+	virtual void  append(const LLCertificate& cert);
+	
+	// add a copy of a cert to the store
+	virtual void insert(const int index, const LLCertificate& cert);
+	
+	// remove a certificate from the store
+	virtual void remove(int index);
+	
+	// return a certificate at the index
+	virtual LLPointer<LLCertificate> operator[](int index);
+	// return the number of certs in the store
+	virtual int len() const;
+	
+	// load the store from a persisted location
+	virtual void load(const std::string& store_id);
+	
+	// persist the store
+	virtual void save();
+	
+	// return the store id
+	virtual std::string storeId();
+	
+	// validate a cert chain
+	virtual bool validate(const LLCertificateChain& cert_chain) const;
+};
+
+// LLSecAPIBasicCredential class
+class LLSecAPIBasicCredential : public LLCredential
+{
+public:
+	LLSecAPIBasicCredential(const std::string& grid) : LLCredential(grid) {} 
+	virtual ~LLSecAPIBasicCredential() {}
+	// return a value representing the user id, (could be guid, name, whatever)
+	virtual std::string userID() const;	
+	
+	// printible string identifying the credential.
+	virtual std::string asString() const;
+};
+
 // LLSecAPIBasicHandler Class
 // Interface handler class for the various security storage handlers.
 class LLSecAPIBasicHandler : public LLSecAPIHandler
 {
 public:
 	
-	LLSecAPIBasicHandler(const std::string& protected_data_filename);
+	LLSecAPIBasicHandler(const std::string& protected_data_filename,
+						 const std::string& legacy_password_path);
 	LLSecAPIBasicHandler();
 	
 	virtual ~LLSecAPIBasicHandler();
@@ -102,12 +158,32 @@ public:
 	// retrieve protected data
 	virtual LLSD getProtectedData(const std::string& data_type,
 								  const std::string& data_id);
+	
+	// delete a protected data item from the store
+	virtual void deleteProtectedData(const std::string& data_type,
+									 const std::string& data_id);
+	
+	// credential management routines
+	
+	virtual LLPointer<LLCredential> createCredential(const std::string& grid,
+													 const LLSD& identifier, 
+													 const LLSD& authenticator);
+	
+	virtual LLPointer<LLCredential> loadCredential(const std::string& grid);
+
+	virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator);
+	
+	virtual void deleteCredential(LLPointer<LLCredential> cred);
+	
 protected:
 	void _readProtectedData();
 	void _writeProtectedData();
-	
+	std::string _legacyLoadPassword();
+
 	std::string mProtectedDataFilename;
 	LLSD mProtectedDataMap;
+	
+	std::string mLegacyPasswordPath;
 };
 
 #endif // LLSECHANDLER_BASIC
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 99fa271b78..dd991c8eff 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -230,10 +230,9 @@ static bool gUseCircuitCallbackCalled = false;
 
 EStartupState LLStartUp::gStartupState = STATE_FIRST;
 
-// *NOTE:Mani - to reconcile with giab changes...
-static std::string gFirstname;
-static std::string gLastname;
-static std::string gPassword;
+static LLPointer<LLCredential> gUserCredential;
+static std::string gDisplayName;
+static BOOL gRememberPassword = TRUE;     
 
 static U64 gFirstSimHandle = 0;
 static LLHost gFirstSim;
@@ -250,7 +249,6 @@ boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener(
 
 void login_show();
 void login_callback(S32 option, void* userdata);
-bool is_hex_string(U8* str, S32 len);
 void show_first_run_dialog();
 bool first_run_dialog_callback(const LLSD& notification, const LLSD& response);
 void set_startup_status(const F32 frac, const std::string& string, const std::string& msg);
@@ -716,69 +714,25 @@ bool idle_startup()
 		//
 		// Log on to system
 		//
-		if (!LLStartUp::sSLURLCommand.empty())
-		{
-			// this might be a secondlife:///app/login URL
-			gLoginHandler.parseDirectLogin(LLStartUp::sSLURLCommand);
-		}
-		if (!gLoginHandler.getFirstName().empty()
-			|| !gLoginHandler.getLastName().empty()
-			/*|| !gLoginHandler.getWebLoginKey().isNull()*/ )
-		{
-			// We have at least some login information on a SLURL
-			gFirstname = gLoginHandler.getFirstName();
-			gLastname = gLoginHandler.getLastName();
-			LL_DEBUGS("LLStartup") << "STATE_FIRST: setting gFirstname, gLastname from gLoginHandler: '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
-
-			// Show the login screen if we don't have everything
-			show_connect_box = 
-				gFirstname.empty() || gLastname.empty();
-		}
-        else if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)
-        {
-            LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
-			gFirstname = cmd_line_login[0].asString();
-			gLastname = cmd_line_login[1].asString();
-			LL_DEBUGS("LLStartup") << "Setting gFirstname, gLastname from gSavedSettings(\"UserLoginInfo\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
-
-			LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str());
-			char md5pass[33];               /* Flawfinder: ignore */
-			pass.hex_digest(md5pass);
-			gPassword = md5pass;
-			
-#ifdef USE_VIEWER_AUTH
-			show_connect_box = true;
-#else
-			show_connect_box = false;
-#endif
-			gSavedSettings.setBOOL("AutoLogin", TRUE);
-        }
-		else if (gSavedSettings.getBOOL("AutoLogin"))
-		{
-			gFirstname = gSavedSettings.getString("FirstName");
-			gLastname = gSavedSettings.getString("LastName");
-			LL_DEBUGS("LLStartup") << "AutoLogin: setting gFirstname, gLastname from gSavedSettings(\"First|LastName\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
-			gPassword = LLStartUp::loadPasswordFromDisk();
-			gSavedSettings.setBOOL("RememberPassword", TRUE);
-			
-#ifdef USE_VIEWER_AUTH
-			show_connect_box = true;
-#else
-			show_connect_box = false;
-#endif
+		if (gUserCredential.isNull())
+		{
+			gUserCredential = gLoginHandler.initializeLoginInfo(LLStartUp::sSLURLCommand);
 		}
-		else
+		if (gUserCredential.isNull())
 		{
-			// if not automatically logging in, display login dialog
-			// a valid grid is selected
-			gFirstname = gSavedSettings.getString("FirstName");
-			gLastname = gSavedSettings.getString("LastName");
-			LL_DEBUGS("LLStartup") << "normal login: setting gFirstname, gLastname from gSavedSettings(\"First|LastName\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
-			gPassword = LLStartUp::loadPasswordFromDisk();
-			show_connect_box = true;
+			show_connect_box = TRUE;
+		}
+		else if (gSavedSettings.getBOOL("AutoLogin"))  
+		{
+			gRememberPassword = TRUE;
+			gSavedSettings.setBOOL("RememberPassword", TRUE);                                                      
+			show_connect_box = false;    			
+		}
+		else 
+		{
+			gRememberPassword = gSavedSettings.getBOOL("RememberPassword");
+			show_connect_box = TRUE;
 		}
-
-
 		// Go to the next startup state
 		LLStartUp::setStartupState( STATE_BROWSER_INIT );
 		return FALSE;
@@ -810,8 +764,10 @@ bool idle_startup()
 			// Load all the name information out of the login view
 			// NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't
 			// show the login view until login_show() is called below.  
-			// LLPanelLogin::getFields(gFirstname, gLastname, gPassword);
-
+			if (gUserCredential.isNull())                                                                          
+			{                                                                                                      
+				gUserCredential = gLoginHandler.initializeLoginInfo(LLStartUp::sSLURLCommand);                 
+			}     
 			if (gNoRender)
 			{
 				LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL;
@@ -822,8 +778,10 @@ bool idle_startup()
 			// Show the login dialog
 			login_show();
 			// connect dialog is already shown, so fill in the names
-			LLPanelLogin::setFields( gFirstname, gLastname, gPassword);
-
+			if (gUserCredential.notNull())                                                                         
+			{                                                                                                      
+				LLPanelLogin::setFields( gUserCredential, gRememberPassword);                                  
+			}     
 			LLPanelLogin::giveFocus();
 
 			gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
@@ -890,36 +848,32 @@ bool idle_startup()
 		// DEV-42215: Make sure they're not empty -- gFirstname and gLastname
 		// might already have been set from gSavedSettings, and it's too bad
 		// to overwrite valid values with empty strings.
-		if (! gLoginHandler.getFirstName().empty() && ! gLoginHandler.getLastName().empty())
-		{
-			gFirstname = gLoginHandler.getFirstName();
-			gLastname = gLoginHandler.getLastName();
-			LL_DEBUGS("LLStartup") << "STATE_LOGIN_CLEANUP: setting gFirstname, gLastname from gLoginHandler: '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
-		}
 
 		if (show_connect_box)
 		{
 			// TODO if not use viewer auth
 			// Load all the name information out of the login view
-			LLPanelLogin::getFields(&gFirstname, &gLastname, &gPassword);
+			LLPanelLogin::getFields(gUserCredential, gRememberPassword); 
 			// end TODO
 	 
 			// HACK: Try to make not jump on login
 			gKeyboard->resetKeys();
 		}
 
-		if (!gFirstname.empty() && !gLastname.empty())
-		{
-			gSavedSettings.setString("FirstName", gFirstname);
-			gSavedSettings.setString("LastName", gLastname);
-
-			LL_INFOS("AppInit") << "Attempting login as: " << gFirstname << " " << gLastname << LL_ENDL;
-			gDebugInfo["LoginName"] = gFirstname + " " + gLastname;	
+		// save the credentials                                                                                        
+		std::string userid = "unknown";                                                                                
+		if(gUserCredential.notNull())                                                                                  
+		{  
+			userid = gUserCredential->userID();                                                                    
+			gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword);  
 		}
-
+		gSavedSettings.setBOOL("RememberPassword", gRememberPassword);                                                 
+		LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL;                                           
+		gDebugInfo["LoginName"] = userid;                                                                              
+         
 		// create necessary directories
 		// *FIX: these mkdir's should error check
-		gDirUtilp->setLindenUserDir(gFirstname, gLastname);
+		gDirUtilp->setPerAccountChatLogsDir(userid);  
     	LLFile::mkdir(gDirUtilp->getLindenUserDir());
 
         // Set PerAccountSettingsFile to the default value.
@@ -952,8 +906,6 @@ bool idle_startup()
 		{
 			gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));		
 		}
-		
-		gDirUtilp->setPerAccountChatLogsDir(gFirstname, gLastname);
 
 		LLFile::mkdir(gDirUtilp->getChatLogsDir());
 		LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
@@ -1052,7 +1004,7 @@ bool idle_startup()
 
 	if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())
 	{
-		gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
+		gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
 
 		// Update progress status and the display loop.
 		auth_desc = LLTrans::getString("LoginInProgress");
@@ -1076,11 +1028,7 @@ bool idle_startup()
 
 		// This call to LLLoginInstance::connect() starts the 
 		// authentication process.
-		LLSD credentials;
-		credentials["first"] = gFirstname;
-		credentials["last"] = gLastname;
-		credentials["passwd"] = gPassword;
-		login->connect(credentials);
+		login->connect(gUserCredential);
 
 		LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK );
 		return FALSE;
@@ -1128,8 +1076,8 @@ bool idle_startup()
 			if(reason_response == "key")
 			{
 				// Couldn't login because user/password is wrong
-				// Clear the password
-				gPassword = "";
+				// Clear the credential
+				gUserCredential->clearAuthenticator();
 			}
 
 			if(reason_response == "update" 
@@ -1166,7 +1114,8 @@ bool idle_startup()
 			if(process_login_success_response())
 			{
 				// Pass the user information to the voice chat server interface.
-				gVoiceClient->userAuthorized(gFirstname, gLastname, gAgentID);
+				gVoiceClient->userAuthorized(gUserCredential->userID(), gAgentID);
+				LLGridManager::getInstance()->setFavorite(); 
 				LLStartUp::setStartupState( STATE_WORLD_INIT);
 			}
 			else
@@ -2115,20 +2064,9 @@ void login_show()
 #endif
 
 	LLPanelLogin::show(	gViewerWindow->getWindowRectScaled(),
-						bUseDebugLogin,
+						bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"),
 						login_callback, NULL );
 
-	// UI textures have been previously loaded in doPreloadImages()
-	
-	LL_DEBUGS("AppInit") << "Setting Servers" << LL_ENDL;
-
-	LLPanelLogin::addServer(LLViewerLogin::getInstance()->getGridLabel(), LLViewerLogin::getInstance()->getGridChoice());
-
-	LLViewerLogin* vl = LLViewerLogin::getInstance();
-	for(int grid_index = GRID_INFO_ADITI; grid_index < GRID_INFO_OTHER; ++grid_index)
-	{
-		LLPanelLogin::addServer(vl->getKnownGridLabel((EGridInfo)grid_index), grid_index);
-	}
 }
 
 // Callback for when login screen is closed.  Option 0 = connect, option 1 = quit.
@@ -2144,9 +2082,6 @@ void login_callback(S32 option, void *userdata)
 	}
 	else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION
 	{
-		// Make sure we don't save the password if the user is trying to clear it.
-		std::string first, last, password;
-		LLPanelLogin::getFields(&first, &last, &password);
 		if (!gSavedSettings.getBOOL("RememberPassword"))
 		{
 			// turn off the setting and write out to disk
@@ -2169,142 +2104,6 @@ void login_callback(S32 option, void *userdata)
 	}
 }
 
-
-// static
-std::string LLStartUp::loadPasswordFromDisk()
-{
-	// Only load password if we also intend to save it (otherwise the user
-	// wonders what we're doing behind his back).  JC
-	BOOL remember_password = gSavedSettings.getBOOL("RememberPassword");
-	if (!remember_password)
-	{
-		return std::string("");
-	}
-
-	std::string hashed_password("");
-
-	// Look for legacy "marker" password from settings.ini
-	hashed_password = gSavedSettings.getString("Marker");
-	if (!hashed_password.empty())
-	{
-		// Stomp the Marker entry.
-		gSavedSettings.setString("Marker", "");
-
-		// Return that password.
-		return hashed_password;
-	}
-
-	std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
-													   "password.dat");
-	LLFILE* fp = LLFile::fopen(filepath, "rb");		/* Flawfinder: ignore */
-	if (!fp)
-	{
-		return hashed_password;
-	}
-
-	// UUID is 16 bytes, written into ASCII is 32 characters
-	// without trailing \0
-	const S32 HASHED_LENGTH = 32;
-	U8 buffer[HASHED_LENGTH+1];
-
-	if (1 != fread(buffer, HASHED_LENGTH, 1, fp))
-	{
-		return hashed_password;
-	}
-
-	fclose(fp);
-
-	// Decipher with MAC address
-	LLXORCipher cipher(gMACAddress, 6);
-	cipher.decrypt(buffer, HASHED_LENGTH);
-
-	buffer[HASHED_LENGTH] = '\0';
-
-	// Check to see if the mac address generated a bad hashed
-	// password. It should be a hex-string or else the mac adress has
-	// changed. This is a security feature to make sure that if you
-	// get someone's password.dat file, you cannot hack their account.
-	if(is_hex_string(buffer, HASHED_LENGTH))
-	{
-		hashed_password.assign((char*)buffer);
-	}
-
-	return hashed_password;
-}
-
-
-// static
-void LLStartUp::savePasswordToDisk(const std::string& hashed_password)
-{
-	std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
-													   "password.dat");
-	LLFILE* fp = LLFile::fopen(filepath, "wb");		/* Flawfinder: ignore */
-	if (!fp)
-	{
-		return;
-	}
-
-	// Encipher with MAC address
-	const S32 HASHED_LENGTH = 32;
-	U8 buffer[HASHED_LENGTH+1];
-
-	LLStringUtil::copy((char*)buffer, hashed_password.c_str(), HASHED_LENGTH+1);
-
-	LLXORCipher cipher(gMACAddress, 6);
-	cipher.encrypt(buffer, HASHED_LENGTH);
-
-	if (fwrite(buffer, HASHED_LENGTH, 1, fp) != 1)
-	{
-		LL_WARNS("AppInit") << "Short write" << LL_ENDL;
-	}
-
-	fclose(fp);
-}
-
-
-// static
-void LLStartUp::deletePasswordFromDisk()
-{
-	std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
-														  "password.dat");
-	LLFile::remove(filepath);
-}
-
-
-bool is_hex_string(U8* str, S32 len)
-{
-	bool rv = true;
-	U8* c = str;
-	while(rv && len--)
-	{
-		switch(*c)
-		{
-		case '0':
-		case '1':
-		case '2':
-		case '3':
-		case '4':
-		case '5':
-		case '6':
-		case '7':
-		case '8':
-		case '9':
-		case 'a':
-		case 'b':
-		case 'c':
-		case 'd':
-		case 'e':
-		case 'f':
-			++c;
-			break;
-		default:
-			rv = false;
-			break;
-		}
-	}
-	return rv;
-}
-
 void show_first_run_dialog()
 {
 	LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback);
@@ -2881,33 +2680,45 @@ bool process_login_success_response()
 	text = response["secure_session_id"].asString();
 	if(!text.empty()) gAgent.mSecureSessionID.set(text);
 
-	text = response["first_name"].asString();
-	if(!text.empty()) 
-	{
-		// Remove quotes from string.  Login.cgi sends these to force
-		// names that look like numbers into strings.
-		gFirstname.assign(text);
-		LLStringUtil::replaceChar(gFirstname, '"', ' ');
-		LLStringUtil::trim(gFirstname);
-	}
-	text = response["last_name"].asString();
-	if(!text.empty()) 
+	// if the response contains a display name, use that,
+	// otherwise if the response contains a first and/or last name,
+	// use those.  Otherwise use the credential identifier
+
+	gDisplayName = "";
+	if (response.has("display_name"))
 	{
-		gLastname.assign(text);
+		gDisplayName.assign(response["display_name"].asString());
+		if(!gDisplayName.empty())
+		{
+			// Remove quotes from string.  Login.cgi sends these to force
+			// names that look like numbers into strings.
+			LLStringUtil::replaceChar(gDisplayName, '"', ' ');
+			LLStringUtil::trim(gDisplayName);
+		}
 	}
-	gSavedSettings.setString("FirstName", gFirstname);
-	gSavedSettings.setString("LastName", gLastname);
-
-	if (gSavedSettings.getBOOL("RememberPassword"))
+	if(gDisplayName.empty())
 	{
-		// Successful login means the password is valid, so save it.
-		LLStartUp::savePasswordToDisk(gPassword);
+		if(response.has("first_name"))
+		{
+			gDisplayName.assign(response["first_name"].asString());
+			LLStringUtil::replaceChar(gDisplayName, '"', ' ');
+			LLStringUtil::trim(gDisplayName);
+		}
+		if(response.has("last_name"))
+		{
+			text.assign(response["last_name"].asString());
+			LLStringUtil::replaceChar(text, '"', ' ');
+			LLStringUtil::trim(text);
+			if(!gDisplayName.empty())
+			{
+				gDisplayName += " ";
+			}
+			gDisplayName += text;
+		}
 	}
-	else
+	if(gDisplayName.empty())
 	{
-		// Don't leave password from previous session sitting around
-		// during this login session.
-		LLStartUp::deletePasswordFromDisk();
+		gDisplayName.assign(gUserCredential->asString());
 	}
 
 	// this is their actual ability to access content
@@ -3108,7 +2919,7 @@ bool process_login_success_response()
 
 	bool success = false;
 	// JC: gesture loading done below, when we have an asset system
-	// in place.  Don't delete/clear user_credentials until then.
+	// in place.  Don't delete/clear gUserCredentials until then.
 	if(gAgentID.notNull()
 	   && gAgentSessionID.notNull()
 	   && gMessageSystem->mOurCircuitCode
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index 92fe9521d3..28bc7fcd2a 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -101,14 +101,6 @@ public:
 	static void loadInitialOutfit( const std::string& outfit_folder_name,
 								   const std::string& gender_name );
 
-	// Load MD5 of user's password from local disk file.
-	static std::string loadPasswordFromDisk();
-	
-	// Record MD5 of user's password for subsequent login.
-	static void savePasswordToDisk(const std::string& hashed_password);
-	
-	// Delete the saved password local disk file.
-	static void deletePasswordFromDisk();
 	
 	static bool dispatchURL();
 		// if we have a SLURL or sim string ("Ahern/123/45") that started
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 1bff04352c..00f4454fab 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -424,7 +424,7 @@ void init_menus()
 	gPopupMenuView->setBackgroundColor( color );
 
 	// If we are not in production, use a different color to make it apparent.
-	if (LLViewerLogin::getInstance()->isInProductionGrid())
+	if (LLGridManager::getInstance()->isInProductionGrid())
 	{
 		color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
 	}
@@ -439,7 +439,7 @@ void init_menus()
 	gMenuHolder->addChild(gMenuBarView);
   
     gViewerWindow->setMenuBackgroundColor(false, 
-        LLViewerLogin::getInstance()->isInProductionGrid());
+        LLGridManager::getInstance()->isInProductionGrid());
 
 	// Assume L$10 for now, the server will tell us the real cost at login
 	// *TODO:Also fix cost in llfolderview.cpp for Inventory menus
@@ -3415,7 +3415,7 @@ void set_god_level(U8 god_level)
         if(gViewerWindow)
         {
             gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT,
-            LLViewerLogin::getInstance()->isInProductionGrid());
+            LLGridManager::getInstance()->isInProductionGrid());
         }
     
         LLSD args;
@@ -3455,7 +3455,7 @@ BOOL check_toggle_hacked_godmode(void*)
 
 bool enable_toggle_hacked_godmode(void*)
 {
-  return !LLViewerLogin::getInstance()->isInProductionGrid();
+  return !LLGridManager::getInstance()->isInProductionGrid();
 }
 #endif
 
@@ -4320,7 +4320,7 @@ BOOL enable_take()
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLViewerLogin::getInstance()->isInProductionGrid() 
+		if (!LLGridManager::getInstance()->isInProductionGrid() 
             && gAgent.isGodlike())
 		{
 			return TRUE;
@@ -4947,7 +4947,7 @@ bool enable_object_delete()
 	TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-	(!LLViewerLogin::getInstance()->isInProductionGrid()
+	(!LLGridManager::getInstance()->isInProductionGrid()
      && gAgent.isGodlike()) ||
 # endif
 	LLSelectMgr::getInstance()->canDoDelete();
@@ -6556,7 +6556,7 @@ bool enable_object_take_copy()
 		all_valid = true;
 #ifndef HACKED_GODLIKE_VIEWER
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (LLViewerLogin::getInstance()->isInProductionGrid()
+		if (LLGridManager::getInstance()->isInProductionGrid()
             || !gAgent.isGodlike())
 # endif
 		{
@@ -6618,7 +6618,7 @@ BOOL enable_save_into_inventory(void*)
 	return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-	if (!LLViewerLogin::getInstance()->isInProductionGrid()
+	if (!LLGridManager::getInstance()->isInProductionGrid()
         && gAgent.isGodlike())
 	{
 		return TRUE;
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index d7b55d7e97..fcfaf1eef2 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -5,7 +5,7 @@
  *
  * $LicenseInfo:firstyear=2006&license=viewergpl$
  * 
- * Copyright (c) 2006-2009, Linden Research, Inc.
+ * Copyright (c) 2006-2007, Linden Research, Inc.
  * 
  * Second Life Viewer Source Code
  * The source code in this file ("Source Code") is provided by Linden Lab
@@ -13,13 +13,12 @@
  * ("GPL"), unless you have obtained a separate licensing agreement
  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * online at http://secondlife.com/developers/opensource/gplv2
  * 
  * There are special exceptions to the terms and conditions of the GPL as
  * it is applied to this Source Code. View the full text of the exception
  * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlife.com/developers/opensource/flossexception
  * 
  * By copying, modifying or distributing this software, you acknowledge
  * that you have read and understood your obligations described above,
@@ -34,302 +33,462 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llviewernetwork.h"
+#include "llviewercontrol.h"
+#include "llsdserialize.h"
+#include "llweb.h"
 
-#include "llevents.h"
-#include "net.h"
+                                                            
+const char* DEFAULT_LOGIN_PAGE = "http://secondlife.com/app/login/";
 
-#include "llviewercontrol.h"
-#include "lllogin.h"
+const char* SYSTEM_GRID_SLURL_BASE = "http://slurl.com/secondlife/";
+const char* SYSTEM_GRID_APP_SLURL_BASE = "secondlife:///app";
 
-struct LLGridData
-{
-	const char* mLabel;
-	const char* mName;
-	const char* mLoginURI;
-	const char* mHelperURI;
-};
+const char* DEFAULT_SLURL_BASE = "https://%s/region/";
+const char* DEFAULT_APP_SLURL_BASE = "x-grid-location-info://%s/app";
 
-static LLGridData gGridInfo[GRID_INFO_COUNT] = 
+LLGridManager::LLGridManager()
 {
-	{ "None", "", "", ""},
-	{ "Aditi", 
-	  "util.aditi.lindenlab.com", 
-	  "https://login.aditi.lindenlab.com/cgi-bin/login.cgi",
-	  "http://aditi-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Agni", 
-	  "util.agni.lindenlab.com", 
-	  "https://login.agni.lindenlab.com/cgi-bin/login.cgi",
-	  "https://secondlife.com/helpers/" },
-	{ "Aruna",
-	  "util.aruna.lindenlab.com",
-	  "https://login.aruna.lindenlab.com/cgi-bin/login.cgi",
-	  "http://aruna-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Bharati",
-	  "util.bharati.lindenlab.com",
-	  "https://login.bharati.lindenlab.com/cgi-bin/login.cgi",
-	  "http://bharati-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Chandra",
-	  "util.chandra.lindenlab.com",
-	  "https://login.chandra.lindenlab.com/cgi-bin/login.cgi",
-	  "http://chandra-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Damballah",
-	  "util.damballah.lindenlab.com",
-	  "https://login.damballah.lindenlab.com/cgi-bin/login.cgi",
-	  "http://damballah-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Danu",
-	  "util.danu.lindenlab.com",
-	  "https://login.danu.lindenlab.com/cgi-bin/login.cgi",
-	  "http://danu-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Durga",
-	  "util.durga.lindenlab.com",
-	  "https://login.durga.lindenlab.com/cgi-bin/login.cgi",
-	  "http://durga-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Ganga",
-	  "util.ganga.lindenlab.com",
-	  "https://login.ganga.lindenlab.com/cgi-bin/login.cgi",
-	  "http://ganga-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Mitra",
-	  "util.mitra.lindenlab.com",
-	  "https://login.mitra.lindenlab.com/cgi-bin/login.cgi",
-	  "http://mitra-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Mohini",
-	  "util.mohini.lindenlab.com",
-	  "https://login.mohini.lindenlab.com/cgi-bin/login.cgi",
-	  "http://mohini-secondlife.webdev.lindenlab.com/helpers/" },
-  	{ "Nandi",
-	  "util.nandi.lindenlab.com",
-	  "https://login.nandi.lindenlab.com/cgi-bin/login.cgi",
-	  "http://nandi-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Parvati",
-	  "util.parvati.lindenlab.com",
-	  "https://login.parvati.lindenlab.com/cgi-bin/login.cgi",
-	  "http://parvati-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Radha",
-	  "util.radha.lindenlab.com",
-	  "https://login.radha.lindenlab.com/cgi-bin/login.cgi",
-	  "http://radha-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Ravi",
-	  "util.ravi.lindenlab.com",
-	  "https://login.ravi.lindenlab.com/cgi-bin/login.cgi",
-	  "http://ravi-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Siva", 
-	  "util.siva.lindenlab.com",
-	  "https://login.siva.lindenlab.com/cgi-bin/login.cgi",
-	  "http://siva-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Shakti",
-	  "util.shakti.lindenlab.com",
-	  "https://login.shakti.lindenlab.com/cgi-bin/login.cgi",
-	  "http://shakti-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Skanda",
-	  "util.skanda.lindenlab.com",
-	  "https://login.skanda.lindenlab.com/cgi-bin/login.cgi",
-	  "http://skanda-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Soma",
-	  "util.soma.lindenlab.com",
-	  "https://login.soma.lindenlab.com/cgi-bin/login.cgi",
-	  "http://soma-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Uma",
-	  "util.uma.lindenlab.com",
-	  "https://login.uma.lindenlab.com/cgi-bin/login.cgi",
-	  "http://uma-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Vaak",
-	  "util.vaak.lindenlab.com",
-	  "https://login.vaak.lindenlab.com/cgi-bin/login.cgi",
-	  "http://vaak-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Yami",
-	  "util.yami.lindenlab.com",
-	  "https://login.yami.lindenlab.com/cgi-bin/login.cgi",
-	  "http://yami-secondlife.webdev.lindenlab.com/helpers/" },
-	{ "Local", 
-	  "localhost", 
-	  "https://login.dmz.lindenlab.com/cgi-bin/login.cgi",
-	  "" },
-	{ "Other", 
-	  "", 
-	  "https://login.dmz.lindenlab.com/cgi-bin/login.cgi",
-	  "" }
-};
-
-const EGridInfo DEFAULT_GRID_CHOICE = GRID_INFO_AGNI;
-
-
-unsigned char gMACAddress[MAC_ADDRESS_BYTES];		/* Flawfinder: ignore */
-
-LLViewerLogin::LLViewerLogin() :
-	mGridChoice(DEFAULT_GRID_CHOICE)
+	// by default, we use the 'grids.xml' file in the user settings directory
+	// this file is an LLSD file containing multiple grid definitions.
+	// This file does not contain definitions for secondlife.com grids,
+	// as that would be a security issue when they are overwritten by
+	// an attacker.  Don't want someone snagging a password.
+	std::string grid_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
+														   "grids.xml");
+	initialize(grid_file);
+	
+}
+
+
+LLGridManager::LLGridManager(const std::string& grid_file)
 {
+	// initialize with an explicity grid file for testing.
+	initialize(grid_file);
 }
 
- LLViewerLogin::~LLViewerLogin() 
- {
- }
+//
+// LLGridManager - class for managing the list of known grids, and the current
+// selection
+//
+
+
+//
+// LLGridManager::initialze - initialize the list of known grids based
+// on the fixed list of linden grids (fixed for security reasons)
+// the grids.xml file
+// and the command line.
+void LLGridManager::initialize(const std::string& grid_file)
+{
+	// default grid list.
+	// Don't move to a modifiable file for security reasons,
+	mGridName.clear() ;
+	// set to undefined
+	mGridList = LLSD();
+	mGridFile = grid_file;
+	// as we don't want an attacker to override our grid list
+	// to point the default grid to an invalid grid
+	addSystemGrid("None", "", "", "", DEFAULT_LOGIN_PAGE);
+	
+
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+  	addSystemGrid("Agni",                                                                                             
+				  MAINGRID,                                               
+				  "https://login.agni.lindenlab.com/cgi-bin/login.cgi",                    
+				  "https://secondlife.com/helpers/",     
+				  DEFAULT_LOGIN_PAGE);
+#else
+	addSystemGrid("Secondlife.com",                                                                                             
+				  MAINGRID,                                               
+				  "https://login.agni.lindenlab.com/cgi-bin/login.cgi",                    
+				  "https://secondlife.com/helpers/",     
+				  DEFAULT_LOGIN_PAGE,
+				  "Agni");
+#endif // LL_RELEASE_FOR_DOWNLOAD	
+	addSystemGrid("Aditi",                                                                                             
+				  "util.aditi.lindenlab.com",                                              
+				  "https://login.aditi.lindenlab.com/cgi-bin/login.cgi",                   
+				  "http://aditi-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Aruna",                                                                                            
+				  "util.aruna.lindenlab.com",                                              
+				  "https://login.aruna.lindenlab.com/cgi-bin/login.cgi",                   
+				  "http://aruna-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Durga",                                                                                            
+				  "util.durga.lindenlab.com",                                              
+				  "https://login.durga.lindenlab.com/cgi-bin/login.cgi",                   
+				  "http://durga-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Ganga",                                                                                            
+				  "util.ganga.lindenlab.com",                                              
+				  "https://login.ganga.lindenlab.com/cgi-bin/login.cgi",                   
+				  "http://ganga-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Mitra",                                                                                            
+				  "util.mitra.lindenlab.com",                                              
+				  "https://login.mitra.lindenlab.com/cgi-bin/login.cgi",                   
+				  "http://mitra-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Mohini",                                                                                           
+				  "util.mohini.lindenlab.com",                                             
+				  "https://login.mohini.lindenlab.com/cgi-bin/login.cgi",                  
+				  "http://mohini-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Nandi",                                                                                            
+				  "util.nandi.lindenlab.com",                                              
+				  "https://login.nandi.lindenlab.com/cgi-bin/login.cgi",                   
+				  "http://nandi-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Radha",                                                                                            
+				  "util.radha.lindenlab.com",                                              
+				  "https://login.radha.lindenlab.com/cgi-bin/login.cgi",                   
+				  "http://radha-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Ravi",                                                                                             
+				  "util.ravi.lindenlab.com",                                               
+				  "https://login.ravi.lindenlab.com/cgi-bin/login.cgi",                    
+				  "http://ravi-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Siva",                                                                                             
+				  "util.siva.lindenlab.com",                                               
+				  "https://login.siva.lindenlab.com/cgi-bin/login.cgi",                    
+				  "http://siva-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Shakti",                                                                                           
+				  "util.shakti.lindenlab.com",                                             
+				  "https://login.shakti.lindenlab.com/cgi-bin/login.cgi",                  
+				  "http://shakti-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Soma",                                                                                             
+				  "util.soma.lindenlab.com",                                               
+				  "https://login.soma.lindenlab.com/cgi-bin/login.cgi",                    
+				  "http://soma-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	
+	addSystemGrid("Uma",                                                                                              
+				  "util.uma.lindenlab.com",                                                
+				  "https://login.uma.lindenlab.com/cgi-bin/login.cgi",                     
+				  "http://uma-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Vaak",                                                                                             
+				  "util.vaak.lindenlab.com",                                               
+				  "https://login.vaak.lindenlab.com/cgi-bin/login.cgi",                    
+				  "http://vaak-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Yami",                                                                                             
+				  "util.yami.lindenlab.com",                                               
+				  "https://login.yami.lindenlab.com/cgi-bin/login.cgi",                    
+				  "http://yami-secondlife.webdev.lindenlab.com/helpers/",
+				  DEFAULT_LOGIN_PAGE);
+	addSystemGrid("Local (Linden)",                                                                                    
+				  "localhost",                                                             
+				  "https://login.dmz.lindenlab.com/cgi-bin/login.cgi",                     
+				  "",
+				  DEFAULT_LOGIN_PAGE); 
+
+	
+	LLSD other_grids;
+	llifstream llsd_xml;
+	if (!grid_file.empty())
+	{
+		llsd_xml.open( grid_file.c_str(), std::ios::in | std::ios::binary );
 
-void LLViewerLogin::setGridChoice(EGridInfo grid)
-{	
-	if(grid < 0 || grid >= GRID_INFO_COUNT)
+		// parse through the gridfile, inserting grids into the list unless
+		// they overwrite a linden grid.
+		if( llsd_xml.is_open()) 
+		{
+			LLSDSerialize::fromXMLDocument( other_grids, llsd_xml );
+			if(other_grids.isMap())
+			{
+				for(LLSD::map_iterator grid_itr = other_grids.beginMap(); 
+					grid_itr != other_grids.endMap();
+					++grid_itr)
+				{
+					LLSD::String key_name = grid_itr->first;
+					LLSD grid = grid_itr->second;
+					// TODO:  Make sure gridfile specified label is not 
+					// a system grid label
+					LL_INFOS("GridManager") << "reading: " << key_name << LL_ENDL;
+					if (mGridList.has(key_name) &&
+						mGridList[key_name].has(GRID_IS_SYSTEM_GRID_VALUE))
+					{
+						LL_INFOS("GridManager") << "Cannot override grid " << key_name << " as it's a system grid" << LL_ENDL;
+						// If the system grid does exist in the grids file, and it's marked as a favorite, set it as a favorite.
+						if(grid_itr->second.has(GRID_IS_FAVORITE_VALUE) && grid_itr->second[GRID_IS_FAVORITE_VALUE].asBoolean() )
+						{
+							mGridList[key_name][GRID_IS_FAVORITE_VALUE] = TRUE;
+						}
+					}
+					else
+					{
+						try
+						{
+							addGrid(grid);
+							LL_INFOS("GridManager") << "Added grid: " << key_name << LL_ENDL;
+						}
+						catch (...)
+						{
+						}
+					}
+				}
+				llsd_xml.close();
+			}	
+		}     
+	}
+	
+	// load a grid from the command line.
+	// if the actual grid name is specified from the command line,
+	// set it as the 'selected' grid.
+	LLSD cmd_line_grid = gSavedSettings.getString("CmdLineGridChoice");
+	if (gSavedSettings.controlExists("CmdLineGridChoice"))
 	{
-		llerrs << "Invalid grid index specified." << llendl;
+		mGridName = gSavedSettings.getString("CmdLineGridChoice");
+		LL_INFOS("GridManager") << "Grid Name: " << mGridName << LL_ENDL;		
 	}
+	
+	// If a command line login URI was passed in, so we should add the command
+	// line grid to the list of grids
 
-	if(mGridChoice != grid || gSavedSettings.getS32("ServerChoice") != grid)
+	LLSD cmd_line_login_uri = gSavedSettings.getLLSD("CmdLineLoginURI");
+	if (cmd_line_login_uri.isString())
 	{
-		mGridChoice = grid;
-		if(GRID_INFO_LOCAL == mGridChoice)
+		LL_INFOS("GridManager") << "adding cmd line login uri" << LL_ENDL;
+		// grab the other related URI values
+		std::string cmd_line_helper_uri = gSavedSettings.getString("CmdLineHelperURI");
+		std::string cmd_line_login_page = gSavedSettings.getString("LoginPage");
+		
+		// we've a cmd line login, so add a grid for the command line,
+		// overwriting any existing grids
+		LLSD grid = LLSD::emptyMap();
+		grid[GRID_LOGIN_URI_VALUE] = LLSD::emptyArray();
+		grid[GRID_LOGIN_URI_VALUE].append(cmd_line_login_uri);
+		LL_INFOS("GridManager") << "cmd line login uri: " << cmd_line_login_uri.asString() << LL_ENDL;
+		LLURI uri(cmd_line_login_uri.asString());
+		if (mGridName.empty())
 		{
-			mGridName = LOOPBACK_ADDRESS_STRING;
+			// if a grid name was not passed in via the command line,
+			// then set the grid name based on the hostname of the 
+			// login uri
+			mGridName = uri.hostName();
 		}
-		else if(GRID_INFO_OTHER == mGridChoice)
+
+		grid[GRID_NAME_VALUE] = mGridName;
+
+		if (mGridList.has(mGridName) && mGridList[mGridName].has(GRID_LABEL_VALUE))
 		{
-			// *FIX:Mani - could this possibly be valid?
-			mGridName = "other"; 
+			grid[GRID_LABEL_VALUE] = mGridList[mGridName][GRID_LABEL_VALUE];
 		}
 		else
 		{
-			mGridName = gGridInfo[mGridChoice].mLabel;
+			grid[GRID_LABEL_VALUE] = mGridName;			
+		}
+		if(!cmd_line_helper_uri.empty())
+		{
+			grid[GRID_HELPER_URI_VALUE] = cmd_line_helper_uri;
+		}
+
+		if(!cmd_line_login_page.empty())
+		{
+			grid[GRID_LOGIN_PAGE_VALUE] = cmd_line_login_page;
+		}
+		// if the login page, helper URI value, and so on are not specified,
+		// add grid will generate them.
+
+		// Also, we will override a system grid if values are passed in via the command
+		// line, for testing.  These values will not be remembered though.
+		if (mGridList.has(mGridName) && mGridList[mGridName].has(GRID_IS_SYSTEM_GRID_VALUE))
+		{
+			grid[GRID_IS_SYSTEM_GRID_VALUE] = TRUE;
 		}
+		addGrid(grid);
+	}
+	
+	// if a grid was not passed in via the command line, grab it from the CurrentGrid setting.
+	if (mGridName.empty())
+	{
 
-		gSavedSettings.setS32("ServerChoice", mGridChoice);
-		gSavedSettings.setString("CustomServer", "");
+		mGridName = gSavedSettings.getString("CurrentGrid");
 	}
-}
 
-void LLViewerLogin::setGridChoice(const std::string& grid_name)
-{
-	// Set the grid choice based on a string.
-	// The string can be:
-	// - a grid label from the gGridInfo table 
-	// - an ip address
-    if(!grid_name.empty())
-    {
-        // find the grid choice from the user setting.
-        int grid_index = GRID_INFO_NONE; 
-        for(;grid_index < GRID_INFO_OTHER; ++grid_index)
-        {
-            if(0 == LLStringUtil::compareInsensitive(gGridInfo[grid_index].mLabel, grid_name))
-            {
-				// Founding a matching label in the list...
-				setGridChoice((EGridInfo)grid_index);
-				break;
-            }
-        }
-
-        if(GRID_INFO_OTHER == grid_index)
-        {
-            // *FIX:MEP Can and should we validate that this is an IP address?
-            mGridChoice = GRID_INFO_OTHER;
-            mGridName = grid_name;
-			gSavedSettings.setS32("ServerChoice", mGridChoice);
-			gSavedSettings.setString("CustomServer", mGridName);
-        }
-    }
+	if (mGridName.empty() || !mGridList.has(mGridName))
+	{
+		// the grid name was empty, or the grid isn't actually in the list, then set it to the
+		// appropriate default.
+		LL_INFOS("GridManager") << "Resetting grid as grid name " << mGridName << " is not in the list" << LL_ENDL;
+#if LL_RELEASE_FOR_DOWNLOAD
+		mGridName = MAINGRID;
+#else
+		mGridName = "";
+#endif
+	}
+	LL_INFOS("GridManager") << "Selected grid is " << mGridName << LL_ENDL;		
+	gSavedSettings.setString("CurrentGrid", mGridName);
+
 }
 
-void LLViewerLogin::resetURIs()
+LLGridManager::~LLGridManager()
 {
-    // Clear URIs when picking a new server
-	gSavedSettings.setLLSD("CmdLineLoginURI", LLSD::emptyArray());
-	gSavedSettings.setString("CmdLineHelperURI", "");
+	saveFavorites();
 }
 
-EGridInfo LLViewerLogin::getGridChoice() const
+//
+// LLGridManager::addGrid - add a grid to the grid list, populating the needed values
+// if they're not populated yet.
+//
+
+void LLGridManager::addGrid(LLSD& grid_data)
 {
-	return mGridChoice;
+	if (grid_data.isMap() && grid_data.has(GRID_NAME_VALUE))
+	{
+		std::string grid_name = utf8str_tolower(grid_data[GRID_NAME_VALUE]);
+
+		// grid_name should be in the form of a dns address
+		if (!grid_name.empty() &&
+			grid_name.find_first_not_of("abcdefghijklmnopqrstuvwxyz1234567890-_. ") != std::string::npos)
+		{
+			printf("grid name: %s", grid_name.c_str());
+			throw LLInvalidGridName(grid_name);
+		}
+		
+		// populate the other values if they don't exist
+		if (!grid_data.has(GRID_LABEL_VALUE)) 
+		{
+			grid_data[GRID_LABEL_VALUE] = grid_name;
+		}
+		if (!grid_data.has(GRID_ID_VALUE))
+		{
+			grid_data[GRID_ID_VALUE] = grid_name;
+		}
+		
+		// if the grid data doesn't include any of the URIs, then 
+		// generate them from the grid_name, which should be a dns address
+		if (!grid_data.has(GRID_LOGIN_URI_VALUE)) 
+		{
+			grid_data[GRID_LOGIN_URI_VALUE] = LLSD::emptyArray();
+			grid_data[GRID_LOGIN_URI_VALUE].append(std::string("https://") + 
+													grid_name + "/cgi-bin/login.cgi");
+		}
+		// Populate to the default values
+		if (!grid_data.has(GRID_LOGIN_PAGE_VALUE)) 
+		{
+			grid_data[GRID_LOGIN_PAGE_VALUE] = std::string("http://") + grid_name + "/app/login/";
+		}		
+		if (!grid_data.has(GRID_HELPER_URI_VALUE)) 
+		{
+			grid_data[GRID_HELPER_URI_VALUE] = std::string("https://") + grid_name + "/helpers/";
+		}		
+		LL_INFOS("GridManager") << "ADDING: " << grid_name << LL_ENDL;
+		mGridList[grid_name] = grid_data;		
+	}
 }
 
-std::string LLViewerLogin::getGridLabel() const
+//
+// LLGridManager::addSystemGrid - helper for adding a system grid.
+void LLGridManager::addSystemGrid(const std::string& label, 
+								  const std::string& name, 
+								  const std::string& login, 
+								  const std::string& helper,
+								  const std::string& login_page,
+								  const std::string& login_id)
 {
-	if(mGridChoice == GRID_INFO_NONE)
+	LLSD grid = LLSD::emptyMap();
+	grid[GRID_NAME_VALUE] = name;
+	grid[GRID_LABEL_VALUE] = label;
+	grid[GRID_HELPER_URI_VALUE] = helper;
+	grid[GRID_LOGIN_URI_VALUE] = LLSD::emptyArray();
+	grid[GRID_LOGIN_URI_VALUE].append(login);
+	grid[GRID_LOGIN_PAGE_VALUE] = login_page;
+	grid[GRID_IS_SYSTEM_GRID_VALUE] = TRUE;
+	grid[GRID_LOGIN_CREDENTIAL_PAGE_TYPE_VALUE] = GRID_LOGIN_CREDENTIAL_PAGE_TYPE_AGENT;
+	grid[GRID_SLURL_BASE] = SYSTEM_GRID_SLURL_BASE;
+	grid[GRID_APP_SLURL_BASE] = SYSTEM_GRID_APP_SLURL_BASE;
+	if (login_id.empty())
 	{
-		return "None";
+		grid[GRID_ID_VALUE] = name;
 	}
-	else if(mGridChoice < GRID_INFO_OTHER)
+	else
 	{
-		return gGridInfo[mGridChoice].mLabel;
+		grid[GRID_ID_VALUE] = login_id;
 	}
-
-	return mGridName;
-}
-
-std::string LLViewerLogin::getKnownGridLabel(EGridInfo grid_index) const
-{
-	if(grid_index > GRID_INFO_NONE && grid_index < GRID_INFO_OTHER)
+	
+	// only add the system grids beyond agni to the visible list
+	// if we're building a debug version.
+	if (name == std::string(MAINGRID))
 	{
-		return gGridInfo[grid_index].mLabel;
+		grid[GRID_IS_FAVORITE_VALUE] = TRUE;		
 	}
-	return gGridInfo[GRID_INFO_NONE].mLabel;
+	addGrid(grid);
 }
 
-void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const
+// return a list of grid name -> grid label mappings for UI purposes
+std::map<std::string, std::string> LLGridManager::getKnownGrids(bool favorite_only)
 {
-	// return the login uri set on the command line.
-	LLControlVariable* c = gSavedSettings.getControl("CmdLineLoginURI");
-	if(c)
+	std::map<std::string, std::string> result;
+	for(LLSD::map_iterator grid_iter = mGridList.beginMap();
+		grid_iter != mGridList.endMap();
+		grid_iter++) 
 	{
-		LLSD v = c->getValue();
-		if(v.isArray())
+		if(!favorite_only || grid_iter->second.has(GRID_IS_FAVORITE_VALUE))
 		{
-			for(LLSD::array_const_iterator itr = v.beginArray();
-				itr != v.endArray(); ++itr)
-			{
-				std::string uri = itr->asString();
-				if(!uri.empty())
-				{
-					uris.push_back(uri);
-				}
-			}
-		}
-		else
-		{
-			std::string uri = v.asString();
-			if(!uri.empty())
-			{
-				uris.push_back(uri);
-			}
+			result[grid_iter->first] = grid_iter->second[GRID_LABEL_VALUE].asString();
 		}
 	}
 
-	// If there was no command line uri...
-	if(uris.empty())
+	return result;
+}
+
+void LLGridManager::setGridChoice(const std::string& grid_name)
+{
+	// Set the grid choice based on a string.
+	// The string can be:
+	// - a grid label from the gGridInfo table 
+	// - a hostname
+	// - an ip address
+
+	// loop through.  We could do just a hash lookup but we also want to match
+	// on label
+	for(LLSD::map_iterator grid_iter = mGridList.beginMap();
+		grid_iter != mGridList.endMap();
+		grid_iter++) 
 	{
-		// If its a known grid choice, get the uri from the table,
-		// else try the grid name.
-		if(mGridChoice > GRID_INFO_NONE && mGridChoice < GRID_INFO_OTHER)
+		if((grid_name == grid_iter->first) || 
+		   (grid_name == grid_iter->second[GRID_LABEL_VALUE].asString()))
 		{
-			uris.push_back(gGridInfo[mGridChoice].mLoginURI);
-		}
-		else
-		{
-			uris.push_back(mGridName);
+			mGridName = grid_iter->second[GRID_NAME_VALUE].asString();
+			gSavedSettings.setString("CurrentGrid", grid_iter->second[GRID_NAME_VALUE]);			
+			return; 
+
 		}
 	}
+	LLSD grid = LLSD::emptyMap();
+	grid[GRID_NAME_VALUE] = grid_name;
+	addGrid(grid);
+	mGridName = grid_name;
+	gSavedSettings.setString("CurrentGrid", grid_name);
 }
 
-std::string LLViewerLogin::getHelperURI() const
+void LLGridManager::getLoginURIs(std::vector<std::string>& uris)
 {
-	std::string helper_uri = gSavedSettings.getString("CmdLineHelperURI");
-	if (helper_uri.empty())
+	uris.clear();
+	for (LLSD::array_iterator llsd_uri = mGridList[mGridName][GRID_LOGIN_URI_VALUE].beginArray();
+		 llsd_uri != mGridList[mGridName][GRID_LOGIN_URI_VALUE].endArray();
+		 llsd_uri++)
 	{
-		// grab URI from selected grid
-		if(mGridChoice > GRID_INFO_NONE && mGridChoice < GRID_INFO_OTHER)
-		{
-			helper_uri = gGridInfo[mGridChoice].mHelperURI;
-		}
-
-		if (helper_uri.empty())
-		{
-			// what do we do with unnamed/miscellaneous grids?
-			// for now, operations that rely on the helper URI (currency/land purchasing) will fail
-		}
+		uris.push_back(llsd_uri->asString());
 	}
-	return helper_uri;
 }
 
-bool LLViewerLogin::isInProductionGrid()
+bool LLGridManager::isInProductionGrid()
 {
 	// *NOTE:Mani This used to compare GRID_INFO_AGNI to gGridChoice,
 	// but it seems that loginURI trumps that.
 	std::vector<std::string> uris;
 	getLoginURIs(uris);
+	if (uris.size() < 1)
+	{
+		return 1;
+	}
 	LLStringUtil::toLower(uris[0]);
 	if((uris[0].find("agni") != std::string::npos))
 	{
@@ -338,3 +497,51 @@ bool LLViewerLogin::isInProductionGrid()
 
 	return false;
 }
+
+void LLGridManager::saveFavorites()
+{
+	// filter out just those marked as favorites
+	LLSD output_grid_list = LLSD::emptyMap();
+	for(LLSD::map_iterator grid_iter = mGridList.beginMap();
+		grid_iter != mGridList.endMap();
+		grid_iter++)
+	{
+		if(grid_iter->second.has(GRID_IS_FAVORITE_VALUE))
+		{
+			output_grid_list[grid_iter->first] = grid_iter->second;
+		}
+	}       
+	llofstream llsd_xml;
+	llsd_xml.open( mGridFile.c_str(), std::ios::out | std::ios::binary);	
+	LLSDSerialize::toPrettyXML(output_grid_list, llsd_xml);
+	llsd_xml.close();
+}
+
+
+// build a slurl for the given region within the selected grid
+std::string LLGridManager::getSLURLBase(const std::string& grid_name)
+{
+	std::string grid_base;
+	if(mGridList.has(grid_name) && mGridList[grid_name].has(GRID_SLURL_BASE))
+	{
+		return mGridList[grid_name][GRID_SLURL_BASE].asString();
+	}
+	else
+	{
+		return  llformat(DEFAULT_SLURL_BASE, grid_name.c_str());
+	}
+}
+
+// build a slurl for the given region within the selected grid
+std::string LLGridManager::getAppSLURLBase(const std::string& grid_name)
+{
+	std::string grid_base;
+	if(mGridList.has(grid_name) && mGridList[grid_name].has(GRID_APP_SLURL_BASE))
+	{
+		return mGridList[grid_name][GRID_APP_SLURL_BASE].asString();
+	}
+	else
+	{
+		return  llformat(DEFAULT_APP_SLURL_BASE, grid_name.c_str());
+	}
+}
diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h
index edae6dc47b..7b3ce9c499 100644
--- a/indra/newview/llviewernetwork.h
+++ b/indra/newview/llviewernetwork.h
@@ -5,7 +5,7 @@
  *
  * $LicenseInfo:firstyear=2006&license=viewergpl$
  * 
- * Copyright (c) 2006-2009, Linden Research, Inc.
+ * Copyright (c) 2006-2007, Linden Research, Inc.
  * 
  * Second Life Viewer Source Code
  * The source code in this file ("Source Code") is provided by Linden Lab
@@ -13,13 +13,12 @@
  * ("GPL"), unless you have obtained a separate licensing agreement
  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * online at http://secondlife.com/developers/opensource/gplv2
  * 
  * There are special exceptions to the terms and conditions of the GPL as
  * it is applied to this Source Code. View the full text of the exception
  * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlife.com/developers/opensource/flossexception
  * 
  * By copying, modifying or distributing this software, you acknowledge
  * that you have read and understood your obligations described above,
@@ -33,83 +32,137 @@
 
 #ifndef LL_LLVIEWERNETWORK_H
 #define LL_LLVIEWERNETWORK_H
+                                                                                                       
+extern const char* DEFAULT_LOGIN_PAGE;
+      
+#define GRID_NAME_VALUE "name"
+#define GRID_LABEL_VALUE "label"
+#define GRID_ID_VALUE "grid_login_id"
+#define GRID_LOGIN_URI_VALUE "login_uri"
+#define GRID_HELPER_URI_VALUE "helper_uri"
+#define GRID_LOGIN_PAGE_VALUE "login_page"
+#define GRID_IS_SYSTEM_GRID_VALUE "system_grid"
+#define GRID_IS_FAVORITE_VALUE "favorite"
+#define GRID_LOGIN_CREDENTIAL_PAGE_TYPE_VALUE "credential_type"
+#define GRID_LOGIN_CREDENTIAL_PAGE_TYPE_AGENT "agent"
+#define GRID_LOGIN_CREDENTIAL_PAGE_TYPE_ACCOUNT "account"
+#define MAINGRID "util.agni.lindenlab.com"
 
-#include <boost/scoped_ptr.hpp>
+// defines slurl formats associated with various grids.
+// we need to continue to support existing forms, as slurls
+// are shared between viewers that may not understand newer
+// forms.
+#define GRID_SLURL_BASE "slurl_base"
+#define GRID_APP_SLURL_BASE "app_slurl_base"
 
-class LLHost;
-class LLLogin;
-
-enum EGridInfo
+class LLInvalidGridName
 {
-	GRID_INFO_NONE,
-	GRID_INFO_ADITI,
-	GRID_INFO_AGNI,
-	GRID_INFO_ARUNA,
-	GRID_INFO_BHARATI,
-	GRID_INFO_CHANDRA,
-	GRID_INFO_DAMBALLAH,
-	GRID_INFO_DANU,
-	GRID_INFO_DURGA,
-	GRID_INFO_GANGA,
-	GRID_INFO_MITRA,
-	GRID_INFO_MOHINI,
-	GRID_INFO_NANDI,
-	GRID_INFO_PARVATI,
-	GRID_INFO_RADHA,
-	GRID_INFO_RAVI,
-	GRID_INFO_SIVA,
-	GRID_INFO_SHAKTI,
-	GRID_INFO_SKANDA,
-	GRID_INFO_SOMA,
-	GRID_INFO_UMA,
-	GRID_INFO_VAAK,
-	GRID_INFO_YAMI,
-	GRID_INFO_LOCAL,
-	GRID_INFO_OTHER, // IP address set via command line option
-	GRID_INFO_COUNT
+public:
+	LLInvalidGridName(std::string grid_name) : mGridName(grid_name)
+	{
+	}
+protected:
+	std::string mGridName;
 };
 
+
 /**
- * @brief A class to manage the viewer's login state.
+ * @brief A class to manage the grids available to the viewer
+ * including persistance.  This class also maintains the currently
+ * selected grid.
  * 
  **/
-class LLViewerLogin : public LLSingleton<LLViewerLogin>
+class LLGridManager : public LLSingleton<LLGridManager>
 {
 public:
-	LLViewerLogin();
-	~LLViewerLogin();
-
-	void setGridChoice(EGridInfo grid);
-	void setGridChoice(const std::string& grid_name);
-	void resetURIs();
+	
+	// when the grid manager is instantiated, the default grids are automatically
+	// loaded, and the grids favorites list is loaded from the xml file.
+	LLGridManager(const std::string& grid_file);
+	LLGridManager();
+	~LLGridManager();
+	
+	void initialize(const std::string& grid_file);
+	// grid list management
+	
+	// add a grid to the list of grids
+	void addGrid(LLSD& grid_info);	
 
-	/**
-	* @brief Get the enumeration of the grid choice.
-	* Should only return values > 0 && < GRID_INFO_COUNT
-	**/
-	EGridInfo getGridChoice() const;
-
-	/**
-	* @brief Get a readable label for the grid choice.
-	* Returns the readable name for the grid choice. 
-	* If the grid is 'other', returns something
-	* the string used to specifiy the grid.
-	**/
-	std::string getGridLabel() const; 
-
-	std::string getKnownGridLabel(EGridInfo grid_index) const; 
-
-	void getLoginURIs(std::vector<std::string>& uris) const;
-	std::string getHelperURI() const;
+	// retrieve a map of grid-name <-> label
+	// by default only return the user visible grids
+	std::map<std::string, std::string> getKnownGrids(bool favorites_only=FALSE);
+	
+	LLSD getGridInfo(const std::string& grid_name)
+	{
+		if(mGridList.has(grid_name))
+		{
+			return mGridList[grid_name];
+		}
+		else
+		{
+			return LLSD();
+		}
+	}
+	
+	// current grid management
 
+	// select a given grid as the current grid.  If the grid
+	// is not a known grid, then it's assumed to be a dns name for the
+	// grid, and the various URIs will be automatically generated.
+	void setGridChoice(const std::string& grid_name);
+	
+	
+	std::string getGridLabel() 
+	{ 
+		return mGridList[mGridName][GRID_LABEL_VALUE]; 
+	} 	
+	std::string getGridName() const { return mGridName; }
+	void getLoginURIs(std::vector<std::string>& uris);
+	std::string getHelperURI() {return mGridList[mGridName][GRID_HELPER_URI_VALUE];}
+	std::string getLoginPage() {return mGridList[mGridName][GRID_LOGIN_PAGE_VALUE];}
+	std::string getGridID() { return mGridList[mGridName][GRID_ID_VALUE]; }	
+	std::string getLoginPage(const std::string& grid_name) { return mGridList[grid_name][GRID_LOGIN_PAGE_VALUE]; }
+	
+	// build a slurl for the given region within the selected grid
+	std::string getSLURLBase(const std::string& grid_name);
+	std::string getSLURLBase() { return getSLURLBase(mGridName); }
+	
+	std::string getAppSLURLBase(const std::string& grid_name);
+	std::string getAppSLURLBase() { return getAppSLURLBase(mGridName); }	
+	
+	LLSD getGridInfo() { return mGridList[mGridName]; }
+	
+	bool isSystemGrid(const std::string& grid) 
+	{ 
+		return mGridList.has(grid) &&
+		      mGridList[grid].has(GRID_IS_SYSTEM_GRID_VALUE) && 
+	           mGridList[grid][GRID_IS_SYSTEM_GRID_VALUE].asBoolean(); 
+	}
+	bool isSystemGrid() { return isSystemGrid(mGridName); }
+	// Mark this grid as a favorite that should be persisited on 'save'
+	// this is currently used to persist a grid after a successful login
+	void setFavorite() { mGridList[mGridName][GRID_IS_FAVORITE_VALUE] = TRUE; }
+	
 	bool isInProductionGrid();
+	void saveFavorites();
+	void clearFavorites();
+
+protected:
 
-private:
-	EGridInfo mGridChoice;
+	// helper function for adding the predefined grids
+	void addSystemGrid(const std::string& label, 
+					   const std::string& name, 
+					   const std::string& login, 
+					   const std::string& helper,
+					   const std::string& login_page,
+					   const std::string& login_id = "");	
+	
+	
 	std::string mGridName;
+	std::string mGridFile;
+	LLSD mGridList;
 };
 
 const S32 MAC_ADDRESS_BYTES = 6;
-extern unsigned char gMACAddress[MAC_ADDRESS_BYTES];		/* Flawfinder: ignore */
 
 #endif
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 3c79045cc5..ce7b45bc11 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4705,7 +4705,7 @@ BOOL LLViewerObject::permYouOwner() const
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLViewerLogin::getInstance()->isInProductionGrid()
+		if (!LLGridManager::getInstance()->isInProductionGrid()
             && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
 		{
 			return TRUE;
@@ -4742,7 +4742,7 @@ BOOL LLViewerObject::permOwnerModify() const
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLViewerLogin::getInstance()->isInProductionGrid()
+		if (!LLGridManager::getInstance()->isInProductionGrid()
             && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
 	{
 			return TRUE;
@@ -4766,7 +4766,7 @@ BOOL LLViewerObject::permModify() const
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLViewerLogin::getInstance()->isInProductionGrid()
+		if (!LLGridManager::getInstance()->isInProductionGrid()
             && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
 	{
 			return TRUE;
@@ -4790,7 +4790,7 @@ BOOL LLViewerObject::permCopy() const
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLViewerLogin::getInstance()->isInProductionGrid()
+		if (!LLGridManager::getInstance()->isInProductionGrid()
             && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
 		{
 			return TRUE;
@@ -4814,7 +4814,7 @@ BOOL LLViewerObject::permMove() const
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLViewerLogin::getInstance()->isInProductionGrid()
+		if (!LLGridManager::getInstance()->isInProductionGrid()
             && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
 		{
 			return TRUE;
@@ -4838,7 +4838,7 @@ BOOL LLViewerObject::permTransfer() const
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLViewerLogin::getInstance()->isInProductionGrid()
+		if (!LLGridManager::getInstance()->isInProductionGrid()
             && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
 		{
 			return TRUE;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 8059f866ba..3f9a10a4a6 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -767,9 +767,11 @@ void send_stats()
 	system["ram"] = (S32) gSysMemory.getPhysicalMemoryKB();
 	system["os"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
 	system["cpu"] = gSysCPU.getCPUString();
+	unsigned char MACAddress[MAC_ADDRESS_BYTES];
+	LLUUID::getNodeID(MACAddress);
 	std::string macAddressString = llformat("%02x-%02x-%02x-%02x-%02x-%02x",
-											gMACAddress[0],gMACAddress[1],gMACAddress[2],
-											gMACAddress[3],gMACAddress[4],gMACAddress[5]);
+											MACAddress[0],MACAddress[1],MACAddress[2],
+											MACAddress[3],MACAddress[4],MACAddress[5]);
 	system["mac_address"] = macAddressString;
 	system["serial_number"] = LLAppViewer::instance()->getSerialNumber();
 	std::string gpu_desc = llformat(
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 83cbc8a1f9..f8e08dbf7d 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1815,7 +1815,7 @@ void LLViewerWindow::setNormalControlsVisible( BOOL visible )
 
 		// ...and set the menu color appropriately.
 		setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT, 
-			LLViewerLogin::getInstance()->isInProductionGrid());
+			LLGridManager::getInstance()->isInProductionGrid());
 	}
         
 	if ( gStatusBar )
@@ -1836,15 +1836,15 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
     LLSD args;
     LLColor4 new_bg_color;
 
-    if(god_mode && LLViewerLogin::getInstance()->isInProductionGrid())
+    if(god_mode && LLGridManager::getInstance()->isInProductionGrid())
     {
         new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
     }
-    else if(god_mode && !LLViewerLogin::getInstance()->isInProductionGrid())
+    else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid())
     {
         new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
     }
-    else if(!god_mode && !LLViewerLogin::getInstance()->isInProductionGrid())
+    else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid())
     {
         new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
     }
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 423c46e14c..fc264a6fcf 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -1327,18 +1327,11 @@ void LLVoiceClient::connectorShutdown()
 	}
 }
 
-void LLVoiceClient::userAuthorized(const std::string& firstName, const std::string& lastName, const LLUUID &agentID)
+void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
 {
-	mAccountFirstName = firstName;
-	mAccountLastName = lastName;
+	LL_INFOS("Voice") << "name \"" << user_id << "\" , ID " << agentID << LL_ENDL;
 
-	mAccountDisplayName = firstName;
-	mAccountDisplayName += " ";
-	mAccountDisplayName += lastName;
-
-	LL_INFOS("Voice") << "name \"" << mAccountDisplayName << "\" , ID " << agentID << LL_ENDL;
-
-	sConnectingToAgni = LLViewerLogin::getInstance()->isInProductionGrid();
+	sConnectingToAgni = LLGridManager::getInstance()->isInProductionGrid();
 
 	mAccountName = nameFromID(agentID);
 }
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 724179847d..075834f7e0 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -428,10 +428,8 @@ static	void updatePosition(void);
 		void connectorShutdown();
 
 		void requestVoiceAccountProvision(S32 retries = 3);
-		void userAuthorized(
-			const std::string& firstName,
-			const std::string& lastName,
-			const LLUUID &agentID);
+	void userAuthorized(const std::string& user_id,
+						const LLUUID &agentID);
 		void login(
 			const std::string& account_name,
 			const std::string& password,
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index 7866f735c5..45b4d3cad3 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -146,7 +146,7 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url,
 	substitution["VERSION_BUILD"] = LLVersionInfo::getBuild();
 	substitution["CHANNEL"] = LLVersionInfo::getChannel();
 	substitution["LANGUAGE"] = LLUI::getLanguage();
-	substitution["GRID"] = LLViewerLogin::getInstance()->getGridLabel();
+	substitution["GRID"] = LLGridManager::getInstance()->getGridLabel();
 	substitution["OS"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
 	substitution["SESSION_ID"] = gAgent.getSessionID();
 
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 6187b8f1e2..6b6013a6ee 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -47,19 +47,19 @@ auto_resize="false"
 follows="left|bottom"
 name="login"
 layout="topleft"
-width="695"
-min_width="695"
+width="775"
+min_width="775"
 user_resize="false"
 height="80">
 <text
 follows="left|bottom"
 font="SansSerifSmall"
 height="16"
-name="first_name_text"
+name="username_text"
 top="20"
 left="20"
 width="150">
-First name:
+Username:
 </text>
 <line_editor
 follows="left|bottom"
@@ -68,31 +68,11 @@ height="22"
 label="First"
 left_delta="0"
 max_length="31"
-name="first_name_edit"
+name="username_edit"
 select_on_focus="true"
-tool_tip="[SECOND_LIFE] First Name"
+tool_tip="[SECOND_LIFE] Username"
 top_pad="0"
-   width="135" />
-  <text
-   follows="left|bottom"
-   font="SansSerifSmall"
-   height="16"
-   left_pad="8"
-   name="last_name_text"
-   top="20"
-   width="150">
-    Last name:   </text>
-<line_editor
-follows="left|bottom"
-handle_edit_keys_directly="true"
-height="22"
-label="Last"
-max_length="31"
-name="last_name_edit"
-select_on_focus="true"
-tool_tip="[SECOND_LIFE] Last Name"
-  top_pad="0"
-  width="135" />
+width="150" />
 <text
 follows="left|bottom"
 font="SansSerifSmall"
@@ -152,18 +132,7 @@ name="MyHome"
 label="&lt;Type region name&gt;"
 name="Typeregionname"   value="" />
 </combo_box>
-<combo_box
-allow_text_entry="true"
-font="SansSerifSmall"
-   follows="left|right|bottom"
-   height="23"
-layout="topleft"
-top_pad="2"
-name="server_combo"
-width="135"
-  visible="false" />
 <button
-  follows="left|bottom"
   height="23"
   image_unselected="PushButton_On"
   image_selected="PushButton_On_Selected"
@@ -174,6 +143,16 @@ width="135"
   name="connect_btn"
   top="35"
   width="90" />
+<combo_box
+follows="left|bottom"
+allow_text_entry="true"
+font="SansSerifSmall"
+height="23"
+name="server_combo"
+left_pad="15"
+width="200"
+max_chars="255"
+visible="false" />
 </layout_panel>
 <layout_panel
 follows="right|bottom"
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index 7b28a3b72c..9222882f5f 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -10,7 +10,10 @@
 // Precompiled header
 #include "../llviewerprecompiledheaders.h"
 // Own header
+#include "../llsecapi.h"
+#include "../llviewernetwork.h"
 #include "../lllogininstance.h"
+
 // STL headers
 // std headers
 // external library headers
@@ -54,17 +57,69 @@ void LLLogin::disconnect()
 	gDisconnectCalled = true;
 }
 
+LLSD LLCredential::getLoginParams()
+{
+	LLSD result = LLSD::emptyMap();
+
+	// legacy credential
+	result["passwd"] = "$1$testpasssd";
+	result["first"] = "myfirst";
+	result["last"] ="mylast";
+	return result;
+}
+
 //-----------------------------------------------------------------------------
 #include "../llviewernetwork.h"
-unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {'1','2','3','4','5','6'};		/* Flawfinder: ignore */
 
-LLViewerLogin::LLViewerLogin() {}
-LLViewerLogin::~LLViewerLogin() {}
-void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const 
+LLGridManager::~LLGridManager()
+{
+}
+
+void LLGridManager::addGrid(LLSD& grid_data)
+{
+}
+LLGridManager::LLGridManager()
+{	
+}
+
+void LLGridManager::getLoginURIs(std::vector<std::string>& uris)
 {
 	uris.push_back(VIEWERLOGIN_URI);
 }
-std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; }
+
+void LLGridManager::addSystemGrid(const std::string& label, 
+								  const std::string& name, 
+								  const std::string& login, 
+								  const std::string& helper,
+								  const std::string& login_page,
+								  const std::string& login_id)
+{
+}
+std::map<std::string, std::string> LLGridManager::getKnownGrids(bool favorite_only)
+{
+	std::map<std::string, std::string> result;
+	return result;
+}
+
+void LLGridManager::setGridChoice(const std::string& grid_name)
+{
+}
+
+bool LLGridManager::isInProductionGrid()
+{
+	return false;
+}
+
+void LLGridManager::saveFavorites()
+{}
+std::string LLGridManager::getSLURLBase(const std::string& grid_name)
+{
+	return "myslurl";
+}
+std::string LLGridManager::getAppSLURLBase(const std::string& grid_name)
+{
+	return "myappslurl";
+}
 
 //-----------------------------------------------------------------------------
 #include "../llviewercontrol.h"
@@ -197,15 +252,29 @@ namespace tut
 			gSavedSettings.declareString("NextLoginLocation", "", "", FALSE);
 			gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE);
 
-			credentials["first"] = "testfirst";
-			credentials["last"] = "testlast";
-			credentials["passwd"] = "testpass";
+			LLSD authenticator = LLSD::emptyMap();
+			LLSD identifier = LLSD::emptyMap();
+			identifier["type"] = "agent";
+			identifier["first_name"] = "testfirst";
+			identifier["last_name"] = "testlast";
+			authenticator["passwd"] = "testpass";
+			agentCredential = new LLCredential();
+			agentCredential->setCredentialData(identifier, authenticator);
+			
+			authenticator = LLSD::emptyMap();
+			identifier = LLSD::emptyMap();
+			identifier["type"] = "account";
+			identifier["username"] = "testuser";
+			authenticator["secret"] = "testsecret";
+			accountCredential = new LLCredential();
+			accountCredential->setCredentialData(identifier, authenticator);			
 
 			logininstance->setNotificationsInterface(&notifications);
 		}
 
 		LLLoginInstance* logininstance;
-		LLSD credentials;
+		LLPointer<LLCredential> agentCredential;
+		LLPointer<LLCredential> accountCredential;
 		MockNotifications notifications;
     };
 
@@ -219,7 +288,7 @@ namespace tut
 		set_test_name("Test Simple Success And Disconnect");
 
 		// Test default connect.
-		logininstance->connect(credentials);
+		logininstance->connect(agentCredential);
 
 		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
 
@@ -260,7 +329,7 @@ namespace tut
 		const std::string test_uri = "testing-uri";
 
 		// Test default connect.
-		logininstance->connect(test_uri, credentials);
+		logininstance->connect(test_uri, agentCredential);
 
 		// connect should call LLLogin::connect to init gLoginURI and gLoginCreds.
 		ensure_equals("Default connect uri", gLoginURI, "testing-uri"); 
@@ -282,7 +351,7 @@ namespace tut
 		ensure("No TOS, failed auth", logininstance->authFailure());
 
 		// Start again.
-		logininstance->connect(test_uri, credentials);
+		logininstance->connect(test_uri, agentCredential);
 		gTestPump.post(response); // Fail for tos again.
 		gTOSReplyPump->post(true); // Accept tos, should reconnect w/ agree_to_tos.
 		ensure_equals("Accepted agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), true);
@@ -294,11 +363,11 @@ namespace tut
 		gTestPump.post(response);
 		ensure("TOS auth failure", logininstance->authFailure());
 
-		logininstance->connect(test_uri, credentials);
+		logininstance->connect(test_uri, agentCredential);
 		ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false);
 
 		// Critical Message failure response.
-		logininstance->connect(test_uri, credentials);
+		logininstance->connect(test_uri, agentCredential);
 		response["data"]["reason"] = "critical"; // Change response to "critical message"
 		gTestPump.post(response);
 
@@ -312,7 +381,7 @@ namespace tut
 		response["data"]["reason"] = "key"; // bad creds.
 		gTestPump.post(response);
 		ensure("TOS auth failure", logininstance->authFailure());
-		logininstance->connect(test_uri, credentials);
+		logininstance->connect(test_uri, agentCredential);
 		ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false);
 	}
 
@@ -323,7 +392,7 @@ namespace tut
 
 		// Part 1 - Mandatory Update, with User accepts response.
 		// Test connect with update needed.
-		logininstance->connect(credentials);
+		logininstance->connect(agentCredential);
 
 		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
 
@@ -349,7 +418,7 @@ namespace tut
 		set_test_name("Test Mandatory Update User Decline");
 
 		// Test connect with update needed.
-		logininstance->connect(credentials);
+		logininstance->connect(agentCredential);
 
 		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
 
@@ -375,7 +444,7 @@ namespace tut
 
 		// Part 3 - Mandatory Update, with bogus response.
 		// Test connect with update needed.
-		logininstance->connect(credentials);
+		logininstance->connect(agentCredential);
 
 		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
 
@@ -401,7 +470,7 @@ namespace tut
 
 		// Part 3 - Mandatory Update, with bogus response.
 		// Test connect with update needed.
-		logininstance->connect(credentials);
+		logininstance->connect(agentCredential);
 
 		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
 
diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp
new file mode 100644
index 0000000000..a5554d55a5
--- /dev/null
+++ b/indra/newview/tests/llsechandler_basic_test.cpp
@@ -0,0 +1,456 @@
+/** 
+ * @file llsechandler_basic_test.cpp
+ * @author Roxie
+ * @date 2009-02-10
+ * @brief Test the 'basic' sec handler functions
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "../llviewerprecompiledheaders.h"
+#include "../test/lltut.h"
+#include "../llsecapi.h"
+#include "../llsechandler_basic.h"
+#include "../../llxml/llcontrol.h"
+#include "../llviewernetwork.h"
+#include "lluuid.h"
+#include "llxorcipher.h"
+#include "apr_base64.h"
+#include <vector>
+#include <ios>
+#include <llsdserialize.h>
+#include <openssl/pem.h>
+#include "llxorcipher.h"
+
+LLControlGroup gSavedSettings;
+unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {77,21,46,31,89,2};
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+	// Test wrapper declaration : wrapping nothing for the moment
+	struct sechandler_basic_test
+	{
+		std::string mPemTestCert;
+		std::string mDerFormat;
+		X509 *mX509TestCert;
+		LLBasicCertificate* mTestCert;
+
+		sechandler_basic_test()
+		{
+			LLFile::remove("test_password.dat");
+			LLFile::remove("sechandler_settings.tmp");			
+			mPemTestCert = "-----BEGIN CERTIFICATE-----\n"
+"MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx\n"
+"EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h\n"
+"bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy\n"
+"YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp\n"
+"Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy\n"
+"MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG\n"
+"A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt\n"
+"YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD\n"
+"VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB\n"
+"IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA\n"
+"isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj\n"
+"Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50\n"
+"QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt\n"
+"bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR\n"
+"yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID\n"
+"AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0\n"
+"cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f\n"
+"BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj\n"
+"cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB\n"
+"/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1\n"
+"U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl\n"
+"YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos\n"
+"SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/\n"
+"t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u\n"
+"mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb\n"
+"K+9A46sd33oqK8n8\n"
+"-----END CERTIFICATE-----\n"
+"";
+			mDerFormat = "MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIxEzARBgNVBAoT"
+"CklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25hbCBkZSBUZWNub2xvZ2lhIGRh"
+"IEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJyYXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UE"
+"AxMoQXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4"
+"MDBaFw0xMTExMzAyMzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9"
+"MDsGA1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3JtYWNhbyAt"
+"IElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYDVQQDEyhBdXRvcmlkYWRl"
+"IENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB"
+"CgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVAisamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma"
+"/3pUpgcfNAj0vYm5gsyjQo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt"
+"4CyNrY50QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYtbRhF"
+"boUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbURyEeNvZneVRKAAU6o"
+"uwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwIDAQABo4HSMIHPME4GA1UdIARHMEUw"
+"QwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQ"
+"Q2FjcmFpei5wZGYwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292"
+"LmJyL0xDUmFjcmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB"
+"/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1U/hgIh6OcgLA"
+"fiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGlYjJe+9zd+izPRbBqXPVQA34E"
+"Xcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75FosSzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQf"
+"S//JYeIc7Fue2JNLd00UOSMMaiK/t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr"
+"1ME7a55lFEnSeT0umlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5"
+"nmPbK+9A46sd33oqK8n8";
+			
+			mTestCert = new LLBasicCertificate(mPemTestCert);
+			
+			gSavedSettings.cleanup();
+			gSavedSettings.declareString("FirstName", "", "", FALSE);
+			gSavedSettings.declareString("LastName", "", "", FALSE);
+			mX509TestCert = NULL;
+			BIO * validation_bio = BIO_new_mem_buf((void*)mPemTestCert.c_str(), mPemTestCert.length());
+			
+			PEM_read_bio_X509(validation_bio, &mX509TestCert, 0, NULL);
+			BIO_free(validation_bio);
+
+		}
+		~sechandler_basic_test()
+		{
+			LLFile::remove("test_password.dat");
+			LLFile::remove("sechandler_settings.tmp");
+			delete mTestCert;
+			X509_free(mX509TestCert);
+		}
+	};
+	
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<sechandler_basic_test> sechandler_basic_test_factory;
+	typedef sechandler_basic_test_factory::object sechandler_basic_test_object;
+	tut::sechandler_basic_test_factory tut_test("llsechandler_basic");
+	
+	// ---------------------------------------------------------------------------------------
+	// Test functions 
+	// ---------------------------------------------------------------------------------------
+	// test cert data retrieval
+	template<> template<>
+	void sechandler_basic_test_object::test<1>()
+	
+	{
+
+		char buffer[4096];
+
+		ensure_equals("Resultant pem is correct",
+			   mPemTestCert, mTestCert->getPem());
+		std::vector<U8> binary_cert = mTestCert->getBinary();
+
+		apr_base64_encode(buffer, (const char *)&binary_cert[0], binary_cert.size());
+		
+		ensure_equals("Der Format is correct", memcmp(buffer, mDerFormat.c_str(), mDerFormat.length()), 0);
+		
+		LLSD llsd_cert = mTestCert->getLLSD();
+		std::ostringstream llsd_value;
+		llsd_value << LLSDOStreamer<LLSDNotationFormatter>(llsd_cert) << std::endl;
+		std::string llsd_cert_str = llsd_value.str();
+		ensure_equals("Issuer Name/commonName", 
+			   (std::string)llsd_cert["issuer_name"]["commonName"], "Autoridade Certificadora Raiz Brasileira");
+		ensure_equals("Issure Name/countryName", (std::string)llsd_cert["issuer_name"]["countryName"], "BR");
+		ensure_equals("Issuer Name/localityName", (std::string)llsd_cert["issuer_name"]["localityName"], "Brasilia");
+		ensure_equals("Issuer Name/org name", (std::string)llsd_cert["issuer_name"]["organizationName"], "ICP-Brasil");
+		ensure_equals("IssuerName/org unit", 
+			   (std::string)llsd_cert["issuer_name"]["organizationalUnitName"], "Instituto Nacional de Tecnologia da Informacao - ITI");
+		ensure_equals("IssuerName/state", (std::string)llsd_cert["issuer_name"]["stateOrProvinceName"], "DF");
+		ensure_equals("Issuer name string", 
+			   (std::string)llsd_cert["issuer_name_string"], "CN=Autoridade Certificadora Raiz Brasileira,ST=DF,"
+															   "L=Brasilia,OU=Instituto Nacional de Tecnologia da Informacao - ITI,O=ICP-Brasil,C=BR");
+		ensure_equals("subject Name/commonName", 
+			   (std::string)llsd_cert["subject_name"]["commonName"], "Autoridade Certificadora Raiz Brasileira");
+		ensure_equals("subject Name/countryName", (std::string)llsd_cert["subject_name"]["countryName"], "BR");
+		ensure_equals("subject Name/localityName", (std::string)llsd_cert["subject_name"]["localityName"], "Brasilia");
+		ensure_equals("subject Name/org name", (std::string)llsd_cert["subject_name"]["organizationName"], "ICP-Brasil");
+		ensure_equals("subjectName/org unit", 
+			   (std::string)llsd_cert["subject_name"]["organizationalUnitName"], "Instituto Nacional de Tecnologia da Informacao - ITI");
+		ensure_equals("subjectName/state", (std::string)llsd_cert["subject_name"]["stateOrProvinceName"], "DF");
+		ensure_equals("subject name string", 
+			   (std::string)llsd_cert["subject_name_string"], "CN=Autoridade Certificadora Raiz Brasileira,ST=DF,"
+			                                                    "L=Brasilia,OU=Instituto Nacional de Tecnologia da Informacao - ITI,O=ICP-Brasil,C=BR");
+		
+		ensure_equals("md5 digest", (std::string)llsd_cert["md5_digest"], "96:89:7d:61:d1:55:2b:27:e2:5a:39:b4:2a:6c:44:6f");
+		ensure_equals("serial number", (std::string)llsd_cert["serial_number"], "04");
+		// sha1 digest is giving a weird value, and I've no idea why...feh
+		//ensure_equals("sha1 digest", (std::string)llsd_cert["sha1_digest"], "8e:fd:ca:bc:93:e6:1e:92:5d:4d:1d:ed:18:1a:43:20:a4:67:a1:39");
+		ensure_equals("valid from", (std::string)llsd_cert["valid_from"], "2001-11-30T20:58:00Z");
+		ensure_equals("valid to", (std::string)llsd_cert["valid_to"], "2011-12-01T07:59:00Z");
+		
+		ensure("x509 is equal", !X509_cmp(mX509TestCert, mTestCert->getOpenSSLX509()));
+	}
+
+	
+	// test protected data
+	template<> template<>
+	void sechandler_basic_test_object::test<2>()
+
+	{
+		unsigned char MACAddress[MAC_ADDRESS_BYTES];
+		LLUUID::getNodeID(MACAddress);
+		
+		std::string protected_data = "sUSh3wj77NG9oAMyt3XIhaej3KLZhLZWFZvI6rIGmwUUOmmelrRg0NI9rkOj8ZDpTPxpwToaBT5u"
+		"GQhakdaGLJznr9bHr4/6HIC1bouKj4n2rs4TL6j2WSjto114QdlNfLsE8cbbE+ghww58g8SeyLQO"
+		"nyzXoz+/PBz0HD5SMFDuObccoPW24gmqYySz8YoEWhSwO0pUtEEqOjVRsAJgF5wLAtJZDeuilGsq"
+		"4ZT9Y4wZ9Rh8nnF3fDUL6IGamHe1ClXM1jgBu10F6UMhZbnH4C3aJ2E9+LiOntU+l3iCb2MpkEpr"
+		"82r2ZAMwIrpnirL/xoYoyz7MJQYwUuMvBPToZJrxNSsjI+S2Z+I3iEJAELMAAA==";
+		
+		std::vector<U8> binary_data(apr_base64_decode_len(protected_data.c_str()));
+		apr_base64_decode_binary(&binary_data[0], protected_data.c_str());
+
+		LLXORCipher cipher(gMACAddress, MAC_ADDRESS_BYTES);
+		cipher.decrypt(&binary_data[0], 16);
+		LLXORCipher cipher2(MACAddress, MAC_ADDRESS_BYTES);
+		cipher2.encrypt(&binary_data[0], 16);
+		std::ofstream temp_file("sechandler_settings.tmp", std::ofstream::binary);
+		temp_file.write((const char *)&binary_data[0], binary_data.size());
+		temp_file.close();
+
+		LLPointer<LLSecAPIBasicHandler> handler = new LLSecAPIBasicHandler("sechandler_settings.tmp",
+																		   "test_password.dat");
+		// data retrieval for existing data
+		LLSD data = handler->getProtectedData("test_data_type", "test_data_id");
+
+
+		ensure_equals("retrieve existing data1", (std::string)data["data1"], "test_data_1");
+		ensure_equals("retrieve existing data2", (std::string)data["data2"], "test_data_2");
+		ensure_equals("retrieve existing data3", (std::string)data["data3"]["elem1"], "test element1");
+		
+		// data storage
+		LLSD store_data = LLSD::emptyMap();
+		store_data["store_data1"] = "test_store_data1";
+		store_data["store_data2"] = 27;
+		store_data["store_data3"] = LLSD::emptyMap();
+		store_data["store_data3"]["subelem1"] = "test_subelem1";
+		
+		handler->setProtectedData("test_data_type", "test_data_id1", store_data);
+		data = handler->getProtectedData("test_data_type", "test_data_id");
+		
+		data = handler->getProtectedData("test_data_type", "test_data_id");
+		// verify no overwrite of existing data
+		ensure_equals("verify no overwrite 1", (std::string)data["data1"], "test_data_1");
+		ensure_equals("verify no overwrite 2", (std::string)data["data2"], "test_data_2");
+		ensure_equals("verify no overwrite 3", (std::string)data["data3"]["elem1"], "test element1");
+		
+		// verify written data is good
+		data = handler->getProtectedData("test_data_type", "test_data_id1");
+		ensure_equals("verify stored data1", (std::string)data["store_data1"], "test_store_data1");
+		ensure_equals("verify stored data2", (int)data["store_data2"], 27);
+		ensure_equals("verify stored data3", (std::string)data["store_data3"]["subelem1"], "test_subelem1");
+		
+		// verify overwrite works
+		handler->setProtectedData("test_data_type", "test_data_id", store_data);	
+		data = handler->getProtectedData("test_data_type", "test_data_id");
+		ensure_equals("verify overwrite stored data1", (std::string)data["store_data1"], "test_store_data1");
+		ensure_equals("verify overwrite stored data2", (int)data["store_data2"], 27);
+		ensure_equals("verify overwrite stored data3", (std::string)data["store_data3"]["subelem1"], "test_subelem1");
+		
+		// verify other datatype doesn't conflict
+		store_data["store_data3"] = "test_store_data3";
+		store_data["store_data4"] = 28;
+		store_data["store_data5"] = LLSD::emptyMap();
+		store_data["store_data5"]["subelem2"] = "test_subelem2";
+		
+		handler->setProtectedData("test_data_type1", "test_data_id", store_data);	
+		data = handler->getProtectedData("test_data_type1", "test_data_id");
+		ensure_equals("verify datatype stored data3", (std::string)data["store_data3"], "test_store_data3");
+		ensure_equals("verify datatype stored data4", (int)data["store_data4"], 28);
+		ensure_equals("verify datatype stored data5", (std::string)data["store_data5"]["subelem2"], "test_subelem2");	
+		
+		// test data not found
+
+		data = handler->getProtectedData("test_data_type1", "test_data_not_found");
+		ensure("not found", data.isUndefined());
+
+		// cause a 'write' by using 'LLPointer' to delete then instantiate a handler
+		handler = NULL;
+		handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat");
+
+		data = handler->getProtectedData("test_data_type1", "test_data_id");
+		ensure_equals("verify datatype stored data3a", (std::string)data["store_data3"], "test_store_data3");
+		ensure_equals("verify datatype stored data4a", (int)data["store_data4"], 28);
+		ensure_equals("verify datatype stored data5a", (std::string)data["store_data5"]["subelem2"], "test_subelem2");	
+		
+		// rewrite the initial file to verify reloads
+		handler = NULL;
+		std::ofstream temp_file2("sechandler_settings.tmp", std::ofstream::binary);
+		temp_file2.write((const char *)&binary_data[0], binary_data.size());
+		temp_file2.close();
+		
+		// cause a 'write'
+		handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat");
+		data = handler->getProtectedData("test_data_type1", "test_data_id");
+		ensure("not found", data.isUndefined());
+		
+		handler->deleteProtectedData("test_data_type", "test_data_id");
+		ensure("Deleted data not found", handler->getProtectedData("test_data_type", "test_data_id").isUndefined());
+		
+		LLFile::remove("sechandler_settings.tmp");
+		handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat");
+		data = handler->getProtectedData("test_data_type1", "test_data_id");
+		ensure("not found", data.isUndefined());
+		handler = NULL;
+		
+		ensure(LLFile::isfile("sechandler_settings.tmp"));
+	}
+	
+	// test credenitals
+	template<> template<>
+	void sechandler_basic_test_object::test<3>()
+	{
+		LLPointer<LLSecAPIBasicHandler> handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat");
+		
+
+		LLSD my_id = LLSD::emptyMap();
+		LLSD my_authenticator = LLSD::emptyMap();
+		my_id["type"] = "test_type";
+		my_id["username"] = "testuser@lindenlab.com";
+		my_authenticator["type"] = "test_auth";
+		my_authenticator["creds"] = "12345";
+
+		// test creation of credentials		
+		LLPointer<LLCredential> my_cred = handler->createCredential("my_grid", my_id, my_authenticator);
+
+		// test retrieval of credential components
+		ensure_equals("basic credential creation: identifier", my_id, my_cred->getIdentifier());
+		ensure_equals("basic credential creation: authenticator", my_authenticator, my_cred->getAuthenticator());
+		ensure_equals("basic credential creation: grid", "my_grid", my_cred->getGrid());
+		
+		// test setting/overwriting of credential components
+		my_id["first_name"] = "firstname";
+		my_id.erase("username");
+		my_authenticator.erase("creds");
+		my_authenticator["hash"] = "6563245";
+		
+		my_cred->setCredentialData(my_id, my_authenticator);
+		ensure_equals("set credential data: identifier", my_id, my_cred->getIdentifier());
+		ensure_equals("set credential data: authenticator", my_authenticator, my_cred->getAuthenticator());
+		ensure_equals("set credential data: grid", "my_grid", my_cred->getGrid());		
+			
+		// test loading of a credential, that hasn't been saved, without
+		// any legacy saved credential data
+		LLPointer<LLCredential> my_new_cred = handler->loadCredential("my_grid");
+		ensure("unknown credential load test", my_new_cred->getIdentifier().isMap());
+		ensure("unknown credential load test", !my_new_cred->getIdentifier().has("type"));		
+		ensure("unknown credential load test", my_new_cred->getAuthenticator().isMap());
+		ensure("unknown credential load test", !my_new_cred->getAuthenticator().has("type"));	
+		// test saving of a credential
+		handler->saveCredential(my_cred, true);
+
+		// test loading of a known credential
+		my_new_cred = handler->loadCredential("my_grid");
+		ensure_equals("load a known credential: identifier", my_id, my_new_cred->getIdentifier());
+		ensure_equals("load a known credential: authenticator",my_authenticator, my_new_cred->getAuthenticator());
+		ensure_equals("load a known credential: grid", "my_grid", my_cred->getGrid());
+	
+		// test deletion of a credential
+		handler->deleteCredential(my_new_cred);
+
+		ensure("delete credential: identifier", my_new_cred->getIdentifier().isUndefined());
+		ensure("delete credentialt: authenticator", my_new_cred->getIdentifier().isUndefined());
+		ensure_equals("delete credential: grid", "my_grid", my_cred->getGrid());		
+		// load unknown cred
+		
+		my_new_cred = handler->loadCredential("my_grid");
+		ensure("deleted credential load test", my_new_cred->getIdentifier().isMap());
+		ensure("deleted credential load test", !my_new_cred->getIdentifier().has("type"));		
+		ensure("deleted credential load test", my_new_cred->getAuthenticator().isMap());
+		ensure("deleted credential load test", !my_new_cred->getAuthenticator().has("type"));
+		
+		// test loading of an unknown credential with legacy saved username, but without
+		// saved password
+
+		gSavedSettings.setString("FirstName", "myfirstname");
+		gSavedSettings.setString("LastName", "mylastname");
+
+		my_new_cred = handler->loadCredential("my_legacy_grid");
+		ensure_equals("legacy credential with no password: type", 
+					  (const std::string)my_new_cred->getIdentifier()["type"], "agent");
+		ensure_equals("legacy credential with no password: first_name", 
+					  (const std::string)my_new_cred->getIdentifier()["first_name"], "myfirstname");
+		ensure_equals("legacy credential with no password: last_name",
+					  (const std::string)my_new_cred->getIdentifier()["last_name"], "mylastname");
+		
+		ensure("legacy credential with no password: no authenticator", my_new_cred->getAuthenticator().isUndefined());
+		
+		// test loading of an unknown credential with legacy saved password and username
+
+		std::string hashed_password = "fSQcLG03eyIWJmkzfyYaKm81dSweLmsxeSAYKGE7fSQ=";		
+		int length = apr_base64_decode_len(hashed_password.c_str());
+		std::vector<char> decoded_password(length);
+		apr_base64_decode(&decoded_password[0], hashed_password.c_str());
+		unsigned char MACAddress[MAC_ADDRESS_BYTES];
+		LLUUID::getNodeID(MACAddress);
+		LLXORCipher cipher(gMACAddress, MAC_ADDRESS_BYTES);
+		cipher.decrypt((U8*)&decoded_password[0], length);
+		LLXORCipher cipher2(MACAddress, MAC_ADDRESS_BYTES);
+		cipher2.encrypt((U8*)&decoded_password[0], length);
+		llofstream password_file("test_password.dat", std::ofstream::binary);
+		password_file.write(&decoded_password[0], length); 
+		password_file.close();
+		
+		my_new_cred = handler->loadCredential("my_legacy_grid2");		
+		ensure_equals("legacy credential with password: type", 
+					  (const std::string)my_new_cred->getIdentifier()["type"], "agent");
+		ensure_equals("legacy credential with password: first_name", 
+					  (const std::string)my_new_cred->getIdentifier()["first_name"], "myfirstname");
+		ensure_equals("legacy credential with password: last_name",
+					  (const std::string)my_new_cred->getIdentifier()["last_name"], "mylastname");
+		
+		LLSD legacy_authenticator = my_new_cred->getAuthenticator();
+		ensure_equals("legacy credential with password: type", 
+					  (std::string)legacy_authenticator["type"], 
+					  "hash");
+		ensure_equals("legacy credential with password: algorithm", 
+					  (std::string)legacy_authenticator["algorithm"], 
+					  "md5");	
+		ensure_equals("legacy credential with password: algorithm", 
+					  (std::string)legacy_authenticator["secret"], 
+					  "01234567890123456789012345678901");
+		
+		// test creation of credentials		
+		my_cred = handler->createCredential("mysavedgrid", my_id, my_authenticator);
+		// test save without saving authenticator. 		
+		handler->saveCredential(my_cred, FALSE);
+		my_new_cred = handler->loadCredential("mysavedgrid");	
+		ensure_equals("saved credential without auth", 
+					  (const std::string)my_new_cred->getIdentifier()["type"], "test_type");
+		ensure("no authenticator values were saved", my_new_cred->getAuthenticator().isUndefined());
+	}
+
+
+	// test cert store
+	template<> template<>
+	void sechandler_basic_test_object::test<4>()
+	{
+		// instantiate a cert store from a file
+		llofstream certstorefile("mycertstore.pem", std::ios::out | std::ios::binary);
+
+		certstorefile << mPemTestCert;
+		certstorefile.close();
+		// LLBasicCertificateStore test_store("mycertstore.pem");
+		// X509* test_cert = test_store[0]->getOpenSSLX509();
+
+		// ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509TestCert));
+	}
+};
diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp
new file mode 100644
index 0000000000..c7a6b2ad15
--- /dev/null
+++ b/indra/newview/tests/llviewernetwork_test.cpp
@@ -0,0 +1,446 @@
+/** 
+ * @file llviewernetwork_test.cpp
+ * @author Roxie
+ * @date 2009-03-9
+ * @brief Test the viewernetwork functionality
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden LregisterSecAPIab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "../llviewerprecompiledheaders.h"
+#include "../llviewernetwork.h"
+#include "../test/lltut.h"
+#include "../../llxml/llcontrol.h"
+#include "llfile.h"
+
+LLControlGroup gSavedSettings;
+const char *gSampleGridFile = "<llsd><map>"
+"<key>grid1</key><map>"
+"  <key>favorite</key><integer>1</integer>"
+"  <key>helper_uri</key><string>https://helper1/helpers/</string>"
+"  <key>label</key><string>mylabel</string>"
+"  <key>login_page</key><string>loginpage</string>"
+"  <key>login_uri</key><array><string>myloginuri</string></array>"
+"  <key>name</key><string>grid1</string>"
+"  <key>visible</key><integer>1</integer>"
+"  <key>credential_type</key><string>agent</string>"
+"  <key>grid_login_id</key><string>MyGrid</string>"
+"</map>"
+"<key>util.agni.lindenlab.com</key><map>"
+"  <key>favorite</key><integer>1</integer>"
+"  <key>helper_uri</key><string>https://helper1/helpers/</string>"
+"  <key>label</key><string>mylabel</string>"
+"  <key>login_page</key><string>loginpage</string>"
+"  <key>login_uri</key><array><string>myloginuri</string></array>"
+"  <key>name</key><string>util.agni.lindenlab.com</string>"
+"</map></map></llsd>";
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+  // Test wrapper declaration : wrapping nothing for the moment
+  struct viewerNetworkTest
+	{
+		viewerNetworkTest()
+		{
+			gSavedSettings.cleanup();
+			gSavedSettings.cleanup();
+			gSavedSettings.declareString("CmdLineGridChoice", "", "", FALSE);
+			gSavedSettings.declareString("CmdLineHelperURI", "", "", FALSE);
+			gSavedSettings.declareString("LoginPage", "", "", FALSE);
+			gSavedSettings.declareString("CurrentGrid", "", "", FALSE);
+			gSavedSettings.declareLLSD("CmdLineLoginURI", LLSD(), "", FALSE);
+		}
+		~viewerNetworkTest()
+		{
+			LLFile::remove("grid_test.xml");
+		}
+	};
+	
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<viewerNetworkTest> viewerNetworkTestFactory;
+	typedef viewerNetworkTestFactory::object viewerNetworkTestObject;
+	tut::viewerNetworkTestFactory tut_test("llviewernetwork");
+	
+	// ---------------------------------------------------------------------------------------
+	// Test functions 
+	// ---------------------------------------------------------------------------------------
+	// initialization without a grid file
+	template<> template<>
+	void viewerNetworkTestObject::test<1>()
+	{
+
+		LLGridManager manager("grid_test.xml");
+		// validate that some of the defaults are available.
+		std::map<std::string, std::string> known_grids = manager.getKnownGrids();
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("Known grids is a string-string map of size 18", known_grids.size(), 18);
+#else // LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("Known grids is a string-string map of size 18", known_grids.size(), 2);
+#endif // LL_RELEASE_FOR_DOWNLOAD
+
+		ensure_equals("Agni has the right name and label", 
+					  known_grids[std::string("util.agni.lindenlab.com")], std::string("Agni"));
+		ensure_equals("None exists", known_grids[""], "None");
+		
+		LLSD grid = manager.getGridInfo("util.agni.lindenlab.com");
+		ensure("Grid info for agni is a map", grid.isMap());
+		ensure_equals("name is correct for agni", 
+					  grid[GRID_NAME_VALUE].asString(), std::string("util.agni.lindenlab.com"));
+#ifndef LL_RELEASE_FOR_DOWNLOAD		
+		ensure_equals("label is correct for agni", 
+					  grid[GRID_LABEL_VALUE].asString(), std::string("Agni"));
+#else // LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("label is correct for agni", 
+					  grid[GRID_LABEL_VALUE].asString(), std::string("Secondlife.com"));		
+#endif // LL_RELEASE_FOR_DOWNLOAD
+		ensure("Login URI is an array", 
+			   grid[GRID_LOGIN_URI_VALUE].isArray());
+		ensure_equals("Agni login uri is correct", 
+					  grid[GRID_LOGIN_URI_VALUE][0].asString(), 
+					  std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi"));
+		ensure_equals("Agni helper uri is correct",
+					  grid[GRID_HELPER_URI_VALUE].asString(), 
+					  std::string("https://secondlife.com/helpers/"));
+		ensure_equals("Agni login page is correct",
+					  grid[GRID_LOGIN_PAGE_VALUE].asString(), 
+					  std::string("http://secondlife.com/app/login/"));
+		ensure("Agni is not a favorite",
+			   !grid.has(GRID_IS_FAVORITE_VALUE));
+		ensure("Agni is a system grid", 
+			   grid.has(GRID_IS_SYSTEM_GRID_VALUE));
+		ensure("Grid file wasn't greated as it wasn't saved", 
+			   !LLFile::isfile("grid_test.xml"));
+	}
+	
+	// initialization with a grid file
+	template<> template<>
+	void viewerNetworkTestObject::test<2>()
+	{
+		llofstream gridfile("grid_test.xml");
+		gridfile << gSampleGridFile;
+		gridfile.close();
+		
+		LLGridManager manager("grid_test.xml");
+		std::map<std::string, std::string> known_grids = manager.getKnownGrids();
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("adding a grid via a grid file increases known grid size", 
+					  known_grids.size(), 19);
+#else
+		ensure_equals("adding a grid via a grid file increases known grid size", 
+					  known_grids.size(), 3);
+#endif
+		ensure_equals("Agni is still there after we've added a grid via a grid file", 
+					  known_grids["util.agni.lindenlab.com"], std::string("Agni"));
+	
+		// assure Agni doesn't get overwritten
+		LLSD grid = manager.getGridInfo("util.agni.lindenlab.com");
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("Agni grid label was not modified by grid file", 
+					  grid[GRID_LABEL_VALUE].asString(), std::string("Agni"));
+#else \\ LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("Agni grid label was not modified by grid file", 
+					  grid[GRID_LABEL_VALUE].asString(), std::string("Secondlife.com"));
+#endif \\ LL_RELEASE_FOR_DOWNLOAD
+		
+		ensure_equals("Agni name wasn't modified by grid file",
+					  grid[GRID_NAME_VALUE].asString(), std::string("util.agni.lindenlab.com"));
+		ensure("Agni grid URI is still an array after grid file", 
+			   grid[GRID_LOGIN_URI_VALUE].isArray());
+		ensure_equals("Agni login uri still the same after grid file", 
+					  grid[GRID_LOGIN_URI_VALUE][0].asString(),  
+					  std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi"));
+		ensure_equals("Agni helper uri still the same after grid file", 
+					  grid[GRID_HELPER_URI_VALUE].asString(), 
+					  std::string("https://secondlife.com/helpers/"));
+		ensure_equals("Agni login page the same after grid file", 
+					  grid[GRID_LOGIN_PAGE_VALUE].asString(), 
+					  std::string("http://secondlife.com/app/login/"));
+		ensure("Agni still not favorite after grid file", 
+			   !grid.has(GRID_IS_FAVORITE_VALUE));
+		ensure("Agni system grid still set after grid file", 
+			   grid.has(GRID_IS_SYSTEM_GRID_VALUE));
+		
+		ensure_equals("Grid file adds to name<->label map", 
+					  known_grids["grid1"], std::string("mylabel"));
+		grid = manager.getGridInfo("grid1");
+		ensure_equals("grid file grid name is set",
+					  grid[GRID_NAME_VALUE].asString(), std::string("grid1"));
+		ensure_equals("grid file label is set", 
+					  grid[GRID_LABEL_VALUE].asString(), std::string("mylabel"));
+		ensure("grid file login uri is an array",
+			   grid[GRID_LOGIN_URI_VALUE].isArray());
+		ensure_equals("grid file login uri is set",
+					  grid[GRID_LOGIN_URI_VALUE][0].asString(), 
+					  std::string("myloginuri"));
+		ensure_equals("grid file helper uri is set",
+					  grid[GRID_HELPER_URI_VALUE].asString(), 
+					  std::string("https://helper1/helpers/"));
+		ensure_equals("grid file login page is set",
+					  grid[GRID_LOGIN_PAGE_VALUE].asString(), 
+					  std::string("loginpage"));
+		ensure("grid file favorite is set",
+			   grid.has(GRID_IS_FAVORITE_VALUE));
+		ensure("grid file isn't a system grid",
+			   !grid.has(GRID_IS_SYSTEM_GRID_VALUE));		
+		ensure("Grid file still exists after loading", 
+			   LLFile::isfile("grid_test.xml"));
+	}
+	
+	// Initialize via command line
+	
+	template<> template<>
+	void viewerNetworkTestObject::test<3>()
+	{	
+		LLSD loginURI = std::string("https://my.login.uri/cgi-bin/login.cgi");
+		gSavedSettings.setLLSD("CmdLineLoginURI", loginURI);
+		LLGridManager manager("grid_test.xml");
+		
+		// with single login uri specified.
+		std::map<std::string, std::string> known_grids = manager.getKnownGrids();
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("adding a command line grid increases known grid size", 
+					  known_grids.size(), 19);
+#else
+		ensure_equals("adding a command line grid increases known grid size", 
+					  known_grids.size(), 3);
+#endif
+		ensure_equals("Command line grid is added to the list of grids", 
+					  known_grids["my.login.uri"], std::string("my.login.uri"));
+		LLSD grid = manager.getGridInfo("my.login.uri");
+		ensure_equals("Command line grid name is set",
+					  grid[GRID_NAME_VALUE].asString(), std::string("my.login.uri"));
+		ensure_equals("Command line grid label is set", 
+					  grid[GRID_LABEL_VALUE].asString(), std::string("my.login.uri"));
+		ensure("Command line grid login uri is an array",
+			   grid[GRID_LOGIN_URI_VALUE].isArray());
+		ensure_equals("Command line grid login uri is set",
+					  grid[GRID_LOGIN_URI_VALUE][0].asString(), 
+					  std::string("https://my.login.uri/cgi-bin/login.cgi"));
+		ensure_equals("Command line grid helper uri is set",
+					  grid[GRID_HELPER_URI_VALUE].asString(), 
+					  std::string("https://my.login.uri/helpers/"));
+		ensure_equals("Command line grid login page is set",
+					  grid[GRID_LOGIN_PAGE_VALUE].asString(), 
+					  std::string("http://my.login.uri/app/login/"));
+		ensure("Command line grid favorite is set",
+			   !grid.has(GRID_IS_FAVORITE_VALUE));
+		ensure("Command line grid isn't a system grid",
+			   !grid.has(GRID_IS_SYSTEM_GRID_VALUE));		
+		
+		// now try a command line with a custom grid identifier
+		gSavedSettings.setString("CmdLineGridChoice", "mycustomgridchoice");
+		manager = LLGridManager("grid_test.xml");
+		known_grids = manager.getKnownGrids();
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("adding a command line grid with custom name increases known grid size", 
+					  known_grids.size(), 19);
+#else
+		ensure_equals("adding a command line grid with custom name inceases known grid size", 
+					  known_grids.size(), 3);
+#endif
+		ensure_equals("Custom Command line grid is added to the list of grids", 
+					  known_grids["mycustomgridchoice"], std::string("mycustomgridchoice"));
+		grid = manager.getGridInfo("mycustomgridchoice");
+		ensure_equals("Custom Command line grid name is set",
+					  grid[GRID_NAME_VALUE].asString(), std::string("mycustomgridchoice"));
+		ensure_equals("Custom Command line grid label is set", 
+					  grid[GRID_LABEL_VALUE].asString(), std::string("mycustomgridchoice"));		
+		ensure("Custom Command line grid login uri is an array",
+			   grid[GRID_LOGIN_URI_VALUE].isArray());
+		ensure_equals("Custom Command line grid login uri is set",
+					  grid[GRID_LOGIN_URI_VALUE][0].asString(), 
+					  std::string("https://my.login.uri/cgi-bin/login.cgi"));
+		
+		// add a helperuri
+		gSavedSettings.setString("CmdLineHelperURI", "myhelperuri");
+		manager = LLGridManager("grid_test.xml");
+		grid = manager.getGridInfo("mycustomgridchoice");		
+		ensure_equals("Validate command line helper uri", 
+					  grid[GRID_HELPER_URI_VALUE].asString(), std::string("myhelperuri"));		
+		
+		// add a login page
+		gSavedSettings.setString("LoginPage", "myloginpage");
+		manager = LLGridManager("grid_test.xml");
+		grid = manager.getGridInfo("mycustomgridchoice");		
+		ensure_equals("Validate command line helper uri", 
+					  grid[GRID_LOGIN_PAGE_VALUE].asString(), std::string("myloginpage"));			
+	}
+	
+	// validate grid selection
+	template<> template<>
+	void viewerNetworkTestObject::test<4>()
+	{	
+		LLSD loginURI = LLSD::emptyArray();
+		LLSD grid = LLSD::emptyMap();
+		// adding a grid with simply a name will populate the values.
+		grid[GRID_NAME_VALUE] = "myaddedgrid";
+
+		loginURI.append(std::string("https://my.login.uri/cgi-bin/login.cgi"));
+		gSavedSettings.setLLSD("CmdLineLoginURI", loginURI);
+		LLGridManager manager("grid_test.xml");
+		manager.addGrid(grid);
+		manager.setGridChoice("util.agni.lindenlab.com");
+#ifndef LL_RELEASE_FOR_DOWNLOAD		
+		ensure_equals("getGridLabel", manager.getGridLabel(), std::string("Agni"));
+#else // LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("getGridLabel", manager.getGridLabel(), std::string("Secondlife.com"));		
+#endif // LL_RELEASE_FOR_DOWNLOAD
+		ensure_equals("getGridName", manager.getGridName(), 
+					  std::string("util.agni.lindenlab.com"));
+		ensure_equals("getHelperURI", manager.getHelperURI(), 
+					  std::string("https://secondlife.com/helpers/"));
+		ensure_equals("getLoginPage", manager.getLoginPage(), 
+					  std::string("http://secondlife.com/app/login/"));
+		ensure_equals("getLoginPage2", manager.getLoginPage("util.agni.lindenlab.com"), 
+					  std::string("http://secondlife.com/app/login/"));
+		ensure("Is Agni a production grid", manager.isInProductionGrid());		
+		std::vector<std::string> uris;
+		manager.getLoginURIs(uris);
+		ensure_equals("getLoginURIs size", uris.size(), 1);
+		ensure_equals("getLoginURIs", uris[0], 
+					  std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi"));
+		manager.setGridChoice("myaddedgrid");
+		ensure_equals("getGridLabel", manager.getGridLabel(), std::string("myaddedgrid"));		
+		ensure("Is myaddedgrid a production grid", !manager.isInProductionGrid());
+		
+		manager.setFavorite();
+		grid = manager.getGridInfo("myaddedgrid");
+		ensure("setting favorite", grid.has(GRID_IS_FAVORITE_VALUE));
+	}
+	
+	// name based grid population
+	template<> template<>
+	void viewerNetworkTestObject::test<5>()
+	{
+		LLGridManager manager("grid_test.xml");
+		LLSD grid = LLSD::emptyMap();
+		// adding a grid with simply a name will populate the values.
+		grid[GRID_NAME_VALUE] = "myaddedgrid";
+		manager.addGrid(grid);
+		grid = manager.getGridInfo("myaddedgrid");
+		
+		ensure_equals("name based grid has name value", 
+					  grid[GRID_NAME_VALUE].asString(),
+					  std::string("myaddedgrid"));
+		ensure_equals("name based grid has label value", 
+					  grid[GRID_LABEL_VALUE].asString(),
+					  std::string("myaddedgrid"));
+		ensure_equals("name based grid has name value", 
+					  grid[GRID_HELPER_URI_VALUE].asString(),
+					  std::string("https://myaddedgrid/helpers/"));
+		ensure_equals("name based grid has name value", 
+					  grid[GRID_LOGIN_PAGE_VALUE].asString(),
+					  std::string("http://myaddedgrid/app/login/"));
+		ensure("name based grid has array loginuri", 
+			   grid[GRID_LOGIN_URI_VALUE].isArray());
+		ensure_equals("name based grid has single login uri value",
+			   grid[GRID_LOGIN_URI_VALUE].size(), 1);
+		ensure_equals("Name based grid login uri is correct",
+					  grid[GRID_LOGIN_URI_VALUE][0].asString(),
+					  std::string("https://myaddedgrid/cgi-bin/login.cgi"));
+		ensure("name based grid is not a favorite yet", 
+			   !grid.has(GRID_IS_FAVORITE_VALUE));
+		ensure("name based grid does not have system setting",
+			   !grid.has(GRID_IS_SYSTEM_GRID_VALUE));
+		
+		llofstream gridfile("grid_test.xml");
+		gridfile << gSampleGridFile;
+		gridfile.close();
+	}
+	
+	// persistence of the grid list with an empty gridfile.
+	template<> template<>
+	void viewerNetworkTestObject::test<6>()
+	{
+		// try with initial grid list without a grid file,
+		// without setting the grid to a saveable favorite.
+		LLGridManager manager("grid_test.xml");
+		LLSD grid = LLSD::emptyMap();
+		grid[GRID_NAME_VALUE] = std::string("mynewgridname");
+		manager.addGrid(grid);
+		manager.saveFavorites();
+		ensure("Grid file exists after saving", 
+			   LLFile::isfile("grid_test.xml"));
+		manager = LLGridManager("grid_test.xml");
+		// should not be there
+		std::map<std::string, std::string> known_grids = manager.getKnownGrids();
+		ensure("New grid wasn't added to persisted list without being marked a favorite",
+					  known_grids.find(std::string("mynewgridname")) == known_grids.end());
+		
+		// mark a grid a favorite to make sure it's persisted
+		manager.addGrid(grid);
+		manager.setGridChoice("mynewgridname");
+		manager.setFavorite();
+		manager.saveFavorites();
+		ensure("Grid file exists after saving", 
+			   LLFile::isfile("grid_test.xml"));
+		manager = LLGridManager("grid_test.xml");
+		// should not be there
+		known_grids = manager.getKnownGrids();
+		ensure("New grid wasn't added to persisted list after being marked a favorite",
+					  known_grids.find(std::string("mynewgridname")) !=
+					  known_grids.end());
+	}
+	
+	// persistence of the grid file with existing gridfile
+	template<> template<>
+	void viewerNetworkTestObject::test<7>()
+	{
+		
+		llofstream gridfile("grid_test.xml");
+		gridfile << gSampleGridFile;
+		gridfile.close();
+		
+		LLGridManager manager("grid_test.xml");
+		LLSD grid = LLSD::emptyMap();
+		grid[GRID_NAME_VALUE] = std::string("mynewgridname");
+		manager.addGrid(grid);
+		manager.saveFavorites();
+		// validate we didn't lose existing favorites
+		manager = LLGridManager("grid_test.xml");
+		std::map<std::string, std::string> known_grids = manager.getKnownGrids();
+		ensure("New grid wasn't added to persisted list after being marked a favorite",
+			   known_grids.find(std::string("grid1")) !=
+			   known_grids.end());
+		
+		// add a grid
+		manager.addGrid(grid);
+		manager.setGridChoice("mynewgridname");
+		manager.setFavorite();
+		manager.saveFavorites();
+		known_grids = manager.getKnownGrids();
+		ensure("New grid wasn't added to persisted list after being marked a favorite",
+			   known_grids.find(std::string("grid1")) !=
+			   known_grids.end());
+		known_grids = manager.getKnownGrids();
+		ensure("New grid wasn't added to persisted list after being marked a favorite",
+			   known_grids.find(std::string("mynewgridname")) !=
+			   known_grids.end());
+	}
+}
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index f5bda71846..7723c3ca8f 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -122,29 +122,34 @@ private:
 	LLSD mAuthResponse, mValidAuthResponse;
 };
 
-void LLLogin::Impl::connect(const std::string& uri, const LLSD& credentials)
+void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
 {
+    LL_DEBUGS("LLLogin") << " connect with  uri '" << uri << "', login_params " << login_params << LL_ENDL;
+	
     // Launch a coroutine with our login_() method. Run the coroutine until
     // its first wait; at that point, return here.
     std::string coroname = 
         LLCoros::instance().launch("LLLogin::Impl::login_",
-                                   boost::bind(&Impl::login_, this, _1, uri, credentials));
+                                   boost::bind(&Impl::login_, this, _1, uri, login_params));
 }
 
-void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credentials)
+void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_params)
 {
-	LLSD printable_credentials = credentials;
-	if(printable_credentials.has("params") 
-		&& printable_credentials["params"].has("passwd")) 
+	try
 	{
-		printable_credentials["params"]["passwd"] = "*******";
-	}
+	LLSD printable_params = login_params;
+	//if(printable_params.has("params") 
+	//	&& printable_params["params"].has("passwd")) 
+	//{
+	//	printable_params["params"]["passwd"] = "*******";
+	//}
     LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
-                        << " with uri '" << uri << "', credentials " << printable_credentials << LL_ENDL;
+                        << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL;
 
 	// Arriving in SRVRequest state
     LLEventStream replyPump("reply", true);
     // Should be an array of one or more uri strings.
+
     LLSD rewrittenURIs;
     {
         LLEventTimeout filter(replyPump);
@@ -155,9 +160,9 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
 
         // *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
 		F32 seconds_to_timeout = 5.0f;
-		if(credentials.has("cfg_srv_timeout"))
+		if(login_params.has("cfg_srv_timeout"))
 		{
-			seconds_to_timeout = credentials["cfg_srv_timeout"].asReal();
+			seconds_to_timeout = login_params["cfg_srv_timeout"].asReal();
 		}
 
         // If the SRV request times out (e.g. EXT-3934), simulate response: an
@@ -167,9 +172,9 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
 		filter.eventAfter(seconds_to_timeout, fakeResponse);
 
 		std::string srv_pump_name = "LLAres";
-		if(credentials.has("cfg_srv_pump"))
+		if(login_params.has("cfg_srv_pump"))
 		{
-			srv_pump_name = credentials["cfg_srv_pump"].asString();
+			srv_pump_name = login_params["cfg_srv_pump"].asString();
 		}
 
 		// Make request
@@ -190,7 +195,7 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
              urend(rewrittenURIs.endArray());
          urit != urend; ++urit)
     {
-        LLSD request(credentials);
+        LLSD request(login_params);
         request["reply"] = replyPump.getName();
         request["uri"] = *urit;
         std::string status;
@@ -289,6 +294,10 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
 	error_response["reason"] = mAuthResponse["status"];
 	error_response["message"] = mAuthResponse["error"];
 	sendProgressEvent("offline", "fail.login", error_response);
+	}
+	catch (...) {
+		llerrs << "login exception caught" << llendl; 
+	}
 }
 
 void LLLogin::Impl::disconnect()
-- 
GitLab