diff options
Diffstat (limited to 'indra/newview')
108 files changed, 9374 insertions, 15934 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e0a31875c8..47fde08a9d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -7,7 +7,6 @@ include(Boost)  include(BuildVersion)  include(DBusGlib)  include(DirectX) -include(OpenSSL)  include(DragDrop)  include(ELFIO)  include(FMOD) @@ -372,8 +371,6 @@ set(viewer_SOURCE_FILES      llscrollingpanelparam.cpp      llsearchcombobox.cpp      llsearchhistory.cpp -    llsecapi.cpp -    llsechandler_basic.cpp      llselectmgr.cpp      llsidepanelappearance.cpp      llsidepanelinventory.cpp @@ -448,6 +445,7 @@ set(viewer_SOURCE_FILES      llurldispatcherlistener.cpp      llurlhistory.cpp      llurllineeditorctrl.cpp +    llurlsimstring.cpp      llurlwhitelist.cpp      llvectorperfoptions.cpp      llversioninfo.cpp @@ -514,9 +512,7 @@ set(viewer_SOURCE_FILES      llvoground.cpp      llvoicechannel.cpp      llvoiceclient.cpp -    llvoicedw.cpp      llvoicevisualizer.cpp -    llvoicevivox.cpp      llvoinventorylistener.cpp      llvopartgroup.cpp      llvosky.cpp @@ -876,8 +872,6 @@ set(viewer_HEADER_FILES      llscrollingpanelparam.h      llsearchcombobox.h      llsearchhistory.h -    llsecapi.h -    llsechandler_basic.h      llselectmgr.h      llsidepanelappearance.h      llsidepanelinventory.h @@ -954,6 +948,7 @@ set(viewer_HEADER_FILES      llurldispatcherlistener.h      llurlhistory.h      llurllineeditorctrl.h +    llurlsimstring.h      llurlwhitelist.h      llvectorperfoptions.h      llversioninfo.h @@ -1017,9 +1012,7 @@ set(viewer_HEADER_FILES      llvoground.h      llvoicechannel.h      llvoiceclient.h -    llvoicedw.h      llvoicevisualizer.h -    llvoicevivox.h      llvoinventorylistener.h      llvopartgroup.h      llvosky.h @@ -1410,8 +1403,8 @@ if (WINDOWS)          ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libtcmalloc_minimal.dll          ${SHARED_LIB_STAGING_DIR}/Debug/libtcmalloc_minimal-debug.dll          ) -     endif(USE_GOOGLE_PERFTOOLS) -  +    endif(USE_GOOGLE_PERFTOOLS) +        set(COPY_INPUT_DEPENDECIES        # The following commented dependencies are determined at variably at build time. Can't do this here. @@ -1628,8 +1621,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}      ${WINDOWS_LIBRARIES}      ${XMLRPCEPI_LIBRARIES}      ${ELFIO_LIBRARIES} -    ${OPENSSL_LIBRARIES} -    ${CRYPTO_LIBRARIES}      ${LLLOGIN_LIBRARIES}      ${GOOGLE_PERFTOOLS_LIBRARIES}      ) @@ -1806,43 +1797,6 @@ if (LL_TESTS)      "${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py"      ) -  set(test_libs  -    ${LLMESSAGE_LIBRARIES}  -    ${WINDOWS_LIBRARIES}  -    ${LLVFS_LIBRARIES} -    ${LLMATH_LIBRARIES} -    ${LLCOMMON_LIBRARIES}  -    ${GOOGLEMOCK_LIBRARIES} -    ${OPENSSL_LIBRARIES} -    ${CRYPTO_LIBRARIES} -  ) - -    LL_ADD_INTEGRATION_TEST(llsechandler_basic -     llsechandler_basic.cpp -    "${test_libs}" -    ) - -  LL_ADD_INTEGRATION_TEST(llsecapi -     llsecapi.cpp -    "${test_libs}" -    ) - -  set(llslurl_test_sources -      llslurl.cpp -      llviewernetwork.cpp -  ) - - -  LL_ADD_INTEGRATION_TEST(llslurl -     "${llslurl_test_sources}" -    "${test_libs}" -    ) - -  LL_ADD_INTEGRATION_TEST(llviewernetwork -     llviewernetwork.cpp -    "${test_libs}" -    ) -    #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)    #ADD_VIEWER_BUILD_TEST(llagentaccess viewer)    #ADD_VIEWER_BUILD_TEST(llworldmap viewer) @@ -1850,7 +1804,6 @@ if (LL_TESTS)    #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)    #ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)    #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer) -  endif (LL_TESTS) diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index 7436c5642e..4cb01a0f33 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -18,33 +18,6 @@  	<string>APPL</string>  	<key>CFBundleSignature</key>  	<string>????</string> -        <key>CFBundleDocumentTypes</key> -        <array> -                <dict> -                        <key>CFBundleTypeExtensions</key> -                        <array> -                                <string>slurl</string> -                        </array> -                        <key>CFBundleTypeIconFile</key> -                        <string>seconlife</string> -                        <key>CFBundleTypeMIMETypes</key> -                        <array> -                                <string>application/x-grid-location-info</string> -                        </array> -                        <key>CFBundleTypeName</key> -                        <string>Secondlife SLURL</string> -			<key>CFBundleTypeOSTypes</key> -			<array> -			  <string>SLRL</string> -			</array> -                        <key>CFBundleTypeRole</key> -                        <string>Viewer</string> -                        <key>LSTypeIsPackage</key> -			<true/> -                        <key>NSDocumentClass</key> -                        <string>SecondLifeSLURL</string> -                </dict> -        </array>  	<key>CFBundleURLTypes</key>  	<array>  		<dict> @@ -53,7 +26,6 @@  			<key>CFBundleURLSchemes</key>  			<array>  				<string>secondlife</string> -				<string>x-grid-location-info</string>  			</array>  			<key>LSIsAppleDefaultForScheme</key>  			<true/> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 442cd5d31e..30049b73ea 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1264,17 +1264,6 @@        <key>Value</key>        <integer>0</integer>      </map> -    <key>CertStore</key> -    <map> -      <key>Comment</key> -      <string>Specifies the Certificate Store for certificate trust verification</string> -      <key>Persist</key> -      <integer>1</integer> -      <key>Type</key> -      <string>String</string> -      <key>Value</key> -      <string>default</string> -    </map>      <key>ChatBarStealsFocus</key>      <map>        <key>Comment</key> @@ -1651,17 +1640,6 @@        <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> @@ -2388,29 +2366,6 @@        <key>Value</key>        <integer>0</integer>      </map> -	<key>DefaultFemaleAvatar</key> -	<map> -	  <key>Comment</key> -	  <string>Default Female Avatar</string> -	  <key>Persist</key> -	  <integer>1</integer> -	  <key>Type</key> -	  <string>String</string> -	  <key>Value</key> -	  <string>Female Shape & Outfit</string> -	</map> -	<key>DefaultMaleAvatar</key> -	<map> -	  <key>Comment</key> -	  <string>Default Male Avatar</string> -	  <key>Persist</key> -	  <integer>1</integer> -	  <key>Type</key> -	  <string>String</string> -	  <key>Value</key> -	  <string>Male Shape & Outfit</string> -	</map> -      <key>DefaultObjectTexture</key>      <map>        <key>Comment</key> @@ -3487,7 +3442,7 @@        <key>Type</key>        <string>Boolean</string>        <key>Value</key> -      <integer>1</integer> +      <integer>0</integer>      </map>      <key>ForceMandatoryUpdate</key>      <map> @@ -7741,17 +7696,6 @@        <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> @@ -8556,7 +8500,7 @@        <key>Type</key>        <string>Boolean</string>        <key>Value</key> -      <integer>1</integer> +      <integer>0</integer>      </map>      <key>ShowTangentBasis</key>      <map> @@ -10449,17 +10393,6 @@        <key>Value</key>        <string></string>      </map> -    <key>VivoxDebugSIPURIHostName</key> -    <map> -      <key>Comment</key> -      <string>Hostname portion of vivox SIP URIs (empty string for the default).</string> -      <key>Persist</key> -      <integer>1</integer> -      <key>Type</key> -      <string>String</string> -      <key>Value</key> -      <string></string> -    </map>      <key>VivoxDebugVoiceAccountServerURI</key>      <map>        <key>Comment</key> @@ -10471,28 +10404,6 @@        <key>Value</key>        <string></string>      </map> -    <key>VivoxVoiceHost</key> -    <map> -      <key>Comment</key> -      <string>Client SLVoice host to connect to</string> -      <key>Persist</key> -      <integer>1</integer> -      <key>Type</key> -      <string>String</string> -      <key>Value</key> -      <string>127.0.0.1</string> -    </map> -    <key>VivoxVoicePort</key> -    <map> -      <key>Comment</key> -      <string>Client SLVoice port to connect to</string> -      <key>Persist</key> -      <integer>1</integer> -      <key>Type</key> -      <string>U32</string> -      <key>Value</key> -      <integer>44125</integer> -    </map>      <key>VoiceCallsFriendsOnly</key>      <map>        <key>Comment</key> @@ -10625,17 +10536,6 @@        <key>Value</key>        <string>Default</string>      </map> -    <key>VoiceLogFile</key> -    <map> -      <key>Comment</key> -      <string>Log file to use when launching the voice daemon</string> -      <key>Persist</key> -      <integer>1</integer> -      <key>Type</key> -      <string>String</string> -      <key>Value</key> -      <string></string> -    </map>      <key>VoiceOutputAudioDevice</key>      <map>        <key>Comment</key> @@ -10680,17 +10580,6 @@        <key>Value</key>        <integer>0</integer>      </map> -    <key>VoiceServerType</key> -    <map> -      <key>Comment</key> -      <string>The type of voice server to connect to.</string> -      <key>Persist</key> -      <integer>0</integer> -      <key>Type</key> -      <string>String</string> -      <key>Value</key> -      <string>vivox</string> -    </map>      <key>WLSkyDetail</key>      <map>        <key>Comment</key> diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index b7b4c54001..a7322749ca 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -797,12 +797,6 @@ WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" '"$INSTDIR\$INSTEXE"'  ;; URL param must be last item passed to viewer, it ignores subsequent params  ;; to avoid parameter injection attacks.  WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"' -WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info"(default)" "URL:Second Life" -WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "URL Protocol" "" -WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" '"$INSTDIR\$INSTEXE"' -;; URL param must be last item passed to viewer, it ignores subsequent params -;; to avoid parameter injection attacks. -WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"'  ; write out uninstaller  WriteUninstaller "$INSTDIR\uninst.exe" diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 37d1bd15e1..f434782977 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3231,7 +3231,7 @@ bool LLAgent::teleportCore(bool is_local)  	// MBW -- Let the voice client know a teleport has begun so it can leave the existing channel.  	// This was breaking the case of teleporting within a single sim.  Backing it out for now. -//	LLVoiceClient::getInstance()->leaveChannel(); +//	gVoiceClient->leaveChannel();  	return true;  } @@ -3375,7 +3375,7 @@ void LLAgent::setTeleportState(ETeleportState state)  	if (mTeleportState == TELEPORT_MOVING)  	{  		// We're outa here. Save "back" slurl. -		LLAgentUI::buildSLURL(mTeleportSourceSLURL); +		mTeleportSourceSLURL = LLAgentUI::buildSLURL();  	}  	else if(mTeleportState == TELEPORT_ARRIVING)  	{ diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 32f9b00135..a460077b7e 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -42,7 +42,6 @@  #include "llpointer.h"  #include "lluicolor.h"  #include "llvoavatardefines.h" -#include "llslurl.h"  extern const BOOL 	ANIMATE;  extern const U8 	AGENT_STATE_TYPING;  // Typing indication @@ -515,13 +514,13 @@ public:  public:  	static void 	parseTeleportMessages(const std::string& xml_filename); -	const void getTeleportSourceSLURL(LLSLURL& slurl) const { slurl = mTeleportSourceSLURL; } +	const std::string getTeleportSourceSLURL() const { return mTeleportSourceSLURL; }  public:  	// ! TODO ! Define ERROR and PROGRESS enums here instead of exposing the mappings.  	static std::map<std::string, std::string> sTeleportErrorMessages;  	static std::map<std::string, std::string> sTeleportProgressMessages;  private: -	LLSLURL	mTeleportSourceSLURL; 			// SLURL where last TP began +	std::string		mTeleportSourceSLURL; 			// SLURL where last TP began  	//--------------------------------------------------------------------  	// Teleport Actions diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 7a8205acb5..b3ed7c353e 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -53,10 +53,7 @@ void LLAgentListener::requestTeleport(LLSD const & event_data) const  	}  	else  	{ -		std::string url = LLSLURL(event_data["regionname"],  -								  LLVector3(event_data["x"].asReal(),  -											event_data["y"].asReal(),  -											event_data["z"].asReal())).getSLURLString(); +		std::string url = LLSLURL::buildSLURL(event_data["regionname"], event_data["x"], event_data["y"], event_data["z"]);  		LLURLDispatcher::dispatch(url, NULL, false);  	}  } diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index 15d9f36b74..c4597ad6f8 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -76,15 +76,16 @@ void LLAgentUI::buildFullname(std::string& name)  }  //static -void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /*= true*/) +std::string LLAgentUI::buildSLURL(const bool escaped /*= true*/)  { -      LLSLURL return_slurl; -      LLViewerRegion *regionp = gAgent.getRegion(); -      if (regionp) -      { -		  return_slurl = LLSLURL(regionp->getName(), gAgent.getPositionGlobal()); -      } -	slurl = return_slurl; +	std::string slurl; +	LLViewerRegion *regionp = gAgent.getRegion(); +	if (regionp) +	{ +		LLVector3d agentPos = gAgent.getPositionGlobal(); +		slurl = LLSLURL::buildSLURLfromPosGlobal(regionp->getName(), agentPos, escaped); +	} +	return slurl;  }  //static diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h index 577b752fbe..3478793e38 100644 --- a/indra/newview/llagentui.h +++ b/indra/newview/llagentui.h @@ -33,8 +33,6 @@  #ifndef LLAGENTUI_H  #define LLAGENTUI_H -class LLSLURL; -  class LLAgentUI  {  public: @@ -50,7 +48,7 @@ public:  	static void buildName(std::string& name);  	static void buildFullname(std::string &name); -	static void buildSLURL(LLSLURL& slurl, const bool escaped = true); +	static std::string buildSLURL(const bool escaped = true);  	//build location string using the current position of gAgent.  	static BOOL buildLocationString(std::string& str, ELocationFormat fmt = LOCATION_FORMAT_LANDMARK);  	//build location string using a region position of the avatar.  diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 2a355474b1..43c8c679c6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -153,7 +153,7 @@  #include "llworld.h"  #include "llhudeffecttrail.h"  #include "llvectorperfoptions.h" -#include "llslurl.h" +#include "llurlsimstring.h"  #include "llwatchdog.h"  // Included so that constants/settings might be initialized @@ -193,9 +193,6 @@  #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  @@ -510,6 +507,35 @@ 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()  { @@ -621,6 +647,7 @@ bool LLAppViewer::init()      LLCurl::initClass();      initThreads(); +      writeSystemInfo();  	// Build a string representing the current version number. @@ -750,6 +777,10 @@ 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 @@ -861,7 +892,6 @@ bool LLAppViewer::init()  		}  	} -  	// save the graphics card  	gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); @@ -872,17 +902,6 @@ bool LLAppViewer::init()  	gSimFrames = (F32)gFrameCount;  	LLViewerJoystick::getInstance()->init(false); - -	try { -		initializeSecHandler(); -	} -	catch (LLProtectedDataException ex) -	{ -	  LLNotificationsUtil::add("CorruptedProtectedDataStore"); -	} -	LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback); - -  	gGLActive = FALSE;  	if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)  	{ @@ -917,11 +936,13 @@ bool LLAppViewer::mainLoop()  	gServicePump = new LLPumpIO(gAPRPoolp);  	LLHTTPClient::setPump(*gServicePump);  	LLCurl::setCAFile(gDirUtilp->getCAFile()); - +	LLCurl::setSSLVerify(! gSavedSettings.getBOOL("NoVerifySSLCert")); +	  	// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.  	LLVoiceChannel::initClass(); -	LLVoiceClient::getInstance()->init(gServicePump); +	LLVoiceClient::init(gServicePump); +  	LLTimer frameTimer,idleTimer;  	LLTimer debugTime;  	LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); @@ -1252,7 +1273,7 @@ bool LLAppViewer::cleanup()  	// to ensure shutdown order  	LLMortician::setZealous(TRUE); -	LLVoiceClient::getInstance()->terminate(); +	LLVoiceClient::terminate();  	disconnectViewer(); @@ -1451,6 +1472,13 @@ 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()); @@ -2019,6 +2047,7 @@ 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")) @@ -2112,17 +2141,30 @@ bool LLAppViewer::initConfiguration()      // injection and steal passwords. Phoenix. SL-55321      if(clp.hasOption("url"))      { -		LLStartUp::setStartSLURL(LLSLURL(clp.getOption("url")[0])); -		if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION)  -		{   -			LLGridManager::getInstance()->setGridChoice(LLStartUp::getStartSLURL().getGrid()); -			 -		}   +        std::string slurl = clp.getOption("url")[0]; +        if (LLSLURL::isSLURLCommand(slurl)) +        { +	        LLStartUp::sSLURLCommand = slurl; +        } +        else +        { +	        LLURLSimString::setString(slurl); +        }      }      else if(clp.hasOption("slurl"))      { -		LLSLURL start_slurl(clp.getOption("slurl")[0]); -		LLStartUp::setStartSLURL(start_slurl); +        std::string slurl = clp.getOption("slurl")[0]; +        if(LLSLURL::isSLURL(slurl)) +        { +            if (LLSLURL::isSLURLCommand(slurl)) +            { +	            LLStartUp::sSLURLCommand = slurl; +            } +            else +            { +	            LLURLSimString::setString(slurl); +            } +        }      }      const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); @@ -2203,10 +2245,18 @@ bool LLAppViewer::initConfiguration()  	// don't call anotherInstanceRunning() when doing URL handoff, as  	// it relies on checking a marker file which will not work when running  	// out of different directories - -	if (LLStartUp::getStartSLURL().isValid()) +	std::string slurl; +	if (!LLStartUp::sSLURLCommand.empty()) +	{ +		slurl = LLStartUp::sSLURLCommand; +	} +	else if (LLURLSimString::parse()) +	{ +		slurl = LLURLSimString::getURL(); +	} +	if (!slurl.empty())  	{ -		if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString())) +		if (sendURLToOtherInstance(slurl))  		{  			// successfully handed off URL to existing instance, exit  			return false; @@ -2262,9 +2312,9 @@ bool LLAppViewer::initConfiguration()     	// need to do this here - need to have initialized global settings first  	std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); -	if ( !nextLoginLocation.empty() ) +	if ( nextLoginLocation.length() )  	{ -		LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation)); +		LLURLSimString::setString( nextLoginLocation );  	};  	gLastRunVersion = gSavedSettings.getString("LastRunVersion"); @@ -2485,7 +2535,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"] = LLGridManager::getInstance()->getGridLabel(); +	gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();  	// *FIX:Mani - move this ddown in llappviewerwin32  #ifdef LL_WINDOWS @@ -3836,7 +3886,7 @@ void LLAppViewer::sendLogoutRequest()  		gLogoutMaxTime = LOGOUT_REQUEST_TIME;  		mLogoutRequestSent = TRUE; -		LLVoiceClient::getInstance()->leaveChannel(); +		gVoiceClient->leaveChannel();  		//Set internal status variables and marker files  		gLogoutInProgress = TRUE; @@ -4256,7 +4306,7 @@ void LLAppViewer::launchUpdater()  #endif  	// *TODO change userserver to be grid on both viewer and sim, since  	// userserver no longer exists. -	query_map["userserver"] = LLGridManager::getInstance()->getGridLabel(); +	query_map["userserver"] = LLViewerLogin::getInstance()->getGridLabel();  	query_map["channel"] = gSavedSettings.getString("VersionChannelName");  	// *TODO constantize this guy  	// *NOTE: This URL is also used in win_setup/lldownloader.cpp @@ -4269,10 +4319,10 @@ void LLAppViewer::launchUpdater()  	LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;  	// if a sim name was passed in via command line parameter (typically through a SLURL) -	if ( LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION ) +	if ( LLURLSimString::sInstance.mSimString.length() )  	{  		// record the location to start at next time -		gSavedSettings.setString( "NextLoginLocation", LLStartUp::getStartSLURL().getSLURLString());  +		gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString );   	};  #if LL_WINDOWS diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 27e8bec1d5..a915b7fa50 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -191,6 +191,7 @@ 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/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 78b0f7ba83..d34bcb4a68 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -604,7 +604,7 @@ void LLAppViewerLinux::handleCrashReporting(bool reportFreeze)  				{cmd.c_str(),  				 ask_dialog,  				 "-user", -				 (char*)LLGridManager::getInstance()->getGridLabel().c_str(), +				 (char*)LLViewerLogin::getInstance()->getGridLabel().c_str(),  				 "-name",  				 LLAppViewer::instance()->getSecondLifeTitle().c_str(),  				 NULL}; diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 58d28883c6..80d9b14345 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -44,6 +44,7 @@  #include "llviewernetwork.h"  #include "llviewercontrol.h"  #include "llmd5.h" +#include "llurlsimstring.h"  #include "llfloaterworldmap.h"  #include "llurldispatcher.h"  #include <Carbon/Carbon.h> diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 48a85dc73f..c85c72837c 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -282,7 +282,7 @@ bool LLAvatarActions::isCalling(const LLUUID &id)  //static  bool LLAvatarActions::canCall()  { -		return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); +		return LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();  }  // static diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 9824f59358..41bee540fc 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -319,7 +319,7 @@ void LLBottomTray::onChange(EStatusType status, const std::string &channelURI, b  	// skipped to avoid button blinking  	if (status != STATUS_JOINING && status!= STATUS_LEFT_CHANNEL)  	{ -		mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); +		mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());  	}  } @@ -489,7 +489,7 @@ BOOL LLBottomTray::postBuild()  	mSpeakBtn->setShowToolTip( getString("VoiceControlBtnToolTip") );  	// Registering Chat Bar to receive Voice client status change notifications. -	LLVoiceClient::getInstance()->addObserver(this); +	gVoiceClient->addObserver(this);  	mObjectDefaultWidthMap[RS_BUTTON_GESTURES] = mGesturePanel->getRect().getWidth();  	mObjectDefaultWidthMap[RS_BUTTON_MOVEMENT] = mMovementPanel->getRect().getWidth(); diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index df3fe522b5..44f1cefafe 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -133,7 +133,7 @@ LLCallFloater::~LLCallFloater()  	if(LLVoiceClient::instanceExists())  	{ -		LLVoiceClient::getInstance()->removeObserver(this); +		gVoiceClient->removeObserver(this);  	}  	LLTransientFloaterMgr::getInstance()->removeControlView(this);  } @@ -189,7 +189,7 @@ void LLCallFloater::draw()  	// Seems this is a problem somewhere in Voice Client (LLVoiceClient::participantAddedEvent)  //	onChange(); -	bool is_moderator_muted = LLVoiceClient::getInstance()->getIsModeratorMuted(gAgentID); +	bool is_moderator_muted = gVoiceClient->getIsModeratorMuted(gAgentID);  	if (mIsModeratorMutedVoice != is_moderator_muted)  	{ @@ -207,6 +207,7 @@ void LLCallFloater::draw()  void LLCallFloater::onChange()  {  	if (NULL == mParticipants) return; +  	updateParticipantsVoiceState();  	// Add newly joined participants. @@ -236,11 +237,11 @@ void LLCallFloater::updateSession()  	LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();  	if (voice_channel)  	{ -		LL_DEBUGS("Voice") << "Current voice channel: " << voice_channel->getSessionID() << LL_ENDL; +		lldebugs << "Current voice channel: " << voice_channel->getSessionID() << llendl;  		if (mSpeakerManager && voice_channel->getSessionID() == mSpeakerManager->getSessionID())  		{ -			LL_DEBUGS("Voice") << "Speaker manager is already set for session: " << voice_channel->getSessionID() << LL_ENDL; +			lldebugs << "Speaker manager is already set for session: " << voice_channel->getSessionID() << llendl;  			return;  		}  		else @@ -250,6 +251,7 @@ void LLCallFloater::updateSession()  	}  	const LLUUID& session_id = voice_channel ? voice_channel->getSessionID() : LLUUID::null; +	lldebugs << "Set speaker manager for session: " << session_id << llendl;  	LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id);  	if (im_session) @@ -289,7 +291,7 @@ void LLCallFloater::updateSession()  	{  		// by default let show nearby chat participants  		mSpeakerManager = LLLocalSpeakerMgr::getInstance(); -		LL_DEBUGS("Voice") << "Set DEFAULT speaker manager" << LL_ENDL; +		lldebugs << "Set DEFAULT speaker manager" << llendl;  		mVoiceType = VC_LOCAL_CHAT;  	} @@ -468,15 +470,16 @@ void LLCallFloater::updateAgentModeratorState()  static void get_voice_participants_uuids(uuid_vec_t& speakers_uuids)  {  	// Get a list of participants from VoiceClient -       std::set<LLUUID> participants; -       LLVoiceClient::getInstance()->getParticipantList(participants); -	 -	for (std::set<LLUUID>::const_iterator iter = participants.begin(); -		 iter != participants.end(); ++iter) +	LLVoiceClient::participantMap *voice_map = gVoiceClient->getParticipantList(); +	if (voice_map)  	{ -		speakers_uuids.push_back(*iter); +		for (LLVoiceClient::participantMap::const_iterator iter = voice_map->begin(); +			iter != voice_map->end(); ++iter) +		{ +			LLUUID id = (*iter).second->mAvatarID; +			speakers_uuids.push_back(id); +		}  	} -  }  void LLCallFloater::initParticipantsVoiceState() @@ -552,7 +555,7 @@ void LLCallFloater::updateParticipantsVoiceState()  		uuid_vec_t::iterator speakers_iter = std::find(speakers_uuids.begin(), speakers_uuids.end(), participant_id); -		LL_DEBUGS("Voice") << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << LL_ENDL; +		lldebugs << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << llendl;  		// If an avatarID assigned to a panel is found in a speakers list  		// obtained from VoiceClient we assign the JOINED status to the owner @@ -722,7 +725,7 @@ void LLCallFloater::connectToChannel(LLVoiceChannel* channel)  void LLCallFloater::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state)  {  	// check is voice operational and if it doesn't work hide VCP (EXT-4397) -	if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()) +	if(LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking())  	{  		updateState(new_state);  	} diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 1a6c11fa73..79a2631c31 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -700,7 +700,6 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)  						args["FIRST"] = first;  						args["LAST"] = last;  					} -  				}  			}  			else diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 31feabe722..68c31d87fa 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -647,19 +647,20 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL  			if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())  			{  				// for object IMs, create a secondlife:///app/objectim SLapp -				std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString(); +				std::string url = LLSLURL::buildCommand("objectim", chat.mFromID, "");  				url += "?name=" + chat.mFromName;  				url += "&owner=" + args["owner_id"].asString();  				std::string slurl = args["slurl"].asString();  				if (slurl.empty())  				{ -				    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); -				    if(region) -				      { -					LLSLURL region_slurl(region->getName(), chat.mPosAgent); -					slurl = region_slurl.getLocationString(); -				      } +					LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); +					if (region) +					{ +						S32 x, y, z; +						LLSLURL::globalPosToXYZ(LLVector3d(chat.mPosAgent), x, y, z); +						slurl = region->getName() + llformat("/%d/%d/%d", x, y, z); +					}  				}  				url += "&slurl=" + slurl; diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index fd3df359bd..be6c15eab4 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 = LLGridManager::getInstance()->getHelperURI() + "currency.php"; +		transactionURI = LLViewerLogin::getInstance()->getHelperURI() + "currency.php";  	}  	delete mTransaction; diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 56bc4a7933..ef69f39ad2 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -266,18 +266,8 @@ LLSD LLFloaterAbout::getInfo()  	info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();  	bool want_fullname = true;  	info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD(); -	if(LLVoiceClient::getInstance()->voiceEnabled()) -	{ -		LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion(); -		std::ostringstream version_string; -		version_string << version.serverType << " " << version.serverVersion << std::endl; -		info["VOICE_VERSION"] = version_string.str(); -	} -	else  -	{ -		info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); -	} -	 +	info["VIVOX_VERSION"] = gVoiceClient ? gVoiceClient->getAPIVersion() : LLTrans::getString("NotConnected"); +  	// TODO: Implement media plugin version query  	info["QT_WEBKIT_VERSION"] = "4.6 (version number hard-coded)"; diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 464b3a7214..d37bc01885 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -830,7 +830,7 @@ void LLFloaterBuyLandUI::updateNames()  	else  	{  		mParcelSellerName = -			LLSLURL("agent", parcelp->getOwnerID(), "inspect").getSLURLString(); +			LLSLURL::buildCommand("agent", parcelp->getOwnerID(), "inspect");  	}  } @@ -859,7 +859,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa  	static std::string transaction_uri;  	if (transaction_uri.empty())  	{ -		transaction_uri = LLGridManager::getInstance()->getHelperURI() + "landtool.php"; +		transaction_uri = LLViewerLogin::getInstance()->getHelperURI() + "landtool.php";  	}  	const char* method; diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index 882d12f68e..cdb9b8edb8 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -166,7 +166,7 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4&  	if (chat.mSourceType == CHAT_SOURCE_AGENT &&  		chat.mFromID != LLUUID::null)  	{ -		chat.mURL = LLSLURL("agent", chat.mFromID, "inspect").getSLURLString(); +		chat.mURL = LLSLURL::buildCommand("agent", chat.mFromID, "inspect");  	}  	// If the chat line has an associated url, link it up to the name. diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index a15cef7ea4..774caaec90 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -318,7 +318,7 @@ LLFloaterChatterBox* LLFloaterChatterBox::getInstance()  //static   LLFloater* LLFloaterChatterBox::getCurrentVoiceFloater()  { -	if (!LLVoiceClient::getInstance()->voiceEnabled()) +	if (!LLVoiceClient::voiceEnabled())  	{  		return NULL;  	} diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp index 84a5c3dc77..97ebab3425 100644 --- a/indra/newview/llfloaterevent.cpp +++ b/indra/newview/llfloaterevent.cpp @@ -193,7 +193,7 @@ void LLFloaterEvent::processEventInfoReply(LLMessageSystem *msg, void **)  		floater->mTBCategory->setText(floater->mEventInfo.mCategoryStr);  		floater->mTBDate->setText(floater->mEventInfo.mTimeStr);  		floater->mTBDesc->setText(floater->mEventInfo.mDesc); -		floater->mTBRunBy->setText(LLSLURL("agent", floater->mEventInfo.mRunByID, "inspect").getSLURLString()); +		floater->mTBRunBy->setText(LLSLURL::buildCommand("agent", floater->mEventInfo.mRunByID, "inspect"));  		floater->mTBDuration->setText(llformat("%d:%.2d", floater->mEventInfo.mDuration / 60, floater->mEventInfo.mDuration % 60)); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 25d3f971b5..02c83dcd09 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -42,6 +42,7 @@  #include "llnotificationsutil.h"  #include "llparcel.h"  #include "message.h" +#include "lluserauth.h"  #include "llagent.h"  #include "llbutton.h" @@ -803,7 +804,7 @@ void LLPanelLandGeneral::refreshNames()  	else  	{  		// Figure out the owner's name -		owner = LLSLURL("agent", parcel->getOwnerID(), "inspect").getSLURLString(); +		owner = LLSLURL::buildCommand("agent", parcel->getOwnerID(), "inspect");  	}  	if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus()) @@ -815,7 +816,7 @@ void LLPanelLandGeneral::refreshNames()  	std::string group;  	if (!parcel->getGroupID().isNull())  	{ -		group = LLSLURL("group", parcel->getGroupID(), "inspect").getSLURLString(); +		group = LLSLURL::buildCommand("group", parcel->getGroupID(), "inspect");  	}  	mTextGroup->setText(group); @@ -824,9 +825,9 @@ void LLPanelLandGeneral::refreshNames()  		const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID();  		if(auth_buyer_id.notNull())  		{ -		  std::string name; -		  name = LLSLURL("agent", auth_buyer_id, "inspect").getSLURLString(); -		  mSaleInfoForSale2->setTextArg("[BUYER]", name); +			std::string name; +			name = LLSLURL::buildCommand("agent", auth_buyer_id, "inspect"); +			mSaleInfoForSale2->setTextArg("[BUYER]", name);  		}  		else  		{ diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 804ef609ec..de025ac6b9 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -597,7 +597,7 @@ void LLFloaterPreference::onBtnOK()  		llinfos << "Can't close preferences!" << llendl;  	} -	LLPanelLogin::updateLocationCombo( false ); +	LLPanelLogin::refreshLocation( false );  }  // static  @@ -614,7 +614,7 @@ void LLFloaterPreference::onBtnApply( )  	apply();  	saveSettings(); -	LLPanelLogin::updateLocationCombo( false ); +	LLPanelLogin::refreshLocation( false );  }  // static  diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 8c219cb3fd..3758cbe74f 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -2922,7 +2922,8 @@ bool LLDispatchEstateUpdateInfo::operator()(  	LLUUID owner_id(strings[1]);  	regionp->setOwner(owner_id);  	// Update estate owner name in UI -	std::string owner_name = LLSLURL("agent", owner_id, "inspect").getSLURLString(); +	std::string owner_name = +		LLSLURL::buildCommand("agent", owner_id, "inspect");  	panel->setOwnerName(owner_name);  	U32 estate_id = strtoul(strings[2].c_str(), NULL, 10); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index f7c8855bf6..b42b34835d 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -126,9 +126,7 @@ void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg)  // virtual  BOOL LLFloaterReporter::postBuild()  { -	LLSLURL slurl; -	LLAgentUI::buildSLURL(slurl); -	childSetText("abuse_location_edit", slurl.getSLURLString()); +	childSetText("abuse_location_edit", LLAgentUI::buildSLURL());  	enableControls(TRUE); @@ -282,6 +280,7 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)  				{  					object_owner.append("Unknown");  				} +  				setFromAvatar(mObjectID, object_owner);  			}  			else @@ -326,8 +325,7 @@ void LLFloaterReporter::setFromAvatar(const LLUUID& avatar_id, const std::string  	mAbuserID = mObjectID = avatar_id;  	mOwnerName = avatar_name; -	std::string avatar_link = -	  LLSLURL("agent", mObjectID, "inspect").getSLURLString(); +	std::string avatar_link = LLSLURL::buildCommand("agent", mObjectID, "inspect");  	childSetText("owner_name", avatar_link);  	childSetText("object_name", avatar_name);  	childSetText("abuser_name_edit", avatar_name); @@ -506,7 +504,7 @@ void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name  {  	childSetText("object_name", object_name);  	std::string owner_link = -		LLSLURL("agent", owner_id, "inspect").getSLURLString(); +		LLSLURL::buildCommand("agent", owner_id, "inspect");  	childSetText("owner_name", owner_link);  	childSetText("abuser_name_edit", owner_name);  	mAbuserID = owner_id; @@ -568,7 +566,7 @@ LLSD LLFloaterReporter::gatherReport()  	mCopyrightWarningSeen = FALSE;  	std::ostringstream summary; -	if (!LLGridManager::getInstance()->isInProductionGrid()) +	if (!LLViewerLogin::getInstance()->isInProductionGrid())  	{  		summary << "Preview ";  	} diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index aae379afe2..adac9861d4 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1123,7 +1123,7 @@ void LLSnapshotLivePreview::saveWeb(std::string url)  void LLSnapshotLivePreview::regionNameCallback(std::string url, LLSD body, const std::string& name, S32 x, S32 y, S32 z)  { -	body["slurl"] = LLSLURL(name, LLVector3d(x, y, z)).getSLURLString(); +	body["slurl"] = LLSLURL::buildSLURL(name, x, y, z);  	LLHTTPClient::post(url, body,  		new LLSendWebResponder()); diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp index 63365e3461..638c9f1b8c 100644 --- a/indra/newview/llfloatervoicedevicesettings.cpp +++ b/indra/newview/llfloatervoicedevicesettings.cpp @@ -64,6 +64,9 @@ LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings()  	// grab "live" mic volume level  	mMicVolume = gSavedSettings.getF32("AudioLevelMic"); +	// ask for new device enumeration +	// now do this in onOpen() instead... +	//gVoiceClient->refreshDeviceLists();  }  LLPanelVoiceDeviceSettings::~LLPanelVoiceDeviceSettings() @@ -102,7 +105,7 @@ void LLPanelVoiceDeviceSettings::draw()  	refresh();  	// let user know that volume indicator is not yet available -	bool is_in_tuning_mode = LLVoiceClient::getInstance()->inTuningMode(); +	bool is_in_tuning_mode = gVoiceClient->inTuningMode();  	childSetVisible("wait_text", !is_in_tuning_mode);  	LLPanel::draw(); @@ -110,7 +113,7 @@ void LLPanelVoiceDeviceSettings::draw()  	if (is_in_tuning_mode)  	{  		const S32 num_bars = 5; -		F32 voice_power = LLVoiceClient::getInstance()->tuningGetEnergy() / LLVoiceClient::OVERDRIVEN_POWER_LEVEL; +		F32 voice_power = gVoiceClient->tuningGetEnergy() / LLVoiceClient::OVERDRIVEN_POWER_LEVEL;  		S32 discrete_power = llmin(num_bars, llfloor(voice_power * (F32)num_bars + 0.1f));  		for(S32 power_bar_idx = 0; power_bar_idx < num_bars; power_bar_idx++) @@ -191,13 +194,13 @@ void LLPanelVoiceDeviceSettings::refresh()  	LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");  	// set mic volume tuning slider based on last mic volume setting  	F32 current_volume = (F32)volume_slider->getValue().asReal(); -	LLVoiceClient::getInstance()->tuningSetMicVolume(current_volume); +	gVoiceClient->tuningSetMicVolume(current_volume);  	// Fill in popup menus  	mCtrlInputDevices = getChild<LLComboBox>("voice_input_device");  	mCtrlOutputDevices = getChild<LLComboBox>("voice_output_device"); -	if(!LLVoiceClient::getInstance()->deviceSettingsAvailable()) +	if(!gVoiceClient->deviceSettingsAvailable())  	{  		// The combo boxes are disabled, since we can't get the device settings from the daemon just now.  		// Put the currently set default (ONLY) in the box, and select it. @@ -216,16 +219,17 @@ void LLPanelVoiceDeviceSettings::refresh()  	}  	else if (!mDevicesUpdated)  	{ -		LLVoiceDeviceList::const_iterator iter; +		LLVoiceClient::deviceList *devices; +		 +		LLVoiceClient::deviceList::iterator iter;  		if(mCtrlInputDevices)  		{  			mCtrlInputDevices->removeall();  			mCtrlInputDevices->add( getString("default_text"), ADD_BOTTOM ); -			for(iter=LLVoiceClient::getInstance()->getCaptureDevices().begin();  -				iter != LLVoiceClient::getInstance()->getCaptureDevices().end(); -				iter++) +			devices = gVoiceClient->getCaptureDevices(); +			for(iter=devices->begin(); iter != devices->end(); iter++)  			{  				mCtrlInputDevices->add( *iter, ADD_BOTTOM );  			} @@ -241,8 +245,8 @@ void LLPanelVoiceDeviceSettings::refresh()  			mCtrlOutputDevices->removeall();  			mCtrlOutputDevices->add( getString("default_text"), ADD_BOTTOM ); -			for(iter= LLVoiceClient::getInstance()->getRenderDevices().begin();  -				iter !=  LLVoiceClient::getInstance()->getRenderDevices().end(); iter++) +			devices = gVoiceClient->getRenderDevices(); +			for(iter=devices->begin(); iter != devices->end(); iter++)  			{  				mCtrlOutputDevices->add( *iter, ADD_BOTTOM );  			} @@ -264,34 +268,37 @@ void LLPanelVoiceDeviceSettings::initialize()  	mDevicesUpdated = FALSE;  	// ask for new device enumeration -	LLVoiceClient::getInstance()->refreshDeviceLists(); +	gVoiceClient->refreshDeviceLists();  	// put voice client in "tuning" mode -	LLVoiceClient::getInstance()->tuningStart(); +	gVoiceClient->tuningStart();  	LLVoiceChannel::suspend();  }  void LLPanelVoiceDeviceSettings::cleanup()  { -	LLVoiceClient::getInstance()->tuningStop(); +	if (gVoiceClient) +	{ +		gVoiceClient->tuningStop(); +	}  	LLVoiceChannel::resume();  }  // static  void LLPanelVoiceDeviceSettings::onCommitInputDevice(LLUICtrl* ctrl, void* user_data)  { -	if(LLVoiceClient::getInstance()) +	if(gVoiceClient)  	{ -		LLVoiceClient::getInstance()->setCaptureDevice(ctrl->getValue().asString()); +		gVoiceClient->setCaptureDevice(ctrl->getValue().asString());  	}  }  // static  void LLPanelVoiceDeviceSettings::onCommitOutputDevice(LLUICtrl* ctrl, void* user_data)  { -	if(LLVoiceClient::getInstance()) +	if(gVoiceClient)  	{ -		LLVoiceClient::getInstance()->setRenderDevice(ctrl->getValue().asString()); +		gVoiceClient->setRenderDevice(ctrl->getValue().asString());  	}  } diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 896c410e32..f17c9765b9 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -461,7 +461,7 @@ void LLFloaterWorldMap::draw()  	childSetEnabled("Teleport", (BOOL)tracking_status);  //	childSetEnabled("Clear", (BOOL)tracking_status);  	childSetEnabled("Show Destination", (BOOL)tracking_status || LLWorldMap::getInstance()->isTracking()); -	childSetEnabled("copy_slurl", (mSLURL.isValid()) ); +	childSetEnabled("copy_slurl", (mSLURL.size() > 0) );  	setMouseOpaque(TRUE);  	getDragHandle()->setMouseOpaque(TRUE); @@ -660,8 +660,14 @@ void LLFloaterWorldMap::updateLocation()  				childSetValue("location", agent_sim_name);  				// Figure out where user is +				LLVector3d agentPos = gAgent.getPositionGlobal(); + +				S32 agent_x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) ); +				S32 agent_y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) ); +				S32 agent_z = llround( (F32)agentPos.mdV[VZ] ); +  				// Set the current SLURL -				mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal()); +				mSLURL = LLSLURL::buildSLURL(agent_sim_name, agent_x, agent_y, agent_z);  			}  		} @@ -688,15 +694,18 @@ void LLFloaterWorldMap::updateLocation()  		}  		childSetValue("location", sim_name); +		 +		F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS ); +		F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );  		// simNameFromPosGlobal can fail, so don't give the user an invalid SLURL  		if ( gotSimName )  		{ -		  mSLURL = LLSLURL(sim_name, pos_global); +			mSLURL = LLSLURL::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)pos_global.mdV[VZ]));  		}  		else  		{	// Empty SLURL will disable the "Copy SLURL to clipboard" button -			mSLURL = LLSLURL(); +			mSLURL = "";  		}  	}  } @@ -1165,7 +1174,7 @@ void LLFloaterWorldMap::onClearBtn()  	mTrackedStatus = LLTracker::TRACKING_NOTHING;  	LLTracker::stopTracking((void *)(intptr_t)TRUE);  	LLWorldMap::getInstance()->cancelTracking(); -	mSLURL = LLSLURL();					// Clear the SLURL since it's invalid +	mSLURL = "";					// Clear the SLURL since it's invalid  	mSetToUserPosition = TRUE;	// Revert back to the current user position  } @@ -1188,10 +1197,10 @@ void LLFloaterWorldMap::onClickTeleportBtn()  void LLFloaterWorldMap::onCopySLURL()  { -	getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL.getSLURLString())); +	getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL));  	LLSD args; -	args["SLURL"] = mSLURL.getSLURLString(); +	args["SLURL"] = mSLURL;  	LLNotificationsUtil::add("CopySLURL", args);  } diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index 52809ff830..00f5e788fb 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -43,7 +43,6 @@  #include "llhudtext.h"  #include "llmapimagetype.h"  #include "lltracker.h" -#include "llslurl.h"  class LLEventInfo;  class LLFriendObserver; @@ -184,7 +183,7 @@ private:  	LLTracker::ETrackingStatus mTrackedStatus;  	std::string				mTrackedSimName;  	std::string				mTrackedAvatarName; -	LLSLURL  				mSLURL; +	std::string				mSLURL;  };  extern LLFloaterWorldMap* gFloaterWorldMap; diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 03a47b5983..8a056f836f 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -287,7 +287,7 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata)  		return gAgent.getGroupID() != selected_group_id;  	if (userdata.asString() == "call") -	  return real_group_selected && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); +		return real_group_selected && LLVoiceClient::voiceEnabled()&&gVoiceClient->voiceWorking();  	return real_group_selected;  } diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 9704c7537a..3ec8d11fb0 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -58,6 +58,7 @@  #include "lltransientfloatermgr.h"  #include "llinventorymodel.h"  #include "llrootview.h" +  #include "llspeakers.h" diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 0e3b78df7f..4bdf5f42dc 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -300,7 +300,7 @@ void LLFloaterIMPanel::onVolumeChange(LLUICtrl* source, void* user_data)  	LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data;  	if (floaterp)  	{ -		LLVoiceClient::getInstance()->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal()); +		gVoiceClient->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal());  	}  } @@ -312,7 +312,7 @@ void LLFloaterIMPanel::draw()  	BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "")  					  && mSessionInitialized -					  && LLVoiceClient::getInstance()->voiceEnabled() +					  && LLVoiceClient::voiceEnabled()  					  && mCallBackEnabled;  	// hide/show start call and end call buttons @@ -320,8 +320,8 @@ void LLFloaterIMPanel::draw()  	if (!voice_channel)  		return; -	childSetVisible("end_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); -	childSetVisible("start_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); +	childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); +	childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED);  	childSetEnabled("start_call_btn", enable_connect);  	childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty()); @@ -384,11 +384,11 @@ void LLFloaterIMPanel::draw()  	else  	{  		// refresh volume and mute checkbox -		childSetVisible("speaker_volume", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive()); -		childSetValue("speaker_volume", LLVoiceClient::getInstance()->getUserVolume(mOtherParticipantUUID)); +		childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && voice_channel->isActive()); +		childSetValue("speaker_volume", gVoiceClient->getUserVolume(mOtherParticipantUUID));  		childSetValue("mute_btn", LLMuteList::getInstance()->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat)); -		childSetVisible("mute_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive()); +		childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && voice_channel->isActive());  	}  	LLFloater::draw();  } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 5201f92dbc..e0f155a6a9 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -344,13 +344,13 @@ LLIMModel::LLIMSession::~LLIMSession()  	mSpeakers = NULL;  	// End the text IM session if necessary -	if(LLVoiceClient::getInstance() && mOtherParticipantID.notNull()) +	if(gVoiceClient && mOtherParticipantID.notNull())  	{  		switch(mType)  		{  		case IM_NOTHING_SPECIAL:  		case IM_SESSION_P2P_INVITE: -			LLVoiceClient::getInstance()->endUserIMSession(mOtherParticipantID); +			gVoiceClient->endUserIMSession(mOtherParticipantID);  			break;  		default: @@ -925,7 +925,7 @@ void LLIMModel::sendMessage(const std::string& utf8_text,  	if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id)))  	{  		// User is online through the OOW connector, but not with a regular viewer.  Try to send the message via SLVoice. -		sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text); +		sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text);  	}  	if(!sent) @@ -1717,7 +1717,7 @@ void LLOutgoingCallDialog::show(const LLSD& key)  		// skipping "You will now be reconnected to nearby" in notification when call is ended by disabling voice,  		// so no reconnection to nearby chat happens (EXT-4397) -		bool voice_works = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); +		bool voice_works = LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();  		std::string reconnect_nearby = voice_works ? LLTrans::getString("reconnect_nearby") : std::string();  		childSetTextArg("nearby", "[RECONNECT_NEARBY]", reconnect_nearby); @@ -1843,11 +1843,7 @@ LLCallDialog(payload)  void LLIncomingCallDialog::onLifetimeExpired()  {  	// check whether a call is valid or not -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mPayload["session_id"].asUUID()); -	if(channelp && -	   (channelp->getState() != LLVoiceChannel::STATE_NO_CHANNEL_INFO) && -	   (channelp->getState() != LLVoiceChannel::STATE_ERROR) && -	   (channelp->getState() != LLVoiceChannel::STATE_HUNG_UP)) +	if (LLVoiceClient::getInstance()->findSession(mPayload["caller_id"].asUUID()))  	{  		// restart notification's timer if call is still valid  		mLifetimeTimer.start(); @@ -2081,10 +2077,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response)  	{  		if (type == IM_SESSION_P2P_INVITE)  		{ -			if(LLVoiceClient::getInstance()) +			if(gVoiceClient)  			{  				std::string s = mPayload["session_handle"].asString(); -				LLVoiceClient::getInstance()->declineInvite(s); +				gVoiceClient->declineInvite(s);  			}  		}  		else @@ -2172,8 +2168,11 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  	{  		if (type == IM_SESSION_P2P_INVITE)  		{ -		  std::string s = payload["session_handle"].asString(); -		  LLVoiceClient::getInstance()->declineInvite(s); +			if(gVoiceClient) +			{ +				std::string s = payload["session_handle"].asString(); +				gVoiceClient->declineInvite(s); +			}  		}  		else  		{ @@ -3079,7 +3078,7 @@ public:  				return;  			} -			if(!LLVoiceClient::getInstance()->voiceEnabled()) +			if(!LLVoiceClient::voiceEnabled())  			{  				// Don't display voice invites unless the user has voice enabled.  				return; diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 1299324105..94ea236757 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -536,7 +536,8 @@ void LLInspectAvatar::toggleSelectedVoice(bool enabled)  void LLInspectAvatar::updateVolumeSlider()  { -	bool voice_enabled = LLVoiceClient::getInstance()->getVoiceEnabled(mAvatarID); + +	bool voice_enabled = gVoiceClient->getVoiceEnabled(mAvatarID);  	// Do not display volume slider and mute button if it   	// is ourself or we are not in a voice channel together @@ -566,7 +567,6 @@ void LLInspectAvatar::updateVolumeSlider()  		volume_slider->setEnabled( !is_muted );  		F32 volume; -		  		if (is_muted)  		{  			// it's clearer to display their volume as zero @@ -575,7 +575,7 @@ void LLInspectAvatar::updateVolumeSlider()  		else  		{  			// actual volume -			volume = LLVoiceClient::getInstance()->getUserVolume(mAvatarID); +			volume = gVoiceClient->getUserVolume(mAvatarID);  		}  		volume_slider->setValue( (F64)volume );  	} @@ -604,7 +604,7 @@ void LLInspectAvatar::onClickMuteVolume()  void LLInspectAvatar::onVolumeChange(const LLSD& data)  {  	F32 volume = (F32)data.asReal(); -	LLVoiceClient::getInstance()->setUserVolume(mAvatarID, volume); +	gVoiceClient->setUserVolume(mAvatarID, volume);  }  void LLInspectAvatar::nameUpdatedCallback( diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index a2b5ffbac4..91cbbbf430 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -480,7 +480,7 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep)  		// Objects cannot be created by a group, so use agent URL format  		LLUUID creator_id = nodep->mPermissions->getCreator();  		std::string creator_url = -			LLSLURL("agent", creator_id, "about").getSLURLString(); +			LLSLURL::buildCommand("agent", creator_id, "about");  		args["[CREATOR]"] = creator_url;  		// created by one user but owned by another @@ -490,12 +490,12 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep)  		if (group_owned)  		{  			owner_id = nodep->mPermissions->getGroup(); -			owner_url =	LLSLURL("group", owner_id, "about").getSLURLString(); +			owner_url =	LLSLURL::buildCommand("group", owner_id, "about");  		}  		else  		{  			owner_id = nodep->mPermissions->getOwner(); -			owner_url =	LLSLURL("agent", owner_id, "about").getSLURLString(); +			owner_url =	LLSLURL::buildCommand("agent", owner_id, "about");  		}  		args["[OWNER]"] = owner_url; diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index 97ff771658..66e4a1bf66 100644 --- a/indra/newview/llinspectremoteobject.cpp +++ b/indra/newview/llinspectremoteobject.cpp @@ -176,11 +176,11 @@ void LLInspectRemoteObject::update()  	{  		if (mGroupOwned)  		{ -			owner = LLSLURL("group", mOwnerID, "about").getSLURLString(); +			owner = LLSLURL::buildCommand("group", mOwnerID, "about");  		}  		else  		{ -			owner = LLSLURL("agent", mOwnerID, "about").getSLURLString(); +			owner = LLSLURL::buildCommand("agent", mOwnerID, "about");  		}  	}  	else diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e63da1ebb9..6452ae82f8 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1329,6 +1329,7 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)  	return cat->fetch();  } +  void LLInventoryModel::cache(  	const LLUUID& parent_folder_id,  	const LLUUID& agent_id) diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp index 539ca97a93..7336efb62a 100644 --- a/indra/newview/lllandmarkactions.cpp +++ b/indra/newview/lllandmarkactions.cpp @@ -299,7 +299,7 @@ void LLLandmarkActions::getSLURLfromPosGlobal(const LLVector3d& global_pos, slur  	bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal(global_pos, sim_name);  	if (gotSimName)  	{ -	  std::string slurl = LLSLURL(sim_name, global_pos).getSLURLString(); +		std::string slurl = LLSLURL::buildSLURLfromPosGlobal(sim_name, global_pos, escaped);  		cb(slurl);  		return; @@ -351,7 +351,7 @@ void LLLandmarkActions::onRegionResponseSLURL(slurl_callback_t cb,  	bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal(global_pos, sim_name);  	if (gotSimName)  	{ -	  slurl = LLSLURL(sim_name, global_pos).getSLURLString(); +		slurl = LLSLURL::buildSLURLfromPosGlobal(sim_name, global_pos, escaped);  	}  	else  	{ diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 936e6ed316..4e0be81f62 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -668,8 +668,9 @@ void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data)  				value["item_type"] = TELEPORT_HISTORY;  				value["global_pos"] = result->mGlobalPos.getValue();  				std::string region_name = result->mTitle.substr(0, result->mTitle.find(',')); -				//TODO*: add Surl to teleportitem or parse region name from title -				value["tooltip"] = LLSLURL(region_name, result->mGlobalPos).getSLURLString(); +				//TODO*: add slurl to teleportitem or parse region name from title +				value["tooltip"] = LLSLURL::buildSLURLfromPosGlobal(region_name, +						result->mGlobalPos,	false);  				add(result->getTitle(), value);   			}  			result = std::find_if(result + 1, th_items.end(), boost::bind( @@ -1010,9 +1011,7 @@ void LLLocationInputCtrl::changeLocationPresentation()  	if(!mTextEntry->hasSelection() && text == mHumanReadableLocation)  	{  		//needs unescaped one -		LLSLURL slurl; -		LLAgentUI::buildSLURL(slurl, false); -		mTextEntry->setText(slurl.getSLURLString()); +		mTextEntry->setText(LLAgentUI::buildSLURL(false));  		mTextEntry->selectAll();  		mMaturityIcon->setVisible(FALSE); diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index 4e0a7594ba..e3817eecc4 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -35,14 +35,13 @@  #include "llloginhandler.h"  // viewer includes -#include "llsecapi.h"  #include "lllogininstance.h"        // to check if logged in yet  #include "llpanellogin.h"			// save_password_to_disk()  #include "llstartup.h"				// getStartupState() -#include "llslurl.h" +#include "llurlsimstring.h"  #include "llviewercontrol.h"		// gSavedSettings  #include "llviewernetwork.h"		// EGridInfo -#include "llviewerwindow.h"                    // getWindow() +#include "llviewerwindow.h"			// getWindow()  // library includes  #include "llmd5.h" @@ -61,33 +60,109 @@ bool LLLoginHandler::parseDirectLogin(std::string url)  	LLURI uri(url);  	parse(uri.queryMap()); -	// NOTE: Need to add direct login as per identity evolution -	return true; +	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.has("grid")) +	EGridInfo grid_choice = GRID_INFO_NONE; +	if (queryMap["grid"].asString() == "aditi")  	{ -	  LLGridManager::getInstance()->setGridChoice(queryMap["grid"].asString()); +		grid_choice = GRID_INFO_ADITI;  	} -	 -	 -	std::string startLocation = queryMap["location"].asString(); -	 -	if (startLocation == "specify") +	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") +	{ +		grid_choice = GRID_INFO_DURGA; +	} +	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")  	{ -	  LLStartUp::setStartSLURL(LLSLURL(LLGridManager::getInstance()->getGridLoginID(), -					   queryMap["region"].asString())); +		grid_choice = GRID_INFO_YAMI;  	} -	else if (startLocation == "home") +	else if (queryMap["grid"].asString() == "nandi")  	{ -	  LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); +		grid_choice = GRID_INFO_NANDI;  	} -	else if (startLocation == "last") +	else if (queryMap["grid"].asString() == "mitra")  	{ -	  LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); +		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()); +	} +	else if (!startLocation.empty()) // "last" or "home" or ??? (let LLURLSimString figure it out) +	{ +		LLURLSimString::setString(startLocation);  	}  } @@ -145,65 +220,40 @@ bool LLLoginHandler::handle(const LLSD& tokens,  		return true;  	} -	if  (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)  //on splash page          -	{ -	  // 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; -} - +	std::string password = query_map["password"].asString(); +	if (!password.empty()) +	{ +		gSavedSettings.setBOOL("RememberPassword", TRUE); -//  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()                                          -{                                                                                                                            -	LLPointer<LLCredential> result = NULL;                                                                                -	// so try to load it from the UserLoginInfo                                                                           -	result = loadSavedUserLoginInfo();                                                                                    -	if (result.isNull())                                                                                                  -	{                                                                                                                     -		result =  gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());                        -	}                                                                                                                     -	 -	return result;                                                                                                        -}  - +		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); +		} +	} +			 -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 (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)  //on splash page  	{ -	 -		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()->getGrid(),  -													   identifier, authenticator); -	} -	return NULL; +		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;  } diff --git a/indra/newview/llloginhandler.h b/indra/newview/llloginhandler.h index c15b998c91..ac4648761b 100644 --- a/indra/newview/llloginhandler.h +++ b/indra/newview/llloginhandler.h @@ -34,7 +34,6 @@  #define LLLOGINHANDLER_H  #include "llcommandhandler.h" -#include "llsecapi.h"  class LLLoginHandler : public LLCommandHandler  { @@ -47,15 +46,19 @@ 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(); -  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 0459c85050..24c72c65ce 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -48,16 +48,13 @@  // newview  #include "llviewernetwork.h"  #include "llviewercontrol.h" -#include "llslurl.h" -#include "llstartup.h" +#include "llurlsimstring.h"  #include "llfloaterreg.h"  #include "llnotifications.h"  #include "llwindow.h"  #if LL_LINUX || LL_SOLARIS  #include "lltrans.h"  #endif -#include "llsecapi.h" -#include "llstartup.h"  static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";  static const char * const TOS_LISTENER_NAME = "lllogininstance_tos"; @@ -86,14 +83,14 @@ LLLoginInstance::~LLLoginInstance()  {  } -void LLLoginInstance::connect(LLPointer<LLCredential> credentials) +void LLLoginInstance::connect(const LLSD& credentials)  {  	std::vector<std::string> uris; -	LLGridManager::getInstance()->getLoginURIs(uris); +	LLViewerLogin::getInstance()->getLoginURIs(uris);  	connect(uris.front(), credentials);  } -void LLLoginInstance::connect(const std::string& uri, LLPointer<LLCredential> credentials) +void LLLoginInstance::connect(const std::string& uri, const LLSD& credentials)  {  	mAttemptComplete = false; // Reset attempt complete at this point!  	constructAuthParams(credentials); @@ -105,7 +102,7 @@ void LLLoginInstance::reconnect()  	// Sort of like connect, only using the pre-existing  	// request params.  	std::vector<std::string> uris; -	LLGridManager::getInstance()->getLoginURIs(uris); +	LLViewerLogin::getInstance()->getLoginURIs(uris);  	mLoginModule->connect(uris.front(), mRequestData);  } @@ -121,7 +118,7 @@ LLSD LLLoginInstance::getResponse()  	return mResponseData;   } -void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credential) +void LLLoginInstance::constructAuthParams(const LLSD& credentials)  {  	// Set up auth request options.  //#define LL_MINIMIAL_REQUESTED_OPTIONS @@ -148,10 +145,8 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia  	requested_options.append("adult_compliant");   	//requested_options.append("inventory-targets");  	requested_options.append("buddy-list"); -	requested_options.append("newuser-config");  	requested_options.append("ui-config");  #endif -	requested_options.append("voice-config");  	requested_options.append("tutorial_setting");  	requested_options.append("login-flags");  	requested_options.append("global-textures"); @@ -160,18 +155,20 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia  		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; -	unsigned char MACAddress[MAC_ADDRESS_BYTES]; -	LLUUID::getNodeID(MACAddress);	 -	hashed_mac.update( MACAddress, MAC_ADDRESS_BYTES ); +	hashed_mac.update( gMACAddress, 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  @@ -250,15 +247,6 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)  			LLSD data(LLSD::emptyMap());  			data["message"] = message_response;  			data["reply_pump"] = TOS_REPLY_PUMP; -			if(response.has("error_code")) -			{ -				data["error_code"] = response["error_code"]; -			} -			if(response.has("certificate")) -			{ -				data["certificate"] = response["certificate"]; -			} -			  			LLFloaterReg::showInstance("message_critical", data);  			LLEventPumps::instance().obtain(TOS_REPLY_PUMP)  				.listen(TOS_LISTENER_NAME, @@ -466,31 +454,20 @@ bool LLLoginInstance::updateDialogCallback(const LLSD& notification, const LLSD&  std::string construct_start_string()  {  	std::string start; -	LLSLURL start_slurl = LLStartUp::getStartSLURL(); -	switch(start_slurl.getType()) +	if (LLURLSimString::parse())  	{ -		case LLSLURL::LOCATION: -		{ -			// a startup URL was specified -			LLVector3 position = start_slurl.getPosition(); -			std::string unescaped_start =  +		// a startup URL was specified +		std::string unescaped_start =   			STRINGIZE(  "uri:"  -					  << start_slurl.getRegion() << "&"  -						<< position[VX] << "&"  -						<< position[VY] << "&"  -						<< position[VZ]); -			start = xml_escape_string(unescaped_start); -			break; -		} -		case LLSLURL::HOME_LOCATION: -		{ -			start = "home"; -			break; -		} -		default: -		{ -			start = "last"; -		} +						<< LLURLSimString::sInstance.mSimName << "&"  +						<< LLURLSimString::sInstance.mX << "&"  +						<< LLURLSimString::sInstance.mY << "&"  +						<< LLURLSimString::sInstance.mZ); +		start = xml_escape_string(unescaped_start); +	} +	else +	{ +		start = gSavedSettings.getString("LoginLocation");  	}  	return start;  } diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index 44271bb75e..c8704eddb4 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -36,7 +36,6 @@  #include "lleventdispatcher.h"  #include <boost/scoped_ptr.hpp>  #include <boost/function.hpp> -#include "llsecapi.h"  class LLLogin;  class LLEventStream;  class LLNotificationsInterface; @@ -49,8 +48,8 @@ public:  	LLLoginInstance();  	~LLLoginInstance(); -	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 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 reconnect(); // reconnect using the current credentials.  	void disconnect(); @@ -82,7 +81,7 @@ public:  	void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; }  private: -	void constructAuthParams(LLPointer<LLCredential> user_credentials); +	void constructAuthParams(const LLSD& credentials);   	void updateApp(bool mandatory, const std::string& message);  	bool updateDialogCallback(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index c3d0f1bfc2..e11df06d86 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -52,6 +52,7 @@  #include "llsearchcombobox.h"  #include "llsidetray.h"  #include "llslurl.h" +#include "llurlsimstring.h"  #include "llurlregistry.h"  #include "llurldispatcher.h"  #include "llviewerinventory.h" @@ -507,34 +508,29 @@ void LLNavigationBar::onLocationSelection()  	std::string region_name;  	LLVector3 local_coords(128, 128, 0); +	S32 x = 0, y = 0, z = 0;  	// Is the typed location a SLURL? -	LLSLURL slurl = LLSLURL(typed_location); -	if (slurl.getType() == LLSLURL::LOCATION) +	if (LLSLURL::isSLURL(typed_location))  	{ -	  region_name = slurl.getRegion(); -	  local_coords = slurl.getPosition(); +		// Yes. Extract region name and local coordinates from it. +		if (LLURLSimString::parse(LLSLURL::stripProtocol(typed_location), ®ion_name, &x, &y, &z)) +				local_coords.set(x, y, z); +		else +			return;  	} -	else if(!slurl.isValid()) +	// we have to do this check after previous, because LLUrlRegistry contains handlers for slurl too   +	//but we need to know whether typed_location is a simple http url. +	else if (LLUrlRegistry::instance().isUrl(typed_location))   	{ -	  // we have to do this check after previous, because LLUrlRegistry contains handlers for slurl too   -	  // but we need to know whether typed_location is a simple http url. -	  if (LLUrlRegistry::instance().isUrl(typed_location))  -	    {  		// display http:// URLs in the media browser, or  		// anything else is sent to the search floater  		LLWeb::loadURL(typed_location);  		return; -	  } -	  else -	  { -	      // assume that an user has typed the {region name} or possible {region_name, parcel} -	      region_name  = typed_location.substr(0,typed_location.find(',')); -	    }  	}  	else  	{ -	  // was an app slurl, home, whatever.  Bail -	  return; +		// assume that an user has typed the {region name} or possible {region_name, parcel} +		region_name  = typed_location.substr(0,typed_location.find(','));  	}  	// Resolve the region name to its global coordinates. @@ -566,7 +562,7 @@ void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos)  	 */  		LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_NO_MATURITY,  					gAgent.getPosAgentFromGlobal(global_agent_pos)); -	std::string tooltip (LLSLURL(gAgent.getRegion()->getName(), global_agent_pos).getSLURLString()); +	std::string tooltip (LLSLURL::buildSLURLfromPosGlobal(gAgent.getRegion()->getName(), global_agent_pos, false));  	LLLocationHistoryItem item (location,  			global_agent_pos, tooltip,TYPED_REGION_SLURL);// we can add into history only TYPED location @@ -655,7 +651,7 @@ void LLNavigationBar::onRegionNameResponse(  	LLVector3d region_pos = from_region_handle(region_handle);  	LLVector3d global_pos = region_pos + (LLVector3d) local_coords; -	llinfos << "Teleporting to: " << LLSLURL(region_name,	global_pos).getSLURLString()  << llendl; +	llinfos << "Teleporting to: " << LLSLURL::buildSLURLfromPosGlobal(region_name,	global_pos, false)  << llendl;  	gAgent.teleportViaLocation(global_pos);  } diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index 197a0ef728..d6d48a4ead 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -142,7 +142,7 @@ void LLOutputMonitorCtrl::draw()  	// Copied from llmediaremotectrl.cpp  	// *TODO: Give the LLOutputMonitorCtrl an agent-id to monitor, then -	// call directly into LLVoiceClient::getInstance() to ask if that agent-id is muted, is +	// call directly into gVoiceClient to ask if that agent-id is muted, is  	// speaking, and what power.  This avoids duplicating data, which can get  	// out of sync.  	const F32 LEVEL_0 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL / 3.f; @@ -151,14 +151,14 @@ void LLOutputMonitorCtrl::draw()  	if (getVisible() && mAutoUpdate && !mIsMuted && mSpeakerId.notNull())  	{ -		setPower(LLVoiceClient::getInstance()->getCurrentPower(mSpeakerId)); +		setPower(gVoiceClient->getCurrentPower(mSpeakerId));  		if(mIsAgentControl)  		{ -			setIsTalking(LLVoiceClient::getInstance()->getUserPTTState()); +			setIsTalking(gVoiceClient->getUserPTTState());  		}  		else  		{ -			setIsTalking(LLVoiceClient::getInstance()->getIsSpeaking(mSpeakerId)); +			setIsTalking(gVoiceClient->getIsSpeaking(mSpeakerId));  		}  	} diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h index 3a83da67e2..b7454a5066 100644 --- a/indra/newview/lloutputmonitorctrl.h +++ b/indra/newview/lloutputmonitorctrl.h @@ -143,7 +143,7 @@ private:  	LLPointer<LLUIImage> mImageLevel2;  	LLPointer<LLUIImage> mImageLevel3; -	/** whether to deal with LLVoiceClient::getInstance() directly */ +	/** whether to deal with gVoiceClient directly */  	bool			mAutoUpdate;  	/** uuid of a speaker being monitored */ diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp index 3f1b23ba14..67e048885f 100644 --- a/indra/newview/lloverlaybar.cpp +++ b/indra/newview/lloverlaybar.cpp @@ -258,7 +258,7 @@ void LLOverlayBar::refresh()  	{  		// update "remotes"  		childSetVisible("media_remote_container", TRUE); -		childSetVisible("voice_remote_container", LLVoiceClient::getInstance()->voiceEnabled()); +		childSetVisible("voice_remote_container", LLVoiceClient::voiceEnabled());  		childSetVisible("state_buttons", TRUE);  	} diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index b554af66f0..a0ba2f739b 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -163,7 +163,7 @@ BOOL LLPanelAvatarNotes::postBuild()  	resetControls();  	resetData(); -	LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); +	gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this);  	return TRUE;  } @@ -374,7 +374,7 @@ void LLPanelAvatarNotes::onChange(EStatusType status, const std::string &channel  		return;  	} -	childSetEnabled("call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); +	childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());  }  void LLPanelAvatarNotes::setAvatarId(const LLUUID& id) @@ -518,7 +518,7 @@ BOOL LLPanelAvatarProfile::postBuild()  	pic = getChild<LLTextureCtrl>("real_world_pic");  	pic->setFallbackImageName("default_profile_picture.j2c"); -	LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); +	gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this);  	resetControls();  	resetData(); @@ -809,7 +809,7 @@ void LLPanelAvatarProfile::onChange(EStatusType status, const std::string &chann  		return;  	} -	childSetEnabled("call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); +	childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());  }  void LLPanelAvatarProfile::setAvatarId(const LLUUID& id) diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 716166a945..c00b6a4147 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -201,7 +201,7 @@ BOOL LLPanelGroup::postBuild()  		mJoinText = panel_general->getChild<LLUICtrl>("join_cost_text");  	} -	LLVoiceClient::getInstance()->addObserver(this); +	gVoiceClient->addObserver(this);  	return TRUE;  } @@ -322,7 +322,7 @@ void LLPanelGroup::onChange(EStatusType status, const std::string &channelURI, b  		return;  	} -	childSetEnabled("btn_call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); +	childSetEnabled("btn_call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());  }  void LLPanelGroup::notifyObservers() diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 709bb83fe4..c34f0633b9 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -81,8 +81,7 @@ void LLPanelChatControlPanel::onVoiceChannelStateChanged(const LLVoiceChannel::E  void LLPanelChatControlPanel::updateCallButton()  { -	// hide/show call button -	bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); +	bool voice_enabled = LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();  	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); @@ -125,7 +124,7 @@ BOOL LLPanelChatControlPanel::postBuild()  	childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this));  	childSetAction("voice_ctrls_btn", boost::bind(&LLPanelChatControlPanel::onOpenVoiceControlsClicked, this)); -	LLVoiceClient::getInstance()->addObserver(this); +	gVoiceClient->addObserver(this);  	return TRUE;  } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 42e4b397db..ee4dcc44fe 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -51,12 +51,11 @@  #include "llfocusmgr.h"  #include "lllineeditor.h"  #include "llnotificationsutil.h" -#include "llsecapi.h"  #include "llstartup.h"  #include "lltextbox.h"  #include "llui.h"  #include "lluiconstants.h" -#include "llslurl.h" +#include "llurlsimstring.h"  #include "llversioninfo.h"  #include "llviewerhelp.h"  #include "llviewertexturelist.h" @@ -78,7 +77,6 @@  #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; @@ -106,6 +104,7 @@ public:  LLLoginRefreshHandler gLoginRefreshHandler; +  // 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  class LLIamHereLogin : public LLHTTPClient::Responder @@ -154,6 +153,10 @@ namespace {  	boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;  }; +void set_start_location(LLUICtrl* ctrl, void* data) +{ +    LLURLSimString::setString(ctrl->getValue().asString()); +}  //---------------------------------------------------------------------------  // Public methods @@ -184,7 +187,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  		delete LLPanelLogin::sInstance;  	} -	mPasswordModified = FALSE;  	LLPanelLogin::sInstance = this;  	// add to front so we are the bottom-most child @@ -211,7 +213,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	}  #if !USE_VIEWER_AUTH -	childSetPrevalidate("username_edit", LLTextValidate::validateASCIIPrintableNoPipe); +	childSetPrevalidate("first_name_edit", LLTextValidate::validateASCIIPrintableNoSpace); +	childSetPrevalidate("last_name_edit", LLTextValidate::validateASCIIPrintableNoSpace); + +	childSetCommitCallback("password_edit", mungePassword, this);  	getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);  	// change z sort of clickable text to be behind buttons @@ -223,19 +228,27 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	LLComboBox* combo = getChild<LLComboBox>("start_location_combo"); -	if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION) +	std::string sim_string = LLURLSimString::sInstance.mSimString; +	if(sim_string.empty())  	{ -		LLSLURL slurl(gSavedSettings.getString("LoginLocation")); -		LLStartUp::setStartSLURL(slurl); +		LLURLSimString::setString(gSavedSettings.getString("LoginLocation")); +		sim_string = LLURLSimString::sInstance.mSimString;  	} -	updateLocationCombo(false); -	 -	combo->setCommitCallback(onSelectLocation, NULL); + +	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 ); +	} + +	combo->setCommitCallback( &set_start_location, NULL );  	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); @@ -291,10 +304,17 @@ 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 ); -	 -	updateLocationCombo(false); +#if !USE_VIEWER_AUTH +	// Initialize visibility (and don't force visibility - use prefs) +	refreshLocation( false ); +#endif  } @@ -358,6 +378,21 @@ 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()  { @@ -464,14 +499,14 @@ void LLPanelLogin::giveFocus()  	if( sInstance )  	{  		// Grab focus and move cursor to first blank input field -		std::string username = sInstance->childGetText("username_edit"); +		std::string first = sInstance->childGetText("first_name_edit");  		std::string pass = sInstance->childGetText("password_edit"); -		BOOL have_username = !username.empty(); +		BOOL have_first = !first.empty();  		BOOL have_pass = !pass.empty();  		LLLineEditor* edit = NULL; -		if (have_username && !have_pass) +		if (have_first && !have_pass)  		{  			// User saved his name but not his password.  Move  			// focus to password field. @@ -480,7 +515,7 @@ void LLPanelLogin::giveFocus()  		else  		{  			// User doesn't have a name, so start there. -			edit = sInstance->getChild<LLLineEditor>("username_edit"); +			edit = sInstance->getChild<LLLineEditor>("first_name_edit");  		}  		if (edit) @@ -502,8 +537,8 @@ void LLPanelLogin::showLoginWidgets()  	// *TODO: Append all the usual login parameters, like first_login=Y etc.  	std::string splash_screen_url = sInstance->getString("real_url");  	web_browser->navigateTo( splash_screen_url, "text/html" ); -	LLUICtrl* username_edit = sInstance->getChild<LLUICtrl>("username_edit"); -	username_edit->setFocus(TRUE); +	LLUICtrl* first_name_edit = sInstance->getChild<LLUICtrl>("first_name_edit"); +	first_name_edit->setFocus(TRUE);  }  // static @@ -525,120 +560,77 @@ void LLPanelLogin::show(const LLRect &rect,  }  // static -void LLPanelLogin::setFields(LLPointer<LLCredential> credential, -							 BOOL remember) +void LLPanelLogin::setFields(const std::string& firstname, +			     const std::string& lastname, +			     const std::string& password)  {  	if (!sInstance)  	{  		llwarns << "Attempted fillFields with no login view shown" << llendl;  		return;  	} -	LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL; -	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)) +	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)  	{ -		  		// 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", std::string("123456789!123456")); +		sInstance->childSetText("password_edit", filler); +		sInstance->mIncomingPassword = filler; +		sInstance->mMungedPassword = password;  	}  	else  	{ -		sInstance->childSetText("password_edit", std::string());		 +		// 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->childSetValue("remember_check", remember);  }  // static -void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, -							 BOOL remember) +void LLPanelLogin::addServer(const std::string& server, S32 domain_name)  {  	if (!sInstance)  	{ -		llwarns << "Attempted getFields with no login view shown" << llendl; +		llwarns << "Attempted addServer 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()->getGrid()); -	LLSD identifier = LLSD::emptyMap(); -	LLSD authenticator = LLSD::emptyMap(); -	 -	if(credential.notNull()) +	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)  	{ -		authenticator = credential->getAuthenticator(); +		llwarns << "Attempted getFields with no login view shown" << llendl; +		return;  	} -	std::string username = sInstance->childGetText("username_edit"); -	LLStringUtil::trim(username); -	std::string password = sInstance->childGetText("password_edit"); +	*firstname = sInstance->childGetText("first_name_edit"); +	LLStringUtil::trim(*firstname); -	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()->getGrid(), identifier, authenticator); -	remember = sInstance->childGetValue("remember_check"); +	*lastname = sInstance->childGetText("last_name_edit"); +	LLStringUtil::trim(*lastname); + +	*password = sInstance->mMungedPassword;  }  // static @@ -658,147 +650,64 @@ BOOL LLPanelLogin::isGridComboDirty()  }  // static -BOOL LLPanelLogin::areCredentialFieldsDirty() +void LLPanelLogin::getLocation(std::string &location)  {  	if (!sInstance)  	{ -		llwarns << "Attempted getServer with no login view shown" << llendl; -	} -	else -	{ -		std::string username = sInstance->childGetText("username_edit"); -		LLStringUtil::trim(username); -		std::string password = sInstance->childGetText("password_edit"); -		LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("username_edit"); -		if(ctrl && ctrl->isDirty()) -		{ -			return true; -		} -		ctrl = sInstance->getChild<LLLineEditor>("password_edit"); -		if(ctrl && ctrl->isDirty())  -		{ -			return true; -		} +		llwarns << "Attempted getLocation with no login view shown" << llendl; +		return;  	} -	return false;	 +	 +	LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); +	location = combo->getValue().asString();  } -  // static -void LLPanelLogin::updateLocationCombo( bool force_visible ) +void LLPanelLogin::refreshLocation( bool force_visible )  { -	if (!sInstance)  -	{ -		return; -	}	 -	 -	llinfos << "updatelocationcombo " << LLStartUp::getStartSLURL().asString() << llendl; -	LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); -	 -	switch(LLStartUp::getStartSLURL().getType()) -	{ -		case LLSLURL::LOCATION: -		{ -			 -			combo->setCurrentByIndex( 2 );	 -			combo->setTextEntry(LLStartUp::getStartSLURL().getLocationString());	 -			break; -		} -		case LLSLURL::HOME_LOCATION: -			combo->setCurrentByIndex(1); -			break; -		default: -			combo->setCurrentByIndex(0); -			break; -	} -	 +	if (!sInstance) return; + +#if USE_VIEWER_AUTH +	loadLoginPage(); +#else  	BOOL show_start = TRUE; -	 +  	if ( ! force_visible ) +	{ +		// Don't show on first run after install +		// Otherwise ShowStartLocation defaults to true.  		show_start = gSavedSettings.getBOOL("ShowStartLocation"); +	} + +	// Update the value of the location combo. +	updateLocationUI();  	sInstance->childSetVisible("start_location_combo", show_start);  	sInstance->childSetVisible("start_location_text", show_start); -	 -	sInstance->childSetVisible("server_combo", TRUE); -} -// static -void LLPanelLogin::onSelectLocation(LLUICtrl*, void*) -{ -	if (!sInstance) return; -	 -	LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); -	S32 index = combo->getCurrentIndex(); -	 -	switch (index) -	{ -		case 2: -		{ -			LLSLURL slurl = LLSLURL(combo->getSelectedValue()); -			if((slurl.getType() == LLSLURL::LOCATION) && -			   (slurl.getGrid() != LLStartUp::getStartSLURL().getGrid())) -			{ -				 - -				// we've changed the grid, so update the grid selection -				try  -				{ -					LLStartUp::setStartSLURL(slurl); -				} -				catch (LLInvalidGridName ex) -				{ -					LLSD args;	 -					args["GRID"] = slurl.getGrid(); -					LLNotificationsUtil::add("InvalidGrid", args); -					return;  -				}	 -				loadLoginPage(); -			} -			break; -		} -		case 1: -		{ -			LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); -			break; -		} -		default: -		{ -			LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); -			break; -		} -	} -} +	BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid"); +	sInstance->childSetVisible("server_combo", show_server); +#endif +}  // static -void LLPanelLogin::getLocation(LLSLURL& slurl) +void LLPanelLogin::updateLocationUI()  { -	LLSLURL result; -	if (!sInstance) -	{ -		llwarns << "Attempted getLocation with no login view shown" << llendl; -	} -	 -	LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); +	if (!sInstance) return; -	switch(combo->getCurrentIndex()) +	std::string sim_string = LLURLSimString::sInstance.mSimString; +	if (!sim_string.empty())  	{ -		case 0: -			slurl = LLSLURL(LLSLURL::SIM_LOCATION_HOME); -		case 1: -			slurl =  LLSLURL(LLSLURL::SIM_LOCATION_LAST); -		default: -			slurl = LLSLURL(combo->getValue().asString()); +		// Replace "<Type region name>" with this region name +		LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); +		combo->remove(2); +		combo->add( sim_string ); +		combo->setTextEntry(sim_string); +		combo->setCurrentByIndex( 2 );  	}  } -void LLPanelLogin::setLocation(const LLSLURL& slurl) -{ -	LLStartUp::setStartSLURL(slurl); -	updateServer(); -} -  // static  void LLPanelLogin::closePanel()  { @@ -832,13 +741,15 @@ void LLPanelLogin::loadLoginPage()  	std::ostringstream oStr; -	std::string login_page = LLGridManager::getInstance()->getLoginPage(); - +	std::string login_page = gSavedSettings.getString("LoginPage"); +	if (login_page.empty()) +	{ +		login_page = sInstance->getString( "real_url" ); +	}  	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)  	{ @@ -870,10 +781,11 @@ void LLPanelLogin::loadLoginPage()  	curl_free(curl_version);  	// Grid -	char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLoginID().c_str(), 0); +	char* curl_grid = curl_escape(LLViewerLogin::getInstance()->getGridLabel().c_str(), 0);  	oStr << "&grid=" << curl_grid;  	curl_free(curl_grid); -	gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid()); + +	gViewerWindow->setMenuBackgroundColor(false, !LLViewerLogin::getInstance()->isInProductionGrid());  	gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor()); @@ -898,20 +810,30 @@ void LLPanelLogin::loadLoginPage()  		location = gSavedSettings.getString("LoginLocation");  	} -	std::string username; +	std::string firstname, lastname;      if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)      {          LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo"); -		username = cmd_line_login[0].asString() + " " + cmd_line_login[1]; +		firstname = cmd_line_login[0].asString(); +		lastname = cmd_line_login[1].asString();          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 <<"username=" << username << -		 "&location=" << location <<	"®ion=" << curl_region; +	oStr <<"firstname=" << firstname << +		"&lastname=" << lastname << "&location=" << location <<	"®ion=" << curl_region;  	curl_free(curl_region); @@ -944,7 +866,7 @@ void LLPanelLogin::loadLoginPage()  #endif  	LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); - +	  	// navigate to the "real" page  	if (gSavedSettings.getBOOL("RegInClient"))  	{ @@ -993,33 +915,34 @@ void LLPanelLogin::onClickConnect(void *)  		// JC - Make sure the fields all get committed.  		sInstance->setFocus(FALSE); -		LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); -		LLSD combo_val = combo->getSelectedValue(); -		if (combo_val.isUndefined()) +		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 =="")  		{ -			combo_val = combo->getValue(); +			// *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("");  		} -		if(combo_val.isUndefined()) +		else   		{ -			LLNotificationsUtil::add("StartRegionEmpty"); -			return; -		}		 -		try -		{ -			LLGridManager::getInstance()->setGridChoice(combo_val.asString()); +			// *NOTE: Mani - Location field is not always committed by this point! +			LLURLSimString::sInstance.setString(combo_text); +			has_location = true;  		} -		catch (LLInvalidGridName ex) + +		if(!has_first_and_last)  		{ -			LLSD args; -			args["GRID"] = combo_val.asString(); -			LLNotificationsUtil::add("InvalidGrid", args); -			return; +			LLNotificationsUtil::add("MustHaveAccountToLogIn");  		} -		 -		std::string username = sInstance->childGetText("username_edit"); -		if(username.empty()) +		else if(!has_location)  		{ -			LLNotificationsUtil::add("MustHaveAccountToLogIn"); +			LLNotificationsUtil::add("StartRegionEmpty");  		}  		else  		{ @@ -1082,8 +1005,6 @@ 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"); @@ -1091,90 +1012,54 @@ void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)  	}  } - -void LLPanelLogin::updateServer() +// static +void LLPanelLogin::onSelectServer(LLUICtrl*, void*)  { -	try  +	// *NOTE: The paramters for this method are ignored.  +	// LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*) +	// calls this method. + +	// The user twiddled with the grid choice ui. +	// apply the selection to the grid setting. +	std::string grid_label; +	S32 grid_index; + +	LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); +	LLSD combo_val = combo->getValue(); + +	if (LLSD::TypeInteger == combo_val.type())  	{ +		grid_index = combo->getValue().asInteger(); -		updateServerCombo();	 -		// if they've selected another grid, we should load the credentials -		// for that grid and set them to the UI. -		if(sInstance && !sInstance->areCredentialFieldsDirty()) +		if ((S32)GRID_INFO_OTHER == grid_index)  		{ -			LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());	 -			bool remember = sInstance->childGetValue("remember_check"); -			sInstance->setFields(credential, remember); +			// This happens if the user specifies a custom grid +			// via command line. +			grid_label = combo->getSimple();  		} -		// grid changed so show new splash screen (possibly) -		loadLoginPage(); -		updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION);  	} -	catch (LLInvalidGridName ex) +	else  	{ -		// do nothing +		// no valid selection, return other +		grid_index = (S32)GRID_INFO_OTHER; +		grid_label = combo_val.asString();  	} -} -void LLPanelLogin::updateServerCombo() -{ -	if (!sInstance)  +	// This new seelction will override preset uris +	// from the command line. +	LLViewerLogin* vl = LLViewerLogin::getInstance(); +	vl->resetURIs(); +	if(grid_index != GRID_INFO_OTHER)  	{ -		return;	 +		vl->setGridChoice((EGridInfo)grid_index);  	} -	// We add all of the possible values, sorted, and then add a bar and the current value at the top -	LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");	 -	server_choice_combo->removeall(); -#ifdef LL_RELEASE_FOR_DOWNLOAD -	std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(TRUE); -#else -	std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(FALSE);	 -#endif -	for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); -		 grid_choice != known_grids.end(); -		 grid_choice++) +	else  	{ -		if (!grid_choice->first.empty()) -		{ -			server_choice_combo->add(grid_choice->second, grid_choice->first, ADD_SORTED); -		} +		vl->setGridChoice(grid_label);  	} -	 -	server_choice_combo->addSeparator(ADD_TOP); -	 -	server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),  -		LLGridManager::getInstance()->getGrid(), ADD_TOP);	 -	 -	server_choice_combo->selectFirstItem();	 -} -// static -void LLPanelLogin::onSelectServer(LLUICtrl*, void*) -{ -	// *NOTE: The paramters for this method are ignored.  -	// LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*) -	// calls this method. -	LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL; -	// The user twiddled with the grid choice ui. -	// apply the selection to the grid setting. -	LLPointer<LLCredential> credential; -	 -	LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); -	LLSD combo_val = combo->getSelectedValue(); -	if (combo_val.isUndefined()) -	{ -		combo_val = combo->getValue(); -	} -	 -	combo = sInstance->getChild<LLComboBox>("start_location_combo");	 -	combo->setCurrentByIndex(1); -	LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation"))); -	LLGridManager::getInstance()->setGridChoice(combo_val.asString()); -	// This new selection will override preset uris -	// from the command line. -	updateServer(); -	updateLocationCombo(false); -	updateLoginPanelLinks(); +	// grid changed so show new splash screen (possibly) +	loadLoginPage();  }  void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe) @@ -1187,14 +1072,3 @@ void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)  		onSelectServer(combo, NULL);	  	}  } - -void LLPanelLogin::updateLoginPanelLinks() -{ -	LLSD grid_data = LLGridManager::getInstance()->getGridInfo(); -	bool system_grid = grid_data.has(GRID_IS_SYSTEM_GRID_VALUE); -	 -	// need to call through sInstance, as it's called from onSelectServer, which -	// is static. -	sInstance->childSetVisible("create_new_account_text", system_grid); -	sInstance->childSetVisible("forgot_password_text", system_grid); -} diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 9301c263da..1fdc3a9361 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -41,8 +41,6 @@  class LLLineEditor;  class LLUIImage;  class LLPanelLoginListener; -class LLSLURL; -class LLCredential;  class LLPanelLogin:	  	public LLPanel, @@ -67,16 +65,20 @@ public:  		void (*callback)(S32 option, void* user_data),   		void* callback_data); -	static void setFields(LLPointer<LLCredential> credential, BOOL remember); +	// 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 getFields(LLPointer<LLCredential>& credential, BOOL remember); +	static void addServer(const std::string& server, S32 domain_name); +	static void refreshLocation( bool force_visible ); +	static void updateLocationUI(); + +	static void getFields(std::string *firstname, std::string *lastname, +						  std::string *password);  	static BOOL isGridComboDirty(); -	static BOOL areCredentialFieldsDirty(); -	static void getLocation(LLSLURL& slurl); -	static void setLocation(const LLSLURL& slurl); -	 -	static void updateLocationCombo(bool force_visible);  // simply update the combo box +	static void getLocation(std::string &location); +  	static void closePanel();  	void setSiteIsAlive( bool alive ); @@ -84,10 +86,10 @@ 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); -	static void updateServer();  // update the combo box, change the login page to the new server, clear the combo  private:  	friend class LLPanelLoginListener; @@ -101,10 +103,6 @@ private:  	static void onPassKey(LLLineEditor* caller, void* user_data);  	static void onSelectServer(LLUICtrl*, void*);  	static void onServerComboLostFocus(LLFocusableElement*); -	static void updateServerCombo(); -	static void onSelectLocation(LLUICtrl*, void*); -	 -	static void updateLoginPanelLinks();  private:  	LLPointer<LLUIImage> mLogoImage; @@ -113,7 +111,8 @@ private:  	void			(*mCallback)(S32 option, void *userdata);  	void*			mCallbackData; -	BOOL            mPasswordModified; +	std::string mIncomingPassword; +	std::string mMungedPassword;  	static LLPanelLogin* sInstance;  	static BOOL		sCapslockDidNotification; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 4c24670f47..5802d53cd1 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -619,7 +619,7 @@ BOOL LLPanelPeople::postBuild()  	if(recent_view_sort)  		mRecentViewSortMenuHandle  = recent_view_sort->getHandle(); -	LLVoiceClient::getInstance()->addObserver(this); +	gVoiceClient->addObserver(this);  	// call this method in case some list is empty and buttons can be in inconsistent state  	updateButtons(); @@ -809,7 +809,7 @@ void LLPanelPeople::updateButtons()  		}  	} -	bool enable_calls = LLVoiceClient::getInstance()->isVoiceWorking() && LLVoiceClient::getInstance()->voiceEnabled(); +	bool enable_calls = gVoiceClient->voiceWorking() && gVoiceClient->voiceEnabled();  	buttonSetEnabled("teleport_btn",		friends_tab_active && item_selected && isFriendOnline(selected_uuids.front()));  	buttonSetEnabled("view_profile_btn",	item_selected); diff --git a/indra/newview/llpanelplacestab.cpp b/indra/newview/llpanelplacestab.cpp index 6b12796e59..9806b8c64d 100644 --- a/indra/newview/llpanelplacestab.cpp +++ b/indra/newview/llpanelplacestab.cpp @@ -70,7 +70,10 @@ void LLPanelPlacesTab::onRegionResponse(const LLVector3d& landmark_global_pos,  	std::string sl_url;  	if ( gotSimName )  	{ -		sl_url = LLSLURL(sim_name, landmark_global_pos).getSLURLString(); +		F32 region_x = (F32)fmod( landmark_global_pos.mdV[VX], (F64)REGION_WIDTH_METERS ); +		F32 region_y = (F32)fmod( landmark_global_pos.mdV[VY], (F64)REGION_WIDTH_METERS ); + +		sl_url = LLSLURL::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)landmark_global_pos.mdV[VZ]));  	}  	else  	{ diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 79a6d80716..eb245453db 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -346,6 +346,7 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)  {  	if (mExcludeAgent && gAgent.getID() == avatar_id) return;  	if (mAvatarList->contains(avatar_id)) return; +  	mAvatarList->getIDs().push_back(avatar_id);  	mAvatarList->setDirty();  	adjustParticipant(avatar_id); @@ -631,7 +632,7 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD&  	else if (item == "can_call")  	{  		bool not_agent = mUUIDs.front() != gAgentID; -		bool can_call = not_agent &&  LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); +		bool can_call = not_agent && LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();  		return can_call;  	} diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp deleted file mode 100644 index ba343f5387..0000000000 --- a/indra/newview/llsecapi.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/**  - * @file llsecapi.cpp - * @brief Security API for services such as certificate handling - * secure local storage, etc. - * - * $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 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://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://secondlife.com/developers/opensource/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 "llsecapi.h" -#include "llsechandler_basic.h" -#include <openssl/evp.h> -#include <map> -#include "llhttpclient.h" - - - -std::map<std::string, LLPointer<LLSecAPIHandler> > gHandlerMap; -LLPointer<LLSecAPIHandler> gSecAPIHandler; - -void initializeSecHandler() -{ -	OpenSSL_add_all_algorithms(); -	OpenSSL_add_all_ciphers(); -	OpenSSL_add_all_digests();	 -	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]; - -	// initialize all SecAPIHandlers -	LLProtectedDataException ex = LLProtectedDataException(""); -	std::map<std::string, LLPointer<LLSecAPIHandler> >::const_iterator itr; -	for(itr = gHandlerMap.begin(); itr != gHandlerMap.end(); ++itr) -	{ -		LLPointer<LLSecAPIHandler> handler = (*itr).second; -		try  -		{ -			handler->init(); -		} -		catch (LLProtectedDataException e) -		{ -			ex = e; -		} -	} -	if (ex.getMessage().length() > 0 )  // an exception was thrown. -	{ -		throw ex; -	} - -} -// start using a given security api handler.  If the string is empty -// the default is used -LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type) -{ -	if (gHandlerMap.find(handler_type) != gHandlerMap.end()) -	{ -		return gHandlerMap[handler_type]; -	} -	else -	{ -		return LLPointer<LLSecAPIHandler>(NULL); -	} -} -// register a handler -void registerSecHandler(const std::string& handler_type,  -						LLPointer<LLSecAPIHandler>& handler) -{ -	gHandlerMap[handler_type] = handler; -} - -std::ostream& operator <<(std::ostream& s, const LLCredential& cred) -{ -	return s << (std::string)cred; -} - -	 -// secapiSSLCertVerifyCallback -// basic callback called when a cert verification is requested. -// calls SECAPI to validate the context -// not initialized in the above initialization function, due to unit tests -// see llappviewer - -int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param) -{ -	LLURLRequest *req = (LLURLRequest *)param; -	LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(""); -	LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); -	LLSD validation_params = LLSD::emptyMap(); -	LLURI uri(req->getURL()); -	validation_params[CERT_HOSTNAME] = uri.hostName(); -	try -	{ -		chain->validate(VALIDATION_POLICY_SSL, store, validation_params); -	} -	catch (LLCertValidationTrustException& cert_exception) -	{ -		LL_WARNS("AppInit") << "Cert not trusted: " << cert_exception.getMessage() << LL_ENDL; -		return 0;		 -	} -	catch (LLCertException& cert_exception) -	{ -		LL_WARNS("AppInit") << "cert error " << cert_exception.getMessage() << LL_ENDL; -		return 0; -	} -	catch (...) -	{ -		LL_WARNS("AppInit") << "cert error " << LL_ENDL; -		return 0; -	} -	return 1; -} - -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["account_name"]; -		result["passwd"] = mAuthenticator["secret"]; -                                     -	} -	return result; -} diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h deleted file mode 100644 index 5211dc2699..0000000000 --- a/indra/newview/llsecapi.h +++ /dev/null @@ -1,493 +0,0 @@ -/**  - * @file llsecapi.h - * @brief Security API for services such as certificate handling - * secure local storage, etc. - * - * $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 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://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://secondlife.com/developers/opensource/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$ - */ - -#ifndef LLSECAPI_H -#define LLSECAPI_H -#include <vector> -#include <openssl/x509.h> -#include <ostream> - -#ifdef LL_WINDOWS -#pragma warning(disable:4250) -#endif // LL_WINDOWS - -// All error handling is via exceptions. - - -#define CERT_SUBJECT_NAME "subject_name" -#define CERT_ISSUER_NAME "issuer_name" -#define CERT_NAME_CN "commonName" -		 -#define CERT_SUBJECT_NAME_STRING "subject_name_string" -#define CERT_ISSUER_NAME_STRING "issuer_name_string" -		 -#define CERT_SERIAL_NUMBER "serial_number" -		 -#define CERT_VALID_FROM "valid_from" -#define CERT_VALID_TO "valid_to" -#define CERT_SHA1_DIGEST "sha1_digest" -#define CERT_MD5_DIGEST "md5_digest" -#define CERT_HOSTNAME "hostname" -#define CERT_BASIC_CONSTRAINTS "basicConstraints" -#define CERT_BASIC_CONSTRAINTS_CA "CA" -#define CERT_BASIC_CONSTRAINTS_PATHLEN "pathLen" - -#define CERT_KEY_USAGE "keyUsage" -#define CERT_KU_DIGITAL_SIGNATURE    "digitalSignature" -#define CERT_KU_NON_REPUDIATION      "nonRepudiation" -#define CERT_KU_KEY_ENCIPHERMENT     "keyEncipherment" -#define CERT_KU_DATA_ENCIPHERMENT    "dataEncipherment" -#define CERT_KU_KEY_AGREEMENT        "keyAgreement" -#define CERT_KU_CERT_SIGN        "certSigning" -#define CERT_KU_CRL_SIGN             "crlSigning" -#define CERT_KU_ENCIPHER_ONLY        "encipherOnly" -#define CERT_KU_DECIPHER_ONLY        "decipherOnly" - -#define BASIC_SECHANDLER "BASIC_SECHANDLER" -#define CERT_VALIDATION_DATE "validation_date" - -#define CERT_EXTENDED_KEY_USAGE "extendedKeyUsage" -#define CERT_EKU_SERVER_AUTH SN_server_auth - -#define CERT_SUBJECT_KEY_IDENTFIER "subjectKeyIdentifier" -#define CERT_AUTHORITY_KEY_IDENTIFIER "authorityKeyIdentifier" -#define CERT_AUTHORITY_KEY_IDENTIFIER_ID "authorityKeyIdentifierId" -#define CERT_AUTHORITY_KEY_IDENTIFIER_NAME "authorityKeyIdentifierName" -#define CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL "authorityKeyIdentifierSerial" - -// validate the current time lies within  -// the validation period of the cert -#define VALIDATION_POLICY_TIME 1 - -// validate that the CA, or some cert in the chain -// lies within the certificate store -#define VALIDATION_POLICY_TRUSTED 2 - -// validate that the subject name of -// the cert contains the passed in hostname -// or validates against the hostname -#define VALIDATION_POLICY_HOSTNAME 4 - - -// validate that the cert contains the SSL EKU -#define VALIDATION_POLICY_SSL_KU 8 - -// validate that the cert contains the SSL EKU -#define VALIDATION_POLICY_CA_KU 16 - -#define VALIDATION_POLICY_CA_BASIC_CONSTRAINTS 32 - -// validate that the cert is correct for SSL -#define VALIDATION_POLICY_SSL (VALIDATION_POLICY_TIME | \ -                               VALIDATION_POLICY_HOSTNAME | \ -                               VALIDATION_POLICY_TRUSTED | \ -                               VALIDATION_POLICY_SSL_KU | \ -                               VALIDATION_POLICY_CA_BASIC_CONSTRAINTS | \ -                               VALIDATION_POLICY_CA_KU) - - - - - - -class LLProtectedDataException -{ -public: -	LLProtectedDataException(const char *msg)  -	{ -		LL_WARNS("SECAPI") << "Protected Data Error: " << (std::string)msg << LL_ENDL; -		mMsg = (std::string)msg; -	} -	std::string getMessage() { return mMsg; } -protected: -	std::string mMsg; -}; - -// class LLCertificate -// parent class providing an interface for certifiate. -// LLCertificates are considered unmodifiable -// Certificates are pulled out of stores, or created via -// factory calls -class LLCertificate : public LLRefCount -{ -	LOG_CLASS(LLCertificate); -public: -	LLCertificate() {} -	 -	virtual ~LLCertificate() {} -	 -	// return a PEM encoded certificate.  The encoding -	// includes the -----BEGIN CERTIFICATE----- and end certificate elements -	virtual std::string getPem() const=0;  -	 -	// return a DER encoded certificate -	virtual std::vector<U8> getBinary() const=0;   -	 -	// return an LLSD object containing information about the certificate -	// such as its name, signature, expiry time, serial number -	virtual LLSD getLLSD() const=0;  -	 -	// return an openSSL X509 struct for the certificate -	virtual X509* getOpenSSLX509() const=0; - -}; - -// class LLCertificateVector -// base class for a list of certificates. - - -class LLCertificateVector : public LLRefCount -{ -	 -public: -	 -	LLCertificateVector() {}; -	virtual ~LLCertificateVector() {}; -	 -	// base iterator implementation class, providing -	// the functionality needed for the iterator class. -	class iterator_impl : public LLRefCount -	{ -	public: -		iterator_impl() {}; -		virtual ~iterator_impl() {}; -		virtual void seek(bool incr)=0; -		virtual LLPointer<iterator_impl> clone() const=0; -		virtual bool equals(const LLPointer<iterator_impl>& _iter) const=0; -		virtual LLPointer<LLCertificate> get()=0; -	}; -	 -	// iterator class -	class iterator -	{ -	public: -		iterator(LLPointer<iterator_impl> impl) : mImpl(impl) {} -		iterator() : mImpl(NULL) {} -		iterator(const iterator& _iter) {mImpl = _iter.mImpl->clone(); } -		~iterator() {} -		iterator& operator++() { if(mImpl.notNull()) mImpl->seek(true); return *this;} -		iterator& operator--() { if(mImpl.notNull()) mImpl->seek(false); return *this;} -		 -		iterator operator++(int) { iterator result = *this; if(mImpl.notNull()) mImpl->seek(true); return result;} -		iterator operator--(int) { iterator result = *this; if(mImpl.notNull()) mImpl->seek(false); return result;} -		LLPointer<LLCertificate> operator*() { return mImpl->get(); }		 -		 -		LLPointer<iterator_impl> mImpl; -	protected: -		friend bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs); -		bool equals(const iterator& _iter) const { return mImpl->equals(_iter.mImpl); } -	}; -	 -	// numeric indexer -	virtual LLPointer<LLCertificate> operator[](int)=0; -	 -	// Iteration -	virtual iterator begin()=0; -	 -	virtual iterator end()=0; -	 -	// find a cert given params -	virtual iterator find(const LLSD& params) =0; -	 -	// return the number of certs in the store -	virtual int size() const = 0;	 -	 -	// append the cert to the store.  if a copy of the cert already exists in the store, it is removed first -	virtual void  add(LLPointer<LLCertificate> cert)=0; -	 -	// insert the cert to the store.  if a copy of the cert already exists in the store, it is removed first -	virtual void  insert(iterator location, LLPointer<LLCertificate> cert)=0;	 -	 -	// remove a certificate from the store -	virtual LLPointer<LLCertificate> erase(iterator cert)=0;	 -}; - - -// 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 LLCertificateStore : virtual public LLCertificateVector -{ -	 -public: -	 -	LLCertificateStore() {} -	virtual ~LLCertificateStore() {} -	 -	// persist the store -	virtual void save()=0; -	 -	// return the store id -	virtual std::string storeId() const=0; -}; - -// class LLCertificateChain -// Class representing a chain of certificates in order, with the  -// first element being the child cert. -class LLCertificateChain : virtual public LLCertificateVector -{	 - -public: -	LLCertificateChain() {} -	 -	virtual ~LLCertificateChain() {} - -	// validate a certificate chain given the params. -	// Will throw exceptions on error -	 -	virtual void validate(int validation_policy, -						  LLPointer<LLCertificateStore> ca_store, -						  const LLSD& validation_params) =0; -}; - - - - -inline -bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs) -{ -	return _lhs.equals(_rhs); -} -inline -bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs) -{ -	return !(_lhs == _rhs); -} - - -// -// 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); - - -// All error handling is via exceptions. - -class LLCertException -{ -public: -	LLCertException(LLPointer<LLCertificate> cert, const char* msg) -	{ - -		mCert = cert; - -		LL_WARNS("SECAPI") << "Certificate Error: " << (std::string)msg << LL_ENDL; -		mMsg = (std::string)msg; -	} -	LLPointer<LLCertificate> getCert() { return mCert; } -	std::string getMessage() { return mMsg; } -protected: -	LLPointer<LLCertificate> mCert; -	std::string mMsg; -}; - -class LLInvalidCertificate : public LLCertException -{ -public: -	LLInvalidCertificate(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalid") -	{ -	} -protected: -}; - -class LLCertValidationTrustException : public LLCertException -{ -public: -	LLCertValidationTrustException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertUntrusted") -	{ -	} -protected: -}; - -class LLCertValidationHostnameException : public LLCertException -{ -public: -	LLCertValidationHostnameException(std::string hostname, -									  LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidHostname") -	{ -		mHostname = hostname; -	} -	 -	std::string getHostname() { return mHostname; } -protected: -	std::string mHostname; -}; - -class LLCertValidationExpirationException : public LLCertException -{ -public: -	LLCertValidationExpirationException(LLPointer<LLCertificate> cert, -										LLDate current_time) : LLCertException(cert, "CertExpired") -	{ -		mTime = current_time; -	} -	LLDate GetTime() { return mTime; } -protected: -	LLDate mTime; -}; - -class LLCertKeyUsageValidationException : public LLCertException -{ -public: -	LLCertKeyUsageValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertKeyUsage") -	{ -	} -protected: -}; - -class LLCertBasicConstraintsValidationException : public LLCertException -{ -public: -	LLCertBasicConstraintsValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertBasicConstraints") -	{ -	} -protected: -}; - -class LLCertValidationInvalidSignatureException : public LLCertException -{ -public: -	LLCertValidationInvalidSignatureException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidSignature") -	{ -	} -protected: -}; - -// LLSecAPIHandler Class -// Interface handler class for the various security storage handlers. -class LLSecAPIHandler : public LLRefCount -{ -public: -	 -	 -	LLSecAPIHandler() {} -	virtual ~LLSecAPIHandler() {} -	 -	// initialize the SecAPIHandler -	virtual void init() {}; -	 -	// instantiate a certificate from a pem string -	virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert)=0; -	 -	 -	 -	// instiate a certificate from an openssl X509 structure -	virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)=0; -	 -	// instantiate a chain from an X509_STORE_CTX -	virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)=0; -	 -	// instantiate a cert store given it's id.  if a persisted version -	// exists, it'll be loaded.  If not, one will be created (but not -	// persisted) -	virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id)=0; -	 -	// persist data in a protected store -	virtual void setProtectedData(const std::string& data_type, -								  const std::string& data_id, -								  const LLSD& data)=0; -	 -	// 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 initializeSecHandler(); -				 -// retrieve a security api depending on the api type -LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type); - -void registerSecHandler(const std::string& handler_type,  -						LLPointer<LLSecAPIHandler>& handler); - -extern LLPointer<LLSecAPIHandler> gSecAPIHandler; - - -int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param); - - -#endif // LL_SECAPI_H diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp deleted file mode 100644 index 51e250ffc6..0000000000 --- a/indra/newview/llsechandler_basic.cpp +++ /dev/null @@ -1,1586 +0,0 @@ -/**  - * @file llsechandler_basic.cpp - * @brief Security API for services such as certificate handling - * secure local storage, etc. - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - *  - * Copyright (c) 2003-2000, 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://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://secondlife.com/developers/opensource/flossexception - *  -LLS * 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 "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/ossl_typ.h> -#include <openssl/x509.h> -#include <openssl/x509v3.h> -#include <openssl/pem.h> -#include <openssl/asn1.h> -#include <openssl/rand.h> -#include <openssl/err.h> -#include <iostream> -#include <iomanip> -#include <time.h> - - - -// 128 bits of salt data... -#define STORE_SALT_SIZE 16  -#define BUFFER_READ_SIZE 256 -std::string cert_string_from_asn1_string(ASN1_STRING* value); -std::string cert_string_from_octet_string(ASN1_OCTET_STRING* value); - -LLSD _basic_constraints_ext(X509* cert); -LLSD _key_usage_ext(X509* cert); -LLSD _ext_key_usage_ext(X509* cert); -LLSD _subject_key_identifier_ext(X509 *cert); -LLSD _authority_key_identifier_ext(X509* cert); - -LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert)  -{ -	 -	// BIO_new_mem_buf returns a read only bio, but takes a void* which isn't const -	// so we need to cast it. -	BIO * pem_bio = BIO_new_mem_buf((void*)pem_cert.c_str(), pem_cert.length()); -	if(pem_bio == NULL) -	{ -		LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; -		throw LLInvalidCertificate(this); -	} -	mCert = NULL; -	PEM_read_bio_X509(pem_bio, &mCert, 0, NULL); -	BIO_free(pem_bio); -	if (!mCert) -	{ -		throw LLInvalidCertificate(this); -	} -	_initLLSD(); -} - - -LLBasicCertificate::LLBasicCertificate(X509* pCert)  -{ -	if (!pCert || !pCert->cert_info) -	{ -		throw LLInvalidCertificate(this); -	}	 -	mCert = X509_dup(pCert); -	_initLLSD(); -} - -LLBasicCertificate::~LLBasicCertificate()  -{ -	if(mCert) -	{ -		X509_free(mCert); -	} -} - -// -// retrieve the pem using the openssl functionality -std::string LLBasicCertificate::getPem() const -{  -	char * pem_bio_chars = NULL; -	// a BIO is the equivalent of a 'std::stream', and -	// can be a file, mem stream, whatever.  Grab a memory based -	// BIO for the result -	BIO *pem_bio = BIO_new(BIO_s_mem()); -	if (!pem_bio) -	{ -		LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;		 -		return std::string(); -	} -	PEM_write_bio_X509(pem_bio, mCert); -	int length = BIO_get_mem_data(pem_bio, &pem_bio_chars); -	std::string result = std::string(pem_bio_chars, length); -	BIO_free(pem_bio); -	return result; -} - -// get the DER encoding for the cert -// DER is a binary encoding format for certs... -std::vector<U8> LLBasicCertificate::getBinary() const -{  -	U8 * der_bio_data = NULL; -	// get a memory bio  -	BIO *der_bio = BIO_new(BIO_s_mem()); -	if (!der_bio) -	{ -		LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;			 -		return std::vector<U8>(); -	} -	i2d_X509_bio(der_bio, mCert); -	int length = BIO_get_mem_data(der_bio, &der_bio_data); -	std::vector<U8> result(length); -	// vectors are guranteed to be a contiguous chunk of memory. -	memcpy(&result[0], der_bio_data,  length); -	BIO_free(der_bio); -	return result; -} - - -LLSD LLBasicCertificate::getLLSD() const -{ -	return mLLSDInfo; -} - -// Initialize the LLSD info for the certificate -LLSD& LLBasicCertificate::_initLLSD() -{  - -	// call the various helpers to build the LLSD -	mLLSDInfo[CERT_SUBJECT_NAME] = cert_name_from_X509_NAME(X509_get_subject_name(mCert)); -	mLLSDInfo[CERT_ISSUER_NAME] = cert_name_from_X509_NAME(X509_get_issuer_name(mCert)); -	mLLSDInfo[CERT_SUBJECT_NAME_STRING] = cert_string_name_from_X509_NAME(X509_get_subject_name(mCert)); -	mLLSDInfo[CERT_ISSUER_NAME_STRING] = cert_string_name_from_X509_NAME(X509_get_issuer_name(mCert)); -	ASN1_INTEGER *sn = X509_get_serialNumber(mCert); -	if (sn != NULL) -	{ -		mLLSDInfo[CERT_SERIAL_NUMBER] = cert_string_from_asn1_integer(sn); -	} -	 -	mLLSDInfo[CERT_VALID_TO] = cert_date_from_asn1_time(X509_get_notAfter(mCert)); -	mLLSDInfo[CERT_VALID_FROM] = cert_date_from_asn1_time(X509_get_notBefore(mCert)); -	mLLSDInfo[CERT_SHA1_DIGEST] = cert_get_digest("sha1", mCert); -	mLLSDInfo[CERT_MD5_DIGEST] = cert_get_digest("md5", mCert); -	// add the known extensions -	mLLSDInfo[CERT_BASIC_CONSTRAINTS] = _basic_constraints_ext(mCert); -	mLLSDInfo[CERT_KEY_USAGE] = _key_usage_ext(mCert); -	mLLSDInfo[CERT_EXTENDED_KEY_USAGE] = _ext_key_usage_ext(mCert); -	mLLSDInfo[CERT_SUBJECT_KEY_IDENTFIER] = _subject_key_identifier_ext(mCert); -	mLLSDInfo[CERT_AUTHORITY_KEY_IDENTIFIER] = _authority_key_identifier_ext(mCert); -	return mLLSDInfo;  -} - -// Retrieve the basic constraints info -LLSD _basic_constraints_ext(X509* cert) -{ -	LLSD result; -	BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL); -	if(bs) -	{ -		result = LLSD::emptyMap(); -		// Determines whether the cert can be used as a CA -		result[CERT_BASIC_CONSTRAINTS_CA] = (bool)bs->ca; -	 -		if(bs->pathlen)  -		{ -			// the pathlen determines how deep a certificate chain can be from -			// this CA -			if((bs->pathlen->type == V_ASN1_NEG_INTEGER) -			   || !bs->ca)  -			{ -				result[CERT_BASIC_CONSTRAINTS_PATHLEN] = 0; -			}  -			else  -			{ -				result[CERT_BASIC_CONSTRAINTS_PATHLEN] = (int)ASN1_INTEGER_get(bs->pathlen); -			} -		} - -	} -	return result; -} - -// retrieve the key usage, which specifies how the cert can be used. -//  -LLSD _key_usage_ext(X509* cert) -{ -	LLSD result; -	ASN1_STRING *usage_str = (ASN1_STRING *)X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL); -	if(usage_str) -	{ -		result = LLSD::emptyArray(); -		long usage = 0; -		if(usage_str->length > 0)  -		{ -			usage = usage_str->data[0]; -			if(usage_str->length > 1) -			{ -				usage |= usage_str->data[1] << 8; -			} -		} -		ASN1_STRING_free(usage_str); -		if(usage) -		{ -			if(usage & KU_DIGITAL_SIGNATURE) result.append(LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE)); -			if(usage & KU_NON_REPUDIATION) result.append(LLSD((std::string)CERT_KU_NON_REPUDIATION)); -			if(usage & KU_KEY_ENCIPHERMENT) result.append(LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT)); -			if(usage & KU_DATA_ENCIPHERMENT) result.append(LLSD((std::string)CERT_KU_DATA_ENCIPHERMENT)); -			if(usage & KU_KEY_AGREEMENT) result.append(LLSD((std::string)CERT_KU_KEY_AGREEMENT)); -			if(usage & KU_KEY_CERT_SIGN) result.append(LLSD((std::string)CERT_KU_CERT_SIGN));			 -			if(usage & KU_CRL_SIGN) result.append(LLSD((std::string)CERT_KU_CRL_SIGN));	 -			if(usage & KU_ENCIPHER_ONLY) result.append(LLSD((std::string)CERT_KU_ENCIPHER_ONLY));				 -			if(usage & KU_DECIPHER_ONLY) result.append(LLSD((std::string)CERT_KU_DECIPHER_ONLY));		 -		} -	} -	return result; -} - -// retrieve the extended key usage for the cert -LLSD _ext_key_usage_ext(X509* cert) -{ -	LLSD result; -	EXTENDED_KEY_USAGE *eku = (EXTENDED_KEY_USAGE *)X509_get_ext_d2i(cert, NID_ext_key_usage, NULL, NULL); -	if(eku) -	{ -		result = LLSD::emptyArray(); -		while(sk_ASN1_OBJECT_num(eku)) -		{ -			ASN1_OBJECT *usage = sk_ASN1_OBJECT_pop(eku); -			if(usage) -			{ -				int nid = OBJ_obj2nid(usage); -				if (nid) -				{ -					std::string sn = OBJ_nid2sn(nid); -					result.append(sn); -				} -				ASN1_OBJECT_free(usage); -			} -		} -	} -	return result; -} - -// retrieve the subject key identifier of the cert -LLSD _subject_key_identifier_ext(X509 *cert) -{ -	LLSD result; -	ASN1_OCTET_STRING *skeyid = (ASN1_OCTET_STRING *)X509_get_ext_d2i(cert, NID_subject_key_identifier, NULL, NULL); -	if(skeyid) -	{ -		result = cert_string_from_octet_string(skeyid); -	} -	return result; -} - -// retrieve the authority key identifier of the cert -LLSD _authority_key_identifier_ext(X509* cert) -{ -	LLSD result; -	AUTHORITY_KEYID *akeyid = (AUTHORITY_KEYID *)X509_get_ext_d2i(cert, NID_authority_key_identifier, NULL, NULL); -	if(akeyid) -	{ -		result = LLSD::emptyMap(); -		if(akeyid->keyid) -		{ -			result[CERT_AUTHORITY_KEY_IDENTIFIER_ID] = cert_string_from_octet_string(akeyid->keyid); -		} -		if(akeyid->serial) -		{ -			result[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL] = cert_string_from_asn1_integer(akeyid->serial); -		}	 -	} -	 -	// we ignore the issuer name in the authority key identifier, we check the issue name via -	// the the issuer name entry in the cert. -	 - -	return result; -} - -// retrieve an openssl x509 object, -// which must be freed by X509_free -X509* LLBasicCertificate::getOpenSSLX509() const -{  -	return X509_dup(mCert);  -}   - -// generate a single string containing the subject or issuer -// name of the cert. -std::string cert_string_name_from_X509_NAME(X509_NAME* name) -{ -	char * name_bio_chars = NULL; -	// get a memory bio -	BIO *name_bio = BIO_new(BIO_s_mem()); -	// stream the name into the bio.  The name will be in the 'short name' format -	X509_NAME_print_ex(name_bio, name, 0, XN_FLAG_RFC2253); -	int length = BIO_get_mem_data(name_bio, &name_bio_chars); -	std::string result = std::string(name_bio_chars, length); -	BIO_free(name_bio); -	return result; -} - -// generate an LLSD from a certificate name (issuer or subject name).   -// the name will be strings indexed by the 'long form' -LLSD cert_name_from_X509_NAME(X509_NAME* name) -{ -	LLSD result = LLSD::emptyMap(); -	int name_entries = X509_NAME_entry_count(name); -	for (int entry_index=0; entry_index < name_entries; entry_index++)  -	{ -		char buffer[32]; -		X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, entry_index); -		 -		std::string name_value = std::string((const char*)M_ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)),  -											 M_ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry))); - -		ASN1_OBJECT* name_obj = X509_NAME_ENTRY_get_object(entry);		 -		OBJ_obj2txt(buffer, sizeof(buffer), name_obj, 0); -		std::string obj_buffer_str = std::string(buffer); -		result[obj_buffer_str] = name_value; -	} -	 -	return result; -} - -// Generate a string from an ASN1 integer.  ASN1 Integers are -// bignums, so they can be 'infinitely' long, therefore we -// cannot simply use a conversion to U64 or something. -// We retrieve as a readable string for UI - -std::string cert_string_from_asn1_integer(ASN1_INTEGER* value) -{ -	std::string result; -	BIGNUM *bn = ASN1_INTEGER_to_BN(value, NULL); -	if(bn) -	{ -		char * ascii_bn = BN_bn2hex(bn); - -		if(ascii_bn) -		{ -			result = ascii_bn; -			OPENSSL_free(ascii_bn); -		} -		BN_free(bn); -	} -	return result; -} - -// Generate a string from an OCTET string. -// we retrieve as a  - -std::string cert_string_from_octet_string(ASN1_OCTET_STRING* value) -{ -	 -	std::stringstream result; -	result << std::hex << std::setprecision(2); -	for (int i=0; i < value->length; i++) -	{ -		if (i != 0)  -		{ -			result << ":"; -		} -		result  << std::setfill('0') << std::setw(2) << (int)value->data[i]; -	} -	return result.str(); -} - -// Generate a string from an ASN1 integer.  ASN1 Integers are -// bignums, so they can be 'infinitely' long, therefore we -// cannot simply use a conversion to U64 or something. -// We retrieve as a readable string for UI - -std::string cert_string_from_asn1_string(ASN1_STRING* value) -{ -	char * string_bio_chars = NULL; -	std::string result; -	// get a memory bio -	BIO *string_bio = BIO_new(BIO_s_mem()); -	if(!string_bio) -	{ -		// stream the name into the bio.  The name will be in the 'short name' format -		ASN1_STRING_print_ex(string_bio, value, ASN1_STRFLGS_RFC2253); -		int length = BIO_get_mem_data(string_bio, &string_bio_chars); -		result = std::string(string_bio_chars, length); -		BIO_free(string_bio); -	} -	else -	{ -		LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; -	} -	 -	return result; -} - -// retrieve a date structure from an ASN1 time, for  -// validity checking. -LLDate cert_date_from_asn1_time(ASN1_TIME* asn1_time) -{ -	 -	struct tm timestruct = {0}; -	int i = asn1_time->length; -	 -	if (i < 10) -	{ -		return LLDate(); -	}	 -	// convert the date from the ASN1 time (which is a string in ZULU time), to -	// a timeval. -	timestruct.tm_year = (asn1_time->data[0]-'0') * 10 + (asn1_time->data[1]-'0'); -	 -	/* Deal with Year 2000 */ -	if (timestruct.tm_year < 70) -		timestruct.tm_year += 100; -	 -	timestruct.tm_mon = (asn1_time->data[2]-'0') * 10 + (asn1_time->data[3]-'0') - 1; -	timestruct.tm_mday = (asn1_time->data[4]-'0') * 10 + (asn1_time->data[5]-'0'); -	timestruct.tm_hour = (asn1_time->data[6]-'0') * 10 + (asn1_time->data[7]-'0'); -	timestruct.tm_min = (asn1_time->data[8]-'0') * 10 + (asn1_time->data[9]-'0'); -	timestruct.tm_sec = (asn1_time->data[10]-'0') * 10 + (asn1_time->data[11]-'0'); - -#if LL_WINDOWS -	return LLDate((F64)_mkgmtime(×truct)); -#else // LL_WINDOWS -	return LLDate((F64)timegm(×truct)); -#endif // LL_WINDOWS -} - -													    -// Generate a string containing a digest.  The digest time is 'ssh1' or -// 'md5', and the resulting string is of the form "aa:12:5c:' and so on -std::string cert_get_digest(const std::string& digest_type, X509 *cert) -{ -	unsigned char digest_data[BUFFER_READ_SIZE]; -	unsigned int len = sizeof(digest_data); -	std::stringstream result; -	const EVP_MD* digest = NULL; -	// we could use EVP_get_digestbyname, but that requires initializer code which -	// would require us to complicate things by plumbing it into the system. -	if (digest_type == "md5") -	{ -		digest = EVP_md5(); -	} -	else if (digest_type == "sha1") -	{ -		digest = EVP_sha1(); -	} -	else -	{ -		return std::string(); -	} - -	X509_digest(cert, digest, digest_data, &len); -	result << std::hex << std::setprecision(2); -	for (unsigned int i=0; i < len; i++) -	{ -		if (i != 0)  -		{ -			result << ":"; -		} -		result  << std::setfill('0') << std::setw(2) << (int)digest_data[i]; -	} -	return result.str(); -} - - -// class LLBasicCertificateVector -// This class represents a list of certificates, implemented by a vector of certificate pointers. -// it contains implementations of the virtual functions for iterators, search, add, remove, etc. -// - -//  Find a certificate in the list. -// It will find a cert that has minimally the params listed, with the values being the same -LLBasicCertificateVector::iterator LLBasicCertificateVector::find(const LLSD& params) -{ -	BOOL found = FALSE; -	// loop through the entire vector comparing the values in the certs -	// against those passed in via the params. -	// params should be a map.  Only the items specified in the map will be -	// checked, but they must match exactly, even if they're maps or arrays. -	 -	for(iterator cert = begin(); -		cert != end(); -		cert++) -	{ - -			found= TRUE; -		LLSD cert_info = (*cert)->getLLSD(); -			for (LLSD::map_const_iterator param = params.beginMap(); -			 param != params.endMap(); -			 param++) -		{ - -			if (!cert_info.has((std::string)param->first) ||  -				(!valueCompareLLSD(cert_info[(std::string)param->first], param->second))) -			{ -				found = FALSE; -				break; -			} -		} -		if (found) -		{ -			return (cert); -		} -	} -	return end(); -} - -// Insert a certificate into the store.  If the certificate already  -// exists in the store, nothing is done. -void  LLBasicCertificateVector::insert(iterator _iter,  -									   LLPointer<LLCertificate> cert) -{ -	LLSD cert_info = cert->getLLSD(); -	if (cert_info.isMap() && cert_info.has(CERT_SHA1_DIGEST)) -	{ -		LLSD existing_cert_info = LLSD::emptyMap(); -		existing_cert_info[CERT_MD5_DIGEST] = cert_info[CERT_MD5_DIGEST]; -		if(find(existing_cert_info) == end()) -		{ -			BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get()); -			mCerts.insert(basic_iter->mIter, cert); -		} -	} -} - -// remove a certificate from the store -LLPointer<LLCertificate> LLBasicCertificateVector::erase(iterator _iter) -{ -	 -	if (_iter != end()) -	{ -		BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get()); -		LLPointer<LLCertificate> result = (*_iter); -		mCerts.erase(basic_iter->mIter); -		return result; -	} -	return NULL; -} - - -// -// LLBasicCertificateStore -// This class represents a store of CA certificates.  The basic implementation -// uses a pem file such as the legacy CA.pem stored in the existing  -// SL implementation. -LLBasicCertificateStore::LLBasicCertificateStore(const std::string& filename) -{ -	mFilename = filename; -	load_from_file(filename); -} - -void LLBasicCertificateStore::load_from_file(const std::string& filename) -{ -	// scan the PEM file extracting each certificate -	BIO* file_bio = BIO_new(BIO_s_file()); -	if(file_bio) -	{ -		if (BIO_read_filename(file_bio, filename.c_str()) > 0) -		{	 -			X509 *cert_x509 = NULL; -			while((PEM_read_bio_X509(file_bio, &cert_x509, 0, NULL)) &&  -				  (cert_x509 != NULL)) -			{ -				try -				{ -					add(new LLBasicCertificate(cert_x509)); -				} -				catch (...) -				{ -					LL_WARNS("SECAPI") << "Failure creating certificate from the certificate store file." << LL_ENDL; -				} -				X509_free(cert_x509); -				cert_x509 = NULL; -			} -			BIO_free(file_bio); -		} -	} -	else -	{ -		LL_WARNS("SECAPI") << "Could not allocate a file BIO" << LL_ENDL; -	} -} - - -LLBasicCertificateStore::~LLBasicCertificateStore() -{ -} - - -// persist the store -void LLBasicCertificateStore::save() -{ -	llofstream file_store(mFilename, llofstream::binary); -	if(!file_store.fail()) -	{ -		for(iterator cert = begin(); -			cert != end(); -			cert++) -		{ -			std::string pem = (*cert)->getPem(); -			if(!pem.empty()) -			{ -				file_store << (*cert)->getPem() << std::endl; -			} -		} -		file_store.close(); -	} -	else -	{ -		LL_WARNS("SECAPI") << "Could not open certificate store " << mFilename << "for save" << LL_ENDL; -	} -} - -// return the store id -std::string LLBasicCertificateStore::storeId() const -{ -	// this is the basic handler which uses the CA.pem store, -	// so we ignore this. -	return std::string(""); -} - - -// -// LLBasicCertificateChain -// This class represents a chain of certs, each cert being signed by the next cert -// in the chain.  Certs must be properly signed by the parent -LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store) -{ - -	// we're passed in a context, which contains a cert, and a blob of untrusted -	// certificates which compose the chain. -	if((store == NULL) || (store->cert == NULL)) -	{ -		LL_WARNS("SECAPI") << "An invalid store context was passed in when trying to create a certificate chain" << LL_ENDL; -		return; -	} -	// grab the child cert -	LLPointer<LLCertificate> current = new LLBasicCertificate(store->cert); - -	add(current); -	if(store->untrusted != NULL) -	{ -		// if there are other certs in the chain, we build up a vector -		// of untrusted certs so we can search for the parents of each -		// consecutive cert. -		LLBasicCertificateVector untrusted_certs; -		for(int i = 0; i < sk_X509_num(store->untrusted); i++) -		{ -			LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(store->untrusted, i)); -			untrusted_certs.add(cert); - -		}		 -		while(untrusted_certs.size() > 0) -		{ -			LLSD find_data = LLSD::emptyMap(); -			LLSD cert_data = current->getLLSD(); -			// we simply build the chain via subject/issuer name as the -			// client should not have passed in multiple CA's with the same  -			// subject name.  If they did, it'll come out in the wash during -			// validation. -			find_data[CERT_SUBJECT_NAME_STRING] = cert_data[CERT_ISSUER_NAME_STRING];  -			LLBasicCertificateVector::iterator issuer = untrusted_certs.find(find_data); -			if (issuer != untrusted_certs.end()) -			{ -				current = untrusted_certs.erase(issuer); -				add(current); -			} -			else -			{ -				break; -			} -		} -	} -} - - -// subdomain wildcard specifiers can be divided into 3 parts -// the part before the first *, the part after the first * but before -// the second *, and the part after the second *. -// It then iterates over the second for each place in the string -// that it matches.  ie if the subdomain was testfoofoobar, and -// the wildcard was test*foo*bar, it would match test, then -// recursively match foofoobar and foobar - -bool _cert_subdomain_wildcard_match(const std::string& subdomain, -									const std::string& wildcard) -{ -	// split wildcard into the portion before the *, and the portion after - -	int wildcard_pos = wildcard.find_first_of('*');	 -	// check the case where there is no wildcard. -	if(wildcard_pos == wildcard.npos) -	{ -		return (subdomain == wildcard); -	} -	 -	// we need to match the first part of the subdomain string up to the wildcard -	// position -	if(subdomain.substr(0, wildcard_pos) != wildcard.substr(0, wildcard_pos)) -	{ -		// the first portions of the strings didn't match -		return FALSE; -	} -	 -	// as the portion of the wildcard string before the * matched, we need to check the -	// portion afterwards.  Grab that portion. -	std::string new_wildcard_string = wildcard.substr( wildcard_pos+1, wildcard.npos); -	if(new_wildcard_string.empty()) -	{ -		// we had nothing after the *, so it's an automatic match -		return TRUE; -	} -	 -	// grab the portion of the remaining wildcard string before the next '*'.  We need to find this -	// within the remaining subdomain string. and then recursively check. -	std::string new_wildcard_match_string = new_wildcard_string.substr(0, new_wildcard_string.find_first_of('*')); -	 -	// grab the portion of the subdomain after the part that matched the initial wildcard portion -	std::string new_subdomain = subdomain.substr(wildcard_pos, subdomain.npos); -	 -	// iterate through the current subdomain, finding instances of the match string. -	int sub_pos = new_subdomain.find_first_of(new_wildcard_match_string); -	while(sub_pos != std::string::npos) -	{ -		new_subdomain = new_subdomain.substr(sub_pos, std::string::npos); -		if(_cert_subdomain_wildcard_match(new_subdomain, new_wildcard_string)) -		{ -			return TRUE; -		} -		sub_pos = new_subdomain.find_first_of(new_wildcard_match_string, 1); - - -	} -	// didn't find any instances of the match string that worked in the subdomain, so fail. -	return FALSE; -} - - -// RFC2459 does not address wildcards as part of it's name matching -// specification, and there is no RFC specifying wildcard matching, -// RFC2818 does a few statements about wildcard matching, but is very  -// general.  Generally, wildcard matching is per implementation, although -// it's pretty similar. -// in our case, we use the '*' wildcard character only, within each -// subdomain.  The hostname and the CN specification should have the -// same number of subdomains. -// We then iterate that algorithm over each subdomain. -bool _cert_hostname_wildcard_match(const std::string& hostname, const std::string& common_name) -{ -	std::string new_hostname = hostname; -	std::string new_cn = common_name; -	int subdomain_pos = new_hostname.find_first_of('.'); -	int subcn_pos = new_cn.find_first_of('.'); -	 -	while((subcn_pos != std::string::npos) && (subdomain_pos != std::string::npos)) -	{ -		// snip out the first subdomain and cn element - -		if(!_cert_subdomain_wildcard_match(new_hostname.substr(0, subdomain_pos), -										   new_cn.substr(0, subcn_pos))) -		{ -			return FALSE; -		} -		new_hostname = new_hostname.substr(subdomain_pos+1, std::string::npos); -		new_cn = new_cn.substr(subcn_pos+1, std::string::npos); -		subdomain_pos = new_hostname.find_first_of('.'); -		subcn_pos = new_cn.find_first_of('.'); -	} -	return _cert_subdomain_wildcard_match(new_hostname, new_cn); - -} - -// validate that the LLSD array in llsd_set contains the llsd_value  -bool _LLSDArrayIncludesValue(const LLSD& llsd_set, LLSD llsd_value) -{ -	for(LLSD::array_const_iterator set_value = llsd_set.beginArray(); -		set_value != llsd_set.endArray(); -		set_value++) -	{ -		if(valueCompareLLSD((*set_value), llsd_value)) -		{ -			return TRUE; -		} -	} -	return FALSE; -} - -void _validateCert(int validation_policy, -				  const LLPointer<LLCertificate> cert, -				  const LLSD& validation_params, -				  int depth) -{ - -	LLSD current_cert_info = cert->getLLSD();		 -	// check basic properties exist in the cert -	if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING)) -	{ -		throw LLCertException(cert, "Cert doesn't have a Subject Name");				 -	} -	 -	if(!current_cert_info.has(CERT_ISSUER_NAME_STRING)) -	{ -		throw LLCertException(cert, "Cert doesn't have an Issuer Name");				 -	} -	 -	// check basic properties exist in the cert -	if(!current_cert_info.has(CERT_VALID_FROM) || !current_cert_info.has(CERT_VALID_TO)) -	{ -		throw LLCertException(cert, "Cert doesn't have an expiration period");				 -	} -	if (!current_cert_info.has(CERT_SHA1_DIGEST)) -	{ -		throw LLCertException(cert, "No SHA1 digest"); -	} - -	if (validation_policy & VALIDATION_POLICY_TIME) -	{ - -		LLDate validation_date(time(NULL)); -		if(validation_params.has(CERT_VALIDATION_DATE)) -		{ -			validation_date = validation_params[CERT_VALIDATION_DATE]; -		} -		 -		if((validation_date < current_cert_info[CERT_VALID_FROM].asDate()) || -		   (validation_date > current_cert_info[CERT_VALID_TO].asDate())) -		{ -			throw LLCertValidationExpirationException(cert, validation_date); -		} -	} -	if (validation_policy & VALIDATION_POLICY_SSL_KU) -	{ -		if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() && -			(!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE],  -									   LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) || -			!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE],  -									  LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT))))) -		{ -			throw LLCertKeyUsageValidationException(cert); -		} -		// only validate EKU if the cert has it -		if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() &&	    -		   (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE],  -									LLSD((std::string)CERT_EKU_SERVER_AUTH)))) -		{ -			throw LLCertKeyUsageValidationException(cert);			 -		} -	} -	if (validation_policy & VALIDATION_POLICY_CA_KU) -	{ -		if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() && -			(!_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE],  -									   (std::string)CERT_KU_CERT_SIGN))) -			{ -				throw LLCertKeyUsageValidationException(cert);						 -			} -	} -	 -	// validate basic constraints -	if ((validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS) && -		current_cert_info.has(CERT_BASIC_CONSTRAINTS) &&  -		current_cert_info[CERT_BASIC_CONSTRAINTS].isMap()) -	{ -		if(!current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_CA) || -		   !current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_CA]) -		{ -				throw LLCertBasicConstraintsValidationException(cert); -		} -		if (current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_PATHLEN) && -			((current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger() != 0) && -			 (depth > current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger()))) -		{ -			throw LLCertBasicConstraintsValidationException(cert);					 -		} -	} -} - -bool _verify_signature(LLPointer<LLCertificate> parent,  -					   LLPointer<LLCertificate> child) -{ -	bool verify_result = FALSE;  -	LLSD cert1 = parent->getLLSD(); -	LLSD cert2 = child->getLLSD(); -	X509 *signing_cert = parent->getOpenSSLX509(); -	X509 *child_cert = child->getOpenSSLX509(); -	if((signing_cert != NULL) && (child_cert != NULL)) -	{ -		EVP_PKEY *pkey = X509_get_pubkey(signing_cert); -		 -		 -		if(pkey) -		{ -			int verify_code = X509_verify(child_cert, pkey); -			verify_result = ( verify_code > 0); -			EVP_PKEY_free(pkey); -		} -		else -		{ -			LL_WARNS("SECAPI") << "Could not validate the cert chain signature, as the public key of the signing cert could not be retrieved" << LL_ENDL; -		} - -	} -	else -	{ -		LL_WARNS("SECAPI") << "Signature verification failed as there are no certs in the chain" << LL_ENDL; -	} -	if(child_cert) -	{ -		X509_free(child_cert); -	} -	if(signing_cert) -	{ -		X509_free(signing_cert); -	} -	return verify_result; -} - -// validate the certificate chain against a store. -// There are many aspects of cert validatioin policy involved in -// trust validation.  The policies in this validation algorithm include -// * Hostname matching for SSL certs -// * Expiration time matching -// * Signature validation -// * Chain trust (is the cert chain trusted against the store) -// * Basic constraints -// * key usage and extended key usage -// TODO: We should add 'authority key identifier' for chaining. -// This algorithm doesn't simply validate the chain by itself -// and verify the last cert is in the certificate store, or points -// to a cert in the store.  It validates whether any cert in the chain -// is trusted in the store, even if it's not the last one. -void LLBasicCertificateChain::validate(int validation_policy, -									   LLPointer<LLCertificateStore> ca_store, -									   const LLSD& validation_params) -{ - -	if(size() < 1) -	{ -		throw LLCertException(NULL, "No certs in chain"); -	} -	iterator current_cert = begin(); -	LLSD 	current_cert_info = (*current_cert)->getLLSD(); -	LLSD validation_date; -	if (validation_params.has(CERT_VALIDATION_DATE)) -	{ -		validation_date = validation_params[CERT_VALIDATION_DATE]; -	} - -	if (validation_policy & VALIDATION_POLICY_HOSTNAME) -	{ -		if(!validation_params.has(CERT_HOSTNAME)) -		{ -			throw LLCertException((*current_cert), "No hostname passed in for validation");			 -		} -		if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info[CERT_SUBJECT_NAME].has(CERT_NAME_CN)) -		{ -			throw LLInvalidCertificate((*current_cert));				 -		} -		 -		LL_INFOS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() <<  -		     "against the cert CN " << current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString() << LL_ENDL; -		if(!_cert_hostname_wildcard_match(validation_params[CERT_HOSTNAME].asString(), -										  current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString())) -		{ -			throw LLCertValidationHostnameException(validation_params[CERT_HOSTNAME].asString(), -													(*current_cert)); -		} -	} -	 - -	int depth = 0; -	LLPointer<LLCertificate> previous_cert; -	// loop through the cert chain, validating the current cert against the next one. -	while(current_cert != end()) -	{ -		 -		int local_validation_policy = validation_policy; -		if(current_cert == begin()) -		{ -			// for the child cert, we don't validate CA stuff -			local_validation_policy &= ~(VALIDATION_POLICY_CA_KU |  -										 VALIDATION_POLICY_CA_BASIC_CONSTRAINTS); -		} -		else -		{ -			// for non-child certs, we don't validate SSL Key usage -			local_validation_policy &= ~VALIDATION_POLICY_SSL_KU;				 -			if(!_verify_signature((*current_cert), -								  previous_cert)) -			{ -			   throw LLCertValidationInvalidSignatureException(previous_cert); -			} -		} -		_validateCert(local_validation_policy, -					  (*current_cert), -					  validation_params, -					  depth); -		 -		// look for a CA in the CA store that may belong to this chain. -		LLSD cert_llsd = (*current_cert)->getLLSD(); -		LLSD cert_search_params = LLSD::emptyMap();		 -		// is the cert itself in the store? -		cert_search_params[CERT_SHA1_DIGEST] = cert_llsd[CERT_SHA1_DIGEST]; -		LLCertificateStore::iterator found_store_cert = ca_store->find(cert_search_params); -		if(found_store_cert != ca_store->end()) -		{ -			return; -		} -		 -		// is the parent in the cert store? -			 -		cert_search_params = LLSD::emptyMap(); -		cert_search_params[CERT_SUBJECT_NAME_STRING] = cert_llsd[CERT_ISSUER_NAME_STRING]; -		if (cert_llsd.has(CERT_AUTHORITY_KEY_IDENTIFIER)) -		{ -			LLSD cert_aki = cert_llsd[CERT_AUTHORITY_KEY_IDENTIFIER]; -			if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_ID)) -			{ -				cert_search_params[CERT_SUBJECT_KEY_IDENTFIER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_ID]; -			} -			if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL)) -			{ -				cert_search_params[CERT_SERIAL_NUMBER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL]; -			} -		} -		found_store_cert = ca_store->find(cert_search_params); -		 -		if(found_store_cert != ca_store->end()) -		{ -			LLSD foo = (*found_store_cert)->getLLSD(); -			// validate the store cert against the depth -			_validateCert(validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS, -						  (*found_store_cert), -						  LLSD(), -						  depth); -			 -			// verify the signature of the CA -			if(!_verify_signature((*found_store_cert), -								  (*current_cert))) -			{ -				throw LLCertValidationInvalidSignatureException(*current_cert); -			}			 -			// successfully validated. -			return; -		} -		previous_cert = (*current_cert); -		current_cert++; -			   depth++; -	} -	if (validation_policy & VALIDATION_POLICY_TRUSTED) -	{ -		LLPointer<LLCertificate> untrusted_ca_cert = (*this)[size()-1]; -		// we reached the end without finding a trusted cert. -		throw LLCertValidationTrustException((*this)[size()-1]); - -	} -} - - -// 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, -										   const std::string& legacy_password_path) -{ -	mProtectedDataFilename = protected_data_file; -	mProtectedDataMap = LLSD::emptyMap(); -	mLegacyPasswordPath = legacy_password_path; - -} - -LLSecAPIBasicHandler::LLSecAPIBasicHandler() -{ -} - - -void LLSecAPIBasicHandler::init() -{ -	mProtectedDataMap = LLSD::emptyMap(); -	if (mProtectedDataFilename.length() == 0) -	{ -		mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, -															"bin_conf.dat"); -		mLegacyPasswordPath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "password.dat"); -	 -		mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, -															"bin_conf.dat");	 -		std::string store_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, -														"CA.pem"); -		// copy the CA file to a user writable location so we can manipulate it. -		// for this provider, by using a user writable file, there is a risk that -		// an attacking program can modify the file, but OS dependent providers -		// will reduce that risk. -		// by using a user file, modifications will be limited to one user if -		// we read-only the main file -		if (!LLFile::isfile(store_file)) -		{ - -			std::string ca_file_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); -			llifstream ca_file(ca_file_path.c_str(), llifstream::binary | llifstream::in); -			llofstream copied_store_file(store_file.c_str(), llofstream::binary | llofstream::out); - -			while(!ca_file.fail()) -			{ -				char buffer[BUFFER_READ_SIZE]; -				ca_file.read(buffer, sizeof(buffer)); -				copied_store_file.write(buffer, ca_file.gcount()); -			} -			ca_file.close(); -			copied_store_file.close(); -		} -		LL_INFOS("SECAPI") << "Loading certificate store from " << store_file << LL_ENDL; -		mStore = new LLBasicCertificateStore(store_file); -	} -	_readProtectedData(); // initialize mProtectedDataMap -						  // may throw LLProtectedDataException if saved datamap is not decryptable -} -LLSecAPIBasicHandler::~LLSecAPIBasicHandler() -{ -	_writeProtectedData(); -} - -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()) { -		int offset; -		U8 salt[STORE_SALT_SIZE]; -		U8 buffer[BUFFER_READ_SIZE]; -		U8 decrypted_buffer[BUFFER_READ_SIZE]; -		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("Config file too short."); -		} - -		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. -		// 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. -		// We've a strong intent to move to OS dependent protected data stores. -		 - -		// read in the rest of the file. -		EVP_CIPHER_CTX ctx; -		EVP_CIPHER_CTX_init(&ctx); -		EVP_DecryptInit(&ctx, EVP_rc4(), salt, NULL); -		// allocate memory: -		std::string decrypted_data;	 -		 -		while(protected_data_stream.good()) { -			// read data as a block: -			protected_data_stream.read((char *)buffer, BUFFER_READ_SIZE); -			 -			EVP_DecryptUpdate(&ctx, decrypted_buffer, &decrypted_length,  -							  buffer, protected_data_stream.gcount()); -			decrypted_data.append((const char *)decrypted_buffer, protected_data_stream.gcount()); -		} -		 -		// RC4 is a stream cipher, so we don't bother to EVP_DecryptFinal, as there is -		// no block padding. -		EVP_CIPHER_CTX_cleanup(&ctx); -		std::istringstream parse_stream(decrypted_data); -		if (parser->parse(parse_stream, mProtectedDataMap,  -						  LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) -		{ -			throw LLProtectedDataException("Config file cannot be decrypted."); -		} -	} -} - -void LLSecAPIBasicHandler::_writeProtectedData() -{	 -	std::ostringstream formatted_data_ostream; -	U8 salt[STORE_SALT_SIZE]; -	U8 buffer[BUFFER_READ_SIZE]; -	U8 encrypted_buffer[BUFFER_READ_SIZE]; - -	 -	if(mProtectedDataMap.isUndefined()) -	{ -		LLFile::remove(mProtectedDataFilename); -		return; -	} -	// 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. -	std::string tmp_filename = mProtectedDataFilename + ".tmp"; -	 -	llofstream protected_data_stream(tmp_filename.c_str(),  -										llofstream::binary); -	try -	{ -		 -		EVP_CIPHER_CTX ctx; -		EVP_CIPHER_CTX_init(&ctx); -		EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL); -		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); -			if(formatted_data_istream.gcount() == 0) -			{ -				break; -			} -			int encrypted_length; -			EVP_EncryptUpdate(&ctx, encrypted_buffer, &encrypted_length,  -						  buffer, formatted_data_istream.gcount()); -			protected_data_stream.write((const char *)encrypted_buffer, encrypted_length); -		} -		 -		// no EVP_EncrypteFinal, as this is a stream cipher -		EVP_CIPHER_CTX_cleanup(&ctx); - -		protected_data_stream.close(); -	} -	catch (...) -	{ -		// it's good practice to clean up any secure information on error -		// (even though this file isn't really secure.  Perhaps in the future -		// it may be, however. -		LLFile::remove(tmp_filename); -		throw LLProtectedDataException("Error writing Protected Data Store"); -	} - -	// move the temporary file to the specified file location. -	if((((LLFile::isfile(mProtectedDataFilename) != 0) &&  -		 (LLFile::remove(mProtectedDataFilename) != 0))) ||  -	   (LLFile::rename(tmp_filename, mProtectedDataFilename))) -	{ -		LLFile::remove(tmp_filename); -		throw LLProtectedDataException("Could not overwrite protected data store"); -	} -} -		 -// instantiate a certificate from a pem string -LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(const std::string& pem_cert) -{ -	LLPointer<LLCertificate> result = new LLBasicCertificate(pem_cert); -	return result; -} -		 - -		 -// instiate a certificate from an openssl X509 structure -LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert) -{ -	LLPointer<LLCertificate> result = new LLBasicCertificate(openssl_cert); -	return result;		 -} -		 -// instantiate a chain from an X509_STORE_CTX -LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain) -{ -	LLPointer<LLCertificateChain> result = new LLBasicCertificateChain(chain); -	return result; -} -		 -// instantiate a cert store given it's id.  if a persisted version -// exists, it'll be loaded.  If not, one will be created (but not -// persisted) -LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const std::string& store_id) -{ -	return mStore; -} -		 -// retrieve protected data -LLSD LLSecAPIBasicHandler::getProtectedData(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)) -	{ -		return mProtectedDataMap[data_type][data_id]; -	} -																				 -	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) -{ -	if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) { -		mProtectedDataMap[data_type] = LLSD::emptyMap(); -	} -	 -	mProtectedDataMap[data_type][data_id] = data;  -} - -// -// 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("SECAPI") << "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? -	_writeProtectedData(); -} - -// Remove a credential from the credential store. -void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred) -{ -	LLSD undefVal; -	deleteProtectedData("credential", cred->getGrid()); -	cred->setCredentialData(undefVal, undefVal); -	_writeProtectedData(); -} - -// 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)"; -} - - -bool valueCompareLLSD(const LLSD& lhs, const LLSD& rhs) -{ -	if (lhs.type() != rhs.type()) -	{ -		return FALSE; -	} -    if (lhs.isMap()) -	{ -		// iterate through the map, verifying the right hand side has all of the -		// values that the left hand side has. -		for (LLSD::map_const_iterator litt = lhs.beginMap(); -			 litt != lhs.endMap(); -			 litt++) -		{ -			if (!rhs.has(litt->first)) -			{ -				return FALSE; -			} -		} -		 -		// Now validate that the left hand side has everything the -		// right hand side has, and that the values are equal. -		for (LLSD::map_const_iterator ritt = rhs.beginMap(); -			 ritt != rhs.endMap(); -			 ritt++) -		{ -			if (!lhs.has(ritt->first)) -			{ -				return FALSE; -			} -			if (!valueCompareLLSD(lhs[ritt->first], ritt->second)) -			{ -				return FALSE; -			} -		} -		return TRUE; -	} -    else if (lhs.isArray()) -	{ -		LLSD::array_const_iterator ritt = rhs.beginArray(); -		// iterate through the array, comparing -		for (LLSD::array_const_iterator litt = lhs.beginArray(); -			 litt != lhs.endArray(); -			 litt++) -		{ -			if (!valueCompareLLSD(*ritt, *litt)) -			{ -				return FALSE; -			} -			ritt++; -		} -		 -		return (ritt == rhs.endArray()); -	} -    else -	{ -		// simple type, compare as string -		return (lhs.asString() == rhs.asString()); -	} -	 -} diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h deleted file mode 100644 index 4bbb73f062..0000000000 --- a/indra/newview/llsechandler_basic.h +++ /dev/null @@ -1,285 +0,0 @@ -/**  - * @file llsechandler_basic.h - * @brief Security API for services such as certificate handling - * secure local storage, etc. - * - * $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 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://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://secondlife.com/developers/opensource/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$ - */ - -#ifndef LLSECHANDLER_BASIC -#define LLSECHANDLER_BASIC - -#include "llsecapi.h" -#include <vector> -#include <openssl/x509.h> - -// helpers -extern LLSD cert_name_from_X509_NAME(X509_NAME* name); -extern std::string cert_string_name_from_X509_NAME(X509_NAME* name); -extern std::string cert_string_from_asn1_integer(ASN1_INTEGER* value); -extern LLDate cert_date_from_asn1_time(ASN1_TIME* asn1_time); -extern std::string cert_get_digest(const std::string& digest_type, X509 *cert); - - -// class LLCertificate -//  -class LLBasicCertificate : public LLCertificate -{ -public:		 -	LOG_CLASS(LLBasicCertificate); - -	LLBasicCertificate(const std::string& pem_cert); -	LLBasicCertificate(X509* openSSLX509); -	 -	virtual ~LLBasicCertificate(); -	 -	virtual std::string getPem() const; -	virtual std::vector<U8> getBinary() const; -	virtual LLSD getLLSD() const; - -	virtual X509* getOpenSSLX509() const; -	 -	// set llsd elements for testing -	void setLLSD(const std::string name, const LLSD& value) { mLLSDInfo[name] = value; } -protected: - -	// certificates are stored as X509 objects, as validation and -	// other functionality is via openssl -	X509* mCert; -	 -	LLSD& _initLLSD(); -	LLSD mLLSDInfo; -}; - - -// class LLBasicCertificateVector -// Class representing a list of certificates -// This implementation uses a stl vector of certificates. -class LLBasicCertificateVector : virtual public LLCertificateVector -{ -	 -public: -	LLBasicCertificateVector() {} -	 -	virtual ~LLBasicCertificateVector() {} -	 -	// Implementation of the basic iterator implementation. -	// The implementation uses a vector iterator derived from  -	// the vector in the LLBasicCertificateVector class -	class BasicIteratorImpl : public iterator_impl -	{ -	public: -		BasicIteratorImpl(std::vector<LLPointer<LLCertificate> >::iterator _iter) { mIter = _iter;} -		virtual ~BasicIteratorImpl() {}; -		// seek forward or back.  Used by the operator++/operator-- implementations -		virtual void seek(bool incr) -		{ -			if(incr) -			{ -				mIter++; -			} -			else -			{ -				mIter--; -			} -		} -		// create a copy of the iterator implementation class, used by the iterator copy constructor -		virtual LLPointer<iterator_impl> clone() const -		{ -			return new BasicIteratorImpl(mIter); -		} -		 -		virtual bool equals(const LLPointer<iterator_impl>& _iter) const -		{ -			const BasicIteratorImpl *rhs_iter = dynamic_cast<const BasicIteratorImpl *>(_iter.get()); -			return (mIter == rhs_iter->mIter); -		} -		virtual LLPointer<LLCertificate> get() -		{ -			return *mIter; -		} -	protected: -		friend class LLBasicCertificateVector; -		std::vector<LLPointer<LLCertificate> >::iterator mIter; -	}; -	 -	// numeric index of the vector -	virtual LLPointer<LLCertificate> operator[](int _index) { return mCerts[_index];} -	 -	// Iteration -	virtual iterator begin() { return iterator(new BasicIteratorImpl(mCerts.begin())); } -	 -	virtual iterator end() {  return iterator(new BasicIteratorImpl(mCerts.end())); } -	 -	// find a cert given params -	virtual iterator find(const LLSD& params); -	 -	// return the number of certs in the store -	virtual int size() const { return mCerts.size(); }	 -	 -	// insert the cert to the store.  if a copy of the cert already exists in the store, it is removed first -	virtual void  add(LLPointer<LLCertificate> cert) { insert(end(), cert); } -	 -	// insert the cert to the store.  if a copy of the cert already exists in the store, it is removed first -	virtual void  insert(iterator _iter, LLPointer<LLCertificate> cert);	 -	 -	// remove a certificate from the store -	virtual LLPointer<LLCertificate> erase(iterator _iter); -	 -protected: -	std::vector<LLPointer<LLCertificate> >mCerts;	 -}; - -// 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 : virtual public LLBasicCertificateVector, public LLCertificateStore -{ -public: -	LLBasicCertificateStore(const std::string& filename); -	void load_from_file(const std::string& filename); -	 -	virtual ~LLBasicCertificateStore(); -	 -	// persist the store -	virtual void save(); -	 -	// return the store id -	virtual std::string storeId() const; -	 -protected: -	std::vector<LLPointer<LLCertificate> >mCerts; -	std::string mFilename; -}; - -// class LLCertificateChain -// Class representing a chain of certificates in order, with the  -// first element being the child cert. -class LLBasicCertificateChain : virtual public LLBasicCertificateVector, public LLCertificateChain -{ -	 -public: -	LLBasicCertificateChain(const X509_STORE_CTX * store); -	 -	virtual ~LLBasicCertificateChain() {} -	 -	// validate a certificate chain against a certificate store, using the -	// given validation policy. -	virtual void validate(int validation_policy, -						  LLPointer<LLCertificateStore> ca_store, -						  const LLSD& validation_params); -}; - - - -// 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, -						 const std::string& legacy_password_path); -	LLSecAPIBasicHandler(); -	 -	void init(); -	 -	virtual ~LLSecAPIBasicHandler(); -	 -	// instantiate a certificate from a pem string -	virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert); -	 -	 -	// instiate a certificate from an openssl X509 structure -	virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert); -	 -	// instantiate a chain from an X509_STORE_CTX -	virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain); -	 -	// instantiate a cert store given it's id.  if a persisted version -	// exists, it'll be loaded.  If not, one will be created (but not -	// persisted) -	virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id); -	 -	// persist data in a protected store -	virtual void setProtectedData(const std::string& data_type, -								  const std::string& data_id, -								  const LLSD& data); -	 -	// 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; -	LLPointer<LLBasicCertificateStore> mStore; -	 -	std::string mLegacyPasswordPath; -}; - -bool valueCompareLLSD(const LLSD& lhs, const LLSD& rhs); - -#endif // LLSECHANDLER_BASIC - - - diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 3ef810c3e9..d03a492cd1 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2435,7 +2435,7 @@ BOOL LLSelectMgr::selectGetCreator(LLUUID& result_id, std::string& name)  	if (identical)  	{ -		name = LLSLURL("agent", first_id, "inspect").getSLURLString(); +		name = LLSLURL::buildCommand("agent", first_id, "inspect");  	}  	else  	{ @@ -2494,11 +2494,11 @@ BOOL LLSelectMgr::selectGetOwner(LLUUID& result_id, std::string& name)  		BOOL public_owner = (first_id.isNull() && !first_group_owned);  		if (first_group_owned)  		{ -			name = LLSLURL("group", first_id, "inspect").getSLURLString(); +			name = LLSLURL::buildCommand("group", first_id, "inspect");  		}  		else if(!public_owner)  		{ -			name = LLSLURL("agent", first_id, "inspect").getSLURLString(); +			name = LLSLURL::buildCommand("agent", first_id, "inspect");  		}  		else  		{ @@ -2558,7 +2558,7 @@ BOOL LLSelectMgr::selectGetLastOwner(LLUUID& result_id, std::string& name)  		BOOL public_owner = (first_id.isNull());  		if(!public_owner)  		{ -			name = LLSLURL("agent", first_id, "inspect").getSLURLString(); +			name = LLSLURL::buildCommand("agent", first_id, "inspect");  		}  		else  		{ diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index ff7e479368..5d20e280b5 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -1,11 +1,10 @@  /**  - * @file llurlsimstring.cpp (was llsimurlstring.cpp) - * @brief Handles "SLURL fragments" like Ahern/123/45 for - * startup processing, login screen, prefs, etc. + * @file llslurl.cpp + * @brief SLURL manipulation   * - * $LicenseInfo:firstyear=2010&license=viewergpl$ + * $LicenseInfo:firstyear=2009&license=viewergpl$   *  - * Copyright (c) 2006-2010, Linden Research, Inc. + * Copyright (c) 2009, Linden Research, Inc.   *    * Second Life Viewer Source Code   * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +12,13 @@   * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, @@ -34,443 +34,155 @@  #include "llslurl.h" -#include "llpanellogin.h" -#include "llviewercontrol.h" -#include "llviewernetwork.h" -#include "llfiltersd2xmlrpc.h" -#include "curl/curl.h" -const char* LLSLURL::SLURL_HTTP_SCHEME		 = "http"; -const char* LLSLURL::SLURL_HTTPS_SCHEME		 = "https"; -const char* LLSLURL::SLURL_SECONDLIFE_SCHEME	 = "secondlife"; -const char* LLSLURL::SLURL_SECONDLIFE_PATH	 = "secondlife"; -const char* LLSLURL::SLURL_COM		         = "slurl.com"; -// For DnD - even though www.slurl.com redirects to slurl.com in a browser, you  can copy and drag +#include "llweb.h" + +#include "llurlregistry.h" + +const std::string LLSLURL::PREFIX_SL_HELP		= "secondlife://app."; +const std::string LLSLURL::PREFIX_SL			= "sl://"; +const std::string LLSLURL::PREFIX_SECONDLIFE	= "secondlife://"; +const std::string LLSLURL::PREFIX_SLURL_OLD		= "http://slurl.com/secondlife/"; + +// For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag  // text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this  // version is required also. +const std::string LLSLURL::PREFIX_SLURL_WWW		= "http://www.slurl.com/secondlife/"; -const char* LLSLURL::WWW_SLURL_COM		 = "www.slurl.com"; -const char* LLSLURL::MAPS_SECONDLIFE_COM	 = "maps.secondlife.com";	 -const char* LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME = "x-grid-location-info"; -const char* LLSLURL::SLURL_APP_PATH              = "app"; -const char* LLSLURL::SLURL_REGION_PATH           = "region"; -const char* LLSLURL::SIM_LOCATION_HOME           = "home"; -const char* LLSLURL::SIM_LOCATION_LAST           = "last"; +const std::string LLSLURL::PREFIX_SLURL			= "http://maps.secondlife.com/secondlife/"; -// resolve a simstring from a slurl -LLSLURL::LLSLURL(const std::string& slurl) +const std::string LLSLURL::APP_TOKEN = "app/"; + +// static +std::string LLSLURL::stripProtocol(const std::string& url)  { -	// by default we go to agni. -	mType = INVALID; -	LL_INFOS("AppInit") << "SLURL: " << slurl << LL_ENDL; -	if(slurl == SIM_LOCATION_HOME) +	std::string stripped = url; +	if (matchPrefix(stripped, PREFIX_SL_HELP))  	{ -		mType = HOME_LOCATION; +		stripped.erase(0, PREFIX_SL_HELP.length());  	} -	else if(slurl.empty() || (slurl == SIM_LOCATION_LAST)) +	else if (matchPrefix(stripped, PREFIX_SL))  	{ - -		mType = LAST_LOCATION; +		stripped.erase(0, PREFIX_SL.length());  	} -	else +	else if (matchPrefix(stripped, PREFIX_SECONDLIFE))  	{ -		LLURI slurl_uri; -		// parse the slurl as a uri -		if(slurl.find(':') == std::string::npos) -		{ -			// There may be no scheme ('secondlife:' etc.) passed in.  In that case -			// we want to normalize the slurl by putting the appropriate scheme -			// in front of the slurl.  So, we grab the appropriate slurl base -			// from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or -			// https://<hostname>/region/ for Standalone grid (the word region, not the region name) -			// these slurls are typically passed in from the 'starting location' box on the login panel, -			// where the user can type in <regionname>/<x>/<y>/<z> -			std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase(); -			// the slurl that was passed in might have a prepended /, or not.  So, -			// we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife/<region>/<x>/<y>/<z> -			// or some such. -			 -			if(slurl[0] == '/') -		    { -				fixed_slurl += slurl.substr(1); -		    } -			else -		    { -				fixed_slurl += slurl; -		    } -			// We then load the slurl into a LLURI form -			slurl_uri = LLURI(fixed_slurl); -		} -		else -		{ -		    // as we did have a scheme, implying a URI style slurl, we -		    // simply parse it as a URI -		    slurl_uri = LLURI(slurl); -		} -		 -		LLSD path_array = slurl_uri.pathArray(); -		 -		// determine whether it's a maingrid URI or an Standalone/open style URI -		// by looking at the scheme.  If it's a 'secondlife:' slurl scheme or -		// 'sl:' scheme, we know it's maingrid -		 -		// At the end of this if/else block, we'll have determined the grid, -		// and the slurl type (APP or LOCATION) -		if(slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME) -		{ -			// parse a maingrid style slurl.  We know the grid is maingrid -			// so grab it. -			// A location slurl for maingrid (with the special schemes) can be in the form -			// secondlife://<regionname>/<x>/<y>/<z> -			// or -			// secondlife://<Grid>/secondlife/<region>/<x>/<y>/<z> -			// where if grid is empty, it specifies Agni -			 -			// An app style slurl for maingrid can be -			// secondlife://<Grid>/app/<app parameters> -			// where an empty grid implies Agni -			 -			// we'll start by checking the top of the 'path' which will be  -			// either 'app', 'secondlife', or <x>. -			 -			// default to maingrid -			 -			mGrid = MAINGRID; -			 -			if ((path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) || -				(path_array[0].asString() == LLSLURL::SLURL_APP_PATH)) -		    { -				// it's in the form secondlife://<grid>/(app|secondlife) -				// so parse the grid name to derive the grid ID -				if (!slurl_uri.hostName().empty()) -				{ -					mGrid = LLGridManager::getInstance()->getGridByLabel(slurl_uri.hostName()); -				} -				else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) -				{ -					// If the slurl is in the form secondlife:///secondlife/<region> form,  -					// then we are in fact on maingrid.   -					mGrid = MAINGRID; -				} -				else if(path_array[0].asString() == LLSLURL::SLURL_APP_PATH) -				{ -					// for app style slurls, where no grid name is specified, assume the currently -					// selected or logged in grid. -					mGrid =  LLGridManager::getInstance()->getGrid(); -				} - -				if(mGrid.empty()) -				{ -					// we couldn't find the grid in the grid manager, so bail -					return; -				} -				// set the type as appropriate. -				if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) -				{ -					mType = LOCATION; -				} -				else -				{ -					mType = APP; -				} -				path_array.erase(0); -		    } -			else -		    { -				// it wasn't a /secondlife/<region> or /app/<params>, so it must be secondlife://<region> -				// therefore the hostname will be the region name, and it's a location type -				mType = LOCATION; -				// 'normalize' it so the region name is in fact the head of the path_array -				path_array.insert(0, slurl_uri.hostName()); -		    } -		} -		else if((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME) || -		   (slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) ||  -		   (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME)) -		{ -		    // We're dealing with either a Standalone style slurl or slurl.com slurl -		  if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) || -		      (slurl_uri.hostName() == LLSLURL::WWW_SLURL_COM) ||  -		      (slurl_uri.hostName() == LLSLURL::MAPS_SECONDLIFE_COM)) -			{ -				// slurl.com implies maingrid -				mGrid = MAINGRID; -			} -		    else -			{ -				// As it's a Standalone grid/open, we will always have a hostname, as Standalone/open  style -				// urls are properly formed, unlike the stinky maingrid style -				mGrid = slurl_uri.hostName(); -			} -		    if (path_array.size() == 0) -			{ -				// um, we need a path... -				return; -			} -			 -			// we need to normalize the urls so -			// the path portion starts with the 'command' that we want to do -			// it can either be region or app.   -		    if ((path_array[0].asString() == LLSLURL::SLURL_REGION_PATH) || -				(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)) -			{ -				// strip off 'region' or 'secondlife' -				path_array.erase(0); -				// it's a location -				mType = LOCATION; -			} -			else if (path_array[0].asString() == LLSLURL::SLURL_APP_PATH) -			{ -				mType = APP; -				path_array.erase(0); -				// leave app appended.   -			} -			else -			{ -				// not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL -				return; -			} -		} -		else -		{ -		    // invalid scheme, so bail -		    return; -		} -		 -		 -		if(path_array.size() == 0) -		{ -			// we gotta have some stuff after the specifier as to whether it's a region or command -			return; -		} -		 -		// now that we know whether it's an app slurl or a location slurl, -		// parse the slurl into the proper data structures. -		if(mType == APP) -		{		 -			// grab the app command type and strip it (could be a command to jump somewhere,  -			// or whatever ) -			mAppCmd = path_array[0].asString(); -			path_array.erase(0); -			 -			// Grab the parameters -			mAppPath = path_array; -			// and the query -			mAppQuery = slurl_uri.query(); -			mAppQueryMap = slurl_uri.queryMap(); -			return; -		} -		else if(mType == LOCATION) -		{ -			// at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z  -			// are collectively optional -			// are optional -			mRegion = LLURI::unescape(path_array[0].asString()); -			path_array.erase(0); -			 -			// parse the x, y, z -			if(path_array.size() >= 3) -			{	 -			   -			  mPosition = LLVector3(path_array); -			  if((F32(mPosition[VX]) < 0.f) ||  -                             (mPosition[VX] > REGION_WIDTH_METERS) || -			     (F32(mPosition[VY]) < 0.f) ||  -                             (mPosition[VY] > REGION_WIDTH_METERS) || -			     (F32(mPosition[VZ]) < 0.f) ||  -                             (mPosition[VZ] > REGION_HEIGHT_METERS)) -			    { -			      mType = INVALID; -			      return; -			    } -  -			} -			else -			{ -				// if x, y and z were not fully passed in, go to the middle of the region. -				// teleport will adjust the actual location to make sure you're on the ground -				// and such -				mPosition = LLVector3(REGION_WIDTH_METERS/2, REGION_WIDTH_METERS/2, 0); -			} -		} +		stripped.erase(0, PREFIX_SECONDLIFE.length()); +	} +	else if (matchPrefix(stripped, PREFIX_SLURL)) +	{ +		stripped.erase(0, PREFIX_SLURL.length());  	} +	else if (matchPrefix(stripped, PREFIX_SLURL_OLD)) +	{ +		stripped.erase(0, PREFIX_SLURL_OLD.length()); +	} +	else if (matchPrefix(stripped, PREFIX_SLURL_WWW)) +	{ +		stripped.erase(0, PREFIX_SLURL_WWW.length()); +	} +	 +	return stripped;  } - -// Create a slurl for the middle of the region -LLSLURL::LLSLURL(const std::string& grid,  -				 const std::string& region) +// static +bool LLSLURL::isSLURL(const std::string& url)  { -	mGrid = grid; -	mRegion = region; -	mType = LOCATION; -	mPosition = LLVector3((F64)REGION_WIDTH_METERS/2, (F64)REGION_WIDTH_METERS/2, 0); +	if (matchPrefix(url, PREFIX_SL_HELP))		return true; +	if (matchPrefix(url, PREFIX_SL))			return true; +	if (matchPrefix(url, PREFIX_SECONDLIFE))	return true; +	if (matchPrefix(url, PREFIX_SLURL))			return true; +	if (matchPrefix(url, PREFIX_SLURL_OLD))		return true; +	if (matchPrefix(url, PREFIX_SLURL_WWW))		return true; +	 +	return false;  } - - -// create a slurl given the position.  The position will be modded with the region -// width handling global positions as well -LLSLURL::LLSLURL(const std::string& grid,  -		 const std::string& region,  -		 const LLVector3& position) +bool LLSLURL::isValidSLURL(const std::string& url)  { -	mGrid = grid; -	mRegion = region; -	S32 x = llround( (F32)fmod( position[VX], (F32)REGION_WIDTH_METERS ) ); -	S32 y = llround( (F32)fmod( position[VY], (F32)REGION_WIDTH_METERS ) ); -	S32 z = llround( (F32)position[VZ] ); -	mType = LOCATION; -	mPosition = LLVector3(x, y, z); +	std::string temp_url(url); +	//"www." may appear in DnD- see description of PREFIX_SLURL_WWW. +	// If it is found, we remove it because it isn't expected in regexp. +	if (matchPrefix(url, PREFIX_SLURL_WWW)) +	{ +		size_t position = url.find("www."); +		temp_url.erase(position,4); +	} +	 +	return LLUrlRegistry::getInstance()->isUrl(temp_url);  } +// static +bool LLSLURL::isSLURLCommand(const std::string& url) +{  +	if (matchPrefix(url, PREFIX_SL + APP_TOKEN) || +		matchPrefix(url, PREFIX_SECONDLIFE + "/" + APP_TOKEN) || +		matchPrefix(url, PREFIX_SLURL + APP_TOKEN) || +		matchPrefix(url, PREFIX_SLURL_WWW + APP_TOKEN) || +		matchPrefix(url, PREFIX_SLURL_OLD + APP_TOKEN) ) +	{ +		return true; +	} -// create a simstring -LLSLURL::LLSLURL(const std::string& region,  -		 const LLVector3& position) -{ -  *this = LLSLURL(LLGridManager::getInstance()->getGrid(), -		  region, position); +	return false;  } -// create a slurl from a global position -LLSLURL::LLSLURL(const std::string& grid,  -		 const std::string& region,  -		 const LLVector3d& global_position) +// static +bool LLSLURL::isSLURLHelp(const std::string& url)  { -  *this = LLSLURL(grid, -		  region, LLVector3(global_position.mdV[VX], -				    global_position.mdV[VY], -				    global_position.mdV[VZ])); +	return matchPrefix(url, PREFIX_SL_HELP);  } -// create a slurl from a global position -LLSLURL::LLSLURL(const std::string& region,  -		 const LLVector3d& global_position) +// static +std::string LLSLURL::buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z)  { -  *this = LLSLURL(LLGridManager::getInstance()->getGrid(), -		  region, global_position); +	std::string slurl = PREFIX_SLURL + regionname + llformat("/%d/%d/%d",x,y,z);  +	slurl = LLWeb::escapeURL( slurl ); +	return slurl;  } -LLSLURL::LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb) +// static +std::string LLSLURL::buildCommand(const char* noun, const LLUUID& id, const char* verb)  { -  mType = APP; -  mAppCmd = command; -  mAppPath = LLSD::emptyArray(); -  mAppPath.append(LLSD(id)); -  mAppPath.append(LLSD(verb)); +	std::string slurl = llformat("secondlife:///app/%s/%s/%s", +		noun, id.asString().c_str(), verb); +	return slurl;  } - -std::string LLSLURL::getSLURLString() const +// static +std::string LLSLURL::buildUnescapedSLURL(const std::string& regionname, S32 x, S32 y, S32 z)  { -	switch(mType) -	{ -		case HOME_LOCATION: -			return SIM_LOCATION_HOME; -		case LAST_LOCATION: -			return SIM_LOCATION_LAST; -		case LOCATION: -			{ -				// lookup the grid -				S32 x = llround( (F32)mPosition[VX] ); -				S32 y = llround( (F32)mPosition[VY] ); -				S32 z = llround( (F32)mPosition[VZ] );	 -				return LLGridManager::getInstance()->getSLURLBase(mGrid) +  -				LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z);  -			} -		case APP: -		{ -			std::ostringstream app_url; -			app_url << LLGridManager::getInstance()->getAppSLURLBase() << "/" << mAppCmd; -			for(LLSD::array_const_iterator i = mAppPath.beginArray(); -				i != mAppPath.endArray(); -				i++) -			{ -				app_url << "/" << i->asString(); -			} -			if(mAppQuery.length() > 0) -			{ -				app_url << "?" << mAppQuery; -			} -			return app_url.str(); -		}	 -		default: -			LL_WARNS("AppInit") << "Unexpected SLURL type for SLURL string" << (int)mType << LL_ENDL;			 -			return std::string(); -	} +	std::string unescapedslurl = PREFIX_SLURL + regionname + llformat("/%d/%d/%d",x,y,z); +	return unescapedslurl;  } -std::string LLSLURL::getLoginString() const +// static +std::string LLSLURL::buildSLURLfromPosGlobal(const std::string& regionname, +											 const LLVector3d& global_pos, +											 bool escaped /*= true*/)  { -	 -	std::stringstream unescaped_start; -	switch(mType) +	S32 x, y, z; +	globalPosToXYZ(global_pos, x, y, z); +	if(escaped)  	{ -		case LOCATION: -			unescaped_start << "uri:"  -			<< mRegion << "&"  -			<< llround(mPosition[0]) << "&"  -			<< llround(mPosition[1]) << "&"  -			<< llround(mPosition[2]); -			break; -		case HOME_LOCATION: -			unescaped_start << "home"; -			break; -		case LAST_LOCATION: -			unescaped_start << "last"; -			break; -		default: -			LL_WARNS("AppInit") << "Unexpected SLURL type for login string" << (int)mType << LL_ENDL; -			break; +		return buildSLURL(regionname, x, y, z);  	} -	return  xml_escape_string(unescaped_start.str()); -} - -bool LLSLURL::operator==(const LLSLURL& rhs) -{ -	if(rhs.mType != mType) return false; -	switch(mType) +	else  	{ -		case LOCATION: -			return ((mGrid == rhs.mGrid) && -					(mRegion == rhs.mRegion) && -					(mPosition == rhs.mPosition)); -		case APP: -			return getSLURLString() == rhs.getSLURLString(); -			 -		case HOME_LOCATION: -		case LAST_LOCATION: -			return true; -		default: -			return false; +		return buildUnescapedSLURL(regionname, x, y, z);  	}  } -bool LLSLURL::operator !=(const LLSLURL& rhs) +// static +bool LLSLURL::matchPrefix(const std::string& url, const std::string& prefix)  { -	return !(*this == rhs); +	std::string test_prefix = url.substr(0, prefix.length()); +	LLStringUtil::toLower(test_prefix); +	return test_prefix == prefix;  } -std::string LLSLURL::getLocationString() const -{ -	return llformat("%s/%d/%d/%d", -					mRegion.c_str(), -					(int)llround(mPosition[0]), -					(int)llround(mPosition[1]), -					(int)llround(mPosition[2]));						  -} -std::string LLSLURL::asString() const +void LLSLURL::globalPosToXYZ(const LLVector3d& pos, S32& x, S32& y, S32& z)  { -    std::ostringstream result; -    result << "   mAppCmd:"  << getAppCmd() << -              "   mAppPath:" + getAppPath().asString() << -              "   mAppQueryMap:" + getAppQueryMap().asString() << -              "   mAppQuery: " + getAppQuery() << -              "   mGrid: " + getGrid() << -              "   mRegion: " + getRegion() << -              "   mPosition: "  << -              "   mType: " << mType << -              "   mPosition: " << mPosition; -    return result.str(); +	x = llround((F32)fmod(pos.mdV[VX], (F64)REGION_WIDTH_METERS)); +	y = llround((F32)fmod(pos.mdV[VY], (F64)REGION_WIDTH_METERS)); +	z = llround((F32)pos.mdV[VZ]);  } - diff --git a/indra/newview/llslurl.h b/indra/newview/llslurl.h index 28c23561cf..a79a8fc97c 100644 --- a/indra/newview/llslurl.h +++ b/indra/newview/llslurl.h @@ -1,11 +1,10 @@ -/** +/**    * @file llslurl.h - * @brief Handles "SLURL fragments" like Ahern/123/45 for - * startup processing, login screen, prefs, etc. + * @brief SLURL manipulation   * - * $LicenseInfo:firstyear=2010&license=viewergpl$ + * $LicenseInfo:firstyear=2009&license=viewergpl$   *  - * Copyright (c) 2006-2010, Linden Research, Inc. + * Copyright (c) 2009, Linden Research, Inc.   *    * Second Life Viewer Source Code   * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +12,13 @@   * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, @@ -29,84 +29,85 @@   * COMPLETENESS OR PERFORMANCE.   * $/LicenseInfo$   */ -#ifndef LLSLURL_H -#define LLSLURL_H -#include "llstring.h" +#ifndef LL_SLURL_H +#define LL_SLURL_H +#include <string> -// represents a location in a grid +// IAN BUG: where should this live? +// IAN BUG: are static utility functions right?  See LLUUID. +// question of whether to have a LLSLURL object or a  +// some of this was moved from LLURLDispatcher +/** + * SLURL manipulation + */  class LLSLURL  {  public: -	static const char* SLURL_HTTPS_SCHEME; -	static const char* SLURL_HTTP_SCHEME; -	static const char* SLURL_SL_SCHEME; -	static const char* SLURL_SECONDLIFE_SCHEME; -	static const char* SLURL_SECONDLIFE_PATH; -	static const char* SLURL_COM; -	static const char* WWW_SLURL_COM; -	static const char* MAPS_SECONDLIFE_COM; -	static const char* SLURL_X_GRID_LOCATION_INFO_SCHEME; -	static LLSLURL START_LOCATION; -	static const char* SIM_LOCATION_HOME; -	static const char* SIM_LOCATION_LAST; -	static const char* SLURL_APP_PATH; -	static const char* SLURL_REGION_PATH;	 -	 -	enum SLURL_TYPE {  -		INVALID,  -		LOCATION, -		HOME_LOCATION, -		LAST_LOCATION, -		APP, -		HELP  -	}; -		 -	 -	LLSLURL(): mType(LAST_LOCATION)  { } -	LLSLURL(const std::string& slurl); -	LLSLURL(const std::string& grid, const std::string& region); -	LLSLURL(const std::string& region, const LLVector3& position); -	LLSLURL(const std::string& grid, const std::string& region, const LLVector3& position); -	LLSLURL(const std::string& grid, const std::string& region, const LLVector3d& global_position); -	LLSLURL(const std::string& region, const LLVector3d& global_position); -	LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb); -	 -	SLURL_TYPE getType() const { return mType; } -	 -	std::string getSLURLString() const; -	std::string getLoginString() const; -	std::string getLocationString() const;  -	std::string getGrid() const { return mGrid; } -	std::string getRegion() const { return mRegion; } -	LLVector3   getPosition() const { return mPosition; } -	std::string getAppCmd() const { return mAppCmd; } -	std::string getAppQuery() const { return mAppQuery; } -	LLSD        getAppQueryMap() const { return mAppQueryMap; } -	LLSD        getAppPath() const { return mAppPath; } -	 -	bool        isValid() const { return mType != INVALID; } -	bool        isSpatial() const { return (mType == LAST_LOCATION) || (mType == HOME_LOCATION) || (mType == LOCATION); } -	 -	bool operator==(const LLSLURL& rhs); -	bool operator!=(const LLSLURL&rhs); - -    std::string asString() const ; - -protected: -	SLURL_TYPE mType; -	 -	// used for Apps and Help -	std::string mAppCmd; -	LLSD        mAppPath; -	LLSD        mAppQueryMap; -	std::string mAppQuery; -	 -	std::string mGrid;  // reference to grid manager grid -	std::string mRegion; -	LLVector3  mPosition; +	static const std::string PREFIX_SL_HELP; +	static const std::string PREFIX_SL; +	static const std::string PREFIX_SECONDLIFE; +	static const std::string PREFIX_SLURL; +	static const std::string PREFIX_SLURL_OLD; +	static const std::string PREFIX_SLURL_WWW; + +	static const std::string APP_TOKEN; + +	/** +	 * Is this any sort of secondlife:// or sl:// URL? +	 */ +	static bool isSLURL(const std::string& url); + +	/** +	 * Returns true if url is proven valid by regexp check from LLUrlRegistry +	 */ +	static bool isValidSLURL(const std::string& url); + +	/** +	 * Is this a special secondlife://app/ URL? +	 */ +	static bool isSLURLCommand(const std::string& url); + +	/** +	 * Not sure what it is. +	 */ +	static bool isSLURLHelp(const std::string& url); + +	/** +	 * builds: http://slurl.com/secondlife/Region%20Name/x/y/z/ escaping result url. +	 */ +	static std::string buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z); + +	/// Build a SLURL like secondlife:///app/agent/<uuid>/inspect +	static std::string buildCommand(const char* noun, const LLUUID& id, const char* verb); + +	/** +	 * builds: http://slurl.com/secondlife/Region Name/x/y/z/ without escaping result url. +	 */ +	static std::string buildUnescapedSLURL(const std::string& regionname, S32 x, S32 y, S32 z); + +	/** +	 * builds SLURL from global position. Returns escaped or unescaped url. +	 * Returns escaped url by default. +	 */ +	static std::string buildSLURLfromPosGlobal(const std::string& regionname, +											   const LLVector3d& global_pos, +											   bool escaped = true); +	/** +	 * Strip protocol part from the URL. +	 */ +	static std::string stripProtocol(const std::string& url); + +	/** +	 * Convert global position to X, Y Z +	 */ +	static void globalPosToXYZ(const LLVector3d& pos, S32& x, S32& y, S32& z); + +private: +	static bool matchPrefix(const std::string& url, const std::string& prefix); +  }; -#endif // LLSLURL_H +#endif diff --git a/indra/newview/llspeakbutton.cpp b/indra/newview/llspeakbutton.cpp index d7de050636..c5c311ed33 100644 --- a/indra/newview/llspeakbutton.cpp +++ b/indra/newview/llspeakbutton.cpp @@ -59,9 +59,9 @@ LLSpeakButton::Params::Params()  void LLSpeakButton::draw()  { -	// LLVoiceClient::getInstance() is the authoritative global source of info regarding our open-mic state, we merely reflect that state. -	bool openmic = LLVoiceClient::getInstance()->getUserPTTState(); -	bool voiceenabled = LLVoiceClient::getInstance()->voiceEnabled(); +	// gVoiceClient is the authoritative global source of info regarding our open-mic state, we merely reflect that state. +	bool openmic = gVoiceClient->getUserPTTState(); +	bool voiceenabled = gVoiceClient->voiceEnabled();  	mSpeakBtn->setToggleState(openmic && voiceenabled);  	mOutputMonitor->setIsMuted(!voiceenabled);  	LLUICtrl::draw(); @@ -176,11 +176,11 @@ void LLSpeakButton::setLabelVisible(bool visible)  void LLSpeakButton::onMouseDown_SpeakBtn()  {  	bool down = true; -	LLVoiceClient::getInstance()->inputUserControlState(down); // this method knows/care about whether this translates into a toggle-to-talk or down-to-talk +	gVoiceClient->inputUserControlState(down); // this method knows/care about whether this translates into a toggle-to-talk or down-to-talk  }  void LLSpeakButton::onMouseUp_SpeakBtn()  {  	bool down = false; -	LLVoiceClient::getInstance()->inputUserControlState(down); +	gVoiceClient->inputUserControlState(down);  } diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index b9534fac9a..4573520647 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -299,7 +299,7 @@ LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::strin  void LLSpeakerMgr::update(BOOL resort_ok)  { -	if (!LLVoiceClient::getInstance()) +	if (!gVoiceClient)  	{  		return;  	} @@ -313,7 +313,7 @@ void LLSpeakerMgr::update(BOOL resort_ok)  	}  	// update status of all current speakers -	BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); +	BOOL voice_channel_active = (!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());  	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)  	{  		LLUUID speaker_id = speaker_it->first; @@ -321,21 +321,21 @@ void LLSpeakerMgr::update(BOOL resort_ok)  		speaker_map_t::iterator  cur_speaker_it = speaker_it++; -		if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) +		if (voice_channel_active && gVoiceClient->getVoiceEnabled(speaker_id))  		{ -			speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id); -			BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id); +			speakerp->mSpeechVolume = gVoiceClient->getCurrentPower(speaker_id); +			BOOL moderator_muted_voice = gVoiceClient->getIsModeratorMuted(speaker_id);  			if (moderator_muted_voice != speakerp->mModeratorMutedVoice)  			{  				speakerp->mModeratorMutedVoice = moderator_muted_voice;  				speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp));  			} -			if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) +			if (gVoiceClient->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice)  			{  				speakerp->mStatus = LLSpeaker::STATUS_MUTED;  			} -			else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id)) +			else if (gVoiceClient->getIsSpeaking(speaker_id))  			{  				// reset inactivity expiration  				if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) @@ -417,21 +417,19 @@ void LLSpeakerMgr::update(BOOL resort_ok)  void LLSpeakerMgr::updateSpeakerList()  {  	// are we bound to the currently active voice channel? -	if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) -	{ -	        std::set<LLUUID> participants; -	        LLVoiceClient::getInstance()->getParticipantList(participants); -		// add new participants to our list of known speakers -		for (std::set<LLUUID>::iterator participant_it = participants.begin(); -			 participant_it != participants.end();  -			 ++participant_it) +	if ((!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) +	{ +		LLVoiceClient::participantMap* participants = gVoiceClient->getParticipantList(); +		if(participants)  		{ -				setSpeaker(*participant_it,  -						   LLVoiceClient::getInstance()->getDisplayName(*participant_it), -						   LLSpeaker::STATUS_VOICE_ACTIVE,  -						   (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); - +			LLVoiceClient::participantMap::iterator participant_it; +			// add new participants to our list of known speakers +			for (participant_it = participants->begin(); participant_it != participants->end(); ++participant_it) +			{ +				LLVoiceClient::participantState* participantp = participant_it->second; +				setSpeaker(participantp->mAvatarID, participantp->mDisplayName, LLSpeaker::STATUS_VOICE_ACTIVE, (participantp->isAvatar()?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); +			}  		}  	}  } @@ -521,7 +519,7 @@ void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)  BOOL LLSpeakerMgr::isVoiceActive()  {  	// mVoiceChannel = NULL means current voice channel, whatever it is -	return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); +	return LLVoiceClient::voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();  } diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp index 29237946d2..cc06179481 100644 --- a/indra/newview/llspeakingindicatormanager.cpp +++ b/indra/newview/llspeakingindicatormanager.cpp @@ -158,7 +158,7 @@ void SpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker_i  	mSpeakingIndicators.insert(value_type);  	speaker_ids_t speakers_uuids; -	BOOL is_in_same_voice = LLVoiceClient::getInstance()->isParticipant(speaker_id); +	BOOL is_in_same_voice = LLVoiceClient::getInstance()->findParticipantByID(speaker_id) != NULL;  	speakers_uuids.insert(speaker_id);  	switchSpeakerIndicators(speakers_uuids, is_in_same_voice); @@ -210,7 +210,7 @@ void SpeakingIndicatorManager::onChange()  	LL_DEBUGS("SpeakingIndicator") << "Voice participant list was changed, updating indicators" << LL_ENDL;  	speaker_ids_t speakers_uuids; -	LLVoiceClient::getInstance()->getParticipantList(speakers_uuids); +	LLVoiceClient::getInstance()->getParticipantsUUIDSet(speakers_uuids);  	LL_DEBUGS("SpeakingIndicator") << "Switching all OFF, count: " << mSwitchedIndicatorsOn.size() << LL_ENDL;  	// switch all indicators off diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index d7c8b5fcd4..94a32873ec 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -147,7 +147,7 @@  #include "lltrans.h"  #include "llui.h"  #include "llurldispatcher.h" -#include "llslurl.h" +#include "llurlsimstring.h"  #include "llurlhistory.h"  #include "llurlwhitelist.h"  #include "llvieweraudio.h" @@ -192,7 +192,6 @@  #include "llinventorybridge.h"  #include "llappearancemgr.h"  #include "llavatariconctrl.h" -#include "llvoicechannel.h"  #include "lllogin.h"  #include "llevents.h" @@ -229,11 +228,11 @@ static std::string sInitialOutfitGender;	// "male" or "female"  static bool gUseCircuitCallbackCalled = false;  EStartupState LLStartUp::gStartupState = STATE_FIRST; -LLSLURL LLStartUp::sStartSLURL; -static LLPointer<LLCredential> gUserCredential; -static std::string gDisplayName; -static BOOL gRememberPassword = TRUE;      +// *NOTE:Mani - to reconcile with giab changes... +static std::string gFirstname; +static std::string gLastname; +static std::string gPassword;  static U64 gFirstSimHandle = 0;  static LLHost gFirstSim; @@ -250,6 +249,7 @@ 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); @@ -262,9 +262,6 @@ bool callback_choose_gender(const LLSD& notification, const LLSD& response);  void init_start_screen(S32 location_id);  void release_start_screen();  void reset_login(); -LLSD transform_cert_args(LLPointer<LLCertificate> cert); -void general_cert_done(const LLSD& notification, const LLSD& response); -void trust_cert_done(const LLSD& notification, const LLSD& response);  void apply_udp_blacklist(const std::string& csv);  bool process_login_success_response();  void transition_back_to_login_panel(const std::string& emsg); @@ -367,7 +364,7 @@ bool idle_startup()  	if ( STATE_FIRST == LLStartUp::getStartupState() )  	{ -		gViewerWindow->showCursor();  +		gViewerWindow->showCursor();  		gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);  		///////////////////////////////////////////////// @@ -665,25 +662,69 @@ bool idle_startup()  		//  		// Log on to system  		// -		if (gUserCredential.isNull()) -		{ -			gUserCredential = gLoginHandler.initializeLoginInfo(); -		} -		if (gUserCredential.isNull()) -		{ -			show_connect_box = TRUE; -		} -		else if (gSavedSettings.getBOOL("AutoLogin"))   -		{ -			gRememberPassword = TRUE; -			gSavedSettings.setBOOL("RememberPassword", TRUE);                                                       -			show_connect_box = false;    			 +		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  		} -		else  +		else  		{ -			gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); -			show_connect_box = TRUE; +			// 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;  		} + +  		// Go to the next startup state  		LLStartUp::setStartupState( STATE_BROWSER_INIT );  		return FALSE; @@ -715,10 +756,8 @@ 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.   -			if (gUserCredential.isNull())                                                                           -			{                                                                                                       -				gUserCredential = gLoginHandler.initializeLoginInfo();                  -			}      +			// LLPanelLogin::getFields(gFirstname, gLastname, gPassword); +  			if (gNoRender)  			{  				LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL; @@ -729,10 +768,8 @@ bool idle_startup()  			// Show the login dialog  			login_show();  			// connect dialog is already shown, so fill in the names -			if (gUserCredential.notNull())                                                                          -			{                                                                                                       -				LLPanelLogin::setFields( gUserCredential, gRememberPassword);                                   -			}      +			LLPanelLogin::setFields( gFirstname, gLastname, gPassword); +  			LLPanelLogin::giveFocus();  			gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); @@ -802,36 +839,39 @@ 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(gUserCredential, gRememberPassword);  +			LLPanelLogin::getFields(&gFirstname, &gLastname, &gPassword);  			// end TODO  			// HACK: Try to make not jump on login  			gKeyboard->resetKeys();  		} -		// save the credentials                                                                                         -		std::string userid = "unknown";                                                                                 -		if(gUserCredential.notNull())                                                                                   -		{   -			userid = gUserCredential->userID();                                                                     -			gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword);   +		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;	  		} -		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(userid); +		gDirUtilp->setLindenUserDir(gFirstname, gLastname);  		LLFile::mkdir(gDirUtilp->getLindenUserDir()); - +		  		// Set PerAccountSettingsFile to the default value. -		std::string per_account_settings_file = LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount");  		gSavedSettings.setString("PerAccountSettingsFile",  			gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,   				LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount"))); @@ -861,8 +901,9 @@ bool idle_startup()  		{  			gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));		  		} -		gDirUtilp->setPerAccountChatLogsDir(userid);   +		gDirUtilp->setPerAccountChatLogsDir(gFirstname, gLastname); +  		LLFile::mkdir(gDirUtilp->getChatLogsDir());  		LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); @@ -883,7 +924,11 @@ bool idle_startup()  		if (show_connect_box)  		{ -			LLSLURL slurl; +			std::string location; +			LLPanelLogin::getLocation( location ); +			LLURLSimString::setString( location ); + +			// END TODO  			LLPanelLogin::closePanel();  		} @@ -907,21 +952,26 @@ bool idle_startup()  		// their last location, or some URL "-url //sim/x/y[/z]"  		// All accounts have both a home and a last location, and we don't support  		// more locations than that.  Choose the appropriate one.  JC -		switch (LLStartUp::getStartSLURL().getType()) -		  { -		  case LLSLURL::LOCATION: -		    agent_location_id = START_LOCATION_ID_URL; -		    location_which = START_LOCATION_ID_LAST; -		    break; -		  case LLSLURL::LAST_LOCATION: -		    agent_location_id = START_LOCATION_ID_LAST; -		    location_which = START_LOCATION_ID_LAST; -		    break; -		  default: -		    agent_location_id = START_LOCATION_ID_HOME; -		    location_which = START_LOCATION_ID_HOME; -		    break; -		  } +		if (LLURLSimString::parse()) +		{ +			// a startup URL was specified +			agent_location_id = START_LOCATION_ID_URL; + +			// doesn't really matter what location_which is, since +			// gAgentStartLookAt will be overwritten when the +			// UserLoginLocationReply arrives +			location_which = START_LOCATION_ID_LAST; +		} +		else if (gSavedSettings.getString("LoginLocation") == "last" ) +		{ +			agent_location_id = START_LOCATION_ID_LAST;	// last location +			location_which = START_LOCATION_ID_LAST; +		} +		else +		{ +			agent_location_id = START_LOCATION_ID_HOME;	// home +			location_which = START_LOCATION_ID_HOME; +		}  		gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); @@ -948,7 +998,7 @@ bool idle_startup()  	if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())  	{ -		gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel(); +		gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();  		// Update progress status and the display loop.  		auth_desc = LLTrans::getString("LoginInProgress"); @@ -972,7 +1022,11 @@ bool idle_startup()  		// This call to LLLoginInstance::connect() starts the   		// authentication process. -		login->connect(gUserCredential); +		LLSD credentials; +		credentials["first"] = gFirstname; +		credentials["last"] = gLastname; +		credentials["passwd"] = gPassword; +		login->connect(credentials);  		LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK );  		return FALSE; @@ -997,11 +1051,10 @@ bool idle_startup()  		{  			LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): "  			                      << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; -			LLSD response = LLLoginInstance::getInstance()->getResponse();  			// Still have error conditions that may need some   			// sort of handling. -			std::string reason_response = response["reason"]; -			std::string message_response = response["message"]; +			std::string reason_response = LLLoginInstance::getInstance()->getResponse("reason"); +			std::string message_response = LLLoginInstance::getInstance()->getResponse("message");  			if(!message_response.empty())  			{ @@ -1021,8 +1074,8 @@ bool idle_startup()  			if(reason_response == "key")  			{  				// Couldn't login because user/password is wrong -				// Clear the credential -				gUserCredential->clearAuthenticator(); +				// Clear the password +				gPassword = "";  			}  			if(reason_response == "update"  @@ -1035,65 +1088,18 @@ bool idle_startup()  				LLLoginInstance::getInstance()->disconnect();  				LLAppViewer::instance()->forceQuit();  			} -			else  +			else  			{ -				if (reason_response != "tos")  +				// Don't pop up a notification in the TOS case because +				// LLFloaterTOS::onCancel() already scolded the user. +				if (reason_response != "tos")  				{ -					// Don't pop up a notification in the TOS case because -					// LLFloaterTOS::onCancel() already scolded the user. -					std::string error_code; -					if(response.has("errorcode")) -					{ -						error_code = response["errorcode"].asString(); -					} -					if ((reason_response == "CURLError") &&  -						(error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") &&  -						response.has("certificate")) -					{ -						// This was a certificate error, so grab the certificate -						// and throw up the appropriate dialog. -						LLPointer<LLCertificate> certificate = gSecAPIHandler->getCertificate(response["certificate"]); -						if(certificate) -						{ -							LLSD args = transform_cert_args(certificate); - -							if(error_code == "SSL_CACERT") -							{ -								// if we are handling an untrusted CA, throw up the dialog                              -								// with the 'trust this CA' button.                                                     -								LLNotificationsUtil::add("TrustCertificateError", args, response, -														trust_cert_done); -								 -								show_connect_box = true; -							} -							else -							{ -								// the certificate exception returns a unique string for each type of exception.        -								// we grab this string via the LLUserAuth object, and use that to grab the localized    -								// string.                                                                              -								args["REASON"] = LLTrans::getString(message_response); -								 -								LLNotificationsUtil::add("GeneralCertificateError", args, response, -														 general_cert_done); -								 -								reset_login(); -								gSavedSettings.setBOOL("AutoLogin", FALSE); -								show_connect_box = true; -								 -							} - -						} -					} -					else  -					{ -						// This wasn't a certificate error, so throw up the normal -						// notificatioin message. -						LLSD args; -						args["ERROR_MESSAGE"] = emsg.str(); -						LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; -						LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); -					} +					LLSD args; +					args["ERROR_MESSAGE"] = emsg.str(); +					LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; +					LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);  				} +  				//setup map of datetime strings to codes and slt & local time offset from utc  				// *TODO: Does this need to be here?  				LLStringOps::setupDatetimeInfo (false); @@ -1106,12 +1112,7 @@ bool idle_startup()  			if(process_login_success_response())  			{  				// Pass the user information to the voice chat server interface. -				LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); -				// create the default proximal channel -				LLVoiceChannel::initClass(); -				// update the voice settings -				LLVoiceClient::getInstance()->updateSettings(); -				LLGridManager::getInstance()->setFavorite();  +				gVoiceClient->userAuthorized(gFirstname, gLastname, gAgentID);  				LLStartUp::setStartupState( STATE_WORLD_INIT);  			}  			else @@ -1122,7 +1123,6 @@ bool idle_startup()  				LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);  				transition_back_to_login_panel(emsg.str());  				show_connect_box = true; -				return FALSE;  			}  		}  		return FALSE; @@ -1807,12 +1807,9 @@ bool idle_startup()  		// thus, do not show this alert.  		if (!gAgent.isFirstLogin())  		{ -			llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl; -			LLSLURL start_slurl = LLStartUp::getStartSLURL(); -			 -			if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) || -				((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) || -				((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home"))) +			bool url_ok = LLURLSimString::sInstance.parse(); +			if ((url_ok && gAgentStartLocation == "url") || +				(!url_ok && ((gAgentStartLocation == gSavedSettings.getString("LoginLocation")))))  			{  				// Start location is OK  				// Disabled code to restore camera location and focus if logging in to default location @@ -1834,23 +1831,17 @@ bool idle_startup()  			else  			{  				std::string msg; -				switch(start_slurl.getType()) +				if (url_ok)  				{ -					case LLSLURL::LOCATION: -					{ -						 -						msg = "AvatarMovedDesired"; -						break; -					} -					case LLSLURL::HOME_LOCATION: -					{ -						msg = "AvatarMovedHome"; -						break; -					} -					default: -					{ -						msg = "AvatarMovedLast"; -					} +					msg = "AvatarMovedDesired"; +				} +				else if (gSavedSettings.getString("LoginLocation") == "home") +				{ +					msg = "AvatarMovedHome"; +				} +				else +				{ +					msg = "AvatarMovedLast";  				}  				LLNotificationsUtil::add(msg);  			} @@ -2066,9 +2057,20 @@ void login_show()  #endif  	LLPanelLogin::show(	gViewerWindow->getWindowRectScaled(), -						bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"), +						bUseDebugLogin,  						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. @@ -2084,6 +2086,9 @@ 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 @@ -2106,6 +2111,142 @@ 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); @@ -2147,7 +2288,7 @@ bool login_alert_status(const LLSD& notification, const LLSD& response)        //      break;          case 2:     // Teleport              // Restart the login process, starting at our home locaton -	  LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); +            LLURLSimString::setString("home");              LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );              break;          default: @@ -2367,35 +2508,30 @@ void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S3  const std::string COMMON_GESTURES_FOLDER = "Common Gestures";  const std::string MALE_GESTURES_FOLDER = "Male Gestures";  const std::string FEMALE_GESTURES_FOLDER = "Female Gestures"; +const std::string MALE_OUTFIT_FOLDER = "Male Shape & Outfit"; +const std::string FEMALE_OUTFIT_FOLDER = "Female Shape & Outfit";  const S32 OPT_CLOSED_WINDOW = -1;  const S32 OPT_MALE = 0;  const S32 OPT_FEMALE = 1; -const S32 OPT_TRUST_CERT = 0; -const S32 OPT_CANCEL_TRUST = 1; -	 +  bool callback_choose_gender(const LLSD& notification, const LLSD& response) -{ -	 -    // These defaults are returned from the server on login.  They are set in login.xml.                   -    // If no default is returned from the server, they are retrieved from settings.xml.                    -	 -	S32 option = LLNotification::getSelectedOption(notification, response); +{	 +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);  	switch(option)  	{ -		case OPT_MALE: -			LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); -			break; -			 -        case OPT_FEMALE: -        case OPT_CLOSED_WINDOW: -        default: -			LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); -			break; +	case OPT_MALE: +		LLStartUp::loadInitialOutfit( MALE_OUTFIT_FOLDER, "male" ); +		break; + +	case OPT_FEMALE: +	case OPT_CLOSED_WINDOW: +	default: +		LLStartUp::loadInitialOutfit( FEMALE_OUTFIT_FOLDER, "female" ); +		break;  	}  	return false;  } -  void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,  								   const std::string& gender_name )  { @@ -2610,6 +2746,7 @@ void reset_login()  //--------------------------------------------------------------------------- +std::string LLStartUp::sSLURLCommand;  bool LLStartUp::canGoFullscreen()  { @@ -2642,145 +2779,41 @@ void LLStartUp::fontInit()  bool LLStartUp::dispatchURL()  {  	// ok, if we've gotten this far and have a startup URL -        if (!getStartSLURL().isValid()) +	if (!sSLURLCommand.empty())  	{ -	  return false; +		LLMediaCtrl* web = NULL; +		const bool trusted_browser = false; +		LLURLDispatcher::dispatch(sSLURLCommand, web, trusted_browser);  	} -        if(getStartSLURL().getType() != LLSLURL::APP) -	  { -	     +	else if (LLURLSimString::parse()) +	{  		// If we started with a location, but we're already  		// at that location, don't pop dialogs open.  		LLVector3 pos = gAgent.getPositionAgent(); -		LLVector3 slurlpos = getStartSLURL().getPosition(); -		F32 dx = pos.mV[VX] - slurlpos.mV[VX]; -		F32 dy = pos.mV[VY] - slurlpos.mV[VY]; +		F32 dx = pos.mV[VX] - (F32)LLURLSimString::sInstance.mX; +		F32 dy = pos.mV[VY] - (F32)LLURLSimString::sInstance.mY;  		const F32 SLOP = 2.f;	// meters -		if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() +		if( LLURLSimString::sInstance.mSimName != gAgent.getRegion()->getName()  			|| (dx*dx > SLOP*SLOP)  			|| (dy*dy > SLOP*SLOP) )  		{ -			LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(),  -						  NULL, false); +			std::string url = LLURLSimString::getURL(); +			LLMediaCtrl* web = NULL; +			const bool trusted_browser = false; +			LLURLDispatcher::dispatch(url, web, trusted_browser);  		}  		return true;  	}  	return false;  } -void LLStartUp::setStartSLURL(const LLSLURL& slurl)  -{ -  sStartSLURL = slurl; -  switch(slurl.getType()) -    { -    case LLSLURL::HOME_LOCATION: -      { -		  gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME); -	break; -      } -    case LLSLURL::LAST_LOCATION: -      { -	gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST); -	break; -      } -    default: -			LLGridManager::getInstance()->setGridChoice(slurl.getGrid()); -			break; -    } -} -  bool login_alert_done(const LLSD& notification, const LLSD& response)  {  	LLPanelLogin::giveFocus();  	return false;  } -// parse the certificate information into args for the  -// certificate notifications -LLSD transform_cert_args(LLPointer<LLCertificate> cert) -{ -	LLSD args = LLSD::emptyMap(); -	std::string value; -	LLSD cert_info = cert->getLLSD(); -	// convert all of the elements in the cert into                                         -	// args for the xml dialog, so we have flexability to                                   -	// display various parts of the cert by only modifying                                  -	// the cert alert dialog xml.                                                           -	for(LLSD::map_iterator iter = cert_info.beginMap(); -		iter != cert_info.endMap(); -		iter++) -	{ -		// key usage and extended key usage                                             -		// are actually arrays, and we want to format them as comma separated           -		// strings, so special case those.                                              -		LLSDSerialize::toXML(cert_info[iter->first], std::cout); -		if((iter->first== std::string(CERT_KEY_USAGE)) | -		   (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) -		{ -			value = ""; -			LLSD usage = cert_info[iter->first]; -			for (LLSD::array_iterator usage_iter = usage.beginArray(); -				 usage_iter != usage.endArray(); -				 usage_iter++) -			{ -				 -				if(usage_iter != usage.beginArray()) -				{ -					value += ", "; -				} -				 -				value += (*usage_iter).asString(); -			} -			 -		} -		else -		{ -			value = iter->second.asString(); -		} -		 -		std::string name = iter->first; -		std::transform(name.begin(), name.end(), name.begin(), -					   (int(*)(int))toupper); -		args[name.c_str()] = value; -	} -	return args; -} - - -// when we handle a cert error, give focus back to the login panel -void general_cert_done(const LLSD& notification, const LLSD& response) -{ -	LLStartUp::setStartupState( STATE_LOGIN_SHOW );			 -	LLPanelLogin::giveFocus(); -} - -// check to see if the user wants to trust the cert. -// if they do, add it to the cert store and  -void trust_cert_done(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotification::getSelectedOption(notification, response);	 -	switch(option) -	{ -		case OPT_TRUST_CERT: -		{ -			LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); -			LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore"));			 -			store->add(cert); -			store->save(); -			LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );	 -			break; -		} -		case OPT_CANCEL_TRUST: -			reset_login(); -			gSavedSettings.setBOOL("AutoLogin", FALSE);			 -			LLStartUp::setStartupState( STATE_LOGIN_SHOW );				 -		default: -			LLPanelLogin::giveFocus(); -			break; -	} - -}  void apply_udp_blacklist(const std::string& csv)  { @@ -2828,45 +2861,33 @@ bool process_login_success_response()  	text = response["secure_session_id"].asString();  	if(!text.empty()) gAgent.mSecureSessionID.set(text); -	// 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")) +	text = response["first_name"].asString(); +	if(!text.empty())   	{ -		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); -		} +		// 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);  	} -	if(gDisplayName.empty()) +	text = response["last_name"].asString(); +	if(!text.empty())   	{ -		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; -		} +		gLastname.assign(text);  	} -	if(gDisplayName.empty()) +	gSavedSettings.setString("FirstName", gFirstname); +	gSavedSettings.setString("LastName", gLastname); + +	if (gSavedSettings.getBOOL("RememberPassword"))  	{ -		gDisplayName.assign(gUserCredential->asString()); +		// Successful login means the password is valid, so save it. +		LLStartUp::savePasswordToDisk(gPassword); +	} +	else +	{ +		// Don't leave password from previous session sitting around +		// during this login session. +		LLStartUp::deletePasswordFromDisk();  	}  	// this is their actual ability to access content @@ -2960,7 +2981,7 @@ bool process_login_success_response()  		// replace the default help URL format  		gSavedSettings.setString("HelpURLFormat",text); -		// don't fall back to Standalone's pre-connection static help +		// don't fall back to Nebraska's pre-connection static help  		gSavedSettings.setBOOL("HelpUseLocal", false);  	} @@ -3022,44 +3043,7 @@ bool process_login_success_response()  		//setup map of datetime strings to codes and slt & local time offset from utc  		LLStringOps::setupDatetimeInfo(pacific_daylight_time);  	} -	 -	static const char* CONFIG_OPTIONS[] = {"voice-config", "newuser-config"}; -	for (int i = 0; i < sizeof(CONFIG_OPTIONS)/sizeof(CONFIG_OPTIONS[0]); i++) -	{ -		LLSD options = response[CONFIG_OPTIONS[i]]; -		if (!options.isArray() && (options.size() < 1) && !options[0].isMap()) -		{ -			continue; -		} -		llinfos << "config option " << CONFIG_OPTIONS[i][0] << "response " << options << llendl; -		for(LLSD::map_iterator option_it = options[0].beginMap(); -			option_it != options[0].endMap(); -			option_it++) -		{ -			llinfos << "trying option " << option_it->first << llendl; -			LLPointer<LLControlVariable> control = gSavedSettings.getControl(option_it->first); -			if(control.notNull()) -			{ -				if(control->isType(TYPE_BOOLEAN)) -				{ -					llinfos << "Setting BOOL from login " << option_it->first << " " << option_it->second << llendl; -					 -					gSavedSettings.setBOOL(option_it->first, !((option_it->second == "F") || -															   (option_it->second == "false") || -															   (!option_it->second))); -				} -				else if (control->isType(TYPE_STRING)) -				{ -					llinfos << "Setting String from login " << option_it->first << " " << option_it->second << llendl; -					gSavedSettings.setString(option_it->first, option_it->second); -				} -				// we don't support other types now                                                                                                             -				 -			} -			 -		} -	} -	 +  	LLSD initial_outfit = response["initial-outfit"][0];  	if(initial_outfit.size())  	{ @@ -3113,7 +3097,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 gUserCredentials until then. +	// in place.  Don't delete/clear user_credentials until then.  	if(gAgentID.notNull()  	   && gAgentSessionID.notNull()  	   && gMessageSystem->mOurCircuitCode diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index 16cc74504f..92fe9521d3 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -38,7 +38,6 @@  class LLViewerTexture ;  class LLEventPump;  class LLStartupListener; -class LLSLURL;  // functions  bool idle_startup(); @@ -102,18 +101,26 @@ 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  		// the viewer, dispatch it +	static std::string sSLURLCommand; +		// *HACK: On startup, if we were passed a secondlife://app/do/foo +		// command URL, store it for later processing. +  	static void postStartupState(); -	static void setStartSLURL(const LLSLURL& slurl);  -	static LLSLURL& getStartSLURL() { return sStartSLURL; }   private: -	static LLSLURL sStartSLURL; -  	static std::string startupStateToString(EStartupState state);  	static EStartupState gStartupState; // Do not set directly, use LLStartup::setStartupState  	static boost::scoped_ptr<LLEventPump> sStateWatcher; diff --git a/indra/newview/llstylemap.cpp b/indra/newview/llstylemap.cpp index 8fab3bb361..61705c4eb3 100644 --- a/indra/newview/llstylemap.cpp +++ b/indra/newview/llstylemap.cpp @@ -51,7 +51,7 @@ const LLStyle::Params &LLStyleMap::lookupAgent(const LLUUID &source)  			style_params.color.control = "HTMLLinkColor";  			style_params.readonly_color.control = "HTMLLinkColor";  			style_params.link_href =  -					LLSLURL("agent", source, "inspect").getSLURLString(); +					LLSLURL::buildCommand("agent", source, "inspect");  		}  		else  		{ diff --git a/indra/newview/llurl.cpp b/indra/newview/llurl.cpp index 83a5839a93..ab65ead4c5 100644 --- a/indra/newview/llurl.cpp +++ b/indra/newview/llurl.cpp @@ -286,11 +286,5 @@ const char * LLURL::getFullPath()  	return(sReturnString);  } -const char * LLURL::getAuthority() -{ -	strncpy(LLURL::sReturnString,mAuthority, LL_MAX_PATH -1);               /* Flawfinder: ignore */ -	LLURL::sReturnString[LL_MAX_PATH -1] = '\0'; -	return(sReturnString); -}  char LLURL::sReturnString[LL_MAX_PATH] = ""; diff --git a/indra/newview/llurl.h b/indra/newview/llurl.h index e41b83d29f..9a089dd835 100644 --- a/indra/newview/llurl.h +++ b/indra/newview/llurl.h @@ -79,7 +79,6 @@ public:  	virtual const char *getFQURL() const;  	virtual const char *getFullPath(); -	virtual const char *getAuthority();  	virtual const char *updateRelativePath(const LLURL &url); diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index a31c3a0f1b..b88069cd48 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2007&license=viewergpl$   *  - * Copyright (c) 2010, Linden Research, Inc. + * Copyright (c) 2007-2009, Linden Research, Inc.   *    * Second Life Viewer Source Code   * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@   * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, @@ -44,10 +45,10 @@  #include "llsidetray.h"  #include "llslurl.h"  #include "llstartup.h"			// gStartupState +#include "llurlsimstring.h"  #include "llweb.h"  #include "llworldmapmessage.h"  #include "llurldispatcherlistener.h" -#include "llviewernetwork.h"  // library includes  #include "llnotificationsutil.h" @@ -58,25 +59,25 @@ static LLURLDispatcherListener sURLDispatcherListener;  class LLURLDispatcherImpl  {  public: -	static bool dispatch(const LLSLURL& slurl, +	static bool dispatch(const std::string& url,  						 LLMediaCtrl* web,  						 bool trusted_browser);  		// returns true if handled or explicitly blocked. -	static bool dispatchRightClick(const LLSLURL& slurl); +	static bool dispatchRightClick(const std::string& url);  private: -	static bool dispatchCore(const LLSLURL& slurl,  +	static bool dispatchCore(const std::string& url,   							 bool right_mouse,  							 LLMediaCtrl* web,  							 bool trusted_browser);  		// handles both left and right click -	static bool dispatchHelp(const LLSLURL& slurl, bool right_mouse); +	static bool dispatchHelp(const std::string& url, bool right_mouse);  		// Handles sl://app.floater.html.help by showing Help floater.  		// Returns true if handled. -	static bool dispatchApp(const LLSLURL& slurl, +	static bool dispatchApp(const std::string& url,  							bool right_mouse,  							LLMediaCtrl* web,  							bool trusted_browser); @@ -84,16 +85,16 @@ private:  		// by showing panel in Search floater.  		// Returns true if handled or explicitly blocked. -	static bool dispatchRegion(const LLSLURL& slurl, bool right_mouse); +	static bool dispatchRegion(const std::string& url, bool right_mouse);  		// handles secondlife://Ahern/123/45/67/  		// Returns true if handled. -	static void regionHandleCallback(U64 handle, const LLSLURL& slurl, +	static void regionHandleCallback(U64 handle, const std::string& url,  		const LLUUID& snapshot_id, bool teleport);  		// Called by LLWorldMap when a location has been resolved to a  	    // region name -	static void regionNameCallback(U64 handle, const LLSLURL& slurl, +	static void regionNameCallback(U64 handle, const std::string& url,  		const LLUUID& snapshot_id, bool teleport);  		// Called by LLWorldMap when a region name has been resolved to a  		// location in-world, used by places-panel display. @@ -102,57 +103,65 @@ private:  };  // static -bool LLURLDispatcherImpl::dispatchCore(const LLSLURL& slurl, +bool LLURLDispatcherImpl::dispatchCore(const std::string& url,  									   bool right_mouse,  									   LLMediaCtrl* web,  									   bool trusted_browser)  { -	//if (dispatchHelp(slurl, right_mouse)) return true; -	switch(slurl.getType()) -	{ -		case LLSLURL::APP:  -			return dispatchApp(slurl, right_mouse, web, trusted_browser); -		case LLSLURL::LOCATION: -			return dispatchRegion(slurl, right_mouse); -		default: -			return false; -	} +	if (url.empty()) return false; +	//if (dispatchHelp(url, right_mouse)) return true; +	if (dispatchApp(url, right_mouse, web, trusted_browser)) 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"] = slurl; +	args["SLURL"] = url;  	r;  	*/ +	 +	return false;  }  // static -bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl, +bool LLURLDispatcherImpl::dispatch(const std::string& url,  								   LLMediaCtrl* web,  								   bool trusted_browser)  { +	llinfos << "url: " << url << llendl;  	const bool right_click = false; -	return dispatchCore(slurl, right_click, web, trusted_browser); +	return dispatchCore(url, right_click, web, trusted_browser);  }  // static -bool LLURLDispatcherImpl::dispatchRightClick(const LLSLURL& slurl) +bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url)  { +	llinfos << "url: " << url << llendl;  	const bool right_click = true;  	LLMediaCtrl* web = NULL;  	const bool trusted_browser = false; -	return dispatchCore(slurl, right_click, web, trusted_browser); +	return dispatchCore(url, right_click, web, trusted_browser);  }  // static -bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,  +bool LLURLDispatcherImpl::dispatchApp(const std::string& url,   									  bool right_mouse,  									  LLMediaCtrl* web,  									  bool trusted_browser)  { -	llinfos << "cmd: " << slurl.getAppCmd() << " path: " << slurl.getAppPath() << " query: " << slurl.getAppQuery() << llendl; +	// ensure the URL is in the secondlife:///app/ format +	if (!LLSLURL::isSLURLCommand(url)) +	{ +		return false; +	} + +	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( -			slurl.getAppCmd(), slurl.getAppPath(), slurl.getAppQuery(), web, trusted_browser); +			cmd, pathArray, uri.queryMap(), web, trusted_browser);  	// alert if we didn't handle this secondlife:///app/ SLURL  	// (but still return true because it is a valid app SLURL) @@ -164,72 +173,81 @@ bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,  }  // static -bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, bool right_mouse) +bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, bool right_mouse)  { -  if(slurl.getType() != LLSLURL::LOCATION) -    { -      return false; -    } +	if (!LLSLURL::isSLURL(url)) +	{ +		return false; +	} + +	std::string sim_string = LLSLURL::stripProtocol(url); +	std::string region_name; +	S32 x = 128; +	S32 y = 128; +	S32 z = 0; +	if (! LLURLSimString::parse(sim_string, ®ion_name, &x, &y, &z)) +	{ +		return false; +	} +  	// Before we're logged in, need to update the startup screen  	// to tell the user where they are going.  	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::setLocation(slurl); +		LLPanelLogin::refreshLocation( true );  		return true;  	}  	// LLFloaterURLDisplay functionality moved to LLPanelPlaces in Side Tray. -	//LLFloaterURLDisplay* slurl_displayp = LLFloaterReg::getTypedInstance<LLFloaterURLDisplay>("preview_url",LLSD()); -	//if(slurl_displayp) slurl_displayp->setName(region_name); +	//LLFloaterURLDisplay* url_displayp = LLFloaterReg::getTypedInstance<LLFloaterURLDisplay>("preview_url",LLSD()); +	//if(url_displayp) url_displayp->setName(region_name);  	// Request a region handle by name -	LLWorldMapMessage::getInstance()->sendNamedRegionRequest(slurl.getRegion(), -									  LLURLDispatcherImpl::regionNameCallback, -									  slurl.getSLURLString(), -									  false);	// don't teleport +	LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, +								 LLURLDispatcherImpl::regionNameCallback, +								 url, +								 false);	// don't teleport  	return true;  }  /*static*/ -void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport) +void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)  { -       -  if(slurl.getType() == LLSLURL::LOCATION) -    {         -      regionHandleCallback(region_handle, slurl, snapshot_id, teleport); -    } +	std::string sim_string = LLSLURL::stripProtocol(url); +	std::string region_name; +	S32 x = 128; +	S32 y = 128; +	S32 z = 0; + +	if (LLURLSimString::parse(sim_string, ®ion_name, &x, &y, &z)) +	{ +		regionHandleCallback(region_handle, url, snapshot_id, teleport); +	}  }  /* static */ -void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport) +void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)  { +	std::string sim_string = LLSLURL::stripProtocol(url); +	std::string region_name; +	S32 x = 128; +	S32 y = 128; +	S32 z = 0; +	LLURLSimString::parse(sim_string, ®ion_name, &x, &y, &z); + +	LLVector3 local_pos; +	local_pos.mV[VX] = (F32)x; +	local_pos.mV[VY] = (F32)y; +	local_pos.mV[VZ] = (F32)z; -  // we can't teleport cross grid at this point -	if((!LLGridManager::getInstance()->isSystemGrid(slurl.getGrid()) || !LLGridManager::getInstance()->isSystemGrid()) && -	   (slurl.getGrid() != LLGridManager::getInstance()->getGrid())) -	{ -		LLSD args; -		args["SLURL"] = slurl.getLocationString(); -		args["CURRENT_GRID"] = LLGridManager::getInstance()->getGridLabel(); -		LLSD grid_info = LLGridManager::getInstance()->getGridInfo(slurl.getGrid()); -		 -		if(grid_info.has(GRID_LABEL_VALUE)) -		{ -			args["GRID"] = grid_info[GRID_LABEL_VALUE].asString(); -		} -		else  -		{ -			args["GRID"] = slurl.getGrid(); -		} -		LLNotificationsUtil::add("CantTeleportToGrid", args); -		return; -	} -	  	LLVector3d global_pos = from_region_handle(region_handle); -	global_pos += LLVector3d(slurl.getPosition()); +	global_pos += LLVector3d(local_pos);  	if (teleport)  	{	 @@ -253,8 +271,8 @@ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL&  		// LLFloaterURLDisplay functionality moved to LLPanelPlaces in Side Tray.  //		// display informational floater, allow user to click teleport btn -//		LLFloaterURLDisplay* slurl_displayp = LLFloaterReg::getTypedInstance<LLFloaterURLDisplay>("preview_url",LLSD()); -//		if(slurl_displayp) +//		LLFloaterURLDisplay* url_displayp = LLFloaterReg::getTypedInstance<LLFloaterURLDisplay>("preview_url",LLSD()); +//		if(url_displayp)  //		{  //			url_displayp->displayParcelInfo(region_handle, local_pos);  //			if(snapshot_id.notNull()) @@ -269,7 +287,7 @@ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL&  //---------------------------------------------------------------------------  // Teleportation links are handled here because they are tightly coupled -// to SLURL parsing and sim-fragment parsing +// to URL parsing and sim-fragment parsing  class LLTeleportHandler : public LLCommandHandler  {  public: @@ -285,21 +303,18 @@ public:  		// a global position, and teleport to it  		if (tokens.size() < 1) return false; -		LLVector3 coords(128, 128, 0); -		if (tokens.size() <= 4) -		{ -			coords = LLVector3(tokens[1].asReal(),  -							   tokens[2].asReal(),  -							   tokens[3].asReal()); -		} -		  		// Region names may be %20 escaped. -		 -		std::string region_name = LLURI::unescape(tokens[0]); +		std::string region_name = LLURLSimString::unescapeRegionName(tokens[0]); +		// build secondlife://De%20Haro/123/45/67 for use in callback +		std::string url = LLSLURL::PREFIX_SECONDLIFE; +		for (int i = 0; i < tokens.size(); ++i) +		{ +			url += tokens[i].asString() + "/"; +		}  		LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name,  			LLURLDispatcherImpl::regionHandleCallback, -			LLSLURL(region_name, coords).getSLURLString(), +			url,  			true);	// teleport  		return true;  	} @@ -309,21 +324,21 @@ LLTeleportHandler gTeleportHandler;  //---------------------------------------------------------------------------  // static -bool LLURLDispatcher::dispatch(const std::string& slurl, +bool LLURLDispatcher::dispatch(const std::string& url,  							   LLMediaCtrl* web,  							   bool trusted_browser)  { -	return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), web, trusted_browser); +	return LLURLDispatcherImpl::dispatch(url, web, trusted_browser);  }  // static -bool LLURLDispatcher::dispatchRightClick(const std::string& slurl) +bool LLURLDispatcher::dispatchRightClick(const std::string& url)  { -	return LLURLDispatcherImpl::dispatchRightClick(LLSLURL(slurl)); +	return LLURLDispatcherImpl::dispatchRightClick(url);  }  // static -bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl) +bool LLURLDispatcher::dispatchFromTextEditor(const std::string& url)  {  	// *NOTE: Text editors are considered sources of trusted URLs  	// in order to make avatar profile links in chat history work. @@ -333,7 +348,5 @@ bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl)  	// *TODO: Make this trust model more refined.  JC  	const bool trusted_browser = true;  	LLMediaCtrl* web = NULL; -	return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), web, trusted_browser); +	return LLURLDispatcherImpl::dispatch(url, web, trusted_browser);  } - - diff --git a/indra/newview/llurldispatcher.h b/indra/newview/llurldispatcher.h index 407e417e58..ff8a351253 100644 --- a/indra/newview/llurldispatcher.h +++ b/indra/newview/llurldispatcher.h @@ -2,9 +2,9 @@   * @file llurldispatcher.h   * @brief Central registry for all SL URL handlers   * - * $LicenseInfo:firstyear=2010&license=viewergpl$ + * $LicenseInfo:firstyear=2007&license=viewergpl$   *  - * Copyright (c) 2007-2010, Linden Research, Inc. + * Copyright (c) 2007-2009, Linden Research, Inc.   *    * Second Life Viewer Source Code   * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@   * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, @@ -30,16 +31,16 @@   */  #ifndef LLURLDISPATCHER_H  #define LLURLDISPATCHER_H +  class LLMediaCtrl;  class LLURLDispatcher  {  public: -	 -	static bool dispatch(const std::string& slurl, +	static bool dispatch(const std::string& url,  						 LLMediaCtrl* web, -						 bool trusted_browser);	 +						 bool trusted_browser);  		// At startup time and on clicks in internal web browsers,  		// teleport, open map, or run requested command.  		// @param url @@ -53,9 +54,9 @@ public:  		//   that navigates to trusted (Linden Lab) pages.  		// Returns true if someone handled the URL. -	static bool dispatchRightClick(const std::string& slurl); +	static bool dispatchRightClick(const std::string& url); -	static bool dispatchFromTextEditor(const std::string& slurl); +	static bool dispatchFromTextEditor(const std::string& url);  };  #endif diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index 8488527185..1d2687a8c2 100644 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -89,7 +89,7 @@ void LLURLLineEditor::copyEscapedURLToClipboard()  	const std::string unescaped_text = wstring_to_utf8str(mText.getWString().substr(left_pos, length));  	LLWString text_to_copy; -	if (LLSLURL(unescaped_text).isValid()) +	if (LLSLURL::isSLURL(unescaped_text))  		text_to_copy = utf8str_to_wstring(LLWeb::escapeURL(unescaped_text));  	else  		text_to_copy = utf8str_to_wstring(unescaped_text); diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index ef6f4194e0..2661c9f32b 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -157,21 +157,21 @@ void audio_update_volume(bool force_update)  	LLViewerMedia::setVolume( media_muted ? 0.0f : media_volume );  	// Voice -	if (LLVoiceClient::getInstance()) +	if (gVoiceClient)  	{  		F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice");  		voice_volume = mute_volume * master_volume * voice_volume;  		BOOL voice_mute = gSavedSettings.getBOOL("MuteVoice"); -		LLVoiceClient::getInstance()->setVoiceVolume(voice_mute ? 0.f : voice_volume); -		LLVoiceClient::getInstance()->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic")); +		gVoiceClient->setVoiceVolume(voice_mute ? 0.f : voice_volume); +		gVoiceClient->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic"));  		if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized")))  		{ -			LLVoiceClient::getInstance()->setMuteMic(true); +			gVoiceClient->setMuteMic(true);  		}  		else  		{ -			LLVoiceClient::getInstance()->setMuteMic(false); +			gVoiceClient->setMuteMic(false);  		}  	}  } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index ef6379948a..6f037177fa 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -413,6 +413,7 @@ bool handleHighResSnapshotChanged(const LLSD& newvalue)  bool handleVoiceClientPrefsChanged(const LLSD& newvalue)  { +	if(LLVoiceClient::getInstance())  	LLVoiceClient::getInstance()->updateSettings();  	return true;  } @@ -443,7 +444,7 @@ bool handleVelocityInterpolate(const LLSD& newvalue)  bool handleForceShowGrid(const LLSD& newvalue)  { -	LLPanelLogin::updateServer( ); +	LLPanelLogin::refreshLocation( false );  	return true;  } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 444d397146..8a891b1462 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -36,6 +36,7 @@  #include "llnotificationsutil.h"  #include "llsdserialize.h"  #include "message.h" +#include "indra_constants.h"  #include "llagent.h"  #include "llagentcamera.h" @@ -264,14 +265,10 @@ void LLViewerInventoryItem::fetchFromServer(void) const  		// we have to check region. It can be null after region was destroyed. See EXT-245  		if (region)  		{ -		  if(gAgent.getID() != mPermissions.getOwner()) -		    { -		      url = region->getCapability("FetchLib"); -		    } -		  else -		    {	 -		      url = region->getCapability("FetchInventory"); -		    } +			if( ALEXANDRIA_LINDEN_ID.getString() == mPermissions.getOwner().getString()) +				url = region->getCapability("FetchLib"); +			else	 +				url = region->getCapability("FetchInventory");  		}  		else  		{ diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index d91b6d0b1e..0a1d749698 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -430,7 +430,7 @@ void init_menus()  	gPopupMenuView->setBackgroundColor( color );  	// If we are not in production, use a different color to make it apparent. -	if (LLGridManager::getInstance()->isInProductionGrid()) +	if (LLViewerLogin::getInstance()->isInProductionGrid())  	{  		color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );  	} @@ -446,7 +446,7 @@ void init_menus()  	menu_bar_holder->addChild(gMenuBarView);      gViewerWindow->setMenuBackgroundColor(false,  -        LLGridManager::getInstance()->isInProductionGrid()); +        LLViewerLogin::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 @@ -3468,7 +3468,7 @@ void set_god_level(U8 god_level)          if(gViewerWindow)          {              gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT, -            LLGridManager::getInstance()->isInProductionGrid()); +            LLViewerLogin::getInstance()->isInProductionGrid());          }          LLSD args; @@ -3508,7 +3508,7 @@ BOOL check_toggle_hacked_godmode(void*)  bool enable_toggle_hacked_godmode(void*)  { -  return !LLGridManager::getInstance()->isInProductionGrid(); +  return !LLViewerLogin::getInstance()->isInProductionGrid();  }  #endif @@ -4379,7 +4379,7 @@ BOOL enable_take()  		return TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -		if (!LLGridManager::getInstance()->isInProductionGrid()  +		if (!LLViewerLogin::getInstance()->isInProductionGrid()               && gAgent.isGodlike())  		{  			return TRUE; @@ -4992,7 +4992,7 @@ bool enable_object_delete()  	TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -	(!LLGridManager::getInstance()->isInProductionGrid() +	(!LLViewerLogin::getInstance()->isInProductionGrid()       && gAgent.isGodlike()) ||  # endif  	LLSelectMgr::getInstance()->canDoDelete(); @@ -6628,7 +6628,7 @@ bool enable_object_take_copy()  		all_valid = true;  #ifndef HACKED_GODLIKE_VIEWER  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -		if (LLGridManager::getInstance()->isInProductionGrid() +		if (LLViewerLogin::getInstance()->isInProductionGrid()              || !gAgent.isGodlike())  # endif  		{ @@ -6690,7 +6690,7 @@ BOOL enable_save_into_inventory(void*)  	return TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -	if (!LLGridManager::getInstance()->isInProductionGrid() +	if (!LLViewerLogin::getInstance()->isInProductionGrid()          && gAgent.isGodlike())  	{  		return TRUE; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index a471876ce1..c542459cdb 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1574,9 +1574,9 @@ void inventory_offer_handler(LLOfferInfo* info)  	payload["give_inventory_notification"] = FALSE;  	args["OBJECTFROMNAME"] = info->mFromName;  	args["NAME"] = info->mFromName; -	args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString(); +	args["NAME_SLURL"] = LLSLURL::buildCommand("agent", info->mFromID, "about");  	std::string verb = "select?name=" + LLURI::escape(msg); -	args["ITEM_SLURL"] = LLSLURL("inventory", info->mObjectID, verb.c_str()).getSLURLString(); +	args["ITEM_SLURL"] = LLSLURL::buildCommand("inventory", info->mObjectID, verb.c_str());  	LLNotification::Params p("ObjectGiveItem"); @@ -2245,7 +2245,10 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  				query_string["groupowned"] = "true";  			}	 -			chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); +			std::ostringstream link; +			link << "secondlife:///app/objectim/" << session_id << LLURI::mapToQueryString(query_string); + +			chat.mURL = link.str();  			chat.mText = message;  			chat.mSourceType = CHAT_SOURCE_OBJECT; @@ -2328,7 +2331,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  			{  				LLSD args;  				// *TODO: Translate -> [FIRST] [LAST] (maybe) -				args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); +				args["NAME_SLURL"] = LLSLURL::buildCommand("agent", from_id, "about");  				args["MESSAGE"] = message;  				LLSD payload;  				payload["from_id"] = from_id; @@ -2394,7 +2397,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  			}  			else  			{ -				args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); +				args["NAME_SLURL"] = LLSLURL::buildCommand("agent", from_id, "about");  				if(message.empty())  				{  					//support for frienship offers from clients before July 2008 @@ -3153,9 +3156,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)  		{  			// Chat the "back" SLURL. (DEV-4907) -			LLSLURL slurl; -			gAgent.getTeleportSourceSLURL(slurl); -			LLSD substitution = LLSD().with("[T_SLURL]", slurl.getSLURLString()); +			LLSD substitution = LLSD().with("[T_SLURL]", gAgent.getTeleportSourceSLURL());  			std::string completed_from = LLAgent::sTeleportProgressMessages["completed_from"];  			LLStringUtil::format(completed_from, substitution); @@ -5548,9 +5549,7 @@ void send_group_notice(const LLUUID& group_id,  bool handle_lure_callback(const LLSD& notification, const LLSD& response)  {  	std::string text = response["message"].asString(); -	LLSLURL slurl; -	LLAgentUI::buildSLURL(slurl); -	text.append("\r\n").append(slurl.getSLURLString()); +	text.append("\r\n").append(LLAgentUI::buildSLURL());  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);  	if(0 == option) @@ -5993,7 +5992,7 @@ void process_covenant_reply(LLMessageSystem* msg, void**)  	LLFloaterBuyLand::updateEstateName(estate_name);  	std::string owner_name = -		LLSLURL("agent", estate_owner_id, "inspect").getSLURLString(); +		LLSLURL::buildCommand("agent", estate_owner_id, "inspect");  	LLPanelEstateCovenant::updateEstateOwnerName(owner_name);  	LLPanelLandCovenant::updateEstateOwnerName(owner_name);  	LLFloaterBuyLand::updateEstateOwnerName(owner_name); diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index d7bb4efe85..987d23630a 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -5,7 +5,7 @@   *   * $LicenseInfo:firstyear=2006&license=viewergpl$   *  - * Copyright (c) 2006-2010, Linden Research, Inc. + * Copyright (c) 2006-2009, Linden Research, Inc.   *    * Second Life Viewer Source Code   * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +13,13 @@   * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, @@ -33,478 +34,303 @@  #include "llviewerprecompiledheaders.h"  #include "llviewernetwork.h" -#include "llviewercontrol.h" -#include "llsdserialize.h" -#include "llweb.h" - -                                                             -const char* DEFAULT_LOGIN_PAGE = "http://secondlife.com/app/login/"; -const char* SYSTEM_GRID_SLURL_BASE = "secondlife://%s/secondlife/"; -const char* MAIN_GRID_SLURL_BASE = "http://maps.secondlife.com/secondlife/"; -const char* SYSTEM_GRID_APP_SLURL_BASE = "secondlife:///app"; +#include "llevents.h" +#include "net.h" -const char* DEFAULT_SLURL_BASE = "https://%s/region/"; -const char* DEFAULT_APP_SLURL_BASE = "x-grid-location-info://%s/app"; +#include "llviewercontrol.h" +#include "lllogin.h" -LLGridManager::LLGridManager() +struct LLGridData  { -	// 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); -	 -} +	const char* mLabel; +	const char* mName; +	const char* mLoginURI; +	const char* mHelperURI; +}; - -LLGridManager::LLGridManager(const std::string& grid_file) +static LLGridData gGridInfo[GRID_INFO_COUNT] =   { -	// initialize with an explicity grid file for testing. -	initialize(grid_file); -} - -// -// 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) +	{ "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)  { -	// default grid list. -	// Don't move to a modifiable file for security reasons, -	mGrid.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);  + LLViewerLogin::~LLViewerLogin()  + { + } -	 -	LLSD other_grids; -	llifstream llsd_xml; -	if (!grid_file.empty()) +void LLViewerLogin::setGridChoice(EGridInfo grid) +{	 +	if(grid < 0 || grid >= GRID_INFO_COUNT)  	{ -		llsd_xml.open( grid_file.c_str(), std::ios::in | std::ios::binary ); - -		// 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(); -			}	 -		}      +		llerrs << "Invalid grid index specified." << llendl; +		return;  	} -	 -	// load a grid from the command line. -	// if the actual grid name is specified from the command line, -	// set it as the 'selected' grid. -	mGrid = gSavedSettings.getString("CmdLineGridChoice"); -	LL_INFOS("GridManager") << "Grid Name: " << mGrid << LL_ENDL;		 -	 -	// If a command line login URI was passed in, so we should add the command -	// line grid to the list of grids -	LLSD cmd_line_login_uri = gSavedSettings.getLLSD("CmdLineLoginURI"); -	if (cmd_line_login_uri.isString()) +	if(mGridChoice != grid || gSavedSettings.getS32("ServerChoice") != grid)  	{ -		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 (mGrid.empty()) +		mGridChoice = grid; +		if(GRID_INFO_LOCAL == mGridChoice)  		{ -			// 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 -			mGrid = uri.hostName(); +			mGridName = LOOPBACK_ADDRESS_STRING;  		} - -		grid[GRID_VALUE] = mGrid; - -		if (mGridList.has(mGrid) && mGridList[mGrid].has(GRID_LABEL_VALUE)) +		else if(GRID_INFO_OTHER == mGridChoice)  		{ -			grid[GRID_LABEL_VALUE] = mGridList[mGrid][GRID_LABEL_VALUE]; +			// *FIX:Mani - could this possibly be valid? +			mGridName = "other";   		}  		else  		{ -			grid[GRID_LABEL_VALUE] = mGrid;			 -		} -		if(!cmd_line_helper_uri.empty()) -		{ -			grid[GRID_HELPER_URI_VALUE] = cmd_line_helper_uri; +			mGridName = gGridInfo[mGridChoice].mLabel;  		} -		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(mGrid) && mGridList[mGrid].has(GRID_IS_SYSTEM_GRID_VALUE)) -		{ -			grid[GRID_IS_SYSTEM_GRID_VALUE] = TRUE; -		} -		addGrid(grid); +		gSavedSettings.setS32("ServerChoice", mGridChoice); +		gSavedSettings.setString("CustomServer", "");  	} -	 -	// if a grid was not passed in via the command line, grab it from the CurrentGrid setting. -	if (mGrid.empty()) -	{ - -		mGrid = gSavedSettings.getString("CurrentGrid"); -	} - -	if (mGrid.empty() || !mGridList.has(mGrid)) -	{ -		// 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 " << mGrid << " is not in the list" << LL_ENDL; -#if LL_RELEASE_FOR_DOWNLOAD -		mGrid = MAINGRID; -#else -		mGrid = ""; -#endif -	} -	LL_INFOS("GridManager") << "Selected grid is " << mGrid << LL_ENDL;		 -	gSavedSettings.setString("CurrentGrid", mGrid); -  } -LLGridManager::~LLGridManager() +void LLViewerLogin::setGridChoice(const std::string& grid_name)  { -	saveFavorites(); +	// 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); +        } +    }  } -// -// 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) +void LLViewerLogin::resetURIs()  { -	if (grid_data.isMap() && grid_data.has(GRID_VALUE)) -	{ -		std::string grid = utf8str_tolower(grid_data[GRID_VALUE]); +    // Clear URIs when picking a new server +	gSavedSettings.setLLSD("CmdLineLoginURI", LLSD::emptyArray()); +	gSavedSettings.setString("CmdLineHelperURI", ""); +} -		// grid should be in the form of a dns address -		if (!grid.empty() && -			grid.find_first_not_of("abcdefghijklmnopqrstuvwxyz1234567890-_. ") != std::string::npos) -		{ -			printf("grid name: %s", grid.c_str()); -			throw LLInvalidGridName(grid); -		} -		 -		// populate the other values if they don't exist -		if (!grid_data.has(GRID_LABEL_VALUE))  -		{ -			grid_data[GRID_LABEL_VALUE] = grid; -		} -		if (!grid_data.has(GRID_ID_VALUE)) -		{ -			grid_data[GRID_ID_VALUE] = grid; -		} -		 -		// if the grid data doesn't include any of the URIs, then  -		// generate them from the grid, 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 + "/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 + "/app/login/"; -		}		 -		if (!grid_data.has(GRID_HELPER_URI_VALUE))  -		{ -			grid_data[GRID_HELPER_URI_VALUE] = std::string("https://") + grid + "/helpers/"; -		}		 -		LL_INFOS("GridManager") << "ADDING: " << grid << LL_ENDL; -		mGridList[grid] = grid_data;		 -	} +EGridInfo LLViewerLogin::getGridChoice() const +{ +	return mGridChoice;  } -// -// 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) +std::string LLViewerLogin::getGridLabel() const  { -	LLSD grid = LLSD::emptyMap(); -	grid[GRID_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_APP_SLURL_BASE] = SYSTEM_GRID_APP_SLURL_BASE; -	if (login_id.empty()) -	{ -		grid[GRID_ID_VALUE] = name; -	} -	else +	if(mGridChoice == GRID_INFO_NONE)  	{ -		grid[GRID_ID_VALUE] = login_id; +		return "None";  	} -	 -	// only add the system grids beyond agni to the visible list -	// if we're building a debug version. -	if (name == std::string(MAINGRID)) +	else if(mGridChoice < GRID_INFO_OTHER)  	{ -		grid[GRID_SLURL_BASE] = MAIN_GRID_SLURL_BASE;		 -		grid[GRID_IS_FAVORITE_VALUE] = TRUE;		 +		return gGridInfo[mGridChoice].mLabel;  	} -	else -	{ -		grid[GRID_SLURL_BASE] = llformat(SYSTEM_GRID_SLURL_BASE, label.c_str());		 -	} -	addGrid(grid); + +	return mGridName;  } -// return a list of grid name -> grid label mappings for UI purposes -std::map<std::string, std::string> LLGridManager::getKnownGrids(bool favorite_only) +std::string LLViewerLogin::getKnownGridLabel(EGridInfo grid_index) const  { -	std::map<std::string, std::string> result; -	for(LLSD::map_iterator grid_iter = mGridList.beginMap(); -		grid_iter != mGridList.endMap(); -		grid_iter++)  +	if(grid_index > GRID_INFO_NONE && grid_index < GRID_INFO_OTHER)  	{ -		if(!favorite_only || grid_iter->second.has(GRID_IS_FAVORITE_VALUE)) -		{ -			result[grid_iter->first] = grid_iter->second[GRID_LABEL_VALUE].asString(); -		} +		return gGridInfo[grid_index].mLabel;  	} - -	return result; +	return gGridInfo[GRID_INFO_NONE].mLabel;  } -void LLGridManager::setGridChoice(const std::string& grid) +void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const  { -	// 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++)  +	// return the login uri set on the command line. +	LLControlVariable* c = gSavedSettings.getControl("CmdLineLoginURI"); +	if(c)  	{ -		if((grid == grid_iter->first) ||  -		   (grid == grid_iter->second[GRID_LABEL_VALUE].asString())) +		LLSD v = c->getValue(); +		if(v.isArray())  		{ -			mGrid = grid_iter->second[GRID_VALUE].asString(); -			gSavedSettings.setString("CurrentGrid", grid_iter->second[GRID_VALUE]);			 -			return;  - +			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); +			}  		}  	} -	LLSD grid_data = LLSD::emptyMap(); -	grid_data[GRID_VALUE] = grid; -	addGrid(grid_data); -	mGrid = grid; -	gSavedSettings.setString("CurrentGrid", grid); -} -std::string LLGridManager::getGridByLabel( const std::string &grid_label) -{ -	for(LLSD::map_iterator grid_iter = mGridList.beginMap(); -		grid_iter != mGridList.endMap(); -		grid_iter++)  +	// If there was no command line uri... +	if(uris.empty())  	{ -		if (grid_iter->second.has(GRID_LABEL_VALUE) && (grid_iter->second[GRID_LABEL_VALUE].asString() == grid_label)) +		// 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) +		{ +			uris.push_back(gGridInfo[mGridChoice].mLoginURI); +		} +		else  		{ -			return grid_iter->first; +			uris.push_back(mGridName);  		}  	} -	return std::string();  } -void LLGridManager::getLoginURIs(std::vector<std::string>& uris) +std::string LLViewerLogin::getHelperURI() const  { -	uris.clear(); -	for (LLSD::array_iterator llsd_uri = mGridList[mGrid][GRID_LOGIN_URI_VALUE].beginArray(); -		 llsd_uri != mGridList[mGrid][GRID_LOGIN_URI_VALUE].endArray(); -		 llsd_uri++) +	std::string helper_uri = gSavedSettings.getString("CmdLineHelperURI"); +	if (helper_uri.empty())  	{ -		uris.push_back(llsd_uri->asString()); +		// 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 +		}  	} +	return helper_uri;  } -bool LLGridManager::isInProductionGrid() +bool LLViewerLogin::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))  	{ @@ -513,51 +339,3 @@ bool LLGridManager::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) -{ -	std::string grid_base; -	if(mGridList.has(grid) && mGridList[grid].has(GRID_SLURL_BASE)) -	{ -		return mGridList[grid][GRID_SLURL_BASE].asString(); -	} -	else -	{ -		return  llformat(DEFAULT_SLURL_BASE, grid.c_str()); -	} -} - -// build a slurl for the given region within the selected grid -std::string LLGridManager::getAppSLURLBase(const std::string& grid) -{ -	std::string grid_base; -	if(mGridList.has(grid) && mGridList[grid].has(GRID_APP_SLURL_BASE)) -	{ -	  return mGridList[grid][GRID_APP_SLURL_BASE].asString(); -	} -	else -	{ -	  return  llformat(DEFAULT_APP_SLURL_BASE, grid.c_str()); -	} -} diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h index 46f21bf20f..edae6dc47b 100644 --- a/indra/newview/llviewernetwork.h +++ b/indra/newview/llviewernetwork.h @@ -5,7 +5,7 @@   *   * $LicenseInfo:firstyear=2006&license=viewergpl$   *  - * Copyright (c) 2006-2010, Linden Research, Inc. + * Copyright (c) 2006-2009, Linden Research, Inc.   *    * Second Life Viewer Source Code   * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +13,13 @@   * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, @@ -32,136 +33,83 @@  #ifndef LL_LLVIEWERNETWORK_H  #define LL_LLVIEWERNETWORK_H -                                                                                                        -extern const char* DEFAULT_LOGIN_PAGE; -       -#define GRID_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" -// 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" +#include <boost/scoped_ptr.hpp> -class LLInvalidGridName +class LLHost; +class LLLogin; + +enum EGridInfo  { -public: -	LLInvalidGridName(std::string grid) : mGrid(grid) -	{ -	} -protected: -	std::string mGrid; +	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  }; -  /** - * @brief A class to manage the grids available to the viewer - * including persistance.  This class also maintains the currently - * selected grid. + * @brief A class to manage the viewer's login state.   *    **/ -class LLGridManager : public LLSingleton<LLGridManager> +class LLViewerLogin : public LLSingleton<LLViewerLogin>  {  public: -	 -	// 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);	 +	LLViewerLogin(); +	~LLViewerLogin(); -	// 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) -	{ -		if(mGridList.has(grid)) -		{ -			return mGridList[grid]; -		} -		else -		{ -			return LLSD(); -		} -	} -	 -	// current grid management +	void setGridChoice(EGridInfo grid); +	void setGridChoice(const std::string& grid_name); +	void resetURIs(); -	// 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); -	 -	 -	std::string getGridLabel() { return mGridList[mGrid][GRID_LABEL_VALUE]; } 	 -	std::string getGrid() const { return mGrid; } -	void getLoginURIs(std::vector<std::string>& uris); -	std::string getHelperURI() {return mGridList[mGrid][GRID_HELPER_URI_VALUE];} -	std::string getLoginPage() {return mGridList[mGrid][GRID_LOGIN_PAGE_VALUE];} -	std::string getGridLoginID() { return mGridList[mGrid][GRID_ID_VALUE]; }	 -	std::string getLoginPage(const std::string& grid) { return mGridList[grid][GRID_LOGIN_PAGE_VALUE]; } -	 -	// build a slurl for the given region within the selected grid -	std::string getSLURLBase(const std::string& grid); -	std::string getSLURLBase() { return getSLURLBase(mGrid); } -	 -	std::string getAppSLURLBase(const std::string& grid); -	std::string getAppSLURLBase() { return getAppSLURLBase(mGrid); }	 -	 -	LLSD getGridInfo() { return mGridList[mGrid]; } -	 -	std::string getGridByLabel( const std::string &grid_label); -	 -	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(mGrid); } -	// 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[mGrid][GRID_IS_FAVORITE_VALUE] = TRUE; } -	 -	bool isInProductionGrid(); -	void saveFavorites(); -	void clearFavorites(); +	/** +	* @brief Get the enumeration of the grid choice. +	* Should only return values > 0 && < GRID_INFO_COUNT +	**/ +	EGridInfo getGridChoice() const; -protected: +	/** +	* @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; + +	bool isInProductionGrid(); -	// 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 mGrid; -	std::string mGridFile; -	LLSD mGridList; +private: +	EGridInfo mGridChoice; +	std::string mGridName;  };  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 ee89680fea..bb7933c10e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -4727,7 +4727,7 @@ BOOL LLViewerObject::permYouOwner() const  		return TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -		if (!LLGridManager::getInstance()->isInProductionGrid() +		if (!LLViewerLogin::getInstance()->isInProductionGrid()              && (gAgent.getGodLevel() >= GOD_MAINTENANCE))  		{  			return TRUE; @@ -4764,7 +4764,7 @@ BOOL LLViewerObject::permOwnerModify() const  		return TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -		if (!LLGridManager::getInstance()->isInProductionGrid() +		if (!LLViewerLogin::getInstance()->isInProductionGrid()              && (gAgent.getGodLevel() >= GOD_MAINTENANCE))  	{  			return TRUE; @@ -4788,7 +4788,7 @@ BOOL LLViewerObject::permModify() const  		return TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -		if (!LLGridManager::getInstance()->isInProductionGrid() +		if (!LLViewerLogin::getInstance()->isInProductionGrid()              && (gAgent.getGodLevel() >= GOD_MAINTENANCE))  	{  			return TRUE; @@ -4812,7 +4812,7 @@ BOOL LLViewerObject::permCopy() const  		return TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -		if (!LLGridManager::getInstance()->isInProductionGrid() +		if (!LLViewerLogin::getInstance()->isInProductionGrid()              && (gAgent.getGodLevel() >= GOD_MAINTENANCE))  		{  			return TRUE; @@ -4836,7 +4836,7 @@ BOOL LLViewerObject::permMove() const  		return TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -		if (!LLGridManager::getInstance()->isInProductionGrid() +		if (!LLViewerLogin::getInstance()->isInProductionGrid()              && (gAgent.getGodLevel() >= GOD_MAINTENANCE))  		{  			return TRUE; @@ -4860,7 +4860,7 @@ BOOL LLViewerObject::permTransfer() const  		return TRUE;  #else  # ifdef TOGGLE_HACKED_GODLIKE_VIEWER -		if (!LLGridManager::getInstance()->isInProductionGrid() +		if (!LLViewerLogin::getInstance()->isInProductionGrid()              && (gAgent.getGodLevel() >= GOD_MAINTENANCE))  		{  			return TRUE; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index bdc34d0f18..b7c265be59 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -768,11 +768,9 @@ 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", -											MACAddress[0],MACAddress[1],MACAddress[2], -											MACAddress[3],MACAddress[4],MACAddress[5]); +											gMACAddress[0],gMACAddress[1],gMACAddress[2], +											gMACAddress[3],gMACAddress[4],gMACAddress[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 4c6a02db87..ae3f680cbf 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -85,6 +85,7 @@  #include "lltooltip.h"  #include "llmediaentry.h"  #include "llurldispatcher.h" +#include "llurlsimstring.h"  // newview includes  #include "llagent.h" @@ -798,7 +799,7 @@ BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window,  LLCoordGL pos, MASK m  BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)  {  	BOOL down = TRUE; -	LLVoiceClient::getInstance()->middleMouseState(true); +	gVoiceClient->middleMouseState(true);   	handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);    	// Always handled as far as the OS is concerned. @@ -825,15 +826,20 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi  				if (slurl_dnd_enabled)  				{ -					LLSLURL dropped_slurl(data); -					if(dropped_slurl.isSpatial()) +					 +					// special case SLURLs +					// isValidSLURL() call was added here to make sure that dragged SLURL is valid (EXT-4964) +					if ( LLSLURL::isSLURL( data ) && LLSLURL::isValidSLURL( data ) )  					{  						if (drop)  						{ -							LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), NULL, true ); -							return LLWindowCallbacks::DND_MOVE; +							LLURLDispatcher::dispatch( data, NULL, true ); +							LLURLSimString::setStringRaw( LLSLURL::stripProtocol( data ) ); +							LLPanelLogin::refreshLocation( true ); +							LLPanelLogin::updateLocationUI();  						} -					} +						return LLWindowCallbacks::DND_MOVE; +					};  				}  				if (prim_media_dnd_enabled) @@ -951,7 +957,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi  BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)  {  	BOOL down = FALSE; -	LLVoiceClient::getInstance()->middleMouseState(false); +	gVoiceClient->middleMouseState(false);   	handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);    	// Always handled as far as the OS is concerned. @@ -1068,7 +1074,7 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)  BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)  {  	// Let the voice chat code check for its PTT key.  Note that this never affects event processing. -	LLVoiceClient::getInstance()->keyDown(key, mask); +	gVoiceClient->keyDown(key, mask);  	if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)  	{ @@ -1090,7 +1096,7 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)  BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)  {  	// Let the voice chat code check for its PTT key.  Note that this never affects event processing. -	LLVoiceClient::getInstance()->keyUp(key, mask); +	gVoiceClient->keyUp(key, mask);  	return FALSE;  } @@ -1949,7 +1955,7 @@ void LLViewerWindow::setNormalControlsVisible( BOOL visible )  		// ...and set the menu color appropriately.  		setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,  -			LLGridManager::getInstance()->isInProductionGrid()); +			LLViewerLogin::getInstance()->isInProductionGrid());  	}  	if ( gStatusBar ) @@ -1970,15 +1976,15 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)      LLSD args;      LLColor4 new_bg_color; -    if(god_mode && LLGridManager::getInstance()->isInProductionGrid()) +    if(god_mode && LLViewerLogin::getInstance()->isInProductionGrid())      {          new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );      } -    else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid()) +    else if(god_mode && !LLViewerLogin::getInstance()->isInProductionGrid())      {          new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );      } -    else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid()) +    else if(!god_mode && !LLViewerLogin::getInstance()->isInProductionGrid())      {          new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );      } @@ -2194,6 +2200,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)  		}  		return TRUE;  	} +  	// hidden edit menu for cut/copy/paste  	if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))  	{ diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 540cb47710..0ce8894872 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1266,7 +1266,7 @@ void LLVOAvatar::initInstance(void)  	//VTPause();  // VTune -	mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); +	mVoiceVisualizer->setVoiceEnabled( gVoiceClient->getVoiceEnabled( mID ) );  }  const LLVector3 LLVOAvatar::getRenderPosition() const @@ -2197,8 +2197,8 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)  	}  	static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false); -	bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) && -						 LLVoiceClient::getInstance()->getVoiceEnabled(mID); +	bool voice_enabled = (visualizers_in_calls || gVoiceClient->inProximalChannel()) && +						 gVoiceClient->getVoiceEnabled(mID);  	idleUpdateVoiceVisualizer( voice_enabled );  	idleUpdateMisc( detailed_update ); @@ -2261,7 +2261,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)  		// Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been  		// "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking.   		//----------------------------------------------------------------------------------------------------------------- -		if (LLVoiceClient::getInstance()->getIsSpeaking( mID )) +		if (gVoiceClient->getIsSpeaking( mID ))  		{		  			if (!mVoiceVisualizer->getCurrentlySpeaking())  			{ @@ -2270,7 +2270,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)  				//printf( "gAwayTimer.reset();\n" );  			} -			mVoiceVisualizer->setSpeakingAmplitude( LLVoiceClient::getInstance()->getCurrentPower( mID ) ); +			mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) );  			if( isSelf() )  			{ @@ -2499,7 +2499,7 @@ F32 LLVOAvatar::calcMorphAmount()  void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)  {  	// Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync -	if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) ) +	if ( voice_enabled && (gVoiceClient->lipSyncEnabled()) && gVoiceClient->getIsSpeaking( mID ) )  	{  		F32 ooh_morph_amount = 0.0f;  		F32 aah_morph_amount = 0.0f; diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 338bc12f04..fac7fa6a18 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -72,9 +72,9 @@ private:  void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)  { -	LL_WARNS("Voice") << "LLVoiceCallCapResponder::error(" +	llwarns << "LLVoiceCallCapResponder::error("  		<< status << ": " << reason << ")" -		<< LL_ENDL; +		<< llendl;  	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);  	if ( channelp )  	{ @@ -104,8 +104,8 @@ void LLVoiceCallCapResponder::result(const LLSD& content)  		LLSD::map_const_iterator iter;  		for(iter = content.beginMap(); iter != content.endMap(); ++iter)  		{ -			LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got "  -				<< iter->first << LL_ENDL; +			llinfos << "LLVoiceCallCapResponder::result got "  +				<< iter->first << llendl;  		}  		channelp->setChannelInfo( @@ -131,8 +131,10 @@ LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& sess  	{  		// a voice channel already exists for this session id, so this instance will be orphaned  		// the end result should simply be the failure to make voice calls -		LL_WARNS("Voice") << "Duplicate voice channels registered for session_id " << session_id << LL_ENDL; +		llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl;  	} + +	LLVoiceClient::getInstance()->addObserver(this);  }  LLVoiceChannel::~LLVoiceChannel() @@ -143,7 +145,7 @@ LLVoiceChannel::~LLVoiceChannel()  	// later in other destructors anyway). EXT-5524  	if(LLVoiceClient::instanceExists())  	{ -		LLVoiceClient::getInstance()->removeObserver(this); +		gVoiceClient->removeObserver(this);  	}  	sVoiceChannelMap.erase(mSessionID); @@ -163,13 +165,13 @@ void LLVoiceChannel::setChannelInfo(  		if (mURI.empty())  		{  			LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs); -			LL_WARNS("Voice") << "Received empty URI for channel " << mSessionName << LL_ENDL; +			llwarns << "Received empty URI for channel " << mSessionName << llendl;  			deactivate();  		}  		else if (mCredentials.empty())  		{  			LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs); -			LL_WARNS("Voice") << "Received empty credentials for channel " << mSessionName << LL_ENDL; +			llwarns << "Received empty credentials for channel " << mSessionName << llendl;  			deactivate();  		}  		else @@ -284,14 +286,13 @@ void LLVoiceChannel::deactivate()  		//Default mic is OFF when leaving voice calls  		if (gSavedSettings.getBOOL("AutoDisengageMic") &&   			sCurrentVoiceChannel == this && -			LLVoiceClient::getInstance()->getUserPTTState()) +			gVoiceClient->getUserPTTState())  		{  			gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); -			LLVoiceClient::getInstance()->inputUserControlState(true); +			gVoiceClient->inputUserControlState(true);  		}  	} -	LLVoiceClient::getInstance()->removeObserver(this); -	 +  	if (sCurrentVoiceChannel == this)  	{  		// default channel is proximal channel @@ -331,9 +332,7 @@ void LLVoiceChannel::activate()  	{  		setState(STATE_CALL_STARTED);  	} -	 -	LLVoiceClient::getInstance()->addObserver(this); -	 +  	//do not send earlier, channel should be initialized, should not be in STATE_NO_CHANNEL_INFO state  	sCurrentVoiceChannelChangedSignal(this->mSessionID);  } @@ -375,11 +374,6 @@ LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)  	}  } -LLVoiceChannel* LLVoiceChannel::getCurrentVoiceChannel() -{ -	return sCurrentVoiceChannel; -} -  void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)  {  	sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID)); @@ -431,6 +425,7 @@ void LLVoiceChannel::initClass()  	sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();  } +  //static   void LLVoiceChannel::suspend()  { @@ -446,7 +441,7 @@ void LLVoiceChannel::resume()  {  	if (sSuspended)  	{ -		if (LLVoiceClient::getInstance()->voiceEnabled()) +		if (gVoiceClient->voiceEnabled())  		{  			if (sSuspendedVoiceChannel)  			{ @@ -516,9 +511,9 @@ void LLVoiceChannelGroup::activate()  #endif  		//Mic default state is OFF on initiating/joining Ad-Hoc/Group calls -		if (LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle()) +		if (gVoiceClient->getUserPTTState() && gVoiceClient->getPTTIsToggle())  		{ -			LLVoiceClient::getInstance()->inputUserControlState(true); +			gVoiceClient->inputUserControlState(true);  		}  	} @@ -565,7 +560,7 @@ void LLVoiceChannelGroup::setChannelInfo(  		else  		{  			//*TODO: notify user -			LL_WARNS("Voice") << "Received invalid credentials for channel " << mSessionName << LL_ENDL; +			llwarns << "Received invalid credentials for channel " << mSessionName << llendl;  			deactivate();  		}  	} @@ -664,6 +659,7 @@ void LLVoiceChannelGroup::setState(EState state)  LLVoiceChannelProximal::LLVoiceChannelProximal() :   	LLVoiceChannel(LLUUID::null, LLStringUtil::null)  { +	activate();  }  BOOL LLVoiceChannelProximal::isActive() @@ -675,13 +671,13 @@ void LLVoiceChannelProximal::activate()  {  	if (callStarted()) return; -	if((LLVoiceChannel::sCurrentVoiceChannel != this) && (LLVoiceChannel::getState() == STATE_CONNECTED)) +	LLVoiceChannel::activate(); + +	if (callStarted())  	{ -		// we're connected to a non-spatial channel, so disconnect. -		LLVoiceClient::getInstance()->leaveNonSpatialChannel();	 +		// this implicitly puts you back in the spatial channel +		LLVoiceClient::getInstance()->leaveNonSpatialChannel();  	} -	LLVoiceChannel::activate(); -	  }  void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal) @@ -711,7 +707,7 @@ void LLVoiceChannelProximal::handleStatusChange(EStatusType status)  		return;  	case STATUS_VOICE_DISABLED:  		//skip showing "Voice not available at your current location" when agent voice is disabled (EXT-4749) -		if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()) +		if(LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking())  		{  			//TODO: remove or redirect this call status notification  //			LLCallInfoDialog::show("unavailable", mNotifyArgs); @@ -771,7 +767,7 @@ LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string  void LLVoiceChannelP2P::handleStatusChange(EStatusType type)  { -	LL_INFOS("Voice") << "P2P CALL CHANNEL STATUS CHANGE: incoming=" << int(mReceivedCall) << " newstatus=" << LLVoiceClientStatusObserver::status2string(type) << " (mState=" << mState << ")" << LL_ENDL; +	llinfos << "P2P CALL CHANNEL STATUS CHANGE: incoming=" << int(mReceivedCall) << " newstatus=" << LLVoiceClientStatusObserver::status2string(type) << " (mState=" << mState << ")" << llendl;  	// status updates  	switch(type) @@ -845,9 +841,9 @@ void LLVoiceChannelP2P::activate()  		LLRecentPeople::instance().add(mOtherUserID);  		//Default mic is ON on initiating/joining P2P calls -		if (!LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle()) +		if (!gVoiceClient->getUserPTTState() && gVoiceClient->getPTTIsToggle())  		{ -			LLVoiceClient::getInstance()->inputUserControlState(true); +			gVoiceClient->inputUserControlState(true);  		}  	}  } @@ -910,7 +906,7 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s  void LLVoiceChannelP2P::setState(EState state)  { -	LL_INFOS("Voice") << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << LL_ENDL; +	llinfos << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << llendl;  	if (mReceivedCall) // incoming call  	{ diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 573fab1f4f..941cccacc3 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -98,8 +98,7 @@ public:  	static LLVoiceChannel* getChannelByID(const LLUUID& session_id);  	static LLVoiceChannel* getChannelByURI(std::string uri); -	static LLVoiceChannel* getCurrentVoiceChannel(); -	 +	static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; }  	static void initClass();  	static void suspend(); diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index e067754e3e..2238acd643 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -1,6 +1,6 @@   /**    * @file llvoiceclient.cpp - * @brief Voice client delegation class implementation. + * @brief Implementation of LLVoiceClient class which is the interface to the voice client process.   *   * $LicenseInfo:firstyear=2001&license=viewergpl$   *  @@ -17,7 +17,8 @@   * 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://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, @@ -31,312 +32,5421 @@  #include "llviewerprecompiledheaders.h"  #include "llvoiceclient.h" -#include "llviewercontrol.h" -#include "llviewerwindow.h" -#include "llvoicedw.h" -#include "llvoicevivox.h" -#include "llviewernetwork.h" -#include "llhttpnode.h" + +#include <boost/tokenizer.hpp> + +// library includes  #include "llnotificationsutil.h"  #include "llsdserialize.h" -#include "llui.h" +#include "llsdutil.h" -const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f; -std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus) +// project includes +#include "llvoavatar.h" +#include "llbufferstream.h" +#include "llfile.h" +#ifdef LL_STANDALONE +# include "expat.h" +#else +# include "expat/expat.h" +#endif +#include "llcallbacklist.h" +#include "llcallingcard.h"   // for LLFriendObserver +#include "llviewerregion.h" +#include "llviewernetwork.h"		// for gGridChoice +#include "llbase64.h" +#include "llviewercontrol.h" +#include "llkeyboard.h" +#include "llappviewer.h"	// for gDisconnected, gDisableVoice +#include "llmutelist.h"  // to check for muted avatars +#include "llagent.h" +#include "llvoavatarself.h" +#include "llcachename.h" +#include "llimview.h" // for LLIMMgr +#include "llparcel.h" +#include "llviewerparcelmgr.h" +//#include "llfirstuse.h" +#include "llspeakers.h" +#include "lltrans.h" +#include "llviewerwindow.h" +#include "llviewercamera.h" +#include "llvoavatarself.h" +#include "llvoicechannel.h" + +// for base64 decoding +#include "apr_base64.h" + +// for SHA1 hash +#include "apr_sha1.h" + +// for MD5 hash +#include "llmd5.h" + +#define USE_SESSION_GROUPS 0 + +static bool sConnectingToAgni = false; +F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f; + +const F32 LLVoiceClient::VOLUME_MIN = 0.f; +const F32 LLVoiceClient::VOLUME_DEFAULT = 0.5f; +const F32 LLVoiceClient::VOLUME_MAX = 1.0f; + +const F32 VOLUME_SCALE_VIVOX = 0.01f; + +const F32 SPEAKING_TIMEOUT = 1.f; + +const int VOICE_MAJOR_VERSION = 1; +const int VOICE_MINOR_VERSION = 0; + +LLVoiceClient *gVoiceClient = NULL; + +// Don't retry connecting to the daemon more frequently than this: +const F32 CONNECT_THROTTLE_SECONDS = 1.0f; + +// Don't send positional updates more frequently than this: +const F32 UPDATE_THROTTLE_SECONDS = 0.1f; + +const F32 LOGIN_RETRY_SECONDS = 10.0f; +const int MAX_LOGIN_RETRIES = 12; + +// Defines the maximum number of times(in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine() +// which is treated as normal. If this number is exceeded we suspect there is a problem with connection +// to voice server (EXT-4313). When voice works correctly, there is from 1 to 15 times. 50 was chosen  +// to make sure we don't make mistake when slight connection problems happen- situation when connection to server is  +// blocked is VERY rare and it's better to sacrifice response time in this situation for the sake of stability. +const int MAX_NORMAL_JOINING_SPATIAL_NUM = 50; + +static void setUUIDFromStringHash(LLUUID &uuid, const std::string &str)  { -	std::string result = "UNKNOWN"; +	LLMD5 md5_uuid; +	md5_uuid.update((const unsigned char*)str.data(), str.size()); +	md5_uuid.finalize(); +	md5_uuid.raw_digest(uuid.mData); +} + +static int scale_mic_volume(float volume) +{ +	// incoming volume has the range [0.0 ... 2.0], with 1.0 as the default. +	// Map it to Vivox levels as follows: 0.0 -> 30, 1.0 -> 50, 2.0 -> 70 +	return 30 + (int)(volume * 20.0f); +} + +static int scale_speaker_volume(float volume) +{ +	// incoming volume has the range [0.0 ... 1.0], with 0.5 as the default. +	// Map it to Vivox levels as follows: 0.0 -> 30, 0.5 -> 50, 1.0 -> 70 +	return 30 + (int)(volume * 40.0f); +} + +class LLViewerVoiceAccountProvisionResponder : +	public LLHTTPClient::Responder +{ +public: +	LLViewerVoiceAccountProvisionResponder(int retries) +	{ +		mRetries = retries; +	} + +	virtual void error(U32 status, const std::string& reason) +	{ +		if ( mRetries > 0 ) +		{ +			LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, retrying.  status = " << status << ", reason = \"" << reason << "\"" << LL_ENDL; +			if ( gVoiceClient ) gVoiceClient->requestVoiceAccountProvision( +				mRetries - 1); +		} +		else +		{ +			LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, too many retries (giving up).  status = " << status << ", reason = \"" << reason << "\"" << LL_ENDL; +			if ( gVoiceClient ) gVoiceClient->giveUp(); +		} +	} + +	virtual void result(const LLSD& content) +	{ +		if ( gVoiceClient ) +		{ +			std::string voice_sip_uri_hostname; +			std::string voice_account_server_uri; +			 +			LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; +			 +			if(content.has("voice_sip_uri_hostname")) +				voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); +			 +			// this key is actually misnamed -- it will be an entire URI, not just a hostname. +			if(content.has("voice_account_server_name")) +				voice_account_server_uri = content["voice_account_server_name"].asString(); +			 +			gVoiceClient->login( +				content["username"].asString(), +				content["password"].asString(), +				voice_sip_uri_hostname, +				voice_account_server_uri); +		} +	} + +private: +	int mRetries; +}; + +/**  + * @class LLVivoxProtocolParser + * @brief This class helps construct new LLIOPipe specializations + * @see LLIOPipe + * + * THOROUGH_DESCRIPTION + */ +class LLVivoxProtocolParser : public LLIOPipe +{ +	LOG_CLASS(LLVivoxProtocolParser); +public: +	LLVivoxProtocolParser(); +	virtual ~LLVivoxProtocolParser(); + +protected: +	/* @name LLIOPipe virtual implementations +	 */ +	//@{ +	/**  +	 * @brief Process the data in buffer +	 */ +	virtual EStatus process_impl( +		const LLChannelDescriptors& channels, +		buffer_ptr_t& buffer, +		bool& eos, +		LLSD& context, +		LLPumpIO* pump); +	//@} -	// Prevent copy-paste errors when updating this list... -#define CASE(x)  case x:  result = #x;  break +	std::string 	mInput; -	switch(inStatus) +	// Expat control members +	XML_Parser		parser; +	int				responseDepth; +	bool			ignoringTags; +	bool			isEvent; +	int				ignoreDepth; + +	// Members for processing responses. The values are transient and only valid within a call to processResponse(). +	bool			squelchDebugOutput; +	int				returnCode; +	int				statusCode; +	std::string		statusString; +	std::string		requestId; +	std::string		actionString; +	std::string		connectorHandle; +	std::string		versionID; +	std::string		accountHandle; +	std::string		sessionHandle; +	std::string		sessionGroupHandle; +	std::string		alias; +	std::string		applicationString; + +	// Members for processing events. The values are transient and only valid within a call to processResponse(). +	std::string		eventTypeString; +	int				state; +	std::string		uriString; +	bool			isChannel; +	bool			incoming; +	bool			enabled; +	std::string		nameString; +	std::string		audioMediaString; +	std::string		displayNameString; +	std::string		deviceString; +	int				participantType; +	bool			isLocallyMuted; +	bool			isModeratorMuted; +	bool			isSpeaking; +	int				volume; +	F32				energy; +	std::string		messageHeader; +	std::string		messageBody; +	std::string		notificationType; +	bool			hasText; +	bool			hasAudio; +	bool			hasVideo; +	bool			terminated; +	std::string		blockMask; +	std::string		presenceOnly; +	std::string		autoAcceptMask; +	std::string		autoAddAsBuddy; +	int				numberOfAliases; +	std::string		subscriptionHandle; +	std::string		subscriptionType; +		 + +	// Members for processing text between tags +	std::string		textBuffer; +	bool			accumulateText; +	 +	void			reset(); + +	void			processResponse(std::string tag); + +static void XMLCALL ExpatStartTag(void *data, const char *el, const char **attr); +static void XMLCALL ExpatEndTag(void *data, const char *el); +static void XMLCALL ExpatCharHandler(void *data, const XML_Char *s, int len); + +	void			StartTag(const char *tag, const char **attr); +	void			EndTag(const char *tag); +	void			CharData(const char *buffer, int length); +	 +}; + +LLVivoxProtocolParser::LLVivoxProtocolParser() +{ +	parser = NULL; +	parser = XML_ParserCreate(NULL); +	 +	reset(); +} + +void LLVivoxProtocolParser::reset() +{ +	responseDepth = 0; +	ignoringTags = false; +	accumulateText = false; +	energy = 0.f; +	hasText = false; +	hasAudio = false; +	hasVideo = false; +	terminated = false; +	ignoreDepth = 0; +	isChannel = false; +	incoming = false; +	enabled = false; +	isEvent = false; +	isLocallyMuted = false; +	isModeratorMuted = false; +	isSpeaking = false; +	participantType = 0; +	squelchDebugOutput = false; +	returnCode = -1; +	state = 0; +	statusCode = 0; +	volume = 0; +	textBuffer.clear(); +	alias.clear(); +	numberOfAliases = 0; +	applicationString.clear(); +} + +//virtual  +LLVivoxProtocolParser::~LLVivoxProtocolParser() +{ +	if (parser) +		XML_ParserFree(parser); +} + +// virtual +LLIOPipe::EStatus LLVivoxProtocolParser::process_impl( +	const LLChannelDescriptors& channels, +	buffer_ptr_t& buffer, +	bool& eos, +	LLSD& context, +	LLPumpIO* pump) +{ +	LLBufferStream istr(channels, buffer.get()); +	std::ostringstream ostr; +	while (istr.good())  	{ -			CASE(STATUS_LOGIN_RETRY); -			CASE(STATUS_LOGGED_IN); -			CASE(STATUS_JOINING); -			CASE(STATUS_JOINED); -			CASE(STATUS_LEFT_CHANNEL); -			CASE(STATUS_VOICE_DISABLED); -			CASE(BEGIN_ERROR_STATUS); -			CASE(ERROR_CHANNEL_FULL); -			CASE(ERROR_CHANNEL_LOCKED); -			CASE(ERROR_NOT_AVAILABLE); -			CASE(ERROR_UNKNOWN); -		default: -			break; +		char buf[1024]; +		istr.read(buf, sizeof(buf)); +		mInput.append(buf, istr.gcount());  	} -#undef CASE +	// Look for input delimiter(s) in the input buffer.  If one is found, send the message to the xml parser. +	int start = 0; +	int delim; +	while((delim = mInput.find("\n\n\n", start)) != std::string::npos) +	{	 +		 +		// Reset internal state of the LLVivoxProtocolParser (no effect on the expat parser) +		reset(); +		 +		XML_ParserReset(parser, NULL); +		XML_SetElementHandler(parser, ExpatStartTag, ExpatEndTag); +		XML_SetCharacterDataHandler(parser, ExpatCharHandler); +		XML_SetUserData(parser, this);	 +		XML_Parse(parser, mInput.data() + start, delim - start, false); +		 +		// If this message isn't set to be squelched, output the raw XML received. +		if(!squelchDebugOutput) +		{ +			LL_DEBUGS("Voice") << "parsing: " << mInput.substr(start, delim - start) << LL_ENDL; +		} +		 +		start = delim + 3; +	} -	return result; +	if(start != 0) +		mInput = mInput.substr(start); + +	LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL; +	 +	if(!gVoiceClient->mConnected) +	{ +		// If voice has been disabled, we just want to close the socket.  This does so. +		LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL; +		return STATUS_STOP; +	} +	 +	return STATUS_OK; +} + +void XMLCALL LLVivoxProtocolParser::ExpatStartTag(void *data, const char *el, const char **attr) +{ +	if (data) +	{ +		LLVivoxProtocolParser	*object = (LLVivoxProtocolParser*)data; +		object->StartTag(el, attr); +	} +} + +// -------------------------------------------------------------------------------- + +void XMLCALL LLVivoxProtocolParser::ExpatEndTag(void *data, const char *el) +{ +	if (data) +	{ +		LLVivoxProtocolParser	*object = (LLVivoxProtocolParser*)data; +		object->EndTag(el); +	} +} + +// -------------------------------------------------------------------------------- + +void XMLCALL LLVivoxProtocolParser::ExpatCharHandler(void *data, const XML_Char *s, int len) +{ +	if (data) +	{ +		LLVivoxProtocolParser	*object = (LLVivoxProtocolParser*)data; +		object->CharData(s, len); +	} +} + +// -------------------------------------------------------------------------------- + + +void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) +{ +	// Reset the text accumulator. We shouldn't have strings that are inturrupted by new tags +	textBuffer.clear(); +	// only accumulate text if we're not ignoring tags. +	accumulateText = !ignoringTags; +	 +	if (responseDepth == 0) +	{	 +		isEvent = !stricmp("Event", tag); +		 +		if (!stricmp("Response", tag) || isEvent) +		{ +			// Grab the attributes +			while (*attr) +			{ +				const char	*key = *attr++; +				const char	*value = *attr++; +				 +				if (!stricmp("requestId", key)) +				{ +					requestId = value; +				} +				else if (!stricmp("action", key)) +				{ +					actionString = value; +				} +				else if (!stricmp("type", key)) +				{ +					eventTypeString = value; +				} +			} +		} +		LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")"  << LL_ENDL; +	} +	else +	{ +		if (ignoringTags) +		{ +			LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL; +		} +		else +		{ +			LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")"  << LL_ENDL; +	 +			// Ignore the InputXml stuff so we don't get confused +			if (!stricmp("InputXml", tag)) +			{ +				ignoringTags = true; +				ignoreDepth = responseDepth; +				accumulateText = false; + +				LL_DEBUGS("VivoxProtocolParser") << "starting ignore, ignoreDepth is " << ignoreDepth << LL_ENDL; +			} +			else if (!stricmp("CaptureDevices", tag)) +			{ +				gVoiceClient->clearCaptureDevices(); +			} +			else if (!stricmp("RenderDevices", tag)) +			{ +				gVoiceClient->clearRenderDevices(); +			} +			else if (!stricmp("CaptureDevice", tag)) +			{ +				deviceString.clear(); +			} +			else if (!stricmp("RenderDevice", tag)) +			{ +				deviceString.clear(); +			} +			else if (!stricmp("Buddies", tag)) +			{ +				gVoiceClient->deleteAllBuddies(); +			} +			else if (!stricmp("BlockRules", tag)) +			{ +				gVoiceClient->deleteAllBlockRules(); +			} +			else if (!stricmp("AutoAcceptRules", tag)) +			{ +				gVoiceClient->deleteAllAutoAcceptRules(); +			} +			 +		} +	} +	responseDepth++; +} + +// -------------------------------------------------------------------------------- + +void LLVivoxProtocolParser::EndTag(const char *tag) +{ +	const std::string& string = textBuffer; + +	responseDepth--; + +	if (ignoringTags) +	{ +		if (ignoreDepth == responseDepth) +		{ +			LL_DEBUGS("VivoxProtocolParser") << "end of ignore" << LL_ENDL; +			ignoringTags = false; +		} +		else +		{ +			LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL; +		} +	} +	 +	if (!ignoringTags) +	{ +		LL_DEBUGS("VivoxProtocolParser") << "processing tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL; + +		// Closing a tag. Finalize the text we've accumulated and reset +		if (!stricmp("ReturnCode", tag)) +			returnCode = strtol(string.c_str(), NULL, 10); +		else if (!stricmp("SessionHandle", tag)) +			sessionHandle = string; +		else if (!stricmp("SessionGroupHandle", tag)) +			sessionGroupHandle = string; +		else if (!stricmp("StatusCode", tag)) +			statusCode = strtol(string.c_str(), NULL, 10); +		else if (!stricmp("StatusString", tag)) +			statusString = string; +		else if (!stricmp("ParticipantURI", tag)) +			uriString = string; +		else if (!stricmp("Volume", tag)) +			volume = strtol(string.c_str(), NULL, 10); +		else if (!stricmp("Energy", tag)) +			energy = (F32)strtod(string.c_str(), NULL); +		else if (!stricmp("IsModeratorMuted", tag)) +			isModeratorMuted = !stricmp(string.c_str(), "true"); +		else if (!stricmp("IsSpeaking", tag)) +			isSpeaking = !stricmp(string.c_str(), "true"); +		else if (!stricmp("Alias", tag)) +			alias = string; +		else if (!stricmp("NumberOfAliases", tag)) +			numberOfAliases = strtol(string.c_str(), NULL, 10); +		else if (!stricmp("Application", tag)) +			applicationString = string; +		else if (!stricmp("ConnectorHandle", tag)) +			connectorHandle = string; +		else if (!stricmp("VersionID", tag)) +			versionID = string; +		else if (!stricmp("AccountHandle", tag)) +			accountHandle = string; +		else if (!stricmp("State", tag)) +			state = strtol(string.c_str(), NULL, 10); +		else if (!stricmp("URI", tag)) +			uriString = string; +		else if (!stricmp("IsChannel", tag)) +			isChannel = !stricmp(string.c_str(), "true"); +		else if (!stricmp("Incoming", tag)) +			incoming = !stricmp(string.c_str(), "true"); +		else if (!stricmp("Enabled", tag)) +			enabled = !stricmp(string.c_str(), "true"); +		else if (!stricmp("Name", tag)) +			nameString = string; +		else if (!stricmp("AudioMedia", tag)) +			audioMediaString = string; +		else if (!stricmp("ChannelName", tag)) +			nameString = string; +		else if (!stricmp("DisplayName", tag)) +			displayNameString = string; +		else if (!stricmp("Device", tag)) +			deviceString = string; +		else if (!stricmp("AccountName", tag)) +			nameString = string; +		else if (!stricmp("ParticipantType", tag)) +			participantType = strtol(string.c_str(), NULL, 10); +		else if (!stricmp("IsLocallyMuted", tag)) +			isLocallyMuted = !stricmp(string.c_str(), "true"); +		else if (!stricmp("MicEnergy", tag)) +			energy = (F32)strtod(string.c_str(), NULL); +		else if (!stricmp("ChannelName", tag)) +			nameString = string; +		else if (!stricmp("ChannelURI", tag)) +			uriString = string; +		else if (!stricmp("BuddyURI", tag)) +			uriString = string; +		else if (!stricmp("Presence", tag)) +			statusString = string; +		else if (!stricmp("CaptureDevice", tag)) +		{ +			gVoiceClient->addCaptureDevice(deviceString); +		} +		else if (!stricmp("RenderDevice", tag)) +		{ +			gVoiceClient->addRenderDevice(deviceString); +		} +		else if (!stricmp("Buddy", tag)) +		{ +			gVoiceClient->processBuddyListEntry(uriString, displayNameString); +		} +		else if (!stricmp("BlockRule", tag)) +		{ +			gVoiceClient->addBlockRule(blockMask, presenceOnly); +		} +		else if (!stricmp("BlockMask", tag)) +			blockMask = string; +		else if (!stricmp("PresenceOnly", tag)) +			presenceOnly = string; +		else if (!stricmp("AutoAcceptRule", tag)) +		{ +			gVoiceClient->addAutoAcceptRule(autoAcceptMask, autoAddAsBuddy); +		} +		else if (!stricmp("AutoAcceptMask", tag)) +			autoAcceptMask = string; +		else if (!stricmp("AutoAddAsBuddy", tag)) +			autoAddAsBuddy = string; +		else if (!stricmp("MessageHeader", tag)) +			messageHeader = string; +		else if (!stricmp("MessageBody", tag)) +			messageBody = string; +		else if (!stricmp("NotificationType", tag)) +			notificationType = string; +		else if (!stricmp("HasText", tag)) +			hasText = !stricmp(string.c_str(), "true"); +		else if (!stricmp("HasAudio", tag)) +			hasAudio = !stricmp(string.c_str(), "true"); +		else if (!stricmp("HasVideo", tag)) +			hasVideo = !stricmp(string.c_str(), "true"); +		else if (!stricmp("Terminated", tag)) +			terminated = !stricmp(string.c_str(), "true"); +		else if (!stricmp("SubscriptionHandle", tag)) +			subscriptionHandle = string; +		else if (!stricmp("SubscriptionType", tag)) +			subscriptionType = string; +		 +		textBuffer.clear(); +		accumulateText= false; +		 +		if (responseDepth == 0) +		{ +			// We finished all of the XML, process the data +			processResponse(tag); +		} +	} +} + +// -------------------------------------------------------------------------------- + +void LLVivoxProtocolParser::CharData(const char *buffer, int length) +{ +	/* +		This method is called for anything that isn't a tag, which can be text you +		want that lies between tags, and a lot of stuff you don't want like file formatting +		(tabs, spaces, CR/LF, etc). +		 +		Only copy text if we are in accumulate mode... +	*/ +	if (accumulateText) +		textBuffer.append(buffer, length); +} + +// -------------------------------------------------------------------------------- + +void LLVivoxProtocolParser::processResponse(std::string tag) +{ +	LL_DEBUGS("VivoxProtocolParser") << tag << LL_ENDL; + +	// SLIM SDK: the SDK now returns a statusCode of "200" (OK) for success.  This is a change vs. previous SDKs. +	// According to Mike S., "The actual API convention is that responses with return codes of 0 are successful, regardless of the status code returned", +	// so I believe this will give correct behavior. +	 +	if(returnCode == 0) +		statusCode = 0; +		 +	if (isEvent) +	{ +		const char *eventTypeCstr = eventTypeString.c_str(); +		if (!stricmp(eventTypeCstr, "AccountLoginStateChangeEvent")) +		{ +			gVoiceClient->accountLoginStateChangeEvent(accountHandle, statusCode, statusString, state); +		} +		else if (!stricmp(eventTypeCstr, "SessionAddedEvent")) +		{ +			/* +			<Event type="SessionAddedEvent"> +				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> +				<SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle> +				<Uri>sip:confctl-1408789@bhr.vivox.com</Uri> +				<IsChannel>true</IsChannel> +				<Incoming>false</Incoming> +				<ChannelName /> +			</Event> +			*/ +			gVoiceClient->sessionAddedEvent(uriString, alias, sessionHandle, sessionGroupHandle, isChannel, incoming, nameString, applicationString); +		} +		else if (!stricmp(eventTypeCstr, "SessionRemovedEvent")) +		{ +			gVoiceClient->sessionRemovedEvent(sessionHandle, sessionGroupHandle); +		} +		else if (!stricmp(eventTypeCstr, "SessionGroupAddedEvent")) +		{ +			gVoiceClient->sessionGroupAddedEvent(sessionGroupHandle); +		} +		else if (!stricmp(eventTypeCstr, "MediaStreamUpdatedEvent")) +		{ +			/* +			<Event type="MediaStreamUpdatedEvent"> +				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> +				<SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle> +				<StatusCode>200</StatusCode> +				<StatusString>OK</StatusString> +				<State>2</State> +				<Incoming>false</Incoming> +			</Event> +			*/ +			gVoiceClient->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming); +		}		 +		else if (!stricmp(eventTypeCstr, "TextStreamUpdatedEvent")) +		{ +			/* +			<Event type="TextStreamUpdatedEvent"> +				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg1</SessionGroupHandle> +				<SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==1</SessionHandle> +				<Enabled>true</Enabled> +				<State>1</State> +				<Incoming>true</Incoming> +			</Event> +			*/ +			gVoiceClient->textStreamUpdatedEvent(sessionHandle, sessionGroupHandle, enabled, state, incoming); +		} +		else if (!stricmp(eventTypeCstr, "ParticipantAddedEvent")) +		{ +			/*  +			<Event type="ParticipantAddedEvent"> +				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle> +				<SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle> +				<ParticipantUri>sip:xI5auBZ60SJWIk606-1JGRQ==@bhr.vivox.com</ParticipantUri> +				<AccountName>xI5auBZ60SJWIk606-1JGRQ==</AccountName> +				<DisplayName /> +				<ParticipantType>0</ParticipantType> +			</Event> +			*/ +			gVoiceClient->participantAddedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString, displayNameString, participantType); +		} +		else if (!stricmp(eventTypeCstr, "ParticipantRemovedEvent")) +		{ +			/* +			<Event type="ParticipantRemovedEvent"> +				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle> +				<SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle> +				<ParticipantUri>sip:xtx7YNV-3SGiG7rA1fo5Ndw==@bhr.vivox.com</ParticipantUri> +				<AccountName>xtx7YNV-3SGiG7rA1fo5Ndw==</AccountName> +			</Event> +			*/ +			gVoiceClient->participantRemovedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString); +		} +		else if (!stricmp(eventTypeCstr, "ParticipantUpdatedEvent")) +		{ +			/* +			<Event type="ParticipantUpdatedEvent"> +				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> +				<SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle> +				<ParticipantUri>sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com</ParticipantUri> +				<IsModeratorMuted>false</IsModeratorMuted> +				<IsSpeaking>true</IsSpeaking> +				<Volume>44</Volume> +				<Energy>0.0879437</Energy> +			</Event> +			*/ +			 +			// These happen so often that logging them is pretty useless. +			squelchDebugOutput = true; +			 +			gVoiceClient->participantUpdatedEvent(sessionHandle, sessionGroupHandle, uriString, alias, isModeratorMuted, isSpeaking, volume, energy); +		} +		else if (!stricmp(eventTypeCstr, "AuxAudioPropertiesEvent")) +		{ +			gVoiceClient->auxAudioPropertiesEvent(energy); +		} +		else if (!stricmp(eventTypeCstr, "BuddyPresenceEvent")) +		{ +			gVoiceClient->buddyPresenceEvent(uriString, alias, statusString, applicationString); +		} +		else if (!stricmp(eventTypeCstr, "BuddyAndGroupListChangedEvent")) +		{ +			// The buddy list was updated during parsing. +			// Need to recheck against the friends list. +			gVoiceClient->buddyListChanged(); +		} +		else if (!stricmp(eventTypeCstr, "BuddyChangedEvent")) +		{ +			/* +			<Event type="BuddyChangedEvent"> +				<AccountHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==</AccountHandle> +				<BuddyURI>sip:x9fFHFZjOTN6OESF1DUPrZQ==@bhr.vivox.com</BuddyURI> +				<DisplayName>Monroe Tester</DisplayName> +				<BuddyData /> +				<GroupID>0</GroupID> +				<ChangeType>Set</ChangeType> +			</Event> +			*/		 +			// TODO: Question: Do we need to process this at all? +		} +		else if (!stricmp(eventTypeCstr, "MessageEvent"))   +		{ +			gVoiceClient->messageEvent(sessionHandle, uriString, alias, messageHeader, messageBody, applicationString); +		} +		else if (!stricmp(eventTypeCstr, "SessionNotificationEvent"))   +		{ +			gVoiceClient->sessionNotificationEvent(sessionHandle, uriString, notificationType); +		} +		else if (!stricmp(eventTypeCstr, "SubscriptionEvent"))   +		{ +			gVoiceClient->subscriptionEvent(uriString, subscriptionHandle, alias, displayNameString, applicationString, subscriptionType); +		} +		else if (!stricmp(eventTypeCstr, "SessionUpdatedEvent"))   +		{ +			/* +			<Event type="SessionUpdatedEvent"> +				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> +				<SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle> +				<Uri>sip:confctl-9@bhd.vivox.com</Uri> +				<IsMuted>0</IsMuted> +				<Volume>50</Volume> +				<TransmitEnabled>1</TransmitEnabled> +				<IsFocused>0</IsFocused> +				<SpeakerPosition><Position><X>0</X><Y>0</Y><Z>0</Z></Position></SpeakerPosition> +				<SessionFontID>0</SessionFontID> +			</Event> +			*/ +			// We don't need to process this, but we also shouldn't warn on it, since that confuses people. +		} +		 +		else if (!stricmp(eventTypeCstr, "SessionGroupRemovedEvent"))   +		{ +			/* +			<Event type="SessionGroupRemovedEvent"> +				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> +			</Event> +			*/ +			// We don't need to process this, but we also shouldn't warn on it, since that confuses people. +		} +		else +		{ +			LL_WARNS("VivoxProtocolParser") << "Unknown event type " << eventTypeString << LL_ENDL; +		} +	} +	else +	{ +		const char *actionCstr = actionString.c_str(); +		if (!stricmp(actionCstr, "Connector.Create.1")) +		{ +			gVoiceClient->connectorCreateResponse(statusCode, statusString, connectorHandle, versionID); +		} +		else if (!stricmp(actionCstr, "Account.Login.1")) +		{ +			gVoiceClient->loginResponse(statusCode, statusString, accountHandle, numberOfAliases); +		} +		else if (!stricmp(actionCstr, "Session.Create.1")) +		{ +			gVoiceClient->sessionCreateResponse(requestId, statusCode, statusString, sessionHandle);			 +		} +		else if (!stricmp(actionCstr, "SessionGroup.AddSession.1")) +		{ +			gVoiceClient->sessionGroupAddSessionResponse(requestId, statusCode, statusString, sessionHandle);			 +		} +		else if (!stricmp(actionCstr, "Session.Connect.1")) +		{ +			gVoiceClient->sessionConnectResponse(requestId, statusCode, statusString);			 +		} +		else if (!stricmp(actionCstr, "Account.Logout.1")) +		{ +			gVoiceClient->logoutResponse(statusCode, statusString);			 +		} +		else if (!stricmp(actionCstr, "Connector.InitiateShutdown.1")) +		{ +			gVoiceClient->connectorShutdownResponse(statusCode, statusString);			 +		} +		else if (!stricmp(actionCstr, "Account.ListBlockRules.1")) +		{ +			gVoiceClient->accountListBlockRulesResponse(statusCode, statusString);						 +		} +		else if (!stricmp(actionCstr, "Account.ListAutoAcceptRules.1")) +		{ +			gVoiceClient->accountListAutoAcceptRulesResponse(statusCode, statusString);						 +		} +		else if (!stricmp(actionCstr, "Session.Set3DPosition.1")) +		{ +			// We don't need to process these, but they're so spammy we don't want to log them. +			squelchDebugOutput = true; +		} +/* +		else if (!stricmp(actionCstr, "Account.ChannelGetList.1")) +		{ +			gVoiceClient->channelGetListResponse(statusCode, statusString); +		} +		else if (!stricmp(actionCstr, "Connector.AccountCreate.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Connector.MuteLocalMic.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Connector.MuteLocalSpeaker.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Connector.SetLocalMicVolume.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Connector.SetLocalSpeakerVolume.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Session.ListenerSetPosition.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Session.SpeakerSetPosition.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Session.AudioSourceSetPosition.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Session.GetChannelParticipants.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelCreate.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelUpdate.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelDelete.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelCreateAndInvite.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelFolderCreate.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelFolderUpdate.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelFolderDelete.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelAddModerator.1")) +		{ +			 +		} +		else if (!stricmp(actionCstr, "Account.ChannelDeleteModerator.1")) +		{ +			 +		} +*/ +	}  } +/////////////////////////////////////////////////////////////////////////////////////////////// +class LLVoiceClientMuteListObserver : public LLMuteListObserver +{ +	/* virtual */ void onChange()  { gVoiceClient->muteListChanged();} +}; + +class LLVoiceClientFriendsObserver : public LLFriendObserver +{ +public: +	/* virtual */ void changed(U32 mask) { gVoiceClient->updateFriends(mask);} +}; + +static LLVoiceClientMuteListObserver mutelist_listener; +static bool sMuteListListener_listening = false; +static LLVoiceClientFriendsObserver *friendslist_listener = NULL;  /////////////////////////////////////////////////////////////////////////////////////////////// -LLVoiceClient::LLVoiceClient() +class LLVoiceClientCapResponder : public LLHTTPClient::Responder +{ +public: +	LLVoiceClientCapResponder(void){}; + +	virtual void error(U32 status, const std::string& reason);	// called with bad status codes +	virtual void result(const LLSD& content); + +private: +}; + +void LLVoiceClientCapResponder::error(U32 status, const std::string& reason)  { -	mVoiceModule = NULL; +	LL_WARNS("Voice") << "LLVoiceClientCapResponder::error(" +		<< status << ": " << reason << ")" +		<< LL_ENDL; +} + +void LLVoiceClientCapResponder::result(const LLSD& content) +{ +	LLSD::map_const_iterator iter; +	 +	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; + +	if ( content.has("voice_credentials") ) +	{ +		LLSD voice_credentials = content["voice_credentials"]; +		std::string uri; +		std::string credentials; + +		if ( voice_credentials.has("channel_uri") ) +		{ +			uri = voice_credentials["channel_uri"].asString(); +		} +		if ( voice_credentials.has("channel_credentials") ) +		{ +			credentials = +				voice_credentials["channel_credentials"].asString(); +		} + +		gVoiceClient->setSpatialChannel(uri, credentials); +	} +} + + + +#if LL_WINDOWS +static HANDLE sGatewayHandle = 0; + +static bool isGatewayRunning() +{ +	bool result = false; +	if(sGatewayHandle != 0)		 +	{ +		DWORD waitresult = WaitForSingleObject(sGatewayHandle, 0); +		if(waitresult != WAIT_OBJECT_0) +		{ +			result = true; +		}			 +	} +	return result; +} +static void killGateway() +{ +	if(sGatewayHandle != 0) +	{ +		TerminateProcess(sGatewayHandle,0); +	} +} + +#else // Mac and linux + +static pid_t sGatewayPID = 0; +static bool isGatewayRunning() +{ +	bool result = false; +	if(sGatewayPID != 0) +	{ +		// A kill with signal number 0 has no effect, just does error checking.  It should return an error if the process no longer exists. +		if(kill(sGatewayPID, 0) == 0) +		{ +			result = true; +		} +	} +	return result; +} + +static void killGateway() +{ +	if(sGatewayPID != 0) +	{ +		kill(sGatewayPID, SIGTERM); +	} +} + +#endif + +class LLSpeakerVolumeStorage : public LLSingleton<LLSpeakerVolumeStorage> +{ +	LOG_CLASS(LLSpeakerVolumeStorage); +public: + +	/** +	 * Stores volume level for specified user. +	 * +	 * @param[in] speaker_id - LLUUID of user to store volume level for. +	 * @param[in] volume - volume level to be stored for user. +	 */ +	void storeSpeakerVolume(const LLUUID& speaker_id, F32 volume); + +	/** +	 * Gets stored volume level for specified speaker +	 * +	 * @param[in] speaker_id - LLUUID of user to retrieve volume level for. +	 * @param[out] volume - set to stored volume if found, otherwise unmodified. +	 * @return - true if a stored volume is found. +	 */ +	bool getSpeakerVolume(const LLUUID& speaker_id, F32& volume); + +	/** +	 * Removes stored volume level for specified user. +	 * +	 * @param[in] speaker_id - LLUUID of user to remove. +	 */ +	void removeSpeakerVolume(const LLUUID& speaker_id); + +private: +	friend class LLSingleton<LLSpeakerVolumeStorage>; +	LLSpeakerVolumeStorage(); +	~LLSpeakerVolumeStorage(); + +	const static std::string SETTINGS_FILE_NAME; + +	void load(); +	void save(); + +	static F32 transformFromLegacyVolume(F32 volume_in); +	static F32 transformToLegacyVolume(F32 volume_in); + +	typedef std::map<LLUUID, F32> speaker_data_map_t; +	speaker_data_map_t mSpeakersData; +}; + +const std::string LLSpeakerVolumeStorage::SETTINGS_FILE_NAME = "volume_settings.xml"; + +LLSpeakerVolumeStorage::LLSpeakerVolumeStorage() +{ +	load(); +} + +LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage() +{ +	save(); +} + +void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume) +{ +	if ((volume >= LLVoiceClient::VOLUME_MIN) && (volume <= LLVoiceClient::VOLUME_MAX)) +	{ +		mSpeakersData[speaker_id] = volume; + +		// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. +		// LL_DEBUGS("Voice") << "Stored volume = " << volume <<  " for " << id << LL_ENDL; +	} +	else +	{ +		LL_WARNS("Voice") << "Attempted to store out of range volume " << volume << " for " << speaker_id << LL_ENDL; +		llassert(0); +	} +} + +bool LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id, F32& volume) +{ +	speaker_data_map_t::const_iterator it = mSpeakersData.find(speaker_id); +	 +	if (it != mSpeakersData.end()) +	{ +		volume = it->second; + +		// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. +		// LL_DEBUGS("Voice") << "Retrieved stored volume = " << volume <<  " for " << id << LL_ENDL; + +		return true; +	} + +	return false; +} + +void LLSpeakerVolumeStorage::removeSpeakerVolume(const LLUUID& speaker_id) +{ +	mSpeakersData.erase(speaker_id); + +	// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. +	// LL_DEBUGS("Voice") << "Removing stored volume for  " << id << LL_ENDL; +} + +/* static */ F32 LLSpeakerVolumeStorage::transformFromLegacyVolume(F32 volume_in) +{ +	// Convert to linear-logarithmic [0.0..1.0] with 0.5 = 0dB +	// from legacy characteristic composed of two square-curves +	// that intersect at volume_in = 0.5, volume_out = 0.56 + +	F32 volume_out = 0.f; +	volume_in = llclamp(volume_in, 0.f, 1.0f); + +	if (volume_in <= 0.5f) +	{ +		volume_out = volume_in * volume_in * 4.f * 0.56f; +	} +	else +	{ +		volume_out = (1.f - 0.56f) * (4.f * volume_in * volume_in - 1.f) / 3.f + 0.56f; +	} + +	return volume_out; +} + +/* static */ F32 LLSpeakerVolumeStorage::transformToLegacyVolume(F32 volume_in) +{ +	// Convert from linear-logarithmic [0.0..1.0] with 0.5 = 0dB +	// to legacy characteristic composed of two square-curves +	// that intersect at volume_in = 0.56, volume_out = 0.5 + +	F32 volume_out = 0.f; +	volume_in = llclamp(volume_in, 0.f, 1.0f); + +	if (volume_in <= 0.56f) +	{ +		volume_out = sqrt(volume_in / (4.f * 0.56f)); +	} +	else +	{ +		volume_out = sqrt((3.f * (volume_in - 0.56f) / (1.f - 0.56f) + 1.f) / 4.f); +	} + +	return volume_out; +} + +void LLSpeakerVolumeStorage::load() +{ +	// load per-resident voice volume information +	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME); + +	LL_INFOS("Voice") << "Loading stored speaker volumes from: " << filename << LL_ENDL; + +	LLSD settings_llsd; +	llifstream file; +	file.open(filename); +	if (file.is_open()) +	{ +		LLSDSerialize::fromXML(settings_llsd, file); +	} + +	for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); +		iter != settings_llsd.endMap(); ++iter) +	{ +		// Maintain compatibility with 1.23 non-linear saved volume levels +		F32 volume = transformFromLegacyVolume((F32)iter->second.asReal()); + +		storeSpeakerVolume(LLUUID(iter->first), volume); +	} +} + +void LLSpeakerVolumeStorage::save() +{ +	// If we quit from the login screen we will not have an SL account +	// name.  Don't try to save, otherwise we'll dump a file in +	// C:\Program Files\SecondLife\ or similar. JC +	std::string user_dir = gDirUtilp->getLindenUserDir(); +	if (!user_dir.empty()) +	{ +		std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME); +		LLSD settings_llsd; + +		LL_INFOS("Voice") << "Saving stored speaker volumes to: " << filename << LL_ENDL; + +		for(speaker_data_map_t::const_iterator iter = mSpeakersData.begin(); iter != mSpeakersData.end(); ++iter) +		{ +			// Maintain compatibility with 1.23 non-linear saved volume levels +			F32 volume = transformToLegacyVolume(iter->second); + +			settings_llsd[iter->first.asString()] = volume; +		} + +		llofstream file; +		file.open(filename); +		LLSDSerialize::toPrettyXML(settings_llsd, file); +	} +} + + +/////////////////////////////////////////////////////////////////////////////////////////////// + +LLVoiceClient::LLVoiceClient() : +	mState(stateDisabled), +	mSessionTerminateRequested(false), +	mRelogRequested(false), +	mConnected(false), +	mPump(NULL), +	mSpatialJoiningNum(0), +	 +	mTuningMode(false), +	mTuningEnergy(0.0f), +	mTuningMicVolume(0), +	mTuningMicVolumeDirty(true), +	mTuningSpeakerVolume(0), +	mTuningSpeakerVolumeDirty(true), +	mTuningExitState(stateDisabled), +	 +	mAreaVoiceDisabled(false), +	mAudioSession(NULL), +	mAudioSessionChanged(false), +	mNextAudioSession(NULL), +	 +	mCurrentParcelLocalID(0), +	mNumberOfAliases(0), +	mCommandCookie(0), +	mLoginRetryCount(0), +	 +	mBuddyListMapPopulated(false), +	mBlockRulesListReceived(false), +	mAutoAcceptRulesListReceived(false), +	mCaptureDeviceDirty(false), +	mRenderDeviceDirty(false), +	mSpatialCoordsDirty(false), + +	mPTTDirty(true), +	mPTT(true), +	mUsePTT(true), +	mPTTIsMiddleMouse(false), +	mPTTKey(0), +	mPTTIsToggle(false), +	mUserPTTState(false), +	mMuteMic(false), +	mFriendsListDirty(true), +	 +	mEarLocation(0), +	mSpeakerVolumeDirty(true), +	mSpeakerMuteDirty(true), +	mMicVolume(0), +	mMicVolumeDirty(true), +	 +	mVoiceEnabled(false), +	mWriteInProgress(false), +	 +	mLipSyncEnabled(false) +{	 +	gVoiceClient = this; +	 +	mAPIVersion = LLTrans::getString("NotConnected"); + +	mSpeakerVolume = scale_speaker_volume(0); +	 +#if LL_DARWIN || LL_LINUX || LL_SOLARIS +		// HACK: THIS DOES NOT BELONG HERE +		// When the vivox daemon dies, the next write attempt on our socket generates a SIGPIPE, which kills us. +		// This should cause us to ignore SIGPIPE and handle the error through proper channels. +		// This should really be set up elsewhere.  Where should it go? +		signal(SIGPIPE, SIG_IGN); +		 +		// Since we're now launching the gateway with fork/exec instead of system(), we need to deal with zombie processes. +		// Ignoring SIGCHLD should prevent zombies from being created.  Alternately, we could use wait(), but I'd rather not do that. +		signal(SIGCHLD, SIG_IGN); +#endif + +	// set up state machine +	setState(stateDisabled); +	 +	gIdleCallbacks.addFunction(idle, this);  }  //--------------------------------------------------- -// Basic setup/shutdown  LLVoiceClient::~LLVoiceClient()  {  } +//---------------------------------------------- +  void LLVoiceClient::init(LLPumpIO *pump)  { -	// Initialize all of the voice modules -	m_servicePump = pump; +	// constructor will set up gVoiceClient +	LLVoiceClient::getInstance()->mPump = pump; +	LLVoiceClient::getInstance()->updateSettings();  } -void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID) +void LLVoiceClient::terminate()  { -	// In the future, we should change this to allow voice module registration -	// with a table lookup of sorts. -	std::string voice_server = gSavedSettings.getString("VoiceServerType"); -	LL_DEBUGS("Voice") << "voice server type " << voice_server << LL_ENDL; -	if(voice_server == "diamondware") +	if(gVoiceClient)  	{ -		mVoiceModule = (LLVoiceModuleInterface *)LLDiamondwareVoiceClient::getInstance(); +//		gVoiceClient->leaveAudioSession(); +		gVoiceClient->logout(); +		// As of SDK version 4885, this should no longer be necessary.  It will linger after the socket close if it needs to. +		// ms_sleep(2000); +		gVoiceClient->connectorShutdown(); +		gVoiceClient->closeSocket();		// Need to do this now -- bad things happen if the destructor does it later. +		 +		// This will do unpleasant things on windows. +//		killGateway(); +		 +		// Don't do this anymore -- LLSingleton will take care of deleting the object.		 +//		delete gVoiceClient; +		 +		// Hint to other code not to access the voice client anymore. +		gVoiceClient = NULL; +	} +} + +//--------------------------------------------------- + +void LLVoiceClient::updateSettings() +{ +	setVoiceEnabled(gSavedSettings.getBOOL("EnableVoiceChat")); +	setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled")); +	std::string keyString = gSavedSettings.getString("PushToTalkButton"); +	setPTTKey(keyString); +	setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle")); +	setEarLocation(gSavedSettings.getS32("VoiceEarLocation")); + +	std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice"); +	setCaptureDevice(inputDevice); +	std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice"); +	setRenderDevice(outputDevice); +	F32 mic_level = gSavedSettings.getF32("AudioLevelMic"); +	setMicGain(mic_level); +	setLipSyncEnabled(gSavedSettings.getBOOL("LipSyncEnabled")); +} + +///////////////////////////// +// utility functions + +bool LLVoiceClient::writeString(const std::string &str) +{ +	bool result = false; +	if(mConnected) +	{ +		apr_status_t err; +		apr_size_t size = (apr_size_t)str.size(); +		apr_size_t written = size; +	 +		//MARK: Turn this on to log outgoing XML +//		LL_DEBUGS("Voice") << "sending: " << str << LL_ENDL; + +		// check return code - sockets will fail (broken, etc.) +		err = apr_socket_send( +				mSocket->getSocket(), +				(const char*)str.data(), +				&written); +		 +		if(err == 0) +		{ +			// Success. +			result = true; +		} +		// TODO: handle partial writes (written is number of bytes written) +		// Need to set socket to non-blocking before this will work. +//		else if(APR_STATUS_IS_EAGAIN(err)) +//		{ +//			//  +//		} +		else +		{ +			// Assume any socket error means something bad.  For now, just close the socket. +			char buf[MAX_STRING]; +			LL_WARNS("Voice") << "apr error " << err << " ("<< apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << LL_ENDL; +			daemonDied(); +		} +	} +		 +	return result; +} + + +///////////////////////////// +// session control messages +void LLVoiceClient::connectorCreate() +{ +	std::ostringstream stream; +	std::string logpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); +	std::string loglevel = "0"; +	 +	// Transition to stateConnectorStarted when the connector handle comes back. +	setState(stateConnectorStarting); + +	std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel"); +		 +	if(savedLogLevel != "-1") +	{ +		LL_DEBUGS("Voice") << "creating connector with logging enabled" << LL_ENDL; +		loglevel = "10"; +	} +	 +	stream  +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.Create.1\">" +		<< "<ClientName>V2 SDK</ClientName>" +		<< "<AccountManagementServer>" << mVoiceAccountServerURI << "</AccountManagementServer>" +		<< "<Mode>Normal</Mode>" +		<< "<Logging>" +			<< "<Folder>" << logpath << "</Folder>" +			<< "<FileNamePrefix>Connector</FileNamePrefix>" +			<< "<FileNameSuffix>.log</FileNameSuffix>" +			<< "<LogLevel>" << loglevel << "</LogLevel>" +		<< "</Logging>" +		<< "<Application>SecondLifeViewer.1</Application>" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::connectorShutdown() +{ +	setState(stateConnectorStopping); +	 +	if(!mConnectorHandle.empty()) +	{ +		std::ostringstream stream; +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.InitiateShutdown.1\">" +			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" +		<< "</Request>" +		<< "\n\n\n"; +		 +		mConnectorHandle.clear(); +		 +		writeString(stream.str()); +	} +} + +void LLVoiceClient::userAuthorized(const std::string& firstName, const std::string& lastName, const LLUUID &agentID) +{ +	mAccountFirstName = firstName; +	mAccountLastName = lastName; + +	mAccountDisplayName = firstName; +	mAccountDisplayName += " "; +	mAccountDisplayName += lastName; + +	LL_INFOS("Voice") << "name \"" << mAccountDisplayName << "\" , ID " << agentID << LL_ENDL; + +	sConnectingToAgni = LLViewerLogin::getInstance()->isInProductionGrid(); + +	mAccountName = nameFromID(agentID); +} + +void LLVoiceClient::requestVoiceAccountProvision(S32 retries) +{ +	if ( gAgent.getRegion() && mVoiceEnabled ) +	{ +		std::string url =  +			gAgent.getRegion()->getCapability( +				"ProvisionVoiceAccountRequest"); + +		if ( url == "" ) return; + +		LLHTTPClient::post( +			url, +			LLSD(), +			new LLViewerVoiceAccountProvisionResponder(retries));  	} -	else if(voice_server == "vivox") +} + +void LLVoiceClient::login( +	const std::string& account_name, +	const std::string& password, +	const std::string& voice_sip_uri_hostname, +	const std::string& voice_account_server_uri) +{ +	mVoiceSIPURIHostName = voice_sip_uri_hostname; +	mVoiceAccountServerURI = voice_account_server_uri; + +	if(!mAccountHandle.empty())  	{ -		mVoiceModule = (LLVoiceModuleInterface *)LLVivoxVoiceClient::getInstance(); +		// Already logged in. +		LL_WARNS("Voice") << "Called while already logged in." << LL_ENDL; +		 +		// Don't process another login. +		return; +	} +	else if ( account_name != mAccountName ) +	{ +		//TODO: error? +		LL_WARNS("Voice") << "Wrong account name! " << account_name +				<< " instead of " << mAccountName << LL_ENDL;  	}  	else  	{ -		mVoiceModule = NULL; -		return;  +		mAccountPassword = password; +	} + +	std::string debugSIPURIHostName = gSavedSettings.getString("VivoxDebugSIPURIHostName"); +	 +	if( !debugSIPURIHostName.empty() ) +	{ +		mVoiceSIPURIHostName = debugSIPURIHostName; +	} +	 +	if( mVoiceSIPURIHostName.empty() ) +	{ +		// we have an empty account server name +		// so we fall back to hardcoded defaults + +		if(sConnectingToAgni) +		{ +			// Use the release account server +			mVoiceSIPURIHostName = "bhr.vivox.com"; +		} +		else +		{ +			// Use the development account server +			mVoiceSIPURIHostName = "bhd.vivox.com"; +		} +	} +	 +	std::string debugAccountServerURI = gSavedSettings.getString("VivoxDebugVoiceAccountServerURI"); + +	if( !debugAccountServerURI.empty() ) +	{ +		mVoiceAccountServerURI = debugAccountServerURI; +	} +	 +	if( mVoiceAccountServerURI.empty() ) +	{ +		// If the account server URI isn't specified, construct it from the SIP URI hostname +		mVoiceAccountServerURI = "https://www." + mVoiceSIPURIHostName + "/api2/";		  	} -	mVoiceModule->init(m_servicePump);	 -	mVoiceModule->userAuthorized(user_id, agentID);  } +void LLVoiceClient::idle(void* user_data) +{ +	LLVoiceClient* self = (LLVoiceClient*)user_data; +	self->stateMachine(); +} -void LLVoiceClient::terminate() +std::string LLVoiceClient::state2string(LLVoiceClient::state inState)  { -	if (mVoiceModule) mVoiceModule->terminate(); -	mVoiceModule = NULL; +	std::string result = "UNKNOWN"; +	 +		// Prevent copy-paste errors when updating this list... +#define CASE(x)  case x:  result = #x;  break + +	switch(inState) +	{ +		CASE(stateDisableCleanup); +		CASE(stateDisabled); +		CASE(stateStart); +		CASE(stateDaemonLaunched); +		CASE(stateConnecting); +		CASE(stateConnected); +		CASE(stateIdle); +		CASE(stateMicTuningStart); +		CASE(stateMicTuningRunning); +		CASE(stateMicTuningStop); +		CASE(stateConnectorStart); +		CASE(stateConnectorStarting); +		CASE(stateConnectorStarted); +		CASE(stateLoginRetry); +		CASE(stateLoginRetryWait); +		CASE(stateNeedsLogin); +		CASE(stateLoggingIn); +		CASE(stateLoggedIn); +		CASE(stateCreatingSessionGroup); +		CASE(stateNoChannel); +		CASE(stateJoiningSession); +		CASE(stateSessionJoined); +		CASE(stateRunning); +		CASE(stateLeavingSession); +		CASE(stateSessionTerminated); +		CASE(stateLoggingOut); +		CASE(stateLoggedOut); +		CASE(stateConnectorStopping); +		CASE(stateConnectorStopped); +		CASE(stateConnectorFailed); +		CASE(stateConnectorFailedWaiting); +		CASE(stateLoginFailed); +		CASE(stateLoginFailedWaiting); +		CASE(stateJoinSessionFailed); +		CASE(stateJoinSessionFailedWaiting); +		CASE(stateJail); +	} + +#undef CASE +	 +	return result;  } -const LLVoiceVersionInfo LLVoiceClient::getVersion() +std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus)  { -	if (mVoiceModule)  +	std::string result = "UNKNOWN"; +	 +		// Prevent copy-paste errors when updating this list... +#define CASE(x)  case x:  result = #x;  break + +	switch(inStatus)  	{ -		return mVoiceModule->getVersion(); +		CASE(STATUS_LOGIN_RETRY); +		CASE(STATUS_LOGGED_IN); +		CASE(STATUS_JOINING); +		CASE(STATUS_JOINED); +		CASE(STATUS_LEFT_CHANNEL); +		CASE(STATUS_VOICE_DISABLED); +		CASE(STATUS_VOICE_ENABLED); +		CASE(BEGIN_ERROR_STATUS); +		CASE(ERROR_CHANNEL_FULL); +		CASE(ERROR_CHANNEL_LOCKED); +		CASE(ERROR_NOT_AVAILABLE); +		CASE(ERROR_UNKNOWN); +	default: +		break; +	} + +#undef CASE +	 +	return result; +} + +void LLVoiceClient::setState(state inState) +{ +	LL_DEBUGS("Voice") << "entering state " << state2string(inState) << LL_ENDL; +	 +	mState = inState; +} + +void LLVoiceClient::stateMachine() +{ +	if(gDisconnected) +	{ +		// The viewer has been disconnected from the sim.  Disable voice. +		setVoiceEnabled(false); +	} +	 +	if(mVoiceEnabled) +	{ +		updatePosition(); +	} +	else if(mTuningMode) +	{ +		// Tuning mode is special -- it needs to launch SLVoice even if voice is disabled.  	}  	else  	{ -		LLVoiceVersionInfo result; -		result.serverVersion = std::string(); -		result.serverType = std::string(); -		return result; +		if((getState() != stateDisabled) && (getState() != stateDisableCleanup)) +		{ +			// User turned off voice support.  Send the cleanup messages, close the socket, and reset. +			if(!mConnected) +			{ +				// if voice was turned off after the daemon was launched but before we could connect to it, we may need to issue a kill. +				LL_INFOS("Voice") << "Disabling voice before connection to daemon, terminating." << LL_ENDL; +				killGateway(); +			} +			 +			logout(); +			connectorShutdown(); +			 +			setState(stateDisableCleanup); +		} +	} +	 +	// Check for parcel boundary crossing +	{ +		LLViewerRegion *region = gAgent.getRegion(); +		LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); +		 +		if(region && parcel) +		{ +			S32 parcelLocalID = parcel->getLocalID(); +			std::string regionName = region->getName(); +			std::string capURI = region->getCapability("ParcelVoiceInfoRequest"); +		 +//			LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL; + +			// The region name starts out empty and gets filled in later.   +			// Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes. +			// If either is empty, wait for the next time around. +			if(!regionName.empty()) +			{ +				if(!capURI.empty()) +				{ +					if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName)) +					{ +						// We have changed parcels.  Initiate a parcel channel lookup. +						mCurrentParcelLocalID = parcelLocalID; +						mCurrentRegionName = regionName; +						 +						parcelChanged(); +					} +				} +				else +				{ +					LL_WARNS_ONCE("Voice") << "region doesn't have ParcelVoiceInfoRequest capability.  This is normal for a short time after teleporting, but bad if it persists for very long." << LL_ENDL; +				} +			} +		} +	} + +	switch(getState()) +	{ +		//MARK: stateDisableCleanup +		case stateDisableCleanup: +			// Clean up and reset everything.  +			closeSocket(); +			deleteAllSessions(); +			deleteAllBuddies();		 +			 +			mConnectorHandle.clear(); +			mAccountHandle.clear(); +			mAccountPassword.clear(); +			mVoiceAccountServerURI.clear(); +			 +			setState(stateDisabled);	 +		break; +		 +		//MARK: stateDisabled +		case stateDisabled: +			if(mTuningMode || (mVoiceEnabled && !mAccountName.empty())) +			{ +				setState(stateStart); +			} +		break; +		 +		//MARK: stateStart +		case stateStart: +			if(gSavedSettings.getBOOL("CmdLineDisableVoice")) +			{ +				// Voice is locked out, we must not launch the vivox daemon. +				setState(stateJail); +			} +			else if(!isGatewayRunning()) +			{ +				if(true) +				{ +					// Launch the voice daemon +					 +					// *FIX:Mani - Using the executable dir instead  +					// of mAppRODataDir, the working directory from which the app +					// is launched. +					//std::string exe_path = gDirUtilp->getAppRODataDir(); +					std::string exe_path = gDirUtilp->getExecutableDir(); +					exe_path += gDirUtilp->getDirDelimiter(); +#if LL_WINDOWS +					exe_path += "SLVoice.exe"; +#elif LL_DARWIN +					exe_path += "../Resources/SLVoice"; +#else +					exe_path += "SLVoice"; +#endif +					// See if the vivox executable exists +					llstat s; +					if(!LLFile::stat(exe_path, &s)) +					{ +						// vivox executable exists.  Build the command line and launch the daemon. +						// SLIM SDK: these arguments are no longer necessary. +//						std::string args = " -p tcp -h -c"; +						std::string args; +						std::string loglevel = gSavedSettings.getString("VivoxDebugLevel"); +						 +						if(loglevel.empty()) +						{ +							loglevel = "-1";	// turn logging off completely +						} +						 +						args += " -ll "; +						args += loglevel; +						 +						LL_DEBUGS("Voice") << "Args for SLVoice: " << args << LL_ENDL; + +#if LL_WINDOWS +						PROCESS_INFORMATION pinfo; +						STARTUPINFOW sinfo; +						memset(&sinfo, 0, sizeof(sinfo)); + +						std::string exe_dir = gDirUtilp->getExecutableDir(); + +						llutf16string exe_path16 = utf8str_to_utf16str(exe_path); +						llutf16string exe_dir16 = utf8str_to_utf16str(exe_dir); +						llutf16string args16 = utf8str_to_utf16str(args); +						// Create a writeable copy to keep Windows happy. +						U16 *argscpy_16 = new U16[args16.size() + 1]; +						wcscpy_s(argscpy_16,args16.size()+1,args16.c_str()); +						if(!CreateProcessW(exe_path16.c_str(), argscpy_16, NULL, NULL, FALSE, 0, NULL, exe_dir16.c_str(), &sinfo, &pinfo)) +						{ +//							DWORD dwErr = GetLastError(); +						} +						else +						{ +							// foo = pinfo.dwProcessId; // get your pid here if you want to use it later on +							// CloseHandle(pinfo.hProcess); // stops leaks - nothing else +							sGatewayHandle = pinfo.hProcess; +							CloseHandle(pinfo.hThread); // stops leaks - nothing else +						}		 +						 +						delete[] argscpy_16; +#else	// LL_WINDOWS +						// This should be the same for mac and linux +						{ +							std::vector<std::string> arglist; +							arglist.push_back(exe_path); +							 +							// Split the argument string into separate strings for each argument +							typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +							boost::char_separator<char> sep(" "); +							tokenizer tokens(args, sep); +							tokenizer::iterator token_iter; + +							for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) +							{ +								arglist.push_back(*token_iter); +							} +							 +							// create an argv vector for the child process +							char **fakeargv = new char*[arglist.size() + 1]; +							int i; +							for(i=0; i < arglist.size(); i++) +								fakeargv[i] = const_cast<char*>(arglist[i].c_str()); + +							fakeargv[i] = NULL; +							 +							fflush(NULL); // flush all buffers before the child inherits them +							pid_t id = vfork(); +							if(id == 0) +							{ +								// child +								execv(exe_path.c_str(), fakeargv); +								 +								// If we reach this point, the exec failed. +								// Use _exit() instead of exit() per the vfork man page. +								_exit(0); +							} + +							// parent +							delete[] fakeargv; +							sGatewayPID = id; +						} +#endif	// LL_WINDOWS +						mDaemonHost = LLHost(gSavedSettings.getString("VoiceHost").c_str(), gSavedSettings.getU32("VoicePort")); +					}	 +					else +					{ +						LL_INFOS("Voice") << exe_path << " not found." << LL_ENDL; +					}	 +				} +				else +				{		 +					// SLIM SDK: port changed from 44124 to 44125. +					// We can connect to a client gateway running on another host.  This is useful for testing. +					// To do this, launch the gateway on a nearby host like this: +					//  vivox-gw.exe -p tcp -i 0.0.0.0:44125 +					// and put that host's IP address here. +					mDaemonHost = LLHost(gSavedSettings.getString("VoiceHost"), gSavedSettings.getU32("VoicePort")); +				} + +				mUpdateTimer.start(); +				mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS); + +				setState(stateDaemonLaunched); +				 +				// Dirty the states we'll need to sync with the daemon when it comes up. +				mPTTDirty = true; +				mMicVolumeDirty = true; +				mSpeakerVolumeDirty = true; +				mSpeakerMuteDirty = true; +				// These only need to be set if they're not default (i.e. empty string). +				mCaptureDeviceDirty = !mCaptureDevice.empty(); +				mRenderDeviceDirty = !mRenderDevice.empty(); +				 +				mMainSessionGroupHandle.clear(); +			} +		break; + +		//MARK: stateDaemonLaunched +		case stateDaemonLaunched: +			if(mUpdateTimer.hasExpired()) +			{ +				LL_DEBUGS("Voice") << "Connecting to vivox daemon" << LL_ENDL; + +				mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS); + +				if(!mSocket) +				{ +					mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);	 +				} +				 +				mConnected = mSocket->blockingConnect(mDaemonHost); +				if(mConnected) +				{ +					setState(stateConnecting); +				} +				else +				{ +					// If the connect failed, the socket may have been put into a bad state.  Delete it. +					closeSocket(); +				} +			} +		break; + +		//MARK: stateConnecting +		case stateConnecting: +		// Can't do this until we have the pump available. +		if(mPump) +		{ +			// MBW -- Note to self: pumps and pipes examples in +			//  indra/test/io.cpp +			//  indra/test/llpipeutil.{cpp|h} + +			// Attach the pumps and pipes +				 +			LLPumpIO::chain_t readChain; + +			readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket))); +			readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser())); + +			mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS); + +			setState(stateConnected); +		} + +		break; +		 +		//MARK: stateConnected +		case stateConnected: +			// Initial devices query +			getCaptureDevicesSendMessage(); +			getRenderDevicesSendMessage(); + +			mLoginRetryCount = 0; + +			setState(stateIdle); +		break; + +		//MARK: stateIdle +		case stateIdle: +			// This is the idle state where we're connected to the daemon but haven't set up a connector yet. +			if(mTuningMode) +			{ +				mTuningExitState = stateIdle; +				setState(stateMicTuningStart); +			} +			else if(!mVoiceEnabled) +			{ +				// We never started up the connector.  This will shut down the daemon. +				setState(stateConnectorStopped); +			} +			else if(!mAccountName.empty()) +			{ +				LLViewerRegion *region = gAgent.getRegion(); +				 +				if(region) +				{ +					if ( region->getCapability("ProvisionVoiceAccountRequest") != "" ) +					{ +						if ( mAccountPassword.empty() ) +						{ +							requestVoiceAccountProvision(); +						} +						setState(stateConnectorStart); +					} +					else +					{ +						LL_WARNS_ONCE("Voice") << "region doesn't have ProvisionVoiceAccountRequest capability!" << LL_ENDL; +					} +				} +			} +		break; + +		//MARK: stateMicTuningStart +		case stateMicTuningStart: +			if(mUpdateTimer.hasExpired()) +			{ +				if(mCaptureDeviceDirty || mRenderDeviceDirty) +				{ +					// These can't be changed while in tuning mode.  Set them before starting. +					std::ostringstream stream; +					 +					buildSetCaptureDevice(stream); +					buildSetRenderDevice(stream); + +					if(!stream.str().empty()) +					{ +						writeString(stream.str()); +					}				 + +					// This will come around again in the same state and start the capture, after the timer expires. +					mUpdateTimer.start(); +					mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); +				} +				else +				{ +					// duration parameter is currently unused, per Mike S. +					tuningCaptureStartSendMessage(10000); + +					setState(stateMicTuningRunning); +				} +			} +			 +		break; +		 +		//MARK: stateMicTuningRunning +		case stateMicTuningRunning: +			if(!mTuningMode || mCaptureDeviceDirty || mRenderDeviceDirty) +			{ +				// All of these conditions make us leave tuning mode. +				setState(stateMicTuningStop); +			} +			else +			{ +				// process mic/speaker volume changes +				if(mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty) +				{ +					std::ostringstream stream; +					 +					if(mTuningMicVolumeDirty) +					{ +						LL_INFOS("Voice") << "setting tuning mic level to " << mTuningMicVolume << LL_ENDL; +						stream +						<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetMicLevel.1\">" +						<< "<Level>" << mTuningMicVolume << "</Level>" +						<< "</Request>\n\n\n"; +					} +					 +					if(mTuningSpeakerVolumeDirty) +					{ +						stream +						<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetSpeakerLevel.1\">" +						<< "<Level>" << mTuningSpeakerVolume << "</Level>" +						<< "</Request>\n\n\n"; +					} +					 +					mTuningMicVolumeDirty = false; +					mTuningSpeakerVolumeDirty = false; + +					if(!stream.str().empty()) +					{ +						writeString(stream.str()); +					} +				} +			} +		break; +		 +		//MARK: stateMicTuningStop +		case stateMicTuningStop: +		{ +			// transition out of mic tuning +			tuningCaptureStopSendMessage(); +			 +			setState(mTuningExitState); +			 +			// if we exited just to change devices, this will keep us from re-entering too fast. +			mUpdateTimer.start(); +			mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); +			 +		} +		break; +												 +		//MARK: stateConnectorStart +		case stateConnectorStart: +			if(!mVoiceEnabled) +			{ +				// We were never logged in.  This will shut down the connector. +				setState(stateLoggedOut); +			} +			else if(!mVoiceAccountServerURI.empty()) +			{ +				connectorCreate(); +			} +		break; +		 +		//MARK: stateConnectorStarting +		case stateConnectorStarting:	// waiting for connector handle +			// connectorCreateResponse() will transition from here to stateConnectorStarted. +		break; +		 +		//MARK: stateConnectorStarted +		case stateConnectorStarted:		// connector handle received +			if(!mVoiceEnabled) +			{ +				// We were never logged in.  This will shut down the connector. +				setState(stateLoggedOut); +			} +			else +			{ +				// The connector is started.  Send a login message. +				setState(stateNeedsLogin); +			} +		break; +				 +		//MARK: stateLoginRetry +		case stateLoginRetry: +			if(mLoginRetryCount == 0) +			{ +				// First retry -- display a message to the user +				notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGIN_RETRY); +			} +			 +			mLoginRetryCount++; +			 +			if(mLoginRetryCount > MAX_LOGIN_RETRIES) +			{ +				LL_WARNS("Voice") << "too many login retries, giving up." << LL_ENDL; +				setState(stateLoginFailed); +			} +			else +			{ +				LL_INFOS("Voice") << "will retry login in " << LOGIN_RETRY_SECONDS << " seconds." << LL_ENDL; +				mUpdateTimer.start(); +				mUpdateTimer.setTimerExpirySec(LOGIN_RETRY_SECONDS); +				setState(stateLoginRetryWait); +			} +		break; +		 +		//MARK: stateLoginRetryWait +		case stateLoginRetryWait: +			if(mUpdateTimer.hasExpired()) +			{ +				setState(stateNeedsLogin); +			} +		break; +		 +		//MARK: stateNeedsLogin +		case stateNeedsLogin: +			if(!mAccountPassword.empty()) +			{ +				setState(stateLoggingIn); +				loginSendMessage(); +			}		 +		break; +		 +		//MARK: stateLoggingIn +		case stateLoggingIn:			// waiting for account handle +			// loginResponse() will transition from here to stateLoggedIn. +		break; +		 +		//MARK: stateLoggedIn +		case stateLoggedIn:				// account handle received + +			notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN); + +			// request the current set of block rules (we'll need them when updating the friends list) +			accountListBlockRulesSendMessage(); +			 +			// request the current set of auto-accept rules +			accountListAutoAcceptRulesSendMessage(); +			 +			// Set up the mute list observer if it hasn't been set up already. +			if((!sMuteListListener_listening)) +			{ +				LLMuteList::getInstance()->addObserver(&mutelist_listener); +				sMuteListListener_listening = true; +			} + +			// Set up the friends list observer if it hasn't been set up already. +			if(friendslist_listener == NULL) +			{ +				friendslist_listener = new LLVoiceClientFriendsObserver; +				LLAvatarTracker::instance().addObserver(friendslist_listener); +			} +			 +			// Set the initial state of mic mute, local speaker volume, etc. +			{ +				std::ostringstream stream; +				 +				buildLocalAudioUpdates(stream); +				 +				if(!stream.str().empty()) +				{ +					writeString(stream.str()); +				} +			} +			 +#if USE_SESSION_GROUPS			 +			// create the main session group +			sessionGroupCreateSendMessage(); +			 +			setState(stateCreatingSessionGroup); +#else +			// Not using session groups -- skip the stateCreatingSessionGroup state. +			setState(stateNoChannel); + +			// Initial kick-off of channel lookup logic +			parcelChanged();		 +#endif +		break; +		 +		//MARK: stateCreatingSessionGroup +		case stateCreatingSessionGroup: +			if(mSessionTerminateRequested || !mVoiceEnabled) +			{ +				// TODO: Question: is this the right way out of this state +				setState(stateSessionTerminated); +			} +			else if(!mMainSessionGroupHandle.empty()) +			{ +				setState(stateNoChannel); +				 +				// Start looped recording (needed for "panic button" anti-griefing tool) +				recordingLoopStart(); + +				// Initial kick-off of channel lookup logic +				parcelChanged();		 +			} +		break; +					 +		//MARK: stateNoChannel +		case stateNoChannel: +			 +			mSpatialJoiningNum = 0; +			// Do this here as well as inside sendPositionalUpdate().   +			// Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync. +			sendFriendsListUpdates(); +			 +			if(mSessionTerminateRequested || !mVoiceEnabled) +			{ +				// TODO: Question: Is this the right way out of this state? +				setState(stateSessionTerminated); +			} +			else if(mTuningMode) +			{ +				mTuningExitState = stateNoChannel; +				setState(stateMicTuningStart); +			} +			else if(sessionNeedsRelog(mNextAudioSession)) +			{ +				requestRelog(); +				setState(stateSessionTerminated); +			} +			else if(mNextAudioSession) +			{				 +				sessionState *oldSession = mAudioSession; + +				mAudioSession = mNextAudioSession; +				if(!mAudioSession->mReconnect)	 +				{ +					mNextAudioSession = NULL; +				} +				 +				// The old session may now need to be deleted. +				reapSession(oldSession); +				 +				if(!mAudioSession->mHandle.empty()) +				{ +					// Connect to a session by session handle + +					sessionMediaConnectSendMessage(mAudioSession); +				} +				else +				{ +					// Connect to a session by URI +					sessionCreateSendMessage(mAudioSession, true, false); +				} + +				notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING); +				setState(stateJoiningSession); +			} +			else if(!mSpatialSessionURI.empty()) +			{ +				// If we're not headed elsewhere and have a spatial URI, return to spatial. +				switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials); +			} +		break; + +		//MARK: stateJoiningSession +		case stateJoiningSession:		// waiting for session handle + +			// If this is true we have problem with connection to voice server (EXT-4313). +			// See descriptions of mSpatialJoiningNum and MAX_NORMAL_JOINING_SPATIAL_NUM. +			if(mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM)  +			{ +				// Notify observers to let them know there is problem with voice +				notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED); +				llwarns << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << llendl; +			} + +			// Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for +			// example for p2p many times while waiting for response, so it can't be used to detect errors +			if(mAudioSession && mAudioSession->mIsSpatial) +			{ +				mSpatialJoiningNum++; +			} +			 +			// joinedAudioSession() will transition from here to stateSessionJoined. +			if(!mVoiceEnabled) +			{ +				// User bailed out during connect -- jump straight to teardown. +				setState(stateSessionTerminated); +			} +			else if(mSessionTerminateRequested) +			{ +				if(mAudioSession && !mAudioSession->mHandle.empty()) +				{ +					// Only allow direct exits from this state in p2p calls (for cancelling an invite). +					// Terminating a half-connected session on other types of calls seems to break something in the vivox gateway. +					if(mAudioSession->mIsP2P) +					{ +						sessionMediaDisconnectSendMessage(mAudioSession); +						setState(stateSessionTerminated); +					} +				} +			} +		break; +		 +		//MARK: stateSessionJoined +		case stateSessionJoined:		// session handle received +			 +			mSpatialJoiningNum = 0; +			// It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4 +			// before continuing from this state.  They can happen in either order, and if I don't wait for both, things can get stuck. +			// For now, the SessionGroup.AddSession response handler sets mSessionHandle and the SessionStateChangeEvent handler transitions to stateSessionJoined. +			// This is a cheap way to make sure both have happened before proceeding. +			if(mAudioSession && mAudioSession->mVoiceEnabled) +			{ +				// Dirty state that may need to be sync'ed with the daemon. +				mPTTDirty = true; +				mSpeakerVolumeDirty = true; +				mSpatialCoordsDirty = true; +				 +				setState(stateRunning); +				 +				// Start the throttle timer +				mUpdateTimer.start(); +				mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); + +				// Events that need to happen when a session is joined could go here. +				// Maybe send initial spatial data? +				notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED); + +			} +			else if(!mVoiceEnabled) +			{ +				// User bailed out during connect -- jump straight to teardown. +				setState(stateSessionTerminated); +			} +			else if(mSessionTerminateRequested) +			{ +				// Only allow direct exits from this state in p2p calls (for cancelling an invite). +				// Terminating a half-connected session on other types of calls seems to break something in the vivox gateway. +				if(mAudioSession && mAudioSession->mIsP2P) +				{ +					sessionMediaDisconnectSendMessage(mAudioSession); +					setState(stateSessionTerminated); +				} +			} +		break; +		 +		//MARK: stateRunning +		case stateRunning:				// steady state +			// Disabling voice or disconnect requested. +			if(!mVoiceEnabled || mSessionTerminateRequested) +			{ +				leaveAudioSession(); +			} +			else +			{ +				 +				// Figure out whether the PTT state needs to change +				{ +					bool newPTT; +					if(mUsePTT) +					{ +						// If configured to use PTT, track the user state. +						newPTT = mUserPTTState; +					} +					else +					{ +						// If not configured to use PTT, it should always be true (otherwise the user will be unable to speak). +						newPTT = true; +					} +					 +					if(mMuteMic) +					{ +						// This always overrides any other PTT setting. +						newPTT = false; +					} +					 +					// Dirty if state changed. +					if(newPTT != mPTT) +					{ +						mPTT = newPTT; +						mPTTDirty = true; +					} +				} +				 +				if(!inSpatialChannel()) +				{ +					// When in a non-spatial channel, never send positional updates. +					mSpatialCoordsDirty = false; +				} +				else +				{ +					// Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position) +					enforceTether(); +				} +				 +				// Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often +				// -- the user can only click so fast) or every 10hz, whichever is sooner. +				// Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged. +				if((mAudioSession && mAudioSession->mMuteDirty) || mPTTDirty || mUpdateTimer.hasExpired()) +				{ +					mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); +					sendPositionalUpdate(); +				} +			} +		break; +		 +		//MARK: stateLeavingSession +		case stateLeavingSession:		// waiting for terminate session response +			// The handler for the Session.Terminate response will transition from here to stateSessionTerminated. +		break; + +		//MARK: stateSessionTerminated +		case stateSessionTerminated: +			 +			// Must do this first, since it uses mAudioSession. +			notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL); +			 +			if(mAudioSession) +			{ +				sessionState *oldSession = mAudioSession; + +				mAudioSession = NULL; +				// We just notified status observers about this change.  Don't do it again. +				mAudioSessionChanged = false; + +				// The old session may now need to be deleted. +				reapSession(oldSession); +			} +			else +			{ +				LL_WARNS("Voice") << "stateSessionTerminated with NULL mAudioSession" << LL_ENDL; +			} +	 +			// Always reset the terminate request flag when we get here. +			mSessionTerminateRequested = false; + +			if(mVoiceEnabled && !mRelogRequested) +			{				 +				// Just leaving a channel, go back to stateNoChannel (the "logged in but have no channel" state). +				setState(stateNoChannel); +			} +			else +			{ +				// Shutting down voice, continue with disconnecting. +				logout(); +				 +				// The state machine will take it from here +				mRelogRequested = false; +			} +			 +		break; +		 +		//MARK: stateLoggingOut +		case stateLoggingOut:			// waiting for logout response +			// The handler for the AccountLoginStateChangeEvent will transition from here to stateLoggedOut. +		break; +		 +		//MARK: stateLoggedOut +		case stateLoggedOut:			// logout response received +			 +			// Once we're logged out, all these things are invalid. +			mAccountHandle.clear(); +			deleteAllSessions(); +			deleteAllBuddies(); + +			if(mVoiceEnabled && !mRelogRequested) +			{ +				// User was logged out, but wants to be logged in.  Send a new login request. +				setState(stateNeedsLogin); +			} +			else +			{ +				// shut down the connector +				connectorShutdown(); +			} +		break; +		 +		//MARK: stateConnectorStopping +		case stateConnectorStopping:	// waiting for connector stop +			// The handler for the Connector.InitiateShutdown response will transition from here to stateConnectorStopped. +		break; + +		//MARK: stateConnectorStopped +		case stateConnectorStopped:		// connector stop received +			setState(stateDisableCleanup); +		break; + +		//MARK: stateConnectorFailed +		case stateConnectorFailed: +			setState(stateConnectorFailedWaiting); +		break; +		//MARK: stateConnectorFailedWaiting +		case stateConnectorFailedWaiting: +			if(!mVoiceEnabled) +			{ +				setState(stateDisableCleanup); +			} +		break; + +		//MARK: stateLoginFailed +		case stateLoginFailed: +			setState(stateLoginFailedWaiting); +		break; +		//MARK: stateLoginFailedWaiting +		case stateLoginFailedWaiting: +			if(!mVoiceEnabled) +			{ +				setState(stateDisableCleanup); +			} +		break; + +		//MARK: stateJoinSessionFailed +		case stateJoinSessionFailed: +			// Transition to error state.  Send out any notifications here. +			if(mAudioSession) +			{ +				LL_WARNS("Voice") << "stateJoinSessionFailed: (" << mAudioSession->mErrorStatusCode << "): " << mAudioSession->mErrorStatusString << LL_ENDL; +			} +			else +			{ +				LL_WARNS("Voice") << "stateJoinSessionFailed with no current session" << LL_ENDL; +			} +			 +			notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN); +			setState(stateJoinSessionFailedWaiting); +		break; +		 +		//MARK: stateJoinSessionFailedWaiting +		case stateJoinSessionFailedWaiting: +			// Joining a channel failed, either due to a failed channel name -> sip url lookup or an error from the join message. +			// Region crossings may leave this state and try the join again. +			if(mSessionTerminateRequested) +			{ +				setState(stateSessionTerminated); +			} +		break; +		 +		//MARK: stateJail +		case stateJail: +			// We have given up.  Do nothing. +		break; + +	} +	 +	if(mAudioSession && mAudioSession->mParticipantsChanged) +	{ +		mAudioSession->mParticipantsChanged = false; +		mAudioSessionChanged = true; +	} +	 +	if(mAudioSessionChanged) +	{ +		mAudioSessionChanged = false; +		notifyParticipantObservers();  	}  } -void LLVoiceClient::updateSettings() +void LLVoiceClient::closeSocket(void)  { -	if (mVoiceModule) mVoiceModule->updateSettings(); +	mSocket.reset(); +	mConnected = false;	  } -//-------------------------------------------------- -// tuning +void LLVoiceClient::loginSendMessage() +{ +	std::ostringstream stream; -void LLVoiceClient::tuningStart() +	bool autoPostCrashDumps = gSavedSettings.getBOOL("VivoxAutoPostCrashDumps"); + +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Login.1\">" +		<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" +		<< "<AccountName>" << mAccountName << "</AccountName>" +		<< "<AccountPassword>" << mAccountPassword << "</AccountPassword>" +		<< "<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>" +		<< "<EnableBuddiesAndPresence>true</EnableBuddiesAndPresence>" +		<< "<BuddyManagementMode>Application</BuddyManagementMode>" +		<< "<ParticipantPropertyFrequency>5</ParticipantPropertyFrequency>" +		<< (autoPostCrashDumps?"<AutopostCrashDumps>true</AutopostCrashDumps>":"") +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::logout()  { -	if (mVoiceModule) mVoiceModule->tuningStart(); +	// Ensure that we'll re-request provisioning before logging in again +	mAccountPassword.clear(); +	mVoiceAccountServerURI.clear(); +	 +	setState(stateLoggingOut); +	logoutSendMessage();  } -void LLVoiceClient::tuningStop() +void LLVoiceClient::logoutSendMessage()  { -	if (mVoiceModule) mVoiceModule->tuningStop(); +	if(!mAccountHandle.empty()) +	{ +		std::ostringstream stream; +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Logout.1\">" +			<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +		<< "</Request>" +		<< "\n\n\n"; + +		mAccountHandle.clear(); + +		writeString(stream.str()); +	}  } -bool LLVoiceClient::inTuningMode() +void LLVoiceClient::accountListBlockRulesSendMessage() +{ +	if(!mAccountHandle.empty()) +	{		 +		std::ostringstream stream; + +		LL_DEBUGS("Voice") << "requesting block rules" << LL_ENDL; + +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ListBlockRules.1\">" +			<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +		<< "</Request>" +		<< "\n\n\n"; + +		writeString(stream.str()); +	} +} + +void LLVoiceClient::accountListAutoAcceptRulesSendMessage() +{ +	if(!mAccountHandle.empty()) +	{		 +		std::ostringstream stream; + +		LL_DEBUGS("Voice") << "requesting auto-accept rules" << LL_ENDL; + +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ListAutoAcceptRules.1\">" +			<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +		<< "</Request>" +		<< "\n\n\n"; + +		writeString(stream.str()); +	} +} + +void LLVoiceClient::sessionGroupCreateSendMessage() +{ +	if(!mAccountHandle.empty()) +	{		 +		std::ostringstream stream; + +		LL_DEBUGS("Voice") << "creating session group" << LL_ENDL; + +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Create.1\">" +			<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +			<< "<Type>Normal</Type>" +		<< "</Request>" +		<< "\n\n\n"; + +		writeString(stream.str()); +	} +} + +void LLVoiceClient::sessionCreateSendMessage(sessionState *session, bool startAudio, bool startText) +{ +	LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL; +	 +	session->mCreateInProgress = true; +	if(startAudio) +	{ +		session->mMediaConnectInProgress = true; +	} + +	std::ostringstream stream; +	stream +	<< "<Request requestId=\"" << session->mSIPURI << "\" action=\"Session.Create.1\">" +		<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +		<< "<URI>" << session->mSIPURI << "</URI>"; + +	static const std::string allowed_chars = +				"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +				"0123456789" +				"-._~"; + +	if(!session->mHash.empty()) +	{ +		stream +			<< "<Password>" << LLURI::escape(session->mHash, allowed_chars) << "</Password>" +			<< "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>"; +	} +	 +	stream +		<< "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>" +		<< "<ConnectText>" << (startText?"true":"false") << "</ConnectText>" +		<< "<Name>" << mChannelName << "</Name>" +	<< "</Request>\n\n\n"; +	writeString(stream.str()); +} + +void LLVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio, bool startText) +{ +	LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL; +	 +	session->mCreateInProgress = true; +	if(startAudio) +	{ +		session->mMediaConnectInProgress = true; +	} +	 +	std::string password; +	if(!session->mHash.empty()) +	{ +		static const std::string allowed_chars = +					"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +					"0123456789" +					"-._~" +					; +		password = LLURI::escape(session->mHash, allowed_chars); +	} + +	std::ostringstream stream; +	stream +	<< "<Request requestId=\"" << session->mSIPURI << "\" action=\"SessionGroup.AddSession.1\">" +		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" +		<< "<URI>" << session->mSIPURI << "</URI>" +		<< "<Name>" << mChannelName << "</Name>" +		<< "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>" +		<< "<ConnectText>" << (startText?"true":"false") << "</ConnectText>" +		<< "<Password>" << password << "</Password>" +		<< "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>" +	<< "</Request>\n\n\n" +	; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::sessionMediaConnectSendMessage(sessionState *session) +{ +	LL_DEBUGS("Voice") << "connecting audio to session handle: " << session->mHandle << LL_ENDL; + +	session->mMediaConnectInProgress = true; +	 +	std::ostringstream stream; + +	stream +	<< "<Request requestId=\"" << session->mHandle << "\" action=\"Session.MediaConnect.1\">" +		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" +		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" +		<< "<Media>Audio</Media>" +	<< "</Request>\n\n\n"; + +	writeString(stream.str()); +} + +void LLVoiceClient::sessionTextConnectSendMessage(sessionState *session) +{ +	LL_DEBUGS("Voice") << "connecting text to session handle: " << session->mHandle << LL_ENDL; +	 +	std::ostringstream stream; + +	stream +	<< "<Request requestId=\"" << session->mHandle << "\" action=\"Session.TextConnect.1\">" +		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" +		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" +	<< "</Request>\n\n\n"; + +	writeString(stream.str()); +} + +void LLVoiceClient::sessionTerminate() +{ +	mSessionTerminateRequested = true; +} + +void LLVoiceClient::requestRelog() +{ +	mSessionTerminateRequested = true; +	mRelogRequested = true; +} + + +void LLVoiceClient::leaveAudioSession() +{ +	if(mAudioSession) +	{ +		LL_DEBUGS("Voice") << "leaving session: " << mAudioSession->mSIPURI << LL_ENDL; + +		switch(getState()) +		{ +			case stateNoChannel: +				// In this case, we want to pretend the join failed so our state machine doesn't get stuck. +				// Skip the join failed transition state so we don't send out error notifications. +				setState(stateJoinSessionFailedWaiting); +			break; +			case stateJoiningSession: +			case stateSessionJoined: +			case stateRunning: +				if(!mAudioSession->mHandle.empty()) +				{ + +#if RECORD_EVERYTHING +					// HACK: for testing only +					// Save looped recording +					std::string savepath("/tmp/vivoxrecording"); +					{ +						time_t now = time(NULL); +						const size_t BUF_SIZE = 64; +						char time_str[BUF_SIZE];	/* Flawfinder: ignore */ +						 +						strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); +						savepath += time_str; +					} +					recordingLoopSave(savepath); +#endif + +					sessionMediaDisconnectSendMessage(mAudioSession); +					setState(stateLeavingSession); +				} +				else +				{ +					LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;	 +					setState(stateSessionTerminated); +				} +			break; +			case stateJoinSessionFailed: +			case stateJoinSessionFailedWaiting: +				setState(stateSessionTerminated); +			break; +			 +			default: +				LL_WARNS("Voice") << "called from unknown state" << LL_ENDL; +			break; +		} +	} +	else +	{ +		LL_WARNS("Voice") << "called with no active session" << LL_ENDL; +		setState(stateSessionTerminated); +	} +} + +void LLVoiceClient::sessionTerminateSendMessage(sessionState *session) +{ +	std::ostringstream stream; +	 +	LL_DEBUGS("Voice") << "Sending Session.Terminate with handle " << session->mHandle << LL_ENDL;	 +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Terminate.1\">" +		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::sessionGroupTerminateSendMessage(sessionState *session) +{ +	std::ostringstream stream; +	 +	LL_DEBUGS("Voice") << "Sending SessionGroup.Terminate with handle " << session->mGroupHandle << LL_ENDL;	 +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Terminate.1\">" +		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::sessionMediaDisconnectSendMessage(sessionState *session) +{ +	std::ostringstream stream; +	 +	LL_DEBUGS("Voice") << "Sending Session.MediaDisconnect with handle " << session->mHandle << LL_ENDL;	 +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.MediaDisconnect.1\">" +		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" +		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" +		<< "<Media>Audio</Media>" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +	 +} + +void LLVoiceClient::sessionTextDisconnectSendMessage(sessionState *session) +{ +	std::ostringstream stream; +	 +	LL_DEBUGS("Voice") << "Sending Session.TextDisconnect with handle " << session->mHandle << LL_ENDL;	 +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.TextDisconnect.1\">" +		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" +		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::getCaptureDevicesSendMessage()  { -	if (mVoiceModule)  +	std::ostringstream stream; +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetCaptureDevices.1\">" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::getRenderDevicesSendMessage() +{ +	std::ostringstream stream; +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetRenderDevices.1\">" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::clearCaptureDevices() +{ +	LL_DEBUGS("Voice") << "called" << LL_ENDL; +	mCaptureDevices.clear(); +} + +void LLVoiceClient::addCaptureDevice(const std::string& name) +{ +	LL_DEBUGS("Voice") << name << LL_ENDL; + +	mCaptureDevices.push_back(name); +} + +LLVoiceClient::deviceList *LLVoiceClient::getCaptureDevices() +{ +	return &mCaptureDevices; +} + +void LLVoiceClient::setCaptureDevice(const std::string& name) +{ +	if(name == "Default")  	{ -		return mVoiceModule->inTuningMode(); +		if(!mCaptureDevice.empty()) +		{ +			mCaptureDevice.clear(); +			mCaptureDeviceDirty = true;	 +		} +	} +	else +	{ +		if(mCaptureDevice != name) +		{ +			mCaptureDevice = name; +			mCaptureDeviceDirty = true;	 +		} +	} +} + +void LLVoiceClient::clearRenderDevices() +{	 +	LL_DEBUGS("Voice") << "called" << LL_ENDL; +	mRenderDevices.clear(); +} + +void LLVoiceClient::addRenderDevice(const std::string& name) +{ +	LL_DEBUGS("Voice") << name << LL_ENDL; +	mRenderDevices.push_back(name); +} + +LLVoiceClient::deviceList *LLVoiceClient::getRenderDevices() +{ +	return &mRenderDevices; +} + +void LLVoiceClient::setRenderDevice(const std::string& name) +{ +	if(name == "Default") +	{ +		if(!mRenderDevice.empty()) +		{ +			mRenderDevice.clear(); +			mRenderDeviceDirty = true;	 +		}  	}  	else  	{ -		return false; +		if(mRenderDevice != name) +		{ +			mRenderDevice = name; +			mRenderDeviceDirty = true;	 +		} +	} +	 +} + +void LLVoiceClient::tuningStart() +{ +	mTuningMode = true; +	if(getState() >= stateNoChannel) +	{ +		sessionTerminate(); +	} +} + +void LLVoiceClient::tuningStop() +{ +	mTuningMode = false; +} + +bool LLVoiceClient::inTuningMode() +{ +	bool result = false; +	switch(getState()) +	{ +	case stateMicTuningRunning: +		result = true; +		break; +	default: +		break;  	} +	return result; +} + +void LLVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool loop) +{		 +	mTuningAudioFile = name; +	std::ostringstream stream; +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStart.1\">" +    << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>" +    << "<Loop>" << (loop?"1":"0") << "</Loop>" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::tuningRenderStopSendMessage() +{ +	std::ostringstream stream; +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">" +    << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::tuningCaptureStartSendMessage(int duration) +{ +	LL_DEBUGS("Voice") << "sending CaptureAudioStart" << LL_ENDL; +	 +	std::ostringstream stream; +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStart.1\">" +    << "<Duration>" << duration << "</Duration>" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); +} + +void LLVoiceClient::tuningCaptureStopSendMessage() +{ +	LL_DEBUGS("Voice") << "sending CaptureAudioStop" << LL_ENDL; +	 +	std::ostringstream stream; +	stream +	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">" +	<< "</Request>\n\n\n"; +	 +	writeString(stream.str()); + +	mTuningEnergy = 0.0f;  }  void LLVoiceClient::tuningSetMicVolume(float volume)  { -	if (mVoiceModule) mVoiceModule->tuningSetMicVolume(volume); +	int scaled_volume = scale_mic_volume(volume); + +	if(scaled_volume != mTuningMicVolume) +	{ +		mTuningMicVolume = scaled_volume; +		mTuningMicVolumeDirty = true; +	}  }  void LLVoiceClient::tuningSetSpeakerVolume(float volume)  { -	if (mVoiceModule) mVoiceModule->tuningSetSpeakerVolume(volume); -} +	int scaled_volume = scale_speaker_volume(volume);	 +	if(scaled_volume != mTuningSpeakerVolume) +	{ +		mTuningSpeakerVolume = scaled_volume; +		mTuningSpeakerVolumeDirty = true; +	} +} +				  float LLVoiceClient::tuningGetEnergy(void)  { -	if (mVoiceModule)  +	return mTuningEnergy; +} + +bool LLVoiceClient::deviceSettingsAvailable() +{ +	bool result = true; +	 +	if(!mConnected) +		result = false; +	 +	if(mRenderDevices.empty()) +		result = false; +	 +	return result; +} + +void LLVoiceClient::refreshDeviceLists(bool clearCurrentList) +{ +	if(clearCurrentList)  	{ -		return mVoiceModule->tuningGetEnergy(); +		clearCaptureDevices(); +		clearRenderDevices(); +	} +	getCaptureDevicesSendMessage(); +	getRenderDevicesSendMessage(); +} + +void LLVoiceClient::daemonDied() +{ +	// The daemon died, so the connection is gone.  Reset everything and start over. +	LL_WARNS("Voice") << "Connection to vivox daemon lost.  Resetting state."<< LL_ENDL; + +	// Try to relaunch the daemon +	setState(stateDisableCleanup); +} + +void LLVoiceClient::giveUp() +{ +	// All has failed.  Clean up and stop trying. +	closeSocket(); +	deleteAllSessions(); +	deleteAllBuddies(); +	 +	setState(stateJail); +} + +static void oldSDKTransform (LLVector3 &left, LLVector3 &up, LLVector3 &at, LLVector3d &pos, LLVector3 &vel) +{ +	F32 nat[3], nup[3], nl[3], nvel[3]; // the new at, up, left vectors and the  new position and velocity +	F64 npos[3]; +	 +	// The original XML command was sent like this: +	/* +			<< "<Position>" +				<< "<X>" << pos[VX] << "</X>" +				<< "<Y>" << pos[VZ] << "</Y>" +				<< "<Z>" << pos[VY] << "</Z>" +			<< "</Position>" +			<< "<Velocity>" +				<< "<X>" << mAvatarVelocity[VX] << "</X>" +				<< "<Y>" << mAvatarVelocity[VZ] << "</Y>" +				<< "<Z>" << mAvatarVelocity[VY] << "</Z>" +			<< "</Velocity>" +			<< "<AtOrientation>" +				<< "<X>" << l.mV[VX] << "</X>" +				<< "<Y>" << u.mV[VX] << "</Y>" +				<< "<Z>" << a.mV[VX] << "</Z>" +			<< "</AtOrientation>" +			<< "<UpOrientation>" +				<< "<X>" << l.mV[VZ] << "</X>" +				<< "<Y>" << u.mV[VY] << "</Y>" +				<< "<Z>" << a.mV[VZ] << "</Z>" +			<< "</UpOrientation>" +			<< "<LeftOrientation>" +				<< "<X>" << l.mV [VY] << "</X>" +				<< "<Y>" << u.mV [VZ] << "</Y>" +				<< "<Z>" << a.mV [VY] << "</Z>" +			<< "</LeftOrientation>"; +	*/ + +#if 1 +	// This was the original transform done when building the XML command +	nat[0] = left.mV[VX]; +	nat[1] = up.mV[VX]; +	nat[2] = at.mV[VX]; + +	nup[0] = left.mV[VZ]; +	nup[1] = up.mV[VY]; +	nup[2] = at.mV[VZ]; + +	nl[0] = left.mV[VY]; +	nl[1] = up.mV[VZ]; +	nl[2] = at.mV[VY]; + +	npos[0] = pos.mdV[VX]; +	npos[1] = pos.mdV[VZ]; +	npos[2] = pos.mdV[VY]; + +	nvel[0] = vel.mV[VX]; +	nvel[1] = vel.mV[VZ]; +	nvel[2] = vel.mV[VY]; + +	for(int i=0;i<3;++i) { +		at.mV[i] = nat[i]; +		up.mV[i] = nup[i]; +		left.mV[i] = nl[i]; +		pos.mdV[i] = npos[i]; +	} +	 +	// This was the original transform done in the SDK +	nat[0] = at.mV[2]; +	nat[1] = 0; // y component of at vector is always 0, this was up[2] +	nat[2] = -1 * left.mV[2]; + +	// We override whatever the application gives us +	nup[0] = 0; // x component of up vector is always 0 +	nup[1] = 1; // y component of up vector is always 1 +	nup[2] = 0; // z component of up vector is always 0 + +	nl[0] = at.mV[0]; +	nl[1] = 0;  // y component of left vector is always zero, this was up[0] +	nl[2] = -1 * left.mV[0]; + +	npos[2] = pos.mdV[2] * -1.0; +	npos[1] = pos.mdV[1]; +	npos[0] = pos.mdV[0]; + +	for(int i=0;i<3;++i) { +		at.mV[i] = nat[i]; +		up.mV[i] = nup[i]; +		left.mV[i] = nl[i]; +		pos.mdV[i] = npos[i]; +	} +#else +	// This is the compose of the two transforms (at least, that's what I'm trying for) +	nat[0] = at.mV[VX]; +	nat[1] = 0; // y component of at vector is always 0, this was up[2] +	nat[2] = -1 * up.mV[VZ]; + +	// We override whatever the application gives us +	nup[0] = 0; // x component of up vector is always 0 +	nup[1] = 1; // y component of up vector is always 1 +	nup[2] = 0; // z component of up vector is always 0 + +	nl[0] = left.mV[VX]; +	nl[1] = 0;  // y component of left vector is always zero, this was up[0] +	nl[2] = -1 * left.mV[VY]; + +	npos[0] = pos.mdV[VX]; +	npos[1] = pos.mdV[VZ]; +	npos[2] = pos.mdV[VY] * -1.0; + +	nvel[0] = vel.mV[VX]; +	nvel[1] = vel.mV[VZ]; +	nvel[2] = vel.mV[VY]; + +	for(int i=0;i<3;++i) { +		at.mV[i] = nat[i]; +		up.mV[i] = nup[i]; +		left.mV[i] = nl[i]; +		pos.mdV[i] = npos[i]; +	} +	 +#endif +} + +void LLVoiceClient::sendPositionalUpdate(void) +{	 +	std::ostringstream stream; +	 +	if(mSpatialCoordsDirty) +	{ +		LLVector3 l, u, a, vel; +		LLVector3d pos; + +		mSpatialCoordsDirty = false; +		 +		// Always send both speaker and listener positions together. +		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Set3DPosition.1\">"		 +			<< "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"; +		 +		stream << "<SpeakerPosition>"; + +//		LL_DEBUGS("Voice") << "Sending speaker position " << mAvatarPosition << LL_ENDL; +		l = mAvatarRot.getLeftRow(); +		u = mAvatarRot.getUpRow(); +		a = mAvatarRot.getFwdRow(); +		pos = mAvatarPosition; +		vel = mAvatarVelocity; + +		// SLIM SDK: the old SDK was doing a transform on the passed coordinates that the new one doesn't do anymore. +		// The old transform is replicated by this function. +		oldSDKTransform(l, u, a, pos, vel); +		 +		stream  +			<< "<Position>" +				<< "<X>" << pos.mdV[VX] << "</X>" +				<< "<Y>" << pos.mdV[VY] << "</Y>" +				<< "<Z>" << pos.mdV[VZ] << "</Z>" +			<< "</Position>" +			<< "<Velocity>" +				<< "<X>" << vel.mV[VX] << "</X>" +				<< "<Y>" << vel.mV[VY] << "</Y>" +				<< "<Z>" << vel.mV[VZ] << "</Z>" +			<< "</Velocity>" +			<< "<AtOrientation>" +				<< "<X>" << a.mV[VX] << "</X>" +				<< "<Y>" << a.mV[VY] << "</Y>" +				<< "<Z>" << a.mV[VZ] << "</Z>" +			<< "</AtOrientation>" +			<< "<UpOrientation>" +				<< "<X>" << u.mV[VX] << "</X>" +				<< "<Y>" << u.mV[VY] << "</Y>" +				<< "<Z>" << u.mV[VZ] << "</Z>" +			<< "</UpOrientation>" +			<< "<LeftOrientation>" +				<< "<X>" << l.mV [VX] << "</X>" +				<< "<Y>" << l.mV [VY] << "</Y>" +				<< "<Z>" << l.mV [VZ] << "</Z>" +			<< "</LeftOrientation>"; + +		stream << "</SpeakerPosition>"; + +		stream << "<ListenerPosition>"; + +		LLVector3d	earPosition; +		LLVector3	earVelocity; +		LLMatrix3	earRot; +		 +		switch(mEarLocation) +		{ +			case earLocCamera: +			default: +				earPosition = mCameraPosition; +				earVelocity = mCameraVelocity; +				earRot = mCameraRot; +			break; +			 +			case earLocAvatar: +				earPosition = mAvatarPosition; +				earVelocity = mAvatarVelocity; +				earRot = mAvatarRot; +			break; +			 +			case earLocMixed: +				earPosition = mAvatarPosition; +				earVelocity = mAvatarVelocity; +				earRot = mCameraRot; +			break; +		} + +		l = earRot.getLeftRow(); +		u = earRot.getUpRow(); +		a = earRot.getFwdRow(); +		pos = earPosition; +		vel = earVelocity; + +//		LL_DEBUGS("Voice") << "Sending listener position " << earPosition << LL_ENDL; +		 +		oldSDKTransform(l, u, a, pos, vel); +		 +		stream  +			<< "<Position>" +				<< "<X>" << pos.mdV[VX] << "</X>" +				<< "<Y>" << pos.mdV[VY] << "</Y>" +				<< "<Z>" << pos.mdV[VZ] << "</Z>" +			<< "</Position>" +			<< "<Velocity>" +				<< "<X>" << vel.mV[VX] << "</X>" +				<< "<Y>" << vel.mV[VY] << "</Y>" +				<< "<Z>" << vel.mV[VZ] << "</Z>" +			<< "</Velocity>" +			<< "<AtOrientation>" +				<< "<X>" << a.mV[VX] << "</X>" +				<< "<Y>" << a.mV[VY] << "</Y>" +				<< "<Z>" << a.mV[VZ] << "</Z>" +			<< "</AtOrientation>" +			<< "<UpOrientation>" +				<< "<X>" << u.mV[VX] << "</X>" +				<< "<Y>" << u.mV[VY] << "</Y>" +				<< "<Z>" << u.mV[VZ] << "</Z>" +			<< "</UpOrientation>" +			<< "<LeftOrientation>" +				<< "<X>" << l.mV [VX] << "</X>" +				<< "<Y>" << l.mV [VY] << "</Y>" +				<< "<Z>" << l.mV [VZ] << "</Z>" +			<< "</LeftOrientation>"; + + +		stream << "</ListenerPosition>"; + +		stream << "</Request>\n\n\n"; +	}	 +	 +	if(mAudioSession && (mAudioSession->mVolumeDirty || mAudioSession->mMuteDirty)) +	{ +		participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin(); + +		mAudioSession->mVolumeDirty = false; +		mAudioSession->mMuteDirty = false; +		 +		for(; iter != mAudioSession->mParticipantsByURI.end(); iter++) +		{ +			participantState *p = iter->second; + +			if(p->mVolumeDirty) +			{ +				// Can't set volume/mute for yourself +				if(!p->mIsSelf) +				{ +					// scale from the range 0.0-1.0 to vivox volume in the range 0-100 +					S32 volume = llround(p->mVolume / VOLUME_SCALE_VIVOX); + +					bool mute = p->mOnMuteList; + +					if(mute) +					{ +						// SetParticipantMuteForMe doesn't work in p2p sessions. +						// If we want the user to be muted, set their volume to 0 as well. +						// This isn't perfect, but it will at least reduce their volume to a minimum. +						volume = 0; + +						// Mark the current volume level as set to prevent incoming events +						// changing it to 0, so that we can return to it when unmuting. +						p->mVolumeSet = true; +					} + +					if(volume == 0) +					{ +						mute = true; +					} + +					LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL; +					 +					// SLIM SDK: Send both volume and mute commands. +					 +					// Send a "volume for me" command for the user. +					stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantVolumeForMe.1\">" +						<< "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>" +						<< "<ParticipantURI>" << p->mURI << "</ParticipantURI>" +						<< "<Volume>" << volume << "</Volume>" +						<< "</Request>\n\n\n"; + +					if(!mAudioSession->mIsP2P) +					{ +						// Send a "mute for me" command for the user +						// Doesn't work in P2P sessions +						stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantMuteForMe.1\">" +							<< "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>" +							<< "<ParticipantURI>" << p->mURI << "</ParticipantURI>" +							<< "<Mute>" << (mute?"1":"0") << "</Mute>" +							<< "<Scope>Audio</Scope>" +							<< "</Request>\n\n\n"; +					} +				} +				 +				p->mVolumeDirty = false; +			} +		} +	} +			 +	buildLocalAudioUpdates(stream); +	 +	if(!stream.str().empty()) +	{ +		writeString(stream.str()); +	} +	 +	// Friends list updates can be huge, especially on the first voice login of an account with lots of friends. +	// Batching them all together can choke SLVoice, so send them in separate writes. +	sendFriendsListUpdates(); +} + +void LLVoiceClient::buildSetCaptureDevice(std::ostringstream &stream) +{ +	if(mCaptureDeviceDirty) +	{ +		LL_DEBUGS("Voice") << "Setting input device = \"" << mCaptureDevice << "\"" << LL_ENDL; +	 +		stream  +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetCaptureDevice.1\">" +			<< "<CaptureDeviceSpecifier>" << mCaptureDevice << "</CaptureDeviceSpecifier>" +		<< "</Request>" +		<< "\n\n\n"; +		 +		mCaptureDeviceDirty = false; +	} +} + +void LLVoiceClient::buildSetRenderDevice(std::ostringstream &stream) +{ +	if(mRenderDeviceDirty) +	{ +		LL_DEBUGS("Voice") << "Setting output device = \"" << mRenderDevice << "\"" << LL_ENDL; + +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetRenderDevice.1\">" +			<< "<RenderDeviceSpecifier>" << mRenderDevice << "</RenderDeviceSpecifier>" +		<< "</Request>" +		<< "\n\n\n"; +		mRenderDeviceDirty = false; +	} +} + +void LLVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream) +{ +	buildSetCaptureDevice(stream); + +	buildSetRenderDevice(stream); + +	if(mPTTDirty) +	{ +		mPTTDirty = false; + +		// Send a local mute command. +		// NOTE that the state of "PTT" is the inverse of "local mute". +		//   (i.e. when PTT is true, we send a mute command with "false", and vice versa) +		 +		LL_DEBUGS("Voice") << "Sending MuteLocalMic command with parameter " << (mPTT?"false":"true") << LL_ENDL; + +		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">" +			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" +			<< "<Value>" << (mPTT?"false":"true") << "</Value>" +			<< "</Request>\n\n\n"; +		 +	} + +	if(mSpeakerMuteDirty) +	{ +		const char *muteval = ((mSpeakerVolume <= scale_speaker_volume(0))?"true":"false"); + +		mSpeakerMuteDirty = false; + +		LL_INFOS("Voice") << "Setting speaker mute to " << muteval  << LL_ENDL; +		 +		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalSpeaker.1\">" +			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" +			<< "<Value>" << muteval << "</Value>" +			<< "</Request>\n\n\n";	 +		 +	} +	 +	if(mSpeakerVolumeDirty) +	{ +		mSpeakerVolumeDirty = false; + +		LL_INFOS("Voice") << "Setting speaker volume to " << mSpeakerVolume  << LL_ENDL; + +		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalSpeakerVolume.1\">" +			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" +			<< "<Value>" << mSpeakerVolume << "</Value>" +			<< "</Request>\n\n\n"; +			 +	} +	 +	if(mMicVolumeDirty) +	{ +		mMicVolumeDirty = false; + +		LL_INFOS("Voice") << "Setting mic volume to " << mMicVolume  << LL_ENDL; + +		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalMicVolume.1\">" +			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" +			<< "<Value>" << mMicVolume << "</Value>" +			<< "</Request>\n\n\n";				 +	} + +	 +} + +void LLVoiceClient::checkFriend(const LLUUID& id) +{ +	std::string name; +	buddyListEntry *buddy = findBuddy(id); + +	// Make sure we don't add a name before it's been looked up. +	if(gCacheName->getFullName(id, name)) +	{ + +		const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id); +		bool canSeeMeOnline = false; +		if(relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)) +			canSeeMeOnline = true; +		 +		// When we get here, mNeedsSend is true and mInSLFriends is false.  Change them as necessary. +		 +		if(buddy) +		{ +			// This buddy is already in both lists. + +			if(name != buddy->mDisplayName) +			{ +				// The buddy is in the list with the wrong name.  Update it with the correct name. +				LL_WARNS("Voice") << "Buddy " << id << " has wrong name (\"" << buddy->mDisplayName << "\" should be \"" << name << "\"), updating."<< LL_ENDL; +				buddy->mDisplayName = name; +				buddy->mNeedsNameUpdate = true;		// This will cause the buddy to be resent. +			} +		} +		else +		{ +			// This buddy was not in the vivox list, needs to be added. +			buddy = addBuddy(sipURIFromID(id), name); +			buddy->mUUID = id; +		} +		 +		// In all the above cases, the buddy is in the SL friends list (which is how we got here). +		buddy->mInSLFriends = true; +		buddy->mCanSeeMeOnline = canSeeMeOnline; +		buddy->mNameResolved = true; +		  	}  	else  	{ -		return 0.0; +		// This name hasn't been looked up yet.  Don't do anything with this buddy list entry until it has. +		if(buddy) +		{ +			buddy->mNameResolved = false; +		} +		 +		// Initiate a lookup. +		// The "lookup completed" callback will ensure that the friends list is rechecked after it completes. +		lookupName(id);  	}  } +void LLVoiceClient::clearAllLists() +{ +	// FOR TESTING ONLY +	 +	// This will send the necessary commands to delete ALL buddies, autoaccept rules, and block rules SLVoice tells us about. +	buddyListMap::iterator buddy_it; +	for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();) +	{ +		buddyListEntry *buddy = buddy_it->second; +		buddy_it++; +		 +		std::ostringstream stream; -//------------------------------------------------ -// devices +		if(buddy->mInVivoxBuddies) +		{ +			// delete this entry from the vivox buddy list +			buddy->mInVivoxBuddies = false; +			LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; +			stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddyDelete.1\">" +				<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +				<< "<BuddyURI>" << buddy->mURI << "</BuddyURI>" +				<< "</Request>\n\n\n";		 +		} -bool LLVoiceClient::deviceSettingsAvailable() +		if(buddy->mHasBlockListEntry) +		{ +			// Delete the associated block list entry (so the block list doesn't fill up with junk) +			buddy->mHasBlockListEntry = false; +			stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">" +				<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +				<< "<BlockMask>" << buddy->mURI << "</BlockMask>" +				<< "</Request>\n\n\n";								 +		} +		if(buddy->mHasAutoAcceptListEntry) +		{ +			// Delete the associated auto-accept list entry (so the auto-accept list doesn't fill up with junk) +			buddy->mHasAutoAcceptListEntry = false; +			stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">" +				<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +				<< "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>" +				<< "</Request>\n\n\n"; +		} + +		writeString(stream.str()); + +	} +} + +void LLVoiceClient::sendFriendsListUpdates()  { -	if (mVoiceModule)  +	if(mBuddyListMapPopulated && mBlockRulesListReceived && mAutoAcceptRulesListReceived && mFriendsListDirty)  	{ -		return mVoiceModule->deviceSettingsAvailable(); +		mFriendsListDirty = false; +		 +		if(0) +		{ +			// FOR TESTING ONLY -- clear all buddy list, block list, and auto-accept list entries. +			clearAllLists(); +			return; +		} +		 +		LL_INFOS("Voice") << "Checking vivox buddy list against friends list..." << LL_ENDL; +		 +		buddyListMap::iterator buddy_it; +		for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) +		{ +			// reset the temp flags in the local buddy list +			buddy_it->second->mInSLFriends = false; +		} +		 +		// correlate with the friends list +		{ +			LLCollectAllBuddies collect; +			LLAvatarTracker::instance().applyFunctor(collect); +			LLCollectAllBuddies::buddy_map_t::const_iterator it = collect.mOnline.begin(); +			LLCollectAllBuddies::buddy_map_t::const_iterator end = collect.mOnline.end(); +			 +			for ( ; it != end; ++it) +			{ +				checkFriend(it->second); +			} +			it = collect.mOffline.begin(); +			end = collect.mOffline.end(); +			for ( ; it != end; ++it) +			{ +				checkFriend(it->second); +			} +		} +				 +		LL_INFOS("Voice") << "Sending friend list updates..." << LL_ENDL; + +		for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();) +		{ +			buddyListEntry *buddy = buddy_it->second; +			buddy_it++; +			 +			// Ignore entries that aren't resolved yet. +			if(buddy->mNameResolved) +			{ +				std::ostringstream stream; + +				if(buddy->mInSLFriends && (!buddy->mInVivoxBuddies || buddy->mNeedsNameUpdate)) +				{					 +					if(mNumberOfAliases > 0) +					{ +						// Add (or update) this entry in the vivox buddy list +						buddy->mInVivoxBuddies = true; +						buddy->mNeedsNameUpdate = false; +						LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; +						stream  +							<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddySet.1\">" +								<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +								<< "<BuddyURI>" << buddy->mURI << "</BuddyURI>" +								<< "<DisplayName>" << buddy->mDisplayName << "</DisplayName>" +								<< "<BuddyData></BuddyData>"	// Without this, SLVoice doesn't seem to parse the command. +								<< "<GroupID>0</GroupID>" +							<< "</Request>\n\n\n";	 +					} +				} +				else if(!buddy->mInSLFriends) +				{ +					// This entry no longer exists in your SL friends list.  Remove all traces of it from the Vivox buddy list. + 					if(buddy->mInVivoxBuddies) +					{ +						// delete this entry from the vivox buddy list +						buddy->mInVivoxBuddies = false; +						LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; +						stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddyDelete.1\">" +							<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +							<< "<BuddyURI>" << buddy->mURI << "</BuddyURI>" +							<< "</Request>\n\n\n";		 +					} + +					if(buddy->mHasBlockListEntry) +					{ +						// Delete the associated block list entry, if any +						buddy->mHasBlockListEntry = false; +						stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">" +							<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +							<< "<BlockMask>" << buddy->mURI << "</BlockMask>" +							<< "</Request>\n\n\n";								 +					} +					if(buddy->mHasAutoAcceptListEntry) +					{ +						// Delete the associated auto-accept list entry, if any +						buddy->mHasAutoAcceptListEntry = false; +						stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">" +							<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +							<< "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>" +							<< "</Request>\n\n\n"; +					} +				} +				 +				if(buddy->mInSLFriends) +				{ + +					if(buddy->mCanSeeMeOnline) +					{ +						// Buddy should not be blocked. + +						// If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent. +						 +						// If the buddy has a block list entry, delete it. +						if(buddy->mHasBlockListEntry) +						{ +							buddy->mHasBlockListEntry = false; +							stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">" +								<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +								<< "<BlockMask>" << buddy->mURI << "</BlockMask>" +								<< "</Request>\n\n\n";		 +							 +							 +							// If we just deleted a block list entry, add an auto-accept entry. +							if(!buddy->mHasAutoAcceptListEntry) +							{ +								buddy->mHasAutoAcceptListEntry = true;								 +								stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.CreateAutoAcceptRule.1\">" +									<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +									<< "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>" +									<< "<AutoAddAsBuddy>0</AutoAddAsBuddy>" +									<< "</Request>\n\n\n"; +							} +						} +					} +					else +					{ +						// Buddy should be blocked. +						 +						// If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent. + +						// If this buddy has an autoaccept entry, delete it +						if(buddy->mHasAutoAcceptListEntry) +						{ +							buddy->mHasAutoAcceptListEntry = false; +							stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">" +								<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +								<< "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>" +								<< "</Request>\n\n\n"; +						 +							// If we just deleted an auto-accept entry, add a block list entry. +							if(!buddy->mHasBlockListEntry) +							{ +								buddy->mHasBlockListEntry = true; +								stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.CreateBlockRule.1\">" +									<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +									<< "<BlockMask>" << buddy->mURI << "</BlockMask>" +									<< "<PresenceOnly>1</PresenceOnly>" +									<< "</Request>\n\n\n";								 +							} +						} +					} + +					if(!buddy->mInSLFriends && !buddy->mInVivoxBuddies) +					{ +						// Delete this entry from the local buddy list.  This should NOT invalidate the iterator, +						// since it has already been incremented to the next entry. +						deleteBuddy(buddy->mURI); +					} + +				} +				writeString(stream.str()); +			} +		} +	} +} + +///////////////////////////// +// Response/Event handlers + +void LLVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID) +{	 +	if(statusCode != 0) +	{ +		LL_WARNS("Voice") << "Connector.Create response failure: " << statusString << LL_ENDL; +		setState(stateConnectorFailed);  	}  	else  	{ -		return false; +		// Connector created, move forward. +		LL_INFOS("Voice") << "Connector.Create succeeded, Vivox SDK version is " << versionID << LL_ENDL; +		mAPIVersion = versionID; +		mConnectorHandle = connectorHandle; +		if(getState() == stateConnectorStarting) +		{ +			setState(stateConnectorStarted); +		}  	}  } -void LLVoiceClient::refreshDeviceLists(bool clearCurrentList) +void LLVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases) +{  +	LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL; +	 +	// Status code of 20200 means "bad password".  We may want to special-case that at some point. +	 +	if ( statusCode == 401 ) +	{ +		// Login failure which is probably caused by the delay after a user's password being updated. +		LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; +		setState(stateLoginRetry); +	} +	else if(statusCode != 0) +	{ +		LL_WARNS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; +		setState(stateLoginFailed); +	} +	else +	{ +		// Login succeeded, move forward. +		mAccountHandle = accountHandle; +		mNumberOfAliases = numberOfAliases; +		// This needs to wait until the AccountLoginStateChangeEvent is received. +//		if(getState() == stateLoggingIn) +//		{ +//			setState(stateLoggedIn); +//		} +	} +} + +void LLVoiceClient::sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle) +{	 +	sessionState *session = findSessionBeingCreatedByURI(requestId); +	 +	if(session) +	{ +		session->mCreateInProgress = false; +	} +	 +	if(statusCode != 0) +	{ +		LL_WARNS("Voice") << "Session.Create response failure (" << statusCode << "): " << statusString << LL_ENDL; +		if(session) +		{ +			session->mErrorStatusCode = statusCode;		 +			session->mErrorStatusString = statusString; +			if(session == mAudioSession) +			{ +				setState(stateJoinSessionFailed); +			} +			else +			{ +				reapSession(session); +			} +		} +	} +	else +	{ +		LL_INFOS("Voice") << "Session.Create response received (success), session handle is " << sessionHandle << LL_ENDL; +		if(session) +		{ +			setSessionHandle(session, sessionHandle); +		} +	} +} + +void LLVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle) +{	 +	sessionState *session = findSessionBeingCreatedByURI(requestId); +	 +	if(session) +	{ +		session->mCreateInProgress = false; +	} +	 +	if(statusCode != 0) +	{ +		LL_WARNS("Voice") << "SessionGroup.AddSession response failure (" << statusCode << "): " << statusString << LL_ENDL; +		if(session) +		{ +			session->mErrorStatusCode = statusCode;		 +			session->mErrorStatusString = statusString; +			if(session == mAudioSession) +			{ +				setState(stateJoinSessionFailed); +			} +			else +			{ +				reapSession(session); +			} +		} +	} +	else +	{ +		LL_DEBUGS("Voice") << "SessionGroup.AddSession response received (success), session handle is " << sessionHandle << LL_ENDL; +		if(session) +		{ +			setSessionHandle(session, sessionHandle); +		} +	} +} + +void LLVoiceClient::sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString)  { -	if (mVoiceModule) mVoiceModule->refreshDeviceLists(clearCurrentList); +	sessionState *session = findSession(requestId); +	if(statusCode != 0) +	{ +		LL_WARNS("Voice") << "Session.Connect response failure (" << statusCode << "): " << statusString << LL_ENDL; +		if(session) +		{ +			session->mMediaConnectInProgress = false; +			session->mErrorStatusCode = statusCode;		 +			session->mErrorStatusString = statusString; +			if(session == mAudioSession) +				setState(stateJoinSessionFailed); +		} +	} +	else +	{ +		LL_DEBUGS("Voice") << "Session.Connect response received (success)" << LL_ENDL; +	}  } -void LLVoiceClient::setCaptureDevice(const std::string& name) +void LLVoiceClient::logoutResponse(int statusCode, std::string &statusString) +{	 +	if(statusCode != 0) +	{ +		LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL; +		// Should this ever fail?  do we care if it does? +	} +} + +void LLVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString)  { -	if (mVoiceModule) mVoiceModule->setCaptureDevice(name); +	if(statusCode != 0) +	{ +		LL_WARNS("Voice") << "Connector.InitiateShutdown response failure: " << statusString << LL_ENDL; +		// Should this ever fail?  do we care if it does? +	} +	mConnected = false; +	 +	if(getState() == stateConnectorStopping) +	{ +		setState(stateConnectorStopped); +	}  } -void LLVoiceClient::setRenderDevice(const std::string& name) +void LLVoiceClient::sessionAddedEvent( +		std::string &uriString,  +		std::string &alias,  +		std::string &sessionHandle,  +		std::string &sessionGroupHandle,  +		bool isChannel,  +		bool incoming, +		std::string &nameString, +		std::string &applicationString)  { -	if (mVoiceModule) mVoiceModule->setRenderDevice(name);	 +	sessionState *session = NULL; + +	LL_INFOS("Voice") << "session " << uriString << ", alias " << alias << ", name " << nameString << " handle " << sessionHandle << LL_ENDL; +	 +	session = addSession(uriString, sessionHandle); +	if(session) +	{ +		session->mGroupHandle = sessionGroupHandle; +		session->mIsChannel = isChannel; +		session->mIncoming = incoming; +		session->mAlias = alias; +			 +		// Generate a caller UUID -- don't need to do this for channels +		if(!session->mIsChannel) +		{ +			if(IDFromName(session->mSIPURI, session->mCallerID)) +			{ +				// Normal URI(base64-encoded UUID)  +			} +			else if(!session->mAlias.empty() && IDFromName(session->mAlias, session->mCallerID)) +			{ +				// Wrong URI, but an alias is available.  Stash the incoming URI as an alternate +				session->mAlternateSIPURI = session->mSIPURI; +				 +				// and generate a proper URI from the ID. +				setSessionURI(session, sipURIFromID(session->mCallerID)); +			} +			else +			{ +				LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL; +				setUUIDFromStringHash(session->mCallerID, session->mSIPURI); +				session->mSynthesizedCallerID = true; +				 +				// Can't look up the name in this case -- we have to extract it from the URI. +				std::string namePortion = nameFromsipURI(session->mSIPURI); +				if(namePortion.empty()) +				{ +					// Didn't seem to be a SIP URI, just use the whole provided name. +					namePortion = nameString; +				} +				 +				// Some incoming names may be separated with an underscore instead of a space.  Fix this. +				LLStringUtil::replaceChar(namePortion, '_', ' '); +				 +				// Act like we just finished resolving the name (this stores it in all the right places) +				avatarNameResolved(session->mCallerID, namePortion); +			} +		 +			LL_INFOS("Voice") << "caller ID: " << session->mCallerID << LL_ENDL; + +			if(!session->mSynthesizedCallerID) +			{ +				// If we got here, we don't have a proper name.  Initiate a lookup. +				lookupName(session->mCallerID); +			} +		} +	}  } -const LLVoiceDeviceList& LLVoiceClient::getCaptureDevices() +void LLVoiceClient::sessionGroupAddedEvent(std::string &sessionGroupHandle)  { -	static LLVoiceDeviceList nullCaptureDevices; -	if (mVoiceModule)  +	LL_DEBUGS("Voice") << "handle " << sessionGroupHandle << LL_ENDL; +	 +#if USE_SESSION_GROUPS +	if(mMainSessionGroupHandle.empty())  	{ -		return mVoiceModule->getCaptureDevices(); +		// This is the first (i.e. "main") session group.  Save its handle. +		mMainSessionGroupHandle = sessionGroupHandle;  	}  	else  	{ -		return nullCaptureDevices; +		LL_DEBUGS("Voice") << "Already had a session group handle " << mMainSessionGroupHandle << LL_ENDL; +	} +#endif +} + +void LLVoiceClient::joinedAudioSession(sessionState *session) +{ +	if(mAudioSession != session) +	{ +		sessionState *oldSession = mAudioSession; + +		mAudioSession = session; +		mAudioSessionChanged = true; + +		// The old session may now need to be deleted. +		reapSession(oldSession); +	} +	 +	// This is the session we're joining. +	if(getState() == stateJoiningSession) +	{ +		setState(stateSessionJoined); +		 +		// SLIM SDK: we don't always receive a participant state change for ourselves when joining a channel now. +		// Add the current user as a participant here. +		participantState *participant = session->addParticipant(sipURIFromName(mAccountName)); +		if(participant) +		{ +			participant->mIsSelf = true; +			lookupName(participant->mAvatarID); + +			LL_INFOS("Voice") << "added self as participant \"" << participant->mAccountName  +					<< "\" (" << participant->mAvatarID << ")"<< LL_ENDL; +		} +		 +		if(!session->mIsChannel) +		{ +			// this is a p2p session.  Make sure the other end is added as a participant. +			participantState *participant = session->addParticipant(session->mSIPURI); +			if(participant) +			{ +				if(participant->mAvatarIDValid) +				{ +					lookupName(participant->mAvatarID); +				} +				else if(!session->mName.empty()) +				{ +					participant->mDisplayName = session->mName; +					avatarNameResolved(participant->mAvatarID, session->mName); +				} +				 +				// TODO: Question: Do we need to set up mAvatarID/mAvatarIDValid here? +				LL_INFOS("Voice") << "added caller as participant \"" << participant->mAccountName  +						<< "\" (" << participant->mAvatarID << ")"<< LL_ENDL; +			} +		}  	}  } +void LLVoiceClient::sessionRemovedEvent( +	std::string &sessionHandle,  +	std::string &sessionGroupHandle) +{ +	LL_INFOS("Voice") << "handle " << sessionHandle << LL_ENDL; +	 +	sessionState *session = findSession(sessionHandle); +	if(session) +	{ +		leftAudioSession(session); + +		// This message invalidates the session's handle.  Set it to empty. +		setSessionHandle(session); +		 +		// This also means that the session's session group is now empty. +		// Terminate the session group so it doesn't leak. +		sessionGroupTerminateSendMessage(session); +		 +		// Reset the media state (we now have no info) +		session->mMediaStreamState = streamStateUnknown; +		session->mTextStreamState = streamStateUnknown; +		 +		// Conditionally delete the session +		reapSession(session); +	} +	else +	{ +		LL_WARNS("Voice") << "unknown session " << sessionHandle << " removed" << LL_ENDL; +	} +} -const LLVoiceDeviceList& LLVoiceClient::getRenderDevices() +void LLVoiceClient::reapSession(sessionState *session)  { -	static LLVoiceDeviceList nullRenderDevices;	 -	if (mVoiceModule)  +	if(session)  	{ -		return mVoiceModule->getRenderDevices(); +		if(!session->mHandle.empty()) +		{ +			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (non-null session handle)" << LL_ENDL; +		} +		else if(session->mCreateInProgress) +		{ +			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (create in progress)" << LL_ENDL; +		} +		else if(session->mMediaConnectInProgress) +		{ +			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (connect in progress)" << LL_ENDL; +		} +		else if(session == mAudioSession) +		{ +			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the current session)" << LL_ENDL; +		} +		else if(session == mNextAudioSession) +		{ +			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the next session)" << LL_ENDL; +		} +		else +		{ +			// TODO: Question: Should we check for queued text messages here? +			// We don't have a reason to keep tracking this session, so just delete it. +			LL_DEBUGS("Voice") << "deleting session " << session->mSIPURI << LL_ENDL; +			deleteSession(session); +			session = NULL; +		}	  	}  	else  	{ -		return nullRenderDevices; +//		LL_DEBUGS("Voice") << "session is NULL" << LL_ENDL; +	} +} + +// Returns true if the session seems to indicate we've moved to a region on a different voice server +bool LLVoiceClient::sessionNeedsRelog(sessionState *session) +{ +	bool result = false; +	 +	if(session != NULL) +	{ +		// Only make this check for spatial channels (so it won't happen for group or p2p calls) +		if(session->mIsSpatial) +		{ +			std::string::size_type atsign; +			 +			atsign = session->mSIPURI.find("@"); +			 +			if(atsign != std::string::npos) +			{ +				std::string urihost = session->mSIPURI.substr(atsign + 1); +				if(stricmp(urihost.c_str(), mVoiceSIPURIHostName.c_str())) +				{ +					// The hostname in this URI is different from what we expect.  This probably means we need to relog. +					 +					// We could make a ProvisionVoiceAccountRequest and compare the result with the current values of +					// mVoiceSIPURIHostName and mVoiceAccountServerURI to be really sure, but this is a pretty good indicator. +					 +					result = true; +				} +			} +		} +	} +	 +	return result; +} + +void LLVoiceClient::leftAudioSession( +	sessionState *session) +{ +	if(mAudioSession == session) +	{ +		switch(getState()) +		{ +			case stateJoiningSession: +			case stateSessionJoined: +			case stateRunning: +			case stateLeavingSession: +			case stateJoinSessionFailed: +			case stateJoinSessionFailedWaiting: +				// normal transition +				LL_DEBUGS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL; +				setState(stateSessionTerminated); +			break; +			 +			case stateSessionTerminated: +				// this will happen sometimes -- there are cases where we send the terminate and then go straight to this state. +				LL_WARNS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL; +			break; +			 +			default: +				LL_WARNS("Voice") << "unexpected SessionStateChangeEvent (left session) in state " << state2string(getState()) << LL_ENDL; +				setState(stateSessionTerminated); +			break; +		}  	}  } +void LLVoiceClient::accountLoginStateChangeEvent( +		std::string &accountHandle,  +		int statusCode,  +		std::string &statusString,  +		int state) +{ +	LL_DEBUGS("Voice") << "state is " << state << LL_ENDL; +	/* +		According to Mike S., status codes for this event are: +		login_state_logged_out=0, +        login_state_logged_in = 1, +        login_state_logging_in = 2, +        login_state_logging_out = 3, +        login_state_resetting = 4, +        login_state_error=100	 +	*/ +	 +	switch(state) +	{ +		case 1: +		if(getState() == stateLoggingIn) +		{ +			setState(stateLoggedIn); +		} +		break; + +		case 3: +			// The user is in the process of logging out. +			setState(stateLoggingOut); +		break; -//-------------------------------------------------- -// participants +		case 0: +			// The user has been logged out.   +			setState(stateLoggedOut); +		break; +		 +		default: +			//Used to be a commented out warning +			LL_DEBUGS("Voice") << "unknown state: " << state << LL_ENDL; +		break; +	} +} -void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants) +void LLVoiceClient::mediaStreamUpdatedEvent( +	std::string &sessionHandle,  +	std::string &sessionGroupHandle,  +	int statusCode,  +	std::string &statusString,  +	int state,  +	bool incoming)  { -	if (mVoiceModule)  +	sessionState *session = findSession(sessionHandle); +	 +	LL_DEBUGS("Voice") << "session " << sessionHandle << ", status code " << statusCode << ", string \"" << statusString << "\"" << LL_ENDL; +	 +	if(session)  	{ -	  mVoiceModule->getParticipantList(participants); +		// We know about this session +		 +		// Save the state for later use +		session->mMediaStreamState = state; +		 +		switch(statusCode) +		{ +			case 0: +			case 200: +				// generic success +				// Don't change the saved error code (it may have been set elsewhere) +			break; +			default: +				// save the status code for later +				session->mErrorStatusCode = statusCode; +			break; +		} +		 +		switch(state) +		{ +			case streamStateIdle: +				// Standard "left audio session" +				session->mVoiceEnabled = false; +				session->mMediaConnectInProgress = false; +				leftAudioSession(session); +			break; + +			case streamStateConnected: +				session->mVoiceEnabled = true; +				session->mMediaConnectInProgress = false; +				joinedAudioSession(session); +			break; +			 +			case streamStateRinging: +				if(incoming) +				{ +					// Send the voice chat invite to the GUI layer +					// *TODO: Question: Should we correlate with the mute list here? +					session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID); +					session->mVoiceInvitePending = true; +					if(session->mName.empty()) +					{ +						lookupName(session->mCallerID); +					} +					else +					{ +						// Act like we just finished resolving the name +						avatarNameResolved(session->mCallerID, session->mName); +					} +				} +			break; +			 +			default: +				LL_WARNS("Voice") << "unknown state " << state << LL_ENDL; +			break; +			 +		} +		  	}  	else  	{ -	  participants = std::set<LLUUID>(); +		LL_WARNS("Voice") << "session " << sessionHandle << "not found"<< LL_ENDL;  	}  } -bool LLVoiceClient::isParticipant(const LLUUID &speaker_id) +void LLVoiceClient::textStreamUpdatedEvent( +	std::string &sessionHandle,  +	std::string &sessionGroupHandle,  +	bool enabled, +	int state,  +	bool incoming)  { -  if(mVoiceModule) -    { -      return mVoiceModule->isParticipant(speaker_id); -    } -  return false; +	sessionState *session = findSession(sessionHandle); +	 +	if(session) +	{ +		// Save the state for later use +		session->mTextStreamState = state; +		 +		// We know about this session +		switch(state) +		{ +			case 0:	// We see this when the text stream closes +				LL_DEBUGS("Voice") << "stream closed" << LL_ENDL; +			break; +			 +			case 1:	// We see this on an incoming call from the Connector +				// Try to send any text messages queued for this session. +				sendQueuedTextMessages(session); + +				// Send the text chat invite to the GUI layer +				// TODO: Question: Should we correlate with the mute list here? +				session->mTextInvitePending = true; +				if(session->mName.empty()) +				{ +					lookupName(session->mCallerID); +				} +				else +				{ +					// Act like we just finished resolving the name +					avatarNameResolved(session->mCallerID, session->mName); +				} +			break; + +			default: +				LL_WARNS("Voice") << "unknown state " << state << LL_ENDL; +			break; +			 +		} +	}  } +void LLVoiceClient::participantAddedEvent( +		std::string &sessionHandle,  +		std::string &sessionGroupHandle,  +		std::string &uriString,  +		std::string &alias,  +		std::string &nameString,  +		std::string &displayNameString,  +		int participantType) +{ +	sessionState *session = findSession(sessionHandle); +	if(session) +	{ +		participantState *participant = session->addParticipant(uriString); +		if(participant) +		{ +			participant->mAccountName = nameString; -//-------------------------------------------------- -// text chat +			LL_DEBUGS("Voice") << "added participant \"" << participant->mAccountName  +					<< "\" (" << participant->mAvatarID << ")"<< LL_ENDL; +			if(participant->mAvatarIDValid) +			{ +				// Initiate a lookup +				lookupName(participant->mAvatarID); +			} +			else +			{ +				// If we don't have a valid avatar UUID, we need to fill in the display name to make the active speakers floater work. +				std::string namePortion = nameFromsipURI(uriString); +				if(namePortion.empty()) +				{ +					// Problem with the SIP URI, fall back to the display name +					namePortion = displayNameString; +				} +				if(namePortion.empty()) +				{ +					// Problems with both of the above, fall back to the account name +					namePortion = nameString; +				} +				 +				// Set the display name (which is a hint to the active speakers window not to do its own lookup) +				participant->mDisplayName = namePortion; +				avatarNameResolved(participant->mAvatarID, namePortion); +			} +		} +	} +} -BOOL LLVoiceClient::isSessionTextIMPossible(const LLUUID& id) +void LLVoiceClient::participantRemovedEvent( +		std::string &sessionHandle,  +		std::string &sessionGroupHandle,  +		std::string &uriString,  +		std::string &alias,  +		std::string &nameString)  { -	if (mVoiceModule)  +	sessionState *session = findSession(sessionHandle); +	if(session)  	{ -		return mVoiceModule->isSessionTextIMPossible(id); +		participantState *participant = session->findParticipant(uriString); +		if(participant) +		{ +			session->removeParticipant(participant); +		} +		else +		{ +			LL_DEBUGS("Voice") << "unknown participant " << uriString << LL_ENDL; +		}  	}  	else  	{ -		return FALSE; -	}	 +		LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL; +	}  } -BOOL LLVoiceClient::isSessionCallBackPossible(const LLUUID& id) + +void LLVoiceClient::participantUpdatedEvent( +		std::string &sessionHandle,  +		std::string &sessionGroupHandle,  +		std::string &uriString,  +		std::string &alias,  +		bool isModeratorMuted,  +		bool isSpeaking,  +		int volume,  +		F32 energy)  { -	if (mVoiceModule)  +	sessionState *session = findSession(sessionHandle); +	if(session)  	{ -		return mVoiceModule->isSessionCallBackPossible(id); +		participantState *participant = session->findParticipant(uriString); +		 +		if(participant) +		{ +			participant->mIsSpeaking = isSpeaking; +			participant->mIsModeratorMuted = isModeratorMuted; + +			// SLIM SDK: convert range: ensure that energy is set to zero if is_speaking is false +			if (isSpeaking) +			{ +				participant->mSpeakingTimeout.reset(); +				participant->mPower = energy; +			} +			else +			{ +				participant->mPower = 0.0f; +			} + +			// Ignore incoming volume level if it has been explicitly set, or there +			//  is a volume or mute change pending. +			if ( !participant->mVolumeSet && !participant->mVolumeDirty) +			{ +				participant->mVolume = (F32)volume * VOLUME_SCALE_VIVOX; +			} + +			// *HACK: mantipov: added while working on EXT-3544 +			/* +			Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE  +			LLViewerChatterBoxSessionAgentListUpdates::post() sometimes AFTER. +			 +			participantUpdatedEvent updates voice participant state in particular participantState::mIsModeratorMuted +			Originally we wanted to update session Speaker Manager to fire LLSpeakerVoiceModerationEvent to fix the EXT-3544 bug. +			Calling of the LLSpeakerMgr::update() method was added into LLIMMgr::processAgentListUpdates. +			 +			But in case participantUpdatedEvent() is called after LLViewerChatterBoxSessionAgentListUpdates::post() +			voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager +			and event is not fired. + +			So, we have to call LLSpeakerMgr::update() here. In any case it is better than call it +			in LLCallFloater::draw() +			*/ +			LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel(); + +			// ignore session ID of local chat +			if (voice_cnl && voice_cnl->getSessionID().notNull()) +			{ +				LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(voice_cnl->getSessionID()); +				if (speaker_manager) +				{ +					speaker_manager->update(true); +				} +			} +		} +		else +		{ +			LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL; +		}  	}  	else  	{ -		return FALSE; -	}	 +		LL_INFOS("Voice") << "unknown session " << sessionHandle << LL_ENDL; +	}  } -BOOL LLVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message) +void LLVoiceClient::buddyPresenceEvent( +		std::string &uriString,  +		std::string &alias,  +		std::string &statusString, +		std::string &applicationString)  { -	if (mVoiceModule)  +	buddyListEntry *buddy = findBuddy(uriString); +	 +	if(buddy)  	{ -		return mVoiceModule->sendTextMessage(participant_id, message); +		LL_DEBUGS("Voice") << "Presence event for " << buddy->mDisplayName << " status \"" << statusString << "\", application \"" << applicationString << "\""<< LL_ENDL; +		LL_DEBUGS("Voice") << "before: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL; + +		if(applicationString.empty()) +		{ +			// This presence event is from a client that doesn't set up the Application string.  Do things the old-skool way. +			// NOTE: this will be needed to support people who aren't on the 3010-class SDK yet. + +			if ( stricmp("Unknown", statusString.c_str())== 0)  +			{ +				// User went offline with a non-SLim-enabled viewer. +				buddy->mOnlineSL = false; +			} +			else if ( stricmp("Online", statusString.c_str())== 0)  +			{ +				// User came online with a non-SLim-enabled viewer. +				buddy->mOnlineSL = true; +			} +			else +			{ +				// If the user is online through SLim, their status will be "Online-slc", "Away", or something else. +				// NOTE: we should never see this unless someone is running an OLD version of SLim -- the versions that should be in use now all set the application string. +				buddy->mOnlineSLim = true; +			}  +		} +		else if(applicationString.find("SecondLifeViewer") != std::string::npos) +		{ +			// This presence event is from a viewer that sets the application string +			if ( stricmp("Unknown", statusString.c_str())== 0)  +			{ +				// Viewer says they're offline +				buddy->mOnlineSL = false; +			} +			else +			{ +				// Viewer says they're online +				buddy->mOnlineSL = true; +			} +		} +		else +		{ +			// This presence event is from something which is NOT the SL viewer (assume it's SLim). +			if ( stricmp("Unknown", statusString.c_str())== 0)  +			{ +				// SLim says they're offline +				buddy->mOnlineSLim = false; +			} +			else +			{ +				// SLim says they're online +				buddy->mOnlineSLim = true; +			} +		}  + +		LL_DEBUGS("Voice") << "after: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL; +		 +		// HACK -- increment the internal change serial number in the LLRelationship (without changing the actual status), so the UI notices the change. +		LLAvatarTracker::instance().setBuddyOnline(buddy->mUUID,LLAvatarTracker::instance().isBuddyOnline(buddy->mUUID)); + +		notifyFriendObservers();  	}  	else  	{ -		return FALSE; +		LL_DEBUGS("Voice") << "Presence for unknown buddy " << uriString << LL_ENDL;  	}	  } -void LLVoiceClient::endUserIMSession(const LLUUID& participant_id) +void LLVoiceClient::messageEvent( +		std::string &sessionHandle,  +		std::string &uriString,  +		std::string &alias,  +		std::string &messageHeader,  +		std::string &messageBody, +		std::string &applicationString)  { -	if (mVoiceModule)  +	LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL; +//	LL_DEBUGS("Voice") << "    header " << messageHeader << ", body: \n" << messageBody << LL_ENDL; +	 +	if(messageHeader.find("text/html") != std::string::npos)  	{ -		mVoiceModule->endUserIMSession(participant_id); +		std::string message; + +		{ +			const std::string startMarker = "<body"; +			const std::string startMarker2 = ">"; +			const std::string endMarker = "</body>"; +			const std::string startSpan = "<span"; +			const std::string endSpan = "</span>"; +			std::string::size_type start; +			std::string::size_type end; +			 +			// Default to displaying the raw string, so the message gets through. +			message = messageBody; + +			// Find the actual message text within the XML fragment +			start = messageBody.find(startMarker); +			start = messageBody.find(startMarker2, start); +			end = messageBody.find(endMarker); + +			if(start != std::string::npos) +			{ +				start += startMarker2.size(); +				 +				if(end != std::string::npos) +					end -= start; +					 +				message.assign(messageBody, start, end); +			} +			else  +			{ +				// Didn't find a <body>, try looking for a <span> instead. +				start = messageBody.find(startSpan); +				start = messageBody.find(startMarker2, start); +				end = messageBody.find(endSpan); +				 +				if(start != std::string::npos) +				{ +					start += startMarker2.size(); +					 +					if(end != std::string::npos) +						end -= start; +					 +					message.assign(messageBody, start, end); +				}			 +			} +		}	 +		 +//		LL_DEBUGS("Voice") << "    raw message = \n" << message << LL_ENDL; + +		// strip formatting tags +		{ +			std::string::size_type start; +			std::string::size_type end; +			 +			while((start = message.find('<')) != std::string::npos) +			{ +				if((end = message.find('>', start + 1)) != std::string::npos) +				{ +					// Strip out the tag +					message.erase(start, (end + 1) - start); +				} +				else +				{ +					// Avoid an infinite loop +					break; +				} +			} +		} +		 +		// Decode ampersand-escaped chars +		{ +			std::string::size_type mark = 0; + +			// The text may contain text encoded with <, >, and & +			mark = 0; +			while((mark = message.find("<", mark)) != std::string::npos) +			{ +				message.replace(mark, 4, "<"); +				mark += 1; +			} +			 +			mark = 0; +			while((mark = message.find(">", mark)) != std::string::npos) +			{ +				message.replace(mark, 4, ">"); +				mark += 1; +			} +			 +			mark = 0; +			while((mark = message.find("&", mark)) != std::string::npos) +			{ +				message.replace(mark, 5, "&"); +				mark += 1; +			} +		} +		 +		// strip leading/trailing whitespace (since we always seem to get a couple newlines) +		LLStringUtil::trim(message); +		 +//		LL_DEBUGS("Voice") << "    stripped message = \n" << message << LL_ENDL; +		 +		sessionState *session = findSession(sessionHandle); +		if(session) +		{ +			bool is_busy = gAgent.getBusy(); +			bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat); +			bool is_linden = LLMuteList::getInstance()->isLinden(session->mName); +			bool quiet_chat = false; +			LLChat chat; + +			chat.mMuted = is_muted && !is_linden; +			 +			if(!chat.mMuted) +			{ +				chat.mFromID = session->mCallerID; +				chat.mFromName = session->mName; +				chat.mSourceType = CHAT_SOURCE_AGENT; + +				if(is_busy && !is_linden) +				{ +					quiet_chat = true; +					// TODO: Question: Return busy mode response here?  Or maybe when session is started instead? +				} +								 +				LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL; +				gIMMgr->addMessage(session->mIMSessionID, +						session->mCallerID, +						session->mName.c_str(), +						message.c_str(), +						LLStringUtil::null,		// default arg +						IM_NOTHING_SPECIAL,		// default arg +						0,						// default arg +						LLUUID::null,			// default arg +						LLVector3::zero,		// default arg +						true);					// prepend name and make it a link to the user's profile +			} +		}		  	}  } -//---------------------------------------------- -// channels +void LLVoiceClient::sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string ¬ificationType) +{ +	sessionState *session = findSession(sessionHandle); +	 +	if(session) +	{ +		participantState *participant = session->findParticipant(uriString); +		if(participant) +		{ +			if (!stricmp(notificationType.c_str(), "Typing")) +			{ +				// Other end started typing +				// TODO: The proper way to add a typing notification seems to be LLIMMgr::processIMTypingStart(). +				// It requires an LLIMInfo for the message, which we don't have here. +			} +			else if (!stricmp(notificationType.c_str(), "NotTyping")) +			{ +				// Other end stopped typing +				// TODO: The proper way to remove a typing notification seems to be LLIMMgr::processIMTypingStop(). +				// It requires an LLIMInfo for the message, which we don't have here. +			} +			else +			{ +				LL_DEBUGS("Voice") << "Unknown notification type " << notificationType << "for participant " << uriString << " in session " << session->mSIPURI << LL_ENDL; +			} +		} +		else +		{ +			LL_DEBUGS("Voice") << "Unknown participant " << uriString << " in session " << session->mSIPURI << LL_ENDL; +		} +	} +	else +	{ +		LL_DEBUGS("Voice") << "Unknown session handle " << sessionHandle << LL_ENDL; +	} +} -bool LLVoiceClient::inProximalChannel() +void LLVoiceClient::subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType)  { -	if (mVoiceModule)  +	buddyListEntry *buddy = findBuddy(buddyURI); +	 +	if(!buddy)  	{ -		return mVoiceModule->inProximalChannel(); +		// Couldn't find buddy by URI, try converting the alias... +		if(!alias.empty()) +		{ +			LLUUID id; +			if(IDFromName(alias, id)) +			{ +				buddy = findBuddy(id); +			} +		} +	} +	 +	if(buddy) +	{ +		std::ostringstream stream; +		 +		if(buddy->mCanSeeMeOnline) +		{ +			// Sending the response will create an auto-accept rule +			buddy->mHasAutoAcceptListEntry = true; +		} +		else +		{ +			// Sending the response will create a block rule +			buddy->mHasBlockListEntry = true; +		} +		 +		if(buddy->mInSLFriends) +		{ +			buddy->mInVivoxBuddies = true; +		} +		 +		stream +			<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.SendSubscriptionReply.1\">" +				<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" +				<< "<BuddyURI>" << buddy->mURI << "</BuddyURI>" +				<< "<RuleType>" << (buddy->mCanSeeMeOnline?"Allow":"Hide") << "</RuleType>" +				<< "<AutoAccept>"<< (buddy->mInSLFriends?"1":"0")<< "</AutoAccept>" +				<< "<SubscriptionHandle>" << subscriptionHandle << "</SubscriptionHandle>" +			<< "</Request>" +			<< "\n\n\n"; +			 +		writeString(stream.str()); +	} +} + +void LLVoiceClient::auxAudioPropertiesEvent(F32 energy) +{ +	LL_DEBUGS("Voice") << "got energy " << energy << LL_ENDL; +	mTuningEnergy = energy; +} + +void LLVoiceClient::buddyListChanged() +{ +	// This is called after we receive a BuddyAndGroupListChangedEvent. +	mBuddyListMapPopulated = true; +	mFriendsListDirty = true; +} + +void LLVoiceClient::muteListChanged() +{ +	// The user's mute list has been updated.  Go through the current participant list and sync it with the mute list. +	if(mAudioSession) +	{ +		participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin(); +		 +		for(; iter != mAudioSession->mParticipantsByURI.end(); iter++) +		{ +			participantState *p = iter->second; +			 +			// Check to see if this participant is on the mute list already +			if(p->updateMuteState()) +				mAudioSession->mMuteDirty = true; +		} +	} +} + +void LLVoiceClient::updateFriends(U32 mask) +{ +	if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::POWERS)) +	{ +		// Just resend the whole friend list to the daemon +		mFriendsListDirty = true; +	} +} + +///////////////////////////// +// Managing list of participants +LLVoiceClient::participantState::participantState(const std::string &uri) :  +	 mURI(uri),  +	 mPTT(false),  +	 mIsSpeaking(false),  +	 mIsModeratorMuted(false),  +	 mLastSpokeTimestamp(0.f),  +	 mPower(0.f),  +	 mVolume(VOLUME_DEFAULT), +	 mOnMuteList(false), +	 mVolumeSet(false), +	 mVolumeDirty(false), +	 mAvatarIDValid(false), +	 mIsSelf(false) +{ +} + +LLVoiceClient::participantState *LLVoiceClient::sessionState::addParticipant(const std::string &uri) +{ +	participantState *result = NULL; +	bool useAlternateURI = false; +	 +	// Note: this is mostly the body of LLVoiceClient::sessionState::findParticipant(), but since we need to know if it +	// matched the alternate SIP URI (so we can add it properly), we need to reproduce it here. +	{ +		participantMap::iterator iter = mParticipantsByURI.find(&uri); + +		if(iter == mParticipantsByURI.end()) +		{ +			if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI)) +			{ +				// This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant. +				// Use mSIPURI instead, since it will be properly encoded. +				iter = mParticipantsByURI.find(&(mSIPURI)); +				useAlternateURI = true; +			} +		} + +		if(iter != mParticipantsByURI.end()) +		{ +			result = iter->second; +		} +	} +		 +	if(!result) +	{ +		// participant isn't already in one list or the other. +		result = new participantState(useAlternateURI?mSIPURI:uri); +		mParticipantsByURI.insert(participantMap::value_type(&(result->mURI), result)); +		mParticipantsChanged = true; +		 +		// Try to do a reverse transform on the URI to get the GUID back. +		{ +			LLUUID id; +			if(IDFromName(result->mURI, id)) +			{ +				result->mAvatarIDValid = true; +				result->mAvatarID = id; + +				if(result->updateMuteState()) +					mMuteDirty = true; +			} +			else +			{ +				// Create a UUID by hashing the URI, but do NOT set mAvatarIDValid. +				// This tells both code in LLVoiceClient and code in llfloateractivespeakers.cpp that the ID will not be in the name cache. +				setUUIDFromStringHash(result->mAvatarID, uri); +			} +		} +		 +		mParticipantsByUUID.insert(participantUUIDMap::value_type(&(result->mAvatarID), result)); + +		if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume)) +		{ +			result->mVolumeDirty = true; +			mVolumeDirty = true; +		} + +		LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL; +	} +	 +	return result; +} + +bool LLVoiceClient::participantState::updateMuteState() +{ +	bool result = false; +	 +	if(mAvatarIDValid) +	{ +		bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat); +		if(mOnMuteList != isMuted) +		{ +			mOnMuteList = isMuted; +			mVolumeDirty = true; +			result = true; +		} +	} +	return result; +} + +bool LLVoiceClient::participantState::isAvatar() +{ +	return mAvatarIDValid; +} + +void LLVoiceClient::sessionState::removeParticipant(LLVoiceClient::participantState *participant) +{ +	if(participant) +	{ +		participantMap::iterator iter = mParticipantsByURI.find(&(participant->mURI)); +		participantUUIDMap::iterator iter2 = mParticipantsByUUID.find(&(participant->mAvatarID)); +		 +		LL_DEBUGS("Voice") << "participant \"" << participant->mURI <<  "\" (" << participant->mAvatarID << ") removed." << LL_ENDL; +		 +		if(iter == mParticipantsByURI.end()) +		{ +			LL_ERRS("Voice") << "Internal error: participant " << participant->mURI << " not in URI map" << LL_ENDL; +		} +		else if(iter2 == mParticipantsByUUID.end()) +		{ +			LL_ERRS("Voice") << "Internal error: participant ID " << participant->mAvatarID << " not in UUID map" << LL_ENDL; +		} +		else if(iter->second != iter2->second) +		{ +			LL_ERRS("Voice") << "Internal error: participant mismatch!" << LL_ENDL; +		} +		else +		{ +			mParticipantsByURI.erase(iter); +			mParticipantsByUUID.erase(iter2); +			 +			delete participant; +			mParticipantsChanged = true; +		} +	} +} + +void LLVoiceClient::sessionState::removeAllParticipants() +{ +	LL_DEBUGS("Voice") << "called" << LL_ENDL; + +	while(!mParticipantsByURI.empty()) +	{ +		removeParticipant(mParticipantsByURI.begin()->second); +	} +	 +	if(!mParticipantsByUUID.empty()) +	{ +		LL_ERRS("Voice") << "Internal error: empty URI map, non-empty UUID map" << LL_ENDL; +	} +} + +LLVoiceClient::participantMap *LLVoiceClient::getParticipantList(void) +{ +	participantMap *result = NULL; +	if(mAudioSession) +	{ +		result = &(mAudioSession->mParticipantsByURI); +	} +	return result; +} + +void LLVoiceClient::getParticipantsUUIDSet(std::set<LLUUID>& participant_uuids) +{ +	if (NULL == mAudioSession) return; + +	participantUUIDMap::const_iterator it = mAudioSession->mParticipantsByUUID.begin(), +		it_end = mAudioSession->mParticipantsByUUID.end(); +	for (; it != it_end; ++it) +	{ +		participant_uuids.insert((*(*it).first)); +	} +} + +LLVoiceClient::participantState *LLVoiceClient::sessionState::findParticipant(const std::string &uri) +{ +	participantState *result = NULL; +	 +	participantMap::iterator iter = mParticipantsByURI.find(&uri); + +	if(iter == mParticipantsByURI.end()) +	{ +		if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI)) +		{ +			// This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant. +			// Look up the other URI +			iter = mParticipantsByURI.find(&(mSIPURI)); +		} +	} + +	if(iter != mParticipantsByURI.end()) +	{ +		result = iter->second; +	} +		 +	return result; +} + +LLVoiceClient::participantState* LLVoiceClient::sessionState::findParticipantByID(const LLUUID& id) +{ +	participantState * result = NULL; +	participantUUIDMap::iterator iter = mParticipantsByUUID.find(&id); + +	if(iter != mParticipantsByUUID.end()) +	{ +		result = iter->second; +	} + +	return result; +} + +LLVoiceClient::participantState* LLVoiceClient::findParticipantByID(const LLUUID& id) +{ +	participantState * result = NULL; +	 +	if(mAudioSession) +	{ +		result = mAudioSession->findParticipantByID(id); +	} +	 +	return result; +} + + +void LLVoiceClient::parcelChanged() +{ +	if(getState() >= stateNoChannel) +	{ +		// If the user is logged in, start a channel lookup. +		LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL; + +		std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest"); +		LLSD data; +		LLHTTPClient::post( +			url, +			data, +			new LLVoiceClientCapResponder);  	}  	else  	{ -		return false; +		// The transition to stateNoChannel needs to kick this off again. +		LL_INFOS("Voice") << "not logged in yet, deferring" << LL_ENDL; +	} +} + +void LLVoiceClient::switchChannel( +	std::string uri, +	bool spatial, +	bool no_reconnect, +	bool is_p2p, +	std::string hash) +{ +	bool needsSwitch = false; +	 +	LL_DEBUGS("Voice")  +		<< "called in state " << state2string(getState())  +		<< " with uri \"" << uri << "\""  +		<< (spatial?", spatial is true":", spatial is false") +		<< LL_ENDL; +	 +	switch(getState()) +	{ +		case stateJoinSessionFailed: +		case stateJoinSessionFailedWaiting: +		case stateNoChannel: +			// Always switch to the new URI from these states. +			needsSwitch = true; +		break; + +		default: +			if(mSessionTerminateRequested) +			{ +				// If a terminate has been requested, we need to compare against where the URI we're already headed to. +				if(mNextAudioSession) +				{ +					if(mNextAudioSession->mSIPURI != uri) +						needsSwitch = true; +				} +				else +				{ +					// mNextAudioSession is null -- this probably means we're on our way back to spatial. +					if(!uri.empty()) +					{ +						// We do want to process a switch in this case. +						needsSwitch = true; +					} +				} +			} +			else +			{ +				// Otherwise, compare against the URI we're in now. +				if(mAudioSession) +				{ +					if(mAudioSession->mSIPURI != uri) +					{ +						needsSwitch = true; +					} +				} +				else +				{ +					if(!uri.empty()) +					{ +						// mAudioSession is null -- it's not clear what case would cause this. +						// For now, log it as a warning and see if it ever crops up. +						LL_WARNS("Voice") << "No current audio session." << LL_ENDL; +					} +				} +			} +		break; +	} +	 +	if(needsSwitch) +	{ +		if(uri.empty()) +		{ +			// Leave any channel we may be in +			LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL; + +			sessionState *oldSession = mNextAudioSession; +			mNextAudioSession = NULL; + +			// The old session may now need to be deleted. +			reapSession(oldSession); + +			notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED); +		} +		else +		{ +			LL_DEBUGS("Voice") << "switching to channel " << uri << LL_ENDL; + +			mNextAudioSession = addSession(uri); +			mNextAudioSession->mHash = hash; +			mNextAudioSession->mIsSpatial = spatial; +			mNextAudioSession->mReconnect = !no_reconnect; +			mNextAudioSession->mIsP2P = is_p2p; +		} +		 +		if(getState() <= stateNoChannel) +		{ +			// We're already set up to join a channel, just needed to fill in the session URI +		} +		else +		{ +			// State machine will come around and rejoin if uri/handle is not empty. +			sessionTerminate(); +		} +	} +} + +void LLVoiceClient::joinSession(sessionState *session) +{ +	mNextAudioSession = session; +	 +	if(getState() <= stateNoChannel) +	{ +		// We're already set up to join a channel, just needed to fill in the session handle +	} +	else +	{ +		// State machine will come around and rejoin if uri/handle is not empty. +		sessionTerminate();  	}  } @@ -344,417 +5454,1822 @@ void LLVoiceClient::setNonSpatialChannel(  	const std::string &uri,  	const std::string &credentials)  { -	if (mVoiceModule) mVoiceModule->setNonSpatialChannel(uri, credentials); +	switchChannel(uri, false, false, false, credentials);  }  void LLVoiceClient::setSpatialChannel(  	const std::string &uri,  	const std::string &credentials)  { -	if (mVoiceModule) mVoiceModule->setSpatialChannel(uri, credentials); +	mSpatialSessionURI = uri; +	mSpatialSessionCredentials = credentials; +	mAreaVoiceDisabled = mSpatialSessionURI.empty(); + +	LL_DEBUGS("Voice") << "got spatial channel uri: \"" << uri << "\"" << LL_ENDL; +	 +	if((mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial))) +	{ +		// User is in a non-spatial chat or joining a non-spatial chat.  Don't switch channels. +		LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL; +	} +	else +	{ +		switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials); +	}  } -void LLVoiceClient::leaveNonSpatialChannel() +void LLVoiceClient::callUser(const LLUUID &uuid)  { -	if (mVoiceModule) mVoiceModule->leaveNonSpatialChannel(); +	std::string userURI = sipURIFromID(uuid); + +	switchChannel(userURI, false, true, true);  } -void LLVoiceClient::leaveChannel(void) +LLVoiceClient::sessionState* LLVoiceClient::startUserIMSession(const LLUUID &uuid)  { -	if (mVoiceModule) mVoiceModule->leaveChannel(); +	// Figure out if a session with the user already exists +	sessionState *session = findSession(uuid); +	if(!session) +	{ +		// No session with user, need to start one. +		std::string uri = sipURIFromID(uuid); +		session = addSession(uri); + +		llassert(session); +		if (!session) return NULL; + +		session->mIsSpatial = false; +		session->mReconnect = false;	 +		session->mIsP2P = true; +		session->mCallerID = uuid; +	} +	 +	if(session->mHandle.empty()) +	{ +		// Session isn't active -- start it up. +		sessionCreateSendMessage(session, false, true); +	} +	else +	{	 +		// Session is already active -- start up text. +		sessionTextConnectSendMessage(session); +	} +	 +	return session;  } -std::string LLVoiceClient::getCurrentChannel() +bool LLVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message) +{ +	bool result = false; + +	// Attempt to locate the indicated session +	sessionState *session = startUserIMSession(participant_id); +	if(session) +	{ +		// found the session, attempt to send the message +		session->mTextMsgQueue.push(message); +		 +		// Try to send queued messages (will do nothing if the session is not open yet) +		sendQueuedTextMessages(session); + +		// The message is queued, so we succeed. +		result = true; +	}	 +	else +	{ +		LL_DEBUGS("Voice") << "Session not found for participant ID " << participant_id << LL_ENDL; +	} +	 +	return result; +} + +void LLVoiceClient::sendQueuedTextMessages(sessionState *session)  { -	if (mVoiceModule)  +	if(session->mTextStreamState == 1)  	{ -		return mVoiceModule->getCurrentChannel(); +		if(!session->mTextMsgQueue.empty()) +		{ +			std::ostringstream stream; +			 +			while(!session->mTextMsgQueue.empty()) +			{ +				std::string message = session->mTextMsgQueue.front(); +				session->mTextMsgQueue.pop(); +				stream +				<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SendMessage.1\">" +					<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" +					<< "<MessageHeader>text/HTML</MessageHeader>" +					<< "<MessageBody>" << message << "</MessageBody>" +				<< "</Request>" +				<< "\n\n\n"; +			}		 +			writeString(stream.str()); +		}  	}  	else  	{ -		return std::string(); +		// Session isn't connected yet, defer until later.  	}  } +void LLVoiceClient::endUserIMSession(const LLUUID &uuid) +{ +	// Figure out if a session with the user exists +	sessionState *session = findSession(uuid); +	if(session) +	{ +		// found the session +		if(!session->mHandle.empty()) +		{ +			sessionTextDisconnectSendMessage(session); +		} +	}	 +	else +	{ +		LL_DEBUGS("Voice") << "Session not found for participant ID " << uuid << LL_ENDL; +	} +} -//--------------------------------------- -// invitations +bool LLVoiceClient::answerInvite(std::string &sessionHandle) +{ +	// this is only ever used to answer incoming p2p call invites. +	 +	sessionState *session = findSession(sessionHandle); +	if(session) +	{ +		session->mIsSpatial = false; +		session->mReconnect = false;	 +		session->mIsP2P = true; -void LLVoiceClient::callUser(const LLUUID &uuid) +		joinSession(session); +		return true; +	} +	 +	return false; +} + +bool LLVoiceClient::isOnlineSIP(const LLUUID &id)  { -	if (mVoiceModule) mVoiceModule->callUser(uuid); +	bool result = false; +	buddyListEntry *buddy = findBuddy(id); +	if(buddy) +	{ +		result = buddy->mOnlineSLim; +		LL_DEBUGS("Voice") << "Buddy " << buddy->mDisplayName << " is SIP " << (result?"online":"offline") << LL_ENDL; +	} + +	if(!result) +	{ +		// This user isn't on the buddy list or doesn't show online status through the buddy list, but could be a participant in an existing session if they initiated a text IM. +		sessionState *session = findSession(id); +		if(session && !session->mHandle.empty()) +		{ +			if((session->mTextStreamState != streamStateUnknown) || (session->mMediaStreamState > streamStateIdle)) +			{ +				LL_DEBUGS("Voice") << "Open session with " << id << " found, returning SIP online state" << LL_ENDL; +				// we have a p2p text session open with this user, so by definition they're online. +				result = true; +			} +		} +	} +	 +	return result;  } -bool LLVoiceClient::answerInvite(std::string &channelHandle) +// Returns true if the indicated participant in the current audio session is really an SL avatar. +// Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls. +bool LLVoiceClient::isParticipantAvatar(const LLUUID &id)  { -	if (mVoiceModule)  +	bool result = true;  +	sessionState *session = findSession(id); +	 +	if(session != NULL)  	{ -		return mVoiceModule->answerInvite(channelHandle); +		// this is a p2p session with the indicated caller, or the session with the specified UUID. +		if(session->mSynthesizedCallerID) +			result = false;  	}  	else  	{ -		return false; +		// Didn't find a matching session -- check the current audio session for a matching participant +		if(mAudioSession != NULL) +		{ +			participantState *participant = findParticipantByID(id); +			if(participant != NULL) +			{ +				result = participant->isAvatar(); +			} +		}  	} +	 +	return result;  } -void LLVoiceClient::declineInvite(std::string &channelHandle) +// Returns true if calling back the session URI after the session has closed is possible. +// Currently this will be false only for PSTN P2P calls.		 +bool LLVoiceClient::isSessionCallBackPossible(const LLUUID &session_id)  { -	if (mVoiceModule) mVoiceModule->declineInvite(channelHandle); +	bool result = true;  +	sessionState *session = findSession(session_id); +	 +	if(session != NULL) +	{ +		result = session->isCallBackPossible(); +	} +	 +	return result;  } +// Returns true if the session can accepte text IM's. +// Currently this will be false only for PSTN P2P calls. +bool LLVoiceClient::isSessionTextIMPossible(const LLUUID &session_id) +{ +	bool result = true;  +	sessionState *session = findSession(session_id); +	 +	if(session != NULL) +	{ +		result = session->isTextIMPossible(); +	} +	 +	return result; +} +		 -//------------------------------------------ -// Volume/gain +void LLVoiceClient::declineInvite(std::string &sessionHandle) +{ +	sessionState *session = findSession(sessionHandle); +	if(session) +	{ +		sessionMediaDisconnectSendMessage(session); +	} +} +void LLVoiceClient::leaveNonSpatialChannel() +{ +	LL_DEBUGS("Voice")  +		<< "called in state " << state2string(getState())  +		<< LL_ENDL; +	 +	// Make sure we don't rejoin the current session.	 +	sessionState *oldNextSession = mNextAudioSession; +	mNextAudioSession = NULL; +	 +	// Most likely this will still be the current session at this point, but check it anyway. +	reapSession(oldNextSession); +	 +	verifySessionState(); +	 +	sessionTerminate(); +} -void LLVoiceClient::setVoiceVolume(F32 volume) +std::string LLVoiceClient::getCurrentChannel()  { -	if (mVoiceModule) mVoiceModule->setVoiceVolume(volume); +	std::string result; +	 +	if((getState() == stateRunning) && !mSessionTerminateRequested) +	{ +		result = getAudioSessionURI(); +	} +	 +	return result;  } -void LLVoiceClient::setMicGain(F32 volume) +bool LLVoiceClient::inProximalChannel()  { -	if (mVoiceModule) mVoiceModule->setMicGain(volume); +	bool result = false; +	 +	if((getState() == stateRunning) && !mSessionTerminateRequested) +	{ +		result = inSpatialChannel(); +	} +	 +	return result;  } +std::string LLVoiceClient::sipURIFromID(const LLUUID &id) +{ +	std::string result; +	result = "sip:"; +	result += nameFromID(id); +	result += "@"; +	result += mVoiceSIPURIHostName; +	 +	return result; +} -//------------------------------------------ -// enable/disable voice features +std::string LLVoiceClient::sipURIFromAvatar(LLVOAvatar *avatar) +{ +	std::string result; +	if(avatar) +	{ +		result = "sip:"; +		result += nameFromID(avatar->getID()); +		result += "@"; +		result += mVoiceSIPURIHostName; +	} +	 +	return result; +} -bool LLVoiceClient::voiceEnabled() +std::string LLVoiceClient::nameFromAvatar(LLVOAvatar *avatar)  { -	if (mVoiceModule)  +	std::string result; +	if(avatar)  	{ -		return mVoiceModule->voiceEnabled(); +		result = nameFromID(avatar->getID()); +	}	 +	return result; +} + +std::string LLVoiceClient::nameFromID(const LLUUID &uuid) +{ +	std::string result; +	 +	if (uuid.isNull()) { +		//VIVOX, the uuid emtpy look for the mURIString and return that instead. +		//result.assign(uuid.mURIStringName); +		LLStringUtil::replaceChar(result, '_', ' '); +		return result;  	} -	else +	// Prepending this apparently prevents conflicts with reserved names inside the vivox and diamondware code. +	result = "x"; +	 +	// Base64 encode and replace the pieces of base64 that are less compatible  +	// with e-mail local-parts. +	// See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet" +	result += LLBase64::encode(uuid.mData, UUID_BYTES); +	LLStringUtil::replaceChar(result, '+', '-'); +	LLStringUtil::replaceChar(result, '/', '_'); +	 +	// If you need to transform a GUID to this form on the Mac OS X command line, this will do so: +	// echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-') +	 +	// The reverse transform can be done with: +	// echo 'x5mkTKmxDTuGnjWyC__WfMg==' |cut -b 2- -|tr '_-' '/+' |openssl base64 -d|xxd -p +	 +	return result; +} + +bool LLVoiceClient::IDFromName(const std::string inName, LLUUID &uuid) +{ +	bool result = false; +	 +	// SLIM SDK: The "name" may actually be a SIP URI such as: "sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com" +	// If it is, convert to a bare name before doing the transform. +	std::string name = nameFromsipURI(inName); +	 +	// Doesn't look like a SIP URI, assume it's an actual name. +	if(name.empty()) +		name = inName; + +	// This will only work if the name is of the proper form. +	// As an example, the account name for Monroe Linden (UUID 1673cfd3-8229-4445-8d92-ec3570e5e587) is: +	// "xFnPP04IpREWNkuw1cOXlhw==" +	 +	if((name.size() == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '=')) +	{ +		// The name appears to have the right form. + +		// Reverse the transforms done by nameFromID +		std::string temp = name; +		LLStringUtil::replaceChar(temp, '-', '+'); +		LLStringUtil::replaceChar(temp, '_', '/'); + +		U8 rawuuid[UUID_BYTES + 1];  +		int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1); +		if(len == UUID_BYTES) +		{ +			// The decode succeeded.  Stuff the bits into the result's UUID +			memcpy(uuid.mData, rawuuid, UUID_BYTES); +			result = true; +		} +	}  +	 +	if(!result)  	{ -		return false; +		// VIVOX:  not a standard account name, just copy the URI name mURIString field +		// and hope for the best.  bpj +		uuid.setNull();  // VIVOX, set the uuid field to nulls  	} +	 +	return result;  } -void LLVoiceClient::setVoiceEnabled(bool enabled) +std::string LLVoiceClient::displayNameFromAvatar(LLVOAvatar *avatar)  { -	if (mVoiceModule) mVoiceModule->setVoiceEnabled(enabled); +	return avatar->getFullname();  } -void LLVoiceClient::setLipSyncEnabled(BOOL enabled) +std::string LLVoiceClient::sipURIFromName(std::string &name)  { -	if (mVoiceModule) mVoiceModule->setLipSyncEnabled(enabled); +	std::string result; +	result = "sip:"; +	result += name; +	result += "@"; +	result += mVoiceSIPURIHostName; + +//	LLStringUtil::toLower(result); + +	return result;  } -BOOL LLVoiceClient::lipSyncEnabled() +std::string LLVoiceClient::nameFromsipURI(const std::string &uri)  { -	if (mVoiceModule)  +	std::string result; + +	std::string::size_type sipOffset, atOffset; +	sipOffset = uri.find("sip:"); +	atOffset = uri.find("@"); +	if((sipOffset != std::string::npos) && (atOffset != std::string::npos))  	{ -		return mVoiceModule->lipSyncEnabled(); +		result = uri.substr(sipOffset + 4, atOffset - (sipOffset + 4));  	} -	else +	 +	return result; +} + +bool LLVoiceClient::inSpatialChannel(void) +{ +	bool result = false; +	 +	if(mAudioSession) +		result = mAudioSession->mIsSpatial; +		 +	return result; +} + +std::string LLVoiceClient::getAudioSessionURI() +{ +	std::string result; +	 +	if(mAudioSession) +		result = mAudioSession->mSIPURI; +		 +	return result; +} + +std::string LLVoiceClient::getAudioSessionHandle() +{ +	std::string result; +	 +	if(mAudioSession) +		result = mAudioSession->mHandle; +		 +	return result; +} + + +///////////////////////////// +// Sending updates of current state + +void LLVoiceClient::enforceTether(void) +{ +	LLVector3d tethered	= mCameraRequestedPosition; + +	// constrain 'tethered' to within 50m of mAvatarPosition. +	{ +		F32 max_dist = 50.0f; +		LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition; +		F32 camera_distance = (F32)camera_offset.magVec(); +		if(camera_distance > max_dist) +		{ +			tethered = mAvatarPosition +  +				(max_dist / camera_distance) * camera_offset; +		} +	} +	 +	if(dist_vec(mCameraPosition, tethered) > 0.1)  	{ -		return false; +		mCameraPosition = tethered; +		mSpatialCoordsDirty = true;  	}  } -void LLVoiceClient::setMuteMic(bool muted) +void LLVoiceClient::updatePosition(void) +{ +	if(gVoiceClient) +	{ +		LLViewerRegion *region = gAgent.getRegion(); +		if(region && isAgentAvatarValid()) +		{ +			LLMatrix3 rot; +			LLVector3d pos; + +			// TODO: If camera and avatar velocity are actually used by the voice system, we could compute them here... +			// They're currently always set to zero. + +			// Send the current camera position to the voice code +			rot.setRows(LLViewerCamera::getInstance()->getAtAxis(), LLViewerCamera::getInstance()->getLeftAxis (),  LLViewerCamera::getInstance()->getUpAxis());		 +			pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin()); +			 +			gVoiceClient->setCameraPosition( +					pos,				// position +					LLVector3::zero, 	// velocity +					rot);				// rotation matrix +					 +			// Send the current avatar position to the voice code +			rot = gAgentAvatarp->getRootJoint()->getWorldRotation().getMatrix3(); +	 +			pos = gAgentAvatarp->getPositionGlobal(); +			// TODO: Can we get the head offset from outside the LLVOAvatar? +//			pos += LLVector3d(mHeadOffset); +			pos += LLVector3d(0.f, 0.f, 1.f); +		 +			gVoiceClient->setAvatarPosition( +					pos,				// position +					LLVector3::zero, 	// velocity +					rot);				// rotation matrix +		} +	} +} + +void LLVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)  { -	if (mVoiceModule) mVoiceModule->setMuteMic(muted); +	mCameraRequestedPosition = position; +	 +	if(mCameraVelocity != velocity) +	{ +		mCameraVelocity = velocity; +		mSpatialCoordsDirty = true; +	} +	 +	if(mCameraRot != rot) +	{ +		mCameraRot = rot; +		mSpatialCoordsDirty = true; +	}  } +void LLVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot) +{ +	if(dist_vec(mAvatarPosition, position) > 0.1) +	{ +		mAvatarPosition = position; +		mSpatialCoordsDirty = true; +	} +	 +	if(mAvatarVelocity != velocity) +	{ +		mAvatarVelocity = velocity; +		mSpatialCoordsDirty = true; +	} +	 +	if(mAvatarRot != rot) +	{ +		mAvatarRot = rot; +		mSpatialCoordsDirty = true; +	} +} + +bool LLVoiceClient::channelFromRegion(LLViewerRegion *region, std::string &name) +{ +	bool result = false; +	 +	if(region) +	{ +		name = region->getName(); +	} +	 +	if(!name.empty()) +		result = true; +	 +	return result; +} + +void LLVoiceClient::leaveChannel(void) +{ +	if(getState() == stateRunning) +	{ +		LL_DEBUGS("Voice") << "leaving channel for teleport/logout" << LL_ENDL; +		mChannelName.clear(); +		sessionTerminate(); +	} +} + +void LLVoiceClient::setMuteMic(bool muted) +{ +	mMuteMic = muted; +} -// ---------------------------------------------- -// PTT +bool LLVoiceClient::getMuteMic() const +{ +	return mMuteMic; +}  void LLVoiceClient::setUserPTTState(bool ptt)  { -	if (mVoiceModule) mVoiceModule->setUserPTTState(ptt); +	mUserPTTState = ptt;  }  bool LLVoiceClient::getUserPTTState()  { -	if (mVoiceModule)  +	return mUserPTTState; +} + +void LLVoiceClient::toggleUserPTTState(void) +{ +	mUserPTTState = !mUserPTTState; +} + +void LLVoiceClient::setVoiceEnabled(bool enabled) +{ +	if (enabled != mVoiceEnabled)  	{ -		return mVoiceModule->getUserPTTState(); +		mVoiceEnabled = enabled; +		LLVoiceClientStatusObserver::EStatusType status; + +		if (enabled) +		{ +			LLVoiceChannel::getCurrentVoiceChannel()->activate(); +			status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED; +		} +		else +		{ +			// Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it. +			LLVoiceChannel::getCurrentVoiceChannel()->deactivate(); +			status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED; +		} + +		notifyStatusObservers(status); +	} +} + +bool LLVoiceClient::voiceEnabled() +{ +	return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice"); +} + +//AD *TODO: investigate possible merge of voiceWorking() and voiceEnabled() into one non-static method +bool LLVoiceClient::voiceWorking() +{ +	//Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758) +	// Condition with joining spatial num was added to take into account possible problems with connection to voice +	// server(EXT-4313). See bug descriptions and comments for MAX_NORMAL_JOINING_SPATIAL_NUM for more info. +	return (mSpatialJoiningNum < MAX_NORMAL_JOINING_SPATIAL_NUM) && (stateLoggedIn <= mState) && (mState <= stateSessionTerminated); +} + +void LLVoiceClient::setLipSyncEnabled(BOOL enabled) +{ +	mLipSyncEnabled = enabled; +} + +BOOL LLVoiceClient::lipSyncEnabled() +{ +	    +	if ( mVoiceEnabled && stateDisabled != getState() ) +	{ +		return mLipSyncEnabled;  	}  	else  	{ -		return false; +		return FALSE;  	}  }  void LLVoiceClient::setUsePTT(bool usePTT)  { -	if (mVoiceModule) mVoiceModule->setUsePTT(usePTT); +	if(usePTT && !mUsePTT) +	{ +		// When the user turns on PTT, reset the current state. +		mUserPTTState = false; +	} +	mUsePTT = usePTT;  }  void LLVoiceClient::setPTTIsToggle(bool PTTIsToggle)  { -	if (mVoiceModule) mVoiceModule->setPTTIsToggle(PTTIsToggle); +	if(!PTTIsToggle && mPTTIsToggle) +	{ +		// When the user turns off toggle, reset the current state. +		mUserPTTState = false; +	} +	 +	mPTTIsToggle = PTTIsToggle;  }  bool LLVoiceClient::getPTTIsToggle()  { -	if (mVoiceModule)  +	return mPTTIsToggle; +} + +void LLVoiceClient::setPTTKey(std::string &key) +{ +	if(key == "MiddleMouse")  	{ -		return mVoiceModule->getPTTIsToggle(); +		mPTTIsMiddleMouse = true;  	} -	else { -		return false; +	else +	{ +		mPTTIsMiddleMouse = false; +		if(!LLKeyboard::keyFromString(key, &mPTTKey)) +		{ +			// If the call failed, don't match any key. +			key = KEY_NONE; +		}  	} +} +void LLVoiceClient::setEarLocation(S32 loc) +{ +	if(mEarLocation != loc) +	{ +		LL_DEBUGS("Voice") << "Setting mEarLocation to " << loc << LL_ENDL; +		 +		mEarLocation = loc; +		mSpatialCoordsDirty = true; +	}  } -void LLVoiceClient::inputUserControlState(bool down) +void LLVoiceClient::setVoiceVolume(F32 volume)  { -	if (mVoiceModule) mVoiceModule->inputUserControlState(down);	 +	int scaled_volume = scale_speaker_volume(volume);	 + +	if(scaled_volume != mSpeakerVolume) +	{ +		int min_volume = scale_speaker_volume(0); +		if((scaled_volume == min_volume) || (mSpeakerVolume == min_volume)) +		{ +			mSpeakerMuteDirty = true; +		} + +		mSpeakerVolume = scaled_volume; +		mSpeakerVolumeDirty = true; +	}  } -void LLVoiceClient::toggleUserPTTState(void) +void LLVoiceClient::setMicGain(F32 volume)  { -	if (mVoiceModule) mVoiceModule->toggleUserPTTState(); +	int scaled_volume = scale_mic_volume(volume); +	 +	if(scaled_volume != mMicVolume) +	{ +		mMicVolume = scaled_volume; +		mMicVolumeDirty = true; +	}  }  void LLVoiceClient::keyDown(KEY key, MASK mask)  {	 -	if (mVoiceModule) mVoiceModule->keyDown(key, mask); +	if (gKeyboard->getKeyRepeated(key)) +	{ +		// ignore auto-repeat keys +		return; +	} + +	if(!mPTTIsMiddleMouse) +	{ +		bool down = (mPTTKey != KEY_NONE) +			&& gKeyboard->getKeyDown(mPTTKey); +		inputUserControlState(down); +	}  }  void LLVoiceClient::keyUp(KEY key, MASK mask)  { -	if (mVoiceModule) mVoiceModule->keyUp(key, mask); +	if(!mPTTIsMiddleMouse) +	{ +		bool down = (mPTTKey != KEY_NONE) +			&& gKeyboard->getKeyDown(mPTTKey); +		inputUserControlState(down); +	} +} +void LLVoiceClient::inputUserControlState(bool down) +{ +	if(mPTTIsToggle) +	{ +		if(down) // toggle open-mic state on 'down' +		{ +			toggleUserPTTState(); +		} +	} +	else // set open-mic state as an absolute +	{ +		setUserPTTState(down); +	}  }  void LLVoiceClient::middleMouseState(bool down)  { -	if (mVoiceModule) mVoiceModule->middleMouseState(down); +	if(mPTTIsMiddleMouse) +	{ +		inputUserControlState(down); +	}  } +///////////////////////////// +// Accessors for data related to nearby speakers +BOOL LLVoiceClient::getVoiceEnabled(const LLUUID& id) +{ +	BOOL result = FALSE; +	participantState *participant = findParticipantByID(id); +	if(participant) +	{ +		// I'm not sure what the semantics of this should be. +		// For now, if we have any data about the user that came through the chat channel, assume they're voice-enabled. +		result = TRUE; +	} +	 +	return result; +} -//------------------------------------------- -// nearby speaker accessors +BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id) +{ +	BOOL result = FALSE; -BOOL LLVoiceClient::getVoiceEnabled(const LLUUID& id) +	participantState *participant = findParticipantByID(id); +	if(participant) +	{ +		if (participant->mSpeakingTimeout.getElapsedTimeF32() > SPEAKING_TIMEOUT) +		{ +			participant->mIsSpeaking = FALSE; +		} +		result = participant->mIsSpeaking; +	} +	 +	return result; +} + +BOOL LLVoiceClient::getIsModeratorMuted(const LLUUID& id)  { -	if (mVoiceModule)  +	BOOL result = FALSE; + +	participantState *participant = findParticipantByID(id); +	if(participant)  	{ -		return mVoiceModule->getVoiceEnabled(id); -	}  -	else +		result = participant->mIsModeratorMuted; +	} +	 +	return result; +} + +F32 LLVoiceClient::getCurrentPower(const LLUUID& id) +{		 +	F32 result = 0; +	participantState *participant = findParticipantByID(id); +	if(participant)  	{ -		return FALSE; +		result = participant->mPower;  	} +	 +	return result;  } +  std::string LLVoiceClient::getDisplayName(const LLUUID& id)  { -	if (mVoiceModule)  +	std::string result; +	participantState *participant = findParticipantByID(id); +	if(participant)  	{ -		return mVoiceModule->getDisplayName(id); +		result = participant->mDisplayName;  	} -	else +	 +	return result; +} + + +BOOL LLVoiceClient::getUsingPTT(const LLUUID& id) +{ +	BOOL result = FALSE; + +	participantState *participant = findParticipantByID(id); +	if(participant)  	{ -	  return std::string(); +		// I'm not sure what the semantics of this should be. +		// Does "using PTT" mean they're configured with a push-to-talk button? +		// For now, we know there's no PTT mechanism in place, so nobody is using it.  	} +	 +	return result;  } -bool LLVoiceClient::isVoiceWorking() +BOOL LLVoiceClient::getOnMuteList(const LLUUID& id)  { -	if (mVoiceModule)  +	BOOL result = FALSE; +	 +	participantState *participant = findParticipantByID(id); +	if(participant)  	{ -		return mVoiceModule->isVoiceWorking(); +		result = participant->mOnMuteList;  	} -	return false; + +	return result;  } -BOOL LLVoiceClient::isParticipantAvatar(const LLUUID& id) +// External accessors. +F32 LLVoiceClient::getUserVolume(const LLUUID& id)  { -	if (mVoiceModule)  +	// Minimum volume will be returned for users with voice disabled +	F32 result = VOLUME_MIN; +	 +	participantState *participant = findParticipantByID(id); +	if(participant)  	{ -		return mVoiceModule->isParticipantAvatar(id); +		result = participant->mVolume; + +		// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. +		// LL_DEBUGS("Voice") << "mVolume = " << result <<  " for " << id << LL_ENDL;  	} -	else + +	return result; +} + +void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume) +{ +	if(mAudioSession)  	{ -		return FALSE; +		participantState *participant = findParticipantByID(id); +		if (participant && !participant->mIsSelf) +		{ +			if (!is_approx_equal(volume, VOLUME_DEFAULT)) +			{ +				// Store this volume setting for future sessions if it has been +				// changed from the default +				LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume); +			} +			else +			{ +				// Remove stored volume setting if it is returned to the default +				LLSpeakerVolumeStorage::getInstance()->removeSpeakerVolume(id); +			} + +			participant->mVolume = llclamp(volume, VOLUME_MIN, VOLUME_MAX); +			participant->mVolumeDirty = true; +			mAudioSession->mVolumeDirty = true; +		}  	}  } -BOOL LLVoiceClient::isOnlineSIP(const LLUUID& id) +std::string LLVoiceClient::getGroupID(const LLUUID& id)  { -	if (mVoiceModule)  +	std::string result; + +	participantState *participant = findParticipantByID(id); +	if(participant)  	{ -		return mVoiceModule->isOnlineSIP(id); +		result = participant->mGroupID;  	} -	else +	 +	return result; +} + +BOOL LLVoiceClient::getAreaVoiceDisabled() +{ +	return mAreaVoiceDisabled; +} + +void LLVoiceClient::recordingLoopStart(int seconds, int deltaFramesPerControlFrame) +{ +//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Start)" << LL_ENDL; +	 +	if(!mMainSessionGroupHandle.empty())  	{ -		return FALSE; +		std::ostringstream stream; +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">" +		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" +		<< "<RecordingControlType>Start</RecordingControlType>"  +		<< "<DeltaFramesPerControlFrame>" << deltaFramesPerControlFrame << "</DeltaFramesPerControlFrame>" +		<< "<Filename>" << "" << "</Filename>" +		<< "<EnableAudioRecordingEvents>false</EnableAudioRecordingEvents>" +		<< "<LoopModeDurationSeconds>" << seconds << "</LoopModeDurationSeconds>" +		<< "</Request>\n\n\n"; + + +		writeString(stream.str());  	}  } -BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id) +void LLVoiceClient::recordingLoopSave(const std::string& filename)  { -	if (mVoiceModule)  +//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Flush)" << LL_ENDL; + +	if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())  	{ -		return mVoiceModule->getIsSpeaking(id); +		std::ostringstream stream; +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">" +		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" +		<< "<RecordingControlType>Flush</RecordingControlType>"  +		<< "<Filename>" << filename << "</Filename>" +		<< "</Request>\n\n\n"; + +		writeString(stream.str());  	} -	else +} + +void LLVoiceClient::recordingStop() +{ +//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Stop)" << LL_ENDL; + +	if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())  	{ -		return FALSE; +		std::ostringstream stream; +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">" +		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" +		<< "<RecordingControlType>Stop</RecordingControlType>"  +		<< "</Request>\n\n\n"; + +		writeString(stream.str());  	}  } -BOOL LLVoiceClient::getIsModeratorMuted(const LLUUID& id) +void LLVoiceClient::filePlaybackStart(const std::string& filename)  { -	if (mVoiceModule)  +//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Start)" << LL_ENDL; + +	if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())  	{ -		return mVoiceModule->getIsModeratorMuted(id); +		std::ostringstream stream; +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">" +		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" +		<< "<RecordingControlType>Start</RecordingControlType>"  +		<< "<Filename>" << filename << "</Filename>" +		<< "</Request>\n\n\n"; + +		writeString(stream.str());  	} -	else +} + +void LLVoiceClient::filePlaybackStop() +{ +//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Stop)" << LL_ENDL; + +	if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())  	{ -		return FALSE; +		std::ostringstream stream; +		stream +		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">" +		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" +		<< "<RecordingControlType>Stop</RecordingControlType>"  +		<< "</Request>\n\n\n"; + +		writeString(stream.str());  	}  } -F32 LLVoiceClient::getCurrentPower(const LLUUID& id) -{		 -	if (mVoiceModule)  +void LLVoiceClient::filePlaybackSetPaused(bool paused) +{ +	// TODO: Implement once Vivox gives me a sample +} + +void LLVoiceClient::filePlaybackSetMode(bool vox, float speed) +{ +	// TODO: Implement once Vivox gives me a sample +} + +LLVoiceClient::sessionState::sessionState() : +	mErrorStatusCode(0), +	mMediaStreamState(streamStateUnknown), +	mTextStreamState(streamStateUnknown), +	mCreateInProgress(false), +	mMediaConnectInProgress(false), +	mVoiceInvitePending(false), +	mTextInvitePending(false), +	mSynthesizedCallerID(false), +	mIsChannel(false), +	mIsSpatial(false), +	mIsP2P(false), +	mIncoming(false), +	mVoiceEnabled(false), +	mReconnect(false), +	mVolumeDirty(false), +	mMuteDirty(false), +	mParticipantsChanged(false) +{ +} + +LLVoiceClient::sessionState::~sessionState() +{ +	removeAllParticipants(); +} + +bool LLVoiceClient::sessionState::isCallBackPossible() +{ +	// This may change to be explicitly specified by vivox in the future... +	// Currently, only PSTN P2P calls cannot be returned. +	// Conveniently, this is also the only case where we synthesize a caller UUID. +	return !mSynthesizedCallerID; +} + +bool LLVoiceClient::sessionState::isTextIMPossible() +{ +	// This may change to be explicitly specified by vivox in the future... +	return !mSynthesizedCallerID; +} + + +LLVoiceClient::sessionIterator LLVoiceClient::sessionsBegin(void) +{ +	return mSessions.begin(); +} + +LLVoiceClient::sessionIterator LLVoiceClient::sessionsEnd(void) +{ +	return mSessions.end(); +} + + +LLVoiceClient::sessionState *LLVoiceClient::findSession(const std::string &handle) +{ +	sessionState *result = NULL; +	sessionMap::iterator iter = mSessionsByHandle.find(&handle); +	if(iter != mSessionsByHandle.end())  	{ -		return mVoiceModule->getCurrentPower(id); +		result = iter->second;  	} -	else +	 +	return result; +} + +LLVoiceClient::sessionState *LLVoiceClient::findSessionBeingCreatedByURI(const std::string &uri) +{	 +	sessionState *result = NULL; +	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)  	{ -		return 0.0; +		sessionState *session = *iter; +		if(session->mCreateInProgress && (session->mSIPURI == uri)) +		{ +			result = session; +			break; +		}  	} +	 +	return result;  } -BOOL LLVoiceClient::getOnMuteList(const LLUUID& id) +LLVoiceClient::sessionState *LLVoiceClient::findSession(const LLUUID &participant_id)  { -	if (mVoiceModule)  +	sessionState *result = NULL; +	 +	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) +	{ +		sessionState *session = *iter; +		if((session->mCallerID == participant_id) || (session->mIMSessionID == participant_id)) +		{ +			result = session; +			break; +		} +	} +	 +	return result; +} + +LLVoiceClient::sessionState *LLVoiceClient::addSession(const std::string &uri, const std::string &handle) +{ +	sessionState *result = NULL; +	 +	if(handle.empty())  	{ -		return mVoiceModule->getOnMuteList(id); +		// No handle supplied. +		// Check whether there's already a session with this URI +		for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) +		{ +			sessionState *s = *iter; +			if((s->mSIPURI == uri) || (s->mAlternateSIPURI == uri)) +			{ +				// TODO: I need to think about this logic... it's possible that this case should raise an internal error. +				result = s; +				break; +			} +		} +	} +	else // (!handle.empty()) +	{ +		// Check for an existing session with this handle +		sessionMap::iterator iter = mSessionsByHandle.find(&handle); +		 +		if(iter != mSessionsByHandle.end()) +		{ +			result = iter->second; +		} +	} + +	if(!result) +	{ +		// No existing session found. +		 +		LL_DEBUGS("Voice") << "adding new session: handle " << handle << " URI " << uri << LL_ENDL; +		result = new sessionState(); +		result->mSIPURI = uri; +		result->mHandle = handle; +		 +		mSessions.insert(result); + +		if(!result->mHandle.empty()) +		{ +			mSessionsByHandle.insert(sessionMap::value_type(&(result->mHandle), result)); +		}  	}  	else  	{ -		return FALSE; +		// Found an existing session +		 +		if(uri != result->mSIPURI) +		{ +			// TODO: Should this be an internal error? +			LL_DEBUGS("Voice") << "changing uri from " << result->mSIPURI << " to " << uri << LL_ENDL; +			setSessionURI(result, uri); +		} + +		if(handle != result->mHandle) +		{ +			if(handle.empty()) +			{ +				// There's at least one race condition where where addSession was clearing an existing session handle, which caused things to break. +				LL_DEBUGS("Voice") << "NOT clearing handle " << result->mHandle << LL_ENDL; +			} +			else +			{ +				// TODO: Should this be an internal error? +				LL_DEBUGS("Voice") << "changing handle from " << result->mHandle << " to " << handle << LL_ENDL; +				setSessionHandle(result, handle); +			} +		} +		 +		LL_DEBUGS("Voice") << "returning existing session: handle " << handle << " URI " << uri << LL_ENDL;  	} + +	verifySessionState(); +		 +	return result;  } -F32 LLVoiceClient::getUserVolume(const LLUUID& id) +void LLVoiceClient::setSessionHandle(sessionState *session, const std::string &handle) +{ +	// Have to remove the session from the handle-indexed map before changing the handle, or things will break badly. +	 +	if(!session->mHandle.empty()) +	{ +		// Remove session from the map if it should have been there. +		sessionMap::iterator iter = mSessionsByHandle.find(&(session->mHandle)); +		if(iter != mSessionsByHandle.end()) +		{ +			if(iter->second != session) +			{ +				LL_ERRS("Voice") << "Internal error: session mismatch!" << LL_ENDL; +			} + +			mSessionsByHandle.erase(iter); +		} +		else +		{ +			LL_ERRS("Voice") << "Internal error: session handle not found in map!" << LL_ENDL; +		} +	} +			 +	session->mHandle = handle; + +	if(!handle.empty()) +	{ +		mSessionsByHandle.insert(sessionMap::value_type(&(session->mHandle), session)); +	} + +	verifySessionState(); +} + +void LLVoiceClient::setSessionURI(sessionState *session, const std::string &uri) +{ +	// There used to be a map of session URIs to sessions, which made this complex.... +	session->mSIPURI = uri; + +	verifySessionState(); +} + +void LLVoiceClient::deleteSession(sessionState *session) +{ +	// Remove the session from the handle map +	if(!session->mHandle.empty()) +	{ +		sessionMap::iterator iter = mSessionsByHandle.find(&(session->mHandle)); +		if(iter != mSessionsByHandle.end()) +		{ +			if(iter->second != session) +			{ +				LL_ERRS("Voice") << "Internal error: session mismatch" << LL_ENDL; +			} +			mSessionsByHandle.erase(iter); +		} +	} + +	// Remove the session from the URI map +	mSessions.erase(session); +	 +	// At this point, the session should be unhooked from all lists and all state should be consistent. +	verifySessionState(); + +	// If this is the current audio session, clean up the pointer which will soon be dangling. +	if(mAudioSession == session) +	{ +		mAudioSession = NULL; +		mAudioSessionChanged = true; +	} + +	// ditto for the next audio session +	if(mNextAudioSession == session) +	{ +		mNextAudioSession = NULL; +	} + +	// delete the session +	delete session; +} + +void LLVoiceClient::deleteAllSessions() +{ +	LL_DEBUGS("Voice") << "called" << LL_ENDL; + +	while(!mSessions.empty()) +	{ +		deleteSession(*(sessionsBegin())); +	} +	 +	if(!mSessionsByHandle.empty()) +	{ +		LL_ERRS("Voice") << "Internal error: empty session map, non-empty handle map" << LL_ENDL; +	} +} + +void LLVoiceClient::verifySessionState(void) +{ +	// This is mostly intended for debugging problems with session state management. +	LL_DEBUGS("Voice") << "Total session count: " << mSessions.size() << " , session handle map size: " << mSessionsByHandle.size() << LL_ENDL; + +	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) +	{ +		sessionState *session = *iter; + +		LL_DEBUGS("Voice") << "session " << session << ": handle " << session->mHandle << ", URI " << session->mSIPURI << LL_ENDL; +		 +		if(!session->mHandle.empty()) +		{ +			// every session with a non-empty handle needs to be in the handle map +			sessionMap::iterator i2 = mSessionsByHandle.find(&(session->mHandle)); +			if(i2 == mSessionsByHandle.end()) +			{ +				LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " not found in session map)" << LL_ENDL; +			} +			else +			{ +				if(i2->second != session) +				{ +					LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " in session map points to another session)" << LL_ENDL; +				} +			} +		} +	} +		 +	// check that every entry in the handle map points to a valid session in the session set +	for(sessionMap::iterator iter = mSessionsByHandle.begin(); iter != mSessionsByHandle.end(); iter++) +	{ +		sessionState *session = iter->second; +		sessionIterator i2 = mSessions.find(session); +		if(i2 == mSessions.end()) +		{ +			LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " not found in session map)" << LL_ENDL; +		} +		else +		{ +			if(session->mHandle != (*i2)->mHandle) +			{ +				LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " points to session with different handle " << (*i2)->mHandle << ")" << LL_ENDL; +			} +		} +	} +} + +LLVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) : +	mURI(uri)  { -	if (mVoiceModule)  +	mOnlineSL = false; +	mOnlineSLim = false; +	mCanSeeMeOnline = true; +	mHasBlockListEntry = false; +	mHasAutoAcceptListEntry = false; +	mNameResolved = false; +	mInVivoxBuddies = false; +	mInSLFriends = false; +	mNeedsNameUpdate = false; +} + +void LLVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName) +{ +	buddyListEntry *buddy = addBuddy(uri, displayName); +	buddy->mInVivoxBuddies = true;	 +} + +LLVoiceClient::buddyListEntry *LLVoiceClient::addBuddy(const std::string &uri) +{ +	std::string empty; +	buddyListEntry *buddy = addBuddy(uri, empty); +	if(buddy->mDisplayName.empty()) +	{ +		buddy->mNameResolved = false; +	} +	return buddy; +} + +LLVoiceClient::buddyListEntry *LLVoiceClient::addBuddy(const std::string &uri, const std::string &displayName) +{ +	buddyListEntry *result = NULL; +	buddyListMap::iterator iter = mBuddyListMap.find(&uri); +	 +	if(iter != mBuddyListMap.end()) +	{ +		// Found a matching buddy already in the map. +		LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL; +		result = iter->second; +	} + +	if(!result) +	{ +		// participant isn't already in one list or the other. +		LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL; +		result = new buddyListEntry(uri); +		result->mDisplayName = displayName; + +		if(IDFromName(uri, result->mUUID))  +		{ +			// Extracted UUID from name successfully. +		} +		else +		{ +			LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL; +		} + +		mBuddyListMap.insert(buddyListMap::value_type(&(result->mURI), result)); +	} +	 +	return result; +} + +LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddy(const std::string &uri) +{ +	buddyListEntry *result = NULL; +	buddyListMap::iterator iter = mBuddyListMap.find(&uri); +	if(iter != mBuddyListMap.end()) +	{ +		result = iter->second; +	} +	 +	return result; +} + +LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddy(const LLUUID &id) +{ +	buddyListEntry *result = NULL; +	buddyListMap::iterator iter; + +	for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++) +	{ +		if(iter->second->mUUID == id) +		{ +			result = iter->second; +			break; +		} +	} +	 +	return result; +} + +LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddyByDisplayName(const std::string &name) +{ +	buddyListEntry *result = NULL; +	buddyListMap::iterator iter; + +	for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++) +	{ +		if(iter->second->mDisplayName == name) +		{ +			result = iter->second; +			break; +		} +	} +	 +	return result; +} + +void LLVoiceClient::deleteBuddy(const std::string &uri) +{ +	buddyListMap::iterator iter = mBuddyListMap.find(&uri); +	if(iter != mBuddyListMap.end())  	{ -		return mVoiceModule->getUserVolume(id); +		LL_DEBUGS("Voice") << "deleting buddy " << uri << LL_ENDL; +		buddyListEntry *buddy = iter->second; +		mBuddyListMap.erase(iter); +		delete buddy;  	}  	else  	{ -		return 0.0; +		LL_DEBUGS("Voice") << "attempt to delete nonexistent buddy " << uri << LL_ENDL;  	} +	  } -void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume) +void LLVoiceClient::deleteAllBuddies(void)  { -	if (mVoiceModule) mVoiceModule->setUserVolume(id, volume); +	while(!mBuddyListMap.empty()) +	{ +		deleteBuddy(*(mBuddyListMap.begin()->first)); +	} +	 +	// Don't want to correlate with friends list when we've emptied the buddy list. +	mBuddyListMapPopulated = false; +	 +	// Don't want to correlate with friends list when we've reset the block rules. +	mBlockRulesListReceived = false; +	mAutoAcceptRulesListReceived = false;  } -//-------------------------------------------------- -// status observers +void LLVoiceClient::deleteAllBlockRules(void) +{ +	// Clear the block list entry flags from all local buddy list entries +	buddyListMap::iterator buddy_it; +	for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) +	{ +		buddy_it->second->mHasBlockListEntry = false; +	} +} -void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer) +void LLVoiceClient::deleteAllAutoAcceptRules(void)  { -	if (mVoiceModule) mVoiceModule->addObserver(observer); +	// Clear the auto-accept list entry flags from all local buddy list entries +	buddyListMap::iterator buddy_it; +	for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) +	{ +		buddy_it->second->mHasAutoAcceptListEntry = false; +	}  } -void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer) +void LLVoiceClient::addBlockRule(const std::string &blockMask, const std::string &presenceOnly)  { -	if (mVoiceModule) mVoiceModule->removeObserver(observer); +	buddyListEntry *buddy = NULL; + +	// blockMask is the SIP URI of a friends list entry +	buddyListMap::iterator iter = mBuddyListMap.find(&blockMask); +	if(iter != mBuddyListMap.end()) +	{ +		LL_DEBUGS("Voice") << "block list entry for " << blockMask << LL_ENDL; +		buddy = iter->second; +	} + +	if(buddy == NULL) +	{ +		LL_DEBUGS("Voice") << "block list entry for unknown buddy " << blockMask << LL_ENDL; +		buddy = addBuddy(blockMask); +	} +	 +	if(buddy != NULL) +	{ +		buddy->mHasBlockListEntry = true; +	}  } -void LLVoiceClient::addObserver(LLFriendObserver* observer) +void LLVoiceClient::addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy)  { -	if (mVoiceModule) mVoiceModule->addObserver(observer); +	buddyListEntry *buddy = NULL; + +	// blockMask is the SIP URI of a friends list entry +	buddyListMap::iterator iter = mBuddyListMap.find(&autoAcceptMask); +	if(iter != mBuddyListMap.end()) +	{ +		LL_DEBUGS("Voice") << "auto-accept list entry for " << autoAcceptMask << LL_ENDL; +		buddy = iter->second; +	} + +	if(buddy == NULL) +	{ +		LL_DEBUGS("Voice") << "auto-accept list entry for unknown buddy " << autoAcceptMask << LL_ENDL; +		buddy = addBuddy(autoAcceptMask); +	} + +	if(buddy != NULL) +	{ +		buddy->mHasAutoAcceptListEntry = true; +	}  } -void LLVoiceClient::removeObserver(LLFriendObserver* observer) +void LLVoiceClient::accountListBlockRulesResponse(int statusCode, const std::string &statusString)  { -	if (mVoiceModule) mVoiceModule->removeObserver(observer); +	// Block list entries were updated via addBlockRule() during parsing.  Just flag that we're done. +	mBlockRulesListReceived = true; +} + +void LLVoiceClient::accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString) +{ +	// Block list entries were updated via addBlockRule() during parsing.  Just flag that we're done. +	mAutoAcceptRulesListReceived = true;  }  void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)  { -	if (mVoiceModule) mVoiceModule->addObserver(observer); +	mParticipantObservers.insert(observer);  }  void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)  { -	if (mVoiceModule) mVoiceModule->removeObserver(observer); +	mParticipantObservers.erase(observer);  } -std::string LLVoiceClient::sipURIFromID(const LLUUID &id) +void LLVoiceClient::notifyParticipantObservers()  { -	if (mVoiceModule)  +	for (observer_set_t::iterator it = mParticipantObservers.begin(); +		it != mParticipantObservers.end(); +		)  	{ -		return mVoiceModule->sipURIFromID(id); +		LLVoiceClientParticipantObserver* observer = *it; +		observer->onChange(); +		// In case onChange() deleted an entry. +		it = mParticipantObservers.upper_bound(observer);  	} -	else +} + +void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer) +{ +	mStatusObservers.insert(observer); +} + +void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer) +{ +	mStatusObservers.erase(observer); +} + +void LLVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status) +{ +	if(mAudioSession)  	{ -		return std::string(); +		if(status == LLVoiceClientStatusObserver::ERROR_UNKNOWN) +		{ +			switch(mAudioSession->mErrorStatusCode) +			{ +				case 20713:		status = LLVoiceClientStatusObserver::ERROR_CHANNEL_FULL; 		break; +				case 20714:		status = LLVoiceClientStatusObserver::ERROR_CHANNEL_LOCKED; 	break; +				case 20715: +					//invalid channel, we may be using a set of poorly cached +					//info +					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; +					break; +				case 1009: +					//invalid username and password +					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; +					break; +			} + +			// Reset the error code to make sure it won't be reused later by accident. +			mAudioSession->mErrorStatusCode = 0; +		} +		else if(status == LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL) +		{ +			switch(mAudioSession->mErrorStatusCode) +			{ +				case 404:	// NOT_FOUND +				case 480:	// TEMPORARILY_UNAVAILABLE +				case 408:	// REQUEST_TIMEOUT +					// call failed because other user was not available +					// treat this as an error case +					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; + +					// Reset the error code to make sure it won't be reused later by accident. +					mAudioSession->mErrorStatusCode = 0; +				break; +			} +		}  	} +		 +	LL_DEBUGS("Voice")  +		<< " " << LLVoiceClientStatusObserver::status2string(status)   +		<< ", session URI " << getAudioSessionURI()  +		<< (inSpatialChannel()?", proximal is true":", proximal is false") +	<< LL_ENDL; + +	for (status_observer_set_t::iterator it = mStatusObservers.begin(); +		it != mStatusObservers.end(); +		) +	{ +		LLVoiceClientStatusObserver* observer = *it; +		observer->onChange(status, getAudioSessionURI(), inSpatialChannel()); +		// In case onError() deleted an entry. +		it = mStatusObservers.upper_bound(observer); +	} +  } +void LLVoiceClient::addObserver(LLFriendObserver* observer) +{ +	mFriendObservers.insert(observer); +} -/////////////////// -// version checking +void LLVoiceClient::removeObserver(LLFriendObserver* observer) +{ +	mFriendObservers.erase(observer); +} -class LLViewerRequiredVoiceVersion : public LLHTTPNode +void LLVoiceClient::notifyFriendObservers()  { -	static BOOL sAlertedUser; -	virtual void post( -					  LLHTTPNode::ResponsePtr response, -					  const LLSD& context, -					  const LLSD& input) const +	for (friend_observer_set_t::iterator it = mFriendObservers.begin(); +		it != mFriendObservers.end(); +		)  	{ -		//You received this messsage (most likely on region cross or -		//teleport) -		if ( input.has("body") && input["body"].has("major_version") ) +		LLFriendObserver* observer = *it; +		it++; +		// The only friend-related thing we notify on is online/offline transitions. +		observer->changed(LLFriendObserver::ONLINE); +	} +} + +void LLVoiceClient::lookupName(const LLUUID &id) +{ +	BOOL is_group = FALSE; +	gCacheName->get(id, is_group, &LLVoiceClient::onAvatarNameLookup); +} + +//static +void LLVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) +{ +	if(gVoiceClient) +	{ +		std::string name = llformat("%s %s", first.c_str(), last.c_str()); +		gVoiceClient->avatarNameResolved(id, name); +	} +} + +void LLVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name) +{ +	// If the avatar whose name just resolved is on our friends list, resync the friends list. +	if(LLAvatarTracker::instance().getBuddyInfo(id) != NULL) +	{ +		mFriendsListDirty = true; +	} +	 +	// Iterate over all sessions. +	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) +	{ +		sessionState *session = *iter; + +		// Check for this user as a participant in this session +		participantState *participant = session->findParticipantByID(id); +		if(participant)  		{ -			int major_voice_version = -			input["body"]["major_version"].asInteger(); -			// 			int minor_voice_version = -			// 				input["body"]["minor_version"].asInteger(); -			LLVoiceVersionInfo versionInfo = LLVoiceClient::getInstance()->getVersion(); -			 -			if (major_voice_version > 1) +			// Found -- fill in the name +			participant->mAccountName = name; +			// and post a "participants updated" message to listeners later. +			session->mParticipantsChanged = true; +		} +		 +		// Check whether this is a p2p session whose caller name just resolved +		if(session->mCallerID == id) +		{ +			// this session's "caller ID" just resolved.  Fill in the name. +			session->mName = name; +			if(session->mTextInvitePending)  			{ -				if (!sAlertedUser) -				{ -					//sAlertedUser = TRUE; -					LLNotificationsUtil::add("VoiceVersionMismatch"); -					gSavedSettings.setBOOL("EnableVoiceChat", FALSE); // toggles listener -				} +				session->mTextInvitePending = false; + +				// We don't need to call gIMMgr->addP2PSession() here.  The first incoming message will create the panel.				  			} +			if(session->mVoiceInvitePending) +			{ +				session->mVoiceInvitePending = false; + +				gIMMgr->inviteToSession( +					session->mIMSessionID, +					session->mName, +					session->mCallerID,  +					session->mName,  +					IM_SESSION_P2P_INVITE,  +					LLIMMgr::INVITATION_TYPE_VOICE, +					session->mHandle, +					session->mSIPURI); +			} +			  		}  	} -}; +}  class LLViewerParcelVoiceInfo : public LLHTTPNode  {  	virtual void post( -					  LLHTTPNode::ResponsePtr response, -					  const LLSD& context, -					  const LLSD& input) const +		LLHTTPNode::ResponsePtr response, +		const LLSD& context, +		const LLSD& input) const  	{  		//the parcel you are in has changed something about its  		//voice information -		 +  		//this is a misnomer, as it can also be when you are not in  		//a parcel at all.  Should really be something like  		//LLViewerVoiceInfoChanged.....  		if ( input.has("body") )  		{  			LLSD body = input["body"]; -			 +  			//body has "region_name" (str), "parcel_local_id"(int),  			//"voice_credentials" (map). -			 +  			//body["voice_credentials"] has "channel_uri" (str),  			//body["voice_credentials"] has "channel_credentials" (str) -			 +  			//if we really wanted to be extra careful,  			//we'd check the supplied  			//local parcel id to make sure it's for the same parcel @@ -764,7 +7279,7 @@ class LLViewerParcelVoiceInfo : public LLHTTPNode  				LLSD voice_credentials = body["voice_credentials"];  				std::string uri;  				std::string credentials; -				 +  				if ( voice_credentials.has("channel_uri") )  				{  					uri = voice_credentials["channel_uri"].asString(); @@ -772,96 +7287,51 @@ class LLViewerParcelVoiceInfo : public LLHTTPNode  				if ( voice_credentials.has("channel_credentials") )  				{  					credentials = -					voice_credentials["channel_credentials"].asString(); +						voice_credentials["channel_credentials"].asString();  				} -				 -				LLVoiceClient::getInstance()->setSpatialChannel(uri, credentials); + +				gVoiceClient->setSpatialChannel(uri, credentials);  			}  		}  	}  }; -const std::string LLSpeakerVolumeStorage::SETTINGS_FILE_NAME = "volume_settings.xml"; - -LLSpeakerVolumeStorage::LLSpeakerVolumeStorage() -{ -	load(); -} - -LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage() -{ -	save(); -} - -void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume) -{ -	mSpeakersData[speaker_id] = volume; -} - -S32 LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id) -{ -	// Return value of -1 indicates no level is stored for this speaker -	S32 ret_val = -1; -	speaker_data_map_t::const_iterator it = mSpeakersData.find(speaker_id); -	 -	if (it != mSpeakersData.end()) -	{ -		F32 f_val = it->second; -		// volume can amplify by as much as 4x! -		S32 ivol = (S32)(400.f * f_val * f_val); -		ret_val = llclamp(ivol, 0, 400); -	} -	return ret_val; -} - -void LLSpeakerVolumeStorage::load() -{ -	// load per-resident voice volume information -	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME); - -	LLSD settings_llsd; -	llifstream file; -	file.open(filename); -	if (file.is_open()) -	{ -		LLSDSerialize::fromXML(settings_llsd, file); -	} - -	for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); -		iter != settings_llsd.endMap(); ++iter) -	{ -		mSpeakersData.insert(std::make_pair(LLUUID(iter->first), (F32)iter->second.asReal())); -	} -} - -void LLSpeakerVolumeStorage::save() +class LLViewerRequiredVoiceVersion : public LLHTTPNode  { -	// If we quit from the login screen we will not have an SL account -	// name.  Don't try to save, otherwise we'll dump a file in -	// C:\Program Files\SecondLife\ or similar. JC -	std::string user_dir = gDirUtilp->getLindenUserDir(); -	if (!user_dir.empty()) +	static BOOL sAlertedUser; +	virtual void post( +		LLHTTPNode::ResponsePtr response, +		const LLSD& context, +		const LLSD& input) const  	{ -		std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME); -		LLSD settings_llsd; - -		for(speaker_data_map_t::const_iterator iter = mSpeakersData.begin(); iter != mSpeakersData.end(); ++iter) +		//You received this messsage (most likely on region cross or +		//teleport) +		if ( input.has("body") && input["body"].has("major_version") )  		{ -			settings_llsd[iter->first.asString()] = iter->second; -		} +			int major_voice_version = +				input["body"]["major_version"].asInteger(); +// 			int minor_voice_version = +// 				input["body"]["minor_version"].asInteger(); -		llofstream file; -		file.open(filename); -		LLSDSerialize::toPrettyXML(settings_llsd, file); +			if (gVoiceClient && +				(major_voice_version > VOICE_MAJOR_VERSION) ) +			{ +				if (!sAlertedUser) +				{ +					//sAlertedUser = TRUE; +					LLNotificationsUtil::add("VoiceVersionMismatch"); +					gSavedSettings.setBOOL("EnableVoiceChat", FALSE); // toggles listener +				} +			} +		}  	} -} - +};  BOOL LLViewerRequiredVoiceVersion::sAlertedUser = FALSE;  LLHTTPRegistration<LLViewerParcelVoiceInfo> -gHTTPRegistrationMessageParcelVoiceInfo( -										"/message/ParcelVoiceInfo"); +    gHTTPRegistrationMessageParcelVoiceInfo( +		"/message/ParcelVoiceInfo");  LLHTTPRegistration<LLViewerRequiredVoiceVersion> -gHTTPRegistrationMessageRequiredVoiceVersion( -											 "/message/RequiredVoiceVersion"); +    gHTTPRegistrationMessageRequiredVoiceVersion( +		"/message/RequiredVoiceVersion"); diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index f1a7d3dbec..a29c386182 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -17,7 +17,8 @@   * 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://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, @@ -32,6 +33,7 @@  #define LL_VOICE_CLIENT_H  class LLVOAvatar; +class LLVivoxProtocolParser;  #include "lliopipe.h"  #include "llpumpio.h" @@ -40,14 +42,9 @@ class LLVOAvatar;  #include "v3math.h"  #include "llframetimer.h"  #include "llviewerregion.h" -#include "llcallingcard.h"   // for LLFriendObserver -#include "llsecapi.h" - -// devices - -typedef std::vector<std::string> LLVoiceDeviceList;	 - +#include "m3math.h"			// LLMatrix3 +class LLFriendObserver;  class LLVoiceClientParticipantObserver  {  public: @@ -55,9 +52,6 @@ public:  	virtual void onChange() = 0;  }; - -/////////////////////////////////// -/// @class LLVoiceClientStatusObserver  class LLVoiceClientStatusObserver  {  public: @@ -71,7 +65,11 @@ public:  		STATUS_JOINED,  		STATUS_LEFT_CHANNEL,  		STATUS_VOICE_DISABLED, + +		// Adding STATUS_VOICE_ENABLED as pair status for STATUS_VOICE_DISABLED +		// See LLVoiceClient::setVoiceEnabled()  		STATUS_VOICE_ENABLED, +  		BEGIN_ERROR_STATUS,  		ERROR_CHANNEL_FULL,  		ERROR_CHANNEL_LOCKED, @@ -85,367 +83,699 @@ public:  	static std::string status2string(EStatusType inStatus);  }; -struct LLVoiceVersionInfo +class LLVoiceClient: public LLSingleton<LLVoiceClient>  { -	std::string serverType; -	std::string serverVersion; -}; +	LOG_CLASS(LLVoiceClient); +	public: +		LLVoiceClient();	 +		~LLVoiceClient(); +		 +	public: +		static void init(LLPumpIO *pump);	// Call this once at application startup (creates connector) +		static void terminate();	// Call this to clean up during shutdown +						 +	protected: +		bool writeString(const std::string &str); + +	public: +		 +		static F32 OVERDRIVEN_POWER_LEVEL; -////////////////////////////////// -/// @class LLVoiceModuleInterface -/// @brief Voice module interface -/// -/// Voice modules should provide an implementation for this interface. -///////////////////////////////// +		static const F32 VOLUME_MIN; +		static const F32 VOLUME_DEFAULT; +		static const F32 VOLUME_MAX; -class LLVoiceModuleInterface -{ -public: -	LLVoiceModuleInterface() {} -	virtual ~LLVoiceModuleInterface() {} -	 -	virtual void init(LLPumpIO *pump)=0;	// Call this once at application startup (creates connector) -	virtual void terminate()=0;	// Call this to clean up during shutdown -	 -	virtual void updateSettings()=0; // call after loading settings and whenever they change +		void updateSettings(); // call after loading settings and whenever they change -	virtual bool isVoiceWorking()=0; // connected to a voice server and voice channel +		void getCaptureDevicesSendMessage(); +		void getRenderDevicesSendMessage(); +		 +		void clearCaptureDevices(); +		void addCaptureDevice(const std::string& name); +		void setCaptureDevice(const std::string& name); +		 +		void clearRenderDevices(); +		void addRenderDevice(const std::string& name); +		void setRenderDevice(const std::string& name); + +		void tuningStart(); +		void tuningStop(); +		bool inTuningMode(); +		bool inTuningStates(); +		 +		void tuningRenderStartSendMessage(const std::string& name, bool loop); +		void tuningRenderStopSendMessage(); -	virtual const LLVoiceVersionInfo& getVersion()=0; -	 -	///////////////////// -	/// @name Tuning -	//@{ -	virtual void tuningStart()=0; -	virtual void tuningStop()=0; -	virtual bool inTuningMode()=0; -	 -	virtual void tuningSetMicVolume(float volume)=0; -	virtual void tuningSetSpeakerVolume(float volume)=0; -	virtual float tuningGetEnergy(void)=0; -	//@} -	 -	///////////////////// -	/// @name Devices -	//@{ -	// This returns true when it's safe to bring up the "device settings" dialog in the prefs. -	// i.e. when the daemon is running and connected, and the device lists are populated. -	virtual bool deviceSettingsAvailable()=0; -	 -	// Requery the vivox daemon for the current list of input/output devices. -	// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed -	// (use this if you want to know when it's done). -	// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim. -	virtual void refreshDeviceLists(bool clearCurrentList = true)=0; -	 -	virtual void setCaptureDevice(const std::string& name)=0; -	virtual void setRenderDevice(const std::string& name)=0; -	 -	virtual LLVoiceDeviceList& getCaptureDevices()=0; -	virtual LLVoiceDeviceList& getRenderDevices()=0; -	 -	virtual void getParticipantList(std::set<LLUUID> &participants)=0; -	virtual bool isParticipant(const LLUUID& speaker_id)=0; -	//@} -	 -	//////////////////////////// -	/// @ name Channel stuff -	//@{ -	// returns true iff the user is currently in a proximal (local spatial) channel. -	// Note that gestures should only fire if this returns true. -	virtual bool inProximalChannel()=0; -	 -	virtual void setNonSpatialChannel(const std::string &uri, -									  const std::string &credentials)=0; -	 -	virtual void setSpatialChannel(const std::string &uri, -								   const std::string &credentials)=0; -	 -	virtual void leaveNonSpatialChannel()=0; -	 -	virtual void leaveChannel(void)=0;	 -	 -	// Returns the URI of the current channel, or an empty string if not currently in a channel. -	// NOTE that it will return an empty string if it's in the process of joining a channel. -	virtual std::string getCurrentChannel()=0; -	//@} -	 -	 -	////////////////////////// -	/// @name invitations -	//@{ -	// start a voice channel with the specified user -	virtual void callUser(const LLUUID &uuid)=0; -	virtual bool answerInvite(std::string &channelHandle)=0; -	virtual void declineInvite(std::string &channelHandle)=0; -	//@} -	 -	///////////////////////// -	/// @name Volume/gain -	//@{ -	virtual void setVoiceVolume(F32 volume)=0; -	virtual void setMicGain(F32 volume)=0; -	//@} -	 -	///////////////////////// -	/// @name enable disable voice and features -	//@{ -	virtual bool voiceEnabled()=0; -	virtual void setVoiceEnabled(bool enabled)=0; -	virtual void setLipSyncEnabled(BOOL enabled)=0; -	virtual BOOL lipSyncEnabled()=0;	 -	virtual void setMuteMic(bool muted)=0;		// Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state. -	//@} -	 -	//////////////////////// -	/// @name PTT -	//@{ -	virtual void setUserPTTState(bool ptt)=0; -	virtual bool getUserPTTState()=0; -	virtual void setUsePTT(bool usePTT)=0; -	virtual void setPTTIsToggle(bool PTTIsToggle)=0; -	virtual bool getPTTIsToggle()=0;	 -	virtual void toggleUserPTTState(void)=0; -	virtual void inputUserControlState(bool down)=0;  // interpret any sort of up-down mic-open control input according to ptt-toggle prefs -	 -	virtual void keyDown(KEY key, MASK mask)=0; -	virtual void keyUp(KEY key, MASK mask)=0; -	virtual void middleMouseState(bool down)=0; -	//@} -	 -	////////////////////////// -	/// @name nearby speaker accessors -	//@{ - - -	virtual BOOL getVoiceEnabled(const LLUUID& id)=0;		// true if we've received data for this avatar -	virtual std::string getDisplayName(const LLUUID& id)=0; -	virtual BOOL isOnlineSIP(const LLUUID &id)=0;	 -	virtual BOOL isParticipantAvatar(const LLUUID &id)=0; -	virtual BOOL getIsSpeaking(const LLUUID& id)=0; -	virtual BOOL getIsModeratorMuted(const LLUUID& id)=0; -	virtual F32 getCurrentPower(const LLUUID& id)=0;		// "power" is related to "amplitude" in a defined way.  I'm just not sure what the formula is... -	virtual BOOL getOnMuteList(const LLUUID& id)=0; -	virtual F32 getUserVolume(const LLUUID& id)=0; -	virtual void setUserVolume(const LLUUID& id, F32 volume)=0; // set's volume for specified agent, from 0-1 (where .5 is nominal)	 -	//@} -	 -	////////////////////////// -	/// @name text chat -	//@{ -	virtual BOOL isSessionTextIMPossible(const LLUUID& id)=0; -	virtual BOOL isSessionCallBackPossible(const LLUUID& id)=0; -	virtual BOOL sendTextMessage(const LLUUID& participant_id, const std::string& message)=0; -	virtual void endUserIMSession(const LLUUID &uuid)=0;	 -	//@} -	 -	// authorize the user -	virtual void userAuthorized(const std::string& user_id, -								const LLUUID &agentID)=0; -	 -	////////////////////////////// -	/// @name Status notification -	//@{ -	virtual void addObserver(LLVoiceClientStatusObserver* observer)=0; -	virtual void removeObserver(LLVoiceClientStatusObserver* observer)=0; -	virtual void addObserver(LLFriendObserver* observer)=0; -	virtual void removeObserver(LLFriendObserver* observer)=0;	 -	virtual void addObserver(LLVoiceClientParticipantObserver* observer)=0; -	virtual void removeObserver(LLVoiceClientParticipantObserver* observer)=0;	 -	//@} -	 -	virtual std::string sipURIFromID(const LLUUID &id)=0; -	//@} -	 -}; +		void tuningCaptureStartSendMessage(int duration); +		void tuningCaptureStopSendMessage(); +		 +		void tuningSetMicVolume(float volume); +		void tuningSetSpeakerVolume(float volume); +		float tuningGetEnergy(void); +				 +		// This returns true when it's safe to bring up the "device settings" dialog in the prefs. +		// i.e. when the daemon is running and connected, and the device lists are populated. +		bool deviceSettingsAvailable(); +		 +		// Requery the vivox daemon for the current list of input/output devices. +		// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed +		// (use this if you want to know when it's done). +		// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim. +		void refreshDeviceLists(bool clearCurrentList = true); +		 +		// Call this if the connection to the daemon terminates unexpectedly.  It will attempt to reset everything and relaunch. +		void daemonDied(); +		// Call this if we're just giving up on voice (can't provision an account, etc.).  It will clean up and go away. +		void giveUp(); +		 +		///////////////////////////// +		// Response/Event handlers +		void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID); +		void loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases); +		void sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle); +		void sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle); +		void sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString); +		void logoutResponse(int statusCode, std::string &statusString); +		void connectorShutdownResponse(int statusCode, std::string &statusString); + +		void accountLoginStateChangeEvent(std::string &accountHandle, int statusCode, std::string &statusString, int state); +		void mediaStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, int statusCode, std::string &statusString, int state, bool incoming); +		void textStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, bool enabled, int state, bool incoming); +		void sessionAddedEvent(std::string &uriString, std::string &alias, std::string &sessionHandle, std::string &sessionGroupHandle, bool isChannel, bool incoming, std::string &nameString, std::string &applicationString); +		void sessionGroupAddedEvent(std::string &sessionGroupHandle); +		void sessionRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle); +		void participantAddedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString, std::string &displayNameString, int participantType); +		void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString); +		void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy); +		void auxAudioPropertiesEvent(F32 energy); +		void buddyPresenceEvent(std::string &uriString, std::string &alias, std::string &statusString, std::string &applicationString); +		void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString); +		void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string ¬ificationType); +		void subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType); +		 +		void buddyListChanged(); +		void muteListChanged(); +		void updateFriends(U32 mask); +		 +		///////////////////////////// +		// Sending updates of current state +static	void updatePosition(void); +		void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot); +		void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot); +		bool channelFromRegion(LLViewerRegion *region, std::string &name); +		void leaveChannel(void);		// call this on logout or teleport begin -class LLVoiceClient: public LLSingleton<LLVoiceClient> -{ -	LOG_CLASS(LLVoiceClient); -public: -	LLVoiceClient();	 -	~LLVoiceClient(); +		 +		void setMuteMic(bool muted);		// Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state. +		bool getMuteMic() const; +		void setUserPTTState(bool ptt); +		bool getUserPTTState(); +		void toggleUserPTTState(void); +		void inputUserControlState(bool down); // interpret any sort of up-down mic-open control input according to ptt-toggle prefs +		void setVoiceEnabled(bool enabled); +		static bool voiceEnabled(); +		// Checks is voice working judging from mState +		// Returns true if vivox has successfully logged in and is not in error state +		bool voiceWorking(); +		void setUsePTT(bool usePTT); +		void setPTTIsToggle(bool PTTIsToggle); +		bool getPTTIsToggle(); +		void setPTTKey(std::string &key); +		void setEarLocation(S32 loc); +		void setVoiceVolume(F32 volume); +		void setMicGain(F32 volume); +		void setUserVolume(const LLUUID& id, F32 volume); // sets volume for specified agent, from 0-1 (where .5 is nominal) +		void setLipSyncEnabled(BOOL enabled); +		BOOL lipSyncEnabled(); + +		// PTT key triggering +		void keyDown(KEY key, MASK mask); +		void keyUp(KEY key, MASK mask); +		void middleMouseState(bool down); + +		// Return the version of the Vivox library +		std::string getAPIVersion() const { return mAPIVersion; } +		 +		///////////////////////////// +		// Accessors for data related to nearby speakers +		BOOL getVoiceEnabled(const LLUUID& id);		// true if we've received data for this avatar +		BOOL getIsSpeaking(const LLUUID& id); +		BOOL getIsModeratorMuted(const LLUUID& id); +		F32 getCurrentPower(const LLUUID& id);		// "power" is related to "amplitude" in a defined way.  I'm just not sure what the formula is... +		BOOL getOnMuteList(const LLUUID& id); +		F32 getUserVolume(const LLUUID& id); +		std::string getDisplayName(const LLUUID& id); +		 +		// MBW -- XXX -- Not sure how to get this data out of the TVC +		BOOL getUsingPTT(const LLUUID& id); +		std::string getGroupID(const LLUUID& id);		// group ID if the user is in group chat (empty string if not applicable) -	void init(LLPumpIO *pump);	// Call this once at application startup (creates connector) -	void terminate();	// Call this to clean up during shutdown -	 -	const LLVoiceVersionInfo getVersion(); -	 -static const F32 OVERDRIVEN_POWER_LEVEL; +		///////////////////////////// +		BOOL getAreaVoiceDisabled();		// returns true if the area the avatar is in is speech-disabled. +											// Use this to determine whether to show a "no speech" icon in the menu bar. +		 +		///////////////////////////// +		// Recording controls +		void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200); +		void recordingLoopSave(const std::string& filename); +		void recordingStop(); +		 +		// Playback controls +		void filePlaybackStart(const std::string& filename); +		void filePlaybackStop(); +		void filePlaybackSetPaused(bool paused); +		void filePlaybackSetMode(bool vox = false, float speed = 1.0f); +		 +		 +		// This is used by the string-keyed maps below, to avoid storing the string twice. +		// The 'const std::string *' in the key points to a string actually stored in the object referenced by the map. +		// The add and delete operations for each map allocate and delete in the right order to avoid dangling references. +		// The default compare operation would just compare pointers, which is incorrect, so they must use this comparitor instead. +		struct stringMapComparitor +		{ +			bool operator()(const std::string* a, const std::string * b) const +			{ +				return a->compare(*b) < 0; +			} +		}; + +		struct uuidMapComparitor +		{ +			bool operator()(const LLUUID* a, const LLUUID * b) const +			{ +				return *a < *b; +			} +		}; +		 +		struct participantState +		{ +		public: +			participantState(const std::string &uri); + +			bool updateMuteState();	// true if mute state has changed +			bool isAvatar(); + +			std::string mURI; +			LLUUID mAvatarID; +			std::string mAccountName; +			std::string mDisplayName; +			LLFrameTimer mSpeakingTimeout; +			F32	mLastSpokeTimestamp; +			F32 mPower; +			F32 mVolume; +			std::string mGroupID; +			bool mPTT; +			bool mIsSpeaking; +			bool mIsModeratorMuted; +			bool mOnMuteList;		// true if this avatar is on the user's mute list (and should be muted) +			bool mVolumeSet;		// true if incoming volume messages should not change the volume +			bool mVolumeDirty;		// true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed) +			bool mAvatarIDValid; +			bool mIsSelf; +		}; +		typedef std::map<const std::string *, participantState*, stringMapComparitor> participantMap; + +		typedef std::map<const LLUUID *, participantState*, uuidMapComparitor> participantUUIDMap; +	 +		enum streamState +		{ +			streamStateUnknown = 0, +			streamStateIdle = 1, +			streamStateConnected = 2, +			streamStateRinging = 3, +		}; +		 +		struct sessionState +		{ +		public: +			sessionState(); +			~sessionState(); + +			participantState *addParticipant(const std::string &uri); +			// Note: after removeParticipant returns, the participant* that was passed to it will have been deleted. +			// Take care not to use the pointer again after that. +			void removeParticipant(participantState *participant); +			void removeAllParticipants(); + +			participantState *findParticipant(const std::string &uri); +			participantState *findParticipantByID(const LLUUID& id); + +			bool isCallBackPossible(); +			bool isTextIMPossible(); + +			std::string mHandle; +			std::string mGroupHandle; +			std::string mSIPURI; +			std::string mAlias; +			std::string mName; +			std::string mAlternateSIPURI; +			std::string mHash;			// Channel password +			std::string mErrorStatusString; +			std::queue<std::string> mTextMsgQueue; +			 +			LLUUID		mIMSessionID; +			LLUUID		mCallerID; +			int			mErrorStatusCode; +			int			mMediaStreamState; +			int			mTextStreamState; +			bool		mCreateInProgress;	// True if a Session.Create has been sent for this session and no response has been received yet. +			bool		mMediaConnectInProgress;	// True if a Session.MediaConnect has been sent for this session and no response has been received yet. +			bool		mVoiceInvitePending;	// True if a voice invite is pending for this session (usually waiting on a name lookup) +			bool		mTextInvitePending;		// True if a text invite is pending for this session (usually waiting on a name lookup) +			bool		mSynthesizedCallerID;	// True if the caller ID is a hash of the SIP URI -- this means we shouldn't do a name lookup. +			bool		mIsChannel;	// True for both group and spatial channels (false for p2p, PSTN) +			bool		mIsSpatial;	// True for spatial channels +			bool		mIsP2P; +			bool		mIncoming; +			bool		mVoiceEnabled; +			bool		mReconnect;	// Whether we should try to reconnect to this session if it's dropped +			// Set to true when the mute state of someone in the participant list changes. +			// The code will have to walk the list to find the changed participant(s). +			bool		mVolumeDirty; +			bool		mMuteDirty; + +			bool		mParticipantsChanged; +			participantMap mParticipantsByURI; +			participantUUIDMap mParticipantsByUUID; +		}; + +		participantState *findParticipantByID(const LLUUID& id); +		participantMap *getParticipantList(void); +		void getParticipantsUUIDSet(std::set<LLUUID>& participant_uuids); +		 +		typedef std::map<const std::string*, sessionState*, stringMapComparitor> sessionMap; +		typedef std::set<sessionState*> sessionSet; +				 +		typedef sessionSet::iterator sessionIterator; +		sessionIterator sessionsBegin(void); +		sessionIterator sessionsEnd(void); + +		sessionState *findSession(const std::string &handle); +		sessionState *findSessionBeingCreatedByURI(const std::string &uri); +		sessionState *findSession(const LLUUID &participant_id); +		sessionState *findSessionByCreateID(const std::string &create_id); +		 +		sessionState *addSession(const std::string &uri, const std::string &handle = LLStringUtil::null); +		void setSessionHandle(sessionState *session, const std::string &handle = LLStringUtil::null); +		void setSessionURI(sessionState *session, const std::string &uri); +		void deleteSession(sessionState *session); +		void deleteAllSessions(void); -	void updateSettings(); // call after loading settings and whenever they change +		void verifySessionState(void); -	bool isVoiceWorking(); // connected to a voice server and voice channel +		void joinedAudioSession(sessionState *session); +		void leftAudioSession(sessionState *session); -	// tuning -	void tuningStart(); -	void tuningStop(); -	bool inTuningMode(); +		// This is called in several places where the session _may_ need to be deleted. +		// It contains logic for whether to delete the session or keep it around. +		void reapSession(sessionState *session); +		 +		// Returns true if the session seems to indicate we've moved to a region on a different voice server +		bool sessionNeedsRelog(sessionState *session); +		 +		struct buddyListEntry +		{ +			buddyListEntry(const std::string &uri); +			std::string mURI; +			std::string mDisplayName; +			LLUUID	mUUID; +			bool mOnlineSL; +			bool mOnlineSLim; +			bool mCanSeeMeOnline; +			bool mHasBlockListEntry; +			bool mHasAutoAcceptListEntry; +			bool mNameResolved; +			bool mInSLFriends; +			bool mInVivoxBuddies; +			bool mNeedsNameUpdate; +		}; + +		typedef std::map<const std::string*, buddyListEntry*, stringMapComparitor> buddyListMap; +		 +		// This should be called when parsing a buddy list entry sent by SLVoice.		 +		void processBuddyListEntry(const std::string &uri, const std::string &displayName); + +		buddyListEntry *addBuddy(const std::string &uri); +		buddyListEntry *addBuddy(const std::string &uri, const std::string &displayName); +		buddyListEntry *findBuddy(const std::string &uri); +		buddyListEntry *findBuddy(const LLUUID &id); +		buddyListEntry *findBuddyByDisplayName(const std::string &name); +		void deleteBuddy(const std::string &uri); +		void deleteAllBuddies(void); + +		void deleteAllBlockRules(void); +		void addBlockRule(const std::string &blockMask, const std::string &presenceOnly); +		void deleteAllAutoAcceptRules(void); +		void addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy); +		void accountListBlockRulesResponse(int statusCode, const std::string &statusString);						 +		void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString);						 +		 +		///////////////////////////// +		// session control messages +		void connectorCreate(); +		void connectorShutdown(); + +		void requestVoiceAccountProvision(S32 retries = 3); +		void userAuthorized( +			const std::string& firstName, +			const std::string& lastName, +			const LLUUID &agentID); +		void login( +			const std::string& account_name, +			const std::string& password, +			const std::string& voice_sip_uri_hostname, +			const std::string& voice_account_server_uri); +		void loginSendMessage(); +		void logout(); +		void logoutSendMessage(); + +		void accountListBlockRulesSendMessage(); +		void accountListAutoAcceptRulesSendMessage(); -	void tuningSetMicVolume(float volume); -	void tuningSetSpeakerVolume(float volume); -	float tuningGetEnergy(void); +		void sessionGroupCreateSendMessage(); +		void sessionCreateSendMessage(sessionState *session, bool startAudio = true, bool startText = false); +		void sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio = true, bool startText = false); +		void sessionMediaConnectSendMessage(sessionState *session);		// just joins the audio session +		void sessionTextConnectSendMessage(sessionState *session);		// just joins the text session +		void sessionTerminateSendMessage(sessionState *session); +		void sessionGroupTerminateSendMessage(sessionState *session); +		void sessionMediaDisconnectSendMessage(sessionState *session); +		void sessionTextDisconnectSendMessage(sessionState *session); + +		// Pokes the state machine to leave the audio session next time around. +		void sessionTerminate();	 +		 +		// Pokes the state machine to shut down the connector and restart it. +		void requestRelog(); +		 +		// Does the actual work to get out of the audio session +		void leaveAudioSession(); +		 +		void addObserver(LLVoiceClientParticipantObserver* observer); +		void removeObserver(LLVoiceClientParticipantObserver* observer); + +		void addObserver(LLVoiceClientStatusObserver* observer); +		void removeObserver(LLVoiceClientStatusObserver* observer); + +		void addObserver(LLFriendObserver* observer); +		void removeObserver(LLFriendObserver* observer); +		 +		void lookupName(const LLUUID &id); +		static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); +		void avatarNameResolved(const LLUUID &id, const std::string &name); +		 +		typedef std::vector<std::string> deviceList; + +		deviceList *getCaptureDevices(); +		deviceList *getRenderDevices(); +		 +		void setNonSpatialChannel( +			const std::string &uri, +			const std::string &credentials); +		void setSpatialChannel( +			const std::string &uri, +			const std::string &credentials); +		// start a voice session with the specified user +		void callUser(const LLUUID &uuid); +		 +		// Send a text message to the specified user, initiating the session if necessary. +		bool sendTextMessage(const LLUUID& participant_id, const std::string& message); +		 +		// close any existing text IM session with the specified user +		void endUserIMSession(const LLUUID &uuid); +		 +		bool answerInvite(std::string &sessionHandle); +		void declineInvite(std::string &sessionHandle); +		void leaveNonSpatialChannel(); + +		// Returns the URI of the current channel, or an empty string if not currently in a channel. +		// NOTE that it will return an empty string if it's in the process of joining a channel. +		std::string getCurrentChannel(); +		 +		// returns true iff the user is currently in a proximal (local spatial) channel. +		// Note that gestures should only fire if this returns true. +		bool inProximalChannel(); + +		std::string sipURIFromID(const LLUUID &id); -	// devices -	 -	// This returns true when it's safe to bring up the "device settings" dialog in the prefs. -	// i.e. when the daemon is running and connected, and the device lists are populated. -	bool deviceSettingsAvailable(); +		// Returns true if the indicated user is online via SIP presence according to SLVoice. +		// Note that we only get SIP presence data for other users that are in our vivox buddy list. +		bool isOnlineSIP(const LLUUID &id); + +		// Returns true if the indicated participant is really an SL avatar. +		// This should be used to control the state of the "profile" button. +		// Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls. +		bool isParticipantAvatar(const LLUUID &id); +		 +		// Returns true if calling back the session URI after the session has closed is possible. +		// Currently this will be false only for PSTN P2P calls.		 +		// NOTE: this will return true if the session can't be found.  +		bool isSessionCallBackPossible(const LLUUID &session_id); +		 +		// Returns true if the session can accepte text IM's. +		// Currently this will be false only for PSTN P2P calls. +		// NOTE: this will return true if the session can't be found.  +		bool isSessionTextIMPossible(const LLUUID &session_id); +		 +	private: + +		// internal state for a simple state machine.  This is used to deal with the asynchronous nature of some of the messages. +		// Note: if you change this list, please make corresponding changes to LLVoiceClient::state2string(). +		enum state +		{ +			stateDisableCleanup, +			stateDisabled,				// Voice is turned off. +			stateStart,					// Class is initialized, socket is created +			stateDaemonLaunched,		// Daemon has been launched +			stateConnecting,			// connect() call has been issued +			stateConnected,				// connection to the daemon has been made, send some initial setup commands. +			stateIdle,					// socket is connected, ready for messaging +			stateMicTuningStart, +			stateMicTuningRunning,		 +			stateMicTuningStop, +			stateConnectorStart,		// connector needs to be started +			stateConnectorStarting,		// waiting for connector handle +			stateConnectorStarted,		// connector handle received +			stateLoginRetry,			// need to retry login (failed due to changing password) +			stateLoginRetryWait,		// waiting for retry timer +			stateNeedsLogin,			// send login request +			stateLoggingIn,				// waiting for account handle +			stateLoggedIn,				// account handle received +			stateCreatingSessionGroup,	// Creating the main session group +			stateNoChannel,				//  +			stateJoiningSession,		// waiting for session handle +			stateSessionJoined,			// session handle received +			stateRunning,				// in session, steady state +			stateLeavingSession,		// waiting for terminate session response +			stateSessionTerminated,		// waiting for terminate session response + +			stateLoggingOut,			// waiting for logout response +			stateLoggedOut,				// logout response received +			stateConnectorStopping,		// waiting for connector stop +			stateConnectorStopped,		// connector stop received +			 +			// We go to this state if the login fails because the account needs to be provisioned. +			 +			// error states.  No way to recover from these yet. +			stateConnectorFailed, +			stateConnectorFailedWaiting, +			stateLoginFailed, +			stateLoginFailedWaiting, +			stateJoinSessionFailed, +			stateJoinSessionFailedWaiting, + +			stateJail					// Go here when all else has failed.  Nothing will be retried, we're done. +		}; -	// Requery the vivox daemon for the current list of input/output devices. -	// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed -	// (use this if you want to know when it's done). -	// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim. -	void refreshDeviceLists(bool clearCurrentList = true); +		state mState; +		bool mSessionTerminateRequested; +		bool mRelogRequested; +		// Number of times (in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine(). +		// The larger it is the greater is possibility there is a problem with connection to voice server. +		// Introduced while fixing EXT-4313. +		int mSpatialJoiningNum; +		 +		void setState(state inState); +		state getState(void)  { return mState; }; +		static std::string state2string(state inState); +		 +		void stateMachine(); +		static void idle(void *user_data); +		 +		LLHost mDaemonHost; +		LLSocket::ptr_t mSocket; +		bool mConnected; +		 +		void closeSocket(void); +		 +		LLPumpIO *mPump; +		friend class LLVivoxProtocolParser; +		 +		std::string mAccountName; +		std::string mAccountPassword; +		std::string mAccountDisplayName; +		std::string mAccountFirstName; +		std::string mAccountLastName; +				 +		bool mTuningMode; +		float mTuningEnergy; +		std::string mTuningAudioFile; +		int mTuningMicVolume; +		bool mTuningMicVolumeDirty; +		int mTuningSpeakerVolume; +		bool mTuningSpeakerVolumeDirty; +		state mTuningExitState;					// state to return to when we leave tuning mode. +		 +		std::string mSpatialSessionURI; +		std::string mSpatialSessionCredentials; -	void setCaptureDevice(const std::string& name); -	void setRenderDevice(const std::string& name); +		std::string mMainSessionGroupHandle; // handle of the "main" session group. +		 +		std::string mChannelName;			// Name of the channel to be looked up  +		bool mAreaVoiceDisabled; +		sessionState *mAudioSession;		// Session state for the current audio session +		bool mAudioSessionChanged;			// set to true when the above pointer gets changed, so observers can be notified. -	const LLVoiceDeviceList& getCaptureDevices(); -	const LLVoiceDeviceList& getRenderDevices(); +		sessionState *mNextAudioSession;	// Session state for the audio session we're trying to join -	//////////////////////////// -	// Channel stuff -	// -	 -	// returns true iff the user is currently in a proximal (local spatial) channel. -	// Note that gestures should only fire if this returns true. -	bool inProximalChannel(); -	void setNonSpatialChannel( -							  const std::string &uri, -							  const std::string &credentials); -	void setSpatialChannel( -						   const std::string &uri, -						   const std::string &credentials); -	void leaveNonSpatialChannel(); -	 -	// Returns the URI of the current channel, or an empty string if not currently in a channel. -	// NOTE that it will return an empty string if it's in the process of joining a channel. -	std::string getCurrentChannel(); -	// start a voice channel with the specified user -	void callUser(const LLUUID &uuid);	 -	bool answerInvite(std::string &channelHandle); -	void declineInvite(std::string &channelHandle);	 -	void leaveChannel(void);		// call this on logout or teleport begin -	 -	 -	///////////////////////////// -	// Sending updates of current state +//		std::string mSessionURI;			// URI of the session we're in. +//		std::string mSessionHandle;		// returned by ? +		 +		S32 mCurrentParcelLocalID;			// Used to detect parcel boundary crossings +		std::string mCurrentRegionName;		// Used to detect parcel boundary crossings +		 +		std::string mConnectorHandle;	// returned by "Create Connector" message +		std::string mAccountHandle;		// returned by login message		 +		int 		mNumberOfAliases; +		U32 mCommandCookie; +		std::string mVoiceAccountServerURI; +		std::string mVoiceSIPURIHostName; +		 +		int mLoginRetryCount; +		 +		sessionMap mSessionsByHandle;				// Active sessions, indexed by session handle.  Sessions which are being initiated may not be in this map. +		sessionSet mSessions;						// All sessions, not indexed.  This is the canonical session list. +		 +		bool mBuddyListMapPopulated; +		bool mBlockRulesListReceived; +		bool mAutoAcceptRulesListReceived; +		buddyListMap mBuddyListMap; +		 +		deviceList mCaptureDevices; +		deviceList mRenderDevices; -	void setVoiceVolume(F32 volume); -	void setMicGain(F32 volume); -	void setUserVolume(const LLUUID& id, F32 volume); // set's volume for specified agent, from 0-1 (where .5 is nominal)		 -	bool voiceEnabled(); -	void setLipSyncEnabled(BOOL enabled); -	void setMuteMic(bool muted);		// Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state. -	void setUserPTTState(bool ptt); -	bool getUserPTTState(); -	void toggleUserPTTState(void); -	void inputUserControlState(bool down);  // interpret any sort of up-down mic-open control input according to ptt-toggle prefs	 -	void setVoiceEnabled(bool enabled); - -	void setUsePTT(bool usePTT); -	void setPTTIsToggle(bool PTTIsToggle); -	bool getPTTIsToggle();	 -	 -	BOOL lipSyncEnabled(); -	 -	// PTT key triggering -	void keyDown(KEY key, MASK mask); -	void keyUp(KEY key, MASK mask); -	void middleMouseState(bool down); -	 -	 -	///////////////////////////// -	// Accessors for data related to nearby speakers -	BOOL getVoiceEnabled(const LLUUID& id);		// true if we've received data for this avatar -	std::string getDisplayName(const LLUUID& id);	 -	BOOL isOnlineSIP(const LLUUID &id); -	BOOL isParticipantAvatar(const LLUUID &id); -	BOOL getIsSpeaking(const LLUUID& id); -	BOOL getIsModeratorMuted(const LLUUID& id); -	F32 getCurrentPower(const LLUUID& id);		// "power" is related to "amplitude" in a defined way.  I'm just not sure what the formula is... -	BOOL getOnMuteList(const LLUUID& id); -	F32 getUserVolume(const LLUUID& id); - -	///////////////////////////// -	BOOL getAreaVoiceDisabled();		// returns true if the area the avatar is in is speech-disabled. -													  // Use this to determine whether to show a "no speech" icon in the menu bar. -	void getParticipantList(std::set<LLUUID> &participants); -	bool isParticipant(const LLUUID& speaker_id); -	 -	////////////////////////// -	/// @name text chat -	//@{ -	BOOL isSessionTextIMPossible(const LLUUID& id); -	BOOL isSessionCallBackPossible(const LLUUID& id); -	BOOL sendTextMessage(const LLUUID& participant_id, const std::string& message); -	void endUserIMSession(const LLUUID &uuid);	 -	//@} -	 +		std::string mCaptureDevice; +		std::string mRenderDevice; +		bool mCaptureDeviceDirty; +		bool mRenderDeviceDirty; +		 +		// This should be called when the code detects we have changed parcels. +		// It initiates the call to the server that gets the parcel channel. +		void parcelChanged(); +		 +	void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = ""); +		void joinSession(sessionState *session); +		 +static 	std::string nameFromAvatar(LLVOAvatar *avatar); +static	std::string nameFromID(const LLUUID &id); +static	bool IDFromName(const std::string name, LLUUID &uuid); +static	std::string displayNameFromAvatar(LLVOAvatar *avatar); +		std::string sipURIFromAvatar(LLVOAvatar *avatar); +		std::string sipURIFromName(std::string &name); +		 +		// Returns the name portion of the SIP URI if the string looks vaguely like a SIP URI, or an empty string if not. +static	std::string nameFromsipURI(const std::string &uri);		 -	void userAuthorized(const std::string& user_id, -			const LLUUID &agentID); -	 -	void addObserver(LLVoiceClientStatusObserver* observer); -	void removeObserver(LLVoiceClientStatusObserver* observer); -	void addObserver(LLFriendObserver* observer); -	void removeObserver(LLFriendObserver* observer); -	void addObserver(LLVoiceClientParticipantObserver* observer); -	void removeObserver(LLVoiceClientParticipantObserver* observer); -	 -	std::string sipURIFromID(const LLUUID &id);	 +		bool inSpatialChannel(void); +		std::string getAudioSessionURI(); +		std::string getAudioSessionHandle(); +				 +		void sendPositionalUpdate(void); -protected: -	LLVoiceModuleInterface* mVoiceModule; -	LLPumpIO *m_servicePump; -}; +		void buildSetCaptureDevice(std::ostringstream &stream); +		void buildSetRenderDevice(std::ostringstream &stream); +		void buildLocalAudioUpdates(std::ostringstream &stream); +		 +		void clearAllLists(); +		void checkFriend(const LLUUID& id); +		void sendFriendsListUpdates(); + +		// start a text IM session with the specified user +		// This will be asynchronous, the session may be established at a future time. +		sessionState* startUserIMSession(const LLUUID& uuid); +		void sendQueuedTextMessages(sessionState *session); +		 +		void enforceTether(void); +		 +		bool		mSpatialCoordsDirty; +		 +		LLVector3d	mCameraPosition; +		LLVector3d	mCameraRequestedPosition; +		LLVector3	mCameraVelocity; +		LLMatrix3	mCameraRot; + +		LLVector3d	mAvatarPosition; +		LLVector3	mAvatarVelocity; +		LLMatrix3	mAvatarRot; +		 +		bool		mPTTDirty; +		bool		mPTT; +		 +		bool		mUsePTT; +		bool		mPTTIsMiddleMouse; +		KEY			mPTTKey; +		bool		mPTTIsToggle; +		bool		mUserPTTState; +		bool		mMuteMic; +				 +		// Set to true when the friends list is known to have changed. +		bool		mFriendsListDirty; +		 +		enum +		{ +			earLocCamera = 0,		// ear at camera +			earLocAvatar,			// ear at avatar +			earLocMixed				// ear at avatar location/camera direction +		}; +		 +		S32			mEarLocation;   +		 +		bool		mSpeakerVolumeDirty; +		bool		mSpeakerMuteDirty; +		int			mSpeakerVolume; + +		int			mMicVolume; +		bool		mMicVolumeDirty; +		 +		bool		mVoiceEnabled; +		bool		mWriteInProgress; +		std::string mWriteString; +		 +		LLTimer		mUpdateTimer; +		 +		BOOL		mLipSyncEnabled; -/** - * Speaker volume storage helper class - **/ +		std::string	mAPIVersion; -class LLSpeakerVolumeStorage : public LLSingleton<LLSpeakerVolumeStorage> -{ -	LOG_CLASS(LLSpeakerVolumeStorage); -public: +		typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t; +		observer_set_t mParticipantObservers; -	/** -	 * Sets internal voluem level for specified user. -	 * -	 * @param[in] speaker_id - LLUUID of user to store volume level for -	 * @param[in] volume - external volume level to be stored for user. -	 */ -	void storeSpeakerVolume(const LLUUID& speaker_id, F32 volume); - -	/** -	 * Gets stored external volume level for specified speaker. -	 * -	 * If specified user is not found default level will be returned. It is equivalent of  -	 * external level 0.5 from the 0.0..1.0 range. -	 * Default external level is calculated as: internal = 400 * external^2 -	 * Maps 0.0 to 1.0 to internal values 0-400 with default 0.5 == 100 -	 * -	 * @param[in] speaker_id - LLUUID of user to get his volume level -	 */ -	S32 getSpeakerVolume(const LLUUID& speaker_id); - -private: -	friend class LLSingleton<LLSpeakerVolumeStorage>; -	LLSpeakerVolumeStorage(); -	~LLSpeakerVolumeStorage(); - -	const static std::string SETTINGS_FILE_NAME; - -	void load(); -	void save(); - -	typedef std::map<LLUUID, F32> speaker_data_map_t; -	speaker_data_map_t mSpeakersData; +		void notifyParticipantObservers(); + +		typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t; +		status_observer_set_t mStatusObservers; +		 +		void notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status); + +		typedef std::set<LLFriendObserver*> friend_observer_set_t; +		friend_observer_set_t mFriendObservers; +		void notifyFriendObservers();  }; +extern LLVoiceClient *gVoiceClient; +  #endif //LL_VOICE_CLIENT_H diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp deleted file mode 100644 index 2f3bd567da..0000000000 --- a/indra/newview/llvoicevivox.cpp +++ /dev/null @@ -1,6967 +0,0 @@ - /**  - * @file llvoicevivox.cpp - * @brief Implementation of LLVivoxVoiceClient class which is the interface to the voice client process. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - *  - * Copyright (c) 2001-2010, 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 "llvoicevivox.h" - -#include <boost/tokenizer.hpp> - -#include "llsdutil.h" - -#include "llvoavatarself.h" -#include "llbufferstream.h" -#include "llfile.h" -#ifdef LL_STANDALONE -# include "expat.h" -#else -# include "expat/expat.h" -#endif -#include "llcallbacklist.h" -#include "llviewerregion.h" -#include "llviewernetwork.h"		// for gGridChoice -#include "llbase64.h" -#include "llviewercontrol.h" -#include "llkeyboard.h" -#include "llappviewer.h"	// for gDisconnected, gDisableVoice -#include "llmutelist.h"  // to check for muted avatars -#include "llagent.h" -#include "llcachename.h" -#include "llimview.h" // for LLIMMgr -#include "llparcel.h" -#include "llviewerparcelmgr.h" -//#include "llfirstuse.h" -#include "llspeakers.h" -#include "llviewerwindow.h" -#include "llviewercamera.h" - -#include "llfloaterfriends.h"  //VIVOX, inorder to refresh communicate panel -#include "llviewernetwork.h" -#include "llnotificationsutil.h" - -// for base64 decoding -#include "apr_base64.h" - -// for SHA1 hash -#include "apr_sha1.h" - -// for MD5 hash -#include "llmd5.h" - -#define USE_SESSION_GROUPS 0 - -const F32 SPEAKING_TIMEOUT = 1.f; - -static const std::string VOICE_SERVER_TYPE = "Vivox"; - -// Don't retry connecting to the daemon more frequently than this: -const F32 CONNECT_THROTTLE_SECONDS = 1.0f; - -// Don't send positional updates more frequently than this: -const F32 UPDATE_THROTTLE_SECONDS = 0.1f; - -const F32 LOGIN_RETRY_SECONDS = 10.0f; -const int MAX_LOGIN_RETRIES = 12; - -// Defines the maximum number of times(in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine() -// which is treated as normal. If this number is exceeded we suspect there is a problem with connection -// to voice server (EXT-4313). When voice works correctly, there is from 1 to 15 times. 50 was chosen  -// to make sure we don't make mistake when slight connection problems happen- situation when connection to server is  -// blocked is VERY rare and it's better to sacrifice response time in this situation for the sake of stability. -const int MAX_NORMAL_JOINING_SPATIAL_NUM = 50; - - -static void setUUIDFromStringHash(LLUUID &uuid, const std::string &str) -{ -	LLMD5 md5_uuid; -	md5_uuid.update((const unsigned char*)str.data(), str.size()); -	md5_uuid.finalize(); -	md5_uuid.raw_digest(uuid.mData); -} - -static int scale_mic_volume(float volume) -{ -	// incoming volume has the range [0.0 ... 2.0], with 1.0 as the default.                                                 -	// Map it to Vivox levels as follows: 0.0 -> 30, 1.0 -> 50, 2.0 -> 70                                                    -	return 30 + (int)(volume * 20.0f); -} - -static int scale_speaker_volume(float volume) -{ -	// incoming volume has the range [0.0 ... 1.0], with 0.5 as the default.                                                 -	// Map it to Vivox levels as follows: 0.0 -> 30, 0.5 -> 50, 1.0 -> 70                                                    -	return 30 + (int)(volume * 40.0f); -	 -} - -class LLVivoxVoiceAccountProvisionResponder : -	public LLHTTPClient::Responder -{ -public: -	LLVivoxVoiceAccountProvisionResponder(int retries) -	{ -		mRetries = retries; -	} - -	virtual void error(U32 status, const std::string& reason) -	{ -		if ( mRetries > 0 ) -		{ -			LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, retrying.  status = " << status << ", reason = \"" << reason << "\"" << LL_ENDL; -			LLVivoxVoiceClient::getInstance()->requestVoiceAccountProvision( -				mRetries - 1); -		} -		else -		{ -			LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, too many retries (giving up).  status = " << status << ", reason = \"" << reason << "\"" << LL_ENDL; -			LLVivoxVoiceClient::getInstance()->giveUp(); -		} -	} - -	virtual void result(const LLSD& content) -	{ - -		std::string voice_sip_uri_hostname; -		std::string voice_account_server_uri; -		 -		LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; -		 -		if(content.has("voice_sip_uri_hostname")) -			voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); -		 -		// this key is actually misnamed -- it will be an entire URI, not just a hostname. -		if(content.has("voice_account_server_name")) -			voice_account_server_uri = content["voice_account_server_name"].asString(); -		 -		LLVivoxVoiceClient::getInstance()->login( -			content["username"].asString(), -			content["password"].asString(), -			voice_sip_uri_hostname, -			voice_account_server_uri); - -	} - -private: -	int mRetries; -}; - - - -/////////////////////////////////////////////////////////////////////////////////////////////// - -class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver -{ -	/* virtual */ void onChange()  { LLVivoxVoiceClient::getInstance()->muteListChanged();} -}; - -class LLVivoxVoiceClientFriendsObserver : public LLFriendObserver -{ -public: -	/* virtual */ void changed(U32 mask) { LLVivoxVoiceClient::getInstance()->updateFriends(mask);} -}; - -static LLVivoxVoiceClientMuteListObserver mutelist_listener; -static bool sMuteListListener_listening = false; - -static LLVivoxVoiceClientFriendsObserver *friendslist_listener = NULL; - -/////////////////////////////////////////////////////////////////////////////////////////////// - -class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder -{ -public: -	LLVivoxVoiceClientCapResponder(void){}; - -	virtual void error(U32 status, const std::string& reason);	// called with bad status codes -	virtual void result(const LLSD& content); - -private: -}; - -void LLVivoxVoiceClientCapResponder::error(U32 status, const std::string& reason) -{ -	LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder::error(" -		<< status << ": " << reason << ")" -		<< LL_ENDL; -} - -void LLVivoxVoiceClientCapResponder::result(const LLSD& content) -{ -	LLSD::map_const_iterator iter; -	 -	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; - -	if ( content.has("voice_credentials") ) -	{ -		LLSD voice_credentials = content["voice_credentials"]; -		std::string uri; -		std::string credentials; - -		if ( voice_credentials.has("channel_uri") ) -		{ -			uri = voice_credentials["channel_uri"].asString(); -		} -		if ( voice_credentials.has("channel_credentials") ) -		{ -			credentials = -				voice_credentials["channel_credentials"].asString(); -		} - -		LLVivoxVoiceClient::getInstance()->setSpatialChannel(uri, credentials); -	} -} - - - -#if LL_WINDOWS -static HANDLE sGatewayHandle = 0; - -static bool isGatewayRunning() -{ -	bool result = false; -	if(sGatewayHandle != 0)		 -	{ -		DWORD waitresult = WaitForSingleObject(sGatewayHandle, 0); -		if(waitresult != WAIT_OBJECT_0) -		{ -			result = true; -		}			 -	} -	return result; -} -static void killGateway() -{ -	if(sGatewayHandle != 0) -	{ -		TerminateProcess(sGatewayHandle,0); -	} -} - -#else // Mac and linux - -static pid_t sGatewayPID = 0; -static bool isGatewayRunning() -{ -	bool result = false; -	if(sGatewayPID != 0) -	{ -		// A kill with signal number 0 has no effect, just does error checking.  It should return an error if the process no longer exists. -		if(kill(sGatewayPID, 0) == 0) -		{ -			result = true; -		} -	} -	return result; -} - -static void killGateway() -{ -	if(sGatewayPID != 0) -	{ -		kill(sGatewayPID, SIGTERM); -	} -} - -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////// - -LLVivoxVoiceClient::LLVivoxVoiceClient() : -	mState(stateDisabled), -	mSessionTerminateRequested(false), -	mRelogRequested(false), -	mConnected(false), -	mPump(NULL), -	mSpatialJoiningNum(0), - -	mTuningMode(false), -	mTuningEnergy(0.0f), -	mTuningMicVolume(0), -	mTuningMicVolumeDirty(true), -	mTuningSpeakerVolume(0), -	mTuningSpeakerVolumeDirty(true), -	mTuningExitState(stateDisabled), - -	mAreaVoiceDisabled(false), -	mAudioSession(NULL), -	mAudioSessionChanged(false), -	mNextAudioSession(NULL), - -	mCurrentParcelLocalID(0), -	mNumberOfAliases(0), -	mCommandCookie(0), -	mLoginRetryCount(0), - -	mBuddyListMapPopulated(false), -	mBlockRulesListReceived(false), -	mAutoAcceptRulesListReceived(false), -	mCaptureDeviceDirty(false), -	mRenderDeviceDirty(false), -	mSpatialCoordsDirty(false), - -	mPTTDirty(true), -	mPTT(true), -	mUsePTT(true), -	mPTTIsMiddleMouse(false), -	mPTTKey(0), -	mPTTIsToggle(false), -	mUserPTTState(false), -	mMuteMic(false), -	mFriendsListDirty(true), - -	mEarLocation(0), -	mSpeakerVolumeDirty(true), -	mSpeakerMuteDirty(true), -	mMicVolume(0), -	mMicVolumeDirty(true), - -	mVoiceEnabled(false), -	mWriteInProgress(false), - -	mLipSyncEnabled(false) - - - -{	 -	mSpeakerVolume = scale_speaker_volume(0); - -	mVoiceVersion.serverVersion = ""; -	mVoiceVersion.serverType = VOICE_SERVER_TYPE; -	 -	//  gMuteListp isn't set up at this point, so we defer this until later. -//	gMuteListp->addObserver(&mutelist_listener); -	 -	 -#if LL_DARWIN || LL_LINUX || LL_SOLARIS -		// HACK: THIS DOES NOT BELONG HERE -		// When the vivox daemon dies, the next write attempt on our socket generates a SIGPIPE, which kills us. -		// This should cause us to ignore SIGPIPE and handle the error through proper channels. -		// This should really be set up elsewhere.  Where should it go? -		signal(SIGPIPE, SIG_IGN); -		 -		// Since we're now launching the gateway with fork/exec instead of system(), we need to deal with zombie processes. -		// Ignoring SIGCHLD should prevent zombies from being created.  Alternately, we could use wait(), but I'd rather not do that. -		signal(SIGCHLD, SIG_IGN); -#endif - -	// set up state machine -	setState(stateDisabled); -	 -	gIdleCallbacks.addFunction(idle, this); -} - -//--------------------------------------------------- - -LLVivoxVoiceClient::~LLVivoxVoiceClient() -{ -} - -//---------------------------------------------- - -void LLVivoxVoiceClient::init(LLPumpIO *pump) -{ -	// constructor will set up LLVoiceClient::getInstance() -	LLVivoxVoiceClient::getInstance()->mPump = pump; -} - -void LLVivoxVoiceClient::terminate() -{ - -//	leaveAudioSession(); -	logout(); -	// As of SDK version 4885, this should no longer be necessary.  It will linger after the socket close if it needs to. -	// ms_sleep(2000); -	connectorShutdown(); -	closeSocket();		// Need to do this now -- bad things happen if the destructor does it later. -	 -	// This will do unpleasant things on windows. -//	killGateway(); -	 - - -} - -const LLVoiceVersionInfo& LLVivoxVoiceClient::getVersion() -{ -	return mVoiceVersion; -} - -//--------------------------------------------------- - -void LLVivoxVoiceClient::updateSettings() -{ -	setVoiceEnabled(gSavedSettings.getBOOL("EnableVoiceChat")); -	setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled")); -	std::string keyString = gSavedSettings.getString("PushToTalkButton"); -	setPTTKey(keyString); -	setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle")); -	setEarLocation(gSavedSettings.getS32("VoiceEarLocation")); - -	std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice"); -	setCaptureDevice(inputDevice); -	std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice"); -	setRenderDevice(outputDevice); -	F32 mic_level = gSavedSettings.getF32("AudioLevelMic"); -	setMicGain(mic_level); -	setLipSyncEnabled(gSavedSettings.getBOOL("LipSyncEnabled")); -} - -///////////////////////////// -// utility functions - -bool LLVivoxVoiceClient::writeString(const std::string &str) -{ -	bool result = false; -	if(mConnected) -	{ -		apr_status_t err; -		apr_size_t size = (apr_size_t)str.size(); -		apr_size_t written = size; -	 -		//MARK: Turn this on to log outgoing XML -//		LL_DEBUGS("Voice") << "sending: " << str << LL_ENDL; - -		// check return code - sockets will fail (broken, etc.) -		err = apr_socket_send( -				mSocket->getSocket(), -				(const char*)str.data(), -				&written); -		 -		if(err == 0) -		{ -			// Success. -			result = true; -		} -		// TODO: handle partial writes (written is number of bytes written) -		// Need to set socket to non-blocking before this will work. -//		else if(APR_STATUS_IS_EAGAIN(err)) -//		{ -//			//  -//		} -		else -		{ -			// Assume any socket error means something bad.  For now, just close the socket. -			char buf[MAX_STRING]; -			LL_WARNS("Voice") << "apr error " << err << " ("<< apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << LL_ENDL; -			daemonDied(); -		} -	} -		 -	return result; -} - - -///////////////////////////// -// session control messages -void LLVivoxVoiceClient::connectorCreate() -{ -	std::ostringstream stream; -	std::string logpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); -	std::string loglevel = "0"; -	 -	// Transition to stateConnectorStarted when the connector handle comes back. -	setState(stateConnectorStarting); - -	std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel"); -		 -	if(savedLogLevel != "-1") -	{ -		LL_DEBUGS("Voice") << "creating connector with logging enabled" << LL_ENDL; -		loglevel = "10"; -	} -	 -	stream  -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.Create.1\">" -		<< "<ClientName>V2 SDK</ClientName>" -		<< "<AccountManagementServer>" << mVoiceAccountServerURI << "</AccountManagementServer>" -		<< "<Mode>Normal</Mode>" -		<< "<Logging>" -			<< "<Folder>" << logpath << "</Folder>" -			<< "<FileNamePrefix>Connector</FileNamePrefix>" -			<< "<FileNameSuffix>.log</FileNameSuffix>" -			<< "<LogLevel>" << loglevel << "</LogLevel>" -		<< "</Logging>" -		<< "<Application>SecondLifeViewer.1</Application>" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::connectorShutdown() -{ -	setState(stateConnectorStopping); -	 -	if(!mConnectorHandle.empty()) -	{ -		std::ostringstream stream; -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.InitiateShutdown.1\">" -			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" -		<< "</Request>" -		<< "\n\n\n"; -		 -		mConnectorHandle.clear(); -		 -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID) -{ - -	mAccountDisplayName = user_id; - -	LL_INFOS("Voice") << "name \"" << mAccountDisplayName << "\" , ID " << agentID << LL_ENDL; - -	mAccountName = nameFromID(agentID); -} - -void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries) -{ -	if ( gAgent.getRegion() && mVoiceEnabled ) -	{ -		std::string url =  -			gAgent.getRegion()->getCapability( -				"ProvisionVoiceAccountRequest"); - -		if ( url == "" ) return; - -		LLHTTPClient::post( -			url, -			LLSD(), -			new LLVivoxVoiceAccountProvisionResponder(retries)); -	} -} - -void LLVivoxVoiceClient::login( -	const std::string& account_name, -	const std::string& password, -	const std::string& voice_sip_uri_hostname, -	const std::string& voice_account_server_uri) -{ -	mVoiceSIPURIHostName = voice_sip_uri_hostname; -	mVoiceAccountServerURI = voice_account_server_uri; - -	if(!mAccountHandle.empty()) -	{ -		// Already logged in. -		LL_WARNS("Voice") << "Called while already logged in." << LL_ENDL; -		 -		// Don't process another login. -		return; -	} -	else if ( account_name != mAccountName ) -	{ -		//TODO: error? -		LL_WARNS("Voice") << "Wrong account name! " << account_name -				<< " instead of " << mAccountName << LL_ENDL; -	} -	else -	{ -		mAccountPassword = password; -	} - -	std::string debugSIPURIHostName = gSavedSettings.getString("VivoxDebugSIPURIHostName"); -	 -	if( !debugSIPURIHostName.empty() ) -	{ -		mVoiceSIPURIHostName = debugSIPURIHostName; -	} -	 -	if( mVoiceSIPURIHostName.empty() ) -	{ -		// we have an empty account server name -		// so we fall back to hardcoded defaults - -		if(LLGridManager::getInstance()->isInProductionGrid()) -		{ -			// Use the release account server -			mVoiceSIPURIHostName = "bhr.vivox.com"; -		} -		else -		{ -			// Use the development account server -			mVoiceSIPURIHostName = "bhd.vivox.com"; -		} -	} -	 -	std::string debugAccountServerURI = gSavedSettings.getString("VivoxDebugVoiceAccountServerURI"); - -	if( !debugAccountServerURI.empty() ) -	{ -		mVoiceAccountServerURI = debugAccountServerURI; -	} -	 -	if( mVoiceAccountServerURI.empty() ) -	{ -		// If the account server URI isn't specified, construct it from the SIP URI hostname -		mVoiceAccountServerURI = "https://www." + mVoiceSIPURIHostName + "/api2/";		 -	} -} - -void LLVivoxVoiceClient::idle(void* user_data) -{ -	LLVivoxVoiceClient* self = (LLVivoxVoiceClient*)user_data; -	self->stateMachine(); -} - -std::string LLVivoxVoiceClient::state2string(LLVivoxVoiceClient::state inState) -{ -	std::string result = "UNKNOWN"; -	 -		// Prevent copy-paste errors when updating this list... -#define CASE(x)  case x:  result = #x;  break - -	switch(inState) -	{ -		CASE(stateDisableCleanup); -		CASE(stateDisabled); -		CASE(stateStart); -		CASE(stateDaemonLaunched); -		CASE(stateConnecting); -		CASE(stateConnected); -		CASE(stateIdle); -		CASE(stateMicTuningStart); -		CASE(stateMicTuningRunning); -		CASE(stateMicTuningStop); -		CASE(stateConnectorStart); -		CASE(stateConnectorStarting); -		CASE(stateConnectorStarted); -		CASE(stateLoginRetry); -		CASE(stateLoginRetryWait); -		CASE(stateNeedsLogin); -		CASE(stateLoggingIn); -		CASE(stateLoggedIn); -		CASE(stateCreatingSessionGroup); -		CASE(stateNoChannel); -		CASE(stateJoiningSession); -		CASE(stateSessionJoined); -		CASE(stateRunning); -		CASE(stateLeavingSession); -		CASE(stateSessionTerminated); -		CASE(stateLoggingOut); -		CASE(stateLoggedOut); -		CASE(stateConnectorStopping); -		CASE(stateConnectorStopped); -		CASE(stateConnectorFailed); -		CASE(stateConnectorFailedWaiting); -		CASE(stateLoginFailed); -		CASE(stateLoginFailedWaiting); -		CASE(stateJoinSessionFailed); -		CASE(stateJoinSessionFailedWaiting); -		CASE(stateJail); -	} - -#undef CASE -	 -	return result; -} - - - -void LLVivoxVoiceClient::setState(state inState) -{ -	LL_DEBUGS("Voice") << "entering state " << state2string(inState) << LL_ENDL; -	 -	mState = inState; -} - -void LLVivoxVoiceClient::stateMachine() -{ -	if(gDisconnected) -	{ -		// The viewer has been disconnected from the sim.  Disable voice. -		setVoiceEnabled(false); -	} -	 -	if(mVoiceEnabled) -	{ -		updatePosition(); -	} -	else if(mTuningMode) -	{ -		// Tuning mode is special -- it needs to launch SLVoice even if voice is disabled. -	} -	else -	{ -		if((getState() != stateDisabled) && (getState() != stateDisableCleanup)) -		{ -			// User turned off voice support.  Send the cleanup messages, close the socket, and reset. -			if(!mConnected) -			{ -				// if voice was turned off after the daemon was launched but before we could connect to it, we may need to issue a kill. -				LL_INFOS("Voice") << "Disabling voice before connection to daemon, terminating." << LL_ENDL; -				killGateway(); -			} -			 -			logout(); -			connectorShutdown(); -			 -			setState(stateDisableCleanup); -		} -	} -	 -	// Check for parcel boundary crossing -	{ -		LLViewerRegion *region = gAgent.getRegion(); -		LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); -		 -		if(region && parcel) -		{ -			S32 parcelLocalID = parcel->getLocalID(); -			std::string regionName = region->getName(); -			std::string capURI = region->getCapability("ParcelVoiceInfoRequest"); -		 -//			LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL; - -			// The region name starts out empty and gets filled in later.   -			// Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes. -			// If either is empty, wait for the next time around. -			if(!regionName.empty()) -			{ -				if(!capURI.empty()) -				{ -					if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName)) -					{ -						// We have changed parcels.  Initiate a parcel channel lookup. -						mCurrentParcelLocalID = parcelLocalID; -						mCurrentRegionName = regionName; -						 -						parcelChanged(); -					} -				} -				else -				{ -					LL_WARNS_ONCE("Voice") << "region doesn't have ParcelVoiceInfoRequest capability.  This is normal for a short time after teleporting, but bad if it persists for very long." << LL_ENDL; -				} -			} -		} -	} - -	switch(getState()) -	{ -		//MARK: stateDisableCleanup -		case stateDisableCleanup: -			// Clean up and reset everything.  -			closeSocket(); -			deleteAllSessions(); -			deleteAllBuddies();		 -			 -			mConnectorHandle.clear(); -			mAccountHandle.clear(); -			mAccountPassword.clear(); -			mVoiceAccountServerURI.clear(); -			 -			setState(stateDisabled);	 -		break; -		 -		//MARK: stateDisabled -		case stateDisabled: -			if(mTuningMode || (mVoiceEnabled && !mAccountName.empty())) -			{ -				setState(stateStart); -			} -		break; -		 -		//MARK: stateStart -		case stateStart: -			if(gSavedSettings.getBOOL("CmdLineDisableVoice")) -			{ -				// Voice is locked out, we must not launch the vivox daemon. -				setState(stateJail); -			} -			else if(!isGatewayRunning()) -			{ -				if(true) -				{ -					// Launch the voice daemon -					 -					// *FIX:Mani - Using the executable dir instead  -					// of mAppRODataDir, the working directory from which the app -					// is launched. -					//std::string exe_path = gDirUtilp->getAppRODataDir(); -					std::string exe_path = gDirUtilp->getExecutableDir(); -					exe_path += gDirUtilp->getDirDelimiter(); -#if LL_WINDOWS -					exe_path += "SLVoice.exe"; -#elif LL_DARWIN -					exe_path += "../Resources/SLVoice"; -#else -					exe_path += "SLVoice"; -#endif -					// See if the vivox executable exists -					llstat s; -					if(!LLFile::stat(exe_path, &s)) -					{ -						// vivox executable exists.  Build the command line and launch the daemon. -						// SLIM SDK: these arguments are no longer necessary. -//						std::string args = " -p tcp -h -c"; -						std::string args; -						std::string cmd; -						std::string loglevel = gSavedSettings.getString("VivoxDebugLevel"); -						 -						if(loglevel.empty()) -						{ -							loglevel = "-1";	// turn logging off completely -						} -						 -						args += " -ll "; -						args += loglevel; -						 -						LL_DEBUGS("Voice") << "Args for SLVoice: " << args << LL_ENDL; - -#if LL_WINDOWS -						PROCESS_INFORMATION pinfo; -						STARTUPINFOA sinfo; -						 -						memset(&sinfo, 0, sizeof(sinfo)); -						 -						std::string exe_dir = gDirUtilp->getAppRODataDir(); -						cmd = "SLVoice.exe"; -						cmd += args; - -						// So retarded.  Windows requires that the second parameter to CreateProcessA be writable (non-const) string... -						char *args2 = new char[args.size() + 1]; -						strcpy(args2, args.c_str()); -						if(!CreateProcessA(exe_path.c_str(), args2, NULL, NULL, FALSE, 0, NULL, exe_dir.c_str(), &sinfo, &pinfo)) -						{ -//							DWORD dwErr = GetLastError(); -						} -						else -						{ -							// foo = pinfo.dwProcessId; // get your pid here if you want to use it later on -							// CloseHandle(pinfo.hProcess); // stops leaks - nothing else -							sGatewayHandle = pinfo.hProcess; -							CloseHandle(pinfo.hThread); // stops leaks - nothing else -						}		 -						 -						delete[] args2; -#else	// LL_WINDOWS -						// This should be the same for mac and linux -						{ -							std::vector<std::string> arglist; -							arglist.push_back(exe_path); -							 -							// Split the argument string into separate strings for each argument -							typedef boost::tokenizer<boost::char_separator<char> > tokenizer; -							boost::char_separator<char> sep(" "); -							tokenizer tokens(args, sep); -							tokenizer::iterator token_iter; - -							for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) -							{ -								arglist.push_back(*token_iter); -							} -							 -							// create an argv vector for the child process -							char **fakeargv = new char*[arglist.size() + 1]; -							int i; -							for(i=0; i < arglist.size(); i++) -								fakeargv[i] = const_cast<char*>(arglist[i].c_str()); - -							fakeargv[i] = NULL; -							 -							fflush(NULL); // flush all buffers before the child inherits them -							pid_t id = vfork(); -							if(id == 0) -							{ -								// child -								execv(exe_path.c_str(), fakeargv); -								 -								// If we reach this point, the exec failed. -								// Use _exit() instead of exit() per the vfork man page. -								_exit(0); -							} - -							// parent -							delete[] fakeargv; -							sGatewayPID = id; -						} -#endif	// LL_WINDOWS -						mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost").c_str(), gSavedSettings.getU32("VivoxVoicePort")); -					}	 -					else -					{ -						LL_INFOS("Voice") << exe_path << " not found." << LL_ENDL; -					}	 -				} -				else -				{		 -					// SLIM SDK: port changed from 44124 to 44125. -					// We can connect to a client gateway running on another host.  This is useful for testing. -					// To do this, launch the gateway on a nearby host like this: -					//  vivox-gw.exe -p tcp -i 0.0.0.0:44125 -					// and put that host's IP address here. -					mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost"), gSavedSettings.getU32("VivoxVoicePort")); -				} - -				mUpdateTimer.start(); -				mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS); - -				setState(stateDaemonLaunched); -				 -				// Dirty the states we'll need to sync with the daemon when it comes up. -				mPTTDirty = true; -				mMicVolumeDirty = true; -				mSpeakerVolumeDirty = true; -				mSpeakerMuteDirty = true; -				// These only need to be set if they're not default (i.e. empty string). -				mCaptureDeviceDirty = !mCaptureDevice.empty(); -				mRenderDeviceDirty = !mRenderDevice.empty(); -				 -				mMainSessionGroupHandle.clear(); -			} -		break; - -		//MARK: stateDaemonLaunched -		case stateDaemonLaunched: -			if(mUpdateTimer.hasExpired()) -			{ -				LL_DEBUGS("Voice") << "Connecting to vivox daemon:" << mDaemonHost << LL_ENDL; - -				mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS); - -				if(!mSocket) -				{ -					mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);	 -				} -				 -				mConnected = mSocket->blockingConnect(mDaemonHost); -				if(mConnected) -				{ -					setState(stateConnecting); -				} -				else -				{ -					// If the connect failed, the socket may have been put into a bad state.  Delete it. -					closeSocket(); -				} -			} -		break; - -		//MARK: stateConnecting -		case stateConnecting: -		// Can't do this until we have the pump available. -		if(mPump) -		{ -			// MBW -- Note to self: pumps and pipes examples in -			//  indra/test/io.cpp -			//  indra/test/llpipeutil.{cpp|h} - -			// Attach the pumps and pipes -				 -			LLPumpIO::chain_t readChain; - -			readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket))); -			readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser())); - -			mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS); - -			setState(stateConnected); -		} - -		break; -		 -		//MARK: stateConnected -		case stateConnected: -			// Initial devices query -			getCaptureDevicesSendMessage(); -			getRenderDevicesSendMessage(); - -			mLoginRetryCount = 0; - -			setState(stateIdle); -		break; - -		//MARK: stateIdle -		case stateIdle: -			// This is the idle state where we're connected to the daemon but haven't set up a connector yet. -			if(mTuningMode) -			{ -				mTuningExitState = stateIdle; -				setState(stateMicTuningStart); -			} -			else if(!mVoiceEnabled) -			{ -				// We never started up the connector.  This will shut down the daemon. -				setState(stateConnectorStopped); -			} -			else if(!mAccountName.empty()) -			{ -				LLViewerRegion *region = gAgent.getRegion(); -				 -				if(region) -				{ -					if ( region->getCapability("ProvisionVoiceAccountRequest") != "" ) -					{ -						if ( mAccountPassword.empty() ) -						{ -							requestVoiceAccountProvision(); -						} -						setState(stateConnectorStart); -					} -					else -					{ -						LL_WARNS_ONCE("Voice") << "region doesn't have ProvisionVoiceAccountRequest capability!" << LL_ENDL; -					} -				} -			} -		break; - -		//MARK: stateMicTuningStart -		case stateMicTuningStart: -			if(mUpdateTimer.hasExpired()) -			{ -				if(mCaptureDeviceDirty || mRenderDeviceDirty) -				{ -					// These can't be changed while in tuning mode.  Set them before starting. -					std::ostringstream stream; -					 -					buildSetCaptureDevice(stream); -					buildSetRenderDevice(stream); - -					if(!stream.str().empty()) -					{ -						writeString(stream.str()); -					}				 - -					// This will come around again in the same state and start the capture, after the timer expires. -					mUpdateTimer.start(); -					mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); -				} -				else -				{ -					// duration parameter is currently unused, per Mike S. -					tuningCaptureStartSendMessage(10000); - -					setState(stateMicTuningRunning); -				} -			} -			 -		break; -		 -		//MARK: stateMicTuningRunning -		case stateMicTuningRunning: -			if(!mTuningMode || mCaptureDeviceDirty || mRenderDeviceDirty) -			{ -				// All of these conditions make us leave tuning mode. -				setState(stateMicTuningStop); -			} -			else -			{ -				// process mic/speaker volume changes -				if(mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty) -				{ -					std::ostringstream stream; -					 -					if(mTuningMicVolumeDirty) -					{ -						LL_INFOS("Voice") << "setting tuning mic level to " << mTuningMicVolume << LL_ENDL; -						stream -						<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetMicLevel.1\">" -						<< "<Level>" << mTuningMicVolume << "</Level>" -						<< "</Request>\n\n\n"; -					} -					 -					if(mTuningSpeakerVolumeDirty) -					{ -						stream -						<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetSpeakerLevel.1\">" -						<< "<Level>" << mTuningSpeakerVolume << "</Level>" -						<< "</Request>\n\n\n"; -					} -					 -					mTuningMicVolumeDirty = false; -					mTuningSpeakerVolumeDirty = false; - -					if(!stream.str().empty()) -					{ -						writeString(stream.str()); -					} -				} -			} -		break; -		 -		//MARK: stateMicTuningStop -		case stateMicTuningStop: -		{ -			// transition out of mic tuning -			tuningCaptureStopSendMessage(); -			 -			setState(mTuningExitState); -			 -			// if we exited just to change devices, this will keep us from re-entering too fast. -			mUpdateTimer.start(); -			mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); -			 -		} -		break; -												 -		//MARK: stateConnectorStart -		case stateConnectorStart: -			if(!mVoiceEnabled) -			{ -				// We were never logged in.  This will shut down the connector. -				setState(stateLoggedOut); -			} -			else if(!mVoiceAccountServerURI.empty()) -			{ -				connectorCreate(); -			} -		break; -		 -		//MARK: stateConnectorStarting -		case stateConnectorStarting:	// waiting for connector handle -			// connectorCreateResponse() will transition from here to stateConnectorStarted. -		break; -		 -		//MARK: stateConnectorStarted -		case stateConnectorStarted:		// connector handle received -			if(!mVoiceEnabled) -			{ -				// We were never logged in.  This will shut down the connector. -				setState(stateLoggedOut); -			} -			else -			{ -				// The connector is started.  Send a login message. -				setState(stateNeedsLogin); -			} -		break; -				 -		//MARK: stateLoginRetry -		case stateLoginRetry: -			if(mLoginRetryCount == 0) -			{ -				// First retry -- display a message to the user -				notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGIN_RETRY); -			} -			 -			mLoginRetryCount++; -			 -			if(mLoginRetryCount > MAX_LOGIN_RETRIES) -			{ -				LL_WARNS("Voice") << "too many login retries, giving up." << LL_ENDL; -				setState(stateLoginFailed); -				LLSD args; -				std::stringstream errs; -				errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000"; -				args["HOSTID"] = errs.str(); -				if (LLGridManager::getInstance()->isSystemGrid()) -				{ -					LLNotificationsUtil::add("NoVoiceConnect", args);	 -				} -				else -				{ -					LLNotificationsUtil::add("NoVoiceConnect-GIAB", args);	 -				}				 -			} -			else -			{ -				LL_INFOS("Voice") << "will retry login in " << LOGIN_RETRY_SECONDS << " seconds." << LL_ENDL; -				mUpdateTimer.start(); -				mUpdateTimer.setTimerExpirySec(LOGIN_RETRY_SECONDS); -				setState(stateLoginRetryWait); -			} -		break; -		 -		//MARK: stateLoginRetryWait -		case stateLoginRetryWait: -			if(mUpdateTimer.hasExpired()) -			{ -				setState(stateNeedsLogin); -			} -		break; -		 -		//MARK: stateNeedsLogin -		case stateNeedsLogin: -			if(!mAccountPassword.empty()) -			{ -				setState(stateLoggingIn); -				loginSendMessage(); -			}		 -		break; -		 -		//MARK: stateLoggingIn -		case stateLoggingIn:			// waiting for account handle -			// loginResponse() will transition from here to stateLoggedIn. -		break; -		 -		//MARK: stateLoggedIn -		case stateLoggedIn:				// account handle received - -			notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN); - -			// request the current set of block rules (we'll need them when updating the friends list) -			accountListBlockRulesSendMessage(); -			 -			// request the current set of auto-accept rules -			accountListAutoAcceptRulesSendMessage(); -			 -			// Set up the mute list observer if it hasn't been set up already. -			if((!sMuteListListener_listening)) -			{ -				LLMuteList::getInstance()->addObserver(&mutelist_listener); -				sMuteListListener_listening = true; -			} - -			// Set up the friends list observer if it hasn't been set up already. -			if(friendslist_listener == NULL) -			{ -				friendslist_listener = new LLVivoxVoiceClientFriendsObserver; -				LLAvatarTracker::instance().addObserver(friendslist_listener); -			} -			 -			// Set the initial state of mic mute, local speaker volume, etc. -			{ -				std::ostringstream stream; -				 -				buildLocalAudioUpdates(stream); -				 -				if(!stream.str().empty()) -				{ -					writeString(stream.str()); -				} -			} -			 -#if USE_SESSION_GROUPS			 -			// create the main session group -			sessionGroupCreateSendMessage(); -			 -			setState(stateCreatingSessionGroup); -#else -			// Not using session groups -- skip the stateCreatingSessionGroup state. -			setState(stateNoChannel); - -			// Initial kick-off of channel lookup logic -			parcelChanged();		 -#endif -		break; -		 -		//MARK: stateCreatingSessionGroup -		case stateCreatingSessionGroup: -			if(mSessionTerminateRequested || !mVoiceEnabled) -			{ -				// *TODO: Question: is this the right way out of this state -				setState(stateSessionTerminated); -			} -			else if(!mMainSessionGroupHandle.empty()) -			{ -				setState(stateNoChannel); -				 -				// Start looped recording (needed for "panic button" anti-griefing tool) -				recordingLoopStart(); - -				// Initial kick-off of channel lookup logic -				parcelChanged();		 -			} -		break; -					 -		//MARK: stateNoChannel -		case stateNoChannel: -			 -			LL_DEBUGS("Voice") << "State No Channel" << LL_ENDL; -			mSpatialJoiningNum = 0; -			// Do this here as well as inside sendPositionalUpdate().   -			// Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync. -			sendFriendsListUpdates(); -			 -			if(mSessionTerminateRequested || !mVoiceEnabled) -			{ -				// TODO: Question: Is this the right way out of this state? -				setState(stateSessionTerminated); -			} -			else if(mTuningMode) -			{ -				mTuningExitState = stateNoChannel; -				setState(stateMicTuningStart); -			} -			else if(sessionNeedsRelog(mNextAudioSession)) -			{ -				requestRelog(); -				setState(stateSessionTerminated); -			} -			else if(mNextAudioSession) -			{				 -				sessionState *oldSession = mAudioSession; - -				mAudioSession = mNextAudioSession; -				if(!mAudioSession->mReconnect)	 -				{ -					mNextAudioSession = NULL; -				} -				 -				// The old session may now need to be deleted. -				reapSession(oldSession); -				 -				if(!mAudioSession->mHandle.empty()) -				{ -					// Connect to a session by session handle - -					sessionMediaConnectSendMessage(mAudioSession); -				} -				else -				{ -					// Connect to a session by URI -					sessionCreateSendMessage(mAudioSession, true, false); -				} - -				notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING); -				setState(stateJoiningSession); -			} -			else if(!mSpatialSessionURI.empty()) -			{ -				// If we're not headed elsewhere and have a spatial URI, return to spatial. -				switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials); -			} -		break; - -		//MARK: stateJoiningSession -		case stateJoiningSession:		// waiting for session handle -		   -		  // If this is true we have problem with connection to voice server (EXT-4313). -		  // See descriptions of mSpatialJoiningNum and MAX_NORMAL_JOINING_SPATIAL_NUM. -		  if(mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM)  -		    { -		      // Notify observers to let them know there is problem with voice -		      notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED); -		      llwarns << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << llendl; -		    } -		   -		  // Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for -		  // example for p2p many times while waiting for response, so it can't be used to detect errors -		  if(mAudioSession && mAudioSession->mIsSpatial) -		    { -		      mSpatialJoiningNum++; -		    } -       -			// joinedAudioSession() will transition from here to stateSessionJoined. -			if(!mVoiceEnabled) -			{ -				// User bailed out during connect -- jump straight to teardown. -				setState(stateSessionTerminated); -			} -			else if(mSessionTerminateRequested) -			{ -				if(mAudioSession && !mAudioSession->mHandle.empty()) -				{ -					// Only allow direct exits from this state in p2p calls (for cancelling an invite). -					// Terminating a half-connected session on other types of calls seems to break something in the vivox gateway. -					if(mAudioSession->mIsP2P) -					{ -						sessionMediaDisconnectSendMessage(mAudioSession); -						setState(stateSessionTerminated); -					} -				} -			} -		break; -		 -		//MARK: stateSessionJoined -		case stateSessionJoined:		// session handle received - -		  mSpatialJoiningNum = 0; -			// It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4 -			// before continuing from this state.  They can happen in either order, and if I don't wait for both, things can get stuck. -			// For now, the SessionGroup.AddSession response handler sets mSessionHandle and the SessionStateChangeEvent handler transitions to stateSessionJoined. -			// This is a cheap way to make sure both have happened before proceeding. -			if(mAudioSession && mAudioSession->mVoiceEnabled) -			{ -				// Dirty state that may need to be sync'ed with the daemon. -				mPTTDirty = true; -				mSpeakerVolumeDirty = true; -				mSpatialCoordsDirty = true; -				 -				setState(stateRunning); -				 -				// Start the throttle timer -				mUpdateTimer.start(); -				mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); - -				// Events that need to happen when a session is joined could go here. -				// Maybe send initial spatial data? -				notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED); - -			} -			else if(!mVoiceEnabled) -			{ -				// User bailed out during connect -- jump straight to teardown. -				setState(stateSessionTerminated); -			} -			else if(mSessionTerminateRequested) -			{ -				// Only allow direct exits from this state in p2p calls (for cancelling an invite). -				// Terminating a half-connected session on other types of calls seems to break something in the vivox gateway. -				if(mAudioSession && mAudioSession->mIsP2P) -				{ -					sessionMediaDisconnectSendMessage(mAudioSession); -					setState(stateSessionTerminated); -				} -			} -		break; -		 -		//MARK: stateRunning -		case stateRunning:				// steady state -			// Disabling voice or disconnect requested. -			if(!mVoiceEnabled || mSessionTerminateRequested) -			{ -				leaveAudioSession(); -			} -			else -			{ -				 -				// Figure out whether the PTT state needs to change -				{ -					bool newPTT; -					if(mUsePTT) -					{ -						// If configured to use PTT, track the user state. -						newPTT = mUserPTTState; -					} -					else -					{ -						// If not configured to use PTT, it should always be true (otherwise the user will be unable to speak). -						newPTT = true; -					} -					 -					if(mMuteMic) -					{ -						// This always overrides any other PTT setting. -						newPTT = false; -					} -					 -					// Dirty if state changed. -					if(newPTT != mPTT) -					{ -						mPTT = newPTT; -						mPTTDirty = true; -					} -				} -				 -				if(!inSpatialChannel()) -				{ -					// When in a non-spatial channel, never send positional updates. -					mSpatialCoordsDirty = false; -				} -				else -				{ -					// Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position) -					enforceTether(); -				} -				 -				// Send an update if the ptt state has changed (which shouldn't be able to happen that often -- the user can only click so fast) -				// or every 10hz, whichever is sooner. -				if((mAudioSession && mAudioSession->mVolumeDirty) || mPTTDirty || mSpeakerVolumeDirty || mUpdateTimer.hasExpired()) -				{ -					mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); -					sendPositionalUpdate(); -				} -			} -		break; -		 -		//MARK: stateLeavingSession -		case stateLeavingSession:		// waiting for terminate session response -			// The handler for the Session.Terminate response will transition from here to stateSessionTerminated. -		break; - -		//MARK: stateSessionTerminated -		case stateSessionTerminated: -			 -			// Must do this first, since it uses mAudioSession. -			notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL); -			 -			if(mAudioSession) -			{ -				sessionState *oldSession = mAudioSession; - -				mAudioSession = NULL; -				// We just notified status observers about this change.  Don't do it again. -				mAudioSessionChanged = false; - -				// The old session may now need to be deleted. -				reapSession(oldSession); -			} -			else -			{ -				LL_WARNS("Voice") << "stateSessionTerminated with NULL mAudioSession" << LL_ENDL; -			} -	 -			// Always reset the terminate request flag when we get here. -			mSessionTerminateRequested = false; - -			if(mVoiceEnabled && !mRelogRequested) -			{				 -				// Just leaving a channel, go back to stateNoChannel (the "logged in but have no channel" state). -				setState(stateNoChannel); -			} -			else -			{ -				// Shutting down voice, continue with disconnecting. -				logout(); -				 -				// The state machine will take it from here -				mRelogRequested = false; -			} -			 -		break; -		 -		//MARK: stateLoggingOut -		case stateLoggingOut:			// waiting for logout response -			// The handler for the AccountLoginStateChangeEvent will transition from here to stateLoggedOut. -		break; -		 -		//MARK: stateLoggedOut -		case stateLoggedOut:			// logout response received -			 -			// Once we're logged out, all these things are invalid. -			mAccountHandle.clear(); -			deleteAllSessions(); -			deleteAllBuddies(); - -			if(mVoiceEnabled && !mRelogRequested) -			{ -				// User was logged out, but wants to be logged in.  Send a new login request. -				setState(stateNeedsLogin); -			} -			else -			{ -				// shut down the connector -				connectorShutdown(); -			} -		break; -		 -		//MARK: stateConnectorStopping -		case stateConnectorStopping:	// waiting for connector stop -			// The handler for the Connector.InitiateShutdown response will transition from here to stateConnectorStopped. -		break; - -		//MARK: stateConnectorStopped -		case stateConnectorStopped:		// connector stop received -			setState(stateDisableCleanup); -		break; - -		//MARK: stateConnectorFailed -		case stateConnectorFailed: -			setState(stateConnectorFailedWaiting); -		break; -		//MARK: stateConnectorFailedWaiting -		case stateConnectorFailedWaiting: -			if(!mVoiceEnabled) -			{ -				setState(stateDisableCleanup); -			} -		break; - -		//MARK: stateLoginFailed -		case stateLoginFailed: -			setState(stateLoginFailedWaiting); -		break; -		//MARK: stateLoginFailedWaiting -		case stateLoginFailedWaiting: -			if(!mVoiceEnabled) -			{ -				setState(stateDisableCleanup); -			} -		break; - -		//MARK: stateJoinSessionFailed -		case stateJoinSessionFailed: -			// Transition to error state.  Send out any notifications here. -			if(mAudioSession) -			{ -				LL_WARNS("Voice") << "stateJoinSessionFailed: (" << mAudioSession->mErrorStatusCode << "): " << mAudioSession->mErrorStatusString << LL_ENDL; -			} -			else -			{ -				LL_WARNS("Voice") << "stateJoinSessionFailed with no current session" << LL_ENDL; -			} -			 -			notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN); -			setState(stateJoinSessionFailedWaiting); -		break; -		 -		//MARK: stateJoinSessionFailedWaiting -		case stateJoinSessionFailedWaiting: -			// Joining a channel failed, either due to a failed channel name -> sip url lookup or an error from the join message. -			// Region crossings may leave this state and try the join again. -			if(mSessionTerminateRequested) -			{ -				setState(stateSessionTerminated); -			} -		break; -		 -		//MARK: stateJail -		case stateJail: -			// We have given up.  Do nothing. -		break; - -	} -	 -	if(mAudioSession && mAudioSession->mParticipantsChanged) -	{ -		mAudioSession->mParticipantsChanged = false; -		mAudioSessionChanged = true; -	} -	 -	if(mAudioSessionChanged) -	{ -		mAudioSessionChanged = false; -		notifyParticipantObservers(); -	} -} - -void LLVivoxVoiceClient::closeSocket(void) -{ -	mSocket.reset(); -	mConnected = false;	 -} - -void LLVivoxVoiceClient::loginSendMessage() -{ -	std::ostringstream stream; - -	bool autoPostCrashDumps = gSavedSettings.getBOOL("VivoxAutoPostCrashDumps"); - -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Login.1\">" -		<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" -		<< "<AccountName>" << mAccountName << "</AccountName>" -		<< "<AccountPassword>" << mAccountPassword << "</AccountPassword>" -		<< "<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>" -		<< "<EnableBuddiesAndPresence>true</EnableBuddiesAndPresence>" -		<< "<BuddyManagementMode>Application</BuddyManagementMode>" -		<< "<ParticipantPropertyFrequency>5</ParticipantPropertyFrequency>" -		<< (autoPostCrashDumps?"<AutopostCrashDumps>true</AutopostCrashDumps>":"") -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::logout() -{ -	// Ensure that we'll re-request provisioning before logging in again -	mAccountPassword.clear(); -	mVoiceAccountServerURI.clear(); -	 -	setState(stateLoggingOut); -	logoutSendMessage(); -} - -void LLVivoxVoiceClient::logoutSendMessage() -{ -	if(!mAccountHandle.empty()) -	{ -		std::ostringstream stream; -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Logout.1\">" -			<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -		<< "</Request>" -		<< "\n\n\n"; - -		mAccountHandle.clear(); - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::accountListBlockRulesSendMessage() -{ -	if(!mAccountHandle.empty()) -	{		 -		std::ostringstream stream; - -		LL_DEBUGS("Voice") << "requesting block rules" << LL_ENDL; - -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ListBlockRules.1\">" -			<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -		<< "</Request>" -		<< "\n\n\n"; - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::accountListAutoAcceptRulesSendMessage() -{ -	if(!mAccountHandle.empty()) -	{		 -		std::ostringstream stream; - -		LL_DEBUGS("Voice") << "requesting auto-accept rules" << LL_ENDL; - -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ListAutoAcceptRules.1\">" -			<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -		<< "</Request>" -		<< "\n\n\n"; - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::sessionGroupCreateSendMessage() -{ -	if(!mAccountHandle.empty()) -	{		 -		std::ostringstream stream; - -		LL_DEBUGS("Voice") << "creating session group" << LL_ENDL; - -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Create.1\">" -			<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -			<< "<Type>Normal</Type>" -		<< "</Request>" -		<< "\n\n\n"; - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::sessionCreateSendMessage(sessionState *session, bool startAudio, bool startText) -{ -	LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL; -	 -	session->mCreateInProgress = true; -	if(startAudio) -	{ -		session->mMediaConnectInProgress = true; -	} - -	std::ostringstream stream; -	stream -	<< "<Request requestId=\"" << session->mSIPURI << "\" action=\"Session.Create.1\">" -		<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -		<< "<URI>" << session->mSIPURI << "</URI>"; - -	static const std::string allowed_chars = -				"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" -				"0123456789" -				"-._~"; - -	if(!session->mHash.empty()) -	{ -		stream -			<< "<Password>" << LLURI::escape(session->mHash, allowed_chars) << "</Password>" -			<< "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>"; -	} -	 -	stream -		<< "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>" -		<< "<ConnectText>" << (startText?"true":"false") << "</ConnectText>" -		<< "<Name>" << mChannelName << "</Name>" -	<< "</Request>\n\n\n"; -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio, bool startText) -{ -	LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL; -	 -	session->mCreateInProgress = true; -	if(startAudio) -	{ -		session->mMediaConnectInProgress = true; -	} -	 -	std::string password; -	if(!session->mHash.empty()) -	{ -		static const std::string allowed_chars = -					"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" -					"0123456789" -					"-._~" -					; -		password = LLURI::escape(session->mHash, allowed_chars); -	} - -	std::ostringstream stream; -	stream -	<< "<Request requestId=\"" << session->mSIPURI << "\" action=\"SessionGroup.AddSession.1\">" -		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" -		<< "<URI>" << session->mSIPURI << "</URI>" -		<< "<Name>" << mChannelName << "</Name>" -		<< "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>" -		<< "<ConnectText>" << (startText?"true":"false") << "</ConnectText>" -		<< "<Password>" << password << "</Password>" -		<< "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>" -	<< "</Request>\n\n\n" -	; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::sessionMediaConnectSendMessage(sessionState *session) -{ -	LL_DEBUGS("Voice") << "connecting audio to session handle: " << session->mHandle << LL_ENDL; - -	session->mMediaConnectInProgress = true; -	 -	std::ostringstream stream; - -	stream -	<< "<Request requestId=\"" << session->mHandle << "\" action=\"Session.MediaConnect.1\">" -		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" -		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" -		<< "<Media>Audio</Media>" -	<< "</Request>\n\n\n"; - -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::sessionTextConnectSendMessage(sessionState *session) -{ -	LL_DEBUGS("Voice") << "connecting text to session handle: " << session->mHandle << LL_ENDL; -	 -	std::ostringstream stream; - -	stream -	<< "<Request requestId=\"" << session->mHandle << "\" action=\"Session.TextConnect.1\">" -		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" -		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" -	<< "</Request>\n\n\n"; - -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::sessionTerminate() -{ -	mSessionTerminateRequested = true; -} - -void LLVivoxVoiceClient::requestRelog() -{ -	mSessionTerminateRequested = true; -	mRelogRequested = true; -} - - -void LLVivoxVoiceClient::leaveAudioSession() -{ -	if(mAudioSession) -	{ -		LL_DEBUGS("Voice") << "leaving session: " << mAudioSession->mSIPURI << LL_ENDL; - -		switch(getState()) -		{ -			case stateNoChannel: -				// In this case, we want to pretend the join failed so our state machine doesn't get stuck. -				// Skip the join failed transition state so we don't send out error notifications. -				setState(stateJoinSessionFailedWaiting); -			break; -			case stateJoiningSession: -			case stateSessionJoined: -			case stateRunning: -				if(!mAudioSession->mHandle.empty()) -				{ - -#if RECORD_EVERYTHING -					// HACK: for testing only -					// Save looped recording -					std::string savepath("/tmp/vivoxrecording"); -					{ -						time_t now = time(NULL); -						const size_t BUF_SIZE = 64; -						char time_str[BUF_SIZE];	/* Flawfinder: ignore */ -						 -						strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); -						savepath += time_str; -					} -					recordingLoopSave(savepath); -#endif - -					sessionMediaDisconnectSendMessage(mAudioSession); -					setState(stateLeavingSession); -				} -				else -				{ -					LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;	 -					setState(stateSessionTerminated); -				} -			break; -			case stateJoinSessionFailed: -			case stateJoinSessionFailedWaiting: -				setState(stateSessionTerminated); -			break; -			 -			default: -				LL_WARNS("Voice") << "called from unknown state" << LL_ENDL; -			break; -		} -	} -	else -	{ -		LL_WARNS("Voice") << "called with no active session" << LL_ENDL; -		setState(stateSessionTerminated); -	} -} - -void LLVivoxVoiceClient::sessionTerminateSendMessage(sessionState *session) -{ -	std::ostringstream stream; -	 -	LL_DEBUGS("Voice") << "Sending Session.Terminate with handle " << session->mHandle << LL_ENDL;	 -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Terminate.1\">" -		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::sessionGroupTerminateSendMessage(sessionState *session) -{ -	std::ostringstream stream; -	 -	LL_DEBUGS("Voice") << "Sending SessionGroup.Terminate with handle " << session->mGroupHandle << LL_ENDL;	 -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Terminate.1\">" -		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::sessionMediaDisconnectSendMessage(sessionState *session) -{ -	std::ostringstream stream; -	 -	LL_DEBUGS("Voice") << "Sending Session.MediaDisconnect with handle " << session->mHandle << LL_ENDL;	 -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.MediaDisconnect.1\">" -		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" -		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" -		<< "<Media>Audio</Media>" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -	 -} - -void LLVivoxVoiceClient::sessionTextDisconnectSendMessage(sessionState *session) -{ -	std::ostringstream stream; -	 -	LL_DEBUGS("Voice") << "Sending Session.TextDisconnect with handle " << session->mHandle << LL_ENDL;	 -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.TextDisconnect.1\">" -		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>" -		<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::getCaptureDevicesSendMessage() -{ -	std::ostringstream stream; -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetCaptureDevices.1\">" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::getRenderDevicesSendMessage() -{ -	std::ostringstream stream; -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetRenderDevices.1\">" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::clearCaptureDevices() -{ -	LL_DEBUGS("Voice") << "called" << LL_ENDL; -	mCaptureDevices.clear(); -} - -void LLVivoxVoiceClient::addCaptureDevice(const std::string& name) -{ -	LL_DEBUGS("Voice") << name << LL_ENDL; - -	mCaptureDevices.push_back(name); -} - -LLVoiceDeviceList& LLVivoxVoiceClient::getCaptureDevices() -{ -	return mCaptureDevices; -} - -void LLVivoxVoiceClient::setCaptureDevice(const std::string& name) -{ -	if(name == "Default") -	{ -		if(!mCaptureDevice.empty()) -		{ -			mCaptureDevice.clear(); -			mCaptureDeviceDirty = true;	 -		} -	} -	else -	{ -		if(mCaptureDevice != name) -		{ -			mCaptureDevice = name; -			mCaptureDeviceDirty = true;	 -		} -	} -} - -void LLVivoxVoiceClient::clearRenderDevices() -{	 -	LL_DEBUGS("Voice") << "called" << LL_ENDL; -	mRenderDevices.clear(); -} - -void LLVivoxVoiceClient::addRenderDevice(const std::string& name) -{ -	LL_DEBUGS("Voice") << name << LL_ENDL; -	mRenderDevices.push_back(name); -} - -LLVoiceDeviceList& LLVivoxVoiceClient::getRenderDevices() -{ -	return mRenderDevices; -} - -void LLVivoxVoiceClient::setRenderDevice(const std::string& name) -{ -	if(name == "Default") -	{ -		if(!mRenderDevice.empty()) -		{ -			mRenderDevice.clear(); -			mRenderDeviceDirty = true;	 -		} -	} -	else -	{ -		if(mRenderDevice != name) -		{ -			mRenderDevice = name; -			mRenderDeviceDirty = true;	 -		} -	} -	 -} - -void LLVivoxVoiceClient::tuningStart() -{ -	mTuningMode = true; -	LL_DEBUGS("Voice") << "Starting tuning" << LL_ENDL; -	if(getState() >= stateNoChannel) -	{ -		LL_DEBUGS("Voice") << "no channel" << LL_ENDL; -		sessionTerminate(); -	} -} - -void LLVivoxVoiceClient::tuningStop() -{ -	mTuningMode = false; -} - -bool LLVivoxVoiceClient::inTuningMode() -{ -	bool result = false; -	switch(getState()) -	{ -	case stateMicTuningRunning: -		result = true; -		break; -	default: -		break; -	} -	return result; -} - -void LLVivoxVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool loop) -{		 -	mTuningAudioFile = name; -	std::ostringstream stream; -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStart.1\">" -    << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>" -    << "<Loop>" << (loop?"1":"0") << "</Loop>" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::tuningRenderStopSendMessage() -{ -	std::ostringstream stream; -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">" -    << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::tuningCaptureStartSendMessage(int duration) -{ -	LL_DEBUGS("Voice") << "sending CaptureAudioStart" << LL_ENDL; -	 -	std::ostringstream stream; -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStart.1\">" -    << "<Duration>" << duration << "</Duration>" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); -} - -void LLVivoxVoiceClient::tuningCaptureStopSendMessage() -{ -	LL_DEBUGS("Voice") << "sending CaptureAudioStop" << LL_ENDL; -	 -	std::ostringstream stream; -	stream -	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">" -	<< "</Request>\n\n\n"; -	 -	writeString(stream.str()); - -	mTuningEnergy = 0.0f; -} - -void LLVivoxVoiceClient::tuningSetMicVolume(float volume) -{ -	int scaled_volume = scale_mic_volume(volume); - -	if(scaled_volume != mTuningMicVolume) -	{ -		mTuningMicVolume = scaled_volume; -		mTuningMicVolumeDirty = true; -	} -} - -void LLVivoxVoiceClient::tuningSetSpeakerVolume(float volume) -{ -	int scaled_volume = scale_speaker_volume(volume);	 - -	if(scaled_volume != mTuningSpeakerVolume) -	{ -		mTuningSpeakerVolume = scaled_volume; -		mTuningSpeakerVolumeDirty = true; -	} -} -				 -float LLVivoxVoiceClient::tuningGetEnergy(void) -{ -	return mTuningEnergy; -} - -bool LLVivoxVoiceClient::deviceSettingsAvailable() -{ -	bool result = true; -	 -	if(!mConnected) -		result = false; -	 -	if(mRenderDevices.empty()) -		result = false; -	 -	return result; -} - -void LLVivoxVoiceClient::refreshDeviceLists(bool clearCurrentList) -{ -	if(clearCurrentList) -	{ -		clearCaptureDevices(); -		clearRenderDevices(); -	} -	getCaptureDevicesSendMessage(); -	getRenderDevicesSendMessage(); -} - -void LLVivoxVoiceClient::daemonDied() -{ -	// The daemon died, so the connection is gone.  Reset everything and start over. -	LL_WARNS("Voice") << "Connection to vivox daemon lost.  Resetting state."<< LL_ENDL; - -	// Try to relaunch the daemon -	setState(stateDisableCleanup); -} - -void LLVivoxVoiceClient::giveUp() -{ -	// All has failed.  Clean up and stop trying. -	closeSocket(); -	deleteAllSessions(); -	deleteAllBuddies(); -	 -	setState(stateJail); -} - -static void oldSDKTransform (LLVector3 &left, LLVector3 &up, LLVector3 &at, LLVector3d &pos, LLVector3 &vel) -{ -	F32 nat[3], nup[3], nl[3], nvel[3]; // the new at, up, left vectors and the  new position and velocity -	F64 npos[3]; -	 -	// The original XML command was sent like this: -	/* -			<< "<Position>" -				<< "<X>" << pos[VX] << "</X>" -				<< "<Y>" << pos[VZ] << "</Y>" -				<< "<Z>" << pos[VY] << "</Z>" -			<< "</Position>" -			<< "<Velocity>" -				<< "<X>" << mAvatarVelocity[VX] << "</X>" -				<< "<Y>" << mAvatarVelocity[VZ] << "</Y>" -				<< "<Z>" << mAvatarVelocity[VY] << "</Z>" -			<< "</Velocity>" -			<< "<AtOrientation>" -				<< "<X>" << l.mV[VX] << "</X>" -				<< "<Y>" << u.mV[VX] << "</Y>" -				<< "<Z>" << a.mV[VX] << "</Z>" -			<< "</AtOrientation>" -			<< "<UpOrientation>" -				<< "<X>" << l.mV[VZ] << "</X>" -				<< "<Y>" << u.mV[VY] << "</Y>" -				<< "<Z>" << a.mV[VZ] << "</Z>" -			<< "</UpOrientation>" -			<< "<LeftOrientation>" -				<< "<X>" << l.mV [VY] << "</X>" -				<< "<Y>" << u.mV [VZ] << "</Y>" -				<< "<Z>" << a.mV [VY] << "</Z>" -			<< "</LeftOrientation>"; -	*/ - -#if 1 -	// This was the original transform done when building the XML command -	nat[0] = left.mV[VX]; -	nat[1] = up.mV[VX]; -	nat[2] = at.mV[VX]; - -	nup[0] = left.mV[VZ]; -	nup[1] = up.mV[VY]; -	nup[2] = at.mV[VZ]; - -	nl[0] = left.mV[VY]; -	nl[1] = up.mV[VZ]; -	nl[2] = at.mV[VY]; - -	npos[0] = pos.mdV[VX]; -	npos[1] = pos.mdV[VZ]; -	npos[2] = pos.mdV[VY]; - -	nvel[0] = vel.mV[VX]; -	nvel[1] = vel.mV[VZ]; -	nvel[2] = vel.mV[VY]; - -	for(int i=0;i<3;++i) { -		at.mV[i] = nat[i]; -		up.mV[i] = nup[i]; -		left.mV[i] = nl[i]; -		pos.mdV[i] = npos[i]; -	} -	 -	// This was the original transform done in the SDK -	nat[0] = at.mV[2]; -	nat[1] = 0; // y component of at vector is always 0, this was up[2] -	nat[2] = -1 * left.mV[2]; - -	// We override whatever the application gives us -	nup[0] = 0; // x component of up vector is always 0 -	nup[1] = 1; // y component of up vector is always 1 -	nup[2] = 0; // z component of up vector is always 0 - -	nl[0] = at.mV[0]; -	nl[1] = 0;  // y component of left vector is always zero, this was up[0] -	nl[2] = -1 * left.mV[0]; - -	npos[2] = pos.mdV[2] * -1.0; -	npos[1] = pos.mdV[1]; -	npos[0] = pos.mdV[0]; - -	for(int i=0;i<3;++i) { -		at.mV[i] = nat[i]; -		up.mV[i] = nup[i]; -		left.mV[i] = nl[i]; -		pos.mdV[i] = npos[i]; -	} -#else -	// This is the compose of the two transforms (at least, that's what I'm trying for) -	nat[0] = at.mV[VX]; -	nat[1] = 0; // y component of at vector is always 0, this was up[2] -	nat[2] = -1 * up.mV[VZ]; - -	// We override whatever the application gives us -	nup[0] = 0; // x component of up vector is always 0 -	nup[1] = 1; // y component of up vector is always 1 -	nup[2] = 0; // z component of up vector is always 0 - -	nl[0] = left.mV[VX]; -	nl[1] = 0;  // y component of left vector is always zero, this was up[0] -	nl[2] = -1 * left.mV[VY]; - -	npos[0] = pos.mdV[VX]; -	npos[1] = pos.mdV[VZ]; -	npos[2] = pos.mdV[VY] * -1.0; - -	nvel[0] = vel.mV[VX]; -	nvel[1] = vel.mV[VZ]; -	nvel[2] = vel.mV[VY]; - -	for(int i=0;i<3;++i) { -		at.mV[i] = nat[i]; -		up.mV[i] = nup[i]; -		left.mV[i] = nl[i]; -		pos.mdV[i] = npos[i]; -	} -	 -#endif -} - -void LLVivoxVoiceClient::sendPositionalUpdate(void) -{	 -	std::ostringstream stream; -	 -	if(mSpatialCoordsDirty) -	{ -		LLVector3 l, u, a, vel; -		LLVector3d pos; - -		mSpatialCoordsDirty = false; -		 -		// Always send both speaker and listener positions together. -		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Set3DPosition.1\">"		 -			<< "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"; -		 -		stream << "<SpeakerPosition>"; - -//		LL_DEBUGS("Voice") << "Sending speaker position " << mAvatarPosition << LL_ENDL; -		l = mAvatarRot.getLeftRow(); -		u = mAvatarRot.getUpRow(); -		a = mAvatarRot.getFwdRow(); -		pos = mAvatarPosition; -		vel = mAvatarVelocity; - -		// SLIM SDK: the old SDK was doing a transform on the passed coordinates that the new one doesn't do anymore. -		// The old transform is replicated by this function. -		oldSDKTransform(l, u, a, pos, vel); -		 -		stream  -			<< "<Position>" -				<< "<X>" << pos.mdV[VX] << "</X>" -				<< "<Y>" << pos.mdV[VY] << "</Y>" -				<< "<Z>" << pos.mdV[VZ] << "</Z>" -			<< "</Position>" -			<< "<Velocity>" -				<< "<X>" << vel.mV[VX] << "</X>" -				<< "<Y>" << vel.mV[VY] << "</Y>" -				<< "<Z>" << vel.mV[VZ] << "</Z>" -			<< "</Velocity>" -			<< "<AtOrientation>" -				<< "<X>" << a.mV[VX] << "</X>" -				<< "<Y>" << a.mV[VY] << "</Y>" -				<< "<Z>" << a.mV[VZ] << "</Z>" -			<< "</AtOrientation>" -			<< "<UpOrientation>" -				<< "<X>" << u.mV[VX] << "</X>" -				<< "<Y>" << u.mV[VY] << "</Y>" -				<< "<Z>" << u.mV[VZ] << "</Z>" -			<< "</UpOrientation>" -			<< "<LeftOrientation>" -				<< "<X>" << l.mV [VX] << "</X>" -				<< "<Y>" << l.mV [VY] << "</Y>" -				<< "<Z>" << l.mV [VZ] << "</Z>" -			<< "</LeftOrientation>"; - -		stream << "</SpeakerPosition>"; - -		stream << "<ListenerPosition>"; - -		LLVector3d	earPosition; -		LLVector3	earVelocity; -		LLMatrix3	earRot; -		 -		switch(mEarLocation) -		{ -			case earLocCamera: -			default: -				earPosition = mCameraPosition; -				earVelocity = mCameraVelocity; -				earRot = mCameraRot; -			break; -			 -			case earLocAvatar: -				earPosition = mAvatarPosition; -				earVelocity = mAvatarVelocity; -				earRot = mAvatarRot; -			break; -			 -			case earLocMixed: -				earPosition = mAvatarPosition; -				earVelocity = mAvatarVelocity; -				earRot = mCameraRot; -			break; -		} - -		l = earRot.getLeftRow(); -		u = earRot.getUpRow(); -		a = earRot.getFwdRow(); -		pos = earPosition; -		vel = earVelocity; - -//		LL_DEBUGS("Voice") << "Sending listener position " << earPosition << LL_ENDL; -		 -		oldSDKTransform(l, u, a, pos, vel); -		 -		stream  -			<< "<Position>" -				<< "<X>" << pos.mdV[VX] << "</X>" -				<< "<Y>" << pos.mdV[VY] << "</Y>" -				<< "<Z>" << pos.mdV[VZ] << "</Z>" -			<< "</Position>" -			<< "<Velocity>" -				<< "<X>" << vel.mV[VX] << "</X>" -				<< "<Y>" << vel.mV[VY] << "</Y>" -				<< "<Z>" << vel.mV[VZ] << "</Z>" -			<< "</Velocity>" -			<< "<AtOrientation>" -				<< "<X>" << a.mV[VX] << "</X>" -				<< "<Y>" << a.mV[VY] << "</Y>" -				<< "<Z>" << a.mV[VZ] << "</Z>" -			<< "</AtOrientation>" -			<< "<UpOrientation>" -				<< "<X>" << u.mV[VX] << "</X>" -				<< "<Y>" << u.mV[VY] << "</Y>" -				<< "<Z>" << u.mV[VZ] << "</Z>" -			<< "</UpOrientation>" -			<< "<LeftOrientation>" -				<< "<X>" << l.mV [VX] << "</X>" -				<< "<Y>" << l.mV [VY] << "</Y>" -				<< "<Z>" << l.mV [VZ] << "</Z>" -			<< "</LeftOrientation>"; - - -		stream << "</ListenerPosition>"; - -		stream << "</Request>\n\n\n"; -	}	 -	 -	if(mAudioSession && mAudioSession->mVolumeDirty) -	{ -		participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin(); - -		mAudioSession->mVolumeDirty = false; -		 -		for(; iter != mAudioSession->mParticipantsByURI.end(); iter++) -		{ -			participantState *p = iter->second; -			 -			if(p->mVolumeDirty) -			{ -				// Can't set volume/mute for yourself -				if(!p->mIsSelf) -				{ -					int volume = 56; // nominal default value -					bool mute = p->mOnMuteList; -					 -					if(p->mUserVolume != -1) -					{ -						// scale from user volume in the range 0-400 (with 100 as "normal") to vivox volume in the range 0-100 (with 56 as "normal") -						if(p->mUserVolume < 100) -							volume = (p->mUserVolume * 56) / 100; -						else -							volume = (((p->mUserVolume - 100) * (100 - 56)) / 300) + 56; -					} -					else if(p->mVolume != -1) -					{ -						// Use the previously reported internal volume (comes in with a ParticipantUpdatedEvent) -						volume = p->mVolume; -					} -										 - -					if(mute) -					{ -						// SetParticipantMuteForMe doesn't work in p2p sessions. -						// If we want the user to be muted, set their volume to 0 as well. -						// This isn't perfect, but it will at least reduce their volume to a minimum. -						volume = 0; -					} -					 -					if(volume == 0) -						mute = true; - -					LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL; -					 -					// SLIM SDK: Send both volume and mute commands. -					 -					// Send a "volume for me" command for the user. -					stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantVolumeForMe.1\">" -						<< "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>" -						<< "<ParticipantURI>" << p->mURI << "</ParticipantURI>" -						<< "<Volume>" << volume << "</Volume>" -						<< "</Request>\n\n\n"; - -					if(!mAudioSession->mIsP2P) -					  { -					    // Send a "mute for me" command for the user -					    // Doesn't work in P2P sessions -					    stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantMuteForMe.1\">" -					      << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>" -					      << "<ParticipantURI>" << p->mURI << "</ParticipantURI>" -					      << "<Mute>" << (mute?"1":"0") << "</Mute>" -					      << "<Scope>Audio</Scope>" -					      << "</Request>\n\n\n"; -					    } -				} -				 -				p->mVolumeDirty = false; -			} -		} -	} -			 -	buildLocalAudioUpdates(stream); -	 -	if(!stream.str().empty()) -	{ -		writeString(stream.str()); -	} -	 -	// Friends list updates can be huge, especially on the first voice login of an account with lots of friends. -	// Batching them all together can choke SLVoice, so send them in separate writes. -	sendFriendsListUpdates(); -} - -void LLVivoxVoiceClient::buildSetCaptureDevice(std::ostringstream &stream) -{ -	if(mCaptureDeviceDirty) -	{ -		LL_DEBUGS("Voice") << "Setting input device = \"" << mCaptureDevice << "\"" << LL_ENDL; -	 -		stream  -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetCaptureDevice.1\">" -			<< "<CaptureDeviceSpecifier>" << mCaptureDevice << "</CaptureDeviceSpecifier>" -		<< "</Request>" -		<< "\n\n\n"; -		 -		mCaptureDeviceDirty = false; -	} -} - -void LLVivoxVoiceClient::buildSetRenderDevice(std::ostringstream &stream) -{ -	if(mRenderDeviceDirty) -	{ -		LL_DEBUGS("Voice") << "Setting output device = \"" << mRenderDevice << "\"" << LL_ENDL; - -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetRenderDevice.1\">" -			<< "<RenderDeviceSpecifier>" << mRenderDevice << "</RenderDeviceSpecifier>" -		<< "</Request>" -		<< "\n\n\n"; -		mRenderDeviceDirty = false; -	} -} - -void LLVivoxVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream) -{ -	buildSetCaptureDevice(stream); - -	buildSetRenderDevice(stream); - -	if(mPTTDirty) -	{ -		mPTTDirty = false; - -		// Send a local mute command. -		// NOTE that the state of "PTT" is the inverse of "local mute". -		//   (i.e. when PTT is true, we send a mute command with "false", and vice versa) -		 -		LL_DEBUGS("Voice") << "Sending MuteLocalMic command with parameter " << (mPTT?"false":"true") << LL_ENDL; - -		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">" -			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" -			<< "<Value>" << (mPTT?"false":"true") << "</Value>" -			<< "</Request>\n\n\n"; -		 -	} - -	if(mSpeakerMuteDirty) -	{ -	  const char *muteval = ((mSpeakerVolume <= scale_speaker_volume(0))?"true":"false"); - -		mSpeakerMuteDirty = false; - -		LL_INFOS("Voice") << "Setting speaker mute to " << muteval  << LL_ENDL; -		 -		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalSpeaker.1\">" -			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" -			<< "<Value>" << muteval << "</Value>" -			<< "</Request>\n\n\n";	 -		 -	} -	 -	if(mSpeakerVolumeDirty) -	{ -		mSpeakerVolumeDirty = false; - -		LL_INFOS("Voice") << "Setting speaker volume to " << mSpeakerVolume  << LL_ENDL; - -		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalSpeakerVolume.1\">" -			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" -			<< "<Value>" << mSpeakerVolume << "</Value>" -			<< "</Request>\n\n\n"; -			 -	} -	 -	if(mMicVolumeDirty) -	{ -		mMicVolumeDirty = false; - -		LL_INFOS("Voice") << "Setting mic volume to " << mMicVolume  << LL_ENDL; - -		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalMicVolume.1\">" -			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" -			<< "<Value>" << mMicVolume << "</Value>" -			<< "</Request>\n\n\n";				 -	} - -	 -} - -void LLVivoxVoiceClient::checkFriend(const LLUUID& id) -{ -	std::string name; -	buddyListEntry *buddy = findBuddy(id); - -	// Make sure we don't add a name before it's been looked up. -	if(gCacheName->getFullName(id, name)) -	{ - -		const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id); -		bool canSeeMeOnline = false; -		if(relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)) -			canSeeMeOnline = true; -		 -		// When we get here, mNeedsSend is true and mInSLFriends is false.  Change them as necessary. -		 -		if(buddy) -		{ -			// This buddy is already in both lists. - -			if(name != buddy->mDisplayName) -			{ -				// The buddy is in the list with the wrong name.  Update it with the correct name. -				LL_WARNS("Voice") << "Buddy " << id << " has wrong name (\"" << buddy->mDisplayName << "\" should be \"" << name << "\"), updating."<< LL_ENDL; -				buddy->mDisplayName = name; -				buddy->mNeedsNameUpdate = true;		// This will cause the buddy to be resent. -			} -		} -		else -		{ -			// This buddy was not in the vivox list, needs to be added. -			buddy = addBuddy(sipURIFromID(id), name); -			buddy->mUUID = id; -		} -		 -		// In all the above cases, the buddy is in the SL friends list (which is how we got here). -		buddy->mInSLFriends = true; -		buddy->mCanSeeMeOnline = canSeeMeOnline; -		buddy->mNameResolved = true; -		 -	} -	else -	{ -		// This name hasn't been looked up yet.  Don't do anything with this buddy list entry until it has. -		if(buddy) -		{ -			buddy->mNameResolved = false; -		} -		 -		// Initiate a lookup. -		// The "lookup completed" callback will ensure that the friends list is rechecked after it completes. -		lookupName(id); -	} -} - -void LLVivoxVoiceClient::clearAllLists() -{ -	// FOR TESTING ONLY -	 -	// This will send the necessary commands to delete ALL buddies, autoaccept rules, and block rules SLVoice tells us about. -	buddyListMap::iterator buddy_it; -	for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();) -	{ -		buddyListEntry *buddy = buddy_it->second; -		buddy_it++; -		 -		std::ostringstream stream; - -		if(buddy->mInVivoxBuddies) -		{ -			// delete this entry from the vivox buddy list -			buddy->mInVivoxBuddies = false; -			LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; -			stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddyDelete.1\">" -				<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -				<< "<BuddyURI>" << buddy->mURI << "</BuddyURI>" -				<< "</Request>\n\n\n";		 -		} - -		if(buddy->mHasBlockListEntry) -		{ -			// Delete the associated block list entry (so the block list doesn't fill up with junk) -			buddy->mHasBlockListEntry = false; -			stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">" -				<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -				<< "<BlockMask>" << buddy->mURI << "</BlockMask>" -				<< "</Request>\n\n\n";								 -		} -		if(buddy->mHasAutoAcceptListEntry) -		{ -			// Delete the associated auto-accept list entry (so the auto-accept list doesn't fill up with junk) -			buddy->mHasAutoAcceptListEntry = false; -			stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">" -				<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -				<< "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>" -				<< "</Request>\n\n\n"; -		} - -		writeString(stream.str()); - -	} -} - -void LLVivoxVoiceClient::sendFriendsListUpdates() -{ -	if(mBuddyListMapPopulated && mBlockRulesListReceived && mAutoAcceptRulesListReceived && mFriendsListDirty) -	{ -		mFriendsListDirty = false; -		 -		if(0) -		{ -			// FOR TESTING ONLY -- clear all buddy list, block list, and auto-accept list entries. -			clearAllLists(); -			return; -		} -		 -		LL_INFOS("Voice") << "Checking vivox buddy list against friends list..." << LL_ENDL; -		 -		buddyListMap::iterator buddy_it; -		for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) -		{ -			// reset the temp flags in the local buddy list -			buddy_it->second->mInSLFriends = false; -		} -		 -		// correlate with the friends list -		{ -			LLCollectAllBuddies collect; -			LLAvatarTracker::instance().applyFunctor(collect); -			LLCollectAllBuddies::buddy_map_t::const_iterator it = collect.mOnline.begin(); -			LLCollectAllBuddies::buddy_map_t::const_iterator end = collect.mOnline.end(); -			 -			for ( ; it != end; ++it) -			{ -				checkFriend(it->second); -			} -			it = collect.mOffline.begin(); -			end = collect.mOffline.end(); -			for ( ; it != end; ++it) -			{ -				checkFriend(it->second); -			} -		} -				 -		LL_INFOS("Voice") << "Sending friend list updates..." << LL_ENDL; - -		for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();) -		{ -			buddyListEntry *buddy = buddy_it->second; -			buddy_it++; -			 -			// Ignore entries that aren't resolved yet. -			if(buddy->mNameResolved) -			{ -				std::ostringstream stream; - -				if(buddy->mInSLFriends && (!buddy->mInVivoxBuddies || buddy->mNeedsNameUpdate)) -				{					 -					if(mNumberOfAliases > 0) -					{ -						// Add (or update) this entry in the vivox buddy list -						buddy->mInVivoxBuddies = true; -						buddy->mNeedsNameUpdate = false; -						LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; -						stream  -							<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddySet.1\">" -								<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -								<< "<BuddyURI>" << buddy->mURI << "</BuddyURI>" -								<< "<DisplayName>" << buddy->mDisplayName << "</DisplayName>" -								<< "<BuddyData></BuddyData>"	// Without this, SLVoice doesn't seem to parse the command. -								<< "<GroupID>0</GroupID>" -							<< "</Request>\n\n\n";	 -					} -				} -				else if(!buddy->mInSLFriends) -				{ -					// This entry no longer exists in your SL friends list.  Remove all traces of it from the Vivox buddy list. - 					if(buddy->mInVivoxBuddies) -					{ -						// delete this entry from the vivox buddy list -						buddy->mInVivoxBuddies = false; -						LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; -						stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddyDelete.1\">" -							<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -							<< "<BuddyURI>" << buddy->mURI << "</BuddyURI>" -							<< "</Request>\n\n\n";		 -					} - -					if(buddy->mHasBlockListEntry) -					{ -						// Delete the associated block list entry, if any -						buddy->mHasBlockListEntry = false; -						stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">" -							<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -							<< "<BlockMask>" << buddy->mURI << "</BlockMask>" -							<< "</Request>\n\n\n";								 -					} -					if(buddy->mHasAutoAcceptListEntry) -					{ -						// Delete the associated auto-accept list entry, if any -						buddy->mHasAutoAcceptListEntry = false; -						stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">" -							<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -							<< "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>" -							<< "</Request>\n\n\n"; -					} -				} -				 -				if(buddy->mInSLFriends) -				{ - -					if(buddy->mCanSeeMeOnline) -					{ -						// Buddy should not be blocked. - -						// If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent. -						 -						// If the buddy has a block list entry, delete it. -						if(buddy->mHasBlockListEntry) -						{ -							buddy->mHasBlockListEntry = false; -							stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">" -								<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -								<< "<BlockMask>" << buddy->mURI << "</BlockMask>" -								<< "</Request>\n\n\n";		 -							 -							 -							// If we just deleted a block list entry, add an auto-accept entry. -							if(!buddy->mHasAutoAcceptListEntry) -							{ -								buddy->mHasAutoAcceptListEntry = true;								 -								stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.CreateAutoAcceptRule.1\">" -									<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -									<< "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>" -									<< "<AutoAddAsBuddy>0</AutoAddAsBuddy>" -									<< "</Request>\n\n\n"; -							} -						} -					} -					else -					{ -						// Buddy should be blocked. -						 -						// If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent. - -						// If this buddy has an autoaccept entry, delete it -						if(buddy->mHasAutoAcceptListEntry) -						{ -							buddy->mHasAutoAcceptListEntry = false; -							stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">" -								<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -								<< "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>" -								<< "</Request>\n\n\n"; -						 -							// If we just deleted an auto-accept entry, add a block list entry. -							if(!buddy->mHasBlockListEntry) -							{ -								buddy->mHasBlockListEntry = true; -								stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.CreateBlockRule.1\">" -									<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -									<< "<BlockMask>" << buddy->mURI << "</BlockMask>" -									<< "<PresenceOnly>1</PresenceOnly>" -									<< "</Request>\n\n\n";								 -							} -						} -					} - -					if(!buddy->mInSLFriends && !buddy->mInVivoxBuddies) -					{ -						// Delete this entry from the local buddy list.  This should NOT invalidate the iterator, -						// since it has already been incremented to the next entry. -						deleteBuddy(buddy->mURI); -					} - -				} -				writeString(stream.str()); -			} -		} -	} -} - -///////////////////////////// -// Response/Event handlers - -void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID) -{	 -	if(statusCode != 0) -	{ -		LL_WARNS("Voice") << "Connector.Create response failure: " << statusString << LL_ENDL; -		setState(stateConnectorFailed); -		LLSD args; -		std::stringstream errs; -		errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000"; -		args["HOSTID"] = errs.str(); -		if (LLGridManager::getInstance()->isSystemGrid()) -		{ -			LLNotificationsUtil::add("NoVoiceConnect", args);	 -		} -		else -		{ -			LLNotificationsUtil::add("NoVoiceConnect-GIAB", args);	 -		} -	} -	else -	{ -		// Connector created, move forward. -		LL_INFOS("Voice") << "Connector.Create succeeded, Vivox SDK version is " << versionID << LL_ENDL; -		mVoiceVersion.serverVersion = versionID; -		mConnectorHandle = connectorHandle; -		if(getState() == stateConnectorStarting) -		{ -			setState(stateConnectorStarted); -		} -	} -} - -void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases) -{  -	LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL; -	 -	// Status code of 20200 means "bad password".  We may want to special-case that at some point. -	 -	if ( statusCode == 401 ) -	{ -		// Login failure which is probably caused by the delay after a user's password being updated. -		LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; -		setState(stateLoginRetry); -	} -	else if(statusCode != 0) -	{ -		LL_WARNS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; -		setState(stateLoginFailed); -	} -	else -	{ -		// Login succeeded, move forward. -		mAccountHandle = accountHandle; -		mNumberOfAliases = numberOfAliases; -		// This needs to wait until the AccountLoginStateChangeEvent is received. -//		if(getState() == stateLoggingIn) -//		{ -//			setState(stateLoggedIn); -//		} -	} -} - -void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle) -{	 -	sessionState *session = findSessionBeingCreatedByURI(requestId); -	 -	if(session) -	{ -		session->mCreateInProgress = false; -	} -	 -	if(statusCode != 0) -	{ -		LL_WARNS("Voice") << "Session.Create response failure (" << statusCode << "): " << statusString << LL_ENDL; -		if(session) -		{ -			session->mErrorStatusCode = statusCode;		 -			session->mErrorStatusString = statusString; -			if(session == mAudioSession) -			{ -				setState(stateJoinSessionFailed); -			} -			else -			{ -				reapSession(session); -			} -		} -	} -	else -	{ -		LL_INFOS("Voice") << "Session.Create response received (success), session handle is " << sessionHandle << LL_ENDL; -		if(session) -		{ -			setSessionHandle(session, sessionHandle); -		} -	} -} - -void LLVivoxVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle) -{	 -	sessionState *session = findSessionBeingCreatedByURI(requestId); -	 -	if(session) -	{ -		session->mCreateInProgress = false; -	} -	 -	if(statusCode != 0) -	{ -		LL_WARNS("Voice") << "SessionGroup.AddSession response failure (" << statusCode << "): " << statusString << LL_ENDL; -		if(session) -		{ -			session->mErrorStatusCode = statusCode;		 -			session->mErrorStatusString = statusString; -			if(session == mAudioSession) -			{ -				setState(stateJoinSessionFailed); -			} -			else -			{ -				reapSession(session); -			} -		} -	} -	else -	{ -		LL_DEBUGS("Voice") << "SessionGroup.AddSession response received (success), session handle is " << sessionHandle << LL_ENDL; -		if(session) -		{ -			setSessionHandle(session, sessionHandle); -		} -	} -} - -void LLVivoxVoiceClient::sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString) -{ -	sessionState *session = findSession(requestId); -	if(statusCode != 0) -	{ -		LL_WARNS("Voice") << "Session.Connect response failure (" << statusCode << "): " << statusString << LL_ENDL; -		if(session) -		{ -			session->mMediaConnectInProgress = false; -			session->mErrorStatusCode = statusCode;		 -			session->mErrorStatusString = statusString; -			if(session == mAudioSession) -				setState(stateJoinSessionFailed); -		} -	} -	else -	{ -		LL_DEBUGS("Voice") << "Session.Connect response received (success)" << LL_ENDL; -	} -} - -void LLVivoxVoiceClient::logoutResponse(int statusCode, std::string &statusString) -{	 -	if(statusCode != 0) -	{ -		LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL; -		// Should this ever fail?  do we care if it does? -	} -} - -void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString) -{ -	if(statusCode != 0) -	{ -		LL_WARNS("Voice") << "Connector.InitiateShutdown response failure: " << statusString << LL_ENDL; -		// Should this ever fail?  do we care if it does? -	} -	 -	mConnected = false; -	 -	if(getState() == stateConnectorStopping) -	{ -		setState(stateConnectorStopped); -	} -} - -void LLVivoxVoiceClient::sessionAddedEvent( -		std::string &uriString,  -		std::string &alias,  -		std::string &sessionHandle,  -		std::string &sessionGroupHandle,  -		bool isChannel,  -		bool incoming, -		std::string &nameString, -		std::string &applicationString) -{ -	sessionState *session = NULL; - -	LL_INFOS("Voice") << "session " << uriString << ", alias " << alias << ", name " << nameString << " handle " << sessionHandle << LL_ENDL; -	 -	session = addSession(uriString, sessionHandle); -	if(session) -	{ -		session->mGroupHandle = sessionGroupHandle; -		session->mIsChannel = isChannel; -		session->mIncoming = incoming; -		session->mAlias = alias; -			 -		// Generate a caller UUID -- don't need to do this for channels -		if(!session->mIsChannel) -		{ -			if(IDFromName(session->mSIPURI, session->mCallerID)) -			{ -				// Normal URI(base64-encoded UUID)  -			} -			else if(!session->mAlias.empty() && IDFromName(session->mAlias, session->mCallerID)) -			{ -				// Wrong URI, but an alias is available.  Stash the incoming URI as an alternate -				session->mAlternateSIPURI = session->mSIPURI; -				 -				// and generate a proper URI from the ID. -				setSessionURI(session, sipURIFromID(session->mCallerID)); -			} -			else -			{ -				LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL; -				setUUIDFromStringHash(session->mCallerID, session->mSIPURI); -				session->mSynthesizedCallerID = true; -				 -				// Can't look up the name in this case -- we have to extract it from the URI. -				std::string namePortion = nameFromsipURI(session->mSIPURI); -				if(namePortion.empty()) -				{ -					// Didn't seem to be a SIP URI, just use the whole provided name. -					namePortion = nameString; -				} -				 -				// Some incoming names may be separated with an underscore instead of a space.  Fix this. -				LLStringUtil::replaceChar(namePortion, '_', ' '); -				 -				// Act like we just finished resolving the name (this stores it in all the right places) -				avatarNameResolved(session->mCallerID, namePortion); -			} -		 -			LL_INFOS("Voice") << "caller ID: " << session->mCallerID << LL_ENDL; - -			if(!session->mSynthesizedCallerID) -			{ -				// If we got here, we don't have a proper name.  Initiate a lookup. -				lookupName(session->mCallerID); -			} -		} -	} -} - -void LLVivoxVoiceClient::sessionGroupAddedEvent(std::string &sessionGroupHandle) -{ -	LL_DEBUGS("Voice") << "handle " << sessionGroupHandle << LL_ENDL; -	 -#if USE_SESSION_GROUPS -	if(mMainSessionGroupHandle.empty()) -	{ -		// This is the first (i.e. "main") session group.  Save its handle. -		mMainSessionGroupHandle = sessionGroupHandle; -	} -	else -	{ -		LL_DEBUGS("Voice") << "Already had a session group handle " << mMainSessionGroupHandle << LL_ENDL; -	} -#endif -} - -void LLVivoxVoiceClient::joinedAudioSession(sessionState *session) -{ -	LL_DEBUGS("Voice") << "Joined Audio Session" << LL_ENDL; -	if(mAudioSession != session) -	{ -		sessionState *oldSession = mAudioSession; - -		mAudioSession = session; -		mAudioSessionChanged = true; - -		// The old session may now need to be deleted. -		reapSession(oldSession); -	} -	 -	// This is the session we're joining. -	if(getState() == stateJoiningSession) -	{ -		setState(stateSessionJoined); -		 -		// SLIM SDK: we don't always receive a participant state change for ourselves when joining a channel now. -		// Add the current user as a participant here. -		participantState *participant = session->addParticipant(sipURIFromName(mAccountName)); -		if(participant) -		{ -			participant->mIsSelf = true; -			lookupName(participant->mAvatarID); - -			LL_INFOS("Voice") << "added self as participant \"" << participant->mAccountName  -					<< "\" (" << participant->mAvatarID << ")"<< LL_ENDL; -		} -		 -		if(!session->mIsChannel) -		{ -			// this is a p2p session.  Make sure the other end is added as a participant. -			participantState *participant = session->addParticipant(session->mSIPURI); -			if(participant) -			{ -				if(participant->mAvatarIDValid) -				{ -					lookupName(participant->mAvatarID); -				} -				else if(!session->mName.empty()) -				{ -					participant->mDisplayName = session->mName; -					avatarNameResolved(participant->mAvatarID, session->mName); -				} -				 -				// TODO: Question: Do we need to set up mAvatarID/mAvatarIDValid here? -				LL_INFOS("Voice") << "added caller as participant \"" << participant->mAccountName  -						<< "\" (" << participant->mAvatarID << ")"<< LL_ENDL; -			} -		} -	} -} - -void LLVivoxVoiceClient::sessionRemovedEvent( -	std::string &sessionHandle,  -	std::string &sessionGroupHandle) -{ -	LL_INFOS("Voice") << "handle " << sessionHandle << LL_ENDL; -	 -	sessionState *session = findSession(sessionHandle); -	if(session) -	{ -		leftAudioSession(session); - -		// This message invalidates the session's handle.  Set it to empty. -		setSessionHandle(session); -		 -		// This also means that the session's session group is now empty. -		// Terminate the session group so it doesn't leak. -		sessionGroupTerminateSendMessage(session); -		 -		// Reset the media state (we now have no info) -		session->mMediaStreamState = streamStateUnknown; -		session->mTextStreamState = streamStateUnknown; -		 -		// Conditionally delete the session -		reapSession(session); -	} -	else -	{ -		LL_WARNS("Voice") << "unknown session " << sessionHandle << " removed" << LL_ENDL; -	} -} - -void LLVivoxVoiceClient::reapSession(sessionState *session) -{ -	if(session) -	{ -		if(!session->mHandle.empty()) -		{ -			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (non-null session handle)" << LL_ENDL; -		} -		else if(session->mCreateInProgress) -		{ -			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (create in progress)" << LL_ENDL; -		} -		else if(session->mMediaConnectInProgress) -		{ -			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (connect in progress)" << LL_ENDL; -		} -		else if(session == mAudioSession) -		{ -			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the current session)" << LL_ENDL; -		} -		else if(session == mNextAudioSession) -		{ -			LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the next session)" << LL_ENDL; -		} -		else -		{ -			// TODO: Question: Should we check for queued text messages here? -			// We don't have a reason to keep tracking this session, so just delete it. -			LL_DEBUGS("Voice") << "deleting session " << session->mSIPURI << LL_ENDL; -			deleteSession(session); -			session = NULL; -		}	 -	} -	else -	{ -//		LL_DEBUGS("Voice") << "session is NULL" << LL_ENDL; -	} -} - -// Returns true if the session seems to indicate we've moved to a region on a different voice server -bool LLVivoxVoiceClient::sessionNeedsRelog(sessionState *session) -{ -	bool result = false; -	 -	if(session != NULL) -	{ -		// Only make this check for spatial channels (so it won't happen for group or p2p calls) -		if(session->mIsSpatial) -		{	 -			std::string::size_type atsign; -			 -			atsign = session->mSIPURI.find("@"); -			 -			if(atsign != std::string::npos) -			{ -				std::string urihost = session->mSIPURI.substr(atsign + 1); -				if(stricmp(urihost.c_str(), mVoiceSIPURIHostName.c_str())) -				{ -					// The hostname in this URI is different from what we expect.  This probably means we need to relog. -					 -					// We could make a ProvisionVoiceAccountRequest and compare the result with the current values of -					// mVoiceSIPURIHostName and mVoiceAccountServerURI to be really sure, but this is a pretty good indicator. -					 -					result = true; -				} -			} -		} -	} -	 -	return result; -} - -void LLVivoxVoiceClient::leftAudioSession( -	sessionState *session) -{ -	if(mAudioSession == session) -	{ -		switch(getState()) -		{ -			case stateJoiningSession: -			case stateSessionJoined: -			case stateRunning: -			case stateLeavingSession: -			case stateJoinSessionFailed: -			case stateJoinSessionFailedWaiting: -				// normal transition -				LL_DEBUGS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL; -				setState(stateSessionTerminated); -			break; -			 -			case stateSessionTerminated: -				// this will happen sometimes -- there are cases where we send the terminate and then go straight to this state. -				LL_WARNS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL; -			break; -			 -			default: -				LL_WARNS("Voice") << "unexpected SessionStateChangeEvent (left session) in state " << state2string(getState()) << LL_ENDL; -				setState(stateSessionTerminated); -			break; -		} -	} -} - -void LLVivoxVoiceClient::accountLoginStateChangeEvent( -		std::string &accountHandle,  -		int statusCode,  -		std::string &statusString,  -		int state) -{ -	/* -		According to Mike S., status codes for this event are: -		login_state_logged_out=0, -        login_state_logged_in = 1, -        login_state_logging_in = 2, -        login_state_logging_out = 3, -        login_state_resetting = 4, -        login_state_error=100	 -	*/ -	 -	LL_DEBUGS("Voice") << "state change event: " << state << LL_ENDL; -	switch(state) -	{ -		case 1: -		if(getState() == stateLoggingIn) -		{ -			setState(stateLoggedIn); -		} -		break; - -		case 3: -			// The user is in the process of logging out. -			setState(stateLoggingOut); -		break; - -		case 0: -			// The user has been logged out.   -			setState(stateLoggedOut); -		break; -		 -		default: -			//Used to be a commented out warning -			LL_DEBUGS("Voice") << "unknown state: " << state << LL_ENDL; -		break; -	} -} - -void LLVivoxVoiceClient::mediaStreamUpdatedEvent( -	std::string &sessionHandle,  -	std::string &sessionGroupHandle,  -	int statusCode,  -	std::string &statusString,  -	int state,  -	bool incoming) -{ -	sessionState *session = findSession(sessionHandle); -	 -	LL_DEBUGS("Voice") << "session " << sessionHandle << ", status code " << statusCode << ", string \"" << statusString << "\"" << LL_ENDL; -	 -	if(session) -	{ -		// We know about this session -		 -		// Save the state for later use -		session->mMediaStreamState = state; -		 -		switch(statusCode) -		{ -			case 0: -			case 200: -				// generic success -				// Don't change the saved error code (it may have been set elsewhere) -			break; -			default: -				// save the status code for later -				session->mErrorStatusCode = statusCode; -			break; -		} -		 -		switch(state) -		{ -			case streamStateIdle: -				// Standard "left audio session" -				session->mVoiceEnabled = false; -				session->mMediaConnectInProgress = false; -				leftAudioSession(session); -			break; - -			case streamStateConnected: -				session->mVoiceEnabled = true; -				session->mMediaConnectInProgress = false; -				joinedAudioSession(session); -			break; -			 -			case streamStateRinging: -				if(incoming) -				{ -					// Send the voice chat invite to the GUI layer -					// TODO: Question: Should we correlate with the mute list here? -					session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID); -					session->mVoiceInvitePending = true; -					if(session->mName.empty()) -					{ -						lookupName(session->mCallerID); -					} -					else -					{ -						// Act like we just finished resolving the name -						avatarNameResolved(session->mCallerID, session->mName); -					} -				} -			break; -			 -			default: -				LL_WARNS("Voice") << "unknown state " << state << LL_ENDL; -			break; -			 -		} -		 -	} -	else -	{ -		LL_WARNS("Voice") << "session " << sessionHandle << "not found"<< LL_ENDL; -	} -} - -void LLVivoxVoiceClient::textStreamUpdatedEvent( -	std::string &sessionHandle,  -	std::string &sessionGroupHandle,  -	bool enabled, -	int state,  -	bool incoming) -{ -	sessionState *session = findSession(sessionHandle); -	 -	if(session) -	{ -		// Save the state for later use -		session->mTextStreamState = state; -		 -		// We know about this session -		switch(state) -		{ -			case 0:	// We see this when the text stream closes -				LL_DEBUGS("Voice") << "stream closed" << LL_ENDL; -			break; -			 -			case 1:	// We see this on an incoming call from the Connector -				// Try to send any text messages queued for this session. -				sendQueuedTextMessages(session); - -				// Send the text chat invite to the GUI layer -				// TODO: Question: Should we correlate with the mute list here? -				session->mTextInvitePending = true; -				if(session->mName.empty()) -				{ -					lookupName(session->mCallerID); -				} -				else -				{ -					// Act like we just finished resolving the name -					avatarNameResolved(session->mCallerID, session->mName); -				} -			break; - -			default: -				LL_WARNS("Voice") << "unknown state " << state << LL_ENDL; -			break; -			 -		} -	} -} - -void LLVivoxVoiceClient::participantAddedEvent( -		std::string &sessionHandle,  -		std::string &sessionGroupHandle,  -		std::string &uriString,  -		std::string &alias,  -		std::string &nameString,  -		std::string &displayNameString,  -		int participantType) -{ -	sessionState *session = findSession(sessionHandle); -	if(session) -	{ -		participantState *participant = session->addParticipant(uriString); -		if(participant) -		{ -			participant->mAccountName = nameString; - -			LL_DEBUGS("Voice") << "added participant \"" << participant->mAccountName  -					<< "\" (" << participant->mAvatarID << ")"<< LL_ENDL; - -			if(participant->mAvatarIDValid) -			{ -				// Initiate a lookup -				lookupName(participant->mAvatarID); -			} -			else -			{ -				// If we don't have a valid avatar UUID, we need to fill in the display name to make the active speakers floater work. -				std::string namePortion = nameFromsipURI(uriString); -				if(namePortion.empty()) -				{ -					// Problem with the SIP URI, fall back to the display name -					namePortion = displayNameString; -				} -				if(namePortion.empty()) -				{ -					// Problems with both of the above, fall back to the account name -					namePortion = nameString; -				} -				 -				// Set the display name (which is a hint to the active speakers window not to do its own lookup) -				participant->mDisplayName = namePortion; -				avatarNameResolved(participant->mAvatarID, namePortion); -			} -		} -	} -} - -void LLVivoxVoiceClient::participantRemovedEvent( -		std::string &sessionHandle,  -		std::string &sessionGroupHandle,  -		std::string &uriString,  -		std::string &alias,  -		std::string &nameString) -{ -	sessionState *session = findSession(sessionHandle); -	if(session) -	{ -		participantState *participant = session->findParticipant(uriString); -		if(participant) -		{ -			session->removeParticipant(participant); -		} -		else -		{ -			LL_DEBUGS("Voice") << "unknown participant " << uriString << LL_ENDL; -		} -	} -	else -	{ -		LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL; -	} -} - - -void LLVivoxVoiceClient::participantUpdatedEvent( -		std::string &sessionHandle,  -		std::string &sessionGroupHandle,  -		std::string &uriString,  -		std::string &alias,  -		bool isModeratorMuted,  -		bool isSpeaking,  -		int volume,  -		F32 energy) -{ -	sessionState *session = findSession(sessionHandle); -	if(session) -	{ -		participantState *participant = session->findParticipant(uriString); -		 -		if(participant) -		{ -			participant->mIsSpeaking = isSpeaking; -			participant->mIsModeratorMuted = isModeratorMuted; - -			// SLIM SDK: convert range: ensure that energy is set to zero if is_speaking is false -			if (isSpeaking) -			{ -				participant->mSpeakingTimeout.reset(); -				participant->mPower = energy; -			} -			else -			{ -				participant->mPower = 0.0f; -			} - -			// *HACK: Minimal hack to fix EXT-6508, ignore the incoming volume if it is zero. -			// This happens because we send volume zero to Vivox when someone is muted, -			// Vivox then send it back to us, overwriting the previous volume. -			// Remove this hack once volume refactoring from EXT-6031 is applied. -			if (volume != 0) -			  { -			    participant->mVolume = volume; -			  } -  -			 -			// *HACK: mantipov: added while working on EXT-3544                                                                                    -			/*                                                                                                                                     -			 Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE                                                             -			 LLViewerChatterBoxSessionAgentListUpdates::post() sometimes AFTER.                                                                     -			  -			 participantUpdatedEvent updates voice participant state in particular participantState::mIsModeratorMuted                              -			 Originally we wanted to update session Speaker Manager to fire LLSpeakerVoiceModerationEvent to fix the EXT-3544 bug.                  -			 Calling of the LLSpeakerMgr::update() method was added into LLIMMgr::processAgentListUpdates.                                          -			  -			 But in case participantUpdatedEvent() is called after LLViewerChatterBoxSessionAgentListUpdates::post()                                -			 voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager                                           -			 and event is not fired.                                                                                                                -			  -			 So, we have to call LLSpeakerMgr::update() here. In any case it is better than call it                                                 -			 in LLCallFloater::draw()                                                                                                               -			 */ -			LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel(); -			 -			// ignore session ID of local chat                                                                                                     -			if (voice_cnl && voice_cnl->getSessionID().notNull()) -			{ -				LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(voice_cnl->getSessionID()); -				if (speaker_manager) -				{ -					speaker_manager->update(true); -				} -			} -			 -		} -		else -		{ -			LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL; -		} -	} -	else -	{ -		LL_INFOS("Voice") << "unknown session " << sessionHandle << LL_ENDL; -	} -} - -void LLVivoxVoiceClient::buddyPresenceEvent( -		std::string &uriString,  -		std::string &alias,  -		std::string &statusString, -		std::string &applicationString) -{ -	buddyListEntry *buddy = findBuddy(uriString); -	 -	if(buddy) -	{ -		LL_DEBUGS("Voice") << "Presence event for " << buddy->mDisplayName << " status \"" << statusString << "\", application \"" << applicationString << "\""<< LL_ENDL; -		LL_DEBUGS("Voice") << "before: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL; - -		if(applicationString.empty()) -		{ -			// This presence event is from a client that doesn't set up the Application string.  Do things the old-skool way. -			// NOTE: this will be needed to support people who aren't on the 3010-class SDK yet. - -			if ( stricmp("Unknown", statusString.c_str())== 0)  -			{ -				// User went offline with a non-SLim-enabled viewer. -				buddy->mOnlineSL = false; -			} -			else if ( stricmp("Online", statusString.c_str())== 0)  -			{ -				// User came online with a non-SLim-enabled viewer. -				buddy->mOnlineSL = true; -			} -			else -			{ -				// If the user is online through SLim, their status will be "Online-slc", "Away", or something else. -				// NOTE: we should never see this unless someone is running an OLD version of SLim -- the versions that should be in use now all set the application string. -				buddy->mOnlineSLim = true; -			}  -		} -		else if(applicationString.find("SecondLifeViewer") != std::string::npos) -		{ -			// This presence event is from a viewer that sets the application string -			if ( stricmp("Unknown", statusString.c_str())== 0)  -			{ -				// Viewer says they're offline -				buddy->mOnlineSL = false; -			} -			else -			{ -				// Viewer says they're online -				buddy->mOnlineSL = true; -			} -		} -		else -		{ -			// This presence event is from something which is NOT the SL viewer (assume it's SLim). -			if ( stricmp("Unknown", statusString.c_str())== 0)  -			{ -				// SLim says they're offline -				buddy->mOnlineSLim = false; -			} -			else -			{ -				// SLim says they're online -				buddy->mOnlineSLim = true; -			} -		}  - -		LL_DEBUGS("Voice") << "after: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL; -		 -		// HACK -- increment the internal change serial number in the LLRelationship (without changing the actual status), so the UI notices the change. -		LLAvatarTracker::instance().setBuddyOnline(buddy->mUUID,LLAvatarTracker::instance().isBuddyOnline(buddy->mUUID)); - -		notifyFriendObservers(); -	} -	else -	{ -		LL_DEBUGS("Voice") << "Presence for unknown buddy " << uriString << LL_ENDL; -	}	 -} - -void LLVivoxVoiceClient::messageEvent( -		std::string &sessionHandle,  -		std::string &uriString,  -		std::string &alias,  -		std::string &messageHeader,  -		std::string &messageBody, -		std::string &applicationString) -{ -	LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL; -//	LL_DEBUGS("Voice") << "    header " << messageHeader << ", body: \n" << messageBody << LL_ENDL; -	 -	if(messageHeader.find("text/html") != std::string::npos) -	{ -		std::string message; - -		{ -			const std::string startMarker = "<body"; -			const std::string startMarker2 = ">"; -			const std::string endMarker = "</body>"; -			const std::string startSpan = "<span"; -			const std::string endSpan = "</span>"; -			std::string::size_type start; -			std::string::size_type end; -			 -			// Default to displaying the raw string, so the message gets through. -			message = messageBody; - -			// Find the actual message text within the XML fragment -			start = messageBody.find(startMarker); -			start = messageBody.find(startMarker2, start); -			end = messageBody.find(endMarker); - -			if(start != std::string::npos) -			{ -				start += startMarker2.size(); -				 -				if(end != std::string::npos) -					end -= start; -					 -				message.assign(messageBody, start, end); -			} -			else  -			{ -				// Didn't find a <body>, try looking for a <span> instead. -				start = messageBody.find(startSpan); -				start = messageBody.find(startMarker2, start); -				end = messageBody.find(endSpan); -				 -				if(start != std::string::npos) -				{ -					start += startMarker2.size(); -					 -					if(end != std::string::npos) -						end -= start; -					 -					message.assign(messageBody, start, end); -				}			 -			} -		}	 -		 -//		LL_DEBUGS("Voice") << "    raw message = \n" << message << LL_ENDL; - -		// strip formatting tags -		{ -			std::string::size_type start; -			std::string::size_type end; -			 -			while((start = message.find('<')) != std::string::npos) -			{ -				if((end = message.find('>', start + 1)) != std::string::npos) -				{ -					// Strip out the tag -					message.erase(start, (end + 1) - start); -				} -				else -				{ -					// Avoid an infinite loop -					break; -				} -			} -		} -		 -		// Decode ampersand-escaped chars -		{ -			std::string::size_type mark = 0; - -			// The text may contain text encoded with <, >, and & -			mark = 0; -			while((mark = message.find("<", mark)) != std::string::npos) -			{ -				message.replace(mark, 4, "<"); -				mark += 1; -			} -			 -			mark = 0; -			while((mark = message.find(">", mark)) != std::string::npos) -			{ -				message.replace(mark, 4, ">"); -				mark += 1; -			} -			 -			mark = 0; -			while((mark = message.find("&", mark)) != std::string::npos) -			{ -				message.replace(mark, 5, "&"); -				mark += 1; -			} -		} -		 -		// strip leading/trailing whitespace (since we always seem to get a couple newlines) -		LLStringUtil::trim(message); -		 -//		LL_DEBUGS("Voice") << "    stripped message = \n" << message << LL_ENDL; -		 -		sessionState *session = findSession(sessionHandle); -		if(session) -		{ -			bool is_busy = gAgent.getBusy(); -			bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat); -			bool is_linden = LLMuteList::getInstance()->isLinden(session->mName); -			bool quiet_chat = false; -			LLChat chat; - -			chat.mMuted = is_muted && !is_linden; -			 -			if(!chat.mMuted) -			{ -				chat.mFromID = session->mCallerID; -				chat.mFromName = session->mName; -				chat.mSourceType = CHAT_SOURCE_AGENT; - -				if(is_busy && !is_linden) -				{ -					quiet_chat = true; -					// TODO: Question: Return busy mode response here?  Or maybe when session is started instead? -				} -				 -				LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL; -				gIMMgr->addMessage(session->mIMSessionID, -						session->mCallerID, -						session->mName.c_str(), -						message.c_str(), -						LLStringUtil::null,		// default arg -						IM_NOTHING_SPECIAL,		// default arg -						0,						// default arg -						LLUUID::null,			// default arg -						LLVector3::zero,		// default arg -						true);					// prepend name and make it a link to the user's profile - -			} -		}		 -	} -} - -void LLVivoxVoiceClient::sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string ¬ificationType) -{ -	sessionState *session = findSession(sessionHandle); -	 -	if(session) -	{ -		participantState *participant = session->findParticipant(uriString); -		if(participant) -		{ -			if (!stricmp(notificationType.c_str(), "Typing")) -			{ -				// Other end started typing -				// TODO: The proper way to add a typing notification seems to be LLIMMgr::processIMTypingStart(). -				// It requires an LLIMInfo for the message, which we don't have here. -			} -			else if (!stricmp(notificationType.c_str(), "NotTyping")) -			{ -				// Other end stopped typing -				// TODO: The proper way to remove a typing notification seems to be LLIMMgr::processIMTypingStop(). -				// It requires an LLIMInfo for the message, which we don't have here. -			} -			else -			{ -				LL_DEBUGS("Voice") << "Unknown notification type " << notificationType << "for participant " << uriString << " in session " << session->mSIPURI << LL_ENDL; -			} -		} -		else -		{ -			LL_DEBUGS("Voice") << "Unknown participant " << uriString << " in session " << session->mSIPURI << LL_ENDL; -		} -	} -	else -	{ -		LL_DEBUGS("Voice") << "Unknown session handle " << sessionHandle << LL_ENDL; -	} -} - -void LLVivoxVoiceClient::subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType) -{ -	buddyListEntry *buddy = findBuddy(buddyURI); -	 -	if(!buddy) -	{ -		// Couldn't find buddy by URI, try converting the alias... -		if(!alias.empty()) -		{ -			LLUUID id; -			if(IDFromName(alias, id)) -			{ -				buddy = findBuddy(id); -			} -		} -	} -	 -	if(buddy) -	{ -		std::ostringstream stream; -		 -		if(buddy->mCanSeeMeOnline) -		{ -			// Sending the response will create an auto-accept rule -			buddy->mHasAutoAcceptListEntry = true; -		} -		else -		{ -			// Sending the response will create a block rule -			buddy->mHasBlockListEntry = true; -		} -		 -		if(buddy->mInSLFriends) -		{ -			buddy->mInVivoxBuddies = true; -		} -		 -		stream -			<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.SendSubscriptionReply.1\">" -				<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>" -				<< "<BuddyURI>" << buddy->mURI << "</BuddyURI>" -				<< "<RuleType>" << (buddy->mCanSeeMeOnline?"Allow":"Hide") << "</RuleType>" -				<< "<AutoAccept>"<< (buddy->mInSLFriends?"1":"0")<< "</AutoAccept>" -				<< "<SubscriptionHandle>" << subscriptionHandle << "</SubscriptionHandle>" -			<< "</Request>" -			<< "\n\n\n"; -			 -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::auxAudioPropertiesEvent(F32 energy) -{ -	LL_DEBUGS("Voice") << "got energy " << energy << LL_ENDL; -	mTuningEnergy = energy; -} - -void LLVivoxVoiceClient::buddyListChanged() -{ -	// This is called after we receive a BuddyAndGroupListChangedEvent. -	mBuddyListMapPopulated = true; -	mFriendsListDirty = true; -} - -void LLVivoxVoiceClient::muteListChanged() -{ -	// The user's mute list has been updated.  Go through the current participant list and sync it with the mute list. -	if(mAudioSession) -	{ -		participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin(); -		 -		for(; iter != mAudioSession->mParticipantsByURI.end(); iter++) -		{ -			participantState *p = iter->second; -			 -			// Check to see if this participant is on the mute list already -			if(p->updateMuteState()) -				mAudioSession->mVolumeDirty = true; -		} -	} -} - -void LLVivoxVoiceClient::updateFriends(U32 mask) -{ -	if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::POWERS)) -	{ -		// Just resend the whole friend list to the daemon -		mFriendsListDirty = true; -	} -} - -///////////////////////////// -// Managing list of participants -LLVivoxVoiceClient::participantState::participantState(const std::string &uri) :  -	 mURI(uri),  -	 mPTT(false),  -	 mIsSpeaking(false),  -	 mIsModeratorMuted(false),  -	 mLastSpokeTimestamp(0.f),  -	 mPower(0.f),  -	 mVolume(-1),  -	 mOnMuteList(false),  -	 mUserVolume(-1),  -	 mVolumeDirty(false),  -	 mAvatarIDValid(false), -	 mIsSelf(false) -{ -} - -LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParticipant(const std::string &uri) -{ -	participantState *result = NULL; -	bool useAlternateURI = false; -	 -	// Note: this is mostly the body of LLVivoxVoiceClient::sessionState::findParticipant(), but since we need to know if it -	// matched the alternate SIP URI (so we can add it properly), we need to reproduce it here. -	{ -		participantMap::iterator iter = mParticipantsByURI.find(uri); - -		if(iter == mParticipantsByURI.end()) -		{ -			if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI)) -			{ -				// This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant. -				// Use mSIPURI instead, since it will be properly encoded. -				iter = mParticipantsByURI.find(mSIPURI); -				useAlternateURI = true; -			} -		} - -		if(iter != mParticipantsByURI.end()) -		{ -			result = iter->second; -		} -	} -		 -	if(!result) -	{ -		// participant isn't already in one list or the other. -		result = new participantState(useAlternateURI?mSIPURI:uri); -		mParticipantsByURI.insert(participantMap::value_type(result->mURI, result)); -		mParticipantsChanged = true; -		 -		// Try to do a reverse transform on the URI to get the GUID back. -		{ -			LLUUID id; -			if(LLVivoxVoiceClient::getInstance()->IDFromName(result->mURI, id)) -			{ -				result->mAvatarIDValid = true; -				result->mAvatarID = id; - -				if(result->updateMuteState()) -					mVolumeDirty = true; -			} -			else -			{ -				// Create a UUID by hashing the URI, but do NOT set mAvatarIDValid. -				// This tells both code in LLVivoxVoiceClient and code in llfloateractivespeakers.cpp that the ID will not be in the name cache. -				setUUIDFromStringHash(result->mAvatarID, uri); -			} -		} -		 -		mParticipantsByUUID.insert(participantUUIDMap::value_type(result->mAvatarID, result)); - -		result->mUserVolume = LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID); -		 -		LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL; -	} -	 -	return result; -} - -bool LLVivoxVoiceClient::participantState::updateMuteState() -{ -	bool result = false; -	 -	if(mAvatarIDValid) -	{ -		bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat); -		if(mOnMuteList != isMuted) -		{ -			mOnMuteList = isMuted; -			mVolumeDirty = true; -			result = true; -		} -	} -	return result; -} - -bool LLVivoxVoiceClient::participantState::isAvatar() -{ -	return mAvatarIDValid; -} - -void LLVivoxVoiceClient::sessionState::removeParticipant(LLVivoxVoiceClient::participantState *participant) -{ -	if(participant) -	{ -		participantMap::iterator iter = mParticipantsByURI.find(participant->mURI); -		participantUUIDMap::iterator iter2 = mParticipantsByUUID.find(participant->mAvatarID); -		 -		LL_DEBUGS("Voice") << "participant \"" << participant->mURI <<  "\" (" << participant->mAvatarID << ") removed." << LL_ENDL; -		 -		if(iter == mParticipantsByURI.end()) -		{ -			LL_ERRS("Voice") << "Internal error: participant " << participant->mURI << " not in URI map" << LL_ENDL; -		} -		else if(iter2 == mParticipantsByUUID.end()) -		{ -			LL_ERRS("Voice") << "Internal error: participant ID " << participant->mAvatarID << " not in UUID map" << LL_ENDL; -		} -		else if(iter->second != iter2->second) -		{ -			LL_ERRS("Voice") << "Internal error: participant mismatch!" << LL_ENDL; -		} -		else -		{ -			mParticipantsByURI.erase(iter); -			mParticipantsByUUID.erase(iter2); -			 -			delete participant; -			mParticipantsChanged = true; -		} -	} -} - -void LLVivoxVoiceClient::sessionState::removeAllParticipants() -{ -	LL_DEBUGS("Voice") << "called" << LL_ENDL; - -	while(!mParticipantsByURI.empty()) -	{ -		removeParticipant(mParticipantsByURI.begin()->second); -	} -	 -	if(!mParticipantsByUUID.empty()) -	{ -		LL_ERRS("Voice") << "Internal error: empty URI map, non-empty UUID map" << LL_ENDL; -	} -} - -void LLVivoxVoiceClient::getParticipantList(std::set<LLUUID> &participants) -{ -	if(mAudioSession) -	{ -		for(participantUUIDMap::iterator iter = mAudioSession->mParticipantsByUUID.begin(); -			iter != mAudioSession->mParticipantsByUUID.end();  -			iter++) -		{ -			participants.insert(iter->first); -		} -	} -} - -bool LLVivoxVoiceClient::isParticipant(const LLUUID &speaker_id) -{ -  if(mAudioSession) -    { -      return (mAudioSession->mParticipantsByUUID.find(speaker_id) != mAudioSession->mParticipantsByUUID.end()); -    } -  return false; -} - - -LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::findParticipant(const std::string &uri) -{ -	participantState *result = NULL; -	 -	participantMap::iterator iter = mParticipantsByURI.find(uri); - -	if(iter == mParticipantsByURI.end()) -	{ -		if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI)) -		{ -			// This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant. -			// Look up the other URI -			iter = mParticipantsByURI.find(mSIPURI); -		} -	} - -	if(iter != mParticipantsByURI.end()) -	{ -		result = iter->second; -	} -		 -	return result; -} - -LLVivoxVoiceClient::participantState* LLVivoxVoiceClient::sessionState::findParticipantByID(const LLUUID& id) -{ -	participantState * result = NULL; -	participantUUIDMap::iterator iter = mParticipantsByUUID.find(id); - -	if(iter != mParticipantsByUUID.end()) -	{ -		result = iter->second; -	} - -	return result; -} - -LLVivoxVoiceClient::participantState* LLVivoxVoiceClient::findParticipantByID(const LLUUID& id) -{ -	participantState * result = NULL; -	 -	if(mAudioSession) -	{ -		result = mAudioSession->findParticipantByID(id); -	} -	 -	return result; -} - - -void LLVivoxVoiceClient::parcelChanged() -{ -	if(getState() >= stateNoChannel) -	{ -		// If the user is logged in, start a channel lookup. -		LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL; - -		std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest"); -		LLSD data; -		LLHTTPClient::post( -			url, -			data, -			new LLVivoxVoiceClientCapResponder); -	} -	else -	{ -		// The transition to stateNoChannel needs to kick this off again. -		LL_INFOS("Voice") << "not logged in yet, deferring" << LL_ENDL; -	} -} - -void LLVivoxVoiceClient::switchChannel( -	std::string uri, -	bool spatial, -	bool no_reconnect, -	bool is_p2p, -	std::string hash) -{ -	bool needsSwitch = false; -	 -	LL_DEBUGS("Voice")  -		<< "called in state " << state2string(getState())  -		<< " with uri \"" << uri << "\""  -		<< (spatial?", spatial is true":", spatial is false") -		<< LL_ENDL; -	 -	switch(getState()) -	{ -		case stateJoinSessionFailed: -		case stateJoinSessionFailedWaiting: -		case stateNoChannel: -			// Always switch to the new URI from these states. -			needsSwitch = true; -		break; - -		default: -			if(mSessionTerminateRequested) -			{ -				// If a terminate has been requested, we need to compare against where the URI we're already headed to. -				if(mNextAudioSession) -				{ -					if(mNextAudioSession->mSIPURI != uri) -						needsSwitch = true; -				} -				else -				{ -					// mNextAudioSession is null -- this probably means we're on our way back to spatial. -					if(!uri.empty()) -					{ -						// We do want to process a switch in this case. -						needsSwitch = true; -					} -				} -			} -			else -			{ -				// Otherwise, compare against the URI we're in now. -				if(mAudioSession) -				{ -					if(mAudioSession->mSIPURI != uri) -					{ -						needsSwitch = true; -					} -				} -				else -				{ -					if(!uri.empty()) -					{ -						// mAudioSession is null -- it's not clear what case would cause this. -						// For now, log it as a warning and see if it ever crops up. -						LL_WARNS("Voice") << "No current audio session." << LL_ENDL; -					} -				} -			} -		break; -	} -	 -	if(needsSwitch) -	{ -		if(uri.empty()) -		{ -			// Leave any channel we may be in -			LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL; - -			sessionState *oldSession = mNextAudioSession; -			mNextAudioSession = NULL; - -			// The old session may now need to be deleted. -			reapSession(oldSession); - -			notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED); -		} -		else -		{ -			LL_DEBUGS("Voice") << "switching to channel " << uri << LL_ENDL; - -			mNextAudioSession = addSession(uri); -			mNextAudioSession->mHash = hash; -			mNextAudioSession->mIsSpatial = spatial; -			mNextAudioSession->mReconnect = !no_reconnect; -			mNextAudioSession->mIsP2P = is_p2p; -		} -		 -		if(getState() <= stateNoChannel) -		{ -			// We're already set up to join a channel, just needed to fill in the session URI -		} -		else -		{ -			// State machine will come around and rejoin if uri/handle is not empty. -			sessionTerminate(); -		} -	} -} - -void LLVivoxVoiceClient::joinSession(sessionState *session) -{ -	mNextAudioSession = session; -	 -	if(getState() <= stateNoChannel) -	{ -		// We're already set up to join a channel, just needed to fill in the session handle -	} -	else -	{ -		// State machine will come around and rejoin if uri/handle is not empty. -		sessionTerminate(); -	} -} - -void LLVivoxVoiceClient::setNonSpatialChannel( -	const std::string &uri, -	const std::string &credentials) -{ -	switchChannel(uri, false, false, false, credentials); -} - -void LLVivoxVoiceClient::setSpatialChannel( -	const std::string &uri, -	const std::string &credentials) -{ -	mSpatialSessionURI = uri; -	mSpatialSessionCredentials = credentials; -	mAreaVoiceDisabled = mSpatialSessionURI.empty(); - -	LL_DEBUGS("Voice") << "got spatial channel uri: \"" << uri << "\"" << LL_ENDL; -	 -	if((mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial))) -	{ -		// User is in a non-spatial chat or joining a non-spatial chat.  Don't switch channels. -		LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL; -	} -	else -	{ -		switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials); -	} -} - -void LLVivoxVoiceClient::callUser(const LLUUID &uuid) -{ -	std::string userURI = sipURIFromID(uuid); - -	switchChannel(userURI, false, true, true); -} - -LLVivoxVoiceClient::sessionState* LLVivoxVoiceClient::startUserIMSession(const LLUUID &uuid) -{ -	// Figure out if a session with the user already exists -	sessionState *session = findSession(uuid); -	if(!session) -	{ -		// No session with user, need to start one. -		std::string uri = sipURIFromID(uuid); -		session = addSession(uri); - -		llassert(session); -		if (!session) return NULL; - -		session->mIsSpatial = false; -		session->mReconnect = false;	 -		session->mIsP2P = true; -		session->mCallerID = uuid; -	} -	 -	if(session->mHandle.empty()) -	  { -	    // Session isn't active -- start it up. -	    sessionCreateSendMessage(session, false, true); -	  } -	else -	  {	 -	    // Session is already active -- start up text. -	    sessionTextConnectSendMessage(session); -	  } -	 -	return session; -} - -BOOL LLVivoxVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message) -{ -	bool result = false; - -	// Attempt to locate the indicated session -	sessionState *session = startUserIMSession(participant_id); -	if(session) -	{ -		// found the session, attempt to send the message -		session->mTextMsgQueue.push(message); -		 -		// Try to send queued messages (will do nothing if the session is not open yet) -		sendQueuedTextMessages(session); - -		// The message is queued, so we succeed. -		result = true; -	}	 -	else -	{ -		LL_DEBUGS("Voice") << "Session not found for participant ID " << participant_id << LL_ENDL; -	} -	 -	return result; -} - -void LLVivoxVoiceClient::sendQueuedTextMessages(sessionState *session) -{ -	if(session->mTextStreamState == 1) -	{ -		if(!session->mTextMsgQueue.empty()) -		{ -			std::ostringstream stream; -			 -			while(!session->mTextMsgQueue.empty()) -			{ -				std::string message = session->mTextMsgQueue.front(); -				session->mTextMsgQueue.pop(); -				stream -				<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SendMessage.1\">" -					<< "<SessionHandle>" << session->mHandle << "</SessionHandle>" -					<< "<MessageHeader>text/HTML</MessageHeader>" -					<< "<MessageBody>" << message << "</MessageBody>" -				<< "</Request>" -				<< "\n\n\n"; -			}		 -			writeString(stream.str()); -		} -	} -	else -	{ -		// Session isn't connected yet, defer until later. -	} -} - -void LLVivoxVoiceClient::endUserIMSession(const LLUUID &uuid) -{ -	// Figure out if a session with the user exists -	sessionState *session = findSession(uuid); -	if(session) -	{ -		// found the session -		if(!session->mHandle.empty()) -		{ -			sessionTextDisconnectSendMessage(session); -		} -	}	 -	else -	{ -		LL_DEBUGS("Voice") << "Session not found for participant ID " << uuid << LL_ENDL; -	} -} - -bool LLVivoxVoiceClient::answerInvite(std::string &sessionHandle) -{ -	// this is only ever used to answer incoming p2p call invites. -	 -	sessionState *session = findSession(sessionHandle); -	if(session) -	{ -		session->mIsSpatial = false; -		session->mReconnect = false;	 -		session->mIsP2P = true; - -		joinSession(session); -		return true; -	} -	 -	return false; -} - -BOOL LLVivoxVoiceClient::isOnlineSIP(const LLUUID &id) -{ -	bool result = false; -	buddyListEntry *buddy = findBuddy(id); -	if(buddy) -	{ -		result = buddy->mOnlineSLim; -		LL_DEBUGS("Voice") << "Buddy " << buddy->mDisplayName << " is SIP " << (result?"online":"offline") << LL_ENDL; -	} - -	if(!result) -	{ -		// This user isn't on the buddy list or doesn't show online status through the buddy list, but could be a participant in an existing session if they initiated a text IM. -		sessionState *session = findSession(id); -		if(session && !session->mHandle.empty()) -		{ -			if((session->mTextStreamState != streamStateUnknown) || (session->mMediaStreamState > streamStateIdle)) -			{ -				LL_DEBUGS("Voice") << "Open session with " << id << " found, returning SIP online state" << LL_ENDL; -				// we have a p2p text session open with this user, so by definition they're online. -				result = true; -			} -		} -	} -	 -	return result; -} - -bool LLVivoxVoiceClient::isVoiceWorking() -{ -  //Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758) -  // Condition with joining spatial num was added to take into account possible problems with connection to voice -  // server(EXT-4313). See bug descriptions and comments for MAX_NORMAL_JOINING_SPATIAL_NUM for more info. -  return (mSpatialJoiningNum < MAX_NORMAL_JOINING_SPATIAL_NUM) && (stateLoggedIn <= mState) && (mState <= stateSessionTerminated); -} - -// Returns true if the indicated participant in the current audio session is really an SL avatar. -// Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls. -BOOL LLVivoxVoiceClient::isParticipantAvatar(const LLUUID &id) -{ -	BOOL result = TRUE;  -	sessionState *session = findSession(id); -	 -	if(session != NULL) -	{ -		// this is a p2p session with the indicated caller, or the session with the specified UUID. -		if(session->mSynthesizedCallerID) -			result = FALSE; -	} -	else -	{ -		// Didn't find a matching session -- check the current audio session for a matching participant -		if(mAudioSession != NULL) -		{ -			participantState *participant = findParticipantByID(id); -			if(participant != NULL) -			{ -				result = participant->isAvatar(); -			} -		} -	} -	 -	return result; -} - -// Returns true if calling back the session URI after the session has closed is possible. -// Currently this will be false only for PSTN P2P calls.		 -BOOL LLVivoxVoiceClient::isSessionCallBackPossible(const LLUUID &session_id) -{ -	BOOL result = TRUE;  -	sessionState *session = findSession(session_id); -	 -	if(session != NULL) -	{ -		result = session->isCallBackPossible(); -	} -	 -	return result; -} - -// Returns true if the session can accepte text IM's. -// Currently this will be false only for PSTN P2P calls. -BOOL LLVivoxVoiceClient::isSessionTextIMPossible(const LLUUID &session_id) -{ -	bool result = TRUE;  -	sessionState *session = findSession(session_id); -	 -	if(session != NULL) -	{ -		result = session->isTextIMPossible(); -	} -	 -	return result; -} -		 - -void LLVivoxVoiceClient::declineInvite(std::string &sessionHandle) -{ -	sessionState *session = findSession(sessionHandle); -	if(session) -	{ -		sessionMediaDisconnectSendMessage(session); -	} -} - -void LLVivoxVoiceClient::leaveNonSpatialChannel() -{ -	LL_DEBUGS("Voice")  -		<< "called in state " << state2string(getState())  -		<< LL_ENDL; -	 -	// Make sure we don't rejoin the current session.	 -	sessionState *oldNextSession = mNextAudioSession; -	mNextAudioSession = NULL; -	 -	// Most likely this will still be the current session at this point, but check it anyway. -	reapSession(oldNextSession); -	 -	verifySessionState(); -	 -	sessionTerminate(); -} - -std::string LLVivoxVoiceClient::getCurrentChannel() -{ -	std::string result; -	 -	if((getState() == stateRunning) && !mSessionTerminateRequested) -	{ -		result = getAudioSessionURI(); -	} -	 -	return result; -} - -bool LLVivoxVoiceClient::inProximalChannel() -{ -	bool result = false; -	 -	if((getState() == stateRunning) && !mSessionTerminateRequested) -	{ -		result = inSpatialChannel(); -	} -	 -	return result; -} - -std::string LLVivoxVoiceClient::sipURIFromID(const LLUUID &id) -{ -	std::string result; -	result = "sip:"; -	result += nameFromID(id); -	result += "@"; -	result += mVoiceSIPURIHostName; -	 -	return result; -} - -std::string LLVivoxVoiceClient::sipURIFromAvatar(LLVOAvatar *avatar) -{ -	std::string result; -	if(avatar) -	{ -		result = "sip:"; -		result += nameFromID(avatar->getID()); -		result += "@"; -		result += mVoiceSIPURIHostName; -	} -	 -	return result; -} - -std::string LLVivoxVoiceClient::nameFromAvatar(LLVOAvatar *avatar) -{ -	std::string result; -	if(avatar) -	{ -		result = nameFromID(avatar->getID()); -	}	 -	return result; -} - -std::string LLVivoxVoiceClient::nameFromID(const LLUUID &uuid) -{ -	std::string result; -	 -	if (uuid.isNull()) { -		//VIVOX, the uuid emtpy look for the mURIString and return that instead. -		//result.assign(uuid.mURIStringName); -		LLStringUtil::replaceChar(result, '_', ' '); -		return result; -	} -	// Prepending this apparently prevents conflicts with reserved names inside the vivox and diamondware code. -	result = "x"; -	 -	// Base64 encode and replace the pieces of base64 that are less compatible  -	// with e-mail local-parts. -	// See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet" -	result += LLBase64::encode(uuid.mData, UUID_BYTES); -	LLStringUtil::replaceChar(result, '+', '-'); -	LLStringUtil::replaceChar(result, '/', '_'); -	 -	// If you need to transform a GUID to this form on the Mac OS X command line, this will do so: -	// echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-') -	 -	// The reverse transform can be done with: -	// echo 'x5mkTKmxDTuGnjWyC__WfMg==' |cut -b 2- -|tr '_-' '/+' |openssl base64 -d|xxd -p -	 -	return result; -} - -bool LLVivoxVoiceClient::IDFromName(const std::string inName, LLUUID &uuid) -{ -	bool result = false; -	 -	// SLIM SDK: The "name" may actually be a SIP URI such as: "sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com" -	// If it is, convert to a bare name before doing the transform. -	std::string name = nameFromsipURI(inName); -	 -	// Doesn't look like a SIP URI, assume it's an actual name. -	if(name.empty()) -		name = inName; - -	// This will only work if the name is of the proper form. -	// As an example, the account name for Monroe Linden (UUID 1673cfd3-8229-4445-8d92-ec3570e5e587) is: -	// "xFnPP04IpREWNkuw1cOXlhw==" -	 -	if((name.size() == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '=')) -	{ -		// The name appears to have the right form. - -		// Reverse the transforms done by nameFromID -		std::string temp = name; -		LLStringUtil::replaceChar(temp, '-', '+'); -		LLStringUtil::replaceChar(temp, '_', '/'); - -		U8 rawuuid[UUID_BYTES + 1];  -		int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1); -		if(len == UUID_BYTES) -		{ -			// The decode succeeded.  Stuff the bits into the result's UUID -			memcpy(uuid.mData, rawuuid, UUID_BYTES); -			result = true; -		} -	}  -	 -	if(!result) -	{ -		// VIVOX:  not a standard account name, just copy the URI name mURIString field -		// and hope for the best.  bpj -		uuid.setNull();  // VIVOX, set the uuid field to nulls -	} -	 -	return result; -} - -std::string LLVivoxVoiceClient::displayNameFromAvatar(LLVOAvatar *avatar) -{ -	return avatar->getFullname(); -} - -std::string LLVivoxVoiceClient::sipURIFromName(std::string &name) -{ -	std::string result; -	result = "sip:"; -	result += name; -	result += "@"; -	result += mVoiceSIPURIHostName; - -//	LLStringUtil::toLower(result); - -	return result; -} - -std::string LLVivoxVoiceClient::nameFromsipURI(const std::string &uri) -{ -	std::string result; - -	std::string::size_type sipOffset, atOffset; -	sipOffset = uri.find("sip:"); -	atOffset = uri.find("@"); -	if((sipOffset != std::string::npos) && (atOffset != std::string::npos)) -	{ -		result = uri.substr(sipOffset + 4, atOffset - (sipOffset + 4)); -	} -	 -	return result; -} - -bool LLVivoxVoiceClient::inSpatialChannel(void) -{ -	bool result = false; -	 -	if(mAudioSession) -		result = mAudioSession->mIsSpatial; -		 -	return result; -} - -std::string LLVivoxVoiceClient::getAudioSessionURI() -{ -	std::string result; -	 -	if(mAudioSession) -		result = mAudioSession->mSIPURI; -		 -	return result; -} - -std::string LLVivoxVoiceClient::getAudioSessionHandle() -{ -	std::string result; -	 -	if(mAudioSession) -		result = mAudioSession->mHandle; -		 -	return result; -} - - -///////////////////////////// -// Sending updates of current state - -void LLVivoxVoiceClient::enforceTether(void) -{ -	LLVector3d tethered	= mCameraRequestedPosition; - -	// constrain 'tethered' to within 50m of mAvatarPosition. -	{ -		F32 max_dist = 50.0f; -		LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition; -		F32 camera_distance = (F32)camera_offset.magVec(); -		if(camera_distance > max_dist) -		{ -			tethered = mAvatarPosition +  -				(max_dist / camera_distance) * camera_offset; -		} -	} -	 -	if(dist_vec(mCameraPosition, tethered) > 0.1) -	{ -		mCameraPosition = tethered; -		mSpatialCoordsDirty = true; -	} -} - -void LLVivoxVoiceClient::updatePosition(void) -{ -	 -	LLViewerRegion *region = gAgent.getRegion(); -	if(region && isAgentAvatarValid()) -	{ -		LLMatrix3 rot; -		LLVector3d pos; -		 -		// TODO: If camera and avatar velocity are actually used by the voice system, we could compute them here... -		// They're currently always set to zero. -		 -		// Send the current camera position to the voice code -		rot.setRows(LLViewerCamera::getInstance()->getAtAxis(), LLViewerCamera::getInstance()->getLeftAxis (),  LLViewerCamera::getInstance()->getUpAxis());		 -		pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin()); -		 -		LLVivoxVoiceClient::getInstance()->setCameraPosition( -															 pos,				// position -															 LLVector3::zero, 	// velocity -															 rot);				// rotation matrix -		 -		// Send the current avatar position to the voice code -		rot = gAgentAvatarp->getRootJoint()->getWorldRotation().getMatrix3(); -		pos = gAgentAvatarp->getPositionGlobal(); - -		// TODO: Can we get the head offset from outside the LLVOAvatar? -		//			pos += LLVector3d(mHeadOffset); -		pos += LLVector3d(0.f, 0.f, 1.f); -		 -		LLVivoxVoiceClient::getInstance()->setAvatarPosition( -															 pos,				// position -															 LLVector3::zero, 	// velocity -															 rot);				// rotation matrix -	} -} - -void LLVivoxVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot) -{ -	mCameraRequestedPosition = position; -	 -	if(mCameraVelocity != velocity) -	{ -		mCameraVelocity = velocity; -		mSpatialCoordsDirty = true; -	} -	 -	if(mCameraRot != rot) -	{ -		mCameraRot = rot; -		mSpatialCoordsDirty = true; -	} -} - -void LLVivoxVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot) -{ -	if(dist_vec(mAvatarPosition, position) > 0.1) -	{ -		mAvatarPosition = position; -		mSpatialCoordsDirty = true; -	} -	 -	if(mAvatarVelocity != velocity) -	{ -		mAvatarVelocity = velocity; -		mSpatialCoordsDirty = true; -	} -	 -	if(mAvatarRot != rot) -	{ -		mAvatarRot = rot; -		mSpatialCoordsDirty = true; -	} -} - -bool LLVivoxVoiceClient::channelFromRegion(LLViewerRegion *region, std::string &name) -{ -	bool result = false; -	 -	if(region) -	{ -		name = region->getName(); -	} -	 -	if(!name.empty()) -		result = true; -	 -	return result; -} - -void LLVivoxVoiceClient::leaveChannel(void) -{ -	if(getState() == stateRunning) -	{ -		LL_DEBUGS("Voice") << "leaving channel for teleport/logout" << LL_ENDL; -		mChannelName.clear(); -		sessionTerminate(); -	} -} - -void LLVivoxVoiceClient::setMuteMic(bool muted) -{ -	mMuteMic = muted; -} - -void LLVivoxVoiceClient::setUserPTTState(bool ptt) -{ -	mUserPTTState = ptt; -} - -bool LLVivoxVoiceClient::getUserPTTState() -{ -	return mUserPTTState; -} - -void LLVivoxVoiceClient::inputUserControlState(bool down) -{ -	if(mPTTIsToggle) -	{ -		if(down) // toggle open-mic state on 'down'                                                         -		{ -			toggleUserPTTState(); -		} -	} -	else // set open-mic state as an absolute                                                                   -	{ -		setUserPTTState(down); -	} -} - - -void LLVivoxVoiceClient::toggleUserPTTState(void) -{ -	mUserPTTState = !mUserPTTState; -} - -void LLVivoxVoiceClient::setVoiceEnabled(bool enabled) -{ -	if (enabled != mVoiceEnabled) -	{ -		// TODO: Refactor this so we don't call into LLVoiceChannel, but simply -		// use the status observer -		mVoiceEnabled = enabled; -		LLVoiceClientStatusObserver::EStatusType status; -		 -		 -		if (enabled) -		{ -			LLVoiceChannel::getCurrentVoiceChannel()->activate(); -			status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED; -		} -		else -		{ -			// Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it. -			LLVoiceChannel::getCurrentVoiceChannel()->deactivate(); -			status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED; -		} -	} -} - -bool LLVivoxVoiceClient::voiceEnabled() -{ -	return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice"); -} - -void LLVivoxVoiceClient::setLipSyncEnabled(BOOL enabled) -{ -	mLipSyncEnabled = enabled; -} - -BOOL LLVivoxVoiceClient::lipSyncEnabled() -{ -	    -	if ( mVoiceEnabled && stateDisabled != getState() ) -	{ -		return mLipSyncEnabled; -	} -	else -	{ -		return FALSE; -	} -} - -void LLVivoxVoiceClient::setUsePTT(bool usePTT) -{ -	if(usePTT && !mUsePTT) -	{ -		// When the user turns on PTT, reset the current state. -		mUserPTTState = false; -	} -	mUsePTT = usePTT; -} - -void LLVivoxVoiceClient::setPTTIsToggle(bool PTTIsToggle) -{ -	if(!PTTIsToggle && mPTTIsToggle) -	{ -		// When the user turns off toggle, reset the current state. -		mUserPTTState = false; -	} -	 -	mPTTIsToggle = PTTIsToggle; -} - -bool LLVivoxVoiceClient::getPTTIsToggle() -{ -	return mPTTIsToggle; -} - -void LLVivoxVoiceClient::setPTTKey(std::string &key) -{ -	if(key == "MiddleMouse") -	{ -		mPTTIsMiddleMouse = true; -	} -	else -	{ -		mPTTIsMiddleMouse = false; -		if(!LLKeyboard::keyFromString(key, &mPTTKey)) -		{ -			// If the call failed, don't match any key. -			key = KEY_NONE; -		} -	} -} - -void LLVivoxVoiceClient::setEarLocation(S32 loc) -{ -	if(mEarLocation != loc) -	{ -		LL_DEBUGS("Voice") << "Setting mEarLocation to " << loc << LL_ENDL; -		 -		mEarLocation = loc; -		mSpatialCoordsDirty = true; -	} -} - -void LLVivoxVoiceClient::setVoiceVolume(F32 volume) -{ -	int scaled_volume = scale_speaker_volume(volume);	 - -	if(scaled_volume != mSpeakerVolume) -	{ -	  int min_volume = scale_speaker_volume(0); -		if((scaled_volume == min_volume) || (mSpeakerVolume == min_volume)) -		{ -			mSpeakerMuteDirty = true; -		} - -		mSpeakerVolume = scaled_volume; -		mSpeakerVolumeDirty = true; -	} -} - -void LLVivoxVoiceClient::setMicGain(F32 volume) -{ -	int scaled_volume = scale_mic_volume(volume); -	 -	if(scaled_volume != mMicVolume) -	{ -		mMicVolume = scaled_volume; -		mMicVolumeDirty = true; -	} -} - -void LLVivoxVoiceClient::keyDown(KEY key, MASK mask) -{	 -	if (gKeyboard->getKeyRepeated(key)) -	{ -		// ignore auto-repeat keys                                                                          -		return; -	} -	 -	if(!mPTTIsMiddleMouse) -	{ -		bool down = (mPTTKey != KEY_NONE) -		&& gKeyboard->getKeyDown(mPTTKey); -		inputUserControlState(down); -	} -	 -	 -} -void LLVivoxVoiceClient::keyUp(KEY key, MASK mask) -{ -	if(!mPTTIsMiddleMouse) -	{ -		bool down = (mPTTKey != KEY_NONE) -		&& gKeyboard->getKeyDown(mPTTKey); -		inputUserControlState(down); -	} -	 -} -void LLVivoxVoiceClient::middleMouseState(bool down) -{ -	if(mPTTIsMiddleMouse) -	{ -        if(mPTTIsMiddleMouse) -        { -			inputUserControlState(down); -        }		 -	} -} - -///////////////////////////// -// Accessors for data related to nearby speakers -BOOL LLVivoxVoiceClient::getVoiceEnabled(const LLUUID& id) -{ -	BOOL result = FALSE; -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		// I'm not sure what the semantics of this should be. -		// For now, if we have any data about the user that came through the chat channel, assume they're voice-enabled. -		result = TRUE; -	} -	 -	return result; -} - -std::string LLVivoxVoiceClient::getDisplayName(const LLUUID& id) -{ -	std::string result; -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		result = participant->mDisplayName; -	} -	 -	return result; -} - - - -BOOL LLVivoxVoiceClient::getIsSpeaking(const LLUUID& id) -{ -	BOOL result = FALSE; - -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		if (participant->mSpeakingTimeout.getElapsedTimeF32() > SPEAKING_TIMEOUT) -		{ -			participant->mIsSpeaking = FALSE; -		} -		result = participant->mIsSpeaking; -	} -	 -	return result; -} - -BOOL LLVivoxVoiceClient::getIsModeratorMuted(const LLUUID& id) -{ -	BOOL result = FALSE; - -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		result = participant->mIsModeratorMuted; -	} -	 -	return result; -} - -F32 LLVivoxVoiceClient::getCurrentPower(const LLUUID& id) -{		 -	F32 result = 0; -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		result = participant->mPower; -	} -	 -	return result; -} - - - -BOOL LLVivoxVoiceClient::getUsingPTT(const LLUUID& id) -{ -	BOOL result = FALSE; - -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		// I'm not sure what the semantics of this should be. -		// Does "using PTT" mean they're configured with a push-to-talk button? -		// For now, we know there's no PTT mechanism in place, so nobody is using it. -	} -	 -	return result; -} - -BOOL LLVivoxVoiceClient::getOnMuteList(const LLUUID& id) -{ -	BOOL result = FALSE; -	 -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		result = participant->mOnMuteList; -	} - -	return result; -} - -// External accessiors. Maps 0.0 to 1.0 to internal values 0-400 with .5 == 100 -// internal = 400 * external^2 -F32 LLVivoxVoiceClient::getUserVolume(const LLUUID& id) -{ -	F32 result = 0.0f; -	 -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		S32 ires = 100; // nominal default volume -		 -		if(participant->mIsSelf) -		{ -			// Always make it look like the user's own volume is set at the default. -		} -		else if(participant->mUserVolume != -1) -		{ -			// Use the internal volume -			ires = participant->mUserVolume; -			 -			// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. -//			LL_DEBUGS("Voice") << "mapping from mUserVolume " << ires << LL_ENDL; -		} -		else if(participant->mVolume != -1) -		{ -			// Map backwards from vivox volume  - -			// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. -//			LL_DEBUGS("Voice") << "mapping from mVolume " << participant->mVolume << LL_ENDL; - -			if(participant->mVolume < 56) -			{ -				ires = (participant->mVolume * 100) / 56; -			} -			else -			{ -				ires = (((participant->mVolume - 56) * 300) / (100 - 56)) + 100; -			} -		} -		result = sqrtf(((F32)ires) / 400.f); -	} - -	// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. -//	LL_DEBUGS("Voice") << "returning " << result << LL_ENDL; - -	return result; -} - -void LLVivoxVoiceClient::setUserVolume(const LLUUID& id, F32 volume) -{ -	if(mAudioSession) -	{ -		participantState *participant = findParticipantByID(id); -		if (participant) -		{ -			// store this volume setting for future sessions -			LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume); -			// volume can amplify by as much as 4x! -			S32 ivol = (S32)(400.f * volume * volume); -			participant->mUserVolume = llclamp(ivol, 0, 400); -			participant->mVolumeDirty = TRUE; -			mAudioSession->mVolumeDirty = TRUE; - -		} -	} -} - -std::string LLVivoxVoiceClient::getGroupID(const LLUUID& id) -{ -	std::string result; - -	participantState *participant = findParticipantByID(id); -	if(participant) -	{ -		result = participant->mGroupID; -	} -	 -	return result; -} - -BOOL LLVivoxVoiceClient::getAreaVoiceDisabled() -{ -	return mAreaVoiceDisabled; -} - -void LLVivoxVoiceClient::recordingLoopStart(int seconds, int deltaFramesPerControlFrame) -{ -//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Start)" << LL_ENDL; -	 -	if(!mMainSessionGroupHandle.empty()) -	{ -		std::ostringstream stream; -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">" -		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" -		<< "<RecordingControlType>Start</RecordingControlType>"  -		<< "<DeltaFramesPerControlFrame>" << deltaFramesPerControlFrame << "</DeltaFramesPerControlFrame>" -		<< "<Filename>" << "" << "</Filename>" -		<< "<EnableAudioRecordingEvents>false</EnableAudioRecordingEvents>" -		<< "<LoopModeDurationSeconds>" << seconds << "</LoopModeDurationSeconds>" -		<< "</Request>\n\n\n"; - - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::recordingLoopSave(const std::string& filename) -{ -//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Flush)" << LL_ENDL; - -	if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty()) -	{ -		std::ostringstream stream; -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">" -		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" -		<< "<RecordingControlType>Flush</RecordingControlType>"  -		<< "<Filename>" << filename << "</Filename>" -		<< "</Request>\n\n\n"; - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::recordingStop() -{ -//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Stop)" << LL_ENDL; - -	if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty()) -	{ -		std::ostringstream stream; -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">" -		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" -		<< "<RecordingControlType>Stop</RecordingControlType>"  -		<< "</Request>\n\n\n"; - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::filePlaybackStart(const std::string& filename) -{ -//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Start)" << LL_ENDL; - -	if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty()) -	{ -		std::ostringstream stream; -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">" -		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" -		<< "<RecordingControlType>Start</RecordingControlType>"  -		<< "<Filename>" << filename << "</Filename>" -		<< "</Request>\n\n\n"; - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::filePlaybackStop() -{ -//	LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Stop)" << LL_ENDL; - -	if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty()) -	{ -		std::ostringstream stream; -		stream -		<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">" -		<< "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>" -		<< "<RecordingControlType>Stop</RecordingControlType>"  -		<< "</Request>\n\n\n"; - -		writeString(stream.str()); -	} -} - -void LLVivoxVoiceClient::filePlaybackSetPaused(bool paused) -{ -	// TODO: Implement once Vivox gives me a sample -} - -void LLVivoxVoiceClient::filePlaybackSetMode(bool vox, float speed) -{ -	// TODO: Implement once Vivox gives me a sample -} - -LLVivoxVoiceClient::sessionState::sessionState() : -        mErrorStatusCode(0), -	mMediaStreamState(streamStateUnknown), -	mTextStreamState(streamStateUnknown), -	mCreateInProgress(false), -	mMediaConnectInProgress(false), -	mVoiceInvitePending(false), -	mTextInvitePending(false), -	mSynthesizedCallerID(false), -	mIsChannel(false), -	mIsSpatial(false), -	mIsP2P(false), -	mIncoming(false), -	mVoiceEnabled(false), -	mReconnect(false), -	mVolumeDirty(false), -	mParticipantsChanged(false) -{ -} - -LLVivoxVoiceClient::sessionState::~sessionState() -{ -	removeAllParticipants(); -} - -bool LLVivoxVoiceClient::sessionState::isCallBackPossible() -{ -	// This may change to be explicitly specified by vivox in the future... -	// Currently, only PSTN P2P calls cannot be returned. -	// Conveniently, this is also the only case where we synthesize a caller UUID. -	return !mSynthesizedCallerID; -} - -bool LLVivoxVoiceClient::sessionState::isTextIMPossible() -{ -	// This may change to be explicitly specified by vivox in the future... -	return !mSynthesizedCallerID; -} - - -LLVivoxVoiceClient::sessionIterator LLVivoxVoiceClient::sessionsBegin(void) -{ -	return mSessions.begin(); -} - -LLVivoxVoiceClient::sessionIterator LLVivoxVoiceClient::sessionsEnd(void) -{ -	return mSessions.end(); -} - - -LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::findSession(const std::string &handle) -{ -	sessionState *result = NULL; -	sessionMap::iterator iter = mSessionsByHandle.find(handle); -	if(iter != mSessionsByHandle.end()) -	{ -		result = iter->second; -	} -	 -	return result; -} - -LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::findSessionBeingCreatedByURI(const std::string &uri) -{	 -	sessionState *result = NULL; -	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) -	{ -		sessionState *session = *iter; -		if(session->mCreateInProgress && (session->mSIPURI == uri)) -		{ -			result = session; -			break; -		} -	} -	 -	return result; -} - -LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::findSession(const LLUUID &participant_id) -{ -	sessionState *result = NULL; -	 -	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) -	{ -		sessionState *session = *iter; -		if((session->mCallerID == participant_id) || (session->mIMSessionID == participant_id)) -		{ -			result = session; -			break; -		} -	} -	 -	return result; -} - -LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::addSession(const std::string &uri, const std::string &handle) -{ -	sessionState *result = NULL; -	 -	if(handle.empty()) -	{ -		// No handle supplied. -		// Check whether there's already a session with this URI -		for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) -		{ -			sessionState *s = *iter; -			if((s->mSIPURI == uri) || (s->mAlternateSIPURI == uri)) -			{ -				// TODO: I need to think about this logic... it's possible that this case should raise an internal error. -				result = s; -				break; -			} -		} -	} -	else // (!handle.empty()) -	{ -		// Check for an existing session with this handle -		sessionMap::iterator iter = mSessionsByHandle.find(handle); -		 -		if(iter != mSessionsByHandle.end()) -		{ -			result = iter->second; -		} -	} - -	if(!result) -	{ -		// No existing session found. -		 -		LL_DEBUGS("Voice") << "adding new session: handle " << handle << " URI " << uri << LL_ENDL; -		result = new sessionState(); -		result->mSIPURI = uri; -		result->mHandle = handle; -		 -		mSessions.insert(result); - -		if(!result->mHandle.empty()) -		{ -			mSessionsByHandle.insert(sessionMap::value_type(result->mHandle, result)); -		} -	} -	else -	{ -		// Found an existing session -		 -		if(uri != result->mSIPURI) -		{ -			// TODO: Should this be an internal error? -			LL_DEBUGS("Voice") << "changing uri from " << result->mSIPURI << " to " << uri << LL_ENDL; -			setSessionURI(result, uri); -		} - -		if(handle != result->mHandle) -		{ -			if(handle.empty()) -			{ -				// There's at least one race condition where where addSession was clearing an existing session handle, which caused things to break. -				LL_DEBUGS("Voice") << "NOT clearing handle " << result->mHandle << LL_ENDL; -			} -			else -			{ -				// TODO: Should this be an internal error? -				LL_DEBUGS("Voice") << "changing handle from " << result->mHandle << " to " << handle << LL_ENDL; -				setSessionHandle(result, handle); -			} -		} -		 -		LL_DEBUGS("Voice") << "returning existing session: handle " << handle << " URI " << uri << LL_ENDL; -	} - -	verifySessionState(); -		 -	return result; -} - -void LLVivoxVoiceClient::setSessionHandle(sessionState *session, const std::string &handle) -{ -	// Have to remove the session from the handle-indexed map before changing the handle, or things will break badly. -	 -	if(!session->mHandle.empty()) -	{ -		// Remove session from the map if it should have been there. -		sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle); -		if(iter != mSessionsByHandle.end()) -		{ -			if(iter->second != session) -			{ -				LL_ERRS("Voice") << "Internal error: session mismatch!" << LL_ENDL; -			} - -			mSessionsByHandle.erase(iter); -		} -		else -		{ -			LL_ERRS("Voice") << "Internal error: session handle not found in map!" << LL_ENDL; -		} -	} -			 -	session->mHandle = handle; - -	if(!handle.empty()) -	{ -		mSessionsByHandle.insert(sessionMap::value_type(session->mHandle, session)); -	} - -	verifySessionState(); -} - -void LLVivoxVoiceClient::setSessionURI(sessionState *session, const std::string &uri) -{ -	// There used to be a map of session URIs to sessions, which made this complex.... -	session->mSIPURI = uri; - -	verifySessionState(); -} - -void LLVivoxVoiceClient::deleteSession(sessionState *session) -{ -	// Remove the session from the handle map -	if(!session->mHandle.empty()) -	{ -		sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle); -		if(iter != mSessionsByHandle.end()) -		{ -			if(iter->second != session) -			{ -				LL_ERRS("Voice") << "Internal error: session mismatch" << LL_ENDL; -			} -			mSessionsByHandle.erase(iter); -		} -	} - -	// Remove the session from the URI map -	mSessions.erase(session); -	 -	// At this point, the session should be unhooked from all lists and all state should be consistent. -	verifySessionState(); - -	// If this is the current audio session, clean up the pointer which will soon be dangling. -	if(mAudioSession == session) -	{ -		mAudioSession = NULL; -		mAudioSessionChanged = true; -	} - -	// ditto for the next audio session -	if(mNextAudioSession == session) -	{ -		mNextAudioSession = NULL; -	} - -	// delete the session -	delete session; -} - -void LLVivoxVoiceClient::deleteAllSessions() -{ -	LL_DEBUGS("Voice") << "called" << LL_ENDL; - -	while(!mSessions.empty()) -	{ -		deleteSession(*(sessionsBegin())); -	} -	 -	if(!mSessionsByHandle.empty()) -	{ -		LL_ERRS("Voice") << "Internal error: empty session map, non-empty handle map" << LL_ENDL; -	} -} - -void LLVivoxVoiceClient::verifySessionState(void) -{ -	// This is mostly intended for debugging problems with session state management. -	LL_DEBUGS("Voice") << "Total session count: " << mSessions.size() << " , session handle map size: " << mSessionsByHandle.size() << LL_ENDL; - -	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) -	{ -		sessionState *session = *iter; - -		LL_DEBUGS("Voice") << "session " << session << ": handle " << session->mHandle << ", URI " << session->mSIPURI << LL_ENDL; -		 -		if(!session->mHandle.empty()) -		{ -			// every session with a non-empty handle needs to be in the handle map -			sessionMap::iterator i2 = mSessionsByHandle.find(session->mHandle); -			if(i2 == mSessionsByHandle.end()) -			{ -				LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " not found in session map)" << LL_ENDL; -			} -			else -			{ -				if(i2->second != session) -				{ -					LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " in session map points to another session)" << LL_ENDL; -				} -			} -		} -	} -		 -	// check that every entry in the handle map points to a valid session in the session set -	for(sessionMap::iterator iter = mSessionsByHandle.begin(); iter != mSessionsByHandle.end(); iter++) -	{ -		sessionState *session = iter->second; -		sessionIterator i2 = mSessions.find(session); -		if(i2 == mSessions.end()) -		{ -			LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " not found in session map)" << LL_ENDL; -		} -		else -		{ -			if(session->mHandle != (*i2)->mHandle) -			{ -				LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " points to session with different handle " << (*i2)->mHandle << ")" << LL_ENDL; -			} -		} -	} -} - -LLVivoxVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) : -	mURI(uri) -{ -	mOnlineSL = false; -	mOnlineSLim = false; -	mCanSeeMeOnline = true; -	mHasBlockListEntry = false; -	mHasAutoAcceptListEntry = false; -	mNameResolved = false; -	mInVivoxBuddies = false; -	mInSLFriends = false; -	mNeedsNameUpdate = false; -} - -void LLVivoxVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName) -{ -	buddyListEntry *buddy = addBuddy(uri, displayName); -	buddy->mInVivoxBuddies = true;	 -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::string &uri) -{ -	std::string empty; -	buddyListEntry *buddy = addBuddy(uri, empty); -	if(buddy->mDisplayName.empty()) -	{ -		buddy->mNameResolved = false; -	} -	return buddy; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::string &uri, const std::string &displayName) -{ -	buddyListEntry *result = NULL; -	buddyListMap::iterator iter = mBuddyListMap.find(uri); -	 -	if(iter != mBuddyListMap.end()) -	{ -		// Found a matching buddy already in the map. -		LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL; -		result = iter->second; -	} - -	if(!result) -	{ -		// participant isn't already in one list or the other. -		LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL; -		result = new buddyListEntry(uri); -		result->mDisplayName = displayName; - -		if(IDFromName(uri, result->mUUID))  -		{ -			// Extracted UUID from name successfully. -		} -		else -		{ -			LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL; -		} - -		mBuddyListMap.insert(buddyListMap::value_type(result->mURI, result)); -	} -	 -	return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddy(const std::string &uri) -{ -	buddyListEntry *result = NULL; -	buddyListMap::iterator iter = mBuddyListMap.find(uri); -	if(iter != mBuddyListMap.end()) -	{ -		result = iter->second; -	} -	 -	return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddy(const LLUUID &id) -{ -	buddyListEntry *result = NULL; -	buddyListMap::iterator iter; - -	for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++) -	{ -		if(iter->second->mUUID == id) -		{ -			result = iter->second; -			break; -		} -	} -	 -	return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddyByDisplayName(const std::string &name) -{ -	buddyListEntry *result = NULL; -	buddyListMap::iterator iter; - -	for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++) -	{ -		if(iter->second->mDisplayName == name) -		{ -			result = iter->second; -			break; -		} -	} -	 -	return result; -} - -void LLVivoxVoiceClient::deleteBuddy(const std::string &uri) -{ -	buddyListMap::iterator iter = mBuddyListMap.find(uri); -	if(iter != mBuddyListMap.end()) -	{ -		LL_DEBUGS("Voice") << "deleting buddy " << uri << LL_ENDL; -		buddyListEntry *buddy = iter->second; -		mBuddyListMap.erase(iter); -		delete buddy; -	} -	else -	{ -		LL_DEBUGS("Voice") << "attempt to delete nonexistent buddy " << uri << LL_ENDL; -	} -	 -} - -void LLVivoxVoiceClient::deleteAllBuddies(void) -{ -	while(!mBuddyListMap.empty()) -	{ -		deleteBuddy(mBuddyListMap.begin()->first); -	} -	 -	// Don't want to correlate with friends list when we've emptied the buddy list. -	mBuddyListMapPopulated = false; -	 -	// Don't want to correlate with friends list when we've reset the block rules. -	mBlockRulesListReceived = false; -	mAutoAcceptRulesListReceived = false; -} - -void LLVivoxVoiceClient::deleteAllBlockRules(void) -{ -	// Clear the block list entry flags from all local buddy list entries -	buddyListMap::iterator buddy_it; -	for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) -	{ -		buddy_it->second->mHasBlockListEntry = false; -	} -} - -void LLVivoxVoiceClient::deleteAllAutoAcceptRules(void) -{ -	// Clear the auto-accept list entry flags from all local buddy list entries -	buddyListMap::iterator buddy_it; -	for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) -	{ -		buddy_it->second->mHasAutoAcceptListEntry = false; -	} -} - -void LLVivoxVoiceClient::addBlockRule(const std::string &blockMask, const std::string &presenceOnly) -{ -	buddyListEntry *buddy = NULL; - -	// blockMask is the SIP URI of a friends list entry -	buddyListMap::iterator iter = mBuddyListMap.find(blockMask); -	if(iter != mBuddyListMap.end()) -	{ -		LL_DEBUGS("Voice") << "block list entry for " << blockMask << LL_ENDL; -		buddy = iter->second; -	} - -	if(buddy == NULL) -	{ -		LL_DEBUGS("Voice") << "block list entry for unknown buddy " << blockMask << LL_ENDL; -		buddy = addBuddy(blockMask); -	} -	 -	if(buddy != NULL) -	{ -		buddy->mHasBlockListEntry = true; -	} -} - -void LLVivoxVoiceClient::addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy) -{ -	buddyListEntry *buddy = NULL; - -	// blockMask is the SIP URI of a friends list entry -	buddyListMap::iterator iter = mBuddyListMap.find(autoAcceptMask); -	if(iter != mBuddyListMap.end()) -	{ -		LL_DEBUGS("Voice") << "auto-accept list entry for " << autoAcceptMask << LL_ENDL; -		buddy = iter->second; -	} - -	if(buddy == NULL) -	{ -		LL_DEBUGS("Voice") << "auto-accept list entry for unknown buddy " << autoAcceptMask << LL_ENDL; -		buddy = addBuddy(autoAcceptMask); -	} - -	if(buddy != NULL) -	{ -		buddy->mHasAutoAcceptListEntry = true; -	} -} - -void LLVivoxVoiceClient::accountListBlockRulesResponse(int statusCode, const std::string &statusString) -{ -	// Block list entries were updated via addBlockRule() during parsing.  Just flag that we're done. -	mBlockRulesListReceived = true; -} - -void LLVivoxVoiceClient::accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString) -{ -	// Block list entries were updated via addBlockRule() during parsing.  Just flag that we're done. -	mAutoAcceptRulesListReceived = true; -} - -void LLVivoxVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer) -{ -	mParticipantObservers.insert(observer); -} - -void LLVivoxVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer) -{ -	mParticipantObservers.erase(observer); -} - -void LLVivoxVoiceClient::notifyParticipantObservers() -{ -	for (observer_set_t::iterator it = mParticipantObservers.begin(); -		it != mParticipantObservers.end(); -		) -	{ -		LLVoiceClientParticipantObserver* observer = *it; -		observer->onChange(); -		// In case onChange() deleted an entry. -		it = mParticipantObservers.upper_bound(observer); -	} -} - -void LLVivoxVoiceClient::addObserver(LLVoiceClientStatusObserver* observer) -{ -	mStatusObservers.insert(observer); -} - -void LLVivoxVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer) -{ -	mStatusObservers.erase(observer); -} - -void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status) -{ -	if(mAudioSession) -	{ -		if(status == LLVoiceClientStatusObserver::ERROR_UNKNOWN) -		{ -			switch(mAudioSession->mErrorStatusCode) -			{ -				case 20713:		status = LLVoiceClientStatusObserver::ERROR_CHANNEL_FULL; 		break; -				case 20714:		status = LLVoiceClientStatusObserver::ERROR_CHANNEL_LOCKED; 	break; -				case 20715: -					//invalid channel, we may be using a set of poorly cached -					//info -					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; -					break; -				case 1009: -					//invalid username and password -					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; -					break; -			} - -			// Reset the error code to make sure it won't be reused later by accident. -			mAudioSession->mErrorStatusCode = 0; -		} -		else if(status == LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL) -		{ -			switch(mAudioSession->mErrorStatusCode) -			{ -				case 404:	// NOT_FOUND -				case 480:	// TEMPORARILY_UNAVAILABLE -				case 408:	// REQUEST_TIMEOUT -					// call failed because other user was not available -					// treat this as an error case -					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; - -					// Reset the error code to make sure it won't be reused later by accident. -					mAudioSession->mErrorStatusCode = 0; -				break; -			} -		} -	} -		 -	LL_DEBUGS("Voice")  -		<< " " << LLVoiceClientStatusObserver::status2string(status)   -		<< ", session URI " << getAudioSessionURI()  -		<< (inSpatialChannel()?", proximal is true":", proximal is false") -	<< LL_ENDL; - -	for (status_observer_set_t::iterator it = mStatusObservers.begin(); -		it != mStatusObservers.end(); -		) -	{ -		LLVoiceClientStatusObserver* observer = *it; -		observer->onChange(status, getAudioSessionURI(), inSpatialChannel()); -		// In case onError() deleted an entry. -		it = mStatusObservers.upper_bound(observer); -	} - -} - -void LLVivoxVoiceClient::addObserver(LLFriendObserver* observer) -{ -	mFriendObservers.insert(observer); -} - -void LLVivoxVoiceClient::removeObserver(LLFriendObserver* observer) -{ -	mFriendObservers.erase(observer); -} - -void LLVivoxVoiceClient::notifyFriendObservers() -{ -	for (friend_observer_set_t::iterator it = mFriendObservers.begin(); -		it != mFriendObservers.end(); -		) -	{ -		LLFriendObserver* observer = *it; -		it++; -		// The only friend-related thing we notify on is online/offline transitions. -		observer->changed(LLFriendObserver::ONLINE); -	} -} - -void LLVivoxVoiceClient::lookupName(const LLUUID &id) -{ -	BOOL is_group = FALSE; -	gCacheName->get(id, is_group, &LLVivoxVoiceClient::onAvatarNameLookup); -} - -//static -void LLVivoxVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) -{ -		std::string name = llformat("%s %s", first.c_str(), last.c_str()); -		LLVivoxVoiceClient::getInstance()->avatarNameResolved(id, name); -	 -} - -void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name) -{ -	// If the avatar whose name just resolved is on our friends list, resync the friends list. -	if(LLAvatarTracker::instance().getBuddyInfo(id) != NULL) -	{ -		mFriendsListDirty = true; -	} -	 -	// Iterate over all sessions. -	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) -	{ -		sessionState *session = *iter; - -		// Check for this user as a participant in this session -		participantState *participant = session->findParticipantByID(id); -		if(participant) -		{ -			// Found -- fill in the name -			participant->mAccountName = name; -			// and post a "participants updated" message to listeners later. -			session->mParticipantsChanged = true; -		} -		 -		// Check whether this is a p2p session whose caller name just resolved -		if(session->mCallerID == id) -		{ -			// this session's "caller ID" just resolved.  Fill in the name. -			session->mName = name; -			if(session->mTextInvitePending) -			{ -				session->mTextInvitePending = false; - -				// We don't need to call gIMMgr->addP2PSession() here.  The first incoming message will create the panel.				 -			} -			if(session->mVoiceInvitePending) -			{ -				session->mVoiceInvitePending = false; - -				gIMMgr->inviteToSession( -										LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID), -										session->mName, -										session->mCallerID,  -										session->mName,  -										IM_SESSION_P2P_INVITE,  -										LLIMMgr::INVITATION_TYPE_VOICE, -										session->mHandle); -			} -			 -		} -	} -} - - -LLVivoxProtocolParser::LLVivoxProtocolParser() -{ -	parser = NULL; -	parser = XML_ParserCreate(NULL); -	 -	reset(); -} - -void LLVivoxProtocolParser::reset() -{ -	responseDepth = 0; -	ignoringTags = false; -	accumulateText = false; -	energy = 0.f; -	hasText = false; -	hasAudio = false; -	hasVideo = false; -	terminated = false; -	ignoreDepth = 0; -	isChannel = false; -	incoming = false; -	enabled = false; -	isEvent = false; -	isLocallyMuted = false; -	isModeratorMuted = false; -	isSpeaking = false; -	participantType = 0; -	squelchDebugOutput = false; -	returnCode = -1; -	state = 0; -	statusCode = 0; -	volume = 0; -	textBuffer.clear(); -	alias.clear(); -	numberOfAliases = 0; -	applicationString.clear(); -} - -//virtual  -LLVivoxProtocolParser::~LLVivoxProtocolParser() -{ -	if (parser) -		XML_ParserFree(parser); -} - -// virtual -LLIOPipe::EStatus LLVivoxProtocolParser::process_impl( -													  const LLChannelDescriptors& channels, -													  buffer_ptr_t& buffer, -													  bool& eos, -													  LLSD& context, -													  LLPumpIO* pump) -{ -	LLBufferStream istr(channels, buffer.get()); -	std::ostringstream ostr; -	while (istr.good()) -	{ -		char buf[1024]; -		istr.read(buf, sizeof(buf)); -		mInput.append(buf, istr.gcount()); -	} -	 -	// Look for input delimiter(s) in the input buffer.  If one is found, send the message to the xml parser. -	int start = 0; -	int delim; -	while((delim = mInput.find("\n\n\n", start)) != std::string::npos) -	{	 -		 -		// Reset internal state of the LLVivoxProtocolParser (no effect on the expat parser) -		reset(); -		 -		XML_ParserReset(parser, NULL); -		XML_SetElementHandler(parser, ExpatStartTag, ExpatEndTag); -		XML_SetCharacterDataHandler(parser, ExpatCharHandler); -		XML_SetUserData(parser, this);	 -		XML_Parse(parser, mInput.data() + start, delim - start, false); -		 -		// If this message isn't set to be squelched, output the raw XML received. -		if(!squelchDebugOutput) -		{ -			LL_DEBUGS("Voice") << "parsing: " << mInput.substr(start, delim - start) << LL_ENDL; -		} -		 -		start = delim + 3; -	} -	 -	if(start != 0) -		mInput = mInput.substr(start); -	 -	LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL; -	 -	if(!LLVivoxVoiceClient::getInstance()->mConnected) -	{ -		// If voice has been disabled, we just want to close the socket.  This does so. -		LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL; -		return STATUS_STOP; -	} -	 -	return STATUS_OK; -} - -void XMLCALL LLVivoxProtocolParser::ExpatStartTag(void *data, const char *el, const char **attr) -{ -	if (data) -	{ -		LLVivoxProtocolParser	*object = (LLVivoxProtocolParser*)data; -		object->StartTag(el, attr); -	} -} - -// -------------------------------------------------------------------------------- - -void XMLCALL LLVivoxProtocolParser::ExpatEndTag(void *data, const char *el) -{ -	if (data) -	{ -		LLVivoxProtocolParser	*object = (LLVivoxProtocolParser*)data; -		object->EndTag(el); -	} -} - -// -------------------------------------------------------------------------------- - -void XMLCALL LLVivoxProtocolParser::ExpatCharHandler(void *data, const XML_Char *s, int len) -{ -	if (data) -	{ -		LLVivoxProtocolParser	*object = (LLVivoxProtocolParser*)data; -		object->CharData(s, len); -	} -} - -// -------------------------------------------------------------------------------- - - -void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) -{ -	// Reset the text accumulator. We shouldn't have strings that are inturrupted by new tags -	textBuffer.clear(); -	// only accumulate text if we're not ignoring tags. -	accumulateText = !ignoringTags; -	 -	if (responseDepth == 0) -	{	 -		isEvent = !stricmp("Event", tag); -		 -		if (!stricmp("Response", tag) || isEvent) -		{ -			// Grab the attributes -			while (*attr) -			{ -				const char	*key = *attr++; -				const char	*value = *attr++; -				 -				if (!stricmp("requestId", key)) -				{ -					requestId = value; -				} -				else if (!stricmp("action", key)) -				{ -					actionString = value; -				} -				else if (!stricmp("type", key)) -				{ -					eventTypeString = value; -				} -			} -		} -		LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")"  << LL_ENDL; -	} -	else -	{ -		if (ignoringTags) -		{ -			LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL; -		} -		else -		{ -			LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")"  << LL_ENDL; -			 -			// Ignore the InputXml stuff so we don't get confused -			if (!stricmp("InputXml", tag)) -			{ -				ignoringTags = true; -				ignoreDepth = responseDepth; -				accumulateText = false; -				 -				LL_DEBUGS("VivoxProtocolParser") << "starting ignore, ignoreDepth is " << ignoreDepth << LL_ENDL; -			} -			else if (!stricmp("CaptureDevices", tag)) -			{ -				LLVivoxVoiceClient::getInstance()->clearCaptureDevices(); -			}			 -			else if (!stricmp("RenderDevices", tag)) -			{ -				LLVivoxVoiceClient::getInstance()->clearRenderDevices(); -			} -			else if (!stricmp("CaptureDevice", tag)) -			{ -				deviceString.clear(); -			} -			else if (!stricmp("RenderDevice", tag)) -			{ -				deviceString.clear(); -			}			 -			else if (!stricmp("Buddies", tag)) -			{ -				LLVivoxVoiceClient::getInstance()->deleteAllBuddies(); -			} -			else if (!stricmp("BlockRules", tag)) -			{ -				LLVivoxVoiceClient::getInstance()->deleteAllBlockRules(); -			} -			else if (!stricmp("AutoAcceptRules", tag)) -			{ -				LLVivoxVoiceClient::getInstance()->deleteAllAutoAcceptRules(); -			} -			 -		} -	} -	responseDepth++; -} - -// -------------------------------------------------------------------------------- - -void LLVivoxProtocolParser::EndTag(const char *tag) -{ -	const std::string& string = textBuffer; -	 -	responseDepth--; -	 -	if (ignoringTags) -	{ -		if (ignoreDepth == responseDepth) -		{ -			LL_DEBUGS("VivoxProtocolParser") << "end of ignore" << LL_ENDL; -			ignoringTags = false; -		} -		else -		{ -			LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL; -		} -	} -	 -	if (!ignoringTags) -	{ -		LL_DEBUGS("VivoxProtocolParser") << "processing tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL; -		 -		// Closing a tag. Finalize the text we've accumulated and reset -		if (!stricmp("ReturnCode", tag)) -			returnCode = strtol(string.c_str(), NULL, 10); -		else if (!stricmp("SessionHandle", tag)) -			sessionHandle = string; -		else if (!stricmp("SessionGroupHandle", tag)) -			sessionGroupHandle = string; -		else if (!stricmp("StatusCode", tag)) -			statusCode = strtol(string.c_str(), NULL, 10); -		else if (!stricmp("StatusString", tag)) -			statusString = string; -		else if (!stricmp("ParticipantURI", tag)) -			uriString = string; -		else if (!stricmp("Volume", tag)) -			volume = strtol(string.c_str(), NULL, 10); -		else if (!stricmp("Energy", tag)) -			energy = (F32)strtod(string.c_str(), NULL); -		else if (!stricmp("IsModeratorMuted", tag)) -			isModeratorMuted = !stricmp(string.c_str(), "true"); -		else if (!stricmp("IsSpeaking", tag)) -			isSpeaking = !stricmp(string.c_str(), "true"); -		else if (!stricmp("Alias", tag)) -			alias = string; -		else if (!stricmp("NumberOfAliases", tag)) -			numberOfAliases = strtol(string.c_str(), NULL, 10); -		else if (!stricmp("Application", tag)) -			applicationString = string; -		else if (!stricmp("ConnectorHandle", tag)) -			connectorHandle = string; -		else if (!stricmp("VersionID", tag)) -			versionID = string; -		else if (!stricmp("AccountHandle", tag)) -			accountHandle = string; -		else if (!stricmp("State", tag)) -			state = strtol(string.c_str(), NULL, 10); -		else if (!stricmp("URI", tag)) -			uriString = string; -		else if (!stricmp("IsChannel", tag)) -			isChannel = !stricmp(string.c_str(), "true"); -		else if (!stricmp("Incoming", tag)) -			incoming = !stricmp(string.c_str(), "true"); -		else if (!stricmp("Enabled", tag)) -			enabled = !stricmp(string.c_str(), "true"); -		else if (!stricmp("Name", tag)) -			nameString = string; -		else if (!stricmp("AudioMedia", tag)) -			audioMediaString = string; -		else if (!stricmp("ChannelName", tag)) -			nameString = string; -		else if (!stricmp("DisplayName", tag)) -			displayNameString = string; -		else if (!stricmp("Device", tag)) -			deviceString = string;		 -		else if (!stricmp("AccountName", tag)) -			nameString = string; -		else if (!stricmp("ParticipantType", tag)) -			participantType = strtol(string.c_str(), NULL, 10); -		else if (!stricmp("IsLocallyMuted", tag)) -			isLocallyMuted = !stricmp(string.c_str(), "true"); -		else if (!stricmp("MicEnergy", tag)) -			energy = (F32)strtod(string.c_str(), NULL); -		else if (!stricmp("ChannelName", tag)) -			nameString = string; -		else if (!stricmp("ChannelURI", tag)) -			uriString = string; -		else if (!stricmp("BuddyURI", tag)) -			uriString = string; -		else if (!stricmp("Presence", tag)) -			statusString = string; -		else if (!stricmp("CaptureDevice", tag)) -		{ -			LLVivoxVoiceClient::getInstance()->addCaptureDevice(deviceString); -		} -		else if (!stricmp("RenderDevice", tag)) -		{ -			LLVivoxVoiceClient::getInstance()->addRenderDevice(deviceString); -		} -		else if (!stricmp("Buddy", tag)) -		{ -			LLVivoxVoiceClient::getInstance()->processBuddyListEntry(uriString, displayNameString); -		} -		else if (!stricmp("BlockRule", tag)) -		{ -			LLVivoxVoiceClient::getInstance()->addBlockRule(blockMask, presenceOnly); -		} -		else if (!stricmp("BlockMask", tag)) -			blockMask = string; -		else if (!stricmp("PresenceOnly", tag)) -			presenceOnly = string; -		else if (!stricmp("AutoAcceptRule", tag)) -		{ -			LLVivoxVoiceClient::getInstance()->addAutoAcceptRule(autoAcceptMask, autoAddAsBuddy); -		} -		else if (!stricmp("AutoAcceptMask", tag)) -			autoAcceptMask = string; -		else if (!stricmp("AutoAddAsBuddy", tag)) -			autoAddAsBuddy = string; -		else if (!stricmp("MessageHeader", tag)) -			messageHeader = string; -		else if (!stricmp("MessageBody", tag)) -			messageBody = string; -		else if (!stricmp("NotificationType", tag)) -			notificationType = string; -		else if (!stricmp("HasText", tag)) -			hasText = !stricmp(string.c_str(), "true"); -		else if (!stricmp("HasAudio", tag)) -			hasAudio = !stricmp(string.c_str(), "true"); -		else if (!stricmp("HasVideo", tag)) -			hasVideo = !stricmp(string.c_str(), "true"); -		else if (!stricmp("Terminated", tag)) -			terminated = !stricmp(string.c_str(), "true"); -		else if (!stricmp("SubscriptionHandle", tag)) -			subscriptionHandle = string; -		else if (!stricmp("SubscriptionType", tag)) -			subscriptionType = string; -		 -	 -		textBuffer.clear(); -		accumulateText= false; -		 -		if (responseDepth == 0) -		{ -			// We finished all of the XML, process the data -			processResponse(tag); -		} -	} -} - -// -------------------------------------------------------------------------------- - -void LLVivoxProtocolParser::CharData(const char *buffer, int length) -{ -	/* -	 This method is called for anything that isn't a tag, which can be text you -	 want that lies between tags, and a lot of stuff you don't want like file formatting -	 (tabs, spaces, CR/LF, etc). -	  -	 Only copy text if we are in accumulate mode... -	 */ -	if (accumulateText) -		textBuffer.append(buffer, length); -} - -// -------------------------------------------------------------------------------- - -void LLVivoxProtocolParser::processResponse(std::string tag) -{ -	LL_DEBUGS("VivoxProtocolParser") << tag << LL_ENDL; -	 -	// SLIM SDK: the SDK now returns a statusCode of "200" (OK) for success.  This is a change vs. previous SDKs. -	// According to Mike S., "The actual API convention is that responses with return codes of 0 are successful, regardless of the status code returned", -	// so I believe this will give correct behavior. -	 -	if(returnCode == 0) -		statusCode = 0; -	 -	if (isEvent) -	{ -		const char *eventTypeCstr = eventTypeString.c_str(); -		if (!stricmp(eventTypeCstr, "AccountLoginStateChangeEvent")) -		{ -			LLVivoxVoiceClient::getInstance()->accountLoginStateChangeEvent(accountHandle, statusCode, statusString, state); -		} -		else if (!stricmp(eventTypeCstr, "SessionAddedEvent")) -		{ -			/* -			 <Event type="SessionAddedEvent"> -			 <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> -			 <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle> -			 <Uri>sip:confctl-1408789@bhr.vivox.com</Uri> -			 <IsChannel>true</IsChannel> -			 <Incoming>false</Incoming> -			 <ChannelName /> -			 </Event> -			 */ -			LLVivoxVoiceClient::getInstance()->sessionAddedEvent(uriString, alias, sessionHandle, sessionGroupHandle, isChannel, incoming, nameString, applicationString); -		} -		else if (!stricmp(eventTypeCstr, "SessionRemovedEvent")) -		{ -			LLVivoxVoiceClient::getInstance()->sessionRemovedEvent(sessionHandle, sessionGroupHandle); -		} -		else if (!stricmp(eventTypeCstr, "SessionGroupAddedEvent")) -		{ -			LLVivoxVoiceClient::getInstance()->sessionGroupAddedEvent(sessionGroupHandle); -		} -		else if (!stricmp(eventTypeCstr, "MediaStreamUpdatedEvent")) -		{ -			/* -			 <Event type="MediaStreamUpdatedEvent"> -			 <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> -			 <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle> -			 <StatusCode>200</StatusCode> -			 <StatusString>OK</StatusString> -			 <State>2</State> -			 <Incoming>false</Incoming> -			 </Event> -			 */ -			LLVivoxVoiceClient::getInstance()->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming); -		}		 -		else if (!stricmp(eventTypeCstr, "TextStreamUpdatedEvent")) -		{ -			/* -			 <Event type="TextStreamUpdatedEvent"> -			 <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg1</SessionGroupHandle> -			 <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==1</SessionHandle> -			 <Enabled>true</Enabled> -			 <State>1</State> -			 <Incoming>true</Incoming> -			 </Event> -			 */ -			LLVivoxVoiceClient::getInstance()->textStreamUpdatedEvent(sessionHandle, sessionGroupHandle, enabled, state, incoming); -		} -		else if (!stricmp(eventTypeCstr, "ParticipantAddedEvent")) -		{ -			/*  -			 <Event type="ParticipantAddedEvent"> -			 <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle> -			 <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle> -			 <ParticipantUri>sip:xI5auBZ60SJWIk606-1JGRQ==@bhr.vivox.com</ParticipantUri> -			 <AccountName>xI5auBZ60SJWIk606-1JGRQ==</AccountName> -			 <DisplayName /> -			 <ParticipantType>0</ParticipantType> -			 </Event> -			 */ -			LLVivoxVoiceClient::getInstance()->participantAddedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString, displayNameString, participantType); -		} -		else if (!stricmp(eventTypeCstr, "ParticipantRemovedEvent")) -		{ -			/* -			 <Event type="ParticipantRemovedEvent"> -			 <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle> -			 <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle> -			 <ParticipantUri>sip:xtx7YNV-3SGiG7rA1fo5Ndw==@bhr.vivox.com</ParticipantUri> -			 <AccountName>xtx7YNV-3SGiG7rA1fo5Ndw==</AccountName> -			 </Event> -			 */ -			LLVivoxVoiceClient::getInstance()->participantRemovedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString); -		} -		else if (!stricmp(eventTypeCstr, "ParticipantUpdatedEvent")) -		{ -			/* -			 <Event type="ParticipantUpdatedEvent"> -			 <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> -			 <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle> -			 <ParticipantUri>sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com</ParticipantUri> -			 <IsModeratorMuted>false</IsModeratorMuted> -			 <IsSpeaking>true</IsSpeaking> -			 <Volume>44</Volume> -			 <Energy>0.0879437</Energy> -			 </Event> -			 */ -			 -			// These happen so often that logging them is pretty useless. -			squelchDebugOutput = true; -			 -			LLVivoxVoiceClient::getInstance()->participantUpdatedEvent(sessionHandle, sessionGroupHandle, uriString, alias, isModeratorMuted, isSpeaking, volume, energy); -		} -		else if (!stricmp(eventTypeCstr, "AuxAudioPropertiesEvent")) -		{ -			LLVivoxVoiceClient::getInstance()->auxAudioPropertiesEvent(energy); -		} -		else if (!stricmp(eventTypeCstr, "BuddyPresenceEvent")) -		{ -			LLVivoxVoiceClient::getInstance()->buddyPresenceEvent(uriString, alias, statusString, applicationString); -		} -		else if (!stricmp(eventTypeCstr, "BuddyAndGroupListChangedEvent")) -		{ -			// The buddy list was updated during parsing. -			// Need to recheck against the friends list. -			LLVivoxVoiceClient::getInstance()->buddyListChanged(); -		} -		else if (!stricmp(eventTypeCstr, "BuddyChangedEvent")) -		{ -			/* -			 <Event type="BuddyChangedEvent"> -			 <AccountHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==</AccountHandle> -			 <BuddyURI>sip:x9fFHFZjOTN6OESF1DUPrZQ==@bhr.vivox.com</BuddyURI> -			 <DisplayName>Monroe Tester</DisplayName> -			 <BuddyData /> -			 <GroupID>0</GroupID> -			 <ChangeType>Set</ChangeType> -			 </Event> -			 */		 -			// TODO: Question: Do we need to process this at all? -		} -		else if (!stricmp(eventTypeCstr, "MessageEvent"))   -		{ -			LLVivoxVoiceClient::getInstance()->messageEvent(sessionHandle, uriString, alias, messageHeader, messageBody, applicationString); -		} -		else if (!stricmp(eventTypeCstr, "SessionNotificationEvent"))   -		{ -			LLVivoxVoiceClient::getInstance()->sessionNotificationEvent(sessionHandle, uriString, notificationType); -		} -		else if (!stricmp(eventTypeCstr, "SubscriptionEvent"))   -		{ -			LLVivoxVoiceClient::getInstance()->subscriptionEvent(uriString, subscriptionHandle, alias, displayNameString, applicationString, subscriptionType); -		} -		else if (!stricmp(eventTypeCstr, "SessionUpdatedEvent"))   -		{ -			/* -			 <Event type="SessionUpdatedEvent"> -			 <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> -			 <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle> -			 <Uri>sip:confctl-9@bhd.vivox.com</Uri> -			 <IsMuted>0</IsMuted> -			 <Volume>50</Volume> -			 <TransmitEnabled>1</TransmitEnabled> -			 <IsFocused>0</IsFocused> -			 <SpeakerPosition><Position><X>0</X><Y>0</Y><Z>0</Z></Position></SpeakerPosition> -			 <SessionFontID>0</SessionFontID> -			 </Event> -			 */ -			// We don't need to process this, but we also shouldn't warn on it, since that confuses people. -		} -		 -		else if (!stricmp(eventTypeCstr, "SessionGroupRemovedEvent"))   -		{ -			/* -			 <Event type="SessionGroupRemovedEvent"> -			 <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle> -			 </Event> -			 */ -			// We don't need to process this, but we also shouldn't warn on it, since that confuses people. -		} -		else -		{ -			LL_WARNS("VivoxProtocolParser") << "Unknown event type " << eventTypeString << LL_ENDL; -		} -	} -	else -	{ -		const char *actionCstr = actionString.c_str(); -		if (!stricmp(actionCstr, "Connector.Create.1")) -		{ -			LLVivoxVoiceClient::getInstance()->connectorCreateResponse(statusCode, statusString, connectorHandle, versionID); -		} -		else if (!stricmp(actionCstr, "Account.Login.1")) -		{ -			LLVivoxVoiceClient::getInstance()->loginResponse(statusCode, statusString, accountHandle, numberOfAliases); -		} -		else if (!stricmp(actionCstr, "Session.Create.1")) -		{ -			LLVivoxVoiceClient::getInstance()->sessionCreateResponse(requestId, statusCode, statusString, sessionHandle);			 -		} -		else if (!stricmp(actionCstr, "SessionGroup.AddSession.1")) -		{ -			LLVivoxVoiceClient::getInstance()->sessionGroupAddSessionResponse(requestId, statusCode, statusString, sessionHandle);			 -		} -		else if (!stricmp(actionCstr, "Session.Connect.1")) -		{ -			LLVivoxVoiceClient::getInstance()->sessionConnectResponse(requestId, statusCode, statusString);			 -		} -		else if (!stricmp(actionCstr, "Account.Logout.1")) -		{ -			LLVivoxVoiceClient::getInstance()->logoutResponse(statusCode, statusString);			 -		} -		else if (!stricmp(actionCstr, "Connector.InitiateShutdown.1")) -		{ -			LLVivoxVoiceClient::getInstance()->connectorShutdownResponse(statusCode, statusString);			 -		} -		else if (!stricmp(actionCstr, "Account.ListBlockRules.1")) -		{ -			LLVivoxVoiceClient::getInstance()->accountListBlockRulesResponse(statusCode, statusString);						 -		} -		else if (!stricmp(actionCstr, "Account.ListAutoAcceptRules.1")) -		{ -			LLVivoxVoiceClient::getInstance()->accountListAutoAcceptRulesResponse(statusCode, statusString);						 -		} -		else if (!stricmp(actionCstr, "Session.Set3DPosition.1")) -		{ -			// We don't need to process these, but they're so spammy we don't want to log them. -			squelchDebugOutput = true; -		} -		/* -		 else if (!stricmp(actionCstr, "Account.ChannelGetList.1")) -		 { -		 LLVoiceClient::getInstance()->channelGetListResponse(statusCode, statusString); -		 } -		 else if (!stricmp(actionCstr, "Connector.AccountCreate.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Connector.MuteLocalMic.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Connector.MuteLocalSpeaker.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Connector.SetLocalMicVolume.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Connector.SetLocalSpeakerVolume.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Session.ListenerSetPosition.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Session.SpeakerSetPosition.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Session.AudioSourceSetPosition.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Session.GetChannelParticipants.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelCreate.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelUpdate.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelDelete.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelCreateAndInvite.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelFolderCreate.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelFolderUpdate.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelFolderDelete.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelAddModerator.1")) -		 { -		  -		 } -		 else if (!stricmp(actionCstr, "Account.ChannelDeleteModerator.1")) -		 { -		  -		 } -		 */ -	} -} - diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h deleted file mode 100644 index 10577254e8..0000000000 --- a/indra/newview/llvoicevivox.h +++ /dev/null @@ -1,914 +0,0 @@ -/**  - * @file llvoicevivox.h - * @brief Declaration of LLDiamondwareVoiceClient class which is the interface to the voice client process. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - *  - * Copyright (c) 2001-2010, 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$ - */ -#ifndef LL_VOICE_VIVOX_H -#define LL_VOICE_VIVOX_H - -class LLVOAvatar; -class LLVivoxProtocolParser; - -#include "lliopipe.h" -#include "llpumpio.h" -#include "llchainio.h" -#include "lliosocket.h" -#include "v3math.h" -#include "llframetimer.h" -#include "llviewerregion.h" -#include "llcallingcard.h"   // for LLFriendObserver - -#ifdef LL_STANDALONE -# include "expat.h" -#else -# include "expat/expat.h" -#endif -#include "llvoiceclient.h" - - -class LLVivoxVoiceAccountProvisionResponder; -class LLVivoxVoiceClientMuteListObserver; -class LLVivoxVoiceClientFriendsObserver;	 - - -class LLVivoxVoiceClientParticipantObserver -{ -public: -	virtual ~LLVivoxVoiceClientParticipantObserver() { } -	virtual void onChange() = 0; -}; - - -class LLVivoxVoiceClient: public LLSingleton<LLVivoxVoiceClient>, virtual public LLVoiceModuleInterface -{ -	LOG_CLASS(LLVivoxVoiceClient); -public: -	LLVivoxVoiceClient();	 -	virtual ~LLVivoxVoiceClient(); -	 -	 -	/// @name LLVoiceModuleInterface virtual implementations -	///  @see LLVoiceModuleInterface -	//@{ -	virtual void init(LLPumpIO *pump);	// Call this once at application startup (creates connector) -	virtual void terminate();	// Call this to clean up during shutdown -	 -	virtual const LLVoiceVersionInfo& getVersion(); -	 -	virtual void updateSettings(); // call after loading settings and whenever they change - -	// Returns true if vivox has successfully logged in and is not in error state	 -	virtual bool isVoiceWorking(); - -	///////////////////// -	/// @name Tuning -	//@{ -	virtual void tuningStart(); -	virtual void tuningStop(); -	virtual bool inTuningMode(); -	 -	virtual void tuningSetMicVolume(float volume); -	virtual void tuningSetSpeakerVolume(float volume); -	virtual float tuningGetEnergy(void); -	//@} -	 -	///////////////////// -	/// @name Devices -	//@{ -	// This returns true when it's safe to bring up the "device settings" dialog in the prefs. -	// i.e. when the daemon is running and connected, and the device lists are populated. -	virtual bool deviceSettingsAvailable(); -	 -	// Requery the vivox daemon for the current list of input/output devices. -	// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed -	// (use this if you want to know when it's done). -	// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim. -	virtual void refreshDeviceLists(bool clearCurrentList = true); -	 -	virtual void setCaptureDevice(const std::string& name); -	virtual void setRenderDevice(const std::string& name); -	 -	virtual LLVoiceDeviceList& getCaptureDevices(); -	virtual LLVoiceDeviceList& getRenderDevices(); -	//@}	 -	 -	virtual void getParticipantList(std::set<LLUUID> &participants); -	virtual bool isParticipant(const LLUUID& speaker_id); - -	// Send a text message to the specified user, initiating the session if necessary. -	virtual BOOL sendTextMessage(const LLUUID& participant_id, const std::string& message); -	 -	// close any existing text IM session with the specified user -	virtual void endUserIMSession(const LLUUID &uuid); -	 -	// Returns true if calling back the session URI after the session has closed is possible. -	// Currently this will be false only for PSTN P2P calls.		 -	// NOTE: this will return true if the session can't be found.  -	virtual BOOL isSessionCallBackPossible(const LLUUID &session_id); -	 -	// Returns true if the session can accepte text IM's. -	// Currently this will be false only for PSTN P2P calls. -	// NOTE: this will return true if the session can't be found.  -	virtual BOOL isSessionTextIMPossible(const LLUUID &session_id); -	 -	 -	//////////////////////////// -	/// @name Channel stuff -	//@{ -	// returns true iff the user is currently in a proximal (local spatial) channel. -	// Note that gestures should only fire if this returns true. -	virtual bool inProximalChannel(); -	 -	virtual void setNonSpatialChannel(const std::string &uri, -									  const std::string &credentials); -	 -	virtual void setSpatialChannel(const std::string &uri, -								   const std::string &credentials); -	 -	virtual void leaveNonSpatialChannel(); -	 -	virtual void leaveChannel(void);	 -	 -	// Returns the URI of the current channel, or an empty string if not currently in a channel. -	// NOTE that it will return an empty string if it's in the process of joining a channel. -	virtual std::string getCurrentChannel(); -	//@} -	 -	 -	////////////////////////// -	/// @name invitations -	//@{ -	// start a voice channel with the specified user -	virtual void callUser(const LLUUID &uuid);	 -	virtual bool answerInvite(std::string &channelHandle); -	virtual void declineInvite(std::string &channelHandle); -	//@} -	 -	///////////////////////// -	/// @name Volume/gain -	//@{ -	virtual void setVoiceVolume(F32 volume); -	virtual void setMicGain(F32 volume); -	//@} -	 -	///////////////////////// -	/// @name enable disable voice and features -	//@{ -	virtual bool voiceEnabled(); -	virtual void setVoiceEnabled(bool enabled); -	virtual BOOL lipSyncEnabled();	 -	virtual void setLipSyncEnabled(BOOL enabled); -	virtual void setMuteMic(bool muted);		// Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state. -	//@} -	 -	//////////////////////// -	/// @name PTT -	//@{ -	virtual void setUserPTTState(bool ptt); -	virtual bool getUserPTTState(); -	virtual void setUsePTT(bool usePTT); -	virtual void setPTTIsToggle(bool PTTIsToggle); -	virtual bool getPTTIsToggle(); -	virtual void inputUserControlState(bool down);  // interpret any sort of up-down mic-open control input according to ptt-toggle prefs	 -	virtual void toggleUserPTTState(void); -	 -	virtual void keyDown(KEY key, MASK mask); -	virtual void keyUp(KEY key, MASK mask); -	virtual void middleMouseState(bool down); -	//@} -	 -	////////////////////////// -	/// @name nearby speaker accessors -	//@{ -	virtual BOOL getVoiceEnabled(const LLUUID& id);		// true if we've received data for this avatar -	virtual std::string getDisplayName(const LLUUID& id); -	virtual BOOL isOnlineSIP(const LLUUID &id); -	virtual BOOL isParticipantAvatar(const LLUUID &id); -	virtual BOOL getIsSpeaking(const LLUUID& id); -	virtual BOOL getIsModeratorMuted(const LLUUID& id); -	virtual F32 getCurrentPower(const LLUUID& id);		// "power" is related to "amplitude" in a defined way.  I'm just not sure what the formula is... -	virtual BOOL getOnMuteList(const LLUUID& id); -	virtual F32 getUserVolume(const LLUUID& id); -	virtual void setUserVolume(const LLUUID& id, F32 volume); // set's volume for specified agent, from 0-1 (where .5 is nominal)	 -	//@} -	 -	// authorize the user -	virtual void userAuthorized(const std::string& user_id, -								const LLUUID &agentID); -	 -	////////////////////////////// -	/// @name Status notification -	//@{ -	virtual void addObserver(LLVoiceClientStatusObserver* observer); -	virtual void removeObserver(LLVoiceClientStatusObserver* observer); -	virtual void addObserver(LLFriendObserver* observer); -	virtual void removeObserver(LLFriendObserver* observer);		 -	virtual void addObserver(LLVoiceClientParticipantObserver* observer); -	virtual void removeObserver(LLVoiceClientParticipantObserver* observer); -	 -	 -	 -	//@} -	 -	virtual std::string sipURIFromID(const LLUUID &id); -	//@} - -				 -protected: -	////////////////////// -	// Vivox Specific definitions	 -	 -	friend class LLVivoxVoiceAccountProvisionResponder; -	friend class LLVivoxVoiceClientMuteListObserver; -	friend class LLVivoxVoiceClientFriendsObserver;	 -	 -	enum streamState -	{ -		streamStateUnknown = 0, -		streamStateIdle = 1, -		streamStateConnected = 2, -		streamStateRinging = 3, -	};	 -	struct participantState -	{ -	public: -		participantState(const std::string &uri); -		 -		bool updateMuteState(); -		bool isAvatar(); -		 -		std::string mURI; -		LLUUID mAvatarID; -		std::string mAccountName; -		std::string mDisplayName; -		LLFrameTimer mSpeakingTimeout; -		F32	mLastSpokeTimestamp; -		F32 mPower; -		int mVolume; -		std::string mGroupID; -		int mUserVolume; -		bool mPTT; -		bool mIsSpeaking; -		bool mIsModeratorMuted; -		bool mOnMuteList;		// true if this avatar is on the user's mute list (and should be muted) -		bool mVolumeDirty;		// true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed) -		bool mAvatarIDValid; -		bool mIsSelf; -	}; -	 -	typedef std::map<const std::string, participantState*> participantMap; -	 -	typedef std::map<const LLUUID, participantState*> participantUUIDMap; -	 -	struct sessionState -	{ -	public: -		sessionState(); -		~sessionState(); -		 -		participantState *addParticipant(const std::string &uri); -		// Note: after removeParticipant returns, the participant* that was passed to it will have been deleted. -		// Take care not to use the pointer again after that. -		void removeParticipant(participantState *participant); -		void removeAllParticipants(); -		 -		participantState *findParticipant(const std::string &uri); -		participantState *findParticipantByID(const LLUUID& id); -		 -		bool isCallBackPossible(); -		bool isTextIMPossible(); -		 -		std::string mHandle; -		std::string mGroupHandle; -		std::string mSIPURI; -		std::string mAlias; -		std::string mName; -		std::string mAlternateSIPURI; -		std::string mHash;			// Channel password -		std::string mErrorStatusString; -		std::queue<std::string> mTextMsgQueue; -		 -		LLUUID		mIMSessionID; -		LLUUID		mCallerID; -		int			mErrorStatusCode; -		int			mMediaStreamState; -		int			mTextStreamState; -		bool		mCreateInProgress;	// True if a Session.Create has been sent for this session and no response has been received yet. -		bool		mMediaConnectInProgress;	// True if a Session.MediaConnect has been sent for this session and no response has been received yet. -		bool		mVoiceInvitePending;	// True if a voice invite is pending for this session (usually waiting on a name lookup) -		bool		mTextInvitePending;		// True if a text invite is pending for this session (usually waiting on a name lookup) -		bool		mSynthesizedCallerID;	// True if the caller ID is a hash of the SIP URI -- this means we shouldn't do a name lookup. -		bool		mIsChannel;	// True for both group and spatial channels (false for p2p, PSTN) -		bool		mIsSpatial;	// True for spatial channels -		bool		mIsP2P; -		bool		mIncoming; -		bool		mVoiceEnabled; -		bool		mReconnect;	// Whether we should try to reconnect to this session if it's dropped -		// Set to true when the mute state of someone in the participant list changes. -		// The code will have to walk the list to find the changed participant(s). -		bool		mVolumeDirty; -		 -		bool		mParticipantsChanged; -		participantMap mParticipantsByURI; -		participantUUIDMap mParticipantsByUUID; -	}; - -	// internal state for a simple state machine.  This is used to deal with the asynchronous nature of some of the messages. -	// Note: if you change this list, please make corresponding changes to LLVivoxVoiceClient::state2string(). -	enum state -	{ -		stateDisableCleanup, -		stateDisabled,				// Voice is turned off. -		stateStart,					// Class is initialized, socket is created -		stateDaemonLaunched,		// Daemon has been launched -		stateConnecting,			// connect() call has been issued -		stateConnected,				// connection to the daemon has been made, send some initial setup commands. -		stateIdle,					// socket is connected, ready for messaging -		stateMicTuningStart, -		stateMicTuningRunning,		 -		stateMicTuningStop, -		stateConnectorStart,		// connector needs to be started -		stateConnectorStarting,		// waiting for connector handle -		stateConnectorStarted,		// connector handle received -		stateLoginRetry,			// need to retry login (failed due to changing password) -		stateLoginRetryWait,		// waiting for retry timer -		stateNeedsLogin,			// send login request -		stateLoggingIn,				// waiting for account handle -		stateLoggedIn,				// account handle received -		stateCreatingSessionGroup,	// Creating the main session group -		stateNoChannel,				//  -		stateJoiningSession,		// waiting for session handle -		stateSessionJoined,			// session handle received -		stateRunning,				// in session, steady state -		stateLeavingSession,		// waiting for terminate session response -		stateSessionTerminated,		// waiting for terminate session response -		 -		stateLoggingOut,			// waiting for logout response -		stateLoggedOut,				// logout response received -		stateConnectorStopping,		// waiting for connector stop -		stateConnectorStopped,		// connector stop received -		 -		// We go to this state if the login fails because the account needs to be provisioned. -		 -		// error states.  No way to recover from these yet. -		stateConnectorFailed, -		stateConnectorFailedWaiting, -		stateLoginFailed, -		stateLoginFailedWaiting, -		stateJoinSessionFailed, -		stateJoinSessionFailedWaiting, -		 -		stateJail					// Go here when all else has failed.  Nothing will be retried, we're done. -	}; -	 -	typedef std::map<std::string, sessionState*> sessionMap; -	 -	 -	 -	/////////////////////////////////////////////////////// -	// Private Member Functions -	////////////////////////////////////////////////////// -	 -	////////////////////////////// -	/// @name TVC/Server management and communication -	//@{ -	// Call this if the connection to the daemon terminates unexpectedly.  It will attempt to reset everything and relaunch. -	void daemonDied(); -	 -	// Call this if we're just giving up on voice (can't provision an account, etc.).  It will clean up and go away. -	void giveUp();	 -	 -	// write to the tvc -	bool writeString(const std::string &str); -	 -	void connectorCreate(); -	void connectorShutdown();	 -	void closeSocket(void);	 -	 -	void requestVoiceAccountProvision(S32 retries = 3); -	void login( -			   const std::string& account_name, -			   const std::string& password, -			   const std::string& voice_sip_uri_hostname, -			   const std::string& voice_account_server_uri); -	void loginSendMessage(); -	void logout(); -	void logoutSendMessage();	 -	 -	 -	//@} -	 -	//------------------------------------ -	// tuning -	 -	void tuningRenderStartSendMessage(const std::string& name, bool loop); -	void tuningRenderStopSendMessage(); - -	void tuningCaptureStartSendMessage(int duration); -	void tuningCaptureStopSendMessage(); - -	bool inTuningStates(); - -	//---------------------------------- -	// devices -	void clearCaptureDevices(); -	void addCaptureDevice(const std::string& name); -	void clearRenderDevices(); -	void addRenderDevice(const std::string& name);	 -	void buildSetAudioDevices(std::ostringstream &stream); -	 -	void getCaptureDevicesSendMessage(); -	void getRenderDevicesSendMessage(); -	 -	// local audio updates -	void buildLocalAudioUpdates(std::ostringstream &stream);		 - - -	///////////////////////////// -	// Response/Event handlers -	void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID); -	void loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases); -	void sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle); -	void sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle); -	void sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString); -	void logoutResponse(int statusCode, std::string &statusString); -	void connectorShutdownResponse(int statusCode, std::string &statusString); - -	void accountLoginStateChangeEvent(std::string &accountHandle, int statusCode, std::string &statusString, int state); -	void mediaStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, int statusCode, std::string &statusString, int state, bool incoming); -	void textStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, bool enabled, int state, bool incoming); -	void sessionAddedEvent(std::string &uriString, std::string &alias, std::string &sessionHandle, std::string &sessionGroupHandle, bool isChannel, bool incoming, std::string &nameString, std::string &applicationString); -	void sessionGroupAddedEvent(std::string &sessionGroupHandle); -	void sessionRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle); -	void participantAddedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString, std::string &displayNameString, int participantType); -	void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString); -	void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy); -	void auxAudioPropertiesEvent(F32 energy); -	void buddyPresenceEvent(std::string &uriString, std::string &alias, std::string &statusString, std::string &applicationString); -	void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString); -	void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string ¬ificationType); -	void subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType); -	 -	void buddyListChanged(); -	void muteListChanged(); -	void updateFriends(U32 mask); -		 -	///////////////////////////// -	// Sending updates of current state -	void updatePosition(void); -	void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot); -	void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot); -	bool channelFromRegion(LLViewerRegion *region, std::string &name); - -	void setEarLocation(S32 loc); - -	 -	///////////////////////////// -	// Accessors for data related to nearby speakers - -	// MBW -- XXX -- Not sure how to get this data out of the TVC -	BOOL getUsingPTT(const LLUUID& id); -	std::string getGroupID(const LLUUID& id);		// group ID if the user is in group chat (empty string if not applicable) - -	///////////////////////////// -	BOOL getAreaVoiceDisabled();		// returns true if the area the avatar is in is speech-disabled. -										// Use this to determine whether to show a "no speech" icon in the menu bar. -		 -	 -	// PTT -	void setPTTKey(std::string &key); -	 -	///////////////////////////// -	// Recording controls -	void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200); -	void recordingLoopSave(const std::string& filename); -	void recordingStop(); -	 -	// Playback controls -	void filePlaybackStart(const std::string& filename); -	void filePlaybackStop(); -	void filePlaybackSetPaused(bool paused); -	void filePlaybackSetMode(bool vox = false, float speed = 1.0f); -	 -	participantState *findParticipantByID(const LLUUID& id); -	 - -	//////////////////////////////////////// -	// voice sessions. -	typedef std::set<sessionState*> sessionSet; -			 -	typedef sessionSet::iterator sessionIterator; -	sessionIterator sessionsBegin(void); -	sessionIterator sessionsEnd(void); - -	sessionState *findSession(const std::string &handle); -	sessionState *findSessionBeingCreatedByURI(const std::string &uri); -	sessionState *findSession(const LLUUID &participant_id); -	sessionState *findSessionByCreateID(const std::string &create_id); -	 -	sessionState *addSession(const std::string &uri, const std::string &handle = LLStringUtil::null); -	void setSessionHandle(sessionState *session, const std::string &handle = LLStringUtil::null); -	void setSessionURI(sessionState *session, const std::string &uri); -	void deleteSession(sessionState *session); -	void deleteAllSessions(void); - -	void verifySessionState(void); - -	void joinedAudioSession(sessionState *session); -	void leftAudioSession(sessionState *session); - -	// This is called in several places where the session _may_ need to be deleted. -	// It contains logic for whether to delete the session or keep it around. -	void reapSession(sessionState *session); -	 -	// Returns true if the session seems to indicate we've moved to a region on a different voice server -	bool sessionNeedsRelog(sessionState *session); -	 -	 -	////////////////////////////////////// -	// buddy list stuff, needed for SLIM later -	struct buddyListEntry -	{ -		buddyListEntry(const std::string &uri); -		std::string mURI; -		std::string mDisplayName; -		LLUUID	mUUID; -		bool mOnlineSL; -		bool mOnlineSLim; -		bool mCanSeeMeOnline; -		bool mHasBlockListEntry; -		bool mHasAutoAcceptListEntry; -		bool mNameResolved; -		bool mInSLFriends; -		bool mInVivoxBuddies; -		bool mNeedsNameUpdate; -	}; - -	typedef std::map<std::string, buddyListEntry*> buddyListMap; -	 -	// This should be called when parsing a buddy list entry sent by SLVoice.		 -	void processBuddyListEntry(const std::string &uri, const std::string &displayName); - -	buddyListEntry *addBuddy(const std::string &uri); -	buddyListEntry *addBuddy(const std::string &uri, const std::string &displayName); -	buddyListEntry *findBuddy(const std::string &uri); -	buddyListEntry *findBuddy(const LLUUID &id); -	buddyListEntry *findBuddyByDisplayName(const std::string &name); -	void deleteBuddy(const std::string &uri); -	void deleteAllBuddies(void); - -	void deleteAllBlockRules(void); -	void addBlockRule(const std::string &blockMask, const std::string &presenceOnly); -	void deleteAllAutoAcceptRules(void); -	void addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy); -	void accountListBlockRulesResponse(int statusCode, const std::string &statusString);						 -	void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString);						 -	 -	///////////////////////////// -	// session control messages - -	void accountListBlockRulesSendMessage(); -	void accountListAutoAcceptRulesSendMessage(); -	 -	void sessionGroupCreateSendMessage(); -	void sessionCreateSendMessage(sessionState *session, bool startAudio = true, bool startText = false); -	void sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio = true, bool startText = false); -	void sessionMediaConnectSendMessage(sessionState *session);		// just joins the audio session -	void sessionTextConnectSendMessage(sessionState *session);		// just joins the text session -	void sessionTerminateSendMessage(sessionState *session); -	void sessionGroupTerminateSendMessage(sessionState *session); -	void sessionMediaDisconnectSendMessage(sessionState *session); -	void sessionTextDisconnectSendMessage(sessionState *session); - -	// Pokes the state machine to leave the audio session next time around. -	void sessionTerminate();	 -	 -	// Pokes the state machine to shut down the connector and restart it. -	void requestRelog(); -	 -	// Does the actual work to get out of the audio session -	void leaveAudioSession(); -	 -	void lookupName(const LLUUID &id); -	static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); -	void avatarNameResolved(const LLUUID &id, const std::string &name); -		 -private: -	LLVoiceVersionInfo mVoiceVersion; -		 -	state mState; -	bool mSessionTerminateRequested; -	bool mRelogRequested; -	// Number of times (in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine(). -	// The larger it is the greater is possibility there is a problem with connection to voice server. -	// Introduced while fixing EXT-4313. -	int mSpatialJoiningNum; -	 -	void setState(state inState); -	state getState(void)  { return mState; }; -	std::string state2string(state inState); -	 -	void stateMachine(); -	static void idle(void *user_data); -	 -	LLHost mDaemonHost; -	LLSocket::ptr_t mSocket; -	bool mConnected; -	 -	 -	LLPumpIO *mPump; -	friend class LLVivoxProtocolParser; -	 -	std::string mAccountName; -	std::string mAccountPassword; -	std::string mAccountDisplayName; -			 -	bool mTuningMode; -	float mTuningEnergy; -	std::string mTuningAudioFile; -	int mTuningMicVolume; -	bool mTuningMicVolumeDirty; -	int mTuningSpeakerVolume; -	bool mTuningSpeakerVolumeDirty; -	state mTuningExitState;					// state to return to when we leave tuning mode. -	 -	std::string mSpatialSessionURI; -	std::string mSpatialSessionCredentials; - -	std::string mMainSessionGroupHandle; // handle of the "main" session group. -	 -	std::string mChannelName;			// Name of the channel to be looked up  -	bool mAreaVoiceDisabled; -	sessionState *mAudioSession;		// Session state for the current audio session -	bool mAudioSessionChanged;			// set to true when the above pointer gets changed, so observers can be notified. - -	sessionState *mNextAudioSession;	// Session state for the audio session we're trying to join - -//		std::string mSessionURI;			// URI of the session we're in. -//		std::string mSessionHandle;		// returned by ? -	 -	S32 mCurrentParcelLocalID;			// Used to detect parcel boundary crossings -	std::string mCurrentRegionName;		// Used to detect parcel boundary crossings -	 -	std::string mConnectorHandle;	// returned by "Create Connector" message -	std::string mAccountHandle;		// returned by login message		 -	int 		mNumberOfAliases; -	U32 mCommandCookie; - -	std::string mVoiceAccountServerURI; -	std::string mVoiceSIPURIHostName; -	 -	int mLoginRetryCount; -	 -	sessionMap mSessionsByHandle;				// Active sessions, indexed by session handle.  Sessions which are being initiated may not be in this map. -	sessionSet mSessions;						// All sessions, not indexed.  This is the canonical session list. -	 -	bool mBuddyListMapPopulated; -	bool mBlockRulesListReceived; -	bool mAutoAcceptRulesListReceived; -	buddyListMap mBuddyListMap; -	 -	LLVoiceDeviceList mCaptureDevices; -	LLVoiceDeviceList mRenderDevices; - -	std::string mCaptureDevice; -	std::string mRenderDevice; -	bool mCaptureDeviceDirty; -	bool mRenderDeviceDirty; -	 -	// This should be called when the code detects we have changed parcels. -	// It initiates the call to the server that gets the parcel channel. -	void parcelChanged(); -	 -	void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = ""); -	void joinSession(sessionState *session); -	 -	std::string nameFromAvatar(LLVOAvatar *avatar); -	std::string nameFromID(const LLUUID &id); -	bool IDFromName(const std::string name, LLUUID &uuid); -	std::string displayNameFromAvatar(LLVOAvatar *avatar); -	std::string sipURIFromAvatar(LLVOAvatar *avatar); -	std::string sipURIFromName(std::string &name); -	 -	// Returns the name portion of the SIP URI if the string looks vaguely like a SIP URI, or an empty string if not. -	std::string nameFromsipURI(const std::string &uri);		 - -	bool inSpatialChannel(void); -	std::string getAudioSessionURI(); -	std::string getAudioSessionHandle(); -			 -	void sendPositionalUpdate(void); -	 -	void buildSetCaptureDevice(std::ostringstream &stream); -	void buildSetRenderDevice(std::ostringstream &stream); -	 -	void clearAllLists(); -	void checkFriend(const LLUUID& id); -	void sendFriendsListUpdates(); - -	// start a text IM session with the specified user -	// This will be asynchronous, the session may be established at a future time. -	sessionState* startUserIMSession(const LLUUID& uuid); -	void sendQueuedTextMessages(sessionState *session); -	 -	void enforceTether(void); -	 -	bool		mSpatialCoordsDirty; -	 -	LLVector3d	mCameraPosition; -	LLVector3d	mCameraRequestedPosition; -	LLVector3	mCameraVelocity; -	LLMatrix3	mCameraRot; - -	LLVector3d	mAvatarPosition; -	LLVector3	mAvatarVelocity; -	LLMatrix3	mAvatarRot; -	 -	bool		mPTTDirty; -	bool		mPTT; -	 -	bool		mUsePTT; -	bool		mPTTIsMiddleMouse; -	KEY			mPTTKey; -	bool		mPTTIsToggle; -	bool		mUserPTTState; -	bool		mMuteMic; -			 -	// Set to true when the friends list is known to have changed. -	bool		mFriendsListDirty; -	 -	enum -	{ -		earLocCamera = 0,		// ear at camera -		earLocAvatar,			// ear at avatar -		earLocMixed				// ear at avatar location/camera direction -	}; -	 -	S32			mEarLocation;   -	 -	bool		mSpeakerVolumeDirty; -	bool		mSpeakerMuteDirty; -	int			mSpeakerVolume; - -	int			mMicVolume; -	bool		mMicVolumeDirty; -	 -	bool		mVoiceEnabled; -	bool		mWriteInProgress; -	std::string mWriteString; -	size_t		mWriteOffset; -	 -	LLTimer		mUpdateTimer; -	 -	BOOL		mLipSyncEnabled; - -	typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t; -	observer_set_t mParticipantObservers; - -	void notifyParticipantObservers(); - -	typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t; -	status_observer_set_t mStatusObservers; -	 -	void notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status); - -	typedef std::set<LLFriendObserver*> friend_observer_set_t; -	friend_observer_set_t mFriendObservers; -	void notifyFriendObservers(); -}; - -/**  - * @class LLVivoxProtocolParser - * @brief This class helps construct new LLIOPipe specializations - * @see LLIOPipe - * - * THOROUGH_DESCRIPTION - */ -class LLVivoxProtocolParser : public LLIOPipe -{ -	LOG_CLASS(LLVivoxProtocolParser); -public: -	LLVivoxProtocolParser(); -	virtual ~LLVivoxProtocolParser(); -	 -protected: -	/* @name LLIOPipe virtual implementations -	 */ -	//@{ -	/**  -	 * @brief Process the data in buffer -	 */ -	virtual EStatus process_impl( -								 const LLChannelDescriptors& channels, -								 buffer_ptr_t& buffer, -								 bool& eos, -								 LLSD& context, -								 LLPumpIO* pump); -	//@} -	 -	std::string 	mInput; -	 -	// Expat control members -	XML_Parser		parser; -	int				responseDepth; -	bool			ignoringTags; -	bool			isEvent; -	int				ignoreDepth; -	 -	// Members for processing responses. The values are transient and only valid within a call to processResponse(). -	bool			squelchDebugOutput; -	int				returnCode; -	int				statusCode; -	std::string		statusString; -	std::string		requestId; -	std::string		actionString; -	std::string		connectorHandle; -	std::string		versionID; -	std::string		accountHandle; -	std::string		sessionHandle; -	std::string		sessionGroupHandle; -	std::string		alias; -	std::string		applicationString; -	 -	// Members for processing events. The values are transient and only valid within a call to processResponse(). -	std::string		eventTypeString; -	int				state; -	std::string		uriString; -	bool			isChannel; -	bool			incoming; -	bool			enabled; -	std::string		nameString; -	std::string		audioMediaString; -	std::string     deviceString; -	std::string		displayNameString; -	int				participantType; -	bool			isLocallyMuted; -	bool			isModeratorMuted; -	bool			isSpeaking; -	int				volume; -	F32				energy; -	std::string		messageHeader; -	std::string		messageBody; -	std::string		notificationType; -	bool			hasText; -	bool			hasAudio; -	bool			hasVideo; -	bool			terminated; -	std::string		blockMask; -	std::string		presenceOnly; -	std::string		autoAcceptMask; -	std::string		autoAddAsBuddy; -	int				numberOfAliases; -	std::string		subscriptionHandle; -	std::string		subscriptionType; -	 -	 -	// Members for processing text between tags -	std::string		textBuffer; -	bool			accumulateText; -	 -	void			reset(); -	 -	void			processResponse(std::string tag); -	 -	static void XMLCALL ExpatStartTag(void *data, const char *el, const char **attr); -	static void XMLCALL ExpatEndTag(void *data, const char *el); -	static void XMLCALL ExpatCharHandler(void *data, const XML_Char *s, int len); -	 -	void			StartTag(const char *tag, const char **attr); -	void			EndTag(const char *tag); -	void			CharData(const char *buffer, int length); -	 -}; - - -#endif //LL_VIVOX_VOICE_CLIENT_H - - - diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index aa03b1afd1..1a64f9d881 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -155,7 +155,7 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url,  	substitution["VERSION_PATCH"] = LLVersionInfo::getPatch();  	substitution["VERSION_BUILD"] = LLVersionInfo::getBuild();  	substitution["CHANNEL"] = LLVersionInfo::getChannel(); -	substitution["GRID"] = LLGridManager::getInstance()->getGridLabel(); +	substitution["GRID"] = LLViewerLogin::getInstance()->getGridLabel();  	substitution["OS"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple();  	substitution["SESSION_ID"] = gAgent.getSessionID();  	substitution["FIRST_LOGIN"] = gAgent.isFirstLogin(); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 58b9f5ce18..0b63f5efbd 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -133,11 +133,10 @@ void LLWorld::destroyClass()  LLViewerRegion* LLWorld::addRegion(const U64 ®ion_handle, const LLHost &host)  {  	LLMemType mt(LLMemType::MTYPE_REGIONS); -	llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl; +	  	LLViewerRegion *regionp = getRegionFromHandle(region_handle);  	if (regionp)  	{ -		llinfos << "Region exists, removing it " << llendl;  		LLHost old_host = regionp->getHost();  		// region already exists!  		if (host == old_host && regionp->isAlive()) diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 8237132ac5..15417614af 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -28,7 +28,6 @@  #include "llerror.h"  #include "stringize.h"  #include "llxmlrpctransaction.h" -#include "llsecapi.h"  #if LL_WINDOWS  #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally @@ -357,22 +356,7 @@ public:                                       << data["errorcode"].asString()                                       << " (" << data["error"].asString() << ")"                                       << LL_ENDL; -		 -		switch (curlcode) -		{ -			case CURLE_SSL_PEER_CERTIFICATE: -			case CURLE_SSL_CACERT: -			{ -				LLPointer<LLCertificate> error_cert(mTransaction->getErrorCert()); -				if(error_cert) -				{ -					data["certificate"] = error_cert->getPem(); -				} -				break; -			} -			default: -				break; -		} +        // In addition to CURLE_OK, LLUserAuth distinguishes different error          // values of 'curlcode':          // CURLE_COULDNT_RESOLVE_HOST,          // CURLE_SSL_PEER_CERTIFICATE, diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index d75c8ff1fb..5884cdd1c3 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -31,9 +31,6 @@   */  #include "llviewerprecompiledheaders.h" -#include <openssl/x509_vfy.h> -#include <openssl/ssl.h> -#include "llsecapi.h"  #include "llxmlrpctransaction.h"  #include "llxmlrpclistener.h" @@ -179,8 +176,6 @@ public:  	std::string			mResponseText;  	XMLRPC_REQUEST		mResponse; -	std::string         mCertStore; -	LLPointer<LLCertificate> mErrorCert;  	Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip);  	Impl(const std::string& uri, @@ -195,8 +190,7 @@ public:  private:  	void init(XMLRPC_REQUEST request, bool useGzip); -	static int _sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param); -	static CURLcode _sslCtxFunction(CURL * curl, void *sslctx, void *param); +  	static size_t curlDownloadCallback(  		char* data, size_t size, size_t nmemb, void* user_data);  }; @@ -234,74 +228,8 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,      XMLRPC_RequestFree(request, 1);  } -// _sslCertVerifyCallback -// callback called when a cert verification is requested. -// calls SECAPI to validate the context -int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param) -{ -	LLXMLRPCTransaction::Impl *transaction = (LLXMLRPCTransaction::Impl *)param; -	LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(transaction->mCertStore); -	LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); -	LLSD validation_params = LLSD::emptyMap(); -	LLURI uri(transaction->mURI); -	validation_params[CERT_HOSTNAME] = uri.hostName(); -	try -	{ -		chain->validate(VALIDATION_POLICY_SSL, store, validation_params); -	} -	catch (LLCertValidationTrustException& cert_exception) -	{ -		// this exception is is handled differently than the general cert -		// exceptions, as we allow the user to actually add the certificate -		// for trust. -		// therefore we pass back a different error code -		// NOTE: We're currently 'wired' to pass around CURL error codes.  This is -		// somewhat clumsy, as we may run into errors that do not map directly to curl -		// error codes.  Should be refactored with login refactoring, perhaps. -		transaction->mCurlCode = CURLE_SSL_CACERT; -		// set the status directly.  set curl status generates error messages and we want -		// to use the fixed ones from the exceptions -		transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string()); -		// We should probably have a more generic way of passing information -		// back to the error handlers. -		transaction->mErrorCert = cert_exception.getCert(); -		return 0;		 -	} -	catch (LLCertException& cert_exception) -	{ -		transaction->mCurlCode = CURLE_SSL_PEER_CERTIFICATE; -		// set the status directly.  set curl status generates error messages and we want -		// to use the fixed ones from the exceptions -		transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string()); -		transaction->mErrorCert = cert_exception.getCert(); -		return 0; -	} -	catch (...) -	{ -		// any other odd error, we just handle as a connect error. -		transaction->mCurlCode = CURLE_SSL_CONNECT_ERROR; -		transaction->setCurlStatus(CURLE_SSL_CONNECT_ERROR); -		return 0; -	} -	return 1; -} -// _sslCtxFunction -// Callback function called when an SSL Context is created via CURL -// used to configure the context for custom cert validate(<, <#const & xs#>, <#T * #>, <#long #>)tion -// based on SECAPI -CURLcode LLXMLRPCTransaction::Impl::_sslCtxFunction(CURL * curl, void *sslctx, void *param) -{ -	SSL_CTX * ctx = (SSL_CTX *) sslctx; -	// disable any default verification for server certs -	SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); -	// set the verification callback. -	SSL_CTX_set_cert_verify_callback(ctx, _sslCertVerifyCallback, param); -	// the calls are void -	return CURLE_OK; -	 -}  void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)  { @@ -309,7 +237,6 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)  	{  		mCurlRequest = new LLCurlEasyRequest();  	} -	mErrorCert = NULL;  	if (gSavedSettings.getBOOL("BrowserProxyEnabled"))  	{ @@ -326,12 +253,11 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)  	mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);  	mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this);  	BOOL verifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); -	mCertStore = gSavedSettings.getString("CertStore"); +	mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify() ? 2 : 0);  	mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, verifySSLCert);  	mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, verifySSLCert ? 2 : 0);  	// Be a little impatient about establishing connections.  	mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L); -	mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this);  	/* Setting the DNS cache timeout to -1 disables it completely.  	   This might help with bug #503 */ @@ -417,19 +343,11 @@ bool LLXMLRPCTransaction::Impl::process()  		{  			if (result != CURLE_OK)  			{ -				if ((result != CURLE_SSL_PEER_CERTIFICATE) && -					(result != CURLE_SSL_CACERT)) -				{ -					// if we have a curl error that's not already been handled -					// (a non cert error), then generate the error message as -					// appropriate -					setCurlStatus(result); -				 -					llwarns << "LLXMLRPCTransaction CURL error " -					<< mCurlCode << ": " << mCurlRequest->getErrorString() << llendl; -					llwarns << "LLXMLRPCTransaction request URI: " -					<< mURI << llendl; -				} +				setCurlStatus(result); +				llwarns << "LLXMLRPCTransaction CURL error " +						<< mCurlCode << ": " << mCurlRequest->getErrorString() << llendl; +				llwarns << "LLXMLRPCTransaction request URI: " +						<< mURI << llendl;  				return true;  			} @@ -507,6 +425,7 @@ void LLXMLRPCTransaction::Impl::setStatus(EStatus status,  			case StatusComplete:  				mStatusMessage = "(done)";  				break; +				  			default:  				// Usually this means that there's a problem with the login server,  				// not with the client.  Direct user to status page. @@ -622,11 +541,6 @@ std::string LLXMLRPCTransaction::statusMessage()  	return impl.mStatusMessage;  } -LLPointer<LLCertificate> LLXMLRPCTransaction::getErrorCert() -{ -	return impl.mErrorCert; -} -  std::string LLXMLRPCTransaction::statusURI()  {  	return impl.mStatusURI; diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h index 8beb2e2623..c835423d67 100644 --- a/indra/newview/llxmlrpctransaction.h +++ b/indra/newview/llxmlrpctransaction.h @@ -38,7 +38,6 @@  typedef struct _xmlrpc_request* XMLRPC_REQUEST;  typedef struct _xmlrpc_value* XMLRPC_VALUE;  	// foward decl of types from xmlrpc.h (this usage is type safe) -class LLCertificate;  class LLXMLRPCValue  	// a c++ wrapper around XMLRPC_VALUE @@ -116,8 +115,6 @@ public:  	EStatus status(int* curlCode);  		// return status, and extended CURL code, if code isn't null -	 -	LLPointer<LLCertificate> getErrorCert();  	std::string statusMessage();  		// return a message string, suitable for showing the user  	std::string statusURI(); diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index b5be03346e..a6a4c79da4 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -49,7 +49,7 @@ libcurl Version: [LIBCURL_VERSION]  J2C Decoder Version: [J2C_VERSION]  Audio Driver Version: [AUDIO_DRIVER_VERSION]  Qt Webkit Version: [QT_WEBKIT_VERSION] -Voice Server Version: [VOICE_VERSION] +Vivox Version: [VIVOX_VERSION]  </floater.string>    <floater.string       name="none"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index c42b846dbb..e8ba8c683d 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1384,18 +1384,6 @@ Unable to encode file: [FILE]    <notification     icon="alertmodal.tga" -   name="CorruptedProtectedDataStore" -   type="alertmodal"> -  We are unable to read your protected data so it is being reset. -   This may happen when you change network setup. - -    <usetemplate -     name="okbutton" -     yestext="OK"/> -  </notification> -     -  <notification -   icon="alertmodal.tga"     name="CorruptResourceFile"     type="alertmodal">  Corrupt resource file: [FILE] @@ -2429,57 +2417,6 @@ Please choose the male or female avatar. You can change your mind later.       notext="Female"       yestext="Male"/>    </notification> -  <notification icon="alertmodal.tga" -		name="CantTeleportToGrid" -		type="alertmodal"> -Could not teleport to [SLURL] as it's on a different grid ([GRID]) than the current grid ([CURRENT_GRID]).  Please close your viewer and try again. -    <usetemplate -     name="okbutton" -     yestext="OK"/> -  </notification> - -  <notification icon="alertmodal.tga" -		name="GeneralCertificateError" -		type="alertmodal"> -Could not connect to the server. -[REASON] - -SubjectName: [SUBJECT_NAME_STRING] -IssuerName: [ISSUER_NAME_STRING] -Valid From: [VALID_FROM] -Valid To: [VALID_TO] -MD5 Fingerprint: [SHA1_DIGEST] -SHA1 Fingerprint: [MD5_DIGEST] -Key Usage: [KEYUSAGE] -Extended Key Usage: [EXTENDEDKEYUSAGE] -Subject Key Identifier: [SUBJECTKEYIDENTIFIER] -    <usetemplate -     name="okbutton" -     yestext="OK"/> -   </notification> - -  <notification icon="alertmodal.tga" -		name="TrustCertificateError" -		type="alertmodal"> -The certification authority for this server is not known. - -Certificate Information: -SubjectName: [SUBJECT_NAME_STRING] -IssuerName: [ISSUER_NAME_STRING] -Valid From: [VALID_FROM] -Valid To: [VALID_TO] -MD5 Fingerprint: [SHA1_DIGEST] -SHA1 Fingerprint: [MD5_DIGEST] -Key Usage: [KEYUSAGE] -Extended Key Usage: [EXTENDEDKEYUSAGE] -Subject Key Identifier: [SUBJECTKEYIDENTIFIER] - -Would you like to trust this authority? -    <usetemplate -     name="okcancelbuttons" -     notext="Cancel" -     yestext="Trust"/> -  </notification>    <notification     icon="alertmodal.tga" diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 539c5f785c..01adc00e1a 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -48,31 +48,50 @@ auto_resize="false"  follows="left|bottom"  name="login"  layout="topleft" -width="850" -min_width="850" +width="695" +min_width="695"  user_resize="false"  height="80">  <text  follows="left|bottom"  font="SansSerifSmall"  height="16" -name="username_text" +name="first_name_text"  top="20"  left="20"  width="150"> -Username: +First name:  </text>  <line_editor  follows="left|bottom"  height="22" -label="Username" +label="First"  left_delta="0"  max_length="31" -name="username_edit" +name="first_name_edit"  select_on_focus="true" -tool_tip="[SECOND_LIFE] Username" +tool_tip="[SECOND_LIFE] First Name"  top_pad="0" -width="150" /> +   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" +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" />  <text  follows="left|bottom"  font="SansSerifSmall" @@ -80,7 +99,7 @@ height="15"  left_pad="8"  name="password_text"  top="20" -    width="135"> +    width="150">         Password:  </text>  <line_editor @@ -100,14 +119,26 @@ label="Remember password"    top_pad="3"    name="remember_check"   width="135" /> +<button +  follows="left|bottom" +  height="23" +  image_unselected="PushButton_On" +  image_selected="PushButton_On_Selected" +  label="Log In" +  label_color="White" +  layout="topleft" +  left_pad="10" +  name="connect_btn" +  top="35" +  width="90" />    <text    follows="left|bottom"    font="SansSerifSmall"    height="15" -  left_pad="10" +  left_pad="18"    name="start_location_text"  top="20" -  width="250"> +  width="130">         Start at:   </text>  <combo_box @@ -118,7 +149,7 @@ control_name="LoginLocation"  max_chars="128"  top_pad="0"  name="start_location_combo" -     width="250"> +     width="135">  <combo_box.item  label="My last location"  name="MyLastLocation" @@ -131,37 +162,16 @@ name="MyHome"  label="<Type region name>"  name="Typeregionname"   value="" />  </combo_box> -<button -  height="23" -  image_unselected="PushButton_On" -  image_selected="PushButton_On_Selected" -  label="Log In" -  label_color="White" -  layout="topleft" -  left_pad="10" -  name="connect_btn" -  top="35" -  width="90" /> -  <text -  follows="left|bottom" -  font="SansSerifSmall" -  height="15" -  left_pad="10" -  name="start_location_text" -top="20" -  width="150"> -       Grid Name: - </text>  <combo_box -follows="left|bottom"  allow_text_entry="true"  font="SansSerifSmall" -height="23" +   follows="left|right|bottom" +   height="23" +layout="topleft" +top_pad="2"  name="server_combo" -top_pad="0" -width="150" -max_chars="255" -visible="false" /> +width="135" +  visible="false" />  </layout_panel>  <layout_panel  follows="right|bottom" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 9ac4ef9b37..0c73b8d769 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -46,15 +46,6 @@  	<string name="LoginWaitingForRegionHandshake">Waiting for region handshake...</string>  	<string name="LoginConnectingToRegion">Connecting to region...</string>  	<string name="LoginDownloadingClothing">Downloading clothing...</string> -        <string name="InvalidCertificate">The server returned an invalid or corrupt certificate. Please contact the Grid administrator.</string> -        <string name="CertInvalidHostname">An invalid hostname was used to access the server, please check your SLURL or Grid hostname.</string> -        <string name="CertExpired">The certificate returned by the Grid appears to be expired.  Please check your system clock, or contact your Grid administr\ -ator.</string> -        <string name="CertKeyUsage">The certificate returned by the server could not be used for SSL.  Please contact your Grid administrator.</string> -        <string name="CertBasicConstraints">Too many certificates were in the servers Certificate chain.  Please contact your Grid administrator.</string> -        <string name="CertInvalidSignature">The certificate signature returned by the Grid server could not be verified.  Please contact your Grid administrat -or.</string> -  	<string name="LoginFailedNoNetwork">Network Error: Could not establish connection, please check your network connection.</string>  	<string name="LoginFailed">Login failed.</string>  	<string name="Quit">Quit</string> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 67da9f2cdf..ef93586c6e 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -10,10 +10,7 @@  // Precompiled header  #include "../llviewerprecompiledheaders.h"  // Own header -#include "../llsecapi.h" -#include "../llviewernetwork.h"  #include "../lllogininstance.h" -  // STL headers  // std headers  // external library headers @@ -36,12 +33,7 @@ const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno");  //-----------------------------------------------------------------------------  static LLEventStream gTestPump("test_pump"); -#include "../llslurl.h" -#include "../llstartup.h" -LLSLURL LLStartUp::sStartSLURL; -  #include "lllogin.h" -  static std::string gLoginURI;  static LLSD gLoginCreds;  static bool gDisconnectCalled = false; @@ -62,68 +54,17 @@ 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" -LLGridManager::~LLGridManager() -{ -} - -void LLGridManager::addGrid(LLSD& grid_data) -{ -} -LLGridManager::LLGridManager() -{	 -} +unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {'1','2','3','4','5','6'}; -void LLGridManager::getLoginURIs(std::vector<std::string>& uris) +LLViewerLogin::LLViewerLogin() : mGridChoice(GRID_INFO_NONE) {} +LLViewerLogin::~LLViewerLogin() {} +void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const   {  	uris.push_back(VIEWERLOGIN_URI);  } - -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"; -} +std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; }  //-----------------------------------------------------------------------------  #include "../llviewercontrol.h" @@ -145,6 +86,10 @@ BOOL LLControlGroup::declareString(const std::string& name, const std::string &i  #include "lluicolortable.h"  void LLUIColorTable::saveUserSettings(void)const {} +//----------------------------------------------------------------------------- +#include "../llurlsimstring.h" +LLURLSimString LLURLSimString::sInstance; +bool LLURLSimString::parse() { return true; }  //-----------------------------------------------------------------------------  #include "llnotifications.h" @@ -252,29 +197,15 @@ namespace tut  			gSavedSettings.declareString("NextLoginLocation", "", "", FALSE);  			gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE); -			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);			 +			credentials["first"] = "testfirst"; +			credentials["last"] = "testlast"; +			credentials["passwd"] = "testpass";  			logininstance->setNotificationsInterface(¬ifications);  		}  		LLLoginInstance* logininstance; -		LLPointer<LLCredential> agentCredential; -		LLPointer<LLCredential> accountCredential; +		LLSD credentials;  		MockNotifications notifications;      }; @@ -288,7 +219,7 @@ namespace tut  		set_test_name("Test Simple Success And Disconnect");  		// Test default connect. -		logininstance->connect(agentCredential); +		logininstance->connect(credentials);  		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);  @@ -329,7 +260,7 @@ namespace tut  		const std::string test_uri = "testing-uri";  		// Test default connect. -		logininstance->connect(test_uri, agentCredential); +		logininstance->connect(test_uri, credentials);  		// connect should call LLLogin::connect to init gLoginURI and gLoginCreds.  		ensure_equals("Default connect uri", gLoginURI, "testing-uri");  @@ -351,7 +282,7 @@ namespace tut  		ensure("No TOS, failed auth", logininstance->authFailure());  		// Start again. -		logininstance->connect(test_uri, agentCredential); +		logininstance->connect(test_uri, credentials);  		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); @@ -363,11 +294,11 @@ namespace tut  		gTestPump.post(response);  		ensure("TOS auth failure", logininstance->authFailure()); -		logininstance->connect(test_uri, agentCredential); +		logininstance->connect(test_uri, credentials);  		ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false);  		// Critical Message failure response. -		logininstance->connect(test_uri, agentCredential); +		logininstance->connect(test_uri, credentials);  		response["data"]["reason"] = "critical"; // Change response to "critical message"  		gTestPump.post(response); @@ -381,7 +312,7 @@ namespace tut  		response["data"]["reason"] = "key"; // bad creds.  		gTestPump.post(response);  		ensure("TOS auth failure", logininstance->authFailure()); -		logininstance->connect(test_uri, agentCredential); +		logininstance->connect(test_uri, credentials);  		ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false);  	} @@ -392,7 +323,7 @@ namespace tut  		// Part 1 - Mandatory Update, with User accepts response.  		// Test connect with update needed. -		logininstance->connect(agentCredential); +		logininstance->connect(credentials);  		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);  @@ -418,7 +349,7 @@ namespace tut  		set_test_name("Test Mandatory Update User Decline");  		// Test connect with update needed. -		logininstance->connect(agentCredential); +		logininstance->connect(credentials);  		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);  @@ -444,7 +375,7 @@ namespace tut  		// Part 3 - Mandatory Update, with bogus response.  		// Test connect with update needed. -		logininstance->connect(agentCredential); +		logininstance->connect(credentials);  		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);  @@ -470,7 +401,7 @@ namespace tut  		// Part 3 - Mandatory Update, with bogus response.  		// Test connect with update needed. -		logininstance->connect(agentCredential); +		logininstance->connect(credentials);  		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);  diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp deleted file mode 100644 index caa1461987..0000000000 --- a/indra/newview/tests/llsecapi_test.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/**  - * @file llsecapi_test.cpp - * @author Roxie - * @date 2009-02-10 - * @brief Test the sec api 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 "../llsecapi.h" -#include "../../llxml/llcontrol.h" - - -//----------------------------------------------------------------------------                -// Mock objects for the dependencies of the code we're testing                                - -LLControlGroup::LLControlGroup(const std::string& name) -: LLInstanceTracker<LLControlGroup, std::string>(name) {} -LLControlGroup::~LLControlGroup() {} -BOOL LLControlGroup::declareString(const std::string& name, -                                   const std::string& initial_val, -                                   const std::string& comment, -                                   BOOL persist) {return TRUE;} -void LLControlGroup::setString(const std::string& name, const std::string& val){} -std::string LLControlGroup::getString(const std::string& name) -{ -	return ""; -} - - -LLControlGroup gSavedSettings("test"); -class LLSecAPIBasicHandler : public LLSecAPIHandler -{ -protected: -	LLPointer<LLCertificateChain> mCertChain; -	LLPointer<LLCertificate> mCert; -	LLPointer<LLCertificateStore> mCertStore; -	LLSD mLLSD; -	 -public: -	LLSecAPIBasicHandler() {} -	 -	virtual ~LLSecAPIBasicHandler() {} -	 -	// instantiate a certificate from a pem string -	virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert)  -	{  -		return mCert;  -	} -	 -	 -	// instiate a certificate from an openssl X509 structure -	virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)  -	{	 -		return mCert;  -	} -	 -	 -	// instantiate a chain from an X509_STORE_CTX -	virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)  -	{  -		return mCertChain;  -	} -	 -	// instantiate a cert store given it's id.  if a persisted version -	// exists, it'll be loaded.  If not, one will be created (but not -	// persisted) -	virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id)  -	{  -		return mCertStore;  -	} -	 -	// persist data in a protected store -	virtual void setProtectedData(const std::string& data_type, -								  const std::string& data_id, -								  const LLSD& data) {} -	 -	// retrieve protected data -	virtual LLSD getProtectedData(const std::string& data_type, -								  const std::string& data_id)  -	{  -		return mLLSD; -	} -	 -	virtual void deleteProtectedData(const std::string& data_type, -									 const std::string& data_id) -	{ -	} -	 -	virtual LLPointer<LLCredential> createCredential(const std::string& grid, -													 const LLSD& identifier,  -													 const LLSD& authenticator) -	{ -		LLPointer<LLCredential> cred = NULL; -		return cred; -	} -	 -	virtual LLPointer<LLCredential> loadCredential(const std::string& grid) -	{ -		LLPointer<LLCredential> cred = NULL; -		return cred; -	} -	 -	virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator) {} -	 -	virtual void deleteCredential(LLPointer<LLCredential> cred) {} -}; - -// ------------------------------------------------------------------------------------------- -// TUT -// ------------------------------------------------------------------------------------------- -namespace tut -{ -	// Test wrapper declaration : wrapping nothing for the moment -	struct secapiTest -	{ -		 -		secapiTest() -		{ -		} -		~secapiTest() -		{ -		} -	}; -	 -	// Tut templating thingamagic: test group, object and test instance -	typedef test_group<secapiTest> secapiTestFactory; -	typedef secapiTestFactory::object secapiTestObject; -	tut::secapiTestFactory tut_test("llsecapi"); -	 -	// --------------------------------------------------------------------------------------- -	// Test functions  -	// --------------------------------------------------------------------------------------- -	// registration -	template<> template<> -	void secapiTestObject::test<1>() -	{ -		// retrieve an unknown handler - -		ensure("'Unknown' handler should be NULL", !(BOOL)getSecHandler("unknown")); -		LLPointer<LLSecAPIHandler> test1_handler =  new LLSecAPIBasicHandler(); -		registerSecHandler("sectest1", test1_handler); -		ensure("'Unknown' handler should be NULL", !(BOOL)getSecHandler("unknown")); -		LLPointer<LLSecAPIHandler> retrieved_test1_handler = getSecHandler("sectest1"); -		ensure("Retrieved sectest1 handler should be the same",  -			   retrieved_test1_handler == test1_handler); -		 -		// insert a second handler -		LLPointer<LLSecAPIHandler> test2_handler =  new LLSecAPIBasicHandler(); -		registerSecHandler("sectest2", test2_handler); -		ensure("'Unknown' handler should be NULL", !(BOOL)getSecHandler("unknown")); -		retrieved_test1_handler = getSecHandler("sectest1"); -		ensure("Retrieved sectest1 handler should be the same",  -			   retrieved_test1_handler == test1_handler); - -		LLPointer<LLSecAPIHandler> retrieved_test2_handler = getSecHandler("sectest2"); -		ensure("Retrieved sectest1 handler should be the same",  -			   retrieved_test2_handler == test2_handler); -		 -	} -} diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp deleted file mode 100644 index 236d17c591..0000000000 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ /dev/null @@ -1,964 +0,0 @@ -/**  - * @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 <openssl/err.h> -#include <openssl/evp.h> -#include "llxorcipher.h" - -#define ensure_throws(str, exc_type, cert, func, ...) \ -try \ -{ \ -func(__VA_ARGS__); \ -fail("throws, " str); \ -} \ -catch(exc_type& except) \ -{ \ -ensure("Exception cert is incorrect for " str, except.getCert() == cert); \ -} - -extern bool _cert_hostname_wildcard_match(const std::string& hostname, const std::string& wildcard_string); - -//----------------------------------------------------------------------------                -// Mock objects for the dependencies of the code we're testing                                - -std::string gFirstName; -std::string gLastName; -LLControlGroup::LLControlGroup(const std::string& name) -: LLInstanceTracker<LLControlGroup, std::string>(name) {} -LLControlGroup::~LLControlGroup() {} -BOOL LLControlGroup::declareString(const std::string& name, -                                   const std::string& initial_val, -                                   const std::string& comment, -                                   BOOL persist) {return TRUE;} -void LLControlGroup::setString(const std::string& name, const std::string& val){} -std::string LLControlGroup::getString(const std::string& name) -{ - -	if (name == "FirstName") -		return gFirstName; -	else if (name == "LastName") -		return gLastName; -	return ""; -} - -LLSD LLCredential::getLoginParams() -{ -	LLSD result = LLSD::emptyMap(); -	 -	// legacy credential -	result["passwd"] = "$1$testpasssd"; -	result["first"] = "myfirst"; -	result["last"] ="mylast"; -	return result; -} - - - -LLControlGroup gSavedSettings("test"); -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, mPemRootCert, mPemIntermediateCert, mPemChildCert; -		std::string mDerFormat; -		X509 *mX509TestCert, *mX509RootCert, *mX509IntermediateCert, *mX509ChildCert; - -		sechandler_basic_test() -		{ -			OpenSSL_add_all_algorithms(); -			OpenSSL_add_all_ciphers(); -			OpenSSL_add_all_digests();	 -			ERR_load_crypto_strings(); -			gFirstName = ""; -			gLastName = ""; -			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"; - -			mPemRootCert = "-----BEGIN CERTIFICATE-----\n" -			"MIIB0TCCATqgAwIBAgIJANaTqrzEvHaRMA0GCSqGSIb3DQEBBAUAMBsxGTAXBgNV\n" -			"BAMTEFJveGllcyB0ZXN0IHJvb3QwHhcNMDkwNDE1MjEwNzQ3WhcNMTAwNDE1MjEw\n" -			"NzQ3WjAbMRkwFwYDVQQDExBSb3hpZXMgdGVzdCByb290MIGfMA0GCSqGSIb3DQEB\n" -			"AQUAA4GNADCBiQKBgQCpo5nDW6RNz9IHUVZd7Tw2XAQiBniDF4xH0N1w7sUYTiFq\n" -			"21mABsnOPJD3ra+MtOsXPHcaljm661JjTD8L40v5sfEbqDUPcOw76ClrPqnuAeyT\n" -			"38qk8DHku/mT8YdprevGZdVcUXQg3vosVzOL93HOOHK+u61mEEoM9W5xoNVEdQID\n" -			"AQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQQF\n" -			"AAOBgQAzn0aW/+zWPmcTbvxonyiYYUr9b4SOB/quhAkT8KT4ir1dcZAXRR59+kEn\n" -			"HSTu1FAodV0gvESqyobftF5hZ1XMxdJqGu//xP+YCwlv244G/0pp7KLI8ihNO2+N\n" -			"lPBUJgbo++ZkhiE1jotZi9Ay0Oedh3s/AfbMZPyfpJ23ll6+BA==\n" -			"-----END CERTIFICATE-----\n"; -			 -			 -			 -			mPemIntermediateCert = "-----BEGIN CERTIFICATE-----\n" -			"MIIBzzCCATigAwIBAgIBATANBgkqhkiG9w0BAQQFADAbMRkwFwYDVQQDExBSb3hp\n" -			"ZXMgdGVzdCByb290MB4XDTA5MDQxNTIxMzE1NloXDTEwMDQxNTIxMzE1NlowITEf\n" -			"MB0GA1UEAxMWUm94aWVzIGludGVybWVkaWF0ZSBDQTCBnzANBgkqhkiG9w0BAQEF\n" -			"AAOBjQAwgYkCgYEA15MM0W1R37rx/24Q2Qkb5bSiQZxTUcQAhJ2pA8mwUucXuCVt\n" -			"6ayI2TuN32nkjmsCgUkiT/bdXWp0OJo7/MXRIFeUNMCRxrpeFnxuigYEqbIXAdN6\n" -			"qu/vdG2X4PRv/v9Ijrju4cBEiKIldIgOurWEIfXEsVSFP2XmFQHesF04qDcCAwEA\n" -			"AaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEEBQAD\n" -			"gYEAYljikYgak3W1jSo0vYthNHUy3lBVAKzDhpM96lY5OuXFslpCRX42zNL8X3kN\n" -			"U/4IaJUVtZqx8WsUXl1eXHzBCaXCftapV4Ir6cENLIsXCdXs8paFYzN5nPJA5GYU\n" -			"zWgkSEl1MEhNIc+bJW34vwi29EjrAShAhsIZ84Mt/lvD3Pc=\n" -			"-----END CERTIFICATE-----\n"; -			 -			mPemChildCert = "-----BEGIN CERTIFICATE-----\n" -			"MIIB5DCCAU0CBEnm9eUwDQYJKoZIhvcNAQEEBQAwITEfMB0GA1UEAxMWUm94aWVz\n" -			"IGludGVybWVkaWF0ZSBDQTAeFw0wOTA0MTYwMDAzNDlaFw0xMDA0MTYwMDAzNDla\n" -			"MCAxHjAcBgNVBAMTFWVuaWFjNjMubGluZGVubGFiLmNvbTCBnzANBgkqhkiG9w0B\n" -			"AQEFAAOBjQAwgYkCgYEAp9I5rofEzbjNht+9QejfnsIlEPqSxskoWKCG255TesWR\n" -			"RTmw9wafHQQkJk/VIsaU4RMBYHkknGbHX2dGvMHmKZoWUPSQ/8FZz09o0Qx3TNUZ\n" -			"l7KlGOD2d1c7ZxXDPqlLC6QW8DrE1/8zfwJ5cbYBXc8e7OKdSZeRrnwHyw4Q8r8C\n" -			"AwEAAaMvMC0wEwYDVR0lBAwwCgYIKwYBBQUHAwEwCQYDVR0TBAIwADALBgNVHQ8E\n" -			"BAMCBaAwDQYJKoZIhvcNAQEEBQADgYEAIG0M5tqYlXyMiGKPZfXy/R3M3ZZOapDk\n" -			"W0dsXJYXAc35ftwtn0VYu9CNnZCcli17/d+AKhkK8a/oGPazqudjFF6WLJLTXaY9\n" -			"NmhkJcOPADXkbyQPUPXzLe4YRrkEQeGhzMb4rKDQ1TKAcXfs0Y068pTpsixNSxja\n" -			"NhAUUcve5Is=\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"; -			 -			mX509TestCert = NULL; -			mX509RootCert = NULL; -			mX509IntermediateCert = NULL; -			mX509ChildCert = 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); -			validation_bio = BIO_new_mem_buf((void*)mPemRootCert.c_str(), mPemRootCert.length()); -			PEM_read_bio_X509(validation_bio, &mX509RootCert, 0, NULL); -			BIO_free(validation_bio); -			validation_bio = BIO_new_mem_buf((void*)mPemIntermediateCert.c_str(), mPemIntermediateCert.length()); -			PEM_read_bio_X509(validation_bio, &mX509IntermediateCert, 0, NULL); -			BIO_free(validation_bio);	 -			validation_bio = BIO_new_mem_buf((void*)mPemChildCert.c_str(), mPemChildCert.length()); -			PEM_read_bio_X509(validation_bio, &mX509ChildCert, 0, NULL); -			BIO_free(validation_bio);				 -		} -		~sechandler_basic_test() -		{ -			LLFile::remove("test_password.dat"); -			LLFile::remove("sechandler_settings.tmp"); -			LLFile::remove("mycertstore.pem"); -			X509_free(mX509TestCert); -			X509_free(mX509RootCert); -			X509_free(mX509IntermediateCert); -			X509_free(mX509ChildCert); -		} -	}; -	 -	// 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]; -		LLPointer<LLCertificate> test_cert = new LLBasicCertificate(mPemTestCert); -		 -		ensure_equals("Resultant pem is correct", -			   mPemTestCert, test_cert->getPem()); -		std::vector<U8> binary_cert = test_cert->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 = test_cert->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-30T12:58:00Z"); -		ensure_equals("valid to", (std::string)llsd_cert["valid_to"], "2011-11-30T23:59:00Z"); -		LLSD expectedKeyUsage = LLSD::emptyArray(); -		expectedKeyUsage.append(LLSD((std::string)"certSigning")); -		expectedKeyUsage.append(LLSD((std::string)"crlSigning")); -		ensure("key usage", valueCompareLLSD(llsd_cert["keyUsage"], expectedKeyUsage)); -		ensure("basic constraints", (bool)llsd_cert["basicConstraints"]["CA"]); -		 -		ensure("x509 is equal", !X509_cmp(mX509TestCert, test_cert->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"); -		handler->init();																		 -		// 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"); -		handler->init(); - -		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"); -		handler->init();		 -		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"); -		handler->init();		 -		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"); -		handler->init(); - -		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_grid2"); -		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 -		gFirstName = "myfirstname"; -		gLastName = "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 vector -	template<> template<> -	void sechandler_basic_test_object::test<4>() -	{ -		 -		// validate create from empty vector -		LLPointer<LLBasicCertificateVector> test_vector = new LLBasicCertificateVector(); -		ensure_equals("when loading with nothing, we should result in no certs in vector", test_vector->size(), 0); -		 -		test_vector->add(new LLBasicCertificate(mPemTestCert)); -		ensure_equals("one element in vector", test_vector->size(), 1); -		test_vector->add(new LLBasicCertificate(mPemChildCert)); -		ensure_equals("two elements in vector after add", test_vector->size(), 2); -		 -		test_vector->add(new LLBasicCertificate(mPemChildCert)); -		ensure_equals("two elements in vector after re-add", test_vector->size(), 2); -		// validate order -		X509* test_cert = (*test_vector)[0]->getOpenSSLX509();		 -		ensure("first cert added remains first cert", !X509_cmp(test_cert, mX509TestCert)); -		X509_free(test_cert); -		 -		test_cert = (*test_vector)[1]->getOpenSSLX509();	 -		ensure("adding a duplicate cert", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert);		 -		 -		// -		// validate iterator -		// -		LLBasicCertificateVector::iterator current_cert = test_vector->begin(); -		LLBasicCertificateVector::iterator copy_current_cert = current_cert; -		// operator++(int) -		ensure("validate iterator++ element in vector is expected cert", *current_cert++ == (*test_vector)[0]); -		ensure("validate 2nd iterator++ element in vector is expected cert", *current_cert++ == (*test_vector)[1]); -		ensure("validate end iterator++", current_cert == test_vector->end()); -		 -		// copy  -		ensure("validate copy iterator element in vector is expected cert", *copy_current_cert == (*test_vector)[0]);		 -		 -		// operator--(int) -		current_cert--; -		ensure("validate iterator-- element in vector is expected cert", *current_cert-- == (*test_vector)[1]);		 -		ensure("validate iterator-- element in vector is expected cert", *current_cert == (*test_vector)[0]); -		 -		ensure("begin iterator is equal", current_cert == test_vector->begin()); -		 -		// operator++ -		ensure("validate ++iterator element in vector is expected cert", *++current_cert == (*test_vector)[1]);				 -		ensure("end of cert vector after ++iterator", ++current_cert == test_vector->end()); -		// operator-- -		ensure("validate --iterator element in vector is expected cert", *--current_cert == (*test_vector)[1]);		 -		ensure("validate 2nd --iterator element in vector is expected cert", *--current_cert == (*test_vector)[0]);		 -		 -		// validate remove -		// validate create from empty vector -		test_vector = new LLBasicCertificateVector(); -		test_vector->add(new LLBasicCertificate(mPemTestCert)); -		test_vector->add(new LLBasicCertificate(mPemChildCert)); -		test_vector->erase(test_vector->begin()); -		ensure_equals("one element in store after remove", test_vector->size(), 1); -		test_cert = (*test_vector)[0]->getOpenSSLX509(); -		ensure("validate cert was removed", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert); -		 -		// validate insert -		test_vector->insert(test_vector->begin(), new LLBasicCertificate(mPemChildCert)); -		test_cert = (*test_vector)[0]->getOpenSSLX509(); -		 -		ensure("validate cert was inserted", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert);	 - -		//validate find -		LLSD find_info = LLSD::emptyMap(); -		test_vector->insert(test_vector->begin(), new LLBasicCertificate(mPemRootCert)); -		find_info["issuer_name"] = LLSD::emptyMap(); -		find_info["issuer_name"]["commonName"] = "Roxies intermediate CA"; -		find_info["md5_digest"] = "97:24:c7:4c:d4:ba:2d:0e:9c:a1:18:8e:3a:c6:1f:c3"; -		current_cert = test_vector->find(find_info); -		ensure("found", current_cert != test_vector->end()); -		ensure("found cert", (*current_cert).get() == (*test_vector)[1].get()); -		find_info["sha1_digest"] = "bad value"; -		current_cert =test_vector->find(find_info); -		ensure("didn't find cert", current_cert == test_vector->end());		 -	}	 -	 -	// test cert store -	template<> template<> -	void sechandler_basic_test_object::test<5>() -	{ -		// validate load with nothing -		LLFile::remove("mycertstore.pem"); -		LLPointer<LLBasicCertificateStore> test_store = new LLBasicCertificateStore("mycertstore.pem"); -		ensure_equals("when loading with nothing, we should result in no certs in store", test_store->size(), 0); -		 -		// validate load with empty file -		test_store->save(); -		test_store = NULL; -		test_store = new LLBasicCertificateStore("mycertstore.pem"); -		ensure_equals("when loading with nothing, we should result in no certs in store", test_store->size(), 0); -		test_store=NULL; -		 -		// instantiate a cert store from a file -		llofstream certstorefile("mycertstore.pem", std::ios::out); -		certstorefile << mPemChildCert << std::endl << mPemTestCert << std::endl; -		certstorefile.close(); -		// validate loaded certs -		test_store = new LLBasicCertificateStore("mycertstore.pem"); -		ensure_equals("two elements in store", test_store->size(), 2); -		 -		// operator[] -		X509* test_cert = (*test_store)[0]->getOpenSSLX509(); - -		ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert); -		test_cert = (*test_store)[1]->getOpenSSLX509(); -		ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509TestCert));	 -		X509_free(test_cert); - - -		// validate save -		LLFile::remove("mycertstore.pem"); -		test_store->save(); -		test_store = NULL; -		test_store = new LLBasicCertificateStore("mycertstore.pem"); -		ensure_equals("two elements in store after save", test_store->size(), 2);				 -		LLCertificateStore::iterator current_cert = test_store->begin();		 -		test_cert = (*current_cert)->getOpenSSLX509(); -		ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); -		current_cert++; -		X509_free(test_cert); -		test_cert = (*current_cert)->getOpenSSLX509(); -		ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509TestCert));	 -		X509_free(test_cert); -		current_cert++; -		ensure("end of cert store", current_cert == test_store->end()); -		 -	} -	 -	// cert name wildcard matching -	template<> template<> -	void sechandler_basic_test_object::test<6>() -	{ -		ensure("simple name match",  -			   _cert_hostname_wildcard_match("foo", "foo")); -		 -		ensure("simple name match, with end period",  -			   _cert_hostname_wildcard_match("foo.", "foo.")); -		 -		ensure("simple name match, with begin period",  -			   _cert_hostname_wildcard_match(".foo", ".foo"));		 -		 -		ensure("simple name match, with subdomain",  -			   _cert_hostname_wildcard_match("foo.bar", "foo.bar"));	 -		 -		ensure("stutter name match",  -			   _cert_hostname_wildcard_match("foobbbbfoo", "foo*bbbfoo"));			 -		 -		ensure("simple name match, with beginning wildcard",  -			   _cert_hostname_wildcard_match("foobar", "*bar"));	 -		 -		ensure("simple name match, with ending wildcard",  -			   _cert_hostname_wildcard_match("foobar", "foo*")); -		 -		ensure("simple name match, with beginning null wildcard",  -			   _cert_hostname_wildcard_match("foobar", "*foobar"));			 - -		ensure("simple name match, with ending null wildcard",  -			   _cert_hostname_wildcard_match("foobar", "foobar*")); -		 -		ensure("simple name match, with embedded wildcard",  -			   _cert_hostname_wildcard_match("foobar", "f*r"));		 -		 -		ensure("simple name match, with embedded null wildcard",  -			   _cert_hostname_wildcard_match("foobar", "foo*bar")); - -		ensure("simple name match, with dual embedded wildcard",  -			   _cert_hostname_wildcard_match("foobar", "f*o*ar"));		 - -		ensure("simple name mismatch",  -			   !_cert_hostname_wildcard_match("bar", "foo")); -		 -		ensure("simple name mismatch, with end period",  -			   !_cert_hostname_wildcard_match("foobar.", "foo.")); -		 -		ensure("simple name mismatch, with begin period",  -			   !_cert_hostname_wildcard_match(".foobar", ".foo"));		 -		 -		ensure("simple name mismatch, with subdomain",  -			   !_cert_hostname_wildcard_match("foobar.bar", "foo.bar"));	 -		 -		ensure("simple name mismatch, with beginning wildcard",  -			   !_cert_hostname_wildcard_match("foobara", "*bar"));	 -		 -		ensure("simple name mismatch, with ending wildcard",  -			   !_cert_hostname_wildcard_match("oobar", "foo*")); -		 -		ensure("simple name mismatch, with embedded wildcard",  -			   !_cert_hostname_wildcard_match("oobar", "f*r"));		 -		 -		ensure("simple name mismatch, with dual embedded wildcard",  -			   !_cert_hostname_wildcard_match("foobar", "f*d*ar")); -		 -		ensure("simple wildcard",  -			   _cert_hostname_wildcard_match("foobar", "*")); -		 -		ensure("long domain",  -			   _cert_hostname_wildcard_match("foo.bar.com", "foo.bar.com")); -		 -		ensure("long domain with multiple wildcards",  -			   _cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com"));	 - -		ensure("end periods",  -			   _cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com."));	 -		 -		ensure("mismatch end period",  -			   !_cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com")); -		 -		ensure("mismatch end period2",  -			   !_cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com."));				 -	} -	 -	// test cert chain -	template<> template<> -	void sechandler_basic_test_object::test<7>() -	{ -		// validate create from empty chain -		LLPointer<LLBasicCertificateChain> test_chain = new LLBasicCertificateChain(NULL); -		ensure_equals("when loading with nothing, we should result in no certs in chain", test_chain->size(), 0); - -		// Single cert in the chain. -		X509_STORE_CTX *test_store = X509_STORE_CTX_new(); -		test_store->cert = mX509ChildCert;		 -		test_store->untrusted = NULL; -		test_chain = new LLBasicCertificateChain(test_store); -		X509_STORE_CTX_free(test_store); -		ensure_equals("two elements in store", test_chain->size(), 1);		 -		X509* test_cert = (*test_chain)[0]->getOpenSSLX509(); -		ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert);		 -		 -		// cert + CA -		 -		test_store = X509_STORE_CTX_new(); -		test_store->cert = mX509ChildCert; -		test_store->untrusted = sk_X509_new_null(); -		sk_X509_push(test_store->untrusted, mX509IntermediateCert); -		test_chain = new LLBasicCertificateChain(test_store); -		X509_STORE_CTX_free(test_store); -		ensure_equals("two elements in store", test_chain->size(), 2);	 -		test_cert = (*test_chain)[0]->getOpenSSLX509(); -		ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert); -		test_cert = (*test_chain)[1]->getOpenSSLX509(); -		ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert));	 -		X509_free(test_cert); - -		// cert + nonrelated -		 -		test_store = X509_STORE_CTX_new(); -		test_store->cert = mX509ChildCert; -		test_store->untrusted = sk_X509_new_null(); -		sk_X509_push(test_store->untrusted, mX509TestCert); -		test_chain = new LLBasicCertificateChain(test_store); -		X509_STORE_CTX_free(test_store); -		ensure_equals("two elements in store", test_chain->size(), 1);	 -		test_cert = (*test_chain)[0]->getOpenSSLX509(); -		ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert); -		 -		// cert + CA + nonrelated -		test_store = X509_STORE_CTX_new(); -		test_store->cert = mX509ChildCert; -		test_store->untrusted = sk_X509_new_null(); -		sk_X509_push(test_store->untrusted, mX509IntermediateCert); -		sk_X509_push(test_store->untrusted, mX509TestCert); -		test_chain = new LLBasicCertificateChain(test_store); -		X509_STORE_CTX_free(test_store); -		ensure_equals("two elements in store", test_chain->size(), 2);	 -		test_cert = (*test_chain)[0]->getOpenSSLX509(); -		ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert); -		test_cert = (*test_chain)[1]->getOpenSSLX509(); -		ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert));	 -		X509_free(test_cert); - -		// cert + intermediate + CA  -		test_store = X509_STORE_CTX_new(); -		test_store->cert = mX509ChildCert; -		test_store->untrusted = sk_X509_new_null(); -		sk_X509_push(test_store->untrusted, mX509IntermediateCert); -		sk_X509_push(test_store->untrusted, mX509RootCert); -		test_chain = new LLBasicCertificateChain(test_store); -		X509_STORE_CTX_free(test_store); -		ensure_equals("three elements in store", test_chain->size(), 3);	 -		test_cert = (*test_chain)[0]->getOpenSSLX509(); -		ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); -		X509_free(test_cert); -		test_cert = (*test_chain)[1]->getOpenSSLX509(); -		ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert));	 -		X509_free(test_cert); - -		test_cert = (*test_chain)[2]->getOpenSSLX509(); -		ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509RootCert));	 -		X509_free(test_cert);		 -	} -	// test cert validation -	template<> template<> -	void sechandler_basic_test_object::test<8>() -	{ -		// start with a trusted store with our known root cert -		LLFile::remove("mycertstore.pem"); -		LLPointer<LLBasicCertificateStore> test_store = new LLBasicCertificateStore("mycertstore.pem"); -		test_store->add(new LLBasicCertificate(mX509RootCert)); -		LLSD validation_params; -		 -		// validate basic trust for a chain containing only the intermediate cert.  (1 deep) -		LLPointer<LLBasicCertificateChain> test_chain = new LLBasicCertificateChain(NULL); - -		test_chain->add(new LLBasicCertificate(mX509IntermediateCert)); - -		test_chain->validate(0, test_store, validation_params); - -		// add the root certificate to the chain and revalidate -		test_chain->add(new LLBasicCertificate(mX509RootCert));	 -		test_chain->validate(0, test_store, validation_params); - -		// add the child cert at the head of the chain, and revalidate (3 deep chain) -		test_chain->insert(test_chain->begin(), new LLBasicCertificate(mX509ChildCert)); -		test_chain->validate(0, test_store, validation_params); - -		// basic failure cases -		test_chain = new LLBasicCertificateChain(NULL); -		//validate with only the child cert -		test_chain->add(new LLBasicCertificate(mX509ChildCert)); -		ensure_throws("no CA, with only a child cert",  -					  LLCertValidationTrustException,  -					  (*test_chain)[0], -					  test_chain->validate,  -					  VALIDATION_POLICY_TRUSTED,  -					  test_store,  -					  validation_params); - - -		// validate without the trust flag. -		test_chain->validate(0, test_store, validation_params);		 - -		// clear out the store -		test_store = new LLBasicCertificateStore("mycertstore.pem"); -		// append the intermediate cert -		test_chain->add(new LLBasicCertificate(mX509IntermediateCert));		 -		ensure_throws("no CA, with child and intermediate certs",  -					  LLCertValidationTrustException,  -					  (*test_chain)[1], -					  test_chain->validate,  -					  VALIDATION_POLICY_TRUSTED,  -					  test_store,  -					  validation_params); -		// validate without the trust flag -		test_chain->validate(0, test_store, validation_params); - -		// Test time validity -		LLSD child_info = (*test_chain)[0]->getLLSD(); -		validation_params = LLSD::emptyMap(); -		validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_FROM].asDate().secondsSinceEpoch() + 1.0);   -		test_chain->validate(VALIDATION_POLICY_TIME, test_store, validation_params); - -		validation_params = LLSD::emptyMap();		 -		validation_params[CERT_VALIDATION_DATE] = child_info[CERT_VALID_FROM].asDate(); -		 -		validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_FROM].asDate().secondsSinceEpoch() - 1.0); - 		 -		// test not yet valid -		ensure_throws("Child cert not yet valid",  -					  LLCertValidationExpirationException,  -					  (*test_chain)[0], -					  test_chain->validate,  -					  VALIDATION_POLICY_TIME,  -					  test_store,  -					  validation_params);	 -		validation_params = LLSD::emptyMap();		 -		validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_TO].asDate().secondsSinceEpoch() + 1.0); - 		 -		// test cert expired -		ensure_throws("Child cert expired",  -					  LLCertValidationExpirationException,  -					  (*test_chain)[0], -					  test_chain->validate,  -					  VALIDATION_POLICY_TIME,  -					  test_store,  -					  validation_params); - -		// test SSL KU -		// validate basic trust for a chain containing child and intermediate. -		test_chain = new LLBasicCertificateChain(NULL); -		test_chain->add(new LLBasicCertificate(mX509ChildCert)); -		test_chain->add(new LLBasicCertificate(mX509IntermediateCert)); -		test_chain->validate(VALIDATION_POLICY_SSL_KU, test_store, validation_params);	 - -		test_chain = new LLBasicCertificateChain(NULL); -		test_chain->add(new LLBasicCertificate(mX509TestCert)); - -		ensure_throws("Cert doesn't have ku",  -					  LLCertKeyUsageValidationException,  -					  (*test_chain)[0], -					  test_chain->validate,  -					  VALIDATION_POLICY_SSL_KU,  -					  test_store,  -					  validation_params); -	} -}; - diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp deleted file mode 100644 index 803020dc7a..0000000000 --- a/indra/newview/tests/llslurl_test.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/**  - * @file llsecapi_test.cpp - * @author Roxie - * @date 2009-02-10 - * @brief Test the sec api 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 Lab - * to you under the terms of the GNU General Public License, version maps.secondlife.com2.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 "../llslurl.h" -#include "../../llxml/llcontrol.h" -#include "llsdserialize.h" -//----------------------------------------------------------------------------                -// Mock objects for the dependencies of the code we're testing                                - -LLControlGroup::LLControlGroup(const std::string& name) -: LLInstanceTracker<LLControlGroup, std::string>(name) {} -LLControlGroup::~LLControlGroup() {} -BOOL LLControlGroup::declareString(const std::string& name, -                                   const std::string& initial_val, -                                   const std::string& comment, -                                   BOOL persist) {return TRUE;} -void LLControlGroup::setString(const std::string& name, const std::string& val){} - -std::string gCmdLineLoginURI; -std::string gCmdLineGridChoice; -std::string gCmdLineHelperURI; -std::string gLoginPage; -std::string gCurrentGrid; -std::string LLControlGroup::getString(const std::string& name) -{ -	if (name == "CmdLineGridChoice") -		return gCmdLineGridChoice; -	else if (name == "CmdLineHelperURI") -		return gCmdLineHelperURI; -	else if (name == "LoginPage") -		return gLoginPage; -	else if (name == "CurrentGrid") -		return gCurrentGrid; -	return ""; -} - -LLSD LLControlGroup::getLLSD(const std::string& name) -{ -	if (name == "CmdLineLoginURI") -	{ -		if(!gCmdLineLoginURI.empty()) -		{ -			return LLSD(gCmdLineLoginURI); -		} -	} -	return LLSD(); -} - - -LLControlGroup gSavedSettings("test"); - -// ------------------------------------------------------------------------------------------- -// TUT -// ------------------------------------------------------------------------------------------- -namespace tut -{ -	// Test wrapper declaration : wrapping nothing for the moment -	struct slurlTest -	{ -		slurlTest() -		{	 -			LLGridManager::getInstance()->initialize(std::string("")); -		} -		~slurlTest() -		{ -		} -	}; -	 -	// Tut templating thingamagic: test group, object and test instance -	typedef test_group<slurlTest> slurlTestFactory; -	typedef slurlTestFactory::object slurlTestObject; -	tut::slurlTestFactory tut_test("llslurl"); -	 -	// --------------------------------------------------------------------------------------- -	// Test functions  -	// --------------------------------------------------------------------------------------- -	// construction from slurl string -	template<> template<> -	void slurlTestObject::test<1>() -	{ -		LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com"); -		 -		LLSLURL slurl = LLSLURL(""); -		ensure_equals("null slurl", (int)slurl.getType(), LLSLURL::LAST_LOCATION); -		 -		slurl = LLSLURL("http://slurl.com/secondlife/myregion"); -		ensure_equals("slurl.com slurl, region only - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("slurl.com slurl, region only", slurl.getSLURLString(),  -					  "http://maps.secondlife.com/secondlife/myregion/128/128/0"); -		 -		slurl = LLSLURL("http://maps.secondlife.com/secondlife/myregion/1/2/3"); -		ensure_equals("maps.secondlife.com slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("maps.secondlife.com slurl, region + coords", slurl.getSLURLString(),  -					  "http://maps.secondlife.com/secondlife/myregion/1/2/3"); - -		slurl = LLSLURL("secondlife://myregion"); -		ensure_equals("secondlife: slurl, region only - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("secondlife: slurl, region only", slurl.getSLURLString(),  -					  "http://maps.secondlife.com/secondlife/myregion/128/128/0"); -		 -		slurl = LLSLURL("secondlife://myregion/1/2/3"); -		ensure_equals("secondlife: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("secondlife slurl, region + coords", slurl.getSLURLString(),  -					  "http://maps.secondlife.com/secondlife/myregion/1/2/3"); -		 -		slurl = LLSLURL("/myregion"); -		ensure_equals("/region slurl, region- type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("/region slurl, region ", slurl.getSLURLString(),  -					  "http://maps.secondlife.com/secondlife/myregion/128/128/0"); -		 -		slurl = LLSLURL("/myregion/1/2/3"); -		ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("/ slurl, region + coords", slurl.getSLURLString(),  -					  "http://maps.secondlife.com/secondlife/myregion/1/2/3");	 -		 -		slurl = LLSLURL("my region/1/2/3"); -		ensure_equals(" slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals(" slurl, region + coords", slurl.getSLURLString(),  -					  "http://maps.secondlife.com/secondlife/my%20region/1/2/3");	 -		 -		slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3"); -		ensure_equals("grid slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("grid slurl, region + coords", slurl.getSLURLString(),  -					  "https://my.grid.com/region/my%20region/1/2/3");	 -		 -		slurl = LLSLURL("https://my.grid.com/region/my region"); -		ensure_equals("grid slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("grid slurl, region + coords", slurl.getSLURLString(),  -					  "https://my.grid.com/region/my%20region/128/128/0"); -		 -		LLGridManager::getInstance()->setGridChoice("foo.bar.com");		 -		slurl = LLSLURL("/myregion/1/2/3"); -		ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("/ slurl, region + coords", slurl.getSLURLString(),  -					  "https://foo.bar.com/region/myregion/1/2/3");		 -		 -		slurl = LLSLURL("myregion/1/2/3"); -		ensure_equals(": slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals(" slurl, region + coords", slurl.getSLURLString(),  -					  "https://foo.bar.com/region/myregion/1/2/3");		 -		 -		slurl = LLSLURL(LLSLURL::SIM_LOCATION_HOME); -		ensure_equals("home", slurl.getType(), LLSLURL::HOME_LOCATION); - -		slurl = LLSLURL(LLSLURL::SIM_LOCATION_LAST); -		ensure_equals("last", slurl.getType(), LLSLURL::LAST_LOCATION); -		 -		slurl = LLSLURL("secondlife:///app/foo/bar?12345"); -		ensure_equals("app", slurl.getType(), LLSLURL::APP);		 -		ensure_equals("appcmd", slurl.getAppCmd(), "foo"); -		ensure_equals("apppath", slurl.getAppPath().size(), 1); -		ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar"); -		ensure_equals("appquery", slurl.getAppQuery(), "12345"); -		ensure_equals("grid1", "foo.bar.com", slurl.getGrid()); -	 -		slurl = LLSLURL("secondlife://Aditi/app/foo/bar?12345"); -		ensure_equals("app", slurl.getType(), LLSLURL::APP);		 -		ensure_equals("appcmd", slurl.getAppCmd(), "foo"); -		ensure_equals("apppath", slurl.getAppPath().size(), 1); -		ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar"); -		ensure_equals("appquery", slurl.getAppQuery(), "12345"); -		ensure_equals("grid2", "util.aditi.lindenlab.com", slurl.getGrid());		 - -		LLGridManager::getInstance()->setGridChoice("foo.bar.com");			 -		slurl = LLSLURL("secondlife:///secondlife/myregion/1/2/3"); -		ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("location", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("region" , "myregion", slurl.getRegion()); -		ensure_equals("grid3", "util.agni.lindenlab.com", slurl.getGrid()); -				 -		slurl = LLSLURL("secondlife://Aditi/secondlife/myregion/1/2/3"); -		ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("location", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("region" , "myregion", slurl.getRegion()); -		ensure_equals("grid4", "util.aditi.lindenlab.com", slurl.getGrid());		 -		 -		slurl = LLSLURL("https://my.grid.com/app/foo/bar?12345"); -		ensure_equals("app", slurl.getType(), LLSLURL::APP);		 -		ensure_equals("appcmd", slurl.getAppCmd(), "foo"); -		ensure_equals("apppath", slurl.getAppPath().size(), 1); -		ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar"); -		ensure_equals("appquery", slurl.getAppQuery(), "12345");	 -		 -	} -	 -	// construction from grid/region/vector combos -	template<> template<> -	void slurlTestObject::test<2>() -	{ -		LLSLURL slurl = LLSLURL("mygrid.com", "my region"); -		ensure_equals("grid/region - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals("grid/region", slurl.getSLURLString(),  -					  "https://mygrid.com/region/my%20region/128/128/0");	 -		 -		slurl = LLSLURL("mygrid.com", "my region", LLVector3(1,2,3)); -		ensure_equals("grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals(" grid/region/vector", slurl.getSLURLString(),  -					  "https://mygrid.com/region/my%20region/1/2/3");			 - -		LLGridManager::getInstance()->setGridChoice("foo.bar.com.bar");			 -		slurl = LLSLURL("my region", LLVector3(1,2,3)); -		ensure_equals("grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals(" grid/region/vector", slurl.getSLURLString(),  -					  "https://foo.bar.com.bar/region/my%20region/1/2/3");	 -		 -		LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com");	 -		slurl = LLSLURL("my region", LLVector3(1,2,3)); -		ensure_equals("default grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION); -		ensure_equals(" default grid/region/vector", slurl.getSLURLString(),  -					  "http://maps.secondlife.com/secondlife/my%20region/1/2/3");	 -		 -	} -	// Accessors -	template<> template<> -	void slurlTestObject::test<3>() -	{ -		LLSLURL slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3"); -		ensure_equals("login string", slurl.getLoginString(), "uri:my region&1&2&3"); -		ensure_equals("location string", slurl.getLocationString(), "my region/1/2/3"); -		ensure_equals("grid", slurl.getGrid(), "my.grid.com"); -		ensure_equals("region", slurl.getRegion(), "my region"); -		ensure_equals("position", slurl.getPosition(), LLVector3(1, 2, 3)); -		 -	} -} diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp deleted file mode 100644 index e0c7c83f4b..0000000000 --- a/indra/newview/tests/llviewernetwork_test.cpp +++ /dev/null @@ -1,486 +0,0 @@ -/**  - * @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" - -//----------------------------------------------------------------------------                -// Mock objects for the dependencies of the code we're testing                                - -LLControlGroup::LLControlGroup(const std::string& name) -: LLInstanceTracker<LLControlGroup, std::string>(name) {} -LLControlGroup::~LLControlGroup() {} -BOOL LLControlGroup::declareString(const std::string& name, -                                   const std::string& initial_val, -                                   const std::string& comment, -                                   BOOL persist) {return TRUE;} -void LLControlGroup::setString(const std::string& name, const std::string& val){} - -std::string gCmdLineLoginURI; -std::string gCmdLineGridChoice; -std::string gCmdLineHelperURI; -std::string gLoginPage; -std::string gCurrentGrid; -std::string LLControlGroup::getString(const std::string& name) -{ -	if (name == "CmdLineGridChoice") -		return gCmdLineGridChoice; -	else if (name == "CmdLineHelperURI") -		return gCmdLineHelperURI; -	else if (name == "LoginPage") -		return gLoginPage; -	else if (name == "CurrentGrid") -		return gCurrentGrid; -	return ""; -} - -LLSD LLControlGroup::getLLSD(const std::string& name) -{ -	if (name == "CmdLineLoginURI") -	{ -		if(!gCmdLineLoginURI.empty()) -		{ -			return LLSD(gCmdLineLoginURI); -		} -	} -	return LLSD(); -} - - -LLControlGroup gSavedSettings("test"); - -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() -		{ -			LLFile::remove("grid_test.xml"); -			gCmdLineLoginURI.clear(); -			gCmdLineGridChoice.clear(); -			gCmdLineHelperURI.clear(); -			gLoginPage.clear(); -			gCurrentGrid.clear();			 -		} -		~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 = LLGridManager::getInstance(); -		// grid file doesn't exist -		manager->initialize("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); -		ensure_equals("Agni has the right name and label",  -					  known_grids[std::string("util.agni.lindenlab.com")], std::string("Agni")); -#else // LL_RELEASE_FOR_DOWNLOAD -		ensure_equals("Known grids is a string-string map of size 2", known_grids.size(), 2); -		ensure_equals("Agni has the right name and label",  -					  known_grids[std::string("util.agni.lindenlab.com")], std::string("Secondlife.com"));		 -#endif // LL_RELEASE_FOR_DOWNLOAD - - -		ensure_equals("None exists", known_grids[""], "None"); -		 -		LLSD grid = LLGridManager::getInstance()->getGridInfo("util.agni.lindenlab.com"); -		ensure("Grid info for agni is a map", grid.isMap()); -		ensure_equals("name is correct for agni",  -					  grid[GRID_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 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::getInstance()->initialize("grid_test.xml"); -		std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); -#ifndef LL_RELEASE_FOR_DOWNLOAD -		ensure_equals("adding a grid via a grid file increases known grid size",  -					  known_grids.size(), 19); -		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")); -	 -#else -		ensure_equals("adding a grid via a grid file increases known grid size",  -					  known_grids.size(), 3); -		ensure_equals("Agni is still there after we've added a grid via a grid file",  -					  known_grids["util.agni.lindenlab.com"], std::string("Secondlife.com")); - -#endif -	 -		 -		// assure Agni doesn't get overwritten -		LLSD grid = LLGridManager::getInstance()->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_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 a 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 = LLGridManager::getInstance()->getGridInfo("grid1"); -		ensure_equals("grid file grid name is set", -					  grid[GRID_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>() -	{	 -		gCmdLineLoginURI = "https://my.login.uri/cgi-bin/login.cgi"; -		 -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		// with single login uri specified. -		std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); -		ensure_equals("adding a command line grid increases known grid size",  -					  known_grids.size(), 19); -		ensure_equals("Command line grid is added to the list of grids",  -					  known_grids["my.login.uri"], std::string("my.login.uri")); -		LLSD grid = LLGridManager::getInstance()->getGridInfo("my.login.uri"); -		ensure_equals("Command line grid name is set", -					  grid[GRID_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 -		gCmdLineGridChoice = "mycustomgridchoice";		 -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		known_grids = LLGridManager::getInstance()->getKnownGrids(); -		ensure_equals("adding a command line grid with custom name increases known grid size",  -					  known_grids.size(), 19); -		ensure_equals("Custom Command line grid is added to the list of grids",  -					  known_grids["mycustomgridchoice"], std::string("mycustomgridchoice")); -		grid = LLGridManager::getInstance()->getGridInfo("mycustomgridchoice"); -		ensure_equals("Custom Command line grid name is set", -					  grid[GRID_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 -		gCmdLineHelperURI = "myhelperuri"; -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		grid = LLGridManager::getInstance()->getGridInfo("mycustomgridchoice");		 -		ensure_equals("Validate command line helper uri",  -					  grid[GRID_HELPER_URI_VALUE].asString(), std::string("myhelperuri"));		 -		 -		// add a login page -		gLoginPage = "myloginpage"; -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		grid = LLGridManager::getInstance()->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_VALUE] = "myaddedgrid"; - -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		LLGridManager::getInstance()->addGrid(grid); -		LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com"); -#ifndef LL_RELEASE_FOR_DOWNLOAD		 -		ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("Agni")); -#else // LL_RELEASE_FOR_DOWNLOAD -		ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("Secondlife.com"));		 -#endif // LL_RELEASE_FOR_DOWNLOAD -		ensure_equals("getGrid", LLGridManager::getInstance()->getGrid(),  -					  std::string("util.agni.lindenlab.com")); -		ensure_equals("getHelperURI", LLGridManager::getInstance()->getHelperURI(),  -					  std::string("https://secondlife.com/helpers/")); -		ensure_equals("getLoginPage", LLGridManager::getInstance()->getLoginPage(),  -					  std::string("http://secondlife.com/app/login/")); -		ensure_equals("getLoginPage2", LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com"),  -					  std::string("http://secondlife.com/app/login/")); -		ensure("Is Agni a production grid", LLGridManager::getInstance()->isInProductionGrid());		 -		std::vector<std::string> uris; -		LLGridManager::getInstance()->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")); -		LLGridManager::getInstance()->setGridChoice("myaddedgrid"); -		ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("myaddedgrid"));		 -		ensure("Is myaddedgrid a production grid", !LLGridManager::getInstance()->isInProductionGrid()); -		 -		LLGridManager::getInstance()->setFavorite(); -		grid = LLGridManager::getInstance()->getGridInfo("myaddedgrid"); -		ensure("setting favorite", grid.has(GRID_IS_FAVORITE_VALUE)); -	} -	 -	// name based grid population -	template<> template<> -	void viewerNetworkTestObject::test<5>() -	{ -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		LLSD grid = LLSD::emptyMap(); -		// adding a grid with simply a name will populate the values. -		grid[GRID_VALUE] = "myaddedgrid"; -		LLGridManager::getInstance()->addGrid(grid); -		grid = LLGridManager::getInstance()->getGridInfo("myaddedgrid"); -		 -		ensure_equals("name based grid has name value",  -					  grid[GRID_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::getInstance()->initialize("grid_test.xml"); -		LLSD grid = LLSD::emptyMap(); -		grid[GRID_VALUE] = std::string("mynewgridname"); -		LLGridManager::getInstance()->addGrid(grid); -		LLGridManager::getInstance()->saveFavorites(); -		ensure("Grid file exists after saving",  -			   LLFile::isfile("grid_test.xml")); -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		// should not be there -		std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->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 -		LLGridManager::getInstance()->addGrid(grid); -		LLGridManager::getInstance()->setGridChoice("mynewgridname"); -		LLGridManager::getInstance()->setFavorite(); -		LLGridManager::getInstance()->saveFavorites(); -		ensure("Grid file exists after saving",  -			   LLFile::isfile("grid_test.xml")); -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		// should not be there -		known_grids = LLGridManager::getInstance()->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::getInstance()->initialize("grid_test.xml"); -		LLSD grid = LLSD::emptyMap(); -		grid[GRID_VALUE] = std::string("mynewgridname"); -		LLGridManager::getInstance()->addGrid(grid); -		LLGridManager::getInstance()->saveFavorites(); -		// validate we didn't lose existing favorites -		LLGridManager::getInstance()->initialize("grid_test.xml"); -		std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->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 -		LLGridManager::getInstance()->addGrid(grid); -		LLGridManager::getInstance()->setGridChoice("mynewgridname"); -		LLGridManager::getInstance()->setFavorite(); -		LLGridManager::getInstance()->saveFavorites(); -		known_grids = LLGridManager::getInstance()->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 = LLGridManager::getInstance()->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/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 659da31007..18ac10fe38 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -397,15 +397,6 @@ class WindowsManifest(ViewerManifest):          self.disable_manifest_check() -        # Diamondware Runtimes -        if self.prefix(src="diamondware-runtime/i686-win32", dst=""): -            self.path("SLVoice_dwTVC.exe") -            self.path("libcurl.dll") -            self.path("libeay32.dll") -            self.path("ssleay32.dll") -            self.path("zlib1.dll") -            self.end_prefix() -          # pull in the crash logger and updater from other projects          # tag:"crash-logger" here as a cue to the exporter          self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], @@ -615,9 +606,6 @@ class DarwinManifest(ViewerManifest):                  self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib")                  self.path("vivox-runtime/universal-darwin/libvivoxplatform.dylib", "libvivoxplatform.dylib")                  self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") -                # DiamondWare runtime                                            -                self.path("diamondware-runtime/universal-darwin/SLVoice_dwTVC","SLVoice_dwTVC") -                self.path("diamondware-runtime/universal-darwin/libfmodex.dylib", "libfmodex.dylib")                  libdir = "../../libraries/universal-darwin/lib_release"                  dylibs = {} @@ -913,11 +901,6 @@ class Linux_i686Manifest(LinuxManifest):                      pass              self.end_prefix("lib") -            # Diamondware runtimes -            if self.prefix(src="diamondware-runtime/i686-linux", dst="bin"): -                    self.path("SLVoice_dwTVC") -                    self.end_prefix() -              # Vivox runtimes              if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):                      self.path("SLVoice")  | 
