diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index 029b697e83b5721a7ded44fbd00b8e785edc57bf..2408fab96f1cbfa41ec2c08d497cbfd7672269b6 100644
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -38,6 +38,7 @@
 import shutil
 import sys
 import tarfile
+import errno
 
 def path_ancestors(path):
     path = os.path.normpath(path)
@@ -463,6 +464,12 @@ def ccopy(self, src, dst):
                 return
             # only copy if it's not excluded
             if(self.includes(src, dst)):
+                try:
+                    os.unlink(dst)
+                except OSError, err:
+                    if err.errno != errno.ENOENT:
+                        raise
+
                 shutil.copy2(src, dst)
 
     def ccopytree(self, src, dst):
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp
index df790433df41dad6756ec7c5f235e0b9440b7843..5e4dec7f82ce3f57b41b713676386089d5c7c360 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -40,6 +40,8 @@
   
 #include "../llmath/lluuid.h"
 
+// system includes
+#include <boost/tokenizer.hpp>
 
 // static
 std::string LLURI::escape(const std::string& str, const std::string & allowed)
@@ -130,7 +132,7 @@ LLURI::LLURI()
 
 LLURI::LLURI(const std::string& escaped_str)
 {
-	std::string::size_type delim_pos, delim_pos2;
+	std::string::size_type delim_pos;
 	delim_pos = escaped_str.find(':');
 	std::string temp;
 	if (delim_pos == std::string::npos)
@@ -144,13 +146,39 @@ LLURI::LLURI(const std::string& escaped_str)
 		mEscapedOpaque = escaped_str.substr(delim_pos+1);
 	}
 
-	if (mScheme == "http" || mScheme == "https" || mScheme == "ftp")
+	parseAuthorityAndPathUsingOpaque();
+
+	delim_pos = mEscapedPath.find('?');
+	if (delim_pos != std::string::npos)
+	{
+		mEscapedQuery = mEscapedPath.substr(delim_pos+1);
+		mEscapedPath = mEscapedPath.substr(0,delim_pos);
+	}
+}
+
+static BOOL isDefault(const std::string& scheme, U16 port)
+{
+	if (scheme == "http")
+		return port == 80;
+	if (scheme == "https")
+		return port == 443;
+	if (scheme == "ftp")
+		return port == 21;
+
+	return FALSE;
+}
+
+void LLURI::parseAuthorityAndPathUsingOpaque()
+{
+	if (mScheme == "http" || mScheme == "https" ||
+		mScheme == "ftp" || mScheme == "secondlife" )
 	{
 		if (mEscapedOpaque.substr(0,2) != "//")
 		{
 			return;
 		}
-		
+
+		std::string::size_type delim_pos, delim_pos2;
 		delim_pos = mEscapedOpaque.find('/', 2);
 		delim_pos2 = mEscapedOpaque.find('?', 2);
 		// no path, no query
@@ -182,27 +210,12 @@ LLURI::LLURI(const std::string& escaped_str)
 			mEscapedPath = mEscapedOpaque.substr(delim_pos);
 		}
 	}
-
-	delim_pos = mEscapedPath.find('?');
-	if (delim_pos != std::string::npos)
+	else if (mScheme == "about")
 	{
-		mEscapedQuery = mEscapedPath.substr(delim_pos+1);
-		mEscapedPath = mEscapedPath.substr(0,delim_pos);
+		mEscapedPath = mEscapedOpaque;
 	}
 }
 
-static BOOL isDefault(const std::string& scheme, U16 port)
-{
-	if (scheme == "http")
-		return port == 80;
-	if (scheme == "https")
-		return port == 443;
-	if (scheme == "ftp")
-		return port == 21;
-
-	return FALSE;
-}
-
 LLURI::LLURI(const std::string& scheme,
 			 const std::string& userName,
 			 const std::string& password,
@@ -440,6 +453,22 @@ std::string LLURI::path() const
 	return unescape(mEscapedPath);
 }
 
+LLSD LLURI::pathArray() const
+{
+	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+	boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
+	tokenizer tokens(mEscapedPath, sep);
+	tokenizer::iterator it = tokens.begin();
+	tokenizer::iterator end = tokens.end();
+
+	LLSD params;
+	for ( ; it != end; ++it)
+	{
+		params.append(*it);
+	}
+	return params;
+}
+
 std::string LLURI::query() const
 {
 	return unescape(mEscapedQuery);
diff --git a/indra/llcommon/lluri.h b/indra/llcommon/lluri.h
index 3246dcd81f5382b1330eae361c3a08dc215d6b2c..bfe673c2f749a933b743a7961c37362119b29150 100644
--- a/indra/llcommon/lluri.h
+++ b/indra/llcommon/lluri.h
@@ -107,7 +107,7 @@ class LLURI
   BOOL defaultPort() const;		// true if port is default for scheme
   const std::string& escapedPath() const { return mEscapedPath; }
   std::string path() const;		// ex.: "/abc/def", includes leading slash
-  //    LLSD pathArray() const;			// above decoded into an array of strings
+  LLSD pathArray() const;			// above decoded into an array of strings
   std::string query() const;		// ex.: "x=34", section after "?"
   const std::string& escapedQuery() const { return mEscapedQuery; }
   LLSD queryMap() const;			// above decoded into a map
@@ -135,6 +135,11 @@ class LLURI
 	//@}
 
 private:
+	 // only "http", "https", "ftp", and "secondlife" schemes are parsed
+	 // secondlife scheme parses authority as "" and includes it as part of
+	 // the path.  See lluri_tut.cpp
+	 // i.e. secondlife://app/login has mAuthority = "" and mPath = "/app/login"
+	void parseAuthorityAndPathUsingOpaque();
 	std::string mScheme;
 	std::string mEscapedOpaque;
 	std::string mEscapedAuthority;
diff --git a/indra/newview/linux_tools/handle_secondlifeprotocol.sh b/indra/newview/linux_tools/handle_secondlifeprotocol.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7ff86d1b9344f5352acf1eeb5aa13650c9b59ea9
--- /dev/null
+++ b/indra/newview/linux_tools/handle_secondlifeprotocol.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Send a URL of the form secondlife://... to Second Life.
+#
+
+URL="$1"
+
+if [ -z "$URL" ]; then
+    echo Usage: $0 secondlife://...
+    exit
+fi
+
+RUN_PATH=`dirname "$0" || echo .`
+cd "${RUN_PATH}"
+
+exec ./secondlife -url \'"${URL}"\'
+
diff --git a/indra/newview/linux_tools/register_secondlifeprotocol.sh b/indra/newview/linux_tools/register_secondlifeprotocol.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4ab96f97d69e000589eaa8c4af07c00740141385
--- /dev/null
+++ b/indra/newview/linux_tools/register_secondlifeprotocol.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# Register a protocol handler (default: handle_secondlifeprotocol.sh) for
+# URLs of the form secondlife://...
+#
+
+HANDLER="$1"
+
+RUN_PATH=`dirname "$0" || echo .`
+cd "${RUN_PATH}"
+
+if [ -z "$HANDLER" ]; then
+    HANDLER=`pwd`/handle_secondlifeprotocol.sh
+fi
+
+# Register handler for GNOME-aware apps
+LLGCONFTOOL2=gconftool-2
+if which ${LLGCONFTOOL2} >/dev/null; then
+    (${LLGCONFTOOL2} -s -t string /desktop/gnome/url-handlers/secondlife/command "${HANDLER} \"%s\"" && ${LLGCONFTOOL2} -s -t bool /desktop/gnome/url-handlers/secondlife/enabled true) || echo Warning: Did not register secondlife:// handler with GNOME: ${LLGCONFTOOL2} failed.
+else
+    echo Warning: Did not register secondlife:// handler with GNOME: ${LLGCONFTOOL2} not found.
+fi
+
+# Register handler for KDE-aware apps
+if [ -z "$KDEHOME" ]; then
+    KDEHOME=~/.kde
+fi
+LLKDEPROTDIR=${KDEHOME}/share/services
+if [ -d "$LLKDEPROTDIR" ]; then
+    LLKDEPROTFILE=${LLKDEPROTDIR}/secondlife.protocol
+    cat > ${LLKDEPROTFILE} <<EOF || echo Warning: Did not register secondlife:// handler with KDE: Could not write ${LLKDEPROTFILE}
+[Protocol]
+exec=${HANDLER} '%u'
+protocol=secondlife
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+EOF
+else
+    echo Warning: Did not register secondlife:// handler with KDE: Directory $LLKDEPROTDIR does not exist.
+fi
diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh
index 10041ee255306c4768093bb86df01e77b5eaf000..638a0f0b76edd7952688daf55f6bfc6300540367 100755
--- a/indra/newview/linux_tools/wrapper.sh
+++ b/indra/newview/linux_tools/wrapper.sh
@@ -61,6 +61,10 @@ fi
 
 RUN_PATH=`dirname "$0" || echo .`
 cd "${RUN_PATH}"
+
+# Re-register the secondlife:// protocol handler every launch, for now.
+./register_secondlifeprotocol.sh
+
 if [ -n "$LL_TCMALLOC" ]; then
     tcmalloc_libs='/usr/lib/libtcmalloc.so.0 /usr/lib/libstacktrace.so.0 /lib/libpthread.so.0'
     all=1
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index fc8d44e990ff51f3cb8e9ceb0fd63fc282e12371..c0e983382966addf66e1ae59f02748f61b33340c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -58,6 +58,7 @@
 #include "llviewerobjectlist.h"
 #include "llworldmap.h"
 #include "llmutelist.h"
+#include "llurldispatcher.h"
 
 #include "llweb.h"
 #include "llsecondlifeurls.h"
@@ -801,25 +802,22 @@ int parse_args(int argc, char **argv)
 		}
 		// some programs don't respect the command line options in protocol handlers (I'm looking at you, Opera)
 		// so this allows us to parse the URL straight off the command line without a "-url" paramater
-		else if (!argument.compare(0, std::string( "secondlife://" ).length(), std::string("secondlife://")))
-		{
-			// *NOTE: After setting the url, bail. What can happen is
-			// that someone can use IE (or potentially other browsers)
-			// and do the rough equivalent of command injection and
-			// steal passwords. Phoenix. SL-55321
-			LLURLSimString::setString(argv[j]);
-			gArgs += argv[j];
-			return 0;
-		}
-		else if (!strcmp(argv[j], "-url") && (++j < argc)) 
+		else if (LLURLDispatcher::isSLURL(argv[j])
+				 || !strcmp(argv[j], "-url") && (++j < argc)) 
 		{
+			std::string slurl = argv[j];
+			if (LLURLDispatcher::isSLURLCommand(slurl))
+			{
+				LLStartUp::sSLURLCommand = slurl;
+			}
+			else
+			{
+				LLURLSimString::setString(slurl);
+			}
 			// *NOTE: After setting the url, bail. What can happen is
 			// that someone can use IE (or potentially other browsers)
 			// and do the rough equivalent of command injection and
 			// steal passwords. Phoenix. SL-55321
-			LLURLSimString::setString(argv[j]);
-			gArgs += argv[j];
-			return 0;
 		}
 		else if (!strcmp(argv[j], "-ignorepixeldepth"))
 		{
@@ -982,7 +980,8 @@ bool LLAppViewer::init()
 	gSettingsFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DEFAULT_SETTINGS_FILE);
 	gOldSettingsFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, LEGACY_DEFAULT_SETTINGS_FILE);
 
-    initConfiguration();
+    if (!initConfiguration())
+		return false;
 
 	//////////////////////////////////////////////////////////////////////////////
 	//////////////////////////////////////////////////////////////////////////////
@@ -2071,7 +2070,7 @@ bool LLAppViewer::initConfiguration()
 			if (send_url_to_other_instance(slurl))
 			{
 				// successfully handed off URL to existing instance, exit
-				return 1;
+				return false;
 			}
 		}
 		
@@ -2089,7 +2088,7 @@ bool LLAppViewer::initConfiguration()
 				msg.str().c_str(),
 				NULL,
 				OSMB_OK);
-			return 1;
+			return false;
 		}
 
 		initMarkerFile();
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 63e7a6b129b492a427a4e85aee580c21891637c9..e80491e78628c480f175788fa2b31fdac85c0f4c 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -42,6 +42,7 @@
 #include "llmd5.h"
 #include "llurlsimstring.h"
 #include "llfloaterworldmap.h"
+#include "llurldispatcher.h"
 #include <Carbon/Carbon.h>
 
 
@@ -170,24 +171,8 @@ OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
 	
 	if(result == noErr)
 	{
-		// Got the URL out of the event.
-		// secondlife://
-
-		// Parse it and stash in globals.
-		LLURLSimString::setString(buffer);
-		
-		if(gFloaterWorldMap != NULL)
-		{
-			// If the viewer's already logged in, pass it along directly.
-			if (LLURLSimString::parse())
-			{
-				gFloaterWorldMap->trackURL(LLURLSimString::sInstance.mSimName,
-										   LLURLSimString::sInstance.mX,
-										   LLURLSimString::sInstance.mY,
-										   LLURLSimString::sInstance.mZ);
-				LLFloaterWorldMap::show(NULL, TRUE);
-			}
-		}
+		std::string url = buffer;
+		LLURLDispatcher::dispatch(url);
 	}
 	
 	return(result);
diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp
index fd3aef9afca0ecb8488285a2e98fb23cf41c428a..95a30e89033d05b880f9c3cb310b5ff80730894d 100644
--- a/indra/newview/llcommandhandler.cpp
+++ b/indra/newview/llcommandhandler.cpp
@@ -46,7 +46,7 @@ class LLCommandHandlerRegistry
 public:
 	static LLCommandHandlerRegistry& instance();
 	void add(const char* cmd, LLCommandHandler* handler);
-	bool dispatch(const std::string& cmd, const std::vector<std::string>& params);
+	bool dispatch(const std::string& cmd, const LLSD& params, const LLSD& queryMap);
 
 private:
 	std::map<std::string, LLCommandHandler*> mMap;
@@ -68,13 +68,14 @@ void LLCommandHandlerRegistry::add(const char* cmd, LLCommandHandler* handler)
 }
 
 bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
-										const std::vector<std::string>& params)
+										const LLSD& params,
+										const LLSD& queryMap)
 {
 	std::map<std::string, LLCommandHandler*>::iterator it = mMap.find(cmd);
 	if (it == mMap.end()) return false;
 	LLCommandHandler* handler = it->second;
 	if (!handler) return false;
-	return handler->handle(params);
+	return handler->handle(params, queryMap);
 }
 
 //---------------------------------------------------------------------------
@@ -97,7 +98,7 @@ LLCommandHandler::~LLCommandHandler()
 //---------------------------------------------------------------------------
 
 // static
-bool LLCommandDispatcher::dispatch(const std::string& cmd, const std::vector<std::string>& params)
+bool LLCommandDispatcher::dispatch(const std::string& cmd, const LLSD& params, const LLSD& queryMap)
 {
-	return LLCommandHandlerRegistry::instance().dispatch(cmd, params);
+	return LLCommandHandlerRegistry::instance().dispatch(cmd, params, queryMap);
 }
diff --git a/indra/newview/llcommandhandler.h b/indra/newview/llcommandhandler.h
index 50928e210b1a1dd04fcf94105b2706e7334caa1b..0cb9d123fac879625b0dddd80883d25bd69e5d9a 100644
--- a/indra/newview/llcommandhandler.h
+++ b/indra/newview/llcommandhandler.h
@@ -44,7 +44,7 @@ class LLFooHandler : public LLCommandHandler
 	LLFooHandler() : LLCommandHandler("foo") { }
 
     // Your code here
-	bool handle(const std::vector<std::string>& tokens)
+	bool handle(const LLSD& tokens, const LLSD& queryMap)
 	{
 		if (tokens.size() < 1) return false;
 		LLUUID id( tokens[0] );
@@ -65,7 +65,8 @@ class LLCommandHandler
 		
 	virtual ~LLCommandHandler();
 
-	virtual bool handle(const std::vector<std::string>& params) = 0;
+	virtual bool handle(const LLSD& params,
+						const LLSD& queryMap) = 0;
 		// Execute the command with a provided (possibly empty)
 		// list of parameters.
 		// Return true if you did something, false if the parameters
@@ -76,7 +77,9 @@ class LLCommandHandler
 class LLCommandDispatcher
 {
 public:
-	static bool dispatch(const std::string& cmd, const std::vector<std::string>& params);
+	static bool dispatch(const std::string& cmd,
+						 const LLSD& params,
+						 const LLSD& queryMap);
 		// Execute a command registered via the above mechanism,
 		// passing string parameters.
 		// Returns true if command was found and executed correctly.
diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp
index 2b9d011e9014004eade8b5434ffce0c42178201e..89f738203cf9a5bac6886873ba9c7b0b7cef7c93 100644
--- a/indra/newview/llfloaterevent.cpp
+++ b/indra/newview/llfloaterevent.cpp
@@ -34,14 +34,14 @@ class LLEventHandler : public LLCommandHandler
 {
 public:
 	LLEventHandler() : LLCommandHandler("event") { }
-	bool handle(const std::vector<std::string>& tokens)
+	bool handle(const LLSD& tokens, const LLSD& queryMap)
 	{
 		if (tokens.size() < 2)
 		{
 			return false;
 		}
-		U32 event_id = atoi(tokens[0].c_str());
-		if (tokens[1] == "about")
+		U32 event_id = tokens[0].asInteger();
+		if (tokens[1].asString() == "about")
 		{
 			LLFloaterEventInfo::show(event_id);
 			return true;
diff --git a/indra/newview/llfloaterparcel.cpp b/indra/newview/llfloaterparcel.cpp
index 61b71761533e06c5f12a44f5f8f3d16114538d39..f737188b340f38fc51f71e3c4f02457b5285f88c 100644
--- a/indra/newview/llfloaterparcel.cpp
+++ b/indra/newview/llfloaterparcel.cpp
@@ -29,7 +29,7 @@ class LLParcelHandler : public LLCommandHandler
 {
 public:
 	LLParcelHandler() : LLCommandHandler("parcel") { }
-	bool handle(const std::vector<std::string>& params)
+	bool handle(const LLSD& params, const LLSD& queryMap)
 	{
 		if (params.size() < 2)
 		{
@@ -40,7 +40,7 @@ class LLParcelHandler : public LLCommandHandler
 		{
 			return false;
 		}
-		if (params[1] == "about")
+		if (params[1].asString() == "about")
 		{
 			LLFloaterParcelInfo::show(parcel_id);
 			return true;
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 100ae0cfaef33795fd068579e7e23c8e69c4a0a2..25a88e6e7cfed74dac92e6dd02cf20efe07ecf0d 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -47,13 +47,16 @@
 #include "llspinctrl.h"
 #include "message.h"
 
+#include "llcommandhandler.h"
 #include "llfloaterabout.h"
+#include "llfloaterpreference.h"
 #include "llpanelnetwork.h"
 #include "llpanelaudioprefs.h"
 #include "llpaneldisplay.h"
 #include "llpaneldebug.h"
 #include "llpanelgeneral.h"
 #include "llpanelinput.h"
+#include "llpanellogin.h"
 #include "llpanelLCD.h"
 #include "llpanelmsgs.h"
 #include "llpanelweb.h"
@@ -71,6 +74,13 @@
 #include "llkeyboard.h"
 #include "llscrollcontainer.h"
 
+#if LL_WINDOWS
+// for Logitech LCD keyboards / speakers
+#ifndef LL_LOGITECH_LCD_H
+#include "lllogitechlcd.h"
+#endif
+extern llLCD	*gLcdScreen; 
+#endif
 
 const S32 PREF_BORDER = 4;
 const S32 PREF_PAD = 5;
@@ -81,13 +91,20 @@ const S32 PREF_FLOATER_MIN_HEIGHT = 2 * SCROLLBAR_SIZE + 2 * LLPANEL_BORDER_WIDT
 
 LLFloaterPreference* LLFloaterPreference::sInstance = NULL;
 
-#if LL_WINDOWS
-// for Logitech LCD keyboards / speakers
-#ifndef LL_LOGITECH_LCD_H
-#include "lllogitechlcd.h"
-#endif
-extern llLCD	*gLcdScreen; 
-#endif
+
+class LLPreferencesHandler : public LLCommandHandler
+{
+public:
+	LLPreferencesHandler() : LLCommandHandler("preferences") { }
+	bool handle(const LLSD& tokens, const LLSD& queryMap)
+	{
+		LLFloaterPreference::show(NULL);
+		return true;
+	}
+};
+
+LLPreferencesHandler gPreferencesHandler;
+
 
 // Must be done at run time, not compile time. JC
 S32 pref_min_width()
@@ -410,6 +427,8 @@ void LLFloaterPreference::show(void*)
 		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 		gAgent.sendReliableMessage();
 	}
+
+	LLPanelLogin::setAlwaysRefresh(true);
 }
 
 
@@ -423,6 +442,9 @@ void LLFloaterPreference::onClickAbout(void*)
 // static 
 void LLFloaterPreference::onBtnOK( void* userdata )
 {
+	//refresh splash page if we're displaying it
+	LLPanelLogin::loadLoginPage();
+
 	LLFloaterPreference *fp =(LLFloaterPreference *)userdata;
 	// commit any outstanding text entry
 	if (fp->hasFocus())
@@ -466,6 +488,16 @@ void LLFloaterPreference::onBtnApply( void* userdata )
 		}
 	}
 	fp->apply();
+
+	//refresh splash page if we're displaying it
+	LLPanelLogin::loadLoginPage();
+}
+
+
+void LLFloaterPreference::onClose(bool app_quitting)
+{
+	LLPanelLogin::setAlwaysRefresh(false);
+	LLFloater::onClose(app_quitting);
 }
 
 
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index a4c43fc8d6915096bb88af11606c7326a7a7ae16..bf554766b7316a2ea14829efd6ee9672e0a9d980 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -117,6 +117,7 @@ class LLFloaterPreference : public LLFloater
 	LLPreferenceCore		*mPreferenceCore;
 
 	/*virtual*/ void		draw();
+	/*virtual*/ void		onClose(bool app_quitting);
 
 	LLButton*	mAboutBtn;
 	LLButton	*mOKBtn;
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index fe0717552904e70a73a196421cde887569920f51..8ebdb14e15cd46b3b17accfc93ebafcbb21542c1 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -44,13 +44,16 @@
 
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
+#include "llcommandhandler.h"
 #include "llcombobox.h"
+#include "llcurl.h"
 #include "llviewercontrol.h"
 #include "llfloaterabout.h"
 #include "llfloatertest.h"
 #include "llfloaterpreference.h"
 #include "llfocusmgr.h"
 #include "lllineeditor.h"
+#include "llstartup.h"
 #include "lltextbox.h"
 #include "llui.h"
 #include "lluiconstants.h"
@@ -74,11 +77,145 @@
 #include "llglheaders.h"
 
 
+LLString load_password_from_disk(void);
+void save_password_to_disk(const char* hashed_password);
+
 const S32 BLACK_BORDER_HEIGHT = 160;
 const S32 MAX_PASSWORD = 16;
 
 LLPanelLogin *LLPanelLogin::sInstance = NULL;
-BOOL LLPanelLogin::sCapslockDidNotification = FALSE;
+
+
+//parses the input url and returns true if afterwards
+//a web-login-key, firstname and lastname  is set
+bool LLLoginHandler::parseDirectLogin(std::string url)
+{
+	LLURI uri(url);
+	parse(uri.queryMap());
+
+	if (mWebLoginKey.isNull() ||
+		mFirstName.empty() ||
+		mLastName.empty())
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+
+void LLLoginHandler::parse(const LLSD& queryMap)
+{
+	mWebLoginKey = queryMap["web_login_key"].asUUID();
+	mFirstName = queryMap["first_name"].asString();
+	mLastName = queryMap["last_name"].asString();
+	
+	if (queryMap["grid"].asString() == "aditi")
+	{
+		gGridChoice = GRID_INFO_ADITI;
+	}
+	else if (queryMap["grid"].asString() == "agni")
+	{
+		gGridChoice = GRID_INFO_AGNI;
+	}
+	else if (queryMap["grid"].asString() == "siva")
+	{
+		gGridChoice = GRID_INFO_SIVA;
+	}
+	else if (queryMap["grid"].asString() == "durga")
+	{
+		gGridChoice = GRID_INFO_DURGA;
+	}
+	else if (queryMap["grid"].asString() == "shakti")
+	{
+		gGridChoice = GRID_INFO_SHAKTI;
+	}
+	else if (queryMap["grid"].asString() == "soma")
+	{
+		gGridChoice = GRID_INFO_SOMA;
+	}
+	else if (queryMap["grid"].asString() == "ganga")
+	{
+		gGridChoice = GRID_INFO_GANGA;
+	}
+	else if (queryMap["grid"].asString() == "vaak")
+	{
+		gGridChoice = GRID_INFO_VAAK;
+	}
+	else if (queryMap["grid"].asString() == "uma")
+	{
+		gGridChoice = GRID_INFO_UMA;
+	}
+	
+	snprintf(gGridName, MAX_STRING, "%s", gGridInfo[gGridChoice].mName);		/* Flawfinder: ignore */
+	LLAppViewer::instance()->resetURIs();
+	
+	LLString startLocation = queryMap["location"].asString();
+
+	if (startLocation == "specify")
+	{
+		LLURLSimString::setString(queryMap["region"].asString());
+	}
+	else if (startLocation == "home")
+	{
+		gSavedSettings.setBOOL("LoginLastLocation", FALSE);
+		LLURLSimString::setString("");
+	}
+	else if (startLocation == "last")
+	{
+		gSavedSettings.setBOOL("LoginLastLocation", TRUE);
+		LLURLSimString::setString("");
+	}
+}
+
+bool LLLoginHandler::handle(const LLSD& tokens,
+						  const LLSD& queryMap)
+{	
+	parse(queryMap);
+	
+	//if we haven't initialized stuff yet, this is 
+	//coming in from the GURL handler, just parse
+	if (STATE_FIRST == LLStartUp::getStartupState())
+	{
+		return true;
+	}
+	
+	LLString password = queryMap["password"].asString();
+
+	if (!password.empty())
+	{
+		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);
+			password = md5pass;
+			save_password_to_disk(password.c_str());
+		}
+	}
+	else
+	{
+		save_password_to_disk(NULL);
+		gSavedSettings.setBOOL("RememberPassword", FALSE);
+	}
+			
+
+	if  (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)  //on splash page
+	{
+		if (mWebLoginKey.isNull()) {
+			LLPanelLogin::loadLoginPage();
+		} else {
+			LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
+		}
+	}
+	return true;
+}
+
+LLLoginHandler gLoginHandler;
 
 // helper class that trys to download a URL from a web site and calls a method 
 // on parent class indicating if the web server is working or not
@@ -157,92 +294,11 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	mLogoImage = gImageList.getImage("startup_logo.tga", LLUUID::null, MIPMAP_FALSE, TRUE);
 
 	gUICtrlFactory->buildPanel(this, "panel_login.xml");
-	//setRect(rect);
+	
+	//leave room for the login menu bar
+	setRect(LLRect(0, rect.getHeight()-18, rect.getWidth(), 0)); 
 	reshape(rect.getWidth(), rect.getHeight());
-
-	childSetPrevalidate("first_name_edit", LLLineEditor::prevalidatePrintableNoSpace);
-	childSetPrevalidate("last_name_edit", LLLineEditor::prevalidatePrintableNoSpace);
-
-	childSetCommitCallback("password_edit", mungePassword);
-	childSetKeystrokeCallback("password_edit", onPassKey, this);
-	childSetUserData("password_edit", this);
-
-	LLLineEditor* edit = LLUICtrlFactory::getLineEditorByName(this, "password_edit");
-	if (edit) edit->setDrawAsterixes(TRUE);
-
-	LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(this, "start_location_combo");
-	if (combo)
-	{
-		combo->setAllowTextEntry(TRUE, 128, FALSE);
-
-		// The XML file loads the combo with the following labels:
-		// 0 - "My Home"
-		// 1 - "My Last Location"
-		// 2 - "<Type region name>"
-
-		BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
-		LLString sim_string = LLURLSimString::sInstance.mSimString;
-		if (!sim_string.empty())
-		{
-			// Replace "<Type region name>" with this region name
-			combo->remove(2);
-			combo->add( sim_string );
-			combo->setTextEntry(sim_string);
-			combo->setCurrentByIndex( 2 );
-		}
-		else if (login_last)
-		{
-			combo->setCurrentByIndex( 1 );
-		}
-		else
-		{
-			combo->setCurrentByIndex( 0 );
-		}
-
-		combo->setCommitCallback( &LLPanelGeneral::set_start_location );
-	}
 	
-	// Specific servers added later.
-	childSetVisible("server_combo", show_server);
-
-	childSetAction("new_account_btn", onClickNewAccount, this);
-	childSetVisible("new_account_btn", !gHideLinks);
-
-	childSetAction("connect_btn", onClickConnect, this);
-
-	setDefaultBtn("connect_btn");
-
-	childSetAction("preferences_btn", LLFloaterPreference::show, this);
-
-	childSetAction("quit_btn", onClickQuit, this);
-
-	LLTextBox* version_text = LLUICtrlFactory::getTextBoxByName(this, "version_text");
-	if (version_text)
-	{
-		LLString version = llformat("%d.%d.%d (%d)",
-			LL_VERSION_MAJOR,
-			LL_VERSION_MINOR,
-			LL_VERSION_PATCH,
-			LL_VIEWER_BUILD );
-		version_text->setText(version);
-		version_text->setClickedCallback(onClickVersion);
-		version_text->setCallbackUserData(this);
-	}
-
-	LLTextBox* channel_text = LLUICtrlFactory::getTextBoxByName(this, "channel_text");
-	if (channel_text)
-	{
-		channel_text->setText(gChannelName);
-		channel_text->setClickedCallback(onClickVersion);
-		channel_text->setCallbackUserData(this);
-	}
-
-	LLTextBox* forgot_password_text = LLUICtrlFactory::getTextBoxByName(this, "forgot_password_text");
-	if (forgot_password_text)
-	{
-		forgot_password_text->setClickedCallback(onClickForgotPassword);
-	}
-    
 	// get the web browser control
 	#if LL_LIBXUL_ENABLED
 	LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(this, "login_html");
@@ -266,11 +322,11 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 
 		// force the size to be correct (XML doesn't seem to be sufficient to do this) (with some padding so the other login screen doesn't show through)
 		LLRect htmlRect = mRect;
-		htmlRect.setCenterAndSize( mRect.getCenterX() - 2, mRect.getCenterY() + 40, mRect.getWidth() + 6, mRect.getHeight() - 78 );
+		htmlRect.setCenterAndSize( mRect.getCenterX() - 2, mRect.getCenterY(), mRect.getWidth() + 6, mRect.getHeight());
 		web_browser->setRect( htmlRect );
 		web_browser->reshape( htmlRect.getWidth(), htmlRect.getHeight(), TRUE );
-		reshape( mRect.getWidth(), mRect.getHeight(), 1 );
-
+		reshape( mRect.getWidth(), mRect.getHeight(), 1 );    
+		
 		// kick off a request to grab the url manually
 		gResponsePtr = LLIamHereLogin::build( this );
 		LLHTTPClient::get( childGetValue( "real_url" ).asString(), gResponsePtr );
@@ -280,7 +336,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	#endif
 
 	// Initialize visibility (and don't force visibility - use prefs)
-	refreshLocation( false );
 }
 
 void LLPanelLogin::setSiteIsAlive( bool alive )
@@ -292,9 +347,8 @@ void LLPanelLogin::setSiteIsAlive( bool alive )
 	{
 		if ( web_browser )
 		{
-			// navigate to the "real" page 
-			web_browser->navigateTo( childGetValue( "real_url" ).asString() );
-
+			loadLoginPage();
+			
 			// mark as available
 			mHtmlAvailable = TRUE;
 		};
@@ -316,21 +370,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )
 #endif
 }
 
-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()
 {
@@ -366,13 +405,6 @@ void LLPanelLogin::draw()
 			glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * mRect.getWidth(), 0.f, 0.f);
 			glScalef(image_aspect / view_aspect, 1.f, 1.f);
 		}
-		// Don't maintain aspect ratio if screen wider than image.  This results in the
-		// hand being partially cut off.  JC
-		//else
-		//{
-		//	glTranslatef(0.f, -0.5f * (view_aspect / image_aspect - 1.f) * (F32)BLACK_BORDER_HEIGHT, 0.f);
-		//	glScalef(1.f, view_aspect / image_aspect, 1.f);
-		//}
 
 		S32 width = mRect.getWidth();
 		S32 height = mRect.getHeight();
@@ -381,9 +413,6 @@ void LLPanelLogin::draw()
 		{
 			// draw a background box in black
 			gl_rect_2d( 0, height - 264, width, 264, LLColor4( 0.0f, 0.0f, 0.0f, 1.f ) );
-
-			// draw the bottom part of the background image - just the blue background to the native client UI
-			gl_draw_scaled_image(0, -264, width + 8, mLogoImage->getHeight(), mLogoImage);
 		}
 		else
 		{
@@ -451,54 +480,14 @@ BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
 
 	return LLPanel::handleKeyHere(key, mask, called_from_parent);
 }
-
-// virtual 
-void LLPanelLogin::setFocus(BOOL b)
-{
-	if(b != hasFocus())
-	{
-		if(b)
-		{
-			LLPanelLogin::giveFocus();
-		}
-		else
-		{
-			LLPanel::setFocus(b);
-		}
-	}
-}
+	
 
 // static
 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 pass = sInstance->childGetText("password_edit");
-
-		BOOL have_first = !first.empty();
-		BOOL have_pass = !pass.empty();
-
-		LLLineEditor* edit = NULL;
-		if (have_first && !have_pass)
-		{
-			// User saved his name but not his password.  Move
-			// focus to password field.
-			edit = LLUICtrlFactory::getLineEditorByName(sInstance, "password_edit");
-		}
-		else
-		{
-			// User doesn't have a name, so start there.
-			edit = LLUICtrlFactory::getLineEditorByName(sInstance, "first_name_edit");
-		}
 
-		if (edit)
-		{
-			edit->setFocus(TRUE);
-			edit->selectAll();
-		}
-	}
+	if (sInstance)
+		sInstance->setFocus(TRUE);
 }
 
 
@@ -510,266 +499,156 @@ void LLPanelLogin::show(const LLRect &rect,
 {
 	new LLPanelLogin(rect, show_server, callback, callback_data);
 
+	LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(sInstance, "login_html");
+	
+	if (!web_browser) return;
+
 	if( !gFocusMgr.getKeyboardFocus() )
 	{
 		// Grab focus and move cursor to first enabled control
-		sInstance->setFocus(TRUE);
+		web_browser->setFocus(TRUE);
 	}
 
 	// Make sure that focus always goes here (and use the latest sInstance that was just created)
-	gFocusMgr.setDefaultKeyboardFocus(sInstance);
+	gFocusMgr.setDefaultKeyboardFocus(web_browser);
 }
 
+
 // static
-void LLPanelLogin::setFields(const std::string& firstname, const std::string& lastname, const std::string& password,
-							 BOOL remember)
+void LLPanelLogin::close()
 {
-	if (!sInstance)
+	if (sInstance)
 	{
-		llwarns << "Attempted fillFields with no login view shown" << llendl;
-		return;
-	}
-
-	sInstance->childSetText("first_name_edit", firstname);
-	sInstance->childSetText("last_name_edit", lastname);
+		gViewerWindow->getRootView()->removeChild( LLPanelLogin::sInstance );
+		
+		gFocusMgr.setDefaultKeyboardFocus(NULL);
 
-	// Max "actual" password length is 16 characters.
-	// Hex digests are always 32 characters.
-	if (password.length() == 32)
-	{
-		// 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;
-	}
-	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;
+		delete sInstance;
+		sInstance = NULL;
 	}
-
-	sInstance->childSetValue("remember_check", remember);
 }
 
-
 // static
-void LLPanelLogin::addServer(const char *server, S32 domain_name)
+void LLPanelLogin::setAlwaysRefresh(bool refresh)
 {
-	if (!sInstance)
-	{
-		llwarns << "Attempted addServer with no login view shown" << llendl;
-		return;
-	}
+	if (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP) return;
 
-	LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
-	if (combo)
+	LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(sInstance, "login_html");
+
+	if (web_browser)
 	{
-		combo->add(server, LLSD(domain_name) );
-		combo->setCurrentByIndex(0);
+		web_browser->setAlwaysRefresh(refresh);
 	}
 }
 
-// static
-void LLPanelLogin::getFields(LLString &firstname, LLString &lastname, LLString &password,
-							BOOL &remember)
-{
-	if (!sInstance)
-	{
-		llwarns << "Attempted getFields with no login view shown" << llendl;
-		return;
-	}
 
-	firstname = sInstance->childGetText("first_name_edit");
-	LLString::trim(firstname);
 
-	lastname = sInstance->childGetText("last_name_edit");
-	LLString::trim(lastname);
+void LLPanelLogin::loadLoginPage()
+{
+	if (!sInstance) return;
 
-	password = sInstance->mMungedPassword;
-	remember = sInstance->childGetValue("remember_check");
-}
+	LLURLSimString::sInstance.parse();
 
+	LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(sInstance, "login_html");
 
-// static.  Return TRUE if user made a choice from the popup
-BOOL LLPanelLogin::getServer(LLString &server, S32 &domain_name)
-{
-	BOOL user_picked = FALSE;
-	if (!sInstance)
+	std::ostringstream oStr;
+
+	LLString location;
+	LLString region;
+	LLString password;
+	
+	if (LLURLSimString::parse())
 	{
-		llwarns << "Attempted getServer with no login view shown" << llendl;
+		std::ostringstream oRegionStr;
+		location = "specify";
+		oRegionStr << LLURLSimString::sInstance.mSimName << "/" << LLURLSimString::sInstance.mX << "/"
+			 << LLURLSimString::sInstance.mY << "/"
+			 << LLURLSimString::sInstance.mZ;
+		region = oRegionStr.str();
 	}
 	else
 	{
-		LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
-		if (combo)
+		if (gSavedSettings.getBOOL("LoginLastLocation"))
 		{
-			LLSD combo_val = combo->getValue();
-			if (LLSD::TypeInteger == combo_val.type())
-			{
-				domain_name = combo->getValue().asInteger();
-
-				if ((S32)GRID_INFO_OTHER == domain_name)
-				{
-					server = gGridName;
-				}
-			}
-			else
-			{
-				// no valid selection, return other
-				domain_name = (S32)GRID_INFO_OTHER;
-				server = combo_val.asString();
-			}
-			user_picked = combo->isDirty();
+			location = "last";
+		}
+		else
+		{
+			location = "home";
 		}
 	}
-
-	return user_picked;
-}
-
-// static
-void LLPanelLogin::getLocation(LLString &location)
-{
-	if (!sInstance)
+	
+	LLString firstname, lastname;
+	
+	if (gCmdLineFirstName.empty())
 	{
-		llwarns << "Attempted getLocation with no login view shown" << llendl;
-		return;
+		firstname = gSavedSettings.getString("FirstName");
 	}
-	
-	LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "start_location_combo");
-	if (combo)
+	else
 	{
-		location = combo->getValue().asString();
+		firstname = gCmdLineFirstName;
 	}
-}
-
-// static
-void LLPanelLogin::refreshLocation( bool force_visible )
-{
-	if (!sInstance) return;
-
-	LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "start_location_combo");
-	if (!combo) return;
-
-	LLString sim_string = LLURLSimString::sInstance.mSimString;
-	if (!sim_string.empty())
+	
+	if (gCmdLineLastName.empty())
 	{
-		combo->setCurrentByIndex( 3 );		// BUG?  Maybe 2?
-		combo->setTextEntry(sim_string);
+		lastname = gSavedSettings.getString("LastName");
 	}
 	else
 	{
-		BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
-		combo->setCurrentByIndex( login_last ? 1 : 0 );
+		lastname = gCmdLineLastName;
 	}
+	
+	LLString version = llformat("%d.%d.%d (%d)",
+						LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD);
 
-	BOOL show_start = TRUE;
-
-	if ( ! force_visible )
-		show_start = gSavedSettings.getBOOL("ShowStartLocation");
-
-	sInstance->childSetVisible("start_location_combo", show_start);
-	sInstance->childSetVisible("start_location_text", show_start);
-}
-
-// static
-void LLPanelLogin::close()
-{
-	if (sInstance)
-	{
-		gViewerWindow->getRootView()->removeChild( LLPanelLogin::sInstance );
-		
-		gFocusMgr.setDefaultKeyboardFocus(NULL);
-
-		delete sInstance;
-		sInstance = NULL;
-	}
-}
+	char* curl_region = curl_escape(region.c_str(), 0);
+	char* curl_channel = curl_escape(gChannelName.c_str(), 0);
+	char* curl_version = curl_escape(version.c_str(), 0);
 
+	
+	oStr << sInstance->childGetValue( "real_url" ).asString()  << "&firstname=" << firstname <<
+		"&lastname=" << lastname << "&location=" << location <<	"&region=" << curl_region <<
+		"&grid=" << gGridInfo[gGridChoice].mLabel << "&channel=" << curl_channel <<
+		"&version=" << curl_version;
 
-//---------------------------------------------------------------------------
-// Protected methods
-//---------------------------------------------------------------------------
+	
+	curl_free(curl_region);
+	curl_free(curl_channel);
+	curl_free(curl_version);
 
-// static
-void LLPanelLogin::onClickConnect(void *)
-{
-	if (sInstance && sInstance->mCallback)
+	if (!gCmdLinePassword.empty())
 	{
-		// tell the responder we're not here anymore
-		if ( gResponsePtr )
-			gResponsePtr->setParent( 0 );
-
-		// JC - Make sure the fields all get committed.
-		sInstance->setFocus(FALSE);
-
-		LLString first = sInstance->childGetText("first_name_edit");
-		LLString last  = sInstance->childGetText("last_name_edit");
-		if (!first.empty() && !last.empty())
-		{
-			// has both first and last name typed
-
-			// store off custom server entry, if currently selected
-			LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
-			if (combo)
-			{
-				S32 selected_server = combo->getValue();
-				if (selected_server == GRID_INFO_NONE)
-				{
-					LLString custom_server = combo->getValue().asString();
-					gSavedSettings.setString("CustomServer", custom_server);
-				}
-			}
-			sInstance->mCallback(0, sInstance->mCallbackData);
-		}
-		else
-		{
-			// empty first or last name
-			// same as clicking new account
-			onClickNewAccount(NULL);
-		}
+		oStr << "&password=" << gCmdLinePassword;
 	}
-}
-
-
-// static
-void LLPanelLogin::newAccountAlertCallback(S32 option, void*)
-{
-	if (0 == option)
+	else if (!(password = load_password_from_disk()).empty())
 	{
-		llinfos << "Going to account creation URL" << llendl;
-		LLWeb::loadURL( CREATE_ACCOUNT_URL );
+		oStr << "&password=$1$" << password;
 	}
-	else
+	if (gAutoLogin)
 	{
-		sInstance->setFocus(TRUE);
+		oStr << "&auto_login=TRUE";
 	}
-}
-
-
-// static
-void LLPanelLogin::onClickNewAccount(void*)
-{
-	if (gHideLinks)
+	if (gSavedSettings.getBOOL("ShowStartLocation"))
 	{
-		gViewerWindow->alertXml("MustHaveAccountToLogInNoLinks");
-	}
-	else
+		oStr << "&show_start_location=TRUE";
+	}	
+	if (gSavedSettings.getBOOL("RememberPassword"))
 	{
-		gViewerWindow->alertXml("MustHaveAccountToLogIn",
-								LLPanelLogin::newAccountAlertCallback);
-	}
+		oStr << "&remember_password=TRUE";
+	}	
+#ifndef	LL_RELEASE_FOR_DOWNLOAD
+	oStr << "&show_grid=TRUE";
+#endif
+	
+	// navigate to the "real" page 
+	web_browser->navigateTo( oStr.str() );
 }
 
 
+//---------------------------------------------------------------------------
+// Protected methods
+//---------------------------------------------------------------------------
+
 // static
 void LLPanelLogin::onClickQuit(void*)
 {
@@ -789,22 +668,3 @@ void LLPanelLogin::onClickVersion(void*)
 {
 	LLFloaterAbout::show(NULL);
 }
-
-void LLPanelLogin::onClickForgotPassword(void*)
-{
-	if (sInstance )
-	{
-		LLWeb::loadURL(sInstance->childGetValue( "forgot_password_url" ).asString());
-	}
-}
-
-
-// static
-void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
-{
-	if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
-	{
-		LLNotifyBox::showXml("CapsKeyOn");
-		sCapslockDidNotification = TRUE;
-	}
-}
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index 447b9ea01c0bb63da89122243eb0b1ac48d4fb8b..191e88c25bdad6ef9e77e5d9d5816d35a531d348 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -33,7 +33,7 @@
 #define LL_LLPANELLOGIN_H
 
 #include "llpanel.h"
-
+#include "llcommandhandler.h"
 #include "lldbstrings.h"
 #include "llmemory.h"
 #include "llviewerimage.h"
@@ -46,6 +46,22 @@ class LLCheckBoxCtrl;
 class LLButton;
 class LLComboBox;
 
+
+class LLLoginHandler : public LLCommandHandler
+{
+ public:
+	LLLoginHandler() : LLCommandHandler("login") { }
+	bool handle(const LLSD& tokens, const LLSD& queryMap);
+	bool parseDirectLogin(std::string url);
+	void parse(const LLSD& queryMap);
+
+	LLUUID mWebLoginKey;
+	LLString mFirstName;
+	LLString mLastName;
+};
+
+extern LLLoginHandler gLoginHandler;
+
 class LLPanelLogin
 :	public LLPanel
 {
@@ -57,39 +73,22 @@ class LLPanelLogin
 
 	virtual BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
 	virtual void draw();
-	virtual void setFocus( BOOL b );
 
 	static void show(const LLRect &rect, BOOL show_server, 
 		void (*callback)(S32 option, void* user_data), 
 		void* callback_data);
 
-	static void setFields(const std::string& firstname, const std::string& lastname, 
-		const std::string& password, BOOL remember);
-
-	static void addServer(const char *server, S32 domain_name);
-	static void refreshLocation( bool force_visible );
-
-	static void getFields(LLString &firstname, LLString &lastname,
-		LLString &password, BOOL &remember);
-
-	static BOOL getServer(LLString &server, S32& domain_name);
-	static void getLocation(LLString &location);
-
 	static void close();
 
 	void setSiteIsAlive( bool alive );
 
-	static void	giveFocus();
-	static void mungePassword(LLUICtrl* caller, void* user_data);
-	
+	static void loadLoginPage();	
+	static void giveFocus();
+	static void setAlwaysRefresh(bool refresh); 
+
 private:
-	static void onClickConnect(void*);
-	static void onClickNewAccount(void*);
-	static void newAccountAlertCallback(S32 option, void*);
 	static void onClickQuit(void*);
 	static void onClickVersion(void*);
-	static void onClickForgotPassword(void*);
-	static void onPassKey(LLLineEditor* caller, void* user_data);
 	
 private:
 	LLPointer<LLViewerImage> mLogoImage;
@@ -97,11 +96,7 @@ class LLPanelLogin
 	void			(*mCallback)(S32 option, void *userdata);
 	void*			mCallbackData;
 
-	std::string mIncomingPassword;
-	std::string mMungedPassword;
-
 	static LLPanelLogin* sInstance;
-	static BOOL		sCapslockDidNotification;
 	BOOL			mHtmlAvailable;
 };
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index d5af7243a0742700a900522a4ea0941732b8e52d..267b2340d049be4bfca28644bcd8aa8a0d0cb5de 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -329,6 +329,7 @@ BOOL idle_startup()
 	static std::string auth_message;
 	static LLString firstname;
 	static LLString lastname;
+	static LLUUID web_login_key;
 	static LLString password;
 	static std::vector<const char*> requested_options;
 
@@ -348,7 +349,6 @@ BOOL idle_startup()
 	static S32  location_which = START_LOCATION_ID_LAST;
 
 	static BOOL show_connect_box = TRUE;
-	static BOOL remember_password = TRUE;
 
 	static BOOL stipend_since_login = FALSE;
 
@@ -634,28 +634,34 @@ BOOL idle_startup()
 		//
 		// Log on to system
 		//
-		if( !gCmdLineFirstName.empty() 
+		if ((!gLoginHandler.mFirstName.empty() &&
+			 !gLoginHandler.mLastName.empty() &&
+			 !gLoginHandler.mWebLoginKey.isNull())		
+			|| gLoginHandler.parseDirectLogin(LLStartUp::sSLURLCommand) )
+		{
+			firstname = gLoginHandler.mFirstName;
+			lastname = gLoginHandler.mLastName;
+			web_login_key = gLoginHandler.mWebLoginKey;
+
+			show_connect_box = FALSE;
+		}
+		else if( !gCmdLineFirstName.empty() 
 			&& !gCmdLineLastName.empty() 
 			&& !gCmdLinePassword.empty())
 		{
 			firstname = gCmdLineFirstName;
 			lastname = gCmdLineLastName;
 
-			LLMD5 pass((unsigned char*)gCmdLinePassword.c_str());
-			char md5pass[33];		/* Flawfinder: ignore */
-			pass.hex_digest(md5pass);
-			password = md5pass;
-
-			remember_password = gSavedSettings.getBOOL("RememberPassword");
-			show_connect_box = FALSE;
+			show_connect_box = TRUE;
+			gAutoLogin = TRUE;
 		}
 		else if (gAutoLogin || gSavedSettings.getBOOL("AutoLogin"))
 		{
 			firstname = gSavedSettings.getString("FirstName");
 			lastname = gSavedSettings.getString("LastName");
 			password = load_password_from_disk();
-			remember_password = TRUE;
-			show_connect_box = FALSE;
+			gSavedSettings.setBOOL("RememberPassword", TRUE);
+			show_connect_box = TRUE;
 		}
 		else
 		{
@@ -664,7 +670,6 @@ BOOL idle_startup()
 			firstname = gSavedSettings.getString("FirstName");
 			lastname = gSavedSettings.getString("LastName");
 			password = load_password_from_disk();
-			remember_password = gSavedSettings.getBOOL("RememberPassword");
 			show_connect_box = TRUE;
 		}
 
@@ -674,7 +679,8 @@ BOOL idle_startup()
 	}
 
 	if (STATE_LOGIN_SHOW == LLStartUp::getStartupState())
-	{
+	{		
+
 		llinfos << "Initializing Window" << llendl;
 		
 		gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
@@ -695,8 +701,6 @@ BOOL idle_startup()
 			// Show the login dialog
 			login_show();
 
-			// connect dialog is already shown, so fill in the names
-			LLPanelLogin::setFields( firstname, lastname, password, remember_password );
 			LLPanelLogin::giveFocus();
 
 			gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
@@ -708,6 +712,31 @@ BOOL idle_startup()
 			// skip directly to message template verification
 			LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
 		}
+		
+		// Create selection manager
+		// Must be done before menus created, because many enabled callbacks
+		// require its existance.
+		gSelectMgr = new LLSelectMgr();
+		gParcelMgr = new LLViewerParcelMgr();
+		gHUDManager = new LLHUDManager();
+		gMuteListp = new LLMuteList();
+
+		// Initialize UI
+		if (!gNoRender)
+		{
+			// Initialize all our tools.  Must be done after saved settings loaded.
+			if ( gToolMgr == NULL )
+			{
+				gToolMgr = new LLToolMgr();
+				gToolMgr->initTools();
+			}
+
+			// Quickly get something onscreen to look at.
+			gViewerWindow->initWorldUI();
+		}
+		
+		gViewerWindow->setNormalControlsVisible( FALSE );	
+		gLoginMenuBarView->setVisible( TRUE );
 
 		timeout.reset();
 		return do_normal_idle;
@@ -725,11 +754,16 @@ BOOL idle_startup()
 
 	if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState())
 	{
+		//reset the values that could have come in from a slurl
+		if (!gLoginHandler.mWebLoginKey.isNull())
+		{
+			firstname = gLoginHandler.mFirstName;
+			lastname = gLoginHandler.mLastName;
+			web_login_key = gLoginHandler.mWebLoginKey;
+		}
+				
 		if (show_connect_box)
 		{
-			// Load all the name information out of the login view
-			LLPanelLogin::getFields(firstname, lastname, password, remember_password);
-
 			// HACK: Try to make not jump on login
 			gKeyboard->resetKeys();
 		}
@@ -789,25 +823,6 @@ BOOL idle_startup()
 
 		if (show_connect_box)
 		{
-			LLString server_label;
-			S32 domain_name_index;
-			BOOL user_picked_server = LLPanelLogin::getServer( server_label, domain_name_index );
-			gGridChoice = (EGridInfo) domain_name_index;
-			gSavedSettings.setS32("ServerChoice", gGridChoice);
-			if (gGridChoice == GRID_INFO_OTHER)
-			{
-				snprintf(gGridName, MAX_STRING, "%s", server_label.c_str());			/* Flawfinder: ignore */
-			}
-
-			if ( user_picked_server )
-			{	// User picked a grid from the popup, so clear the stored urls and they will be re-generated from gGridChoice
-				sAuthUris.clear();
-                LLAppViewer::instance()->resetURIs();
-			}
-
-			LLString location;
-			LLPanelLogin::getLocation( location );
-			LLURLSimString::setString( location );
 			LLPanelLogin::close();
 		}
 
@@ -940,11 +955,12 @@ BOOL idle_startup()
 			// a startup URL was specified
 			std::stringstream unescaped_start;
 			unescaped_start << "uri:" 
-				<< LLURLSimString::sInstance.mSimName << "&" 
-				<< LLURLSimString::sInstance.mX << "&" 
-				<< LLURLSimString::sInstance.mY << "&" 
-				<< LLURLSimString::sInstance.mZ;
+							<< LLURLSimString::sInstance.mSimName << "&" 
+							<< LLURLSimString::sInstance.mX << "&" 
+							<< LLURLSimString::sInstance.mY << "&" 
+							<< LLURLSimString::sInstance.mZ;
 			start << xml_escape_string(unescaped_start.str().c_str());
+			
 		}
 		else if (gSavedSettings.getBOOL("LoginLastLocation"))
 		{
@@ -960,13 +976,13 @@ BOOL idle_startup()
 		hashed_mac.update( gMACAddress, MAC_ADDRESS_BYTES );
 		hashed_mac.finalize();
 		hashed_mac.hex_digest(hashed_mac_string);
-		
+
 		gUserAuthp->authenticate(
 			sAuthUris[sAuthUriNum].c_str(),
 			auth_method.c_str(),
 			firstname.c_str(),
 			lastname.c_str(),
-			password.c_str(),
+			web_login_key,
 			start.str().c_str(),
 			gSkipOptionalUpdate,
 			gAcceptTOS,
@@ -976,6 +992,7 @@ BOOL idle_startup()
 			requested_options,
 			hashed_mac_string,
 			LLAppViewer::instance()->getSerialNumber());
+
 		// reset globals
 		gAcceptTOS = FALSE;
 		gAcceptCriticalMessage = FALSE;
@@ -1237,15 +1254,7 @@ BOOL idle_startup()
 			if(text) lastname.assign(text);
 			gSavedSettings.setString("FirstName", firstname);
 			gSavedSettings.setString("LastName", lastname);
-			if (remember_password)
-			{
-				save_password_to_disk(password.c_str());
-			}
-			else
-			{
-				save_password_to_disk(NULL);
-			}
-			gSavedSettings.setBOOL("RememberPassword", remember_password);
+			
 			gSavedSettings.setBOOL("LoginLastLocation", gSavedSettings.getBOOL("LoginLastLocation"));
 
 			text = gUserAuthp->getResponse("agent_access");
@@ -1471,14 +1480,6 @@ BOOL idle_startup()
 		// type the name/password again if we crash.
 		gSavedSettings.saveToFile(gSettingsFileName, TRUE);
 
-		// Create selection manager
-		// Must be done before menus created, because many enabled callbacks
-		// require its existance.
-		gSelectMgr = new LLSelectMgr();
-		gParcelMgr = new LLViewerParcelMgr();
-		gHUDManager = new LLHUDManager();
-		gMuteListp = new LLMuteList();
-
 		//
 		// Initialize classes w/graphics stuff.
 		//
@@ -1547,21 +1548,11 @@ BOOL idle_startup()
 		if ( gViewerWindow != NULL && gToolMgr != NULL )
 		{	// This isn't the first logon attempt, so show the UI
 			gViewerWindow->setNormalControlsVisible( TRUE );
-		}
+		}	
+		gLoginMenuBarView->setVisible( FALSE );
 
-		// Initialize UI
 		if (!gNoRender)
 		{
-			// Initialize all our tools.  Must be done after saved settings loaded.
-			if ( gToolMgr == NULL )
-			{
-				gToolMgr = new LLToolMgr();
-				gToolMgr->initTools();
-			}
-
-			// Quickly get something onscreen to look at.
-			gViewerWindow->initWorldUI();
-
 			// Move the progress view in front of the UI
 			gViewerWindow->moveProgressViewToFront();
 
@@ -2344,68 +2335,12 @@ void login_show()
 	// UI textures have been previously loaded in doPreloadImages()
 	
 	llinfos << "Setting Servers" << llendl;
-	
-	if( GRID_INFO_OTHER == gGridChoice )
-	{
-		LLPanelLogin::addServer( gGridName, GRID_INFO_OTHER );
-	}
-	else
-	{
-		LLPanelLogin::addServer( gGridInfo[gGridChoice].mLabel, gGridChoice );
-	}
-
-	// Arg!  We hate loops!
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_DMZ].mLabel,	GRID_INFO_DMZ );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_LOCAL].mLabel,	GRID_INFO_LOCAL );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_AGNI].mLabel,	GRID_INFO_AGNI );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_ADITI].mLabel,	GRID_INFO_ADITI );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_SIVA].mLabel,	GRID_INFO_SIVA );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_DURGA].mLabel,	GRID_INFO_DURGA );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_SHAKTI].mLabel,	GRID_INFO_SHAKTI );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_GANGA].mLabel,	GRID_INFO_GANGA );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_UMA].mLabel,	GRID_INFO_UMA );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_SOMA].mLabel,	GRID_INFO_SOMA );
-	LLPanelLogin::addServer( gGridInfo[GRID_INFO_VAAK].mLabel,	GRID_INFO_VAAK );
 }
 
 // Callback for when login screen is closed.  Option 0 = connect, option 1 = quit.
 void login_callback(S32 option, void *userdata)
 {
-	const S32 CONNECT_OPTION = 0;
-	const S32 QUIT_OPTION = 1;
 
-	if (CONNECT_OPTION == option)
-	{
-		LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
-		return;
-	}
-	else if (QUIT_OPTION == option)
-	{
-		// Make sure we don't save the password if the user is trying to clear it.
-		LLString first, last, password;
-		BOOL remember = TRUE;
-		LLPanelLogin::getFields(first, last, password, remember);
-		if (!remember)
-		{
-			// turn off the setting and write out to disk
-			gSavedSettings.setBOOL("RememberPassword", FALSE);
-			gSavedSettings.saveToFile(gSettingsFileName, TRUE);
-
-			// stomp the saved password on disk
-			save_password_to_disk(NULL);
-		}
-
-		LLPanelLogin::close();
-
-		// Next iteration through main loop should shut down the app cleanly.
-		LLAppViewer::instance()->userQuit(); // gQuit = TRUE;
-
-		return;
-	}
-	else
-	{
-		llwarns << "Unknown login button clicked" << llendl;
-	}
 }
 
 LLString load_password_from_disk()
@@ -3645,6 +3580,7 @@ void reset_login()
 	if ( gViewerWindow )
 	{	// Hide menus and normal buttons
 		gViewerWindow->setNormalControlsVisible( FALSE );
+		gLoginMenuBarView->setVisible( TRUE );
 	}
 
 	// Hide any other stuff
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 166209d5820c54def3c809093b82fefafbab040c..fa8213d6621d120089cea8c63187e5ce6939ef09 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -85,6 +85,8 @@ LLToolPie::LLToolPie()
 
 BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
 {
+	if (!gCamera) return FALSE;
+
 	//left mouse down always picks transparent
 	gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, leftMouseCallback, 
 											  TRUE, TRUE);
diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp
index 5b8583d2119b93ba84b83daed8a47e281dee4b67..c6d9b2fbe2229cfc77934939bb9b46ef43cc73b2 100644
--- a/indra/newview/llurldispatcher.cpp
+++ b/indra/newview/llurldispatcher.cpp
@@ -48,9 +48,6 @@
 // library includes
 #include "llsd.h"
 
-// system includes
-#include <boost/tokenizer.hpp>
-
 const std::string SLURL_SL_HELP_PREFIX		= "secondlife://app.";
 const std::string SLURL_SL_PREFIX			= "sl://";
 const std::string SLURL_SECONDLIFE_PREFIX	= "secondlife://";
@@ -111,9 +108,9 @@ bool LLURLDispatcherImpl::isSLURL(const std::string& url)
 
 // static
 bool LLURLDispatcherImpl::isSLURLCommand(const std::string& url)
-{
+{ 
 	if (matchPrefix(url, SLURL_SL_PREFIX + SLURL_APP_TOKEN)
-		|| matchPrefix(url, SLURL_SECONDLIFE_PREFIX + SLURL_APP_TOKEN)
+		|| matchPrefix(url, SLURL_SECONDLIFE_PREFIX + "/" + SLURL_APP_TOKEN)
 		|| matchPrefix(url, SLURL_SLURL_PREFIX + SLURL_APP_TOKEN) )
 	{
 		return true;
@@ -128,6 +125,14 @@ bool LLURLDispatcherImpl::dispatchCore(const std::string& url, bool right_mouse)
 	if (dispatchHelp(url, right_mouse)) return true;
 	if (dispatchApp(url, right_mouse)) return true;
 	if (dispatchRegion(url, right_mouse)) return true;
+
+	/*
+	// Inform the user we can't handle this
+	std::map<std::string, std::string> args;
+	args["[SLURL]"] = url;
+	gViewerWindow->alertXml("BadURL", args);
+	*/
+	
 	return false;
 }
 
@@ -162,41 +167,14 @@ bool LLURLDispatcherImpl::dispatchApp(const std::string& url, BOOL right_mouse)
 	{
 		return false;
 	}
-	std::string s = stripProtocol(url);
-
-	// At this point, "secondlife://app/foo/bar/baz/" should be left
-	// as: 	"app/foo/bar/baz/"
-	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-	boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
-	tokenizer tokens(s, sep);
-	tokenizer::iterator it = tokens.begin();
-	tokenizer::iterator end = tokens.end();
-
-	// Build parameter list suitable for LLDispatcher dispatch
-	if (it == end) return false;
-	if (*it != "app") return false;
-	++it;
-
-	if (it == end) return false;
-	std::string cmd = *it;
-	++it;
-
-	std::vector<std::string> params;
-	for ( ; it != end; ++it)
-	{
-		params.push_back(*it);
-	}
 
-	bool handled = LLCommandDispatcher::dispatch(cmd, params);
-	if (handled) return true;
-
-	// Inform the user we can't handle this
-	std::map<std::string, std::string> args;
-	args["[SLURL]"] = url;
-	gViewerWindow->alertXml("BadURL", args);
-	// This was a SLURL with a /app prefix, and we "handled" it by displaying an error dialog,
-	// so return true.  It doesn't need to be parsed any further.
-	return true;
+	LLURI uri(url);
+	LLSD pathArray = uri.pathArray();
+	pathArray.erase(0); // erase "app"
+	std::string cmd = pathArray.get(0);
+	pathArray.erase(0); // erase "cmd"
+	bool handled = LLCommandDispatcher::dispatch(cmd, pathArray, uri.queryMap());
+	return handled;
 }
 
 // static
@@ -209,14 +187,14 @@ bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, BOOL right_mous
 
 	// Before we're logged in, need to update the startup screen
 	// to tell the user where they are going.
-	if (LLStartUp::getStartupState() < STATE_CLEANUP)
+	if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
 	{
 		// Parse it and stash in globals, it will be dispatched in
 		// STATE_CLEANUP.
 		LLURLSimString::setString(url);
 		// We're at the login screen, so make sure user can see
 		// the login location box to know where they are going.
-		LLPanelLogin::refreshLocation( true );
+		LLPanelLogin::loadLoginPage();
 		return true;
 	}
 
@@ -312,7 +290,7 @@ class LLTeleportHandler : public LLCommandHandler
 {
 public:
 	LLTeleportHandler() : LLCommandHandler("teleport") { }
-	bool handle(const std::vector<std::string>& tokens)
+	bool handle(const LLSD& tokens, const LLSD& queryMap)
 	{
 		// construct a "normal" SLURL, resolve the region to
 		// a global position, and teleport to it
@@ -323,9 +301,9 @@ class LLTeleportHandler : public LLCommandHandler
 
 		// build secondlife://De%20Haro/123/45/67 for use in callback
 		std::string url = SLURL_SECONDLIFE_PREFIX;
-		for (size_t i = 0; i < tokens.size(); ++i)
+		for (int i = 0; i < tokens.size(); ++i)
 		{
-			url += tokens[i] + "/";
+			url += tokens[i].asString() + "/";
 		}
 		gWorldMap->sendNamedRegionRequest(region_name,
 			LLURLDispatcherImpl::regionHandleCallback,
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index be595e616c8e886bba096e299593648124d99dd2..688b2889c8da0bdf975d9732027e77d4f1667881 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -235,6 +235,7 @@ extern BOOL gAllowSelectAvatar;
 LLMenuBarGL		*gMenuBarView = NULL;
 LLViewerMenuHolderGL	*gMenuHolder = NULL;
 LLMenuGL		*gPopupMenuView = NULL;
+LLMenuBarGL		*gLoginMenuBarView = NULL;
 
 // Pie menus
 LLPieMenu	*gPieSelf	= NULL;
@@ -750,6 +751,15 @@ void init_menus()
 	// Debug menu visiblity
 	//
 	show_debug_menus();
+
+	gLoginMenuBarView = (LLMenuBarGL*)gUICtrlFactory->buildMenu("menu_login.xml", gMenuHolder);
+	LLRect menuBarRect = gLoginMenuBarView->getRect();
+	gLoginMenuBarView->setRect(LLRect(menuBarRect.mLeft, menuBarRect.mTop, gViewerWindow->getRootView()->getRect().getWidth() - menuBarRect.mLeft,  menuBarRect.mBottom));
+
+	gLoginMenuBarView->setBackgroundColor( color );
+
+	gMenuHolder->addChild(gLoginMenuBarView);
+	
 }
 
 void init_landmark_menu(LLMenuGL* menu)
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index 55fab8608977510df835a8b2a696072a1ead5cf3..6814c31eb8067930a2a0fa47d803dce4f28c189e 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -141,6 +141,7 @@ extern LLMenuBarGL*		gMenuBarView;
 //extern LLView*			gMenuBarHolder;
 extern LLMenuGL*		gPopupMenuView;
 extern LLViewerMenuHolderGL*	gMenuHolder;
+extern LLMenuBarGL*		gLoginMenuBarView;
 
 // Pie menus
 extern LLPieMenu	*gPieSelf;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 74788f6f26dad3fb3a903b6db067397c45e0de4d..bc41a88e2766978454dd064f736bdf6b6fe390b7 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -31,6 +31,7 @@
 
 #include "llviewerprecompiledheaders.h"
 
+#include "llpanellogin.h"
 #include "llviewerwindow.h"
 
 // system library includes
@@ -105,6 +106,7 @@
 #include "llfloatermap.h"
 #include "llfloatermute.h"
 #include "llfloaternamedesc.h"
+#include "llfloaterpreference.h"
 #include "llfloatersnapshot.h"
 #include "llfloatertools.h"
 #include "llfloaterworldmap.h"
@@ -2842,7 +2844,7 @@ BOOL LLViewerWindow::handlePerFrameHover()
 	// *NOTE: sometimes tools handle the mouse as a captor, so this
 	// logic is a little confusing
 	LLTool *tool = NULL;
-	if (gToolMgr && gHoverView)
+	if (gToolMgr && gHoverView && gCamera)
 	{
 		tool = gToolMgr->getCurrentTool();
 
@@ -2915,8 +2917,8 @@ BOOL LLViewerWindow::handlePerFrameHover()
 			mToolTip->setVisible( TRUE );
 		}
 	}		
-
-	if (tool != gToolNull  && tool != gToolInspect && tool != gToolDragAndDrop && !gSavedSettings.getBOOL("FreezeTime"))
+	
+	if (tool && tool != gToolNull  && tool != gToolInspect && tool != gToolDragAndDrop && !gSavedSettings.getBOOL("FreezeTime"))
 	{ 
 		LLMouseHandler *captor = gFocusMgr.getMouseCapture();
 		// With the null, inspect, or drag and drop tool, don't muck
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 39d8c2e640dc6d783b9eb26f35a5c9059ed15231..7bb12f78535307a78975c4ba38af593e0c7c7bed 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -450,6 +450,8 @@ def construct(self):
                 if self.prefix("linux_tools", ""):
                         self.path("client-readme.txt","README-linux.txt")
                         self.path("wrapper.sh","secondlife")
+                        self.path("handle_secondlifeprotocol.sh")
+                        self.path("register_secondlifeprotocol.sh")
                         self.path("unicode.ttf","unicode.ttf")
                         self.end_prefix("linux_tools")