summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorLoren Shih <seraph@lindenlab.com>2010-04-07 14:47:25 -0400
committerLoren Shih <seraph@lindenlab.com>2010-04-07 14:47:25 -0400
commit52293aa4bb7af45d2c3733f20982f4acb030c2d8 (patch)
treef963815f91b6259ea403d41807d19b69e759897e /indra
parent516ec63f52245a777725d29efe3c35e4e4e72936 (diff)
parent8ac6310020bd2d524c97c729c29a0afe4a529ecf (diff)
automated merge
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/lluri.cpp3
-rw-r--r--indra/llcommon/lluuid.cpp162
-rw-r--r--indra/llmessage/llcurl.cpp29
-rw-r--r--indra/llmessage/llcurl.h12
-rw-r--r--indra/llmessage/llhttpclient.cpp16
-rw-r--r--indra/llmessage/llhttpclient.h11
-rw-r--r--indra/llmessage/llurlrequest.cpp51
-rw-r--r--indra/llmessage/llurlrequest.h68
-rw-r--r--indra/llui/llurlentry.cpp31
-rw-r--r--indra/llui/llurlregistry.cpp1
-rw-r--r--indra/llui/tests/llurlentry_test.cpp26
-rw-r--r--indra/llvfs/lldir.cpp39
-rw-r--r--indra/llvfs/lldir.h4
-rw-r--r--indra/newview/CMakeLists.txt55
-rw-r--r--indra/newview/Info-SecondLife.plist28
-rw-r--r--indra/newview/app_settings/settings.xml119
-rw-r--r--indra/newview/installers/windows/installer_template.nsi6
-rw-r--r--indra/newview/llagent.cpp14
-rw-r--r--indra/newview/llagent.h5
-rw-r--r--indra/newview/llagentlistener.cpp5
-rw-r--r--indra/newview/llagentui.cpp17
-rw-r--r--indra/newview/llagentui.h4
-rw-r--r--indra/newview/llappviewer.cpp197
-rw-r--r--indra/newview/llappviewer.h3
-rw-r--r--indra/newview/llappviewerlinux.cpp2
-rw-r--r--indra/newview/llappviewermacosx.cpp1
-rw-r--r--indra/newview/llavataractions.cpp2
-rw-r--r--indra/newview/llbottomtray.cpp4
-rw-r--r--indra/newview/llcallfloater.cpp31
-rw-r--r--indra/newview/llcallingcard.cpp1
-rw-r--r--indra/newview/llchathistory.cpp15
-rw-r--r--indra/newview/llcurrencyuimanager.cpp2
-rw-r--r--indra/newview/llfloaterabout.cpp14
-rw-r--r--indra/newview/llfloaterbuyland.cpp4
-rw-r--r--indra/newview/llfloaterchat.cpp2
-rw-r--r--indra/newview/llfloaterchatterbox.cpp2
-rw-r--r--indra/newview/llfloaterevent.cpp2
-rw-r--r--indra/newview/llfloatergodtools.cpp1
-rw-r--r--indra/newview/llfloaterland.cpp16
-rw-r--r--indra/newview/llfloaterland.h5
-rw-r--r--indra/newview/llfloaterpreference.cpp8
-rw-r--r--indra/newview/llfloaterregioninfo.cpp3
-rw-r--r--indra/newview/llfloaterreporter.cpp12
-rw-r--r--indra/newview/llfloatersnapshot.cpp22
-rw-r--r--indra/newview/llfloatertos.cpp44
-rw-r--r--indra/newview/llfloatertos.h7
-rw-r--r--indra/newview/llfloatervoicedevicesettings.cpp41
-rw-r--r--indra/newview/llfloaterworldmap.cpp25
-rw-r--r--indra/newview/llfloaterworldmap.h3
-rw-r--r--indra/newview/llgrouplist.cpp2
-rw-r--r--indra/newview/llimfloater.cpp1
-rw-r--r--indra/newview/llimpanel.cpp14
-rw-r--r--indra/newview/llimview.cpp27
-rw-r--r--indra/newview/llinspectavatar.cpp8
-rw-r--r--indra/newview/llinspectobject.cpp6
-rw-r--r--indra/newview/llinspectremoteobject.cpp4
-rw-r--r--indra/newview/llinventorymodel.cpp1
-rw-r--r--indra/newview/lllandmarkactions.cpp4
-rw-r--r--indra/newview/lllocationinputctrl.cpp9
-rw-r--r--indra/newview/llloginhandler.cpp200
-rw-r--r--indra/newview/llloginhandler.h11
-rw-r--r--indra/newview/lllogininstance.cpp77
-rw-r--r--indra/newview/lllogininstance.h7
-rw-r--r--indra/newview/llnavigationbar.cpp34
-rw-r--r--indra/newview/llnotificationtiphandler.cpp4
-rw-r--r--indra/newview/lloutputmonitorctrl.cpp8
-rw-r--r--indra/newview/lloutputmonitorctrl.h2
-rw-r--r--indra/newview/lloverlaybar.cpp2
-rw-r--r--indra/newview/llpanelavatar.cpp8
-rw-r--r--indra/newview/llpaneleditwearable.cpp21
-rw-r--r--indra/newview/llpaneleditwearable.h4
-rw-r--r--indra/newview/llpanelgroup.cpp4
-rw-r--r--indra/newview/llpanelgrouplandmoney.cpp2
-rw-r--r--indra/newview/llpanelimcontrolpanel.cpp5
-rw-r--r--indra/newview/llpanellogin.cpp542
-rw-r--r--indra/newview/llpanellogin.h29
-rw-r--r--indra/newview/llpaneloutfitedit.cpp75
-rw-r--r--indra/newview/llpaneloutfitedit.h13
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp21
-rw-r--r--indra/newview/llpaneloutfitsinventory.h2
-rw-r--r--indra/newview/llpanelpeople.cpp4
-rw-r--r--indra/newview/llpanelplacestab.cpp5
-rw-r--r--indra/newview/llparticipantlist.cpp3
-rw-r--r--indra/newview/llscreenchannel.cpp4
-rw-r--r--indra/newview/llsecapi.cpp161
-rw-r--r--indra/newview/llsecapi.h493
-rw-r--r--indra/newview/llsechandler_basic.cpp1586
-rw-r--r--indra/newview/llsechandler_basic.h285
-rw-r--r--indra/newview/llselectmgr.cpp8
-rw-r--r--indra/newview/llsidepanelappearance.cpp6
-rw-r--r--indra/newview/llslurl.cpp514
-rw-r--r--indra/newview/llslurl.h159
-rw-r--r--indra/newview/llspeakbutton.cpp10
-rw-r--r--indra/newview/llspeakers.cpp40
-rw-r--r--indra/newview/llspeakingindicatormanager.cpp4
-rw-r--r--indra/newview/llstartup.cpp722
-rw-r--r--indra/newview/llstartup.h17
-rw-r--r--indra/newview/llstylemap.cpp2
-rw-r--r--indra/newview/lltexturecache.cpp59
-rw-r--r--indra/newview/lltexturecache.h3
-rw-r--r--indra/newview/llurl.cpp6
-rw-r--r--indra/newview/llurl.h1
-rw-r--r--indra/newview/llurldispatcher.cpp201
-rw-r--r--indra/newview/llurldispatcher.h19
-rw-r--r--indra/newview/llurllineeditorctrl.cpp2
-rw-r--r--indra/newview/llvieweraudio.cpp10
-rw-r--r--indra/newview/llviewercontrol.cpp3
-rw-r--r--indra/newview/llviewerinventory.cpp13
-rw-r--r--indra/newview/llviewermenu.cpp27
-rw-r--r--indra/newview/llviewermessage.cpp23
-rw-r--r--indra/newview/llviewernetwork.cpp694
-rw-r--r--indra/newview/llviewernetwork.h182
-rw-r--r--indra/newview/llviewerobject.cpp12
-rw-r--r--indra/newview/llviewerstats.cpp6
-rw-r--r--indra/newview/llviewerwindow.cpp33
-rw-r--r--indra/newview/llvoavatar.cpp15
-rw-r--r--indra/newview/llvoicechannel.cpp64
-rw-r--r--indra/newview/llvoicechannel.h3
-rw-r--r--indra/newview/llvoiceclient.cpp7224
-rw-r--r--indra/newview/llvoiceclient.h1022
-rw-r--r--indra/newview/llvoicevivox.cpp6967
-rw-r--r--indra/newview/llvoicevivox.h914
-rw-r--r--indra/newview/llweb.cpp2
-rw-r--r--indra/newview/llworld.cpp3
-rw-r--r--indra/newview/llxmlrpclistener.cpp18
-rw-r--r--indra/newview/llxmlrpctransaction.cpp102
-rw-r--r--indra/newview/llxmlrpctransaction.h3
-rw-r--r--indra/newview/skins/default/xui/en/floater_about.xml13
-rw-r--r--indra/newview/skins/default/xui/en/floater_god_tools.xml8
-rw-r--r--indra/newview/skins/default/xui/en/floater_report_abuse.xml7
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml30
-rw-r--r--indra/newview/skins/default/xui/en/floater_tos.xml5
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml11
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml63
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_alpha.xml53
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_eyes.xml55
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_gloves.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_hair.xml55
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_jacket.xml61
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_pants.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shape.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shirt.xml47
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shoes.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_skin.xml57
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_skirt.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_socks.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_tattoo.xml37
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_underpants.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_undershirt.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_wearable.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_login.xml88
-rw-r--r--indra/newview/skins/default/xui/en/panel_online_status_toast.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfit_edit.xml5
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_status_bar.xml8
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml9
-rw-r--r--indra/newview/skins/default/xui/es/floater_customize.xml14
-rw-r--r--indra/newview/skins/default/xui/es/floater_incoming_call.xml2
-rw-r--r--indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml6
-rw-r--r--indra/newview/skins/default/xui/es/floater_land_holdings.xml2
-rw-r--r--indra/newview/skins/default/xui/es/floater_preferences.xml4
-rw-r--r--indra/newview/skins/default/xui/es/floater_tools.xml8
-rw-r--r--indra/newview/skins/default/xui/es/menu_attachment_self.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_avatar_self.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_land.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_object.xml4
-rw-r--r--indra/newview/skins/default/xui/es/menu_participant_list.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_people_nearby.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_people_nearby_multiselect.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_viewer.xml2
-rw-r--r--indra/newview/skins/default/xui/es/notifications.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_classified.xml2
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_pick.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_notes.xml2
-rw-r--r--indra/newview/skins/default/xui/es/panel_people.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_region_general.xml3
-rw-r--r--indra/newview/skins/default/xui/es/panel_side_tray.xml14
-rw-r--r--indra/newview/skins/default/xui/es/strings.xml6
-rw-r--r--indra/newview/skins/default/xui/es/teleport_strings.xml14
-rw-r--r--indra/newview/skins/default/xui/fr/floater_preferences.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/floater_tools.xml6
-rw-r--r--indra/newview/skins/default/xui/it/floater_about_land.xml2
-rw-r--r--indra/newview/skins/default/xui/it/floater_buy_land.xml38
-rw-r--r--indra/newview/skins/default/xui/it/floater_preferences.xml4
-rw-r--r--indra/newview/skins/default/xui/it/floater_tools.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_group_invite.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_login.xml11
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_sound.xml4
-rw-r--r--indra/newview/skins/default/xui/it/role_actions.xml2
-rw-r--r--indra/newview/skins/default/xui/it/strings.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/floater_report_abuse.xml2
-rw-r--r--indra/newview/skins/default/xui/pl/panel_preferences_sound.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/floater_preferences.xml4
-rw-r--r--indra/newview/tests/lllogininstance_test.cpp115
-rw-r--r--indra/newview/tests/llsecapi_test.cpp188
-rw-r--r--indra/newview/tests/llsechandler_basic_test.cpp964
-rw-r--r--indra/newview/tests/llslurl_test.cpp258
-rw-r--r--indra/newview/tests/llviewernetwork_test.cpp486
-rwxr-xr-xindra/newview/viewer_manifest.py17
-rw-r--r--indra/viewer_components/login/lllogin.cpp43
201 files changed, 10541 insertions, 16697 deletions
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp
index 0e8f3f0f73..9d4f3a98f0 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -231,8 +231,7 @@ static BOOL isDefault(const std::string& scheme, U16 port)
void LLURI::parseAuthorityAndPathUsingOpaque()
{
if (mScheme == "http" || mScheme == "https" ||
- mScheme == "ftp" || mScheme == "secondlife" ||
- mScheme == "x-grid-location-info")
+ mScheme == "ftp" || mScheme == "secondlife" )
{
if (mEscapedOpaque.substr(0,2) != "//")
{
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index 583c1e589b..bcbae06ec5 100644
--- a/indra/llcommon/lluuid.cpp
+++ b/indra/llcommon/lluuid.cpp
@@ -33,12 +33,9 @@
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
#if LL_WINDOWS
-#undef WIN32_LEAN_AND_MEAN
-#include <winsock2.h>
-#include <windows.h>
-// ugh, this is ugly. We need to straighten out our linking for this library
-#pragma comment(lib, "IPHLPAPI.lib")
-#include <iphlpapi.h>
+# undef WIN32_LEAN_AND_MEAN
+# include <winsock2.h>
+# include <windows.h>
#endif
#include "lldefs.h"
@@ -455,102 +452,67 @@ static void get_random_bytes(void *buf, int nbytes)
return;
}
-#if LL_WINDOWS
-// Code copied from http://msdn.microsoft.com/en-us/library/aa365939(VS.85).aspx
-// This code grabs the first hardware address, rather than the first interface.
-// Using a VPN can cause the first returned interface to be changed.
-
-const S32 MAC_ADDRESS_BYTES=6;
-
-
-// static
-S32 LLUUID::getNodeID(unsigned char *node_id)
+#if LL_WINDOWS
+typedef struct _ASTAT_
{
+ ADAPTER_STATUS adapt;
+ NAME_BUFFER NameBuff [30];
+}ASTAT, * PASTAT;
- // Declare and initialize variables.
- DWORD dwSize = 0;
- DWORD dwRetVal = 0;
- int i;
-
-/* variables used for GetIfTable and GetIfEntry */
- MIB_IFTABLE *pIfTable;
- MIB_IFROW *pIfRow;
-
- // Allocate memory for our pointers.
- pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE));
- if (pIfTable == NULL)
- {
- printf("Error allocating memory needed to call GetIfTable\n");
- return 0;
- }
-
- // Before calling GetIfEntry, we call GetIfTable to make
- // sure there are entries to get and retrieve the interface index.
-
- // Make an initial call to GetIfTable to get the
- // necessary size into dwSize
- if (GetIfTable(pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
- free(pIfTable);
- pIfTable = (MIB_IFTABLE *) malloc(dwSize);
- if (pIfTable == NULL)
- {
- printf("Error allocating memory\n");
- return 0;
- }
- }
- // Make a second call to GetIfTable to get the actual
- // data we want.
- if ((dwRetVal = GetIfTable(pIfTable, &dwSize, 0)) == NO_ERROR)
- {
- if (pIfTable->dwNumEntries > 0)
- {
- pIfRow = (MIB_IFROW *) malloc(sizeof (MIB_IFROW));
- if (pIfRow == NULL)
- {
- printf("Error allocating memory\n");
- if (pIfTable != NULL)
- {
- free(pIfTable);
- pIfTable = NULL;
- }
- return 0;
- }
-
- int limit = MAC_ADDRESS_BYTES;
- memcpy(node_id, "\0\0\0\0\0\0", limit); // zero out array of bytes
- for (i = 0; i < (int) pIfTable->dwNumEntries; i++)
- {
- pIfRow->dwIndex = pIfTable->table[i].dwIndex;
- if ((dwRetVal = GetIfEntry(pIfRow)) == NO_ERROR)
- {
- switch (pIfRow->dwType)
- {
- case IF_TYPE_ETHERNET_CSMACD:
- case IF_TYPE_IEEE80211:
- limit = min((int) pIfRow->dwPhysAddrLen, limit);
- if (pIfRow->dwPhysAddrLen == 0)
- break;
- memcpy(node_id, (UCHAR *)&pIfRow->bPhysAddr[0], limit); // just incase the PhysAddr is not the expected MAC_Address size
- free(pIfTable);
- return 1; //return first hardware device found.
- break;
-
- case IF_TYPE_OTHER:
- case IF_TYPE_PPP:
- case IF_TYPE_SOFTWARE_LOOPBACK:
- case IF_TYPE_ISO88025_TOKENRING:
- case IF_TYPE_IEEE1394:
- case IF_TYPE_ATM:
- case IF_TYPE_TUNNEL:
- default:
- break;
- }
- }
- }
- }
- }
- free(pIfTable);
- return 0;
+// static
+S32 LLUUID::getNodeID(unsigned char * node_id)
+{
+ ASTAT Adapter;
+ NCB Ncb;
+ UCHAR uRetCode;
+ LANA_ENUM lenum;
+ int i;
+ int retval = 0;
+
+ memset( &Ncb, 0, sizeof(Ncb) );
+ Ncb.ncb_command = NCBENUM;
+ Ncb.ncb_buffer = (UCHAR *)&lenum;
+ Ncb.ncb_length = sizeof(lenum);
+ uRetCode = Netbios( &Ncb );
+ // printf( "The NCBENUM return code is: 0x%x \n", uRetCode );
+
+ for(i=0; i < lenum.length ;i++)
+ {
+ memset( &Ncb, 0, sizeof(Ncb) );
+ Ncb.ncb_command = NCBRESET;
+ Ncb.ncb_lana_num = lenum.lana[i];
+
+ uRetCode = Netbios( &Ncb );
+ // printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
+ // lenum.lana[i], uRetCode );
+
+ memset( &Ncb, 0, sizeof (Ncb) );
+ Ncb.ncb_command = NCBASTAT;
+ Ncb.ncb_lana_num = lenum.lana[i];
+
+ strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */
+ Ncb.ncb_buffer = (unsigned char *)&Adapter;
+ Ncb.ncb_length = sizeof(Adapter);
+
+ uRetCode = Netbios( &Ncb );
+// printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
+// lenum.lana[i], uRetCode );
+ if ( uRetCode == 0 )
+ {
+// printf( "The Ethernet Number on LANA %d is: %02x%02x%02x%02x%02x%02x\n",
+// lenum.lana[i],
+// Adapter.adapt.adapter_address[0],
+// Adapter.adapt.adapter_address[1],
+// Adapter.adapt.adapter_address[2],
+// Adapter.adapt.adapter_address[3],
+// Adapter.adapt.adapter_address[4],
+// Adapter.adapt.adapter_address[5] );
+ memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */
+ retval = 1;
+
+ }
+ }
+ return retval;
}
#elif LL_DARWIN
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 91e11b8c0d..024e17a777 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -89,6 +89,10 @@ S32 gCurlMultiCount = 0;
std::vector<LLMutex*> LLCurl::sSSLMutex;
std::string LLCurl::sCAPath;
std::string LLCurl::sCAFile;
+// Verify SSL certificates by default (matches libcurl default). The ability
+// to alter this flag is only to allow us to suppress verification if it's
+// broken for some reason.
+bool LLCurl::sSSLVerify = true;
//static
void LLCurl::setCAPath(const std::string& path)
@@ -103,6 +107,18 @@ void LLCurl::setCAFile(const std::string& file)
}
//static
+void LLCurl::setSSLVerify(bool verify)
+{
+ sSSLVerify = verify;
+}
+
+//static
+bool LLCurl::getSSLVerify()
+{
+ return sSSLVerify;
+}
+
+//static
std::string LLCurl::getVersionString()
{
return std::string(curl_version());
@@ -465,7 +481,8 @@ void LLCurl::Easy::prepRequest(const std::string& url,
setErrorBuffer();
setCA();
- setopt(CURLOPT_SSL_VERIFYPEER, true);
+ setopt(CURLOPT_SSL_VERIFYPEER, LLCurl::getSSLVerify());
+ setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify()? 2 : 0);
setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
setoptString(CURLOPT_URL, url);
@@ -895,15 +912,6 @@ void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userd
}
}
-void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata)
-{
- if (mEasy)
- {
- mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata);
- }
-}
-
void LLCurlEasyRequest::slist_append(const char* str)
{
if (mEasy)
@@ -1053,4 +1061,3 @@ void LLCurl::cleanupClass()
#endif
curl_global_cleanup();
}
-
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index b6a637ae5b..caf02cccd9 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -158,6 +158,16 @@ public:
static const std::string& getCAPath() { return sCAPath; }
/**
+ * @ brief Set flag controlling whether to verify HTTPS certs.
+ */
+ static void setSSLVerify(bool verify);
+
+ /**
+ * @ brief Get flag controlling whether to verify HTTPS certs.
+ */
+ static bool getSSLVerify();
+
+ /**
* @ brief Initialize LLCurl class
*/
static void initClass();
@@ -182,6 +192,7 @@ public:
private:
static std::string sCAPath;
static std::string sCAFile;
+ static bool sSSLVerify;
};
namespace boost
@@ -229,7 +240,6 @@ public:
void setHeaderCallback(curl_header_callback callback, void* userdata);
void setWriteCallback(curl_write_callback callback, void* userdata);
void setReadCallback(curl_read_callback callback, void* userdata);
- void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
void slist_append(const char* str);
void sendRequest(const std::string& url);
void requestComplete();
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index 345b76d1a1..dd56e18caf 100644
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -31,7 +31,7 @@
*/
#include "linden_common.h"
-#include <openssl/x509_vfy.h>
+
#include "llhttpclient.h"
#include "llassetstorage.h"
@@ -46,10 +46,7 @@
#include "message.h"
#include <curl/curl.h>
-
const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
-LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL;
-
////////////////////////////////////////////////////////////////////////////
// Responder class moved to LLCurl
@@ -209,19 +206,13 @@ namespace
LLPumpIO* theClientPump = NULL;
}
-void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback)
-{
- LLHTTPClient::mCertVerifyCallback = callback;
-}
-
static void request(
const std::string& url,
LLURLRequest::ERequestAction method,
Injector* body_injector,
LLCurl::ResponderPtr responder,
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
- const LLSD& headers = LLSD()
- )
+ const LLSD& headers = LLSD())
{
if (!LLHTTPClient::hasPump())
{
@@ -231,7 +222,7 @@ static void request(
LLPumpIO::chain_t chain;
LLURLRequest* req = new LLURLRequest(method, url);
- req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
+ req->checkRootCertificate(LLCurl::getSSLVerify());
lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " "
@@ -426,6 +417,7 @@ static LLSD blocking_request(
std::string body_str;
// other request method checks root cert first, we skip?
+ //req->checkRootCertificate(true);
// * Set curl handle options
curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts
diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h
index 8afbc9e0fc..3d0646e5fe 100644
--- a/indra/llmessage/llhttpclient.h
+++ b/indra/llmessage/llhttpclient.h
@@ -40,8 +40,7 @@
#include <string>
#include <boost/intrusive_ptr.hpp>
-#include <openssl/x509_vfy.h>
-#include "llurlrequest.h"
+
#include "llassettype.h"
#include "llcurl.h"
#include "lliopipe.h"
@@ -62,7 +61,6 @@ public:
typedef LLCurl::Responder Responder;
typedef LLCurl::ResponderPtr ResponderPtr;
-
/** @name non-blocking API */
//@{
static void head(
@@ -157,12 +155,7 @@ public:
static void setPump(LLPumpIO& pump);
///< must be called before any of the above calls are made
static bool hasPump();
-
- static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback);
- static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; }
-
-protected:
- static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback;
+ ///< for testing
};
#endif // LL_LLHTTPCLIENT_H
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index 1e76d10828..4e7ceff984 100644
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -36,8 +36,7 @@
#include "llurlrequest.h"
#include <algorithm>
-#include <openssl/x509_vfy.h>
-#include <openssl/ssl.h>
+
#include "llcurl.h"
#include "llioutil.h"
#include "llmemtype.h"
@@ -57,8 +56,6 @@ const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
-
-
/**
* class LLURLRequestDetail
*/
@@ -75,7 +72,6 @@ public:
U32 mBodyLimit;
S32 mByteAccumulator;
bool mIsBodyLimitSet;
- LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback;
};
LLURLRequestDetail::LLURLRequestDetail() :
@@ -84,8 +80,7 @@ LLURLRequestDetail::LLURLRequestDetail() :
mLastRead(NULL),
mBodyLimit(0),
mByteAccumulator(0),
- mIsBodyLimitSet(false),
- mSSLVerifyCallback(NULL)
+ mIsBodyLimitSet(false)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
mCurlRequest = new LLCurlEasyRequest();
@@ -99,36 +94,6 @@ LLURLRequestDetail::~LLURLRequestDetail()
mLastRead = NULL;
}
-void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param)
-{
- mDetail->mSSLVerifyCallback = callback;
- mDetail->mCurlRequest->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this);
- mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, true);
- mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, 2);
-}
-
-
-// _sslCtxFunction
-// Callback function called when an SSL Context is created via CURL
-// used to configure the context for custom cert validation
-
-CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
-{
- LLURLRequest *req = (LLURLRequest *)param;
- if(req == NULL || req->mDetail->mSSLVerifyCallback == NULL)
- {
- SSL_CTX_set_cert_verify_callback((SSL_CTX *)sslctx, NULL, NULL);
- return CURLE_OK;
- }
- 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, req->mDetail->mSSLVerifyCallback, (void *)req);
- // the calls are void
- return CURLE_OK;
-
-}
/**
* class LLURLRequest
@@ -183,11 +148,6 @@ void LLURLRequest::setURL(const std::string& url)
mDetail->mURL = url;
}
-std::string LLURLRequest::getURL() const
-{
- return mDetail->mURL;
-}
-
void LLURLRequest::addHeader(const char* header)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
@@ -200,6 +160,13 @@ void LLURLRequest::setBodyLimit(U32 size)
mDetail->mIsBodyLimitSet = true;
}
+void LLURLRequest::checkRootCertificate(bool check)
+{
+ mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, (check? TRUE : FALSE));
+ mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, (check? 2 : 0));
+ mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
+}
+
void LLURLRequest::setCallback(LLURLRequestComplete* callback)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h
index 69fd22e592..cb3c466440 100644
--- a/indra/llmessage/llurlrequest.h
+++ b/indra/llmessage/llurlrequest.h
@@ -44,8 +44,6 @@
#include "lliopipe.h"
#include "llchainio.h"
#include "llerror.h"
-#include <openssl/x509_vfy.h>
-#include "llcurl.h"
extern const std::string CONTEXT_REQUEST;
@@ -74,8 +72,6 @@ class LLURLRequest : public LLIOPipe
{
LOG_CLASS(LLURLRequest);
public:
-
- typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param);
/**
* @brief This enumeration is for specifying the type of request.
*/
@@ -129,7 +125,7 @@ public:
*
*/
void setURL(const std::string& url);
- std::string getURL() const;
+
/**
* @brief Add a header to the http post.
*
@@ -147,9 +143,8 @@ public:
* Set whether request will check that remote server
* certificates are signed by a known root CA when using HTTPS.
*/
- void setSSLVerifyCallback(SSLCertVerifyCallback callback, void * param);
+ void checkRootCertificate(bool check);
-
/**
* @brief Return at most size bytes of body.
*
@@ -194,7 +189,6 @@ public:
* @brief Give this pipe a chance to handle a generated error
*/
virtual EStatus handleError(EStatus status, LLPumpIO* pump);
-
protected:
/**
@@ -223,8 +217,6 @@ protected:
S32 mRequestTransferedBytes;
S32 mResponseTransferedBytes;
- static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);
-
private:
/**
* @brief Initialize the object. Called during construction.
@@ -372,6 +364,62 @@ protected:
};
+/**
+ * @class LLURLRequestClientFactory
+ * @brief Template class to build url request based client chains
+ *
+ * This class eases construction of a basic sd rpc client. Here is an
+ * example of it's use:
+ * <code>
+ * class LLUsefulService : public LLService { ... }<br>
+ * LLService::registerCreator(<br>
+ * "useful",<br>
+ * LLService::creator_t(new LLURLRequestClientFactory<LLUsefulService>))<br>
+ * </code>
+ *
+ * This class should work, but I never got around to using/testing it.
+ *
+ */
+#if 0
+template<class Client>
+class LLURLRequestClientFactory : public LLChainIOFactory
+{
+public:
+ LLURLRequestClientFactory(LLURLRequest::ERequestAction action) {}
+ LLURLRequestClientFactory(
+ LLURLRequest::ERequestAction action,
+ const std::string& fixed_url) :
+ mAction(action),
+ mURL(fixed_url)
+ {
+ }
+ virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
+ {
+ lldebugs << "LLURLRequestClientFactory::build" << llendl;
+ LLIOPipe::ptr_t service(new Client);
+ chain.push_back(service);
+ LLURLRequest* http(new LLURLRequest(mAction));
+ LLIOPipe::ptr_t http_pipe(http);
+ // *FIX: how do we know the content type?
+ //http->addHeader("Content-Type: text/llsd");
+ if(mURL.empty())
+ {
+ chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
+ }
+ else
+ {
+ http->setURL(mURL);
+ }
+ chain.push_back(http_pipe);
+ chain.push_back(service);
+ return true;
+ }
+
+protected:
+ LLURLRequest::ERequestAction mAction;
+ std::string mURL;
+};
+#endif
/**
* External constants
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index d7666ca4c3..736de651da 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -41,9 +41,6 @@
#include "lltrans.h"
#include "lluicolortable.h"
-#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
-
-
LLUrlEntryBase::LLUrlEntryBase() :
mColor(LLUIColorTable::instance().getColor("HTMLLinkColor")),
mDisabledLink(false)
@@ -306,11 +303,10 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
//
// LLUrlEntryAgent Describes a Second Life agent Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
-// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
//
LLUrlEntryAgent::LLUrlEntryAgent()
{
- mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+",
+ mPattern = boost::regex("secondlife:///app/agent/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_agent.xml";
mIcon = "Generic_Person";
@@ -422,11 +418,10 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect
-// x-grid-location-info://lincoln.lindenlab.com/app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect
//
LLUrlEntryGroup::LLUrlEntryGroup()
{
- mPattern = boost::regex(APP_HEADER_REGEX "/group/[\\da-f-]+/\\w+",
+ mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_group.xml";
mIcon = "Generic_Group";
@@ -487,8 +482,7 @@ LLUrlEntryInventory::LLUrlEntryInventory()
//*TODO: add supporting of inventory item names with whitespaces
//this pattern cann't parse for example
//secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces&param2=value
- //x-grid-location-info://lincoln.lindenlab.com/app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces&param2=value
- mPattern = boost::regex(APP_HEADER_REGEX "/inventory/[\\da-f-]+/\\w+\\S*",
+ mPattern = boost::regex("secondlife:///app/inventory/[\\da-f-]+/\\w+\\S*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_inventory.xml";
}
@@ -531,11 +525,10 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const
///
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
-/// x-grid-location-info://lincoln.lindenlab.com/app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
///
LLUrlEntryParcel::LLUrlEntryParcel()
{
- mPattern = boost::regex(APP_HEADER_REGEX "/parcel/[\\da-f-]+/about",
+ mPattern = boost::regex("secondlife:///app/parcel/[\\da-f-]+/about",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_parcel.xml";
mTooltip = LLTrans::getString("TooltipParcelUrl");
@@ -551,7 +544,7 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC
//
LLUrlEntryPlace::LLUrlEntryPlace()
{
- mPattern = boost::regex("((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?",
+ mPattern = boost::regex("secondlife://\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_slurl.xml";
mTooltip = LLTrans::getString("TooltipSLURL");
@@ -596,11 +589,10 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const
//
// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
// secondlife:///app/teleport/Ahern/50/50/50/
-// x-grid-location-info://lincoln.lindenlab.com/app/teleport/Ahern/50/50/50/
//
LLUrlEntryTeleport::LLUrlEntryTeleport()
{
- mPattern = boost::regex(APP_HEADER_REGEX "/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*",
+ mPattern = boost::regex("secondlife:///app/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_teleport.xml";
mTooltip = LLTrans::getString("TooltipTeleportUrl");
@@ -618,12 +610,7 @@ std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabe
LLURI uri(url);
LLSD path_array = uri.pathArray();
S32 path_parts = path_array.size();
- std::string host = uri.hostName();
- std::string label = LLTrans::getString("SLurlLabelTeleport");
- if (!host.empty())
- {
- label += " " + host;
- }
+ const std::string label = LLTrans::getString("SLurlLabelTeleport");
if (path_parts == 6)
{
// handle teleport url with (X,Y,Z) coordinates
@@ -722,7 +709,7 @@ std::string LLUrlEntrySLLabel::getTooltip(const std::string &string) const
//
LLUrlEntryWorldMap::LLUrlEntryWorldMap()
{
- mPattern = boost::regex(APP_HEADER_REGEX "/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*",
+ mPattern = boost::regex("secondlife:///app/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_map.xml";
mTooltip = LLTrans::getString("TooltipMapUrl");
@@ -745,7 +732,7 @@ std::string LLUrlEntryWorldMap::getLabel(const std::string &url, const LLUrlLabe
}
const std::string label = LLTrans::getString("SLurlLabelShowOnMap");
- std::string location = path_array[2];
+ std::string location = unescapeUrl(path_array[2]);
std::string x = (path_parts > 3) ? path_array[3] : "128";
std::string y = (path_parts > 4) ? path_array[4] : "128";
std::string z = (path_parts > 5) ? path_array[5] : "0";
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 7e09a5a919..0a70aa586a 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -53,6 +53,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntryParcel());
registerUrl(new LLUrlEntryTeleport());
registerUrl(new LLUrlEntryWorldMap());
+ registerUrl(new LLUrlEntryObjectIM());
registerUrl(new LLUrlEntryPlace());
registerUrl(new LLUrlEntryInventory());
registerUrl(new LLUrlEntryObjectIM());
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 4463b6cc6f..cbb303a059 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -286,13 +286,6 @@ namespace tut
"XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar",
"secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar");
- testRegex("Standalone Agent Url ", url,
- "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about",
- "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
-
- testRegex("Standalone Agent Url Multicase with Text", url,
- "M x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M",
- "x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
}
template<> template<>
@@ -322,15 +315,6 @@ namespace tut
testRegex("Group Url multicase", url,
"XXX secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About XXX",
"secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About");
-
- testRegex("Standalone Group Url ", url,
- "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about",
- "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
-
- testRegex("Standalone Group Url Multicase ith Text", url,
- "M x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M",
- "x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
-
}
template<> template<>
@@ -377,11 +361,7 @@ namespace tut
// DEV-35459: SLURLs and teleport Links not parsed properly
testRegex("SLURL with quote", url,
"XXX secondlife://A'ksha%20Oasis/41/166/701 XXX",
- "secondlife://A%27ksha%20Oasis/41/166/701");
-
- testRegex("Standalone All Hands (50,50) [2] with text", url,
- "XXX x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50 XXX",
- "x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50");
+ "secondlife://A%27ksha%20Oasis/41/166/701");
}
template<> template<>
@@ -481,10 +461,6 @@ namespace tut
testRegex("Teleport url with quote", url,
"XXX secondlife:///app/teleport/A'ksha%20Oasis/41/166/701 XXX",
"secondlife:///app/teleport/A%27ksha%20Oasis/41/166/701");
-
- testRegex("Standalone All Hands", url,
- "XXX x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50 XXX",
- "x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50");
}
template<> template<>
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index b4ee42ef3a..da4abde451 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -459,6 +459,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
}
//llinfos << "*** EXPANDED FILENAME: <" << expanded_filename << ">" << llendl;
+
return expanded_filename;
}
@@ -564,23 +565,27 @@ std::string LLDir::getForbiddenFileChars()
return "\\/:*?\"<>|";
}
-void LLDir::setLindenUserDir(const std::string &username)
+void LLDir::setLindenUserDir(const std::string &first, const std::string &last)
{
- // if the username isn't set, that's bad
- if (!username.empty())
+ // if both first and last aren't set, that's bad.
+ if (!first.empty() && !last.empty())
{
// some platforms have case-sensitive filesystems, so be
// utterly consistent with our firstname/lastname case.
- std::string userlower(username);
- LLStringUtil::toLower(userlower);
- LLStringUtil::replaceChar(userlower, ' ', '_');
+ std::string firstlower(first);
+ LLStringUtil::toLower(firstlower);
+ std::string lastlower(last);
+ LLStringUtil::toLower(lastlower);
mLindenUserDir = getOSUserAppDir();
mLindenUserDir += mDirDelimiter;
- mLindenUserDir += userlower;
+ mLindenUserDir += firstlower;
+ mLindenUserDir += "_";
+ mLindenUserDir += lastlower;
+ llinfos << "Got name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
}
else
{
- llerrs << "NULL name for LLDir::setLindenUserDir" << llendl;
+ llerrs << "Invalid name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
}
dumpCurrentDirectories();
@@ -598,25 +603,27 @@ void LLDir::setChatLogsDir(const std::string &path)
}
}
-void LLDir::setPerAccountChatLogsDir(const std::string &username)
+void LLDir::setPerAccountChatLogsDir(const std::string &first, const std::string &last)
{
// if both first and last aren't set, assume we're grabbing the cached dir
- if (!username.empty())
+ if (!first.empty() && !last.empty())
{
// some platforms have case-sensitive filesystems, so be
// utterly consistent with our firstname/lastname case.
- std::string userlower(username);
- LLStringUtil::toLower(userlower);
- LLStringUtil::replaceChar(userlower, ' ', '_');
+ std::string firstlower(first);
+ LLStringUtil::toLower(firstlower);
+ std::string lastlower(last);
+ LLStringUtil::toLower(lastlower);
mPerAccountChatLogsDir = getChatLogsDir();
mPerAccountChatLogsDir += mDirDelimiter;
- mPerAccountChatLogsDir += userlower;
+ mPerAccountChatLogsDir += firstlower;
+ mPerAccountChatLogsDir += "_";
+ mPerAccountChatLogsDir += lastlower;
}
else
{
- llerrs << "NULL name for LLDir::setPerAccountChatLogsDir" << llendl;
+ llwarns << "Invalid name for LLDir::setPerAccountChatLogsDir" << llendl;
}
-
}
void LLDir::setSkinFolder(const std::string &skin_folder)
diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 05d5efc66f..9067d75bac 100644
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -137,8 +137,8 @@ class LLDir
static std::string getForbiddenFileChars();
virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir
- virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory.
- virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir
+ virtual void setPerAccountChatLogsDir(const std::string &first, const std::string &last); // Set the per user chat log directory.
+ virtual void setLindenUserDir(const std::string &first, const std::string &last); // Set the linden user dir to this user's dir
virtual void setSkinFolder(const std::string &skin_folder);
virtual bool setCacheDir(const std::string &path);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 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..8b66cce8a3 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 &amp; 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 &amp; 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>
@@ -8184,13 +8128,13 @@
<key>NearbyPeopleSortOrder</key>
<map>
<key>Comment</key>
- <string>Specifies sort order for nearby people (0 = by name, 2 = by most recent)</string>
+ <string>Specifies sort order for nearby people (0 = by name, 3 = by distance, 4 = by most recent)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
- <integer>2</integer>
+ <integer>4</integer>
</map>
<key>RecentPeopleSortOrder</key>
<map>
@@ -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..ec465358fa 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1295,6 +1295,11 @@ void LLAgent::stopAutoPilot(BOOL user_cancel)
{
resetAxes(mAutoPilotTargetFacing);
}
+ // If the user cancelled, don't change the fly state
+ if (!user_cancel)
+ {
+ setFlying(mAutoPilotFlyOnStop);
+ }
//NB: auto pilot can terminate for a reason other than reaching the destination
if (mAutoPilotFinishedCallback)
{
@@ -1302,11 +1307,6 @@ void LLAgent::stopAutoPilot(BOOL user_cancel)
}
mLeaderID = LLUUID::null;
- // If the user cancelled, don't change the fly state
- if (!user_cancel)
- {
- setFlying(mAutoPilotFlyOnStop);
- }
setControlFlags(AGENT_CONTROL_STOP);
if (user_cancel && !mAutoPilotBehaviorName.empty())
@@ -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..8e959993fe 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())
{
- if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString()))
+ slurl = LLURLSimString::getURL();
+ }
+ if (!slurl.empty())
+ {
+ 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
@@ -2966,41 +3016,59 @@ void LLAppViewer::migrateCacheDirectory()
#endif // LL_WINDOWS || LL_DARWIN
}
+//static
+S32 LLAppViewer::getCacheVersion()
+{
+ static const S32 cache_version = 7;
+
+ return cache_version ;
+}
+
bool LLAppViewer::initCache()
{
mPurgeCache = false;
- // Purge cache if user requested it
- if (gSavedSettings.getBOOL("PurgeCacheOnStartup") ||
- gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
+ BOOL disable_texture_cache = FALSE ;
+ BOOL read_only = mSecondInstance ? TRUE : FALSE;
+ LLAppViewer::getTextureCache()->setReadOnly(read_only) ;
+
+ if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getCacheVersion())
{
- gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false);
- mPurgeCache = true;
+ if(read_only)
+ {
+ disable_texture_cache = TRUE ; //if the cache version of this viewer is different from the running one, this viewer can not use the texture cache.
+ }
+ else
+ {
+ mPurgeCache = true; // Purge cache if the version number is different.
+ gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getCacheVersion());
+ }
}
- // Purge cache if it belongs to an old version
- else
+
+ if(!read_only)
{
- static const S32 cache_version = 6;
- if (gSavedSettings.getS32("LocalCacheVersion") != cache_version)
+ // Purge cache if user requested it
+ if (gSavedSettings.getBOOL("PurgeCacheOnStartup") ||
+ gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
{
+ gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false);
mPurgeCache = true;
- gSavedSettings.setS32("LocalCacheVersion", cache_version);
}
- }
- // We have moved the location of the cache directory over time.
- migrateCacheDirectory();
-
- // Setup and verify the cache location
- std::string cache_location = gSavedSettings.getString("CacheLocation");
- std::string new_cache_location = gSavedSettings.getString("NewCacheLocation");
- if (new_cache_location != cache_location)
- {
- gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"));
- purgeCache(); // purge old cache
- gSavedSettings.setString("CacheLocation", new_cache_location);
- gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location));
- }
+ // We have moved the location of the cache directory over time.
+ migrateCacheDirectory();
+ // Setup and verify the cache location
+ std::string cache_location = gSavedSettings.getString("CacheLocation");
+ std::string new_cache_location = gSavedSettings.getString("NewCacheLocation");
+ if (new_cache_location != cache_location)
+ {
+ gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"));
+ purgeCache(); // purge old cache
+ gSavedSettings.setString("CacheLocation", new_cache_location);
+ gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location));
+ }
+ }
+
if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")))
{
LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL;
@@ -3008,7 +3076,7 @@ bool LLAppViewer::initCache()
gSavedSettings.setString("CacheLocationTopFolder", "");
}
- if (mPurgeCache)
+ if (mPurgeCache && !read_only)
{
LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
purgeCache();
@@ -3017,14 +3085,13 @@ bool LLAppViewer::initCache()
LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache"));
// Init the texture cache
- // Allocate 80% of the cache size for textures
- BOOL read_only = mSecondInstance ? TRUE : FALSE;
+ // Allocate 80% of the cache size for textures
const S32 MB = 1024*1024;
S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB;
const S64 MAX_CACHE_SIZE = 1024*MB;
cache_size = llmin(cache_size, MAX_CACHE_SIZE);
S64 texture_cache_size = ((cache_size * 8)/10);
- S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, read_only);
+ S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, disable_texture_cache);
texture_cache_size -= extra;
LLSplashScreen::update(LLTrans::getString("StartupInitializingVFS"));
@@ -3836,7 +3903,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 +4323,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 +4336,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..60645c46d4 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -102,6 +102,8 @@ public:
static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; }
static LLTextureFetch* getTextureFetch() { return sTextureFetch; }
+ static S32 getCacheVersion() ;
+
const std::string& getSerialNumber() { return mSerialNumber; }
bool getPurgeCache() const { return mPurgeCache; }
@@ -191,6 +193,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/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp
index e7b2da043f..bd07cfdfbf 100644
--- a/indra/newview/llfloatergodtools.cpp
+++ b/indra/newview/llfloatergodtools.cpp
@@ -922,6 +922,7 @@ LLPanelObjectTools::~LLPanelObjectTools()
BOOL LLPanelObjectTools::postBuild()
{
+ refresh();
return TRUE;
}
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 25d3f971b5..2ff483cd34 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"
@@ -90,6 +91,7 @@ static std::string MATURITY = "[MATURITY]";
// constants used in callbacks below - syntactic sugar.
static const BOOL BUY_GROUP_LAND = TRUE;
static const BOOL BUY_PERSONAL_LAND = FALSE;
+LLPointer<LLParcelSelection> LLPanelLandGeneral::sSelectionForBuyPass = NULL;
// Statics
LLParcelSelectionObserver* LLFloaterLand::sObserver = NULL;
@@ -803,7 +805,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 +817,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 +826,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
{
@@ -974,6 +976,8 @@ void LLPanelLandGeneral::onClickBuyPass(void* data)
args["PARCEL_NAME"] = parcel_name;
args["TIME"] = time;
+ // creating pointer on selection to avoid deselection of parcel until we are done with buying pass (EXT-6464)
+ sSelectionForBuyPass = LLViewerParcelMgr::getInstance()->getParcelSelection();
LLNotificationsUtil::add("LandBuyPass", args, LLSD(), cbBuyPass);
}
@@ -1005,6 +1009,8 @@ bool LLPanelLandGeneral::cbBuyPass(const LLSD& notification, const LLSD& respons
// User clicked OK
LLViewerParcelMgr::getInstance()->buyPass();
}
+ // we are done with buying pass, additional selection is no longer needed
+ sSelectionForBuyPass = NULL;
return false;
}
diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h
index fe80766a74..0a743e5215 100644
--- a/indra/newview/llfloaterland.h
+++ b/indra/newview/llfloaterland.h
@@ -234,6 +234,11 @@ protected:
LLSafeHandle<LLParcelSelection>& mParcel;
+ // This pointer is needed to avoid parcel deselection until buying pass is completed or canceled.
+ // Deselection happened because of zero references to parcel selection, which took place when
+ // "Buy Pass" was called from popup menu(EXT-6464)
+ static LLPointer<LLParcelSelection> sSelectionForBuyPass;
+
static LLHandle<LLFloater> sBuyPassDialogHandle;
};
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 804ef609ec..60ce16aafb 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -107,6 +107,8 @@
#include "llpluginclassmedia.h"
#include "llteleporthistorystorage.h"
+#include "lllogininstance.h" // to check if logged in yet
+
const F32 MAX_USER_FAR_CLIP = 512.f;
const F32 MIN_USER_FAR_CLIP = 64.f;
@@ -597,7 +599,7 @@ void LLFloaterPreference::onBtnOK()
llinfos << "Can't close preferences!" << llendl;
}
- LLPanelLogin::updateLocationCombo( false );
+ LLPanelLogin::refreshLocation( false );
}
// static
@@ -614,7 +616,7 @@ void LLFloaterPreference::onBtnApply( )
apply();
saveSettings();
- LLPanelLogin::updateLocationCombo( false );
+ LLPanelLogin::refreshLocation( false );
}
// static
@@ -858,6 +860,8 @@ void LLFloaterPreference::refreshEnabledState()
ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders);
// now turn off any features that are unavailable
disableUnavailableSettings();
+
+ childSetEnabled ("block_list", LLLoginInstance::getInstance()->authSuccess());
}
void LLFloaterPreference::disableUnavailableSettings()
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..03389e62d7 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());
@@ -1319,7 +1319,27 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp)
// static
void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
{
+ LLSnapshotLivePreview* previewp = getPreviewView(floater);
+ if (NULL == previewp)
+ {
+ return;
+ }
+
+ // Disable buttons until Snapshot is ready. EXT-6534
+ BOOL got_snap = previewp->getSnapshotUpToDate();
+
+ // process Main buttons
+ floater->childSetEnabled("share", got_snap);
+ floater->childSetEnabled("save", got_snap);
+ floater->childSetEnabled("set_profile_pic", got_snap);
+
+ // process Share actions buttons
+ floater->childSetEnabled("share_to_web", got_snap);
+ floater->childSetEnabled("share_to_email", got_snap);
+ // process Save actions buttons
+ floater->childSetEnabled("save_to_inventory", got_snap);
+ floater->childSetEnabled("save_to_computer", got_snap);
}
// static
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index 69ee8cd547..3db9587797 100644
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -57,7 +57,9 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data)
: LLModalDialog( data["message"].asString() ),
mMessage(data["message"].asString()),
mWebBrowserWindowId( 0 ),
- mLoadCompleteCount( 0 ),
+ mLoadingScreenLoaded(false),
+ mSiteAlive(false),
+ mRealNavigateBegun(false),
mReplyPumpName(data["reply_pump"].asString())
{
}
@@ -138,6 +140,11 @@ BOOL LLFloaterTOS::postBuild()
if ( web_browser )
{
web_browser->addObserver(this);
+
+ // Don't use the start_url parameter for this browser instance -- it may finish loading before we get to add our observer.
+ // Store the URL separately and navigate here instead.
+ web_browser->navigateTo( getString( "loading_url" ) );
+
gResponsePtr = LLIamHere::build( this );
LLHTTPClient::get( getString( "real_url" ), gResponsePtr );
}
@@ -147,15 +154,16 @@ BOOL LLFloaterTOS::postBuild()
void LLFloaterTOS::setSiteIsAlive( bool alive )
{
+ mSiteAlive = alive;
+
// only do this for TOS pages
if (hasChild("tos_html"))
{
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
// if the contents of the site was retrieved
if ( alive )
{
// navigate to the "real" page
- web_browser->navigateTo( getString( "real_url" ) );
+ loadIfNeeded();
}
else
{
@@ -167,6 +175,19 @@ void LLFloaterTOS::setSiteIsAlive( bool alive )
}
}
+void LLFloaterTOS::loadIfNeeded()
+{
+ if(!mRealNavigateBegun && mSiteAlive)
+ {
+ LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
+ if(web_browser)
+ {
+ mRealNavigateBegun = true;
+ web_browser->navigateTo( getString( "real_url" ) );
+ }
+ }
+}
+
LLFloaterTOS::~LLFloaterTOS()
{
@@ -216,8 +237,13 @@ void LLFloaterTOS::onCancel( void* userdata )
LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(false));
}
- self->mLoadCompleteCount = 0; // reset counter for next time we come to TOS
- self->closeFloater(); // destroys this object
+ // reset state for next time we come to TOS
+ self->mLoadingScreenLoaded = false;
+ self->mSiteAlive = false;
+ self->mRealNavigateBegun = false;
+
+ // destroys this object
+ self->closeFloater();
}
//virtual
@@ -225,8 +251,12 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev
{
if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
{
- // skip past the loading screen navigate complete
- if ( ++mLoadCompleteCount == 2 )
+ if(!mLoadingScreenLoaded)
+ {
+ mLoadingScreenLoaded = true;
+ loadIfNeeded();
+ }
+ else if(mRealNavigateBegun)
{
llinfos << "NAVIGATE COMPLETE" << llendl;
// enable Agree to TOS radio button now that page has loaded
diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h
index 1d573e8170..6ea56408ee 100644
--- a/indra/newview/llfloatertos.h
+++ b/indra/newview/llfloatertos.h
@@ -66,9 +66,14 @@ public:
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
private:
+
+ void loadIfNeeded();
+
std::string mMessage;
int mWebBrowserWindowId;
- int mLoadCompleteCount;
+ bool mLoadingScreenLoaded;
+ bool mSiteAlive;
+ bool mRealNavigateBegun;
std::string mReplyPumpName;
};
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..b3223ad494 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -125,7 +125,7 @@ public:
}
// support the secondlife:///app/worldmap/{LOCATION}/{COORDS} SLapp
- const std::string region_name = params[0].asString();
+ const std::string region_name = LLURI::unescape(params[0].asString());
S32 x = (params.size() > 1) ? params[1].asInteger() : 128;
S32 y = (params.size() > 2) ? params[2].asInteger() : 128;
S32 z = (params.size() > 3) ? params[3].asInteger() : 0;
@@ -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), &region_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/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index 1f1afe293a..afc00bf7ef 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -71,8 +71,8 @@ public:
p.notification->getResponseTemplate()));
}
- // set line max count to 2 in case of a very long name
- snapToMessageHeight(getChild<LLTextBox>("message"), 2);
+ // set line max count to 3 in case of a very long name
+ snapToMessageHeight(getChild<LLTextBox>("message"), 3);
}
};
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/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index c0528da999..da74295f9e 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -270,6 +270,8 @@ LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part,
LLPanelEditWearable::LLPanelEditWearable()
: LLPanel()
+ , mWearablePtr(NULL)
+ , mWearableItem(NULL)
{
}
@@ -338,8 +340,7 @@ BOOL LLPanelEditWearable::isDirty() const
//virtual
void LLPanelEditWearable::draw()
{
- BOOL is_dirty = isDirty();
- mBtnRevert->setEnabled(is_dirty);
+ updateVerbs();
LLPanel::draw();
}
@@ -401,6 +402,9 @@ void LLPanelEditWearable::showWearable(LLWearable* wearable, BOOL show)
return;
}
+ mWearableItem = gInventory.getItem(mWearablePtr->getItemID());
+ llassert(mWearableItem);
+
EWearableType type = wearable->getType();
LLPanel *targetPanel = NULL;
std::string title;
@@ -489,6 +493,7 @@ void LLPanelEditWearable::initializePanel()
updateScrollingPanelUI();
}
+ updateVerbs();
}
void LLPanelEditWearable::updateScrollingPanelUI()
@@ -645,7 +650,19 @@ void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value
}
}
+void LLPanelEditWearable::updateVerbs()
+{
+ bool can_copy = false;
+ if(mWearableItem)
+ {
+ can_copy = mWearableItem->getPermissions().allowCopyBy(gAgentID);
+ }
+ BOOL is_dirty = isDirty();
+ mBtnRevert->setEnabled(is_dirty);
+ childSetEnabled("save_as_button", is_dirty && can_copy);
+}
+// EOF
diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h
index 4178659617..8b63685177 100644
--- a/indra/newview/llpaneleditwearable.h
+++ b/indra/newview/llpaneleditwearable.h
@@ -41,6 +41,7 @@
class LLWearable;
class LLTextEditor;
class LLTextBox;
+class LLViewerInventoryItem;
class LLViewerVisualParam;
class LLVisualParamHint;
class LLViewerJointMesh;
@@ -73,9 +74,12 @@ private:
LLPanel* getPanel(EWearableType type);
void getSortedParams(value_map_t &sorted_params, const std::string &edit_group);
void buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params, LLAccordionCtrlTab *tab);
+ // update bottom bar buttons ("Save", "Revert", etc)
+ void updateVerbs();
// the pointer to the wearable we're editing. NULL means we're not editing a wearable.
LLWearable *mWearablePtr;
+ LLViewerInventoryItem* mWearableItem;
// these are constant no matter what wearable we're editing
LLButton *mBtnRevert;
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/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp
index f276df8573..9ac3a07041 100644
--- a/indra/newview/llpanelgrouplandmoney.cpp
+++ b/indra/newview/llpanelgrouplandmoney.cpp
@@ -1600,7 +1600,7 @@ void LLPanelGroupLandMoney::setGroupID(const LLUUID& id)
mImplementationp->mMoneySalesTabEHp->setGroupID(mGroupID);
}
- mImplementationp->mBeenActivated = true;
+ mImplementationp->mBeenActivated = false;
activate();
}
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 << "&region=" << curl_region;
+ oStr <<"firstname=" << firstname <<
+ "&lastname=" << lastname << "&location=" << location << "&region=" << 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/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 270999e560..dc039486e1 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -113,9 +113,9 @@ private:
LLPanelOutfitEdit::LLPanelOutfitEdit()
-: LLPanel(), mLookID(), mFetchLook(NULL), mSearchFilter(NULL),
+: LLPanel(), mCurrentOutfitID(), mFetchLook(NULL), mSearchFilter(NULL),
mLookContents(NULL), mInventoryItemsPanel(NULL), mAddToLookBtn(NULL),
-mRemoveFromLookBtn(NULL), mLookObserver(NULL), mNumItemsInLook(0)
+mRemoveFromLookBtn(NULL), mLookObserver(NULL)
{
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE);
@@ -157,7 +157,7 @@ BOOL LLPanelOutfitEdit::postBuild()
{
// gInventory.isInventoryUsable() no longer needs to be tested per Richard's fix for race conditions between inventory and panels
- mLookName = getChild<LLTextBox>("curr_look_name");
+ mCurrentOutfitName = getChild<LLTextBox>("curr_outfit_name");
childSetCommitCallback("add_btn", boost::bind(&LLPanelOutfitEdit::showAddWearablesPanel, this), NULL);
@@ -206,7 +206,7 @@ BOOL LLPanelOutfitEdit::postBuild()
mLookContents = getChild<LLScrollListCtrl>("look_items_list");
mLookContents->sortByColumn("look_item_sort", TRUE);
mLookContents->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onLookItemSelectionChange, this));
-
+
/*
LLButton::Params remove_params;
remove_params.name("remove_from_look");
@@ -220,12 +220,12 @@ BOOL LLPanelOutfitEdit::postBuild()
//childSetAction("remove_from_look_btn", boost::bind(&LLPanelOutfitEdit::onRemoveFromLookClicked, this), this);
mRemoveFromLookBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onRemoveFromLookClicked, this));
//getChild<LLPanel>("look_info_group_bar")->addChild(mRemoveFromLookBtn); remove_item_btn
-
+
mEditWearableBtn = getChild<LLButton>("edit_wearable_btn");
mEditWearableBtn->setEnabled(FALSE);
mEditWearableBtn->setVisible(FALSE);
mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this));
-
+
childSetAction("remove_item_btn", boost::bind(&LLPanelOutfitEdit::onRemoveFromLookClicked, this), this);
return TRUE;
@@ -302,7 +302,7 @@ void LLPanelOutfitEdit::onAddToLookClicked(void)
{
LLFolderViewItem* curr_item = mInventoryItemsPanel->getRootFolder()->getCurSelectedItem();
LLFolderViewEventListener* listenerp = curr_item->getListener();
- link_inventory_item(gAgent.getID(), listenerp->getUUID(), mLookID, listenerp->getName(),
+ link_inventory_item(gAgent.getID(), listenerp->getUUID(), mCurrentOutfitID, listenerp->getName(),
LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL));
updateLookInfo();
}
@@ -367,19 +367,32 @@ void LLPanelOutfitEdit::onUpClicked(void)
void LLPanelOutfitEdit::onEditWearableClicked(void)
{
LLUUID id_to_edit = mLookContents->getSelectionInterface()->getCurrentID();
-
LLViewerInventoryItem * item_to_edit = gInventory.getItem(id_to_edit);
if (item_to_edit)
{
// returns null if not a wearable (attachment, etc).
LLWearable* wearable_to_edit = gAgentWearables.getWearableFromAssetID(item_to_edit->getAssetUUID());
- if (!wearable_to_edit || !wearable_to_edit->getPermissions().allowModifyBy(gAgent.getID()) )
- {
- LLSidepanelAppearance::editWearable(wearable_to_edit, getParent());
- if (mEditWearableBtn->getVisible())
+ if(wearable_to_edit)
+ {
+ bool can_modify = false;
+ bool is_complete = item_to_edit->isComplete();
+ // if item_to_edit is a link, its properties are not appropriate,
+ // lets get original item with actual properties
+ LLViewerInventoryItem* original_item = gInventory.getItem(wearable_to_edit->getItemID());
+ if(original_item)
{
- mEditWearableBtn->setVisible(FALSE);
+ can_modify = original_item->getPermissions().allowModifyBy(gAgentID);
+ is_complete = original_item->isComplete();
+ }
+
+ if (can_modify && is_complete)
+ {
+ LLSidepanelAppearance::editWearable(wearable_to_edit, getParent());
+ if (mEditWearableBtn->getVisible())
+ {
+ mEditWearableBtn->setVisible(FALSE);
+ }
}
}
}
@@ -445,7 +458,7 @@ void LLPanelOutfitEdit::lookFetched(void)
// collectDescendentsIf takes non-const reference:
LLFindCOFValidItems is_cof_valid;
- gInventory.collectDescendentsIf(mLookID,
+ gInventory.collectDescendentsIf(mCurrentOutfitID,
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH,
@@ -468,12 +481,6 @@ void LLPanelOutfitEdit::lookFetched(void)
mLookContents->addElement(row);
}
-
- if (mLookContents->getItemCount() != mNumItemsInLook)
- {
- mNumItemsInLook = mLookContents->getItemCount();
- LLAppearanceMgr::instance().updateCOF(mLookID);
- }
}
void LLPanelOutfitEdit::updateLookInfo()
@@ -482,7 +489,7 @@ void LLPanelOutfitEdit::updateLookInfo()
{
mLookContents->clearRows();
- mFetchLook->setFetchID(mLookID);
+ mFetchLook->setFetchID(mCurrentOutfitID);
mFetchLook->startFetch();
if (mFetchLook->isFinished())
{
@@ -495,28 +502,26 @@ void LLPanelOutfitEdit::updateLookInfo()
}
}
-void LLPanelOutfitEdit::displayLookInfo(const LLInventoryCategory* pLook)
+void LLPanelOutfitEdit::displayCurrentOutfit()
{
- if (!pLook)
- {
- return;
- }
-
if (!getVisible())
{
setVisible(TRUE);
}
- if (mLookID != pLook->getUUID())
+ mCurrentOutfitID = LLAppearanceMgr::getInstance()->getCOF();
+
+ std::string current_outfit_name;
+ if (LLAppearanceMgr::getInstance()->getBaseOutfitName(current_outfit_name))
{
- mLookID = pLook->getUUID();
- mLookName->setText(pLook->getName());
- updateLookInfo();
+ mCurrentOutfitName->setText(current_outfit_name);
+ }
+ else
+ {
+ mCurrentOutfitName->setText(getString("No Outfit"));
}
-}
-void LLPanelOutfitEdit::reset()
-{
- mLookID.setNull();
+ updateLookInfo();
}
+
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 5c00f84e0e..ba382d7320 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -81,10 +81,6 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void changed(U32 mask);
- void reset();
- // Ignore all old information, useful if you are
- // recycling an existing dialog and need to clear it.
-
/*virtual*/ void setParcelID(const LLUUID& parcel_id);
// Sends a request for data about the given parcel, which will
// only update the location if there is none already available.
@@ -100,7 +96,7 @@ public:
void onEditWearableClicked(void);
void onUpClicked(void);
- void displayLookInfo(const LLInventoryCategory* pLook);
+ void displayCurrentOutfit();
void lookFetched(void);
@@ -108,8 +104,10 @@ public:
private:
- LLUUID mLookID;
- LLTextBox* mLookName;
+ //*TODO got rid of mCurrentOutfitID
+ LLUUID mCurrentOutfitID;
+
+ LLTextBox* mCurrentOutfitName;
LLScrollListCtrl* mLookContents;
LLInventoryPanel* mInventoryItemsPanel;
LLFilterEditor* mSearchFilter;
@@ -119,7 +117,6 @@ private:
LLButton* mRemoveFromLookBtn;
LLButton* mUpBtn;
LLButton* mEditWearableBtn;
- S32 mNumItemsInLook;
LLLookFetchObserver* mFetchLook;
LLInventoryLookObserver* mLookObserver;
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index 7f17dc5f67..7d8b1dea0e 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -131,7 +131,7 @@ void LLPanelOutfitsInventory::updateVerbs()
if (mListCommands)
{
- mListCommands->childSetVisible("look_edit_btn",sShowDebugEditor);
+ mListCommands->childSetVisible("edit_current_outfit_btn",sShowDebugEditor);
updateListCommands();
}
}
@@ -269,19 +269,12 @@ void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewIte
}
}
-void LLPanelOutfitsInventory::onSelectorButtonClicked()
+void LLPanelOutfitsInventory::showEditOutfitPanel()
{
- LLFolderViewItem* cur_item = getRootFolder()->getCurSelectedItem();
-
- LLFolderViewEventListener* listenerp = cur_item->getListener();
- if (getIsCorrectType(listenerp))
- {
- LLSD key;
- key["type"] = "look";
- key["id"] = listenerp->getUUID();
-
- LLSideTray::getInstance()->showPanel("sidepanel_appearance", key);
- }
+ LLSD key;
+ key["type"] = "edit_outfit";
+
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", key);
}
LLFolderViewEventListener *LLPanelOutfitsInventory::getCorrectListenerForAction()
@@ -328,7 +321,7 @@ void LLPanelOutfitsInventory::initListCommandsHandlers()
mListCommands->childSetAction("make_outfit_btn", boost::bind(&LLPanelOutfitsInventory::onAddButtonClick, this));
mListCommands->childSetAction("wear_btn", boost::bind(&LLPanelOutfitsInventory::onWearButtonClick, this));
- mListCommands->childSetAction("look_edit_btn", boost::bind(&LLPanelOutfitsInventory::onSelectorButtonClicked, this));
+ mListCommands->childSetAction("edit_current_outfit_btn", boost::bind(&LLPanelOutfitsInventory::showEditOutfitPanel, this));
LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>("trash_btn");
trash_btn->setDragAndDropHandler(boost::bind(&LLPanelOutfitsInventory::handleDragAndDropToTrash, this
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index a4d38df740..41afc2f372 100644
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -64,7 +64,7 @@ public:
bool onSaveCommit(const LLSD& notification, const LLSD& response);
void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
- void onSelectorButtonClicked();
+ void showEditOutfitPanel();
// If a compatible listener type is selected, then return a pointer to that.
// Otherwise, return NULL.
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/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index dffb5e5e12..e9a80907b7 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -480,7 +480,9 @@ void LLScreenChannel::showToastsBottom()
}
toast_rect = (*it).toast->getRect();
- toast_rect.setOriginAndSize(getRect().mLeft, bottom + toast_margin, toast_rect.getWidth() ,toast_rect.getHeight());
+ toast_rect.setOriginAndSize(getRect().mRight - toast_rect.getWidth(),
+ bottom + toast_margin, toast_rect.getWidth(),
+ toast_rect.getHeight());
(*it).toast->setRect(toast_rect);
if(floater && floater->overlapsScreenChannel())
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(&timestruct));
-#else // LL_WINDOWS
- return LLDate((F64)timegm(&timestruct));
-#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/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 88043365db..f98912b324 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -184,11 +184,9 @@ void LLSidepanelAppearance::onOpen(const LLSD& key)
mLookInfoType = key["type"].asString();
- if (mLookInfoType == "look")
+ if (mLookInfoType == "edit_outfit")
{
- LLInventoryCategory *pLook = gInventory.getCategory(key["id"].asUUID());
- if (pLook)
- mOutfitEdit->displayLookInfo(pLook);
+ mOutfitEdit->displayCurrentOutfit();
}
}
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 83a97c1ab1..23393df431 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;
@@ -1808,12 +1808,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
@@ -1835,23 +1832,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);
}
@@ -2067,9 +2058,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.
@@ -2085,6 +2087,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
@@ -2107,6 +2112,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);
@@ -2148,7 +2289,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:
@@ -2368,35 +2509,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 )
{
@@ -2611,6 +2747,7 @@ void reset_login()
//---------------------------------------------------------------------------
+std::string LLStartUp::sSLURLCommand;
bool LLStartUp::canGoFullscreen()
{
@@ -2643,145 +2780,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)
{
@@ -2829,45 +2862,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
@@ -2961,7 +2982,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);
}
@@ -3023,44 +3044,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())
{
@@ -3114,7 +3098,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/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 651070a2ea..df79725474 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -742,7 +742,7 @@ LLTextureCache::LLTextureCache(bool threaded)
mHeaderMutex(NULL),
mListMutex(NULL),
mHeaderAPRFile(NULL),
- mReadOnly(FALSE),
+ mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called.
mTexturesSizeTotal(0),
mDoPurge(FALSE)
{
@@ -929,13 +929,16 @@ U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_
S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
const char* entries_filename = "texture.entries";
const char* cache_filename = "texture.cache";
-const char* textures_dirname = "textures";
+const char* old_textures_dirname = "textures";
+//change the location of the texture cache to prevent from being deleted by old version viewers.
+const char* textures_dirname = "texturecache";
void LLTextureCache::setDirNames(ELLPath location)
{
std::string delem = gDirUtilp->getDirDelimiter();
- mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
- mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
+
+ mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, entries_filename);
+ mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, cache_filename);
mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
}
@@ -947,16 +950,38 @@ void LLTextureCache::purgeCache(ELLPath location)
{
setDirNames(location);
llassert_always(mHeaderAPRFile == NULL);
- LLAPRFile::remove(mHeaderEntriesFileName, getLocalAPRFilePool());
- LLAPRFile::remove(mHeaderDataFileName, getLocalAPRFilePool());
+
+ //remove the legacy cache if exists
+ std::string texture_dir = mTexturesDirName ;
+ mTexturesDirName = gDirUtilp->getExpandedFilename(location, old_textures_dirname);
+ if(LLFile::isdir(mTexturesDirName))
+ {
+ std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename);
+ LLAPRFile::remove(file_name, getLocalAPRFilePool());
+
+ file_name = gDirUtilp->getExpandedFilename(location, cache_filename);
+ LLAPRFile::remove(file_name, getLocalAPRFilePool());
+
+ purgeAllTextures(true);
+ }
+ mTexturesDirName = texture_dir ;
}
+
+ //remove the current texture cache.
purgeAllTextures(true);
}
-S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
+//is called in the main thread before initCache(...) is called.
+void LLTextureCache::setReadOnly(BOOL read_only)
{
- mReadOnly = read_only;
-
+ mReadOnly = read_only ;
+}
+
+//called in the main thread.
+S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_texture_cache)
+{
+ llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
+
S64 header_size = (max_size * 2) / 10;
S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE;
sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
@@ -968,6 +993,15 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
sCacheMaxTexturesSize = max_size;
max_size -= sCacheMaxTexturesSize;
+ if(disable_texture_cache) //the texture cache is disabled
+ {
+ llinfos << "The texture cache is disabled!" << llendl ;
+ setReadOnly(TRUE) ;
+ purgeAllTextures(true);
+
+ return max_size ;
+ }
+
LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries
<< " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL;
@@ -976,6 +1010,7 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
if (!mReadOnly)
{
LLFile::mkdir(mTexturesDirName);
+
const char* subdirs = "0123456789abcdef";
for (S32 i=0; i<16; i++)
{
@@ -986,6 +1021,8 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
readHeaderCache();
purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it
+ llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
+
return max_size; // unused cache space
}
@@ -1462,9 +1499,9 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
}
if (purge_directories)
{
- gDirUtilp->deleteFilesInDir(mTexturesDirName,mask);
+ gDirUtilp->deleteFilesInDir(mTexturesDirName, mask);
LLFile::rmdir(mTexturesDirName);
- }
+ }
}
mHeaderIDMap.clear();
mTexturesSizeMap.clear();
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index ca8815ee7e..5dc06ff401 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -110,7 +110,8 @@ public:
/*virtual*/ S32 update(U32 max_time_ms);
void purgeCache(ELLPath location);
- S64 initCache(ELLPath location, S64 maxsize, BOOL read_only);
+ void setReadOnly(BOOL read_only) ;
+ S64 initCache(ELLPath location, S64 maxsize, BOOL disable_texture_cache);
handle_t readFromCache(const std::string& local_filename, const LLUUID& id, U32 priority, S32 offset, S32 size,
ReadResponder* responder);
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, &region_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, &region_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, &region_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 820db7e3ff..7c439d7200 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();
@@ -5331,6 +5331,16 @@ class LLWorldCreateLandmark : public view_listener_t
}
};
+class LLWorldPlaceProfile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent"));
+
+ return true;
+ }
+};
+
void handle_look_at_selection(const LLSD& param)
{
const F32 PADDING_FACTOR = 1.75f;
@@ -6626,7 +6636,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
{
@@ -6688,7 +6698,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;
@@ -7738,6 +7748,7 @@ void initialize_menus()
commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL));
view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark");
+ view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile");
view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation");
view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome");
view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 1afbca81c3..7981de0c20 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1572,9 +1572,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");
@@ -2239,7 +2239,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;
@@ -2322,7 +2325,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;
@@ -2388,7 +2391,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
@@ -3149,9 +3152,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);
@@ -5544,9 +5545,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)
@@ -5989,7 +5988,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..81033485ee 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_COPY;
+ };
}
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..af833db9c3 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;
@@ -5607,6 +5607,8 @@ void LLVOAvatar::sitDown(BOOL bSitting)
//-----------------------------------------------------------------------------
void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
{
+ sitDown(TRUE);
+
if (isSelf())
{
// Might be first sit
@@ -5639,7 +5641,6 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
mDrawable->mXform.setRotation(mDrawable->getWorldRotation() * inv_obj_rot);
gPipeline.markMoved(mDrawable, TRUE);
- sitDown(TRUE);
mRoot.getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject
mRoot.setPosition(getPosition());
mRoot.updateWorldMatrixChildren();
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 &lt;, &gt;, and &amp;
+ mark = 0;
+ while((mark = message.find("&lt;", mark)) != std::string::npos)
+ {
+ message.replace(mark, 4, "<");
+ mark += 1;
+ }
+
+ mark = 0;
+ while((mark = message.find("&gt;", mark)) != std::string::npos)
+ {
+ message.replace(mark, 4, ">");
+ mark += 1;
+ }
+
+ mark = 0;
+ while((mark = message.find("&amp;", 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 &notificationType)
+{
+ 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 &notificationType);
+ 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 &lt;, &gt;, and &amp;
- mark = 0;
- while((mark = message.find("&lt;", mark)) != std::string::npos)
- {
- message.replace(mark, 4, "<");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&gt;", mark)) != std::string::npos)
- {
- message.replace(mark, 4, ">");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&amp;", 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 &notificationType)
-{
- 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 &notificationType);
- 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 &region_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 a55201fd53..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">
@@ -110,19 +110,14 @@ Packets Lost: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number
top="5"
width="435"
word_wrap="true">
-Second Life is brought to you by Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les and many others.
+Second Life is brought to you by Philip, Tessa, Andrew, Cory, Ian, James, Phoenix, Ryan, Haney, Dan, Char, Ben, John, Tanya, Eddie, Richard, Mitch, Doug, Eric, Frank, Bruce, Aaron, Peter, Alice, Charlie, Debra, Eileen, Helen, Janet, Steffan, Steve, Tom, Mark, Hunter, Xenon, Burgess, Bill, Jim, Lee, Hamlet, Daniel, Jeff, Todd, Sarah, Tim, Stephanie, Colin, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Jack, Vektor, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Jesse, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Yuko, Makiko, Thomas, Harry, Seth, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Brad, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, Beez, Milo, Hermia, Red, Thrax, Gulliver, Joe, Sally, Paul, Jose, Rejean, Dore, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, Dustin, George, Del, Matthew, Cat, Jacqui, Adrian, Viola, Alfred, Noel, Irfan, Yool, Rika, Jane, Frontier, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Jeremy, JP, Jake, Anthony, Maurice, Madhavi, Leopard, Kyle, Joon, Bert, Belinda, Jon, Kristi, Bridie, Pramod, Socrates, Maria, Aric, Adreanne, Jay, Kari, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Colossus, Zen, BigPapi, Pastrami, Kurz, Mani, Neuro, Mel, Sardonyx, MJ, Rowan, Sgt, Elvis, Samuel, Leo, Bryan, Niko, Austin, Soft, Poppy, Rachel, Aki, Banzai, Alexa, Sue, Bender, CG, Angelo, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Rothman, Niall, Marin, Allison, Katie, Dawn, Dusty, Katt, Judy, Andrea, Ambroff, Infinity, Rico, Gail, Kalpana, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Maestro, Simone, Yang, T, Shannon, Nelson, Khanh, Scott, Courtney, Charlene, Quixote, Susan, Zed, Amanda, Katelin, Enkidu, Roxie, Esbee, JoRoan, Scarlet, Tay, Kevin, Wolfgang, Johnny, Ray, Andren, Merov, Bob, Rand, Howard, Callen, Heff, Galen, Newell, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl, Ashley, JessieAnn, Huseby, Karina, Paris, Kurt, Rick, Lis, Kotler, Theeba, Lynx, Murphy, Doten, Taka, Norm, Jillian, Marcus, Mae, Novack, Esther, Perry, Dana, Ducot, Javier, Porter, Madison, Gecko, Dough, JR, Gisele, Crimp, Norie, Arch, Kimi, Fisher, Barbara, Jason, Peggy, Bernard, Jules, Leroy, Eva, Khederian, Campbell, Vogt, Masido, Karel, Torres, Lo, Breezer, Delby, Rountree, Anna, Servus, Rue, Itiaes, Chuck, Luna, Novella, Zaza, Wen, Gino, Lex, Cassandra, Limey, Nancy, Anukul, Silver, Brodesky, Jinsai, Squid, Gez, Rakesh, Ladan, Edelman, Marcet, Squire, Tatem, Tony, Jerm, Tia, Falcon, BK, Tiggs, Driscoll, Bacon, Timothee, Cru, Carmilla, Coyot, Webb, Kazu, Rudas, LJ, Sea, Ali Wallace, Bewest, Pup, Drub, Dragon, Inoshiro, Byron, Rhett, Xandix, Aimee, Fredrik, Thor, Teddy, Baron, Nelly, Ghengis, Epic, Eli, Stone, Grapes, Irie, Prep, Scobu, Valerie, Alain, and many others.
-Thank you to the following Residents for helping to ensure that this is the best version yet: (in progress)
+Thank you to the following Residents for helping to ensure that this is the best version yet: Drew Dwi, Zai Lynch, Latif Khalifa, Ellla McMahon, Harleen Gretzky, Squirrel Wood, Malarthi Behemoth, Dante Tucker, Buckaroo Mu, Eddi Decosta, Dirk, Talamasca, Torben Trautman, Irene Muni, Lilly Zenovka, Vick Forcella, Sasy Scarborough, Gentle Welinder, Elric Anatine, Techwolf Lupindo, Dusan Writer, WolfPup Lowenhar, Marianne McCann, Fiachra Lach, Sitearm Madonna, Sudane Erato, Sahkolihaa Contepomi, Sachi Vixen, Questar Utu, Dimitrio Lewis, Matto Destiny, Scrim Pinion, Radio Signals, Psi Merlin, Pixel Gausman, Mel Vanbeeck, Laurent Bechir, Lamorna Proctor, Lares Carter, Gwyneth Llewelyn, Hydra Shaftoe, Holger Gilruth, Gentle Heron, Carla Broek, Boroondas Gupte, Fury Rosewood, Flower Ducatillon, Colpo Wexler, gwampa Lomu, Borg Capalini, Beansy Twine, Ardy Lay, , 45ms Zhong, Adeon Writer, Aeonix Aeon, Ai Austin, Aiko Ying, Alexandrea Fride, Alliez Mysterio, Annie Milestone, Annika Genezzia, Ansariel Hiller, ArminasX Saiman, Arya Braveheart, Asaeda Meltingdots, Asturkon Jua, Avallyn Oakleaf, Avatar Quinzet, BabyA Littlething, Bacchus Ireto, Bazaar, Riva, Benjamin Bigdipper, Beth Walcher, Bezilon Kasei, Biancaluce Robbiani, Bill Walach, blakopal Galicia, Blitzckreed Levenque, Bryn Oh, Callipygian Christensen, Cap Carver, Carr Arbenlow, Chantal Harvey, Charles Courtois, Charlie Sazaland, Cherry Cheevers, ChickyBabes Zuzu, Christopher Organiser, Ciaran Laval, Clara Young, Celierra Darling, Corinne Helendale, Corro Moseley, Coughdrop Littlething, Darien Caldwell, Dartagan Shepherd, Debs Regent, Decro Schmooz, Denim Kamachi, DiJodi Dubratt, Dil Spitz, Edgware Marker, Egehan Dryke, Emma Portilo, Emmie Fairymeadow, Evangelista Emerald, Faelon Swordthain, Frenchimmo Sabra, Gaberoonie Zanzibar, Ganymedes Costagravas, Gene Frostbite, GeneJ Composer, Giggles Littlebird, Grady Echegaray, Guni Greenstein, Gypsy Tripsa, Hackshaven Harford, Ham Rambler, Han Shuffle, Hanglow Short, Hatzfeld Runo, herina Bode, Horatio Freund, Hypatia Callisto, Hypatia Pickens, Identity Euler, Imnotgoing Sideways, Innula Zenovka, Iyoba Tarantal, Jack Abraham, Jagga Meredith, Jennifer Boyle, Jeremy Marquez, Jessica Qin, Jinx Nordberg, Jo Bernandes, Jocial Sonnenkern, Joel Savard, Jondan Lundquist, Josef Munster, Josette Windlow, Juilan Tripsa, Juro Kothari, Justin RiversRunRed, Kagehi Kohn, Kaimen Takahe, Keklily Longfall, Ken Lavender, Kestral Karas, Khisme Nitely, Kimar Coba, Kithrak Kirkorian, Kitty Barnett, Kolor Fall, Komiko Okamoto, Korvel Noh, Larry Pixel, Leal Choche, len Starship, Lenae Munz, Lexi Frua, Lillie Cordeaux, Lizzy Macarthur, LSL Scientist, Luban Yiyuan, Luc Starsider, Maccus McCullough, Madison Blanc, Maggie Darwin, Mallory Destiny, Manx Wharton, Marc Claridge, Marc2 Sands, Matthew Anthony, Maxim RiversRunRed, Medhue Simoni, Melinda Latynina, Mencius Watts, Michi Lumin, Midian Farspire, Miles Glaz, Mindy Mathy, Mitch Wagner, Mo Hax, Mourna Biziou, Nao Noe, naofan Teardrop, Naomah Beaumont, Nathiel Siamendes, Nber Medici, Neko Link, Netpat Igaly, Neutron Chesnokov, Newfie Pendragon, Nicholai Laviscu, Nick Rhodes, Nicoladie Gymnast, Ollie Kubrick, Orenj Marat, Orion Delphis, Oryx Tempel, Parvati Silverweb, PeterPunk Mooney, Pixel Scientist, Pounce Teazle, Professor Noarlunga, Quantum Destiny, Quicksilver Hermes, Ralf Setsuko, RAT Quan, RedMokum Bravin, Revolution Perenti, Rezit Sideways, Rich Grainger, Rosco Teardrop, Rose Evans, Rudee Voom, RufusTT Horsefly, Saii Hallard, SaintLEOlions Zimer, Samm Larkham, Satanello Miami, SexySteven Morrisey, Sheet Spotter, Shnurui Troughton, sicarius Thorne, Sicarius Toxx, Sini Nubalo, SLB Wirefly, snowy Sidran, Soupa Segura, ST Mensing, Starshine Halasy, Stickman Ingmann, Synystyr Texan, Takeda Terrawyng, Tali Rosca, Templar Merlin, Tezcatlipoca Bisiani, Tiel Stonecutter, Tony Kembia, TouchaHoney Perhaps, Trey Reanimator, TriloByte Zanzibar, Trinity Dechou, Trinity Dejavu, Unlikely Quintessa, UsikuFarasi Kanarik, Veritas Raymaker, Vex Streeter, Viaticus Speculaas, Villain Baroque, Vixie Durant, Void Singer, Watty Berkson, Westley Schridde, Westley Streeter, Whimsy Winx, Winter Ventura, Wundur Primbee, xstorm Radek, YongYong Francois, Zak Westminster, Zana Kohime, Zaren Alexander, Zeja Pyle, ZenMondo Wormser, Zoex Flanagan, and many others.
-
-
-
-
-It is a rare mind indeed that can render the hitherto non-existent blindingly obvious. The cry 'I could have thought of that' is a very popular and misleading one, for the fact is that they didn't, and a very significant and revealing fact it is too.
- -- Douglas Adams
+"The work goes on, the cause endures, the hope still lives, and the dreams shall never die" - Edward Kennedy
</text_editor>
</panel>
<panel
diff --git a/indra/newview/skins/default/xui/en/floater_god_tools.xml b/indra/newview/skins/default/xui/en/floater_god_tools.xml
index 240871ec25..dfe3cf4485 100644
--- a/indra/newview/skins/default/xui/en/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_god_tools.xml
@@ -61,10 +61,10 @@
height="10"
layout="topleft"
left="10"
- name="Sim Name:"
+ name="Region Name:"
top="12"
width="80">
- Sim Name:
+ Region Name:
</text>
<line_editor
border_style="line"
@@ -481,10 +481,10 @@
height="10"
layout="topleft"
left="10"
- name="Sim Name:"
+ name="Region Name:"
top="10"
width="80">
- Sim Name:
+ Region Name:
</text>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
index ac0fca9cce..21c0bfef48 100644
--- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml
+++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
@@ -456,7 +456,7 @@
layout="topleft"
left_delta="0"
name="dscr_title"
- top_pad="5"
+ top_pad="6"
width="50">
Details:
</text>
@@ -464,11 +464,12 @@
type="string"
length="1"
follows="left|top"
- height="16"
+ height="22"
layout="topleft"
name="bug_aviso"
left_pad="10"
- width="200">
+ word_wrap="true"
+ width="270">
Please be as specific as possible
</text>
<text_editor
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 4c67698943..cc9e72cfb5 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2540,18 +2540,18 @@ even though the user gets a free copy.
height="19"
initial_value="0"
label="Horizontal (U)"
- label_width="90"
+ label_width="125"
layout="topleft"
left="20"
max_val="100"
name="TexScaleU"
top_pad="6"
- width="160" />
+ width="185" />
<check_box
height="19"
label="Flip"
layout="topleft"
- left_pad="10"
+ left_pad="5"
name="checkbox flip s"
top_delta="0"
width="70" />
@@ -2560,17 +2560,17 @@ even though the user gets a free copy.
height="19"
initial_value="0"
label="Vertical (V)"
- label_width="90"
+ label_width="125"
layout="topleft"
left="20"
max_val="100"
name="TexScaleV"
- width="160" />
+ width="185" />
<check_box
height="19"
label="Flip"
layout="topleft"
- left_pad="10"
+ left_pad="5"
name="checkbox flip t"
top_delta="0"
width="70" />
@@ -2582,12 +2582,12 @@ even though the user gets a free copy.
initial_value="0"
label="Rotation˚"
layout="topleft"
- label_width="100"
+ label_width="135"
left="10"
max_val="9999"
min_val="-9999"
name="TexRot"
- width="170" />
+ width="195" />
<spinner
decimal_digits="1"
@@ -2596,19 +2596,19 @@ even though the user gets a free copy.
initial_value="1"
label="Repeats / Meter"
layout="topleft"
- label_width="100"
+ label_width="135"
left="10"
max_val="10"
min_val="0.1"
name="rptctrl"
- width="170" />
+ width="195" />
<button
follows="left|top"
height="23"
label="Apply"
label_selected="Apply"
layout="topleft"
- left_pad="10"
+ left_pad="5"
name="button apply"
width="75" />
<text
@@ -2627,24 +2627,24 @@ even though the user gets a free copy.
height="19"
initial_value="0"
label="Horizontal (U)"
- label_width="90"
+ label_width="125"
layout="topleft"
left="20"
min_val="-1"
name="TexOffsetU"
- width="160" />
+ width="185" />
<spinner
follows="left|top"
height="19"
initial_value="0"
label="Vertical (V)"
- label_width="90"
+ label_width="125"
layout="topleft"
left_delta="0"
min_val="-1"
name="TexOffsetV"
top_pad="1"
- width="160" />
+ width="185" />
<panel
border="false"
follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/floater_tos.xml b/indra/newview/skins/default/xui/en/floater_tos.xml
index f3665e87ed..cbfaac958b 100644
--- a/indra/newview/skins/default/xui/en/floater_tos.xml
+++ b/indra/newview/skins/default/xui/en/floater_tos.xml
@@ -11,6 +11,10 @@
name="real_url">
http://secondlife.com/app/tos/
</floater.string>
+ <floater.string
+ name="loading_url">
+ data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ </floater.string>
<button
enabled="false"
height="20"
@@ -59,7 +63,6 @@
layout="topleft"
left_delta="0"
name="tos_html"
- start_url="data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E"
top_delta="40"
width="568" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 8b4554502a..3af80f63fe 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -220,6 +220,13 @@
name="Land"
tear_off="true">
<menu_item_call
+ label="Place Profile"
+ layout="topleft"
+ name="Place Profile">
+ <menu_item_call.on_click
+ function="World.PlaceProfile" />
+ </menu_item_call>
+ <menu_item_call
label="About Land"
name="About Land">
<menu_item_call.on_click
@@ -369,7 +376,7 @@
function="CheckControl"
parameter="ShowNavbarFavoritesPanel" />
</menu_item_check>
- <menu_item_separator/>
+ <menu_item_separator/>-->
<menu_item_separator/>
<menu
create_jump_keys="true"
@@ -815,7 +822,7 @@
function="ShowHelp"
parameter="f1_help" />
</menu_item_call>
- <menu_item_call
+<!-- <menu_item_call
label="Tutorial"
name="Tutorial">
<menu_item_call.on_click
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_edit_alpha.xml b/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
index 40647e1b81..1d0c0a02b0 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
@@ -1,33 +1,38 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_alpha_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="180"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="400"
left="10"
layout="topleft"
name="avatar_alpha_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="80"
+ height="100"
label="Lower Alpha"
layout="topleft"
- left="10"
+ left="30"
name="Lower Alpha"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="94" />
<check_box
control_name="LowerAlphaTextureInvisible"
follows="left"
@@ -41,14 +46,14 @@
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="80"
+ height="100"
label="Upper Alpha"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Upper Alpha"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="94" />
<check_box
control_name="UpperAlphaTextureInvisible"
follows="left"
@@ -62,14 +67,14 @@
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="80"
+ height="100"
label="Head Alpha"
layout="topleft"
- left_pad="10"
+ left="30"
name="Head Alpha"
tool_tip="Click to choose a picture"
- top="10"
- width="64" />
+ top="120"
+ width="94" />
<check_box
control_name="HeadAlphaTextureInvisible"
follows="left"
@@ -83,14 +88,14 @@
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="80"
+ height="100"
label="Eye Alpha"
layout="topleft"
- left="10"
+ left_pad="20"
name="Eye Alpha"
tool_tip="Click to choose a picture"
- top="100"
- width="64" />
+ top="120"
+ width="94" />
<check_box
control_name="Eye AlphaTextureInvisible"
follows="left"
@@ -104,14 +109,14 @@
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="80"
+ height="100"
label="Hair Alpha"
layout="topleft"
- left_pad="10"
+ left="30"
name="Hair Alpha"
tool_tip="Click to choose a picture"
- top_delta="-4"
- width="64" />
+ top="230"
+ width="94" />
<check_box
control_name="HairAlphaTextureInvisible"
follows="left"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_eyes.xml b/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
index c514054c41..f11ef43c76 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_eyes_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_eye_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -23,31 +28,49 @@
height="80"
label="Iris"
layout="topleft"
- left="8"
+ left="10"
name="Iris"
tool_tip="Click to choose a picture"
- top_pad="10"
+ top="10"
width="64" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
- <accordion_tab
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
+ <accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="eyes_main_tab"
title="Eyes">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="eyes_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_gloves.xml b/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
index 7aca40e8d9..7d8eed5085 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_gloves_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_gloves_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -34,31 +39,49 @@
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
width="64" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="gloves_main_tab"
title="Gloves">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="gloves_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_hair.xml b/indra/newview/skins/default/xui/en/panel_edit_hair.xml
index e7d1c05301..cd81aa2c4f 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_hair.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_hair_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_hair_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -23,26 +28,43 @@
height="80"
label="Texture"
layout="topleft"
- left="8"
+ left="10"
name="Texture"
tool_tip="Click to choose a picture"
top="10"
width="64" />
</panel>
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
<accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="hair_color_tab"
title="Color">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="hair_color_param_list"
top="0"
@@ -50,11 +72,13 @@
</accordion_tab>
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="hair_style_tab"
title="Style">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="hair_style_param_list"
top="0"
@@ -62,11 +86,13 @@
</accordion_tab>
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="hair_eyebrows_tab"
title="Eyebrows">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="hair_eyebrows_param_list"
top="0"
@@ -74,16 +100,19 @@
</accordion_tab>
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="hair_facial_tab"
title="Facial">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="hair_facial_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_jacket.xml b/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
index ed92b1e0f8..ba03865937 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_jacket_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_jacket_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -23,11 +28,11 @@
height="80"
label="Upper Fabric"
layout="topleft"
- left="10"
+ left="25"
name="Upper Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="74" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -35,42 +40,60 @@
height="80"
label="Lower Fabric"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Lower Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="74" />
<color_swatch
can_apply_immediately="true"
follows="left|top"
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="64" />
+ width="74" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="jacket_main_tab"
title="Jacket">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="jacket_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_pants.xml b/indra/newview/skins/default/xui/en/panel_edit_pants.xml
index b764188e04..5b02d1f968 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_pants.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_pants_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_pants_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -34,31 +39,49 @@
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
width="64" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="pants_main_tab"
title="Pants">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="pants_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shape.xml b/indra/newview/skins/default/xui/en/panel_edit_shape.xml
index 9a3b5c26ec..e1c574001a 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shape.xml
@@ -4,7 +4,7 @@
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_shape_panel"
top_pad="10"
width="333" >
@@ -14,7 +14,7 @@
bg_opaque_color="DkGray2"
background_visible="true"
background_opaque="true"
- follows="top|left"
+ follows="top|left|right"
height="50"
left="10"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shirt.xml b/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
index 4b7235545f..7da8de4c0b 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_shirt_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_shirt_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -34,31 +39,49 @@
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
width="64" />
</panel>
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
<accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
name="wearable_accordion"
- top_pad="10"
- width="303">
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="shirt_main_tab"
title="Shirt">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="shirt_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shoes.xml b/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
index e886afa010..84fe26f7f6 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_shoes_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_shoes_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -34,31 +39,49 @@
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
width="64" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="shoes_main_tab"
title="Shoes">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="shoes_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_skin.xml b/indra/newview/skins/default/xui/en/panel_edit_skin.xml
index 918606b54c..b5c8c95473 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_skin.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_skin_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_skin_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
allow_no_texture="true"
can_apply_immediately="true"
@@ -24,7 +29,7 @@
height="80"
label="Head Tattoos"
layout="topleft"
- left="10"
+ left="25"
name="Head Tattoos"
tool_tip="Click to choose a picture"
top="10"
@@ -37,7 +42,7 @@
height="80"
label="Upper Tattoos"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Upper Tattoos"
tool_tip="Click to choose a picture"
top="10"
@@ -50,26 +55,43 @@
height="80"
label="Lower Tattoos"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Lower Tattoos"
tool_tip="Click to choose a picture"
top="10"
width="74" />
</panel>
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
<accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
+ layout="topleft"
+ follows="all"
+ height ="300"
+ left="0"
name="wearable_accordion"
- top_pad="10"
- width="303">
+ top="0"
+ single_expansion="true"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="skin_color_tab"
title="Skin Color">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="skin_color_param_list"
top="0"
@@ -77,11 +99,13 @@
</accordion_tab>
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="skin_face_tab"
title="Face Detail">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="skin_face_param_list"
top="0"
@@ -89,11 +113,13 @@
</accordion_tab>
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="skin_makeup_tab"
title="Makeup">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="skin_makeup_param_list"
top="0"
@@ -101,16 +127,19 @@
</accordion_tab>
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="skin_body_tab"
title="Body Detail">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="skin_body_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_skirt.xml b/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
index 6cccab1843..16f6950bd5 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_skirt_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_skirt_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -34,31 +39,49 @@
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
width="64" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="skirt_main_tab"
title="Skirt">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="skirt_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_socks.xml b/indra/newview/skins/default/xui/en/panel_edit_socks.xml
index fc7de00714..e4f916703b 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_socks.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_socks_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_socks_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -34,31 +39,49 @@
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
width="64" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="socks_main_tab"
title="Socks">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="socks_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
index b214cd3de0..ed990eb095 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
@@ -1,57 +1,62 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_tattoo_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="400"
left="10"
layout="topleft"
name="avatar_tattoo_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="80"
+ height="100"
label="Head Tattoo"
layout="topleft"
- left="10"
+ left="30"
name="Head Tattoo"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="94" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="80"
+ height="100"
label="Upper Tattoo"
layout="topleft"
- left_pad="10"
+ left_pad="30"
name="Upper Tattoo"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="94" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="80"
+ height="100"
label="Lower Tattoo"
layout="topleft"
- left_pad="10"
+ left="30"
name="Lower Tattoo"
tool_tip="Click to choose a picture"
- top="10"
- width="64" />
+ top_pad="10"
+ width="94" />
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_underpants.xml b/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
index 03e0bb70ef..d43497c943 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_underpants_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_underpants_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -34,31 +39,49 @@
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
width="64" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="underpants_main_tab"
title="Underpants">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="underpants_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
index 20c56142fb..45c6ef4526 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
+ background_visible="true"
follows="all"
height="400"
layout="topleft"
- left="10"
+ left="0"
name="edit_undershirt_panel"
top_pad="10"
- width="313" >
+ width="333" >
<panel
- border="true"
- follows="left|top|right"
- height="100"
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="top|left|right"
+ height="90"
left="10"
layout="topleft"
name="avatar_undershirt_color_panel"
top="0"
- width="293" >
+ width="313" >
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -34,31 +39,49 @@
height="80"
label="Color/Tint"
layout="topleft"
- left_pad="10"
+ left_pad="20"
name="Color/Tint"
tool_tip="Click to open Color Picker"
top="10"
width="64" />
</panel>
- <accordion
- follows="left|top|right|bottom"
- height ="340"
- left="10"
- name="wearable_accordion"
- top_pad="10"
- width="303">
+ <panel
+ border="false"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ follows="all"
+ height="300"
+ layout="topleft"
+ left="10"
+ name="accordion_panel"
+ top_pad="10"
+ width="313">
+ <accordion
+ follows="all"
+ height ="300"
+ layout="topleft"
+ left="0"
+ name="wearable_accordion"
+ single_expansion="true"
+ top="0"
+ width="313">
<accordion_tab
layout="topleft"
+ fit_panel="false"
min_height="150"
name="undershirt_main_tab"
title="Undershirt">
<scrolling_panel_list
follows="all"
+ layout="topleft"
left="0"
name="undershirt_main_param_list"
top="0"
width="303" />
</accordion_tab>
</accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
index b4272bb10a..dc2f085356 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
@@ -155,7 +155,7 @@ left="0"
bg_opaque_color="DkGray2"
background_visible="true"
background_opaque="true"
- follows="top|left"
+ follows="top|left|right"
height="60"
label="Shirt"
layout="topleft"
@@ -164,7 +164,7 @@ left="0"
top_pad="10"
width="313">
<text
- follows="top|left"
+ follows="top|left|right"
height="16"
layout="topleft"
left="10"
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="&lt;Type region name&gt;"
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/panel_online_status_toast.xml b/indra/newview/skins/default/xui/en/panel_online_status_toast.xml
index 14cb5fffee..b1a7697e83 100644
--- a/indra/newview/skins/default/xui/en/panel_online_status_toast.xml
+++ b/indra/newview/skins/default/xui/en/panel_online_status_toast.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
background_visible="false"
- height="152"
+ height="40"
label="friend_online_status"
layout="topleft"
left="0"
name="friend_online_status"
top="0"
- width="305">
+ width="220">
<avatar_icon
follows="top|left"
height="18"
@@ -21,7 +21,7 @@
<text
font="SansSerifSmall"
follows="all"
- height="137"
+ height="13"
layout="topleft"
left_pad="5"
name="message"
@@ -29,7 +29,7 @@
top="15"
use_ellipses="true"
value=""
- width="285"
+ width="189"
word_wrap="true"
max_length="350" />
</panel> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
index 4d3ee07195..c1800384a3 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
@@ -12,6 +12,9 @@
name="outfit_edit"
top="0"
width="320">
+ <string
+ name="No Outfit"
+ value="No Outfit"/>
<panel.string
name="not_available">
@@ -94,7 +97,7 @@
font="SansSerifHugeBold"
height="26"
layout="topleft"
- name="curr_look_name"
+ name="curr_outfit_name"
text_color="LtGray"
top_pad="0"
value="[Current Outfit]"
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
index f9ad525642..66ed43efec 100644
--- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
@@ -122,7 +122,7 @@
label="Edit Outfit"
layout="topleft"
right="-140"
- name="look_edit_btn"
+ name="edit_current_outfit_btn"
top="26"
visible="false"
width="50" />
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 8c7de22cf8..c2624ce0d0 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -62,11 +62,11 @@
halign="right"
font="SansSerifSmall"
follows="right|top"
- image_selected="BuyArrow_Over"
- image_unselected="BuyArrow_Over"
- image_pressed="BuyArrow_Press"
+ image_selected="spacer35.tga"
+ image_unselected="spacer35.tga"
+ image_pressed="spacer35.tga"
height="16"
- label="Buy"
+ label="Buy L$"
label_color="EmphasisColor"
left_pad="0"
label_shadow="false"
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/skins/default/xui/es/floater_customize.xml b/indra/newview/skins/default/xui/es/floater_customize.xml
index 8daf2bed15..b7058d4314 100644
--- a/indra/newview/skins/default/xui/es/floater_customize.xml
+++ b/indra/newview/skins/default/xui/es/floater_customize.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater customize" title="APARIENCIA" width="527">
- <tab_container name="customize tab container" width="525">
+<floater name="floater customize" title="APARIENCIA">
+ <tab_container name="customize tab container">
<text label="Partes del cuerpo" name="body_parts_placeholder">
Partes del cuerpo
</text>
- <panel label="Forma" name="Shape" width="389">
+ <panel label="Forma" name="Shape">
<button label="Restablecer" label_selected="Restablecer" name="Revert"/>
<button label="Cuerpo" label_selected="Cuerpo" name="Body"/>
<button label="Cabeza" label_selected="Cabeza" name="Head"/>
@@ -40,12 +40,12 @@
<text name="no modify instructions">
No tiene permiso para modificar este ítem.
</text>
- <text name="Item Action Label" right="107">
+ <text name="Item Action Label">
Forma:
</text>
<button label="Crear una forma nueva" label_selected="Crear una forma nueva" name="Create New"/>
- <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
- <button label="Guardar como..." label_selected="Guardar como..." left="199" name="Save As" width="102"/>
+ <button label="Guardar" label_selected="Guardar" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
</panel>
<panel label="Piel" name="Skin">
<button label="Color de piel" label_selected="Color de piel" name="Skin Color" width="115"/>
@@ -522,7 +522,7 @@
<button label="Revertir" label_selected="Revertir" name="Revert"/>
</panel>
</tab_container>
- <scroll_container left="230" name="panel_container"/>
+ <scroll_container name="panel_container"/>
<button label="Información del script" label_selected="Información del script" name="script_info" tool_tip="Mostrar los scripts anexados a tu avatar"/>
<button label="Hacer un vestuario" label_selected="Hacer un vestuario" name="make_outfit_btn"/>
<button label="Cancelar" label_selected="Cancelar" name="Cancel"/>
diff --git a/indra/newview/skins/default/xui/es/floater_incoming_call.xml b/indra/newview/skins/default/xui/es/floater_incoming_call.xml
index 2b5fc7f193..021e5fb6b7 100644
--- a/indra/newview/skins/default/xui/es/floater_incoming_call.xml
+++ b/indra/newview/skins/default/xui/es/floater_incoming_call.xml
@@ -22,6 +22,6 @@
¿Quieres dejar [CURRENT_CHAT] y entrar a este chat de voz?
</text>
<button label="Aceptar" label_selected="Aceptar" name="Accept"/>
- <button label="Expulsar" label_selected="Expulsar" name="Reject"/>
+ <button label="Rechazar" label_selected="Rechazar" name="Reject"/>
<button label="Comenzar un MI" name="Start IM"/>
</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml
index 0cbee11bfb..36e7e40e59 100644
--- a/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml
+++ b/indra/newview/skins/default/xui/es/floater_inventory_view_finder.xml
@@ -11,12 +11,12 @@
<check_box label="Sonidos" name="check_sound"/>
<check_box label="Texturas" name="check_texture"/>
<check_box label="Fotos" name="check_snapshot"/>
- <button label="Todo" label_selected="Todo" name="All" width="70"/>
- <button label="Nada" label_selected="Nada" name="None" width="70" bottom_delta="0" left="83"/>
+ <button label="Todos" label_selected="Todo" name="All" width="70"/>
+ <button label="Ninguno" label_selected="Nada" name="None" width="70" bottom_delta="0" left="83"/>
<check_box label="Mostrar siempre las&#10;carpetas" name="check_show_empty"/>
<check_box label="Desde el fin de sesión" name="check_since_logoff" bottom_delta="-36"/>
<text name="- OR -">
- - O -
+ - o -
</text>
<spinner label="horas atrás" name="spin_hours_ago"/>
<spinner label="días atrás" name="spin_days_ago"/>
diff --git a/indra/newview/skins/default/xui/es/floater_land_holdings.xml b/indra/newview/skins/default/xui/es/floater_land_holdings.xml
index 36a02b7300..ed7055b3a1 100644
--- a/indra/newview/skins/default/xui/es/floater_land_holdings.xml
+++ b/indra/newview/skins/default/xui/es/floater_land_holdings.xml
@@ -17,7 +17,7 @@
<column label="Superficie" name="area"/>
</scroll_list>
<text name="allowed_label">
- Propiedades de terreno permitidas en el plan de pago actual:
+ Propiedad de terreno permitida en el plan de pago:
</text>
<text name="allowed_text">
[AREA] m²
diff --git a/indra/newview/skins/default/xui/es/floater_preferences.xml b/indra/newview/skins/default/xui/es/floater_preferences.xml
index 37d56ea839..61f12fc0d7 100644
--- a/indra/newview/skins/default/xui/es/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/es/floater_preferences.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater min_width="350" name="Preferences" title="PREFERENCIAS" width="646">
+<floater name="Preferences" title="PREFERENCIAS">
<button label="OK" label_selected="OK" name="OK"/>
<button label="Cancelar" label_selected="Cancelar" name="Cancel"/>
- <tab_container name="pref core" tab_width="146" width="646">
+ <tab_container name="pref core">
<panel label="General" name="general"/>
<panel label="Gráficos" name="display"/>
<panel label="Privacidad" name="im"/>
diff --git a/indra/newview/skins/default/xui/es/floater_tools.xml b/indra/newview/skins/default/xui/es/floater_tools.xml
index 9c5fea9267..59f953c239 100644
--- a/indra/newview/skins/default/xui/es/floater_tools.xml
+++ b/indra/newview/skins/default/xui/es/floater_tools.xml
@@ -182,7 +182,7 @@
<button label="Configurar..." label_selected="Configurar..." name="button set group" tool_tip="Elige un grupo con el que compartir los permisos de este objeto"/>
<name_box initial_value="Cargando..." name="Group Name Proxy"/>
<button label="Transferir" label_selected="Transferir" name="button deed" tool_tip="La transferencia entrega este objeto con los permisos del próximo propietario. Los objetos compartidos por el grupo pueden ser transferidos por un oficial del grupo."/>
- <check_box label="Comprtir" name="checkbox share with group" tool_tip="Permite que todos los miembros del grupo compartan tus permisos de modificación en este objeto. Debes transferirlo para activar las restricciones según los roles."/>
+ <check_box label="Compartir" name="checkbox share with group" tool_tip="Permite que todos los miembros del grupo compartan tus permisos de modificación en este objeto. Debes transferirlo para activar las restricciones según los roles."/>
<text name="label click action" width="180">
Al tocarlo:
</text>
@@ -475,7 +475,7 @@ máximo" name="checkbox fullbright"/>
<text name="label_area">
Área: [AREA] m²
</text>
- <button label="Acerca del terreno" label_selected="Acerca del terreno" name="button about land" width="140"/>
+ <button label="Acerca del terreno" label_selected="Acerca del terreno" name="button about land"/>
<check_box label="Mostrar los propietarios" name="checkbox show owners" tool_tip="El color de las parcelas es según su propietario:
Verde = Su terreno
@@ -492,7 +492,7 @@ Gris = Público"/>
<text name="label_parcel_trans">
Transacciones de terreno
</text>
- <button label="Comprar terreno" label_selected="Comprar terreno" name="button buy land" width="140"/>
- <button label="Abandonar el terreno" label_selected="Abandonar el terreno" name="button abandon land" width="140"/>
+ <button label="Comprar terreno" label_selected="Comprar terreno" name="button buy land"/>
+ <button label="Abandonar el terreno" label_selected="Abandonar el terreno" name="button abandon land"/>
</panel>
</floater>
diff --git a/indra/newview/skins/default/xui/es/menu_attachment_self.xml b/indra/newview/skins/default/xui/es/menu_attachment_self.xml
index c5afb99d49..8cbe4299a8 100644
--- a/indra/newview/skins/default/xui/es/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/es/menu_attachment_self.xml
@@ -4,7 +4,7 @@
<menu_item_call label="Editar" name="Edit..."/>
<menu_item_call label="Quitar" name="Detach"/>
<menu_item_call label="Soltar" name="Drop"/>
- <menu_item_call label="Levantarse" name="Stand Up"/>
+ <menu_item_call label="Levantarme" name="Stand Up"/>
<menu_item_call label="Mi apariencia" name="Appearance..."/>
<menu_item_call label="Mis amigos" name="Friends..."/>
<menu_item_call label="Mis grupos" name="Groups..."/>
diff --git a/indra/newview/skins/default/xui/es/menu_avatar_self.xml b/indra/newview/skins/default/xui/es/menu_avatar_self.xml
index 46b6d3ece6..67e56844b1 100644
--- a/indra/newview/skins/default/xui/es/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/es/menu_avatar_self.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<context_menu name="Self Pie">
- <menu_item_call label="Levantarse" name="Stand Up"/>
+ <menu_item_call label="Levantarme" name="Stand Up"/>
<context_menu label="Quitarme ▶" name="Take Off &gt;">
<context_menu label="Ropas ▶" name="Clothes &gt;">
<menu_item_call label="Camisa" name="Shirt"/>
diff --git a/indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml
index cb8fb82f0d..f21866e54f 100644
--- a/indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu name="Gear Menu">
- <menu_item_call label="Levantarse" name="stand_up"/>
+ <menu_item_call label="Levantarme" name="stand_up"/>
<menu_item_call label="Mi apariencia" name="my_appearance"/>
<menu_item_call label="Mi perfil" name="my_profile"/>
<menu_item_call label="Mis amigos" name="my_friends"/>
diff --git a/indra/newview/skins/default/xui/es/menu_land.xml b/indra/newview/skins/default/xui/es/menu_land.xml
index c315cb2f2c..b0f15be1b6 100644
--- a/indra/newview/skins/default/xui/es/menu_land.xml
+++ b/indra/newview/skins/default/xui/es/menu_land.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<context_menu name="Land Pie">
<menu_item_call label="Acerca del terreno" name="Place Information..."/>
- <menu_item_call label="Sentarse aquí" name="Sit Here"/>
+ <menu_item_call label="Sentarme aquí" name="Sit Here"/>
<menu_item_call label="Comprar este terreno" name="Land Buy"/>
<menu_item_call label="Comprar un pase" name="Land Buy Pass"/>
<menu_item_call label="Construir" name="Create"/>
diff --git a/indra/newview/skins/default/xui/es/menu_object.xml b/indra/newview/skins/default/xui/es/menu_object.xml
index 1677b9461e..d2743cd4fc 100644
--- a/indra/newview/skins/default/xui/es/menu_object.xml
+++ b/indra/newview/skins/default/xui/es/menu_object.xml
@@ -4,12 +4,12 @@
<menu_item_call label="Editar" name="Edit..."/>
<menu_item_call label="Construir" name="Build"/>
<menu_item_call label="Abrir" name="Open"/>
- <menu_item_call label="Sentarse aquí" name="Object Sit"/>
+ <menu_item_call label="Sentarme aquí" name="Object Sit"/>
<menu_item_call label="Levantarme" name="Object Stand Up"/>
<menu_item_call label="Perfil del objeto" name="Object Inspect"/>
<menu_item_call label="Acercar el zoom" name="Zoom In"/>
<context_menu label="Ponerme ▶" name="Put On">
- <menu_item_call label="Ponerse" name="Wear"/>
+ <menu_item_call label="Ponerme" name="Wear"/>
<context_menu label="Anexar ▶" name="Object Attach"/>
<context_menu label="Anexar como HUD ▶" name="Object Attach HUD"/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/es/menu_participant_list.xml b/indra/newview/skins/default/xui/es/menu_participant_list.xml
index 60c92eec75..ed69683de9 100644
--- a/indra/newview/skins/default/xui/es/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/es/menu_participant_list.xml
@@ -5,7 +5,7 @@
<menu_item_call label="Ver el perfil" name="View Profile"/>
<menu_item_call label="Añadir como amigo" name="Add Friend"/>
<menu_item_call label="MI" name="IM"/>
- <menu_item_call label="Llamada" name="Call"/>
+ <menu_item_call label="Llamar" name="Call"/>
<menu_item_call label="Compartir" name="Share"/>
<menu_item_call label="Pagar" name="Pay"/>
<menu_item_check label="Ignorar la voz" name="Block/Unblock"/>
diff --git a/indra/newview/skins/default/xui/es/menu_people_nearby.xml b/indra/newview/skins/default/xui/es/menu_people_nearby.xml
index 88df983838..dc1486d879 100644
--- a/indra/newview/skins/default/xui/es/menu_people_nearby.xml
+++ b/indra/newview/skins/default/xui/es/menu_people_nearby.xml
@@ -4,7 +4,7 @@
<menu_item_call label="Añadir como amigo" name="Add Friend"/>
<menu_item_call label="Quitarle como amigo" name="Remove Friend"/>
<menu_item_call label="MI" name="IM"/>
- <menu_item_call label="Llamada" name="Call"/>
+ <menu_item_call label="Llamar" name="Call"/>
<menu_item_call label="Mapa" name="Map"/>
<menu_item_call label="Compartir" name="Share"/>
<menu_item_call label="Pagar" name="Pay"/>
diff --git a/indra/newview/skins/default/xui/es/menu_people_nearby_multiselect.xml b/indra/newview/skins/default/xui/es/menu_people_nearby_multiselect.xml
index b87d6c6deb..4ab6000994 100644
--- a/indra/newview/skins/default/xui/es/menu_people_nearby_multiselect.xml
+++ b/indra/newview/skins/default/xui/es/menu_people_nearby_multiselect.xml
@@ -3,7 +3,7 @@
<menu_item_call label="Añadir como amigos" name="Add Friends"/>
<menu_item_call label="Quitar amigos" name="Remove Friend"/>
<menu_item_call label="MI" name="IM"/>
- <menu_item_call label="Llamada" name="Call"/>
+ <menu_item_call label="Llamar" name="Call"/>
<menu_item_call label="Compartir" name="Share"/>
<menu_item_call label="Pagar" name="Pay"/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml
index 93964a2f4f..bef803b45c 100644
--- a/indra/newview/skins/default/xui/es/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/es/menu_viewer.xml
@@ -19,7 +19,7 @@
<menu_item_call label="Dejar el estatus de Administrador" name="Leave Admin Options"/>
<menu_item_call label="Salir de [APP_NAME]" name="Quit"/>
</menu>
- <menu label="Comunicarse" name="Communicate">
+ <menu label="Comunicarme" name="Communicate">
<menu_item_call label="Mis amigos" name="My Friends"/>
<menu_item_call label="Mis grupos" name="My Groups"/>
<menu_item_check label="Chat" name="Nearby Chat"/>
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index df18b88832..9cb3b70260 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -74,7 +74,7 @@ Detalles del error: la notificación de nombre &apos;[_NAME]&apos; no se ha enco
<notification name="LoginFailedNoNetwork">
No se puede conectar con [SECOND_LIFE_GRID].
&apos;[DIAGNOSTIC]&apos;
-Asegúrate de que tu conexión a internet está funcionando adecuadamente.
+Asegúrate de que tu conexión a Internet está funcionando adecuadamente.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="MessageTemplateNotFound">
@@ -903,7 +903,7 @@ Deberás reconfigurar el nombre y las opciones de la nueva parcela.
Generalmente, esto es un fallo pasajero. Por favor, personaliza y guarda el ítem de aquí a unos minutos.
</notification>
<notification name="YouHaveBeenLoggedOut">
- Vaya, se ha cerrado tu sesión en [SECOND_LIFE]
+ Vaya, se ha cerrado tu sesión en [SECOND_LIFE].
[MESSAGE]
<usetemplate name="okcancelbuttons" notext="Salir" yestext="Ver MI y Chat"/>
</notification>
@@ -1093,9 +1093,9 @@ Si es la primera vez que usas [SECOND_LIFE], debes crear una cuenta antes de pod
<usetemplate name="okcancelbuttons" notext="Continuar" yestext="Cuenta nueva..."/>
</notification>
<notification name="LoginPacketNeverReceived">
- Tenemos problemas de conexión. Puede deberse a un problema de tu conexión a internet o de [SECOND_LIFE_GRID].
+ Tenemos problemas de conexión. Puede deberse a un problema de tu conexión a Internet o de [SECOND_LIFE_GRID].
-Puedes revisar tu conexión a internet y volver a intentarlo en unos minutos, pulsar Ayuda para conectarte a [SUPPORT_SITE], o pulsar Teleporte para intentar teleportarte a tu Base.
+Puedes revisar tu conexión a Internet y volver a intentarlo en unos minutos, pulsar Ayuda para conectarte a [SUPPORT_SITE], o pulsar Teleporte para intentar teleportarte a tu Base.
<url name="url">
http://es.secondlife.com/support/
</url>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_classified.xml b/indra/newview/skins/default/xui/es/panel_edit_classified.xml
index 7afa50c0a2..6d53b401c0 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_classified.xml
@@ -29,7 +29,7 @@
<text name="classified_location">
cargando...
</text>
- <button label="Configurarlo en esta localización" name="set_to_curr_location_btn"/>
+ <button label="Configurar en esta posición" name="set_to_curr_location_btn"/>
<text name="category_label" value="Categoría:"/>
<text name="content_type_label" value="Tipo de contenido:"/>
<icons_combo_box label="Contenido general" name="content_type">
diff --git a/indra/newview/skins/default/xui/es/panel_edit_pick.xml b/indra/newview/skins/default/xui/es/panel_edit_pick.xml
index bde29f1665..f8a03d2302 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_pick.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_pick.xml
@@ -21,11 +21,11 @@
<text name="pick_location">
cargando...
</text>
- <button label="Configurar en la posición actual" name="set_to_curr_location_btn"/>
+ <button label="Configurar en mi posición" name="set_to_curr_location_btn"/>
</panel>
</scroll_container>
<panel label="bottom_panel" name="bottom_panel">
- <button label="Guardar el destacado" name="save_changes_btn"/>
+ <button label="Guardar" name="save_changes_btn"/>
<button label="Cancelar" name="cancel_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_notes.xml b/indra/newview/skins/default/xui/es/panel_notes.xml
index bf8da4cf73..8de2afa767 100644
--- a/indra/newview/skins/default/xui/es/panel_notes.xml
+++ b/indra/newview/skins/default/xui/es/panel_notes.xml
@@ -15,7 +15,7 @@
<panel name="notes_buttons_panel">
<button label="Añadir como amigo" name="add_friend" tool_tip="Ofrecer amistad a este Residente"/>
<button label="MI" name="im" tool_tip="Abrir un mensaje instantáneo"/>
- <button label="Llamada" name="call" tool_tip="Llamar a este Residente"/>
+ <button label="Llamar" name="call" tool_tip="Llamar a este Residente"/>
<button label="Mapa" name="show_on_map_btn" tool_tip="Mostrar al Residente en el mapa"/>
<button label="Teleportar" name="teleport" tool_tip="Ofrecer teleporte"/>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_people.xml b/indra/newview/skins/default/xui/es/panel_people.xml
index 6008c6a934..376aea5278 100644
--- a/indra/newview/skins/default/xui/es/panel_people.xml
+++ b/indra/newview/skins/default/xui/es/panel_people.xml
@@ -49,9 +49,9 @@ Si estás buscando gente para pasar el rato, [secondlife:///app/worldmap usa el
<panel name="button_bar">
<button label="Perfil" name="view_profile_btn" tool_tip="Mostrar imágenes, grupos y otra información del Residente"/>
<button label="MI" name="im_btn" tool_tip="Abrir un mensaje instantáneo"/>
- <button label="Llamada" name="call_btn" tool_tip="Llamar a este Residente"/>
+ <button label="Llamar" name="call_btn" tool_tip="Llamar a este Residente"/>
<button label="Compartir" name="share_btn"/>
- <button label="Teleportarse" name="teleport_btn" tool_tip="Ofrecer teleporte"/>
+ <button label="Teleportar" name="teleport_btn" tool_tip="Ofrecer teleporte"/>
<button label="Perfil del grupo" name="group_info_btn" tool_tip="Ver la información del grupo"/>
<button label="Chat de grupo" name="chat_btn" tool_tip="Abrir el chat"/>
<button label="Multiconferencia" name="group_call_btn" tool_tip="Llamar a este grupo"/>
diff --git a/indra/newview/skins/default/xui/es/panel_region_general.xml b/indra/newview/skins/default/xui/es/panel_region_general.xml
index 54b60b276c..9ee7bef493 100644
--- a/indra/newview/skins/default/xui/es/panel_region_general.xml
+++ b/indra/newview/skins/default/xui/es/panel_region_general.xml
@@ -24,8 +24,7 @@
<check_box label="Impedir los &apos;empujones&apos;" name="restrict_pushobject"/>
<check_box label="Permitir la reventa del terreno" name="allow_land_resell_check"/>
<check_box label="Permitir unir/dividir el terreno" name="allow_parcel_changes_check"/>
- <check_box label="Bloquear el mostrar el terreno en
-la búsqueda." name="block_parcel_search_check" tool_tip="Permitir que la gente vea esta región y sus parcelas en los resultados de la búsqueda."/>
+ <check_box label="Bloquear el mostrar el terreno en la búsqueda" name="block_parcel_search_check" tool_tip="Permitir que la gente vea esta región y sus parcelas en los resultados de la búsqueda."/>
<spinner label="Nº máximo de avatares" label_width="120" name="agent_limit_spin" width="180"/>
<spinner label="Plus de objetos" label_width="120" name="object_bonus_spin" width="180"/>
<text label="Calificación" name="access_text">
diff --git a/indra/newview/skins/default/xui/es/panel_side_tray.xml b/indra/newview/skins/default/xui/es/panel_side_tray.xml
index 4e9834063b..cf5afb3cd1 100644
--- a/indra/newview/skins/default/xui/es/panel_side_tray.xml
+++ b/indra/newview/skins/default/xui/es/panel_side_tray.xml
@@ -3,27 +3,27 @@
partially on screen to hold tab buttons. -->
<side_tray name="sidebar">
<sidetray_tab description="Manejar la barra lateral." name="sidebar_openclose" tab_title="Barra lateral"/>
- <sidetray_tab description="Base." name="sidebar_home" tab_title="Home">
- <panel label="base" name="panel_home"/>
+ <sidetray_tab description="Inicio." name="sidebar_home" tab_title="Inicio">
+ <panel label="Inicio" name="panel_home"/>
</sidetray_tab>
- <sidetray_tab description="Edita tu perfil público y tus destacados." name="sidebar_me" tab_title="My Profile">
+ <sidetray_tab description="Edita tu perfil público y tus destacados." name="sidebar_me" tab_title="Mi perfil">
<panel_container name="panel_container">
<panel label="Yo" name="panel_me"/>
</panel_container>
</sidetray_tab>
- <sidetray_tab description="Encuentra a tus amigos, contactos y gente que esté cerca." name="sidebar_people" tab_title="People">
+ <sidetray_tab description="Encuentra a tus amigos, contactos y gente que esté cerca." name="sidebar_people" tab_title="Gente">
<panel_container name="panel_container">
<panel label="Perfil del grupo" name="panel_group_info_sidetray"/>
<panel label="Residentes y objetos ignorados" name="panel_block_list_sidetray"/>
</panel_container>
</sidetray_tab>
- <sidetray_tab description="Encontrar lugares donde ir o que ya visitaste." label="Lugares" name="sidebar_places" tab_title="Places">
+ <sidetray_tab description="Encontrar lugares donde ir o que ya visitaste." label="Lugares" name="sidebar_places" tab_title="Lugares">
<panel label="Lugares" name="panel_places"/>
</sidetray_tab>
- <sidetray_tab description="Mira tu inventario." name="sidebar_inventory" tab_title="My Inventory">
+ <sidetray_tab description="Mira tu inventario." name="sidebar_inventory" tab_title="Mi inventario">
<panel label="Modificar el inventario" name="sidepanel_inventory"/>
</sidetray_tab>
- <sidetray_tab description="Cambia tu apariencia y tu &apos;look&apos; actual." name="sidebar_appearance" tab_title="My Appearance">
+ <sidetray_tab description="Cambia tu apariencia y tu &apos;look&apos; actual." name="sidebar_appearance" tab_title="Mi apariencia">
<panel label="Modificar la apariencia" name="sidepanel_appearance"/>
</sidetray_tab>
</side_tray>
diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml
index a8fc7f6b58..0f2af7aaef 100644
--- a/indra/newview/skins/default/xui/es/strings.xml
+++ b/indra/newview/skins/default/xui/es/strings.xml
@@ -89,7 +89,7 @@
Descargando la ropa...
</string>
<string name="LoginFailedNoNetwork">
- Error de red: no se ha podido conectar; por favor, revisa tu conexión a internet.
+ Error de red: no se ha podido conectar; por favor, revisa tu conexión a Internet.
</string>
<string name="LoginFailed">
Error en el inicio de sesión.
@@ -101,7 +101,7 @@
http://join.secondlife.com/index.php?lang=es-ES
</string>
<string name="AgentLostConnection">
- Esta región puede estar teniendo problemas. Por favor, comprueba tu conexión a internet.
+ Esta región puede estar teniendo problemas. Por favor, comprueba tu conexión a Internet.
</string>
<string name="SavingSettings">
Guardando tus configuraciones...
@@ -2013,7 +2013,7 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].
Puente: ancho
</string>
<string name="Broad">
- Ancho
+ Aumentar
</string>
<string name="Brow Size">
Arco ciliar
diff --git a/indra/newview/skins/default/xui/es/teleport_strings.xml b/indra/newview/skins/default/xui/es/teleport_strings.xml
index 7e7ed6202f..e0e0061729 100644
--- a/indra/newview/skins/default/xui/es/teleport_strings.xml
+++ b/indra/newview/skins/default/xui/es/teleport_strings.xml
@@ -10,7 +10,7 @@ Si sigues recibiendo este mensaje, por favor, acude al [SUPPORT_SITE].
Si sigues recibiendo este mensaje, por favor, acude al [SUPPORT_SITE].
</message>
<message name="blocked_tport">
- Lo sentimos, en estos momentos los teleportes están bloqueados. Vuelva a intentarlo en un momento. Si sigue sin poder teleportarse, desconéctese y vuelva a iniciar sesión para solucionar el problema.
+ Lo sentimos, en estos momentos los teleportes están bloqueados. Vuelve a intentarlo en un momento. Si sigues sin poder teleportarte, desconéctate y vuelve a iniciar sesión para solucionar el problema.
</message>
<message name="nolandmark_tport">
Lo sentimos, pero el sistema no ha podido localizar el destino de este hito.
@@ -20,22 +20,22 @@ Si sigues recibiendo este mensaje, por favor, acude al [SUPPORT_SITE].
Vuelva a intentarlo en un momento.
</message>
<message name="noaccess_tport">
- Lo sentimos, pero usted no tiene acceso al destino de este teleporte.
+ Lo sentimos, pero no tienes acceso al destino de este teleporte.
</message>
<message name="missing_attach_tport">
- Aún no han llegado sus objetos anexados. Espere unos segundos más o desconéctese y vuelva a iniciar sesión antes de teleportarse.
+ Aún no han llegado tus objetos anexados. Espera unos segundos más o desconéctate y vuelve a iniciar sesión antes de teleportarte.
</message>
<message name="too_many_uploads_tport">
- La cola de espera en esta región está actualmente obstruida, por lo que su petición de teleporte no se atenderá en un tiempo prudencial. Por favor, vuelva a intentarlo en unos minutos o vaya a una zona menos ocupada.
+ La cola de espera en esta región está actualmente obstruida, por lo que tu petición de teleporte no se atenderá en un tiempo prudencial. Por favor, vuelve a intentarlo en unos minutos o ve a una zona menos ocupada.
</message>
<message name="expired_tport">
- Lo sentimos, pero el sistema no ha podido atender a su petición de teleporte en un tiempo prudencial. Por favor, vuelva a intentarlo en unos pocos minutos.
+ Lo sentimos, pero el sistema no ha podido atender a tu petición de teleporte en un tiempo prudencial. Por favor, vuelve a intentarlo en unos minutos.
</message>
<message name="expired_region_handoff">
- Lo sentimos, pero el sistema no ha podido completar su paso a otra región en un tiempo prudencial. Por favor, vuelva a intentarlo en unos pocos minutos.
+ Lo sentimos, pero el sistema no ha podido completar tu paso a otra región en un tiempo prudencial. Por favor, vuelve a intentarlo en unos minutos.
</message>
<message name="no_host">
- Ha sido imposible encontrar el destino del teleporte: o está desactivado temporalmente o ya no existe. Por favor, vuelva a intentarlo en unos pocos minutos.
+ Ha sido imposible encontrar el destino del teleporte: o está desactivado temporalmente o ya no existe. Por favor, vuelve a intentarlo en unos minutos.
</message>
<message name="no_inventory_host">
En estos momentos no está disponible el sistema del inventario.
diff --git a/indra/newview/skins/default/xui/fr/floater_preferences.xml b/indra/newview/skins/default/xui/fr/floater_preferences.xml
index 406e91a18a..052e43388b 100644
--- a/indra/newview/skins/default/xui/fr/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/fr/floater_preferences.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater min_width="330" name="Preferences" title="PRÉFÉRENCES" width="626">
+<floater name="Preferences" title="PRÉFÉRENCES">
<button label="OK" label_selected="OK" name="OK"/>
<button label="Annuler" label_selected="Annuler" name="Cancel"/>
- <tab_container name="pref core" tab_width="126" width="626">
+ <tab_container name="pref core">
<panel label="Général" name="general"/>
<panel label="Graphiques" name="display"/>
<panel label="Confidentialité" name="im"/>
diff --git a/indra/newview/skins/default/xui/fr/floater_tools.xml b/indra/newview/skins/default/xui/fr/floater_tools.xml
index 1d9d395960..16d276f8c2 100644
--- a/indra/newview/skins/default/xui/fr/floater_tools.xml
+++ b/indra/newview/skins/default/xui/fr/floater_tools.xml
@@ -441,9 +441,9 @@
<check_box label="Inverser" name="checkbox flip s"/>
<spinner label="Vertical (V)" name="TexScaleV"/>
<check_box label="Inverser" name="checkbox flip t"/>
- <spinner label="Rotation˚" left="122" name="TexRot" width="58"/>
- <spinner label="Répétitions / Mètre" left="122" name="rptctrl" width="58"/>
- <button label="Appliquer" label_selected="Appliquer" left_delta="68" name="button apply" width="75"/>
+ <spinner label="Rotation˚" name="TexRot" />
+ <spinner label="Répétitions / Mètre" name="rptctrl"/>
+ <button label="Appliquer" label_selected="Appliquer" name="button apply"/>
<text name="tex offset">
Décalage de la texture
</text>
diff --git a/indra/newview/skins/default/xui/it/floater_about_land.xml b/indra/newview/skins/default/xui/it/floater_about_land.xml
index a61b0584d3..bc23c2e8ff 100644
--- a/indra/newview/skins/default/xui/it/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/it/floater_about_land.xml
@@ -335,7 +335,7 @@ Solamente terreni più grandi possono essere abilitati nella ricerca.
<check_box label="Tutti i residenti" name="check other scripts"/>
<check_box label="Gruppo" name="check group scripts"/>
<text name="land_options_label">
- Opzioni della terra:
+ Opzioni per il terreno:
</text>
<check_box label="Sicuro (senza danno)" name="check safe" tool_tip="Se spuntato, imposta il terreno su &apos;sicuro&apos;, disabilitando i danni da combattimento. Se non spuntato, viene abilitato il combattimento a morte."/>
<check_box label="Nessuna spinta" name="PushRestrictCheck" tool_tip="Previeni i colpi. Selezionare questa opzione può essere utile per prevenire comportamenti dannosi sul tuo terreno."/>
diff --git a/indra/newview/skins/default/xui/it/floater_buy_land.xml b/indra/newview/skins/default/xui/it/floater_buy_land.xml
index f4e7a6c2c5..2e78168209 100644
--- a/indra/newview/skins/default/xui/it/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/it/floater_buy_land.xml
@@ -1,29 +1,29 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="buy land" title="ACQUISTA TERRENO">
<floater.string name="can_resell">
- Può essere rivenduta.
+ Può essere rivenduto.
</floater.string>
<floater.string name="can_not_resell">
- Può non essere rivenduta.
+ Può non essere rivenduto.
</floater.string>
<floater.string name="can_change">
- Può essere unita o suddivisa.
+ Può essere unito o suddiviso.
</floater.string>
<floater.string name="can_not_change">
- Non può essere unita o suddivisa.
+ Non può essere unito o suddiviso.
</floater.string>
<floater.string name="cant_buy_for_group">
- Non hai il permesso di comprare terra per il tuo gruppo attivo.
+ Non sei autorizzato ad acquistare terreno per il tuo gruppo attivo.
</floater.string>
<floater.string name="no_land_selected">
- Nessuna terra selezionata.
+ Nessun terreno selezionato.
</floater.string>
<floater.string name="multiple_parcels_selected">
- Hai selezionato appezzamenti diversi.
+ Hai selezionato lotti diversi.
Prova a selezionare un&apos;area più piccola.
</floater.string>
<floater.string name="no_permission">
- Non hai il permesso di comprare terra per il tuo gruppo attivo.
+ Non sei autorizzato ad acquistare terreno per il tuo gruppo attivo.
</floater.string>
<floater.string name="parcel_not_for_sale">
Il terreno selezionato non è in vendita.
@@ -32,7 +32,7 @@ Prova a selezionare un&apos;area più piccola.
Il gruppo possiede già il terreno.
</floater.string>
<floater.string name="you_already_own">
- Possiedi già il terreno.
+ Sei già proprietario del terreno.
</floater.string>
<floater.string name="set_to_sell_to_other">
Il terreno selezionato è già impostato per la vendita ad un altro gruppo.
@@ -41,7 +41,7 @@ Prova a selezionare un&apos;area più piccola.
L&apos;area selezionata non è pubblica.
</floater.string>
<floater.string name="not_owned_by_you">
- È selezionato terreno di proprietà di un altro residente.
+ Hai selezionato terreno di proprietà di un altro residente.
Prova a scegliere una superficie più piccola.
</floater.string>
<floater.string name="processing">
@@ -50,13 +50,13 @@ Prova a scegliere una superficie più piccola.
(Potrebbe volerci un minuto o due.)
</floater.string>
<floater.string name="fetching_error">
- C&apos;e stato un errore mentre si stavano ottenendo le informazioni sull&apos;acquisto della terra.
+ Si &apos;e verificato un errore mentre si stavano ottenendo le informazioni sull&apos;acquisto del terreno.
</floater.string>
<floater.string name="buying_will">
- Comprando questa terra:
+ Acuistando il terreno:
</floater.string>
<floater.string name="buying_for_group">
- Comprare la terra per il gruppo farà:
+ Acuistando il terreno per il gruppo:
</floater.string>
<floater.string name="cannot_buy_now">
Non puoi comprare ora:
@@ -68,10 +68,10 @@ Prova a scegliere una superficie più piccola.
nessuno necessario
</floater.string>
<floater.string name="must_upgrade">
- Il tuo tipo di account ha bisogno di un upgrade per possedere terra.
+ Per acquistare terreno devi passare a un livello di abbonamento superiore.
</floater.string>
<floater.string name="cant_own_land">
- Il tuo account può possedere terra.
+ Con questo account puoi essere proprietario di terreno.
</floater.string>
<floater.string name="land_holdings">
Sei proprietario di [BUYER] m² di terreno.
@@ -107,12 +107,10 @@ consente [AMOUNT2] oggetti
[VENDUTO_CON_OGGETTI]
</floater.string>
<floater.string name="insufficient_land_credits">
- Il gruppo [GROUP] avrà bisogno di contribuzioni anticipate, mediante crediti d&apos;uso terriero,
-sufficienti a coprire l&apos;area del terreno prima che l&apos;acquisto
-sia completato.
+ Il gruppo [GROUP] avrà bisogno di contributi di crediti di utilizzo terreno sufficienti a coprire il terreno prima che l&apos;acquisto sia completato.
</floater.string>
<floater.string name="have_enough_lindens">
- Hai [AMOUNT] L$, che sono sufficienti per comprare questa terra.
+ Hai [AMOUNT] L$, che sono sufficienti per comprare questo terreno.
</floater.string>
<floater.string name="not_enough_lindens">
Hai solo [AMOUNT] L$, ed hai bisogno di altri [AMOUNT2] L$.
@@ -209,7 +207,7 @@ venduto con oggetti
<combo_box.item label="US$ 6.00 al mese, addebitato annualmente" name="US$6.00/month,billedannually"/>
</combo_box>
<text name="land_use_action">
- Aumenta il tasso di pagamento mensile delle tasse d&apos;uso della terra a 40 US$/mese.
+ Aumenta le tariffe mensili di utilizzo del terreno a 40 US$/mese.
</text>
<text name="land_use_reason">
Tu occupi 1309 m² di terreno.
diff --git a/indra/newview/skins/default/xui/it/floater_preferences.xml b/indra/newview/skins/default/xui/it/floater_preferences.xml
index 5ffe7f4802..c5b6654a69 100644
--- a/indra/newview/skins/default/xui/it/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/it/floater_preferences.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater min_width="350" name="Preferences" title="PREFERENZE" width="646">
+<floater name="Preferences" title="PREFERENZE">
<button label="OK" label_selected="OK" name="OK"/>
<button label="Annulla" label_selected="Annulla" name="Cancel"/>
- <tab_container name="pref core" tab_width="146" width="646">
+ <tab_container name="pref core" tab_width="100">
<panel label="Generale" name="general"/>
<panel label="Grafica" name="display"/>
<panel label="Riservatezza" name="im"/>
diff --git a/indra/newview/skins/default/xui/it/floater_tools.xml b/indra/newview/skins/default/xui/it/floater_tools.xml
index 16ee797ce4..6ad8d68df2 100644
--- a/indra/newview/skins/default/xui/it/floater_tools.xml
+++ b/indra/newview/skins/default/xui/it/floater_tools.xml
@@ -443,9 +443,9 @@ della texture
<check_box label="Inverti" name="checkbox flip s"/>
<spinner label="Verticale (V)" name="TexScaleV"/>
<check_box label="Inverti" name="checkbox flip t"/>
- <spinner label="Rotazione˚" left="120" name="TexRot" width="60"/>
- <spinner label="Ripetizioni / Metro" left="120" name="rptctrl" width="60"/>
- <button label="Applica" label_selected="Applica" left_delta="72" name="button apply"/>
+ <spinner label="Rotazione˚" name="TexRot" />
+ <spinner label="Ripetizioni / Metro" name="rptctrl" />
+ <button label="Applica" label_selected="Applica" name="button apply"/>
<text name="tex offset">
Bilanciamento della texture
</text>
@@ -484,7 +484,7 @@ della texture
<button label="Suddividi" label_selected="Suddividi" name="button subdivide land" width="156"/>
<button label="Iscriviti" label_selected="Iscriviti" name="button join land" width="156"/>
<text name="label_parcel_trans">
- Transazioni del territorio
+ Transazioni terreno
</text>
<button label="Acquista terreno" label_selected="Acquista terreno" name="button buy land" width="156"/>
<button label="Abbandona il terreno" label_selected="Abbandona il terreno" name="button abandon land" width="156"/>
diff --git a/indra/newview/skins/default/xui/it/panel_group_invite.xml b/indra/newview/skins/default/xui/it/panel_group_invite.xml
index 7874f588a5..e3cb3c1092 100644
--- a/indra/newview/skins/default/xui/it/panel_group_invite.xml
+++ b/indra/newview/skins/default/xui/it/panel_group_invite.xml
@@ -13,7 +13,7 @@
Puoi selezionare più residenti da invitare nel tuo gruppo. Per iniziare, clicca su Apri il selettore di residenti.
</text>
<button label="Scelta residenti" name="add_button" tool_tip=""/>
- <name_list name="invitee_list" tool_tip="Tieni premuto Ctrl e fai clic sui nomi dei residenti per una selezionare più nomi"/>
+ <name_list name="invitee_list" tool_tip="Tieni premuto Ctrl e fai clic sui nomi dei residenti per selezionare più nomi"/>
<button label="Rimuovi i selezionati dall&apos;elenco" name="remove_button" tool_tip="Rimuove i residenti selezionati dalla lista degli inviti"/>
<text name="role_text">
Scegli che ruolo assegnare loro:
diff --git a/indra/newview/skins/default/xui/it/panel_login.xml b/indra/newview/skins/default/xui/it/panel_login.xml
index bbf93ceb87..287e938d57 100644
--- a/indra/newview/skins/default/xui/it/panel_login.xml
+++ b/indra/newview/skins/default/xui/it/panel_login.xml
@@ -12,13 +12,21 @@
Nome:
</text>
<line_editor label="Nome" name="first_name_edit" tool_tip="[SECOND_LIFE] First Name"/>
+ <text name="last_name_text">
+ Cognome:
+ </text>
<line_editor label="Cognome" name="last_name_edit" tool_tip="[SECOND_LIFE] Last Name"/>
+ <text name="password_text">
+ Password:
+ </text>
<check_box label="Ricorda password" name="remember_check"/>
<text name="start_location_text">
Inizia da:
</text>
<combo_box name="start_location_combo">
+ <combo_box.item label="La mia ultima ubicazione" name="MyLastLocation"/>
<combo_box.item label="Casa mia" name="MyHome"/>
+ <combo_box.item label="&lt;Scrivi nome regione&gt;" name="Typeregionname"/>
</combo_box>
<button label="Accedi" name="connect_btn"/>
</layout_panel>
@@ -26,6 +34,9 @@
<text name="create_new_account_text">
Iscriviti
</text>
+ <text name="forgot_password_text">
+ Hai dimenticato il nome o la password?
+ </text>
<text name="login_help">
Ti serve aiuto con la fase di accesso?
</text>
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_sound.xml b/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
index 2842b6a8aa..6936f24a8a 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Suoni" name="Preference Media panel">
- <slider label="Comando volume centrale" name="System Volume"/>
- <check_box initial_value="true" label="Disattiva audio quando minimizzato" name="mute_when_minimized"/>
+ <slider label="Vol. principale" name="System Volume"/>
+ <check_box initial_value="true" label="Disatt. se a icona" name="mute_when_minimized"/>
<slider label="Pulsanti" name="UI Volume"/>
<slider label="Ambiente" name="Wind Volume"/>
<slider label="Effetti sonori" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/it/role_actions.xml b/indra/newview/skins/default/xui/it/role_actions.xml
index 95f1f662f9..e3f95f7f86 100644
--- a/indra/newview/skins/default/xui/it/role_actions.xml
+++ b/indra/newview/skins/default/xui/it/role_actions.xml
@@ -20,7 +20,7 @@
<action_set description="Queste Abilità comprendono il potere di intestare, modificare e vendere terreni di proprietà del gruppo. Per aprire la finestra Informazioni sul terreno, fai clic con il pulsante destro del mouse sul terreno e seleziona Informazioni sul terreno, o clicca sull&apos;icona &apos;i&apos; nella Barra di Navigazione." name="Parcel Management">
<action description="Cessione di terreno e acquisto di terreno per il gruppo" longdescription="Intesta terreno e acquista terreno per il gruppo. Ciò viene fatto in Informazioni sul terreno &gt; scheda Generale." name="land deed"/>
<action description="Abbandonare il terreno in favore di Governor Linden" longdescription="Abbandona il terreno in favore di Governor Linden. *ATTENZIONE* Ogni membro con questo ruolo e abilità può abbandonare il terreno di proprietà del gruppo in Informazioni sul terreno &gt; scheda Generale, restituendolo alla proprietà Linden senza effettuare una vendita. Sii sicuro della scelta prima di assegnare questa Abilità." name="land release"/>
- <action description="Informazioni su come impostare il terreno come in vendita" longdescription="Imposta le info per la vendita della terra. *ATTENZIONE* Ogni Membro con questo ruolo e abilità può vendere il terreno di proprietà del gruppo nella scheda Informazioni sul terreno &gt; scheda Generale. Pertanto sii sicuro della scelta prima di assegnare questa Abilità." name="land set sale info"/>
+ <action description="Informazioni su come impostare il terreno come in vendita" longdescription="Imposta le informazioni per la vendita del terreno. *ATTENZIONE* Ogni Membro con questo ruolo e abilità può vendere il terreno di proprietà del gruppo nella scheda Informazioni sul terreno &gt; scheda Generale. Pertanto sii sicuro della scelta prima di assegnare questa Abilità." name="land set sale info"/>
<action description="Suddividere e unire lotti" longdescription="Suddividi e unisci lotti. Viene fatto cliccando con il pulsante destro del mouse sul terreno, selezionando Modifica terreno e trascinando il mouse sul terreno per creare una selezione. Per suddividere, seleziona quale parte vuoi dividere e clicca su Suddividi. Per unire, seleziona due o più lotti confinanti e clicca su Unisci." name="land divide join"/>
</action_set>
<action_set description="Queste abilità permettono di cambiare il nome del lotto, le impostazioni di pubblicazione, la visibilità negli elenchi e il punto di arrivo, nonché opzioni di indirizzamento del Teleport." name="Parcel Identity">
diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml
index 93239983a8..a1b570d716 100644
--- a/indra/newview/skins/default/xui/it/strings.xml
+++ b/indra/newview/skins/default/xui/it/strings.xml
@@ -853,7 +853,7 @@
Offerta di Teleport
</string>
<string name="StartUpNotifications">
- Nuove notifice sono arrivate mentre eri assente...
+ Mentre eri assente sono arrivate nuove notifiche...
</string>
<string name="OverflowInfoChannelString">
Hai ancora [%d] notifiche
diff --git a/indra/newview/skins/default/xui/ja/floater_report_abuse.xml b/indra/newview/skins/default/xui/ja/floater_report_abuse.xml
index 105e903840..dc34441535 100644
--- a/indra/newview/skins/default/xui/ja/floater_report_abuse.xml
+++ b/indra/newview/skins/default/xui/ja/floater_report_abuse.xml
@@ -92,7 +92,7 @@
<text name="dscr_title">
詳細:
</text>
- <text name="bug_aviso" width="210">
+ <text name="bug_aviso">
できるだけ具体的に詳しく記入してください。
</text>
<text name="incomplete_title">
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
index b69efeb77e..04372208d6 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Dźwięki" name="Preference Media panel">
<slider label="Główny" name="System Volume"/>
- <check_box initial_value="true" label="Wycisz dzwięk podczas minimalizacji okna" name="mute_when_minimized"/>
+ <check_box initial_value="true" label="Wycisz podczas minimalizacji" name="mute_when_minimized"/>
<slider label="Interfejs" name="UI Volume"/>
<slider label="Otoczenie" name="Wind Volume"/>
<slider label="Efekty dźwiękowe" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/pt/floater_preferences.xml b/indra/newview/skins/default/xui/pt/floater_preferences.xml
index 2736900d5f..2c76a72ca8 100644
--- a/indra/newview/skins/default/xui/pt/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/pt/floater_preferences.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater min_width="332" name="Preferences" title="PREFERÊNCIAS" width="628">
+<floater name="Preferences" title="PREFERÊNCIAS">
<button label="OK" label_selected="OK" name="OK"/>
<button label="Cancelar" label_selected="Cancelar" name="Cancel"/>
- <tab_container name="pref core" tab_width="128" width="628">
+ <tab_container name="pref core">
<panel label="Geral" name="general"/>
<panel label="Vídeo" name="display"/>
<panel label="Privacidade" name="im"/>
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(&notifications);
}
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&amp;1&amp;2&amp;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")
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index e1922367bf..b9f61ca7e1 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -122,35 +122,29 @@ private:
LLSD mAuthResponse, mValidAuthResponse;
};
-void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
+void LLLogin::Impl::connect(const std::string& uri, const LLSD& credentials)
{
- LL_DEBUGS("LLLogin") << " connect with uri '" << uri << "', login_params " << login_params << LL_ENDL;
-
// Launch a coroutine with our login_() method. Run the coroutine until
// its first wait; at that point, return here.
std::string coroname =
LLCoros::instance().launch("LLLogin::Impl::login_",
- boost::bind(&Impl::login_, this, _1, uri, login_params));
- LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
+ boost::bind(&Impl::login_, this, _1, uri, credentials));
}
-void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_params)
+void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credentials)
{
- try
+ LLSD printable_credentials = credentials;
+ if(printable_credentials.has("params")
+ && printable_credentials["params"].has("passwd"))
{
- LLSD printable_params = login_params;
- //if(printable_params.has("params")
- // && printable_params["params"].has("passwd"))
- //{
- // printable_params["params"]["passwd"] = "*******";
- //}
+ printable_credentials["params"]["passwd"] = "*******";
+ }
LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
- << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL;
+ << " with uri '" << uri << "', credentials " << printable_credentials << LL_ENDL;
// Arriving in SRVRequest state
LLEventStream replyPump("SRVreply", true);
// Should be an array of one or more uri strings.
-
LLSD rewrittenURIs;
{
LLEventTimeout filter(replyPump);
@@ -161,9 +155,9 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
// *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
F32 seconds_to_timeout = 5.0f;
- if(login_params.has("cfg_srv_timeout"))
+ if(credentials.has("cfg_srv_timeout"))
{
- seconds_to_timeout = login_params["cfg_srv_timeout"].asReal();
+ seconds_to_timeout = credentials["cfg_srv_timeout"].asReal();
}
// If the SRV request times out (e.g. EXT-3934), simulate response: an
@@ -173,9 +167,9 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
filter.eventAfter(seconds_to_timeout, fakeResponse);
std::string srv_pump_name = "LLAres";
- if(login_params.has("cfg_srv_pump"))
+ if(credentials.has("cfg_srv_pump"))
{
- srv_pump_name = login_params["cfg_srv_pump"].asString();
+ srv_pump_name = credentials["cfg_srv_pump"].asString();
}
// Make request
@@ -200,7 +194,7 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
urend(rewrittenURIs.endArray());
urit != urend; ++urit)
{
- LLSD request(login_params);
+ LLSD request(credentials);
request["reply"] = loginReplyPump.getName();
request["uri"] = *urit;
std::string status;
@@ -297,17 +291,8 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
// to success, add a data/message and data/reason fields.
LLSD error_response;
error_response["reason"] = mAuthResponse["status"];
- error_response["errorcode"] = mAuthResponse["errorcode"];
error_response["message"] = mAuthResponse["error"];
- if(mAuthResponse.has("certificate"))
- {
- error_response["certificate"] = mAuthResponse["certificate"];
- }
sendProgressEvent("offline", "fail.login", error_response);
- }
- catch (...) {
- llerrs << "login exception caught" << llendl;
- }
}
void LLLogin::Impl::disconnect()