/indra/newview/llslurl.cpp
C++ | 482 lines | 326 code | 44 blank | 112 comment | 70 complexity | 7dd233c8a0cccd559b0165a9971d82c0 MD5 | raw file
Possible License(s): LGPL-2.1
- /**
- * @file llurlsimstring.cpp (was llsimurlstring.cpp)
- * @brief Handles "SLURL fragments" like Ahern/123/45 for
- * startup processing, login screen, prefs, etc.
- *
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #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
- // text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this
- // version is required also.
- 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";
- // resolve a simstring from a slurl
- LLSLURL::LLSLURL(const std::string& slurl)
- {
- // by default we go to agni.
- mType = INVALID;
- LL_INFOS("AppInit") << "SLURL: " << slurl << LL_ENDL;
- if(slurl == SIM_LOCATION_HOME)
- {
- mType = HOME_LOCATION;
- }
- else if(slurl.empty() || (slurl == SIM_LOCATION_LAST))
- {
- mType = LAST_LOCATION;
- }
- else
- {
- 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
- {
- // Don't try to match any old http://<host>/ URL as a SLurl.
- // SLE SLurls will have the grid hostname in the URL, so only
- // match http URLs if the hostname matches the grid hostname
- // (or its a slurl.com or maps.secondlife.com URL).
- if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME ||
- slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) &&
- slurl_uri.hostName() != LLGridManager::getInstance()->getGrid())
- {
- return;
- }
- // 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, and optionally z
- if(path_array.size() >= 2)
- {
-
- mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)
- 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);
- }
- }
- }
- }
- // Create a slurl for the middle of the region
- LLSLURL::LLSLURL(const std::string& grid,
- const std::string& region)
- {
- mGrid = grid;
- mRegion = region;
- mType = LOCATION;
- mPosition = LLVector3((F64)REGION_WIDTH_METERS/2, (F64)REGION_WIDTH_METERS/2, 0);
- }
- // 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)
- {
- 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);
- }
- // create a simstring
- LLSLURL::LLSLURL(const std::string& region,
- const LLVector3& position)
- {
- *this = LLSLURL(LLGridManager::getInstance()->getGrid(),
- region, position);
- }
- // create a slurl from a global position
- LLSLURL::LLSLURL(const std::string& grid,
- const std::string& region,
- const LLVector3d& global_position)
- {
- *this = LLSLURL(grid,
- region, LLVector3(global_position.mdV[VX],
- global_position.mdV[VY],
- global_position.mdV[VZ]));
- }
- // create a slurl from a global position
- LLSLURL::LLSLURL(const std::string& region,
- const LLVector3d& global_position)
- {
- *this = LLSLURL(LLGridManager::getInstance()->getGrid(),
- region, global_position);
- }
- LLSLURL::LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb)
- {
- mType = APP;
- mAppCmd = command;
- mAppPath = LLSD::emptyArray();
- mAppPath.append(LLSD(id));
- mAppPath.append(LLSD(verb));
- }
- std::string LLSLURL::getSLURLString() const
- {
- 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 LLSLURL::getLoginString() const
- {
-
- std::stringstream unescaped_start;
- switch(mType)
- {
- 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 xml_escape_string(unescaped_start.str());
- }
- bool LLSLURL::operator==(const LLSLURL& rhs)
- {
- if(rhs.mType != mType) return false;
- switch(mType)
- {
- 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;
- }
- }
- bool LLSLURL::operator !=(const LLSLURL& rhs)
- {
- return !(*this == rhs);
- }
- 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
- {
- 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();
- }