llurldispatcher.cpp

Go to the documentation of this file.
00001 
00031 #include "llviewerprecompiledheaders.h"
00032 
00033 #include "llurldispatcher.h"
00034 
00035 // viewer includes
00036 #include "llagent.h"                    // teleportViaLocation()
00037 #include "llcommandhandler.h"
00038 #include "llfloaterurldisplay.h"
00039 #include "llfloaterdirectory.h"
00040 #include "llfloaterhtml.h"
00041 #include "llfloaterworldmap.h"
00042 #include "llfloaterhtmlhelp.h"
00043 #include "llpanellogin.h"
00044 #include "llstartup.h"                  // gStartupState
00045 #include "llurlsimstring.h"
00046 #include "llviewerwindow.h"             // alertXml()
00047 #include "llweb.h"
00048 #include "llworldmap.h"
00049 
00050 // library includes
00051 #include "llsd.h"
00052 
00053 const std::string SLURL_SL_HELP_PREFIX          = "secondlife://app.";
00054 const std::string SLURL_SL_PREFIX                       = "sl://";
00055 const std::string SLURL_SECONDLIFE_PREFIX       = "secondlife://";
00056 const std::string SLURL_SLURL_PREFIX            = "http://slurl.com/secondlife/";
00057 
00058 const std::string SLURL_APP_TOKEN = "app/";
00059 
00060 class LLURLDispatcherImpl
00061 {
00062 public:
00063         static bool isSLURL(const std::string& url);
00064 
00065         static bool isSLURLCommand(const std::string& url);
00066 
00067         static bool dispatch(const std::string& url, bool from_external_browser);
00068                 // returns true if handled or explicitly blocked.
00069 
00070         static bool dispatchRightClick(const std::string& url);
00071 
00072 private:
00073         static bool dispatchCore(const std::string& url, 
00074                 bool from_external_browser, bool right_mouse);
00075                 // handles both left and right click
00076 
00077         static bool dispatchHelp(const std::string& url, BOOL right_mouse);
00078                 // Handles sl://app.floater.html.help by showing Help floater.
00079                 // Returns true if handled.
00080 
00081         static bool dispatchApp(const std::string& url, bool from_external_browser, BOOL right_mouse);
00082                 // Handles secondlife:///app/agent/<agent_id>/about and similar
00083                 // by showing panel in Search floater.
00084                 // Returns true if handled or explicitly blocked.
00085 
00086         static bool dispatchRegion(const std::string& url, BOOL right_mouse);
00087                 // handles secondlife://Ahern/123/45/67/
00088                 // Returns true if handled.
00089 
00090         static void regionHandleCallback(U64 handle, const std::string& url,
00091                 const LLUUID& snapshot_id, bool teleport);
00092                 // Called by LLWorldMap when a location has been resolved to a
00093             // region name
00094 
00095         static void regionNameCallback(U64 handle, const std::string& url,
00096                 const LLUUID& snapshot_id, bool teleport);
00097                 // Called by LLWorldMap when a region name has been resolved to a
00098                 // location in-world, used by places-panel display.
00099 
00100         static bool matchPrefix(const std::string& url, const std::string& prefix);
00101         
00102         static std::string stripProtocol(const std::string& url);
00103 
00104         friend class LLTeleportHandler;
00105 };
00106 
00107 // static
00108 bool LLURLDispatcherImpl::isSLURL(const std::string& url)
00109 {
00110         if (matchPrefix(url, SLURL_SL_HELP_PREFIX)) return true;
00111         if (matchPrefix(url, SLURL_SL_PREFIX)) return true;
00112         if (matchPrefix(url, SLURL_SECONDLIFE_PREFIX)) return true;
00113         if (matchPrefix(url, SLURL_SLURL_PREFIX)) return true;
00114         return false;
00115 }
00116 
00117 // static
00118 bool LLURLDispatcherImpl::isSLURLCommand(const std::string& url)
00119 { 
00120         if (matchPrefix(url, SLURL_SL_PREFIX + SLURL_APP_TOKEN)
00121                 || matchPrefix(url, SLURL_SECONDLIFE_PREFIX + "/" + SLURL_APP_TOKEN)
00122                 || matchPrefix(url, SLURL_SLURL_PREFIX + SLURL_APP_TOKEN) )
00123         {
00124                 return true;
00125         }
00126         return false;
00127 }
00128 
00129 // static
00130 bool LLURLDispatcherImpl::dispatchCore(const std::string& url, bool from_external_browser, bool right_mouse)
00131 {
00132         if (url.empty()) return false;
00133         if (dispatchHelp(url, right_mouse)) return true;
00134         if (dispatchApp(url, from_external_browser, right_mouse)) return true;
00135         if (dispatchRegion(url, right_mouse)) return true;
00136 
00137         /*
00138         // Inform the user we can't handle this
00139         std::map<std::string, std::string> args;
00140         args["[SLURL]"] = url;
00141         gViewerWindow->alertXml("BadURL", args);
00142         */
00143         
00144         return false;
00145 }
00146 
00147 // static
00148 bool LLURLDispatcherImpl::dispatch(const std::string& url, bool from_external_browser)
00149 {
00150         llinfos << "url: " << url << llendl;
00151         const bool right_click = false;
00152         return dispatchCore(url, from_external_browser, right_click);
00153 }
00154 
00155 // static
00156 bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url)
00157 {
00158         llinfos << "url: " << url << llendl;
00159         const bool from_external_browser = false;
00160         const bool right_click = true;
00161         return dispatchCore(url, from_external_browser, right_click);
00162 }
00163 // static
00164 bool LLURLDispatcherImpl::dispatchHelp(const std::string& url, BOOL right_mouse)
00165 {
00166         if (matchPrefix(url, SLURL_SL_HELP_PREFIX))
00167         {
00168                 gViewerHtmlHelp.show();
00169                 return true;
00170         }
00171         return false;
00172 }
00173 
00174 // static
00175 bool LLURLDispatcherImpl::dispatchApp(const std::string& url, 
00176                                                                           bool from_external_browser,
00177                                                                           BOOL right_mouse)
00178 {
00179         if (!isSLURL(url))
00180         {
00181                 return false;
00182         }
00183 
00184         LLURI uri(url);
00185         LLSD pathArray = uri.pathArray();
00186         pathArray.erase(0); // erase "app"
00187         std::string cmd = pathArray.get(0);
00188         pathArray.erase(0); // erase "cmd"
00189         bool handled = LLCommandDispatcher::dispatch(
00190                         cmd, from_external_browser, pathArray, uri.queryMap());
00191         return handled;
00192 }
00193 
00194 // static
00195 bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, BOOL right_mouse)
00196 {
00197         if (!isSLURL(url))
00198         {
00199                 return false;
00200         }
00201 
00202         // Before we're logged in, need to update the startup screen
00203         // to tell the user where they are going.
00204         if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
00205         {
00206                 // Parse it and stash in globals, it will be dispatched in
00207                 // STATE_CLEANUP.
00208                 LLURLSimString::setString(url);
00209                 // We're at the login screen, so make sure user can see
00210                 // the login location box to know where they are going.
00211                 
00212                 LLPanelLogin::refreshLocation( true );
00213                 return true;
00214         }
00215 
00216         std::string sim_string = stripProtocol(url);
00217         std::string region_name;
00218         S32 x = 128;
00219         S32 y = 128;
00220         S32 z = 0;
00221         LLURLSimString::parse(sim_string, &region_name, &x, &y, &z);
00222 
00223         LLFloaterURLDisplay* url_displayp = LLFloaterURLDisplay::getInstance(LLSD());
00224         url_displayp->setName(region_name);
00225 
00226         // Request a region handle by name
00227         LLWorldMap::getInstance()->sendNamedRegionRequest(region_name,
00228                                                                           LLURLDispatcherImpl::regionNameCallback,
00229                                                                           url,
00230                                                                           false);       // don't teleport
00231         return true;
00232 }
00233 
00234 /*static*/
00235 void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)
00236 {
00237         std::string sim_string = stripProtocol(url);
00238         std::string region_name;
00239         S32 x = 128;
00240         S32 y = 128;
00241         S32 z = 0;
00242         LLURLSimString::parse(sim_string, &region_name, &x, &y, &z);
00243 
00244         LLVector3 local_pos;
00245         local_pos.mV[VX] = (F32)x;
00246         local_pos.mV[VY] = (F32)y;
00247         local_pos.mV[VZ] = (F32)z;
00248 
00249         
00250         // determine whether the point is in this region
00251         if ((x >= 0) && (x < REGION_WIDTH_UNITS) &&
00252                 (y >= 0) && (y < REGION_WIDTH_UNITS))
00253         {
00254                 // if so, we're done
00255                 regionHandleCallback(region_handle, url, snapshot_id, teleport);
00256         }
00257 
00258         else
00259         {
00260                 // otherwise find the new region from the location
00261                 
00262                 // add the position to get the new region
00263                 LLVector3d global_pos = from_region_handle(region_handle) + LLVector3d(local_pos);
00264 
00265                 U64 new_region_handle = to_region_handle(global_pos);
00266                 LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle,
00267                                                                                    LLURLDispatcherImpl::regionHandleCallback,
00268                                                                                    url, teleport);
00269         }
00270 }
00271 
00272 /* static */
00273 void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)
00274 {
00275         std::string sim_string = stripProtocol(url);
00276         std::string region_name;
00277         S32 x = 128;
00278         S32 y = 128;
00279         S32 z = 0;
00280         LLURLSimString::parse(sim_string, &region_name, &x, &y, &z);
00281 
00282         // remap x and y to local coordinates
00283         S32 local_x = x % REGION_WIDTH_UNITS;
00284         S32 local_y = y % REGION_WIDTH_UNITS;
00285         if (local_x < 0)
00286                 local_x += REGION_WIDTH_UNITS;
00287         if (local_y < 0)
00288                 local_y += REGION_WIDTH_UNITS;
00289         
00290         LLVector3 local_pos;
00291         local_pos.mV[VX] = (F32)local_x;
00292         local_pos.mV[VY] = (F32)local_y;
00293         local_pos.mV[VZ] = (F32)z;
00294 
00295 
00296         
00297         if (teleport)
00298         {
00299                 LLVector3d global_pos = from_region_handle(region_handle);
00300                 global_pos += LLVector3d(local_pos);
00301                 gAgent.teleportViaLocation(global_pos);
00302                 if(gFloaterWorldMap)
00303                 {
00304                         gFloaterWorldMap->trackLocation(global_pos);
00305                 }
00306         }
00307         else
00308         {
00309                 // display informational floater, allow user to click teleport btn
00310                 LLFloaterURLDisplay* url_displayp = LLFloaterURLDisplay::getInstance(LLSD());
00311 
00312 
00313                 url_displayp->displayParcelInfo(region_handle, local_pos);
00314                 if(snapshot_id.notNull())
00315                 {
00316                         url_displayp->setSnapshotDisplay(snapshot_id);
00317                 }
00318                 std::string locationString = llformat("%s %d, %d, %d", region_name.c_str(), x, y, z);
00319                 url_displayp->setLocationString(locationString);
00320         }
00321 }
00322 
00323 // static
00324 bool LLURLDispatcherImpl::matchPrefix(const std::string& url, const std::string& prefix)
00325 {
00326         std::string test_prefix = url.substr(0, prefix.length());
00327         LLString::toLower(test_prefix);
00328         return test_prefix == prefix;
00329 }
00330 
00331 // static
00332 std::string LLURLDispatcherImpl::stripProtocol(const std::string& url)
00333 {
00334         std::string stripped = url;
00335         if (matchPrefix(stripped, SLURL_SL_HELP_PREFIX))
00336         {
00337                 stripped.erase(0, SLURL_SL_HELP_PREFIX.length());
00338         }
00339         else if (matchPrefix(stripped, SLURL_SL_PREFIX))
00340         {
00341                 stripped.erase(0, SLURL_SL_PREFIX.length());
00342         }
00343         else if (matchPrefix(stripped, SLURL_SECONDLIFE_PREFIX))
00344         {
00345                 stripped.erase(0, SLURL_SECONDLIFE_PREFIX.length());
00346         }
00347         else if (matchPrefix(stripped, SLURL_SLURL_PREFIX))
00348         {
00349                 stripped.erase(0, SLURL_SLURL_PREFIX.length());
00350         }
00351         return stripped;
00352 }
00353 
00354 //---------------------------------------------------------------------------
00355 // Teleportation links are handled here because they are tightly coupled
00356 // to URL parsing and sim-fragment parsing
00357 class LLTeleportHandler : public LLCommandHandler
00358 {
00359 public:
00360         // not allowed from outside the app
00361         LLTeleportHandler() : LLCommandHandler("teleport", false) { }
00362 
00363         bool handle(const LLSD& tokens, const LLSD& queryMap)
00364         {
00365                 // construct a "normal" SLURL, resolve the region to
00366                 // a global position, and teleport to it
00367                 if (tokens.size() < 1) return false;
00368 
00369                 // Region names may be %20 escaped.
00370                 std::string region_name = LLURLSimString::unescapeRegionName(tokens[0]);
00371 
00372                 // build secondlife://De%20Haro/123/45/67 for use in callback
00373                 std::string url = SLURL_SECONDLIFE_PREFIX;
00374                 for (int i = 0; i < tokens.size(); ++i)
00375                 {
00376                         url += tokens[i].asString() + "/";
00377                 }
00378                 LLWorldMap::getInstance()->sendNamedRegionRequest(region_name,
00379                         LLURLDispatcherImpl::regionHandleCallback,
00380                         url,
00381                         true);  // teleport
00382                 return true;
00383         }
00384 };
00385 LLTeleportHandler gTeleportHandler;
00386 
00387 //---------------------------------------------------------------------------
00388 
00389 // static
00390 bool LLURLDispatcher::isSLURL(const std::string& url)
00391 {
00392         return LLURLDispatcherImpl::isSLURL(url);
00393 }
00394 
00395 // static
00396 bool LLURLDispatcher::isSLURLCommand(const std::string& url)
00397 {
00398         return LLURLDispatcherImpl::isSLURLCommand(url);
00399 }
00400 
00401 // static
00402 bool LLURLDispatcher::dispatch(const std::string& url, bool from_external_browser)
00403 {
00404         return LLURLDispatcherImpl::dispatch(url, from_external_browser);
00405 }
00406 // static
00407 bool LLURLDispatcher::dispatchRightClick(const std::string& url)
00408 {
00409         return LLURLDispatcherImpl::dispatchRightClick(url);
00410 }
00411 
00412 // static
00413 bool LLURLDispatcher::dispatchFromTextEditor(const std::string& url)
00414 {
00415         // text editors are by definition internal to our code
00416         const bool from_external_browser = false;
00417         return LLURLDispatcherImpl::dispatch(url, from_external_browser);
00418 }
00419 
00420 // static
00421 std::string LLURLDispatcher::buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z)
00422 {
00423         std::string slurl = SLURL_SLURL_PREFIX + regionname + llformat("/%d/%d/%d",x,y,z); 
00424         slurl = LLWeb::escapeURL( slurl );
00425         return slurl;
00426 }

Generated on Fri May 16 08:34:08 2008 for SecondLife by  doxygen 1.5.5