Newer
Older
Tess Chu
committed
/**
* @file llurldispatcher.cpp
* @brief Central registry for all URL handlers
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* 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
Tess Chu
committed
*/
#include "llviewerprecompiledheaders.h"
#include "llurldispatcher.h"
// viewer includes
#include "llagent.h" // teleportViaLocation()
#include "llcommandhandler.h"
#include "llfloaterhelpbrowser.h"
James Cook
committed
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
James Cook
committed
#include "llfloaterworldmap.h"
Mnikolenko ProductEngine
committed
#include "llnotifications.h"
Tess Chu
committed
#include "llpanellogin.h"
brad kittenbrink
committed
#include "llregionhandle.h"
#include "llslurl.h"
Tess Chu
committed
#include "llstartup.h" // gStartupState
#include "llweb.h"
#include "llworldmapmessage.h"
#include "llurldispatcherlistener.h"
#include "llviewernetwork.h"
Tess Chu
committed
// library includes
#include "llnotificationsutil.h"
Tess Chu
committed
#include "llsd.h"
#include "stringize.h"
Tess Chu
committed
static LLURLDispatcherListener sURLDispatcherListener;
Tess Chu
committed
class LLURLDispatcherImpl
{
public:
static bool dispatch(const LLSLURL& slurl,
callum
committed
const std::string& nav_type,
Melinda Green
committed
bool trusted_browser);
// returns true if handled or explicitly blocked.
Tess Chu
committed
static bool dispatchRightClick(const LLSLURL& slurl);
Tess Chu
committed
private:
static bool dispatchCore(const LLSLURL& slurl,
callum
committed
const std::string& nav_type,
Melinda Green
committed
bool right_mouse,
Melinda Green
committed
bool trusted_browser);
Tess Chu
committed
// handles both left and right click
static bool dispatchHelp(const LLSLURL& slurl, bool right_mouse);
Tess Chu
committed
// Handles sl://app.floater.html.help by showing Help floater.
// Returns true if handled.
static bool dispatchApp(const LLSLURL& slurl,
callum
committed
const std::string& nav_type,
Melinda Green
committed
bool right_mouse,
Melinda Green
committed
bool trusted_browser);
// Handles secondlife:///app/agent/<agent_id>/about and similar
Tess Chu
committed
// by showing panel in Search floater.
// Returns true if handled or explicitly blocked.
Tess Chu
committed
callum
committed
static bool dispatchRegion(const LLSLURL& slurl, const std::string& nav_type, bool right_mouse);
Tess Chu
committed
// handles secondlife://Ahern/123/45/67/
// Returns true if handled.
static void regionHandleCallback(U64 handle, const LLSLURL& slurl,
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,
Josh Bell
committed
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.
Tess Chu
committed
friend class LLTeleportHandler;
};
// static
bool LLURLDispatcherImpl::dispatchCore(const LLSLURL& slurl,
callum
committed
const std::string& nav_type,
Melinda Green
committed
bool right_mouse,
Melinda Green
committed
bool trusted_browser)
Tess Chu
committed
{
//if (dispatchHelp(slurl, right_mouse)) return true;
switch(slurl.getType())
{
case LLSLURL::APP:
callum
committed
return dispatchApp(slurl, nav_type, right_mouse, web, trusted_browser);
case LLSLURL::LOCATION:
callum
committed
return dispatchRegion(slurl, nav_type, right_mouse);
default:
return false;
}
/*
// Inform the user we can't handle this
std::map<std::string, std::string> args;
Tess Chu
committed
}
// static
bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl,
callum
committed
const std::string& nav_type,
Melinda Green
committed
bool trusted_browser)
Tess Chu
committed
{
const bool right_click = false;
callum
committed
return dispatchCore(slurl, nav_type, right_click, web, trusted_browser);
Tess Chu
committed
}
// static
bool LLURLDispatcherImpl::dispatchRightClick(const LLSLURL& slurl)
Tess Chu
committed
{
const bool right_click = true;
Melinda Green
committed
const bool trusted_browser = false;
callum
committed
return dispatchCore(slurl, "clicked", right_click, web, trusted_browser);
Tess Chu
committed
}
Melinda Green
committed
Tess Chu
committed
// static
bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,
callum
committed
const std::string& nav_type,
Melinda Green
committed
bool right_mouse,
Melinda Green
committed
bool trusted_browser)
Tess Chu
committed
{
LL_INFOS() << "cmd: " << slurl.getAppCmd() << " path: " << slurl.getAppPath() << " query: " << slurl.getAppQuery() << LL_ENDL;
bool handled = LLCommandDispatcher::dispatch(
callum
committed
slurl.getAppCmd(), slurl.getAppPath(), query_map, web, nav_type, trusted_browser);
// alert if we didn't handle this secondlife:///app/ SLURL
// (but still return true because it is a valid app SLURL)
if (! handled)
{
LLNotificationsUtil::add("UnsupportedCommandSLURL");
}
return true;
Tess Chu
committed
}
// static
callum
committed
bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, const std::string& nav_type, bool right_mouse)
Tess Chu
committed
{
if(slurl.getType() != LLSLURL::LOCATION)
Tess Chu
committed
// 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)
Tess Chu
committed
{
// We're at the login screen, so make sure user can see
// the login location box to know where they are going.
Josh Bell
committed
LLPanelLogin::setLocation(slurl);
Tess Chu
committed
return true;
}
LLSLURL _slurl = slurl;
const std::string& grid = slurl.getGrid();
const std::string& current_grid = LLGridManager::getInstance()->getGrid();
if (grid != current_grid)
{
_slurl = LLSLURL(llformat("%s:%s", grid.c_str(), slurl.getRegion().c_str()), slurl.getPosition());
}
Tess Chu
committed
Josh Bell
committed
// Request a region handle by name
LLWorldMapMessage::getInstanceFast()->sendNamedRegionRequest(slurl.getRegion(),
LLURLDispatcherImpl::regionNameCallback,
slurl.getSLURLString(),
LLUI::getInstance()->mSettingGroups["config"]->getBOOL("SLURLTeleportDirectly")); // don't teleport
Josh Bell
committed
return true;
}
/*static*/
void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport)
Josh Bell
committed
{
if(slurl.getType() == LLSLURL::LOCATION)
{
regionHandleCallback(region_handle, slurl, snapshot_id, teleport);
}
void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport)
// we can't teleport cross grid at this point
if(LLGridManager::instance().isInSecondlife() &&
(LLGridManager::getInstance()->getGrid(slurl.getGrid())
!= LLGridManager::getInstance()->getGrid()))
{
LLSD args;
args["SLURL"] = slurl.getLocationString();
args["CURRENT_GRID"] = LLGridManager::getInstance()->getGridLabel();
std::string grid_label =
LLGridManager::getInstance()->getGridLabel(slurl.getGrid());
}
else
{
args["GRID"] = slurl.getGrid();
}
LLNotificationsUtil::add("CantTeleportToGrid", args);
return;
}
global_pos += LLVector3d(slurl.getPosition());
Josh Bell
committed
if (teleport)
Josh Bell
committed
gAgent.teleportViaLocation(global_pos);
James Cook
committed
LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance();
if(instance)
{
instance->trackLocation(global_pos);
}
Josh Bell
committed
}
else
{
LLSD key;
key["type"] = "remote_place";
key["x"] = global_pos.mdV[VX];
key["y"] = global_pos.mdV[VY];
key["z"] = global_pos.mdV[VZ];
LLFloaterSidePanelContainer::showPanel("places", key);
Tess Chu
committed
}
}
Josh Bell
committed
//---------------------------------------------------------------------------
// Teleportation links are handled here because they are tightly coupled
// to SLURL parsing and sim-fragment parsing
Mnikolenko ProductEngine
committed
class LLTeleportHandler : public LLCommandHandler, public LLEventAPI
Josh Bell
committed
{
public:
Melinda Green
committed
// Teleport requests *must* come from a trusted browser
// inside the app, otherwise a malicious web page could
// cause a constant teleport loop. JC
LLTeleportHandler() :
LLCommandHandler("teleport", UNTRUSTED_THROTTLE),
LLEventAPI("LLTeleportHandler", "Low-level teleport API")
{
LLEventAPI::add("teleport",
"Teleport to specified [\"regionname\"] at\n"
"specified region-relative [\"x\"], [\"y\"], [\"z\"].\n"
"If [\"regionname\"] omitted, teleport to GLOBAL\n"
"coordinates [\"x\"], [\"y\"], [\"z\"].",
&LLTeleportHandler::from_event);
}
Melinda Green
committed
bool handle(const LLSD& tokens, const LLSD& query_map,
Josh Bell
committed
{
// construct a "normal" SLURL, resolve the region to
// 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());
Mnikolenko ProductEngine
committed
// Region names may be %20 escaped.
std::string region_name = LLURI::unescape(tokens[0]);
LLSD args;
args["LOCATION"] = region_name;
Mnikolenko ProductEngine
committed
LLSD payload;
payload["region_name"] = region_name;
payload["callback_url"] = LLSLURL(region_name, coords).getSLURLString();
LLNotificationsUtil::add("TeleportViaSLAPP", args, payload);
return true;
}
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
void from_event(const LLSD& params) const
{
Response response(LLSD(), params);
if (params.has("regionname"))
{
// region specified, coordinates (if any) are region-local
LLVector3 local_pos(
params.has("x")? params["x"].asReal() : 128,
params.has("y")? params["y"].asReal() : 128,
params.has("z")? params["z"].asReal() : 0);
std::string regionname(params["regionname"]);
std::string destination(LLSLURL(regionname, local_pos).getSLURLString());
// have to resolve region's global coordinates first
teleport_via_slapp(regionname, destination);
response["message"] = "Teleporting to " + destination;
}
else // no regionname
{
// coordinates are global, and at least (x, y) are required
if (! (params.has("x") && params.has("y")))
{
return response.error("Specify either regionname or global (x, y)");
}
LLVector3d global_pos(params["x"].asReal(), params["y"].asReal(),
params["z"].asReal());
gAgent.teleportViaLocation(global_pos);
LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance();
if (instance)
{
instance->trackLocation(global_pos);
}
response["message"] = STRINGIZE("Teleporting to global " << global_pos);
}
}
Mnikolenko ProductEngine
committed
static void teleport_via_slapp(std::string region_name, std::string callback_url)
{
LLWorldMapMessage::getInstanceFast()->sendNamedRegionRequest(region_name,
Josh Bell
committed
LLURLDispatcherImpl::regionHandleCallback,
Mnikolenko ProductEngine
committed
callback_url,
Josh Bell
committed
true); // teleport
}
Mnikolenko ProductEngine
committed
static bool teleport_via_slapp_callback(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
std::string region_name = notification["payload"]["region_name"].asString();
std::string callback_url = notification["payload"]["callback_url"].asString();
if (option == 0)
{
teleport_via_slapp(region_name, callback_url);
return true;
}
return false;
}
Josh Bell
committed
};
LLTeleportHandler gTeleportHandler;
Mnikolenko ProductEngine
committed
static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportViaSLAPP", LLTeleportHandler::teleport_via_slapp_callback);
Tess Chu
committed
//---------------------------------------------------------------------------
// static
bool LLURLDispatcher::dispatch(const std::string& slurl,
callum
committed
const std::string& nav_type,
Melinda Green
committed
bool trusted_browser)
Tess Chu
committed
{
callum
committed
return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), nav_type, web, trusted_browser);
Tess Chu
committed
}
Melinda Green
committed
Tess Chu
committed
// static
bool LLURLDispatcher::dispatchRightClick(const std::string& slurl)
Tess Chu
committed
{
return LLURLDispatcherImpl::dispatchRightClick(LLSLURL(slurl));
Tess Chu
committed
}
bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl, bool trusted_content)
Melinda Green
committed
// *NOTE: Text editors are considered sources of trusted URLs
// in order to make avatar profile links in chat history work.
// While a malicious resident could chat an app SLURL, the
// receiving resident will see it and must affirmatively
Melinda Green
committed
// click on it.
// *TODO: Make this trust model more refined. JC
Mnikolenko ProductEngine
committed
return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), "clicked", web, trusted_content);