PageRenderTime 87ms CodeModel.GetById 19ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llslurl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 482 lines | 326 code | 44 blank | 112 comment | 70 complexity | 7dd233c8a0cccd559b0165a9971d82c0 MD5 | raw file
  1/** 
  2 * @file llurlsimstring.cpp (was llsimurlstring.cpp)
  3 * @brief Handles "SLURL fragments" like Ahern/123/45 for
  4 * startup processing, login screen, prefs, etc.
  5 *
  6 * $LicenseInfo:firstyear=2010&license=viewerlgpl$
  7 * Second Life Viewer Source Code
  8 * Copyright (C) 2010, Linden Research, Inc.
  9 * 
 10 * This library is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU Lesser General Public
 12 * License as published by the Free Software Foundation;
 13 * version 2.1 of the License only.
 14 * 
 15 * This library is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18 * Lesser General Public License for more details.
 19 * 
 20 * You should have received a copy of the GNU Lesser General Public
 21 * License along with this library; if not, write to the Free Software
 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 23 * 
 24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 25 * $/LicenseInfo$
 26 */
 27
 28#include "llviewerprecompiledheaders.h"
 29
 30#include "llslurl.h"
 31
 32#include "llpanellogin.h"
 33#include "llviewercontrol.h"
 34#include "llviewernetwork.h"
 35#include "llfiltersd2xmlrpc.h"
 36#include "curl/curl.h"
 37const char* LLSLURL::SLURL_HTTP_SCHEME		 = "http";
 38const char* LLSLURL::SLURL_HTTPS_SCHEME		 = "https";
 39const char* LLSLURL::SLURL_SECONDLIFE_SCHEME	 = "secondlife";
 40const char* LLSLURL::SLURL_SECONDLIFE_PATH	 = "secondlife";
 41const char* LLSLURL::SLURL_COM		         = "slurl.com";
 42// For DnD - even though www.slurl.com redirects to slurl.com in a browser, you  can copy and drag
 43// text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this
 44// version is required also.
 45
 46const char* LLSLURL::WWW_SLURL_COM				 = "www.slurl.com";
 47const char* LLSLURL::MAPS_SECONDLIFE_COM		 = "maps.secondlife.com";
 48const char* LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME = "x-grid-location-info";
 49const char* LLSLURL::SLURL_APP_PATH              = "app";
 50const char* LLSLURL::SLURL_REGION_PATH           = "region";
 51const char* LLSLURL::SIM_LOCATION_HOME           = "home";
 52const char* LLSLURL::SIM_LOCATION_LAST           = "last";
 53
 54// resolve a simstring from a slurl
 55LLSLURL::LLSLURL(const std::string& slurl)
 56{
 57	// by default we go to agni.
 58	mType = INVALID;
 59	LL_INFOS("AppInit") << "SLURL: " << slurl << LL_ENDL;
 60	if(slurl == SIM_LOCATION_HOME)
 61	{
 62		mType = HOME_LOCATION;
 63	}
 64	else if(slurl.empty() || (slurl == SIM_LOCATION_LAST))
 65	{
 66
 67		mType = LAST_LOCATION;
 68	}
 69	else
 70	{
 71		LLURI slurl_uri;
 72		// parse the slurl as a uri
 73		if(slurl.find(':') == std::string::npos)
 74		{
 75			// There may be no scheme ('secondlife:' etc.) passed in.  In that case
 76			// we want to normalize the slurl by putting the appropriate scheme
 77			// in front of the slurl.  So, we grab the appropriate slurl base
 78			// from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or
 79			// https://<hostname>/region/ for Standalone grid (the word region, not the region name)
 80			// these slurls are typically passed in from the 'starting location' box on the login panel,
 81			// where the user can type in <regionname>/<x>/<y>/<z>
 82			std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase();
 83			// the slurl that was passed in might have a prepended /, or not.  So,
 84			// we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife/<region>/<x>/<y>/<z>
 85			// or some such.
 86			
 87			if(slurl[0] == '/')
 88		    {
 89				fixed_slurl += slurl.substr(1);
 90		    }
 91			else
 92		    {
 93				fixed_slurl += slurl;
 94		    }
 95			// We then load the slurl into a LLURI form
 96			slurl_uri = LLURI(fixed_slurl);
 97		}
 98		else
 99		{
100		    // as we did have a scheme, implying a URI style slurl, we
101		    // simply parse it as a URI
102		    slurl_uri = LLURI(slurl);
103		}
104		
105		LLSD path_array = slurl_uri.pathArray();
106		
107		// determine whether it's a maingrid URI or an Standalone/open style URI
108		// by looking at the scheme.  If it's a 'secondlife:' slurl scheme or
109		// 'sl:' scheme, we know it's maingrid
110		
111		// At the end of this if/else block, we'll have determined the grid,
112		// and the slurl type (APP or LOCATION)
113		if(slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
114		{
115			// parse a maingrid style slurl.  We know the grid is maingrid
116			// so grab it.
117			// A location slurl for maingrid (with the special schemes) can be in the form
118			// secondlife://<regionname>/<x>/<y>/<z>
119			// or
120			// secondlife://<Grid>/secondlife/<region>/<x>/<y>/<z>
121			// where if grid is empty, it specifies Agni
122			
123			// An app style slurl for maingrid can be
124			// secondlife://<Grid>/app/<app parameters>
125			// where an empty grid implies Agni
126			
127			// we'll start by checking the top of the 'path' which will be 
128			// either 'app', 'secondlife', or <x>.
129			
130			// default to maingrid
131			
132			mGrid = MAINGRID;
133			
134			if ((path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) ||
135				(path_array[0].asString() == LLSLURL::SLURL_APP_PATH))
136		    {
137				// it's in the form secondlife://<grid>/(app|secondlife)
138				// so parse the grid name to derive the grid ID
139				if (!slurl_uri.hostName().empty())
140				{
141					mGrid = LLGridManager::getInstance()->getGridByLabel(slurl_uri.hostName());
142				}
143				else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
144				{
145					// If the slurl is in the form secondlife:///secondlife/<region> form, 
146					// then we are in fact on maingrid.  
147					mGrid = MAINGRID;
148				}
149				else if(path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
150				{
151					// for app style slurls, where no grid name is specified, assume the currently
152					// selected or logged in grid.
153					mGrid =  LLGridManager::getInstance()->getGrid();
154				}
155
156				if(mGrid.empty())
157				{
158					// we couldn't find the grid in the grid manager, so bail
159					return;
160				}
161				// set the type as appropriate.
162				if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
163				{
164					mType = LOCATION;
165				}
166				else
167				{
168					mType = APP;
169				}
170				path_array.erase(0);
171		    }
172			else
173		    {
174				// it wasn't a /secondlife/<region> or /app/<params>, so it must be secondlife://<region>
175				// therefore the hostname will be the region name, and it's a location type
176				mType = LOCATION;
177				// 'normalize' it so the region name is in fact the head of the path_array
178				path_array.insert(0, slurl_uri.hostName());
179		    }
180		}
181		else if((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME) ||
182		   (slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) || 
183		   (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME))
184		{
185		    // We're dealing with either a Standalone style slurl or slurl.com slurl
186		  if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) ||
187		      (slurl_uri.hostName() == LLSLURL::WWW_SLURL_COM) || 
188		      (slurl_uri.hostName() == LLSLURL::MAPS_SECONDLIFE_COM))
189			{
190				// slurl.com implies maingrid
191				mGrid = MAINGRID;
192			}
193		    else
194			{
195				// Don't try to match any old http://<host>/ URL as a SLurl.
196				// SLE SLurls will have the grid hostname in the URL, so only
197				// match http URLs if the hostname matches the grid hostname
198				// (or its a slurl.com or maps.secondlife.com URL).
199				if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME ||
200					 slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) &&
201					slurl_uri.hostName() != LLGridManager::getInstance()->getGrid())
202				{
203					return;
204				}
205
206				// As it's a Standalone grid/open, we will always have a hostname, as Standalone/open  style
207				// urls are properly formed, unlike the stinky maingrid style
208				mGrid = slurl_uri.hostName();
209			}
210		    if (path_array.size() == 0)
211			{
212				// um, we need a path...
213				return;
214			}
215			
216			// we need to normalize the urls so
217			// the path portion starts with the 'command' that we want to do
218			// it can either be region or app.  
219		    if ((path_array[0].asString() == LLSLURL::SLURL_REGION_PATH) ||
220				(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH))
221			{
222				// strip off 'region' or 'secondlife'
223				path_array.erase(0);
224				// it's a location
225				mType = LOCATION;
226			}
227			else if (path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
228			{
229				mType = APP;
230				path_array.erase(0);
231				// leave app appended.  
232			}
233			else
234			{
235				// not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL
236				return;
237			}
238		}
239		else
240		{
241		    // invalid scheme, so bail
242		    return;
243		}
244		
245		
246		if(path_array.size() == 0)
247		{
248			// we gotta have some stuff after the specifier as to whether it's a region or command
249			return;
250		}
251		
252		// now that we know whether it's an app slurl or a location slurl,
253		// parse the slurl into the proper data structures.
254		if(mType == APP)
255		{		
256			// grab the app command type and strip it (could be a command to jump somewhere, 
257			// or whatever )
258			mAppCmd = path_array[0].asString();
259			path_array.erase(0);
260			
261			// Grab the parameters
262			mAppPath = path_array;
263			// and the query
264			mAppQuery = slurl_uri.query();
265			mAppQueryMap = slurl_uri.queryMap();
266			return;
267		}
268		else if(mType == LOCATION)
269		{
270			// at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z 
271			// are collectively optional
272			// are optional
273			mRegion = LLURI::unescape(path_array[0].asString());
274			path_array.erase(0);
275			
276			// parse the x, y, and optionally z
277			if(path_array.size() >= 2)
278			{	
279			  
280			  mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)
281			  if((F32(mPosition[VX]) < 0.f) || 
282                             (mPosition[VX] > REGION_WIDTH_METERS) ||
283			     (F32(mPosition[VY]) < 0.f) || 
284                             (mPosition[VY] > REGION_WIDTH_METERS) ||
285			     (F32(mPosition[VZ]) < 0.f) || 
286                             (mPosition[VZ] > REGION_HEIGHT_METERS))
287			    {
288			      mType = INVALID;
289			      return;
290			    }
291 
292			}
293			else
294			{
295				// if x, y and z were not fully passed in, go to the middle of the region.
296				// teleport will adjust the actual location to make sure you're on the ground
297				// and such
298				mPosition = LLVector3(REGION_WIDTH_METERS/2, REGION_WIDTH_METERS/2, 0);
299			}
300		}
301	}
302}
303
304
305// Create a slurl for the middle of the region
306LLSLURL::LLSLURL(const std::string& grid, 
307				 const std::string& region)
308{
309	mGrid = grid;
310	mRegion = region;
311	mType = LOCATION;
312	mPosition = LLVector3((F64)REGION_WIDTH_METERS/2, (F64)REGION_WIDTH_METERS/2, 0);
313}
314
315
316
317// create a slurl given the position.  The position will be modded with the region
318// width handling global positions as well
319LLSLURL::LLSLURL(const std::string& grid, 
320		 const std::string& region, 
321		 const LLVector3& position)
322{
323	mGrid = grid;
324	mRegion = region;
325	S32 x = llround( (F32)fmod( position[VX], (F32)REGION_WIDTH_METERS ) );
326	S32 y = llround( (F32)fmod( position[VY], (F32)REGION_WIDTH_METERS ) );
327	S32 z = llround( (F32)position[VZ] );
328	mType = LOCATION;
329	mPosition = LLVector3(x, y, z);
330}
331
332
333// create a simstring
334LLSLURL::LLSLURL(const std::string& region, 
335		 const LLVector3& position)
336{
337  *this = LLSLURL(LLGridManager::getInstance()->getGrid(),
338		  region, position);
339}
340
341// create a slurl from a global position
342LLSLURL::LLSLURL(const std::string& grid, 
343		 const std::string& region, 
344		 const LLVector3d& global_position)
345{
346  *this = LLSLURL(grid,
347		  region, LLVector3(global_position.mdV[VX],
348				    global_position.mdV[VY],
349				    global_position.mdV[VZ]));
350}
351
352// create a slurl from a global position
353LLSLURL::LLSLURL(const std::string& region, 
354		 const LLVector3d& global_position)
355{
356  *this = LLSLURL(LLGridManager::getInstance()->getGrid(),
357		  region, global_position);
358}
359
360LLSLURL::LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb)
361{
362  mType = APP;
363  mAppCmd = command;
364  mAppPath = LLSD::emptyArray();
365  mAppPath.append(LLSD(id));
366  mAppPath.append(LLSD(verb));
367}
368
369
370std::string LLSLURL::getSLURLString() const
371{
372	switch(mType)
373	{
374		case HOME_LOCATION:
375			return SIM_LOCATION_HOME;
376		case LAST_LOCATION:
377			return SIM_LOCATION_LAST;
378		case LOCATION:
379			{
380				// lookup the grid
381				S32 x = llround( (F32)mPosition[VX] );
382				S32 y = llround( (F32)mPosition[VY] );
383				S32 z = llround( (F32)mPosition[VZ] );	
384				return LLGridManager::getInstance()->getSLURLBase(mGrid) + 
385				LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); 
386			}
387		case APP:
388		{
389			std::ostringstream app_url;
390			app_url << LLGridManager::getInstance()->getAppSLURLBase() << "/" << mAppCmd;
391			for(LLSD::array_const_iterator i = mAppPath.beginArray();
392				i != mAppPath.endArray();
393				i++)
394			{
395				app_url << "/" << i->asString();
396			}
397			if(mAppQuery.length() > 0)
398			{
399				app_url << "?" << mAppQuery;
400			}
401			return app_url.str();
402		}	
403		default:
404			LL_WARNS("AppInit") << "Unexpected SLURL type for SLURL string" << (int)mType << LL_ENDL;			
405			return std::string();
406	}
407}
408
409std::string LLSLURL::getLoginString() const
410{
411	
412	std::stringstream unescaped_start;
413	switch(mType)
414	{
415		case LOCATION:
416			unescaped_start << "uri:" 
417			<< mRegion << "&" 
418			<< llround(mPosition[0]) << "&" 
419			<< llround(mPosition[1]) << "&" 
420			<< llround(mPosition[2]);
421			break;
422		case HOME_LOCATION:
423			unescaped_start << "home";
424			break;
425		case LAST_LOCATION:
426			unescaped_start << "last";
427			break;
428		default:
429			LL_WARNS("AppInit") << "Unexpected SLURL type for login string" << (int)mType << LL_ENDL;
430			break;
431	}
432	return  xml_escape_string(unescaped_start.str());
433}
434
435bool LLSLURL::operator==(const LLSLURL& rhs)
436{
437	if(rhs.mType != mType) return false;
438	switch(mType)
439	{
440		case LOCATION:
441			return ((mGrid == rhs.mGrid) &&
442					(mRegion == rhs.mRegion) &&
443					(mPosition == rhs.mPosition));
444		case APP:
445			return getSLURLString() == rhs.getSLURLString();
446			
447		case HOME_LOCATION:
448		case LAST_LOCATION:
449			return true;
450		default:
451			return false;
452	}
453}
454
455bool LLSLURL::operator !=(const LLSLURL& rhs)
456{
457	return !(*this == rhs);
458}
459
460std::string LLSLURL::getLocationString() const
461{
462	return llformat("%s/%d/%d/%d",
463					mRegion.c_str(),
464					(int)llround(mPosition[0]),
465					(int)llround(mPosition[1]),
466					(int)llround(mPosition[2]));						 
467}
468std::string LLSLURL::asString() const
469{
470    std::ostringstream result;
471    result << "   mAppCmd:"  << getAppCmd() <<
472              "   mAppPath:" + getAppPath().asString() <<
473              "   mAppQueryMap:" + getAppQueryMap().asString() <<
474              "   mAppQuery: " + getAppQuery() <<
475              "   mGrid: " + getGrid() <<
476              "   mRegion: " + getRegion() <<
477              "   mPosition: "  <<
478              "   mType: " << mType <<
479              "   mPosition: " << mPosition;
480    return result.str();
481}
482