Update our url stuffs!

Adds support for JIRA link labels from Alchemy. (Made less of a mess by me)
Adds support for x-grid-info, the future of x-grid-info-location from Alchemy.
Updates uriparser latest from Alchemy.
Updates llstring to be more in line with upstream Alchemy.
Fixes our LLURI Implementation
Updates LLURLAction to modern C++ stuffies~
Adds Email protocol support from alchemy
Sync LLSLURL with Alchemy, adding x-grid-info support.
Also keep NoProtocol Support because yaaassss~
(also we won't suffer from MAINT-5019 because we're not dumb.)
This commit is contained in:
Lirusaito
2019-01-20 09:13:05 -05:00
parent 4b4c8c8e37
commit 7112e163e6
33 changed files with 1529 additions and 301 deletions

View File

@@ -2476,7 +2476,7 @@
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/uriparser-0.8.4-darwin-201511221948.tar.bz2</string>
<string>https://depot.alchemyviewer.org/pub/darwin/lib/uriparser-0.8.4-darwin-201511221948.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
@@ -2498,11 +2498,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>69224d9285e5a26fc7a9aca5d3da7543</string>
<string>cf21d9f7ed7949d2230413e8a391fb73</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>http://depot.alchemyviewer.org/pub/linux64/lib-trusty/uriparser-0.8.4-linux64-201603240044.tar.bz2</string>
<string>https://depot.alchemyviewer.org/pub/linux64/lib-xenial/uriparser-0.8.4-linux64-201609241428.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -2512,11 +2512,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>f9f82fbd29751a969e9ab55a1f33ac7b</string>
<string>89f3fc7f3fe396439d306f099d1a12d3</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>http://depot.alchemyviewer.org/pub/windows/lib-vc14/uriparser-0.8.4-windows-201601151009.tar.bz2</string>
<string>https://depot.alchemyviewer.org/pub/windows/lib-vc141/uriparser-0.8.4-windows-201703090606.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>

View File

@@ -40,6 +40,7 @@ set(cmake_SOURCE_FILES
FindNDOF.cmake
FindOpenJPEG.cmake
FindTut.cmake
FindURIPARSER.cmake
FindXmlRpcEpi.cmake
FreeType.cmake
GLOD.cmake
@@ -93,6 +94,7 @@ set(cmake_SOURCE_FILES
Tut.cmake
UI.cmake
UnixInstall.cmake
URIPARSER.cmake
Variables.cmake
ViewerMiscLibs.cmake
WinManifest.cmake

View File

@@ -0,0 +1,46 @@
# -*- cmake -*-
# - Find uriparser
# Find the URIPARSER includes and library
# This module defines
# URIPARSER_INCLUDE_DIRS, where to find uriparser.h, etc.
# URIPARSER_LIBRARY, the libraries needed to use uriparser.
# URIPARSER_FOUND, If false, do not try to use uriparser.
#
# This FindURIPARSER is about 43 times as fast the one provided with cmake (2.8.x),
# because it doesn't look up the version of uriparser, resulting in a dramatic
# speed up for configure (from 4 minutes 22 seconds to 6 seconds).
#
# Note: Since this file is only used for standalone, the windows
# specific parts were left out.
FIND_PATH(URIPARSER_INCLUDE_DIR uriparser/Uri.h
NO_SYSTEM_ENVIRONMENT_PATH
)
FIND_LIBRARY(URIPARSER_LIBRARY uriparser)
if (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR)
SET(URIPARSER_INCLUDE_DIRS ${URIPARSER_INCLUDE_DIR})
SET(URIPARSER_LIBRARY ${URIPARSER_LIBRARY})
SET(URIPARSER_FOUND "YES")
else (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR)
SET(URIPARSER_FOUND "NO")
endif (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR)
if (URIPARSER_FOUND)
if (NOT URIPARSER_FIND_QUIETLY)
message(STATUS "Found URIPARSER: ${URIPARSER_LIBRARY}")
SET(URIPARSER_FIND_QUIETLY TRUE)
endif (NOT URIPARSER_FIND_QUIETLY)
else (URIPARSER_FOUND)
if (URIPARSER_FIND_REQUIRED)
message(FATAL_ERROR "Could not find URIPARSER library")
endif (URIPARSER_FIND_REQUIRED)
endif (URIPARSER_FOUND)
mark_as_advanced(
URIPARSER_LIBRARY
URIPARSER_INCLUDE_DIR
)

View File

@@ -0,0 +1,20 @@
# -*- cmake -*-
set(URIPARSER_FIND_QUIETLY ON)
set(URIPARSER_FIND_REQUIRED ON)
include(Prebuilt)
if (USESYSTEMLIBS)
include(FindURIPARSER)
else (USESYSTEMLIBS)
use_prebuilt_binary(uriparser)
if (WINDOWS)
set(URIPARSER_LIBRARY
debug uriparserd
optimized uriparser)
elseif (DARWIN OR LINUX)
set(URIPARSER_LIBRARY uriparser)
endif (WINDOWS)
set(URIPARSER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/uriparser)
endif (USESYSTEMLIBS)

View File

@@ -13,6 +13,7 @@ include(LLSharedLibs)
include(GoogleBreakpad)
include(Copy3rdPartyLibs)
include(ZLIB)
include(URIPARSER)
include_directories(
${EXPAT_INCLUDE_DIRS}
@@ -101,6 +102,7 @@ set(llcommon_SOURCE_FILES
llthreadsafequeue.cpp
lltimer.cpp
lluri.cpp
lluriparser.cpp
lluuid.cpp
llworkerthread.cpp
metaclass.cpp
@@ -238,6 +240,7 @@ set(llcommon_HEADER_FILES
llunittype.h
lltypeinfolookup.h
lluri.h
lluriparser.h
lluuid.h
llwin32headers.h
llwin32headerslean.h
@@ -296,6 +299,7 @@ target_link_libraries(
${Boost_THREAD_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${CORESERVICES_LIBRARY}
${URIPARSER_LIBRARY}
)
if (DARWIN)

View File

@@ -1,3 +1,5 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
* @file llstring.cpp
* @brief String utility functions and the std::string class.
@@ -28,12 +30,17 @@
#include "llstring.h"
#include "llerror.h"
#include "llfasttimer.h"
#include "llsd.h"
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include <winnls.h> // for WideCharToMultiByte
#endif
LLTrace::BlockTimerStatHandle FT_STRING_FORMAT("String Format");
std::string ll_safe_string(const char* in)
{
if(in) return std::string(in);
@@ -47,6 +54,23 @@ std::string ll_safe_string(const char* in, S32 maxlen)
return std::string();
}
bool is_char_hex(char hex)
{
if((hex >= '0') && (hex <= '9'))
{
return true;
}
else if((hex >= 'a') && (hex <='f'))
{
return true;
}
else if((hex >= 'A') && (hex <='F'))
{
return true;
}
return false; // uh - oh, not hex any more...
}
U8 hex_as_nybble(char hex)
{
if((hex >= '0') && (hex <= '9'))
@@ -85,7 +109,7 @@ bool iswindividual(llwchar elem)
bool _read_file_into_string(std::string& str, const std::string& filename)
{
llifstream ifs(filename, llifstream::binary);
llifstream ifs(filename.c_str(), llifstream::binary);
if (!ifs.is_open())
{
LL_INFOS() << "Unable to open file " << filename << LL_ENDL;
@@ -552,6 +576,33 @@ std::string utf8str_truncate(const std::string& utf8str, const S32 max_len)
}
}
std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len)
{
if (0 == symbol_len)
{
return std::string();
}
if ((S32)utf8str.length() <= symbol_len)
{
return utf8str;
}
else
{
int len = 0, byteIndex = 0;
const char* aStr = utf8str.c_str();
size_t origSize = utf8str.size();
for (byteIndex = 0; len < symbol_len && byteIndex < origSize; byteIndex++)
{
if ((aStr[byteIndex] & 0xc0) != 0x80)
{
len += 1;
}
}
return utf8str.substr(0, byteIndex);
}
}
std::string utf8str_substChar(
const std::string& utf8str,
const llwchar target_char,
@@ -628,10 +679,10 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
0,
in,
len_in,
NULL,
nullptr,
0,
0,
0);
nullptr,
nullptr);
// We will need two more bytes for the double NULL ending
// created in WideCharToMultiByte().
char* pout = new char [len_out + 2];
@@ -645,8 +696,8 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
len_in,
pout,
len_out,
0,
0);
nullptr,
nullptr);
out.assign(pout);
delete[] pout;
}
@@ -667,8 +718,8 @@ wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page
// reserve place to NULL terminator
int output_str_len = in.length();
wchar_t* w_out = new wchar_t[output_str_len + 1];
memset(w_out, 0, output_str_len + 1);
int real_output_str_len = MultiByteToWideChar (code_page, 0, in.c_str(), in.length(), w_out, output_str_len);
//looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858.
@@ -689,7 +740,7 @@ std::string ll_convert_string_to_utf8_string(const std::string& in)
long LLStringOps::sPacificTimeOffset = 0;
long LLStringOps::sLocalTimeOffset = 0;
bool LLStringOps::sPacificDaylightTime = 0;
bool LLStringOps::sPacificDaylightTime = false;
std::map<std::string, std::string> LLStringOps::datetimeToCodes;
std::vector<std::string> LLStringOps::sWeekDayList;
@@ -708,7 +759,7 @@ S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
#if LL_WINDOWS
// in Windows, wide string functions operator on 16-bit strings,
// not the proper 32 bit wide string
return strcmp(wstring_to_utf8str(LLWString(a)).c_str(), wstring_to_utf8str(LLWString(b)).c_str());
return strcoll(wstring_to_utf8str(LLWString(a)).c_str(), wstring_to_utf8str(LLWString(b)).c_str());
#else
return wcscoll(a, b);
#endif
@@ -719,7 +770,7 @@ void LLStringOps::setupDatetimeInfo (bool daylight)
time_t nowT, localT, gmtT;
struct tm * tmpT;
nowT = time (NULL);
nowT = time (nullptr);
tmpT = gmtime (&nowT);
gmtT = mktime (tmpT);
@@ -799,7 +850,7 @@ void LLStringOps::setupDayFormat(const std::string& data)
}
std::string LLStringOps::getDatetimeCode (std::string key)
std::string LLStringOps::getDatetimeCode(const std::string& key)
{
std::map<std::string, std::string>::iterator iter;
@@ -1167,6 +1218,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
template<>
S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
{
LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT);
S32 res = 0;
std::string output;
@@ -1239,6 +1291,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
template<>
S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
{
LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT);
S32 res = 0;
if (!substitutions.isMap())
@@ -1367,7 +1420,7 @@ void LLStringUtilBase<T>::testHarness()
s2.erase( 4, 1 );
llassert( s2 == "hell");
s2.insert( 0, 1, 'y' );
s2.insert( s2.begin(), 'y' );
llassert( s2 == "yhell");
s2.erase( 1, 3 );
llassert( s2 == "yl");

View File

@@ -29,8 +29,11 @@
#include <string>
#include <cstdio>
#include <locale>
//#include <locale>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <map>
#include "llsd.h"
#include "llfasttimer.h"
@@ -49,6 +52,7 @@
#endif
const char LL_UNKNOWN_CHAR = '?';
class LLSD;
#if LL_DARWIN || LL_LINUX || LL_SOLARIS
// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already)
@@ -209,7 +213,7 @@ public:
// currently in daylight savings time?
static bool getPacificDaylightTime(void) { return sPacificDaylightTime;}
static std::string getDatetimeCode (std::string key);
static std::string getDatetimeCode (const std::string& key);
};
/**
@@ -298,7 +302,7 @@ public:
static bool isValidIndex(const string_type& string, size_type i)
{
return !string.empty() && (0 <= i) && (i <= string.size());
return !string.empty() && (i <= string.size());
}
static bool contains(const string_type& string, T c, size_type i=0)
@@ -308,6 +312,7 @@ public:
static void trimHead(string_type& string);
static void trimTail(string_type& string);
static void trimTail(string_type& string, const string_type& tokens);
static void trim(string_type& string) { trimHead(string); trimTail(string); }
static void truncate(string_type& string, size_type count);
@@ -337,6 +342,7 @@ public:
static void addCRLF(string_type& string);
static void removeCRLF(string_type& string);
static void removeWindowsCR(string_type& string);
static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab );
static void replaceNonstandardASCII( string_type& string, T replacement );
@@ -445,7 +451,7 @@ public:
struct LLDictionaryLess
{
public:
bool operator()(const std::string& a, const std::string& b)
bool operator()(const std::string& a, const std::string& b) const
{
return (LLStringUtil::precedesDict(a, b) ? true : false);
}
@@ -475,6 +481,7 @@ inline std::string chop_tail_copy(
* @brief This translates a nybble stored as a hex value from 0-f back
* to a nybble in the low order bits of the return byte.
*/
LL_COMMON_API bool is_char_hex(char hex);
LL_COMMON_API U8 hex_as_nybble(char hex);
/**
@@ -529,10 +536,13 @@ LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
#if LL_WINDOWS
inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);}
#endif
// Length of this UTF32 string in bytes when transformed to UTF8
LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr);
@@ -548,7 +558,7 @@ LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len
LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.)
LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = nullptr);
/**
* @brief Properly truncate a utf8 string to a maximum byte count.
@@ -568,6 +578,17 @@ LL_COMMON_API S32 utf8str_compare_insensitive(
const std::string& lhs,
const std::string& rhs);
/**
* @brief Properly truncate a utf8 string to a maximum character count.
*
* If symbol_len is longer than the string passed in, the return
* value == utf8str.
* @param utf8str A valid utf8 string to truncate.
* @param symbol_len The maximum number of symbols in the return value.
* @return Returns a valid utf8 string with symbol count <= max_len.
*/
LL_COMMON_API std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len);
/**
* @brief Replace all occurences of target_char with replace_char
*
@@ -810,8 +831,9 @@ public:
}
/// This implementation uses the answer cached by setiter().
virtual bool escaped() const { return mIsEsc; }
virtual T next()
bool escaped() const override { return mIsEsc; }
T next() override
{
// If we're looking at the escape character of an escape sequence,
// skip that character. This is the one time we can modify 'mIter'
@@ -827,21 +849,21 @@ public:
return result;
}
virtual bool is(T ch) const
bool is(T ch) const override
{
// Like base-class is(), except that an escaped character matches
// nothing.
return (! done()) && (! mIsEsc) && *mIter == ch;
}
virtual bool oneof(const string_type& delims) const
bool oneof(const string_type& delims) const override
{
// Like base-class oneof(), except that an escaped character matches
// nothing.
return (! done()) && (! mIsEsc) && LLStringUtilBase<T>::contains(delims, *mIter);
}
virtual bool collect_until(string_type& into, const_iterator from, T delim)
bool collect_until(string_type& into, const_iterator from, T delim) override
{
// Deal with escapes in the characters we collect; that is, an escaped
// character must become just that character without the preceding
@@ -1155,7 +1177,7 @@ BOOL LLStringUtilBase<T>::precedesDict( const string_type& a, const string_type&
{
if( a.size() && b.size() )
{
return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0);
return (LLStringUtilBase<T>::compareDict(a, b) < 0);
}
else
{
@@ -1210,7 +1232,7 @@ void LLStringUtilBase<T>::trimHead(string_type& string)
template<class T>
void LLStringUtilBase<T>::trimTail(string_type& string)
{
if( string.size() )
if(!string.empty())
{
size_type len = string.length();
size_type i = len;
@@ -1223,12 +1245,31 @@ void LLStringUtilBase<T>::trimTail(string_type& string)
}
}
template<class T>
void LLStringUtilBase<T>::trimTail(string_type& string, const string_type& tokens)
{
if(!string.empty())
{
size_type len = string.length();
size_type i = len;
while( i > 0 && (tokens.find_first_of(string[i-1]) != string_type::npos) )
{
i--;
}
string.erase( i, len - i );
}
}
// Replace line feeds with carriage return-line feed pairs.
//static
template<class T>
void LLStringUtilBase<T>::addCRLF(string_type& string)
{
if (string.empty())
return;
const T LF = 10;
const T CR = 13;
@@ -1271,6 +1312,9 @@ void LLStringUtilBase<T>::addCRLF(string_type& string)
template<class T>
void LLStringUtilBase<T>::removeCRLF(string_type& string)
{
if (string.empty())
return;
const T CR = 13;
size_type cr_count = 0;
@@ -1290,6 +1334,32 @@ void LLStringUtilBase<T>::removeCRLF(string_type& string)
//static
template<class T>
void LLStringUtilBase<T>::removeWindowsCR(string_type& string)
{
if (string.empty())
{
return;
}
const T LF = 10;
const T CR = 13;
size_type cr_count = 0;
size_type len = string.size();
size_type i;
for( i = 0; i < len - cr_count - 1; i++ )
{
if( string[i+cr_count] == CR && string[i+cr_count+1] == LF)
{
cr_count++;
}
string[i] = string[i+cr_count];
}
string.erase(i, cr_count);
}
//static
template<class T>
void LLStringUtilBase<T>::replaceChar( string_type& string, T target, T replacement )
{
size_type found_pos = 0;
@@ -1373,6 +1443,7 @@ BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)
return rv;
}
// *TODO: reimplement in terms of algorithm
//static
template<class T>
void LLStringUtilBase<T>::stripNonprintable(string_type& string)
@@ -1383,33 +1454,23 @@ void LLStringUtilBase<T>::stripNonprintable(string_type& string)
{
return;
}
size_t src_size = string.size();
char* c_string = nullptr;
try
{
c_string = new char[src_size + 1];
}
catch (const std::bad_alloc&)
{
return;
}
copy(c_string, string.c_str(), src_size+1);
char* write_head = &c_string[0];
const size_t src_size = string.size();
auto c_string = std::make_unique<char[]>(src_size + 1);
copy(c_string.get(), string.c_str(), src_size+1);
for (size_type i = 0; i < src_size; i++)
{
char* read_head = &string[i];
write_head = &c_string[j];
if(!(*read_head < MIN))
if(string[i] >= MIN)
{
*write_head = *read_head;
c_string[j] = string[i];
++j;
}
}
c_string[j]= '\0';
string = c_string;
delete []c_string;
string.assign(c_string.get());
}
// *TODO: reimplement in terms of algorithm
template<class T>
std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str,
const string_type& triggers,
@@ -1431,7 +1492,9 @@ std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str,
}
// For whatever reason, we must quote this string.
auto needed_escapes = std::count(str.begin(), str.end(), '"');
string_type result;
result.reserve(len + (needed_escapes * escape.length()));
result.push_back('"');
for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci)
{

View File

@@ -1,3 +1,5 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
* @file lluri.cpp
* @author Phoenix
@@ -40,7 +42,8 @@
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/algorithm/string/finder.hpp>
void encode_character(std::ostream& ostr, std::string::value_type val)
// static
void LLURI::encodeCharacter(std::ostream& ostr, std::string::value_type val)
{
ostr << "%"
@@ -95,7 +98,7 @@ std::string LLURI::escape(
}
else
{
encode_character(ostr, c);
encodeCharacter(ostr, c);
}
}
}
@@ -106,7 +109,7 @@ std::string LLURI::escape(
c = *it;
if(allowed.find(c) == std::string::npos)
{
encode_character(ostr, c);
encodeCharacter(ostr, c);
}
else
{
@@ -129,11 +132,30 @@ std::string LLURI::unescape(const std::string& str)
{
++it;
if(it == end) break;
U8 c = hex_as_nybble(*it++);
c = c << 4;
if (it == end) break;
c |= hex_as_nybble(*it);
ostr.put((char)c);
if(is_char_hex(*it))
{
U8 c = hex_as_nybble(*it++);
c = c << 4;
if (it == end) break;
if(is_char_hex(*it))
{
c |= hex_as_nybble(*it);
ostr.put((char)c);
}
else
{
ostr.put((char)c);
ostr.put(*it);
}
}
else
{
ostr.put('%');
ostr.put(*it);
}
}
else
{
@@ -169,11 +191,10 @@ namespace
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@"
}
// *TODO: Consider using curl. After http textures gets merged everywhere.
// static
std::string LLURI::escape(const std::string& str)
{
static std::string default_allowed(unreserved() + ":@!$'()*+,=/?&#;");
static std::string default_allowed = unreserved();
static bool initialized = false;
if(!initialized)
{
@@ -228,7 +249,8 @@ void LLURI::parseAuthorityAndPathUsingOpaque()
{
if (mScheme == "http" || mScheme == "https" ||
mScheme == "ftp" || mScheme == "secondlife" ||
mScheme == "x-grid-location-info")
mScheme == "x-grid-info" ||
mScheme == "x-grid-location-info") // legacy
{
if (mEscapedOpaque.substr(0,2) != "//")
{
@@ -401,6 +423,15 @@ LLURI LLURI::buildHTTP(const std::string& prefix,
return uri;
}
// static
LLURI LLURI::buildHTTP(const std::string& scheme,
const std::string& prefix,
const LLSD& path,
const LLSD& query)
{
return buildHTTP(llformat("%s://%s", scheme.c_str(), prefix.c_str()), path, query);
}
// static
LLURI LLURI::buildHTTP(const std::string& host,
const U32& port,
@@ -485,6 +516,14 @@ std::string LLURI::hostName() const
return unescape(host);
}
std::string LLURI::hostNameAndPort() const
{
std::string user, host, port;
findAuthorityParts(mEscapedAuthority, user, host, port);
return port.empty() ? unescape(host) : unescape(host + ":" + port);
}
std::string LLURI::userName() const
{
std::string user, userPass, host, port;

View File

@@ -4,31 +4,25 @@
* @date 2006-02-05
* @brief Declaration of the URI class.
*
* $LicenseInfo:firstyear=2006&license=viewergpl$
*
* Copyright (c) 2006-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* 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
* Copyright (C) 2010, Linden Research, Inc.
*
* 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
* 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.
*
* 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.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
@@ -72,6 +66,13 @@ public:
const std::string& prefix,
const LLSD& path,
const LLSD& query);
static LLURI buildHTTP(
const std::string& scheme,
const std::string& prefix,
const LLSD& path,
const LLSD& query);
///< prefix is either a full URL prefix of the form
/// "http://example.com:8080", or it can be simply a host and
/// optional port like "example.com" or "example.com:8080", in
@@ -99,20 +100,21 @@ public:
std::string scheme() const; ///< ex.: "http", note lack of colon
std::string opaque() const; ///< everything after the colon
// for schemes that follow path like syntax (http, https, ftp)
std::string authority() const; // ex.: "host.com:80"
std::string hostName() const; // ex.: "host.com"
std::string userName() const;
std::string password() const;
U16 hostPort() const; // ex.: 80, will include implicit port
BOOL defaultPort() const; // true if port is default for scheme
const std::string& escapedPath() const { return mEscapedPath; }
std::string path() const; // ex.: "/abc/def", includes leading slash
LLSD pathArray() const; // above decoded into an array of strings
std::string query() const; // ex.: "x=34", section after "?"
const std::string& escapedQuery() const { return mEscapedQuery; }
LLSD queryMap() const; // above decoded into a map
static LLSD queryMap(std::string escaped_query_string);
// for schemes that follow path like syntax (http, https, ftp)
std::string authority() const; // ex.: "user:pass@host.com:80"
std::string hostName() const; // ex.: "host.com"
std::string hostNameAndPort() const; // ex.: "host.com:80"
std::string userName() const;
std::string password() const;
U16 hostPort() const; // ex.: 80, will include implicit port
BOOL defaultPort() const; // true if port is default for scheme
const std::string& escapedPath() const { return mEscapedPath; }
std::string path() const; // ex.: "/abc/def", includes leading slash
LLSD pathArray() const; // above decoded into an array of strings
std::string query() const; // ex.: "x=34", section after "?"
const std::string& escapedQuery() const { return mEscapedQuery; }
LLSD queryMap() const; // above decoded into a map
static LLSD queryMap(std::string escaped_query_string);
/**
* @brief given a name value map, return a serialized query string.
@@ -127,27 +129,24 @@ public:
/** @name Escaping Utilities */
//@{
/**
* @brief Escape a raw url with a reasonable set of allowed characters.
* @brief 'Escape' symbol into stream
*
* The default set was chosen to match HTTP urls and general
* guidelines for naming resources. Passing in a raw url does not
* produce well defined results because you really need to know
* which segments are path parts because path parts are supposed
* to be escaped individually. The default set chosen is:
* @param ostr Output stream.
* @param val Symbol to encode.
*/
static void encodeCharacter(std::ostream& ostr, std::string::value_type val);
/**
* @brief Escape the string passed except for unreserved
*
* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
* 0123456789
* -._~
* :@!$'()*+,=/?&#;
*
* *NOTE: This API is basically broken because it does not
* allow you to specify significant path characters. For example,
* if the filename actually contained a /, then you cannot use
* this function to generate the serialized url for that
* resource.
* @see http://www.ietf.org/rfc/rfc1738.txt
*
* @param str The raw URI to escape.
* @return Returns the escaped uri or an empty string.
* @return Returns the rfc 1738 escaped uri or an empty string.
*/
static std::string escape(const std::string& str);

View File

@@ -0,0 +1,266 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
* @file lluriparser.cpp
* @author Protey
* @date 2014-10-07
* @brief Implementation of the LLUriParser class.
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "linden_common.h"
#include "lluriparser.h"
LLUriParser::LLUriParser(const std::string& u)
: mRes(0)
, mTmpScheme(false)
, mNormalizedTmp(false)
{
mState.uri = &mUri;
if (u.find("://") == std::string::npos)
{
mNormalizedUri = "http://";
mTmpScheme = true;
}
mNormalizedUri += u;
mRes = parse();
}
LLUriParser::~LLUriParser()
{
uriFreeUriMembersA(&mUri);
}
S32 LLUriParser::parse()
{
mRes = uriParseUriA(&mState, mNormalizedUri.c_str());
return mRes;
}
const char * LLUriParser::scheme() const
{
return mScheme.c_str();
}
void LLUriParser::scheme(const std::string& s)
{
mTmpScheme = !s.size();
mScheme = s;
}
const char * LLUriParser::port() const
{
return mPort.c_str();
}
void LLUriParser::port(const std::string& s)
{
mPort = s;
}
const char * LLUriParser::host() const
{
return mHost.c_str();
}
void LLUriParser::host(const std::string& s)
{
mHost = s;
}
const char * LLUriParser::path() const
{
return mPath.c_str();
}
void LLUriParser::path(const std::string& s)
{
mPath = s;
}
const char * LLUriParser::query() const
{
return mQuery.c_str();
}
void LLUriParser::query(const std::string& s)
{
mQuery = s;
}
const char * LLUriParser::fragment() const
{
return mFragment.c_str();
}
void LLUriParser::fragment(const std::string& s)
{
mFragment = s;
}
void LLUriParser::textRangeToString(UriTextRangeA& textRange, std::string& str)
{
if (textRange.first != nullptr && textRange.afterLast != nullptr && textRange.first < textRange.afterLast)
{
const ptrdiff_t len = textRange.afterLast - textRange.first;
str.assign(textRange.first, static_cast<std::string::size_type>(len));
}
else
{
str = LLStringUtil::null;
}
}
void LLUriParser::extractParts()
{
if (mTmpScheme || mNormalizedTmp)
{
mScheme.clear();
}
else
{
textRangeToString(mUri.scheme, mScheme);
}
textRangeToString(mUri.hostText, mHost);
textRangeToString(mUri.portText, mPort);
textRangeToString(mUri.query, mQuery);
textRangeToString(mUri.fragment, mFragment);
UriPathSegmentA * pathHead = mUri.pathHead;
while (pathHead)
{
std::string partOfPath;
textRangeToString(pathHead->text, partOfPath);
mPath += '/';
mPath += partOfPath;
pathHead = pathHead->next;
}
}
S32 LLUriParser::normalize()
{
mNormalizedTmp = mTmpScheme;
if (!mRes)
{
mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST);
if (!mRes)
{
S32 chars_required;
mRes = uriToStringCharsRequiredA(&mUri, &chars_required);
if (!mRes)
{
chars_required++;
std::vector<char> label_buf(chars_required);
mRes = uriToStringA(&label_buf[0], &mUri, chars_required, nullptr);
if (!mRes)
{
mNormalizedUri = &label_buf[mTmpScheme ? 7 : 0];
mTmpScheme = false;
}
}
}
}
if(mTmpScheme)
{
mNormalizedUri = mNormalizedUri.substr(7);
mTmpScheme = false;
}
return mRes;
}
void LLUriParser::glue(std::string& uri) const
{
std::string first_part;
glueFirst(first_part);
std::string second_part;
glueSecond(second_part);
uri = first_part + second_part;
}
void LLUriParser::glueFirst(std::string& uri, bool use_scheme) const
{
if (use_scheme && mScheme.size())
{
uri = mScheme;
uri += "://";
}
else
{
uri.clear();
}
uri += mHost;
}
void LLUriParser::glueSecond(std::string& uri) const
{
if (mPort.size())
{
uri = ':';
uri += mPort;
}
else
{
uri.clear();
}
uri += mPath;
if (mQuery.size())
{
uri += '?';
uri += mQuery;
}
if (mFragment.size())
{
uri += '#';
uri += mFragment;
}
}
bool LLUriParser::test() const
{
std::string uri;
glue(uri);
return uri == mNormalizedUri;
}
const char * LLUriParser::normalizedUri() const
{
return mNormalizedUri.c_str();
}

View File

@@ -0,0 +1,87 @@
/**
* @file lluriparser.h
* @author Protey
* @date 20146-10-07
* @brief Declaration of the UriParser class.
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#ifndef LL_LLURIPARSER_H
#define LL_LLURIPARSER_H
#include <string>
#include <uriparser/Uri.h>
class LL_COMMON_API LLUriParser
{
public:
LLUriParser(const std::string& u);
~LLUriParser();
const char * scheme() const;
void scheme (const std::string& s);
const char * port() const;
void port (const std::string& s);
const char * host() const;
void host (const std::string& s);
const char * path() const;
void path (const std::string& s);
const char * query() const;
void query (const std::string& s);
const char * fragment() const;
void fragment (const std::string& s);
const char * normalizedUri() const;
void extractParts();
void glue(std::string& uri) const;
void glueFirst(std::string& uri, bool use_scheme = true) const;
void glueSecond(std::string& uri) const;
bool test() const;
S32 normalize();
private:
S32 parse();
void textRangeToString(UriTextRangeA& textRange, std::string& str);
std::string mScheme;
std::string mHost;
std::string mPort;
std::string mPath;
std::string mQuery;
std::string mFragment;
std::string mNormalizedUri;
UriParserStateA mState;
UriUriA mUri;
S32 mRes;
bool mTmpScheme;
bool mNormalizedTmp;
};
#endif // LL_LLURIPARSER_H

View File

@@ -4238,6 +4238,23 @@ void LLTextEditor::appendTextImpl(const std::string &new_text, const LLStyleSP s
{
setLastSegmentToolTip(match.getTooltip());
}
// show query part of url with gray color only for LLUrlEntryHTTP and LLUrlEntryHTTPNoProtocol url entries
std::string label = match.getQuery();
if (!label.empty())
{
/* Singu Note: Upstream uses hardcoded Grey here, they have no care for skins, this could be awful! For now just make it a normal link
link_params.color = LLColor4::grey;
link_params.readonly_color = LLColor4::grey;
appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly());*/
append_link(label);
// set the tooltip for the query part of url
if (tooltip_required)
{
setLastSegmentToolTip(match.getTooltip());
}
}
}
else if (!replace_links) // Still link the link itself
{
@@ -4804,7 +4821,7 @@ BOOL LLTextEditor::handleMouseUpOverSegment(S32 x, S32 y, MASK mask)
if (auto style = segment->getStyle())
{
if (style->isLink())
LLUrlAction::clickAction(style->getLinkHREF());
LLUrlAction::clickAction(style->getLinkHREF(), true);
}
}
}

View File

@@ -1,3 +1,5 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
* @file llurlaction.cpp
* @author Martin Reddy
@@ -24,7 +26,6 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llurlaction.h"
@@ -32,6 +33,7 @@
#include "llwindow.h"
#include "llurlregistry.h"
// global state for the callback functions
LLUrlAction::url_callback_t LLUrlAction::sOpenURLCallback;
LLUrlAction::url_callback_t LLUrlAction::sOpenURLInternalCallback;
@@ -83,18 +85,19 @@ void LLUrlAction::openURLExternal(std::string url)
}
}
void LLUrlAction::executeSLURL(std::string url)
bool LLUrlAction::executeSLURL(std::string url, bool trusted_content)
{
if (sExecuteSLURLCallback)
{
sExecuteSLURLCallback(url);
return sExecuteSLURLCallback(url, trusted_content);
}
return false;
}
void LLUrlAction::clickAction(std::string url)
void LLUrlAction::clickAction(std::string url, bool trusted_content)
{
// Try to handle as SLURL first, then http Url
if ( (sExecuteSLURLCallback) && !sExecuteSLURLCallback(url) )
if ( (sExecuteSLURLCallback) && !sExecuteSLURLCallback(url, trusted_content) )
{
if (sOpenURLCallback)
{
@@ -157,3 +160,86 @@ void LLUrlAction::showProfile(std::string url)
}
}
}
std::string LLUrlAction::getUserID(std::string url)
{
LLURI uri(url);
LLSD path_array = uri.pathArray();
std::string id_str;
if (path_array.size() == 4)
{
id_str = path_array.get(2).asString();
}
return id_str;
}
std::string LLUrlAction::getObjectId(std::string url)
{
LLURI uri(url);
LLSD path_array = uri.pathArray();
std::string id_str;
if (path_array.size() >= 3)
{
id_str = path_array.get(2).asString();
}
return id_str;
}
std::string LLUrlAction::getObjectName(std::string url)
{
LLURI uri(url);
LLSD query_map = uri.queryMap();
std::string name;
if (query_map.has("name"))
{
name = query_map["name"].asString();
}
return name;
}
void LLUrlAction::sendIM(std::string url)
{
std::string id_str = getUserID(url);
if (LLUUID::validate(id_str))
{
executeSLURL("secondlife:///app/agent/" + id_str + "/im");
}
}
void LLUrlAction::addFriend(std::string url)
{
std::string id_str = getUserID(url);
if (LLUUID::validate(id_str))
{
executeSLURL("secondlife:///app/agent/" + id_str + "/requestfriend");
}
}
void LLUrlAction::removeFriend(std::string url)
{
std::string id_str = getUserID(url);
if (LLUUID::validate(id_str))
{
executeSLURL("secondlife:///app/agent/" + id_str + "/removefriend");
}
}
void LLUrlAction::blockObject(std::string url)
{
std::string object_id = getObjectId(url);
std::string object_name = getObjectName(url);
if (LLUUID::validate(object_id))
{
executeSLURL("secondlife:///app/agent/" + object_id + "/block/" + LLURI::escape(object_name));
}
}
void LLUrlAction::unblockObject(std::string url)
{
std::string object_id = getObjectId(url);
std::string object_name = getObjectName(url);
if (LLUUID::validate(object_id))
{
executeSLURL("secondlife:///app/agent/" + object_id + "/unblock/" + object_name);
}
}

View File

@@ -28,11 +28,7 @@
#ifndef LL_LLURLACTION_H
#define LL_LLURLACTION_H
#include <string>
#ifndef BOOST_FUNCTION_HPP_INCLUDED
#include <boost/function.hpp>
#define BOOST_FUNCTION_HPP_INCLUDED
#endif
#include <functional>
///
/// The LLUrlAction class provides a number of static functions that
@@ -60,7 +56,7 @@ public:
static void openURLExternal(std::string url);
/// execute the given secondlife: SLURL
static void executeSLURL(std::string url);
static bool executeSLURL(std::string url, bool trusted_content = true);
/// if the Url specifies an SL location, teleport there
static void teleportToLocation(std::string url);
@@ -69,7 +65,7 @@ public:
static void showLocationOnMap(std::string url);
/// perform the appropriate action for left-clicking on a Url
static void clickAction(std::string url);
static void clickAction(std::string url, bool trusted_content);
/// copy the label for a Url to the clipboard
static void copyLabelToClipboard(std::string url);
@@ -79,10 +75,18 @@ public:
/// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile
static void showProfile(std::string url);
static std::string getUserID(std::string url);
static std::string getObjectName(std::string url);
static std::string getObjectId(std::string url);
static void sendIM(std::string url);
static void addFriend(std::string url);
static void removeFriend(std::string url);
static void blockObject(std::string url);
static void unblockObject(std::string url);
/// specify the callbacks to enable this class's functionality
typedef boost::function<void (const std::string&)> url_callback_t;
typedef boost::function<bool(const std::string& url)> execute_url_callback_t;
typedef std::function<void (const std::string&)> url_callback_t;
typedef std::function<bool(const std::string& url, bool trusted_content)> execute_url_callback_t;
static void setOpenURLCallback(url_callback_t cb);
static void setOpenURLInternalCallback(url_callback_t cb);

View File

@@ -1,3 +1,5 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
* @file llurlentry.cpp
* @author Martin Reddy
@@ -31,6 +33,7 @@
#include "lluri.h"
#include "llurlmatch.h"
#include "llurlregistry.h"
#include "lluriparser.h"
#include "llavatarnamecache.h"
#include "llcachename.h"
@@ -38,14 +41,18 @@
//#include "lluicolortable.h"
#include "message.h"
#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
#include <boost/format.hpp> // <alchemy/>
#define APP_HEADER_REGEX "((((x-grid-info://)|(x-grid-location-info://))[-\\w\\.]+(:\\d+)?/app)|(secondlife:///app))"
#define X_GRID_OR_SECONDLIFE_HEADER_REGEX "((((x-grid-info://)|(x-grid-location-info://))[-\\w\\.]+(:\\d+)?/)|(secondlife://))"
// Utility functions
std::string localize_slapp_label(const std::string& url, const std::string& full_name);
LLUrlEntryBase::LLUrlEntryBase()
{}
{
}
LLUrlEntryBase::~LLUrlEntryBase()
{
@@ -111,7 +118,7 @@ std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url) const
{
// return the label part from [http://www.example.org Label]
const char *text = url.c_str();
S32 start = 0;
size_t start = 0;
while (! isspace(text[start]))
{
start++;
@@ -127,7 +134,7 @@ std::string LLUrlEntryBase::getUrlFromWikiLink(const std::string &string) const
{
// return the url part from [http://www.example.org Label]
const char *text = string.c_str();
S32 end = 0;
size_t end = 0;
while (! isspace(text[end]))
{
end++;
@@ -142,11 +149,14 @@ void LLUrlEntryBase::addObserver(const std::string &id,
// add a callback to be notified when we have a label for the uuid
LLUrlEntryObserver observer;
observer.url = url;
observer.signal = new LLUrlLabelSignal();
if (observer.signal)
try
{
observer.signal = new LLUrlLabelSignal();
observer.signal->connect(cb);
mObservers.insert(std::pair<std::string, LLUrlEntryObserver>(id, observer));
mObservers.emplace(id, observer);
}
catch (...)
{
}
}
@@ -178,12 +188,49 @@ bool LLUrlEntryBase::isLinkDisabled() const
return globally_disabled;
}
static std::string getStringAfterToken(const std::string str, const std::string token)
bool LLUrlEntryBase::isWikiLinkCorrect(const std::string& url)
{
LLWString label = utf8str_to_wstring(getLabelFromWikiLink(url));
label.erase(std::remove(label.begin(), label.end(), L'\u200B'), label.end());
return (LLUrlRegistry::instance().hasUrl(wstring_to_utf8str(label))) ? false : true;
}
std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const
{
LLUriParser up(unescapeUrl(url));
up.normalize();
std::string label;
up.extractParts();
up.glueFirst(label);
return label;
}
std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const
{
LLUriParser up(unescapeUrl(url));
std::string label;
up.extractParts();
up.glueFirst(label, false);
size_t pos = url.find(label);
if (pos == std::string::npos)
{
return "";
}
pos += label.size();
return url.substr(pos);
}
static std::string getStringAfterToken(const std::string& str, const std::string& token)
{
size_t pos = str.find(token);
if (pos == std::string::npos)
{
return "";
return std::string();
}
pos += token.size();
@@ -194,8 +241,9 @@ static std::string getStringAfterToken(const std::string str, const std::string
// LLUrlEntryHTTP Describes generic http: and https: Urls
//
LLUrlEntryHTTP::LLUrlEntryHTTP()
: LLUrlEntryBase()
{
mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*",
mPattern = boost::regex("https?://([^\\s/?\\.#]+\\.?)+\\.\\w+(:\\d+)?(/\\S*)?",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
@@ -206,6 +254,20 @@ std::string LLUrlEntryHTTP::getLabel(const std::string &url, const LLUrlLabelCal
return unescapeUrl(url);
}
std::string LLUrlEntryHTTP::getUrl(const std::string &string) const
{
if (string.find("://") == std::string::npos)
{
return "http://" + escapeUrl(string);
}
return escapeUrl(string);
}
std::string LLUrlEntryHTTP::getTooltip(const std::string &url) const
{
return mTooltip;;
}
//
// LLUrlEntryHTTP Describes generic http: and https: Urls with custom label
// We use the wikipedia syntax of [http://www.example.org Text]
@@ -238,20 +300,22 @@ std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const
// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com
//
LLUrlEntryHTTPNoProtocol::LLUrlEntryHTTPNoProtocol()
: LLUrlEntryBase()
{
mPattern = boost::regex("("
"\\bwww\\.\\S+\\.\\S+" // i.e. www.FOO.BAR
"|" // or
"(?<!@)\\b[^[:space:]:@/>]+\\.(?:com|net|edu|org)([/:][^[:space:]<]*)?\\b" // i.e. FOO.net
")",
boost::regex::perl|boost::regex::icase);
mPattern = boost::regex("\\bwww\\.\\S+\\.([^\\s<]*)?\\b", // i.e. www.FOO.BAR
boost::regex::perl | boost::regex::icase);
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
}
std::string LLUrlEntryHTTPNoProtocol::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
return unescapeUrl(url);
return urlToLabelWithGreyQuery(url);
}
std::string LLUrlEntryHTTPNoProtocol::getQuery(const std::string &url) const
{
return urlToGreyQuery(url);
}
std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const
@@ -263,6 +327,95 @@ std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const
return escapeUrl(string);
}
std::string LLUrlEntryHTTPNoProtocol::getTooltip(const std::string &url) const
{
return unescapeUrl(url);
}
LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL()
: LLUrlEntryBase()
{
mPattern = boost::regex("(http://(maps.secondlife.com|slurl.com)/secondlife/|secondlife://(/app/(worldmap|teleport)/)?)[^ /]+(/-?[0-9]+){1,3}(/?(\\?title|\\?img|\\?msg)=\\S*)?/?",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
}
std::string LLUrlEntryInvalidSLURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
return escapeUrl(url);
}
std::string LLUrlEntryInvalidSLURL::getUrl(const std::string &string) const
{
return escapeUrl(string);
}
std::string LLUrlEntryInvalidSLURL::getTooltip(const std::string &url) const
{
return unescapeUrl(url);
}
bool LLUrlEntryInvalidSLURL::isSLURLvalid(const std::string &url) const
{
S32 actual_parts;
if(url.find(".com/secondlife/") != std::string::npos)
{
actual_parts = 5;
}
else if(url.find("/app/") != std::string::npos)
{
actual_parts = 6;
}
else
{
actual_parts = 3;
}
LLURI uri(url);
LLSD path_array = uri.pathArray();
S32 path_parts = path_array.size();
S32 x,y,z;
if (path_parts == actual_parts)
{
// handle slurl with (X,Y,Z) coordinates
LLStringUtil::convertToS32(path_array[path_parts-3],x);
LLStringUtil::convertToS32(path_array[path_parts-2],y);
LLStringUtil::convertToS32(path_array[path_parts-1],z);
if((x>= 0 && x<= 256) && (y>= 0 && y<= 256) && (z>= 0))
{
return TRUE;
}
}
else if (path_parts == (actual_parts-1))
{
// handle slurl with (X,Y) coordinates
LLStringUtil::convertToS32(path_array[path_parts-2],x);
LLStringUtil::convertToS32(path_array[path_parts-1],y);
;
if((x>= 0 && x<= 256) && (y>= 0 && y<= 256))
{
return TRUE;
}
}
else if (path_parts == (actual_parts-2))
{
// handle slurl with (X) coordinate
LLStringUtil::convertToS32(path_array[path_parts-1],x);
if(x>= 0 && x<= 256)
{
return TRUE;
}
}
return FALSE;
}
//
// LLUrlEntrySLURL Describes generic http: and https: Urls
//
@@ -284,6 +437,7 @@ std::string LLUrlEntrySLURL::getLabel(const std::string &url, const LLUrlLabelCa
// - http://slurl.com/secondlife/Place/X
// - http://slurl.com/secondlife/Place
//
LLURI uri(url);
LLSD path_array = uri.pathArray();
S32 path_parts = path_array.size();
@@ -335,13 +489,62 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
return url.substr(pos, url.size() - pos);
}
//
// LLUrlEntrySeconlifeURL Describes *secondlife.com/ and *lindenlab.com/ urls to substitute icon 'hand.png' before link
//
LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL()
{
mPattern = boost::regex("\\b(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?(/\\S*)?\\b",
boost::regex::perl|boost::regex::icase);
mIcon = "Hand";
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
}
/// Return the url from a string that matched the regex
std::string LLUrlEntrySecondlifeURL::getUrl(const std::string &string) const
{
if (string.find("://") == std::string::npos)
{
return "https://" + escapeUrl(string);
}
return escapeUrl(string);
}
std::string LLUrlEntrySecondlifeURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
return urlToLabelWithGreyQuery(url);
}
std::string LLUrlEntrySecondlifeURL::getQuery(const std::string &url) const
{
return urlToGreyQuery(url);
}
std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const
{
return url;
}
//
// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com and *lindenlab.com urls to substitute icon 'hand.png' before link
//
LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL()
{
mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)",
boost::regex::perl|boost::regex::icase);
mIcon = "Hand";
mMenuName = "menu_url_http.xml";
}
//
// 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
// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
//
LLUrlEntryAgent::LLUrlEntryAgent() :
mAvatarNameCacheConnection()
LLUrlEntryAgent::LLUrlEntryAgent()
{
mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
@@ -372,7 +575,15 @@ void LLUrlEntryAgent::callObservers(const std::string &id,
void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id,
const LLAvatarName& av_name)
{
mAvatarNameCacheConnection.disconnect();
auto range = mAvatarNameCacheConnections.equal_range(id);
for (auto it = range.first; it != range.second; ++it)
{
if (it->second.connected())
{
it->second.disconnect();
}
}
mAvatarNameCacheConnections.erase(range.first, range.second);
std::string label = av_name.getCompleteName();
@@ -459,11 +670,8 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
}
else
{
if (mAvatarNameCacheConnection.connected())
{
mAvatarNameCacheConnection.disconnect();
}
mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2));
auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2));
mAvatarNameCacheConnections.emplace(agent_id, connection);
addObserver(agent_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
@@ -522,16 +730,23 @@ std::string LLUrlEntryAgent::getIcon(const std::string &url)
//
// LLUrlEntryAgentName describes a Second Life agent name Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
//
LLUrlEntryAgentName::LLUrlEntryAgentName() :
mAvatarNameCacheConnection()
LLUrlEntryAgentName::LLUrlEntryAgentName()
{}
void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id,
const LLAvatarName& av_name)
{
mAvatarNameCacheConnection.disconnect();
auto range = mAvatarNameCacheConnections.equal_range(id);
for (auto it = range.first; it != range.second; ++it)
{
if (it->second.connected())
{
it->second.disconnect();
}
}
mAvatarNameCacheConnections.erase(range.first, range.second);
std::string label = getName(av_name);
// received the agent name from the server - tell our observers
@@ -566,11 +781,8 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab
}
else
{
if (mAvatarNameCacheConnection.connected())
{
mAvatarNameCacheConnection.disconnect();
}
mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2));
auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2));
mAvatarNameCacheConnections.emplace(agent_id, connection);
addObserver(agent_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
@@ -585,7 +797,7 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab
//
// LLUrlEntryAgentCompleteName describes a Second Life agent complete name Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
//
LLUrlEntryAgentCompleteName::LLUrlEntryAgentCompleteName()
{
@@ -598,10 +810,26 @@ std::string LLUrlEntryAgentCompleteName::getName(const LLAvatarName& avatar_name
return avatar_name.getCompleteName();
}
//
// LLUrlEntryAgentLegacyName describes a Second Life agent legacy name Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/legacyname
// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/legacyname
//
LLUrlEntryAgentLegacyName::LLUrlEntryAgentLegacyName()
{
mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/legacyname",
boost::regex::perl|boost::regex::icase);
}
std::string LLUrlEntryAgentLegacyName::getName(const LLAvatarName& avatar_name)
{
return avatar_name.getLegacyName();
}
//
// LLUrlEntryAgentDisplayName describes a Second Life agent display name Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
//
LLUrlEntryAgentDisplayName::LLUrlEntryAgentDisplayName()
{
@@ -617,7 +845,7 @@ std::string LLUrlEntryAgentDisplayName::getName(const LLAvatarName& avatar_name)
//
// LLUrlEntryAgentUserName describes a Second Life agent user name Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
//
LLUrlEntryAgentUserName::LLUrlEntryAgentUserName()
{
@@ -634,7 +862,7 @@ std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name)
// 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
// x-grid-info://lincoln.lindenlab.com/app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect
//
LLUrlEntryGroup::LLUrlEntryGroup()
{
@@ -714,7 +942,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
//x-grid-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*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_inventory.xml";
@@ -732,7 +960,7 @@ std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLab
//
LLUrlEntryObjectIM::LLUrlEntryObjectIM()
{
mPattern = boost::regex("secondlife:///app/objectim/[\\da-f-]+\?.*",
mPattern = boost::regex(APP_HEADER_REGEX "/objectim/[\\da-f-]+\?\\S*\\w",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_objectim.xml";
}
@@ -765,7 +993,7 @@ std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers;
///
/// 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
/// x-grid-info://lincoln.lindenlab.com/app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
///
LLUrlEntryParcel::LLUrlEntryParcel()
{
@@ -860,7 +1088,7 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data)
//
LLUrlEntryPlace::LLUrlEntryPlace()
{
mPattern = boost::regex("((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?",
mPattern = boost::regex("((((x-grid-info://)|(x-grid-location-info://))[-\\w\\.]+(:\\d+)?/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_slurl.xml";
mTooltip = LLTrans::getString("TooltipSLURL");
@@ -968,7 +1196,7 @@ std::string LLUrlEntryRegion::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/
// x-grid-info://lincoln.lindenlab.com/app/teleport/Ahern/50/50/50/
//
LLUrlEntryTeleport::LLUrlEntryTeleport()
{
@@ -1042,7 +1270,7 @@ std::string LLUrlEntryTeleport::getLocation(const std::string &url) const
//
LLUrlEntrySL::LLUrlEntrySL()
{
mPattern = boost::regex("secondlife://(\\w+)?(:\\d+)?/\\S+",
mPattern = boost::regex(X_GRID_OR_SECONDLIFE_HEADER_REGEX "(\\w+)?(:\\d+)?/\\S+",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_slapp.xml";
mTooltip = LLTrans::getString("TooltipSLAPP");
@@ -1059,7 +1287,7 @@ std::string LLUrlEntrySL::getLabel(const std::string &url, const LLUrlLabelCallb
//
LLUrlEntrySLLabel::LLUrlEntrySLLabel()
{
mPattern = boost::regex("\\[secondlife://\\S+[ \t]+[^\\]]+\\]",
mPattern = boost::regex("\\[" X_GRID_OR_SECONDLIFE_HEADER_REGEX "\\S+[ \t]+[^\\]]+\\]",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_slapp.xml";
mTooltip = LLTrans::getString("TooltipSLAPP");
@@ -1201,3 +1429,75 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url)
LLStringUtil::trim(mIcon);
return mIcon;
}
//
// LLUrlEntryEmail Describes a generic mailto: Urls
//
LLUrlEntryEmail::LLUrlEntryEmail()
: LLUrlEntryBase()
{
mPattern = boost::regex("(mailto:)?[\\w\\.\\-]+@[\\w\\.\\-]+\\.[a-z]{2,63}",
boost::regex::perl | boost::regex::icase);
mMenuName = "menu_url_email.xml";
mTooltip = LLTrans::getString("TooltipEmail");
}
std::string LLUrlEntryEmail::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
size_t pos = url.find("mailto:");
if (pos == std::string::npos)
{
return escapeUrl(url);
}
std::string ret = escapeUrl(url.substr(pos + 7, url.length() - pos + 8));
return ret;
}
std::string LLUrlEntryEmail::getUrl(const std::string &string) const
{
if (string.find("mailto:") == std::string::npos)
{
return "mailto:" + escapeUrl(string);
}
return escapeUrl(string);
}
// <alchemy>
//
// LLUrlEntryJIRA describes a Jira Issue Tracker entry
//
LLUrlEntryJira::LLUrlEntryJira()
{
mPattern = boost::regex("((?:ALCH|SV|BUG|CHOP|FIRE|MAINT|OPEN|SCR|STORM|SVC|VWR|WEB)-\\d+)",
boost::regex::perl);
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
}
std::string LLUrlEntryJira::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
return unescapeUrl(url);
}
std::string LLUrlEntryJira::getTooltip(const std::string &string) const
{
return getUrl(string);
}
std::string LLUrlEntryJira::getUrl(const std::string &url) const
{
return (boost::format(
(url.find("ALCH") != std::string::npos) ?
"http://alchemy.atlassian.net/browse/%1%" :
(url.find("SV") != std::string::npos) ?
"https://singularityviewer.atlassian.net/browse/%1%" :
(url.find("FIRE") != std::string::npos) ?
"http://jira.phoenixviewer.com/browse/%1%" :
"http://jira.secondlife.com/browse/%1%"
) % url).str();
}
// </alchemy>

View File

@@ -35,10 +35,7 @@
#include "llavatarname.h"
#include "llhost.h" // for resolving parcel name by parcel id
#include <boost/signals2.hpp>
#include <boost/regex.hpp>
#include <string>
#include <map>
class LLAvatarName;
@@ -78,6 +75,9 @@ public:
/// Given a matched Url, return a label for the Url
virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; }
/// Return port, query and fragment parts for the Url
virtual std::string getQuery(const std::string &url) const { return ""; }
/// Return an icon that can be displayed next to Urls of this type
virtual std::string getIcon(const std::string &url);
@@ -96,10 +96,16 @@ public:
/// Should this link text be underlined only when mouse is hovered over it?
virtual bool underlineOnHoverOnly(const std::string &string) const { return true; } // <alchemy/>
virtual bool isTrusted() const { return false; }
virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
bool isLinkDisabled() const;
bool isWikiLinkCorrect(const std::string& url);
virtual bool isSLURLvalid(const std::string &url) const { return TRUE; };
protected:
std::string getIDStringFromUrl(const std::string &url) const;
std::string escapeUrl(const std::string &url) const;
@@ -107,6 +113,8 @@ protected:
std::string getLabelFromWikiLink(const std::string &url) const;
std::string getUrlFromWikiLink(const std::string &string) const;
void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb);
std::string urlToLabelWithGreyQuery(const std::string &url) const;
std::string urlToGreyQuery(const std::string &url) const;
virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon);
typedef struct {
@@ -128,7 +136,9 @@ class LLUrlEntryHTTP : public LLUrlEntryBase
{
public:
LLUrlEntryHTTP();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getUrl(const std::string &string) const override;
/*virtual*/ std::string getTooltip(const std::string &url) const override;
};
///
@@ -138,9 +148,9 @@ class LLUrlEntryHTTPLabel : public LLUrlEntryBase
{
public:
LLUrlEntryHTTPLabel();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getTooltip(const std::string &string) const;
/*virtual*/ std::string getUrl(const std::string &string) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getTooltip(const std::string &string) const override;
/*virtual*/ std::string getUrl(const std::string &string) const override;
};
///
@@ -150,8 +160,21 @@ class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase
{
public:
LLUrlEntryHTTPNoProtocol();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getUrl(const std::string &string) const;
std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
std::string getQuery(const std::string &url) const override;
std::string getUrl(const std::string &string) const override;
std::string getTooltip(const std::string &url) const override;
};
class LLUrlEntryInvalidSLURL : public LLUrlEntryBase
{
public:
LLUrlEntryInvalidSLURL();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getUrl(const std::string &string) const override;
/*virtual*/ std::string getTooltip(const std::string &url) const override;
bool isSLURLvalid(const std::string &url) const override;
};
///
@@ -161,8 +184,31 @@ class LLUrlEntrySLURL : public LLUrlEntryBase
{
public:
LLUrlEntrySLURL();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLocation(const std::string &url) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getLocation(const std::string &url) const override;
};
///
/// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com Urls
///
class LLUrlEntrySecondlifeURL : public LLUrlEntryBase
{
public:
LLUrlEntrySecondlifeURL();
/*virtual*/ bool isTrusted() const override { return true; }
/*virtual*/ std::string getUrl(const std::string &string) const override;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getQuery(const std::string &url) const override;
/*virtual*/ std::string getTooltip(const std::string &url) const override;
};
///
/// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com Urls
///
class LLUrlEntrySimpleSecondlifeURL : public LLUrlEntrySecondlifeURL
{
public:
LLUrlEntrySimpleSecondlifeURL();
};
///
@@ -174,22 +220,27 @@ public:
LLUrlEntryAgent();
~LLUrlEntryAgent()
{
if (mAvatarNameCacheConnection.connected())
for(const auto& conn_pair : mAvatarNameCacheConnections)
{
mAvatarNameCacheConnection.disconnect();
if (conn_pair.second.connected())
{
conn_pair.second.disconnect();
}
}
mAvatarNameCacheConnections.clear();
}
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getIcon(const std::string &url);
/*virtual*/ std::string getTooltip(const std::string &string) const;
//*virtual*/ LLStyle::Params getStyle() const;
/*virtual*/ LLUUID getID(const std::string &string) const;
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getIcon(const std::string &url) override;
/*virtual*/ std::string getTooltip(const std::string &string) const override;
///*virtual*/ LLStyle::Params getStyle() const override;
/*virtual*/ LLUUID getID(const std::string &string) const override;
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const override;
protected:
/*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon);
/*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon) override;
private:
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
boost::signals2::connection mAvatarNameCacheConnection;
using avatar_name_cache_connection_map_t = std::multimap<LLUUID, boost::signals2::connection>;
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
///
@@ -203,19 +254,25 @@ public:
LLUrlEntryAgentName();
~LLUrlEntryAgentName()
{
if (mAvatarNameCacheConnection.connected())
for (const auto& conn_pair : mAvatarNameCacheConnections)
{
mAvatarNameCacheConnection.disconnect();
if (conn_pair.second.connected())
{
conn_pair.second.disconnect();
}
}
mAvatarNameCacheConnections.clear();
}
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
//*virtual*/ LLStyle::Params getStyle() const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
///*virtual*/ LLStyle::Params getStyle() const override;
protected:
// override this to pull out relevant name fields
virtual std::string getName(const LLAvatarName& avatar_name) = 0;
private:
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
boost::signals2::connection mAvatarNameCacheConnection;
using avatar_name_cache_connection_map_t = std::multimap<LLUUID, boost::signals2::connection>;
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
@@ -229,7 +286,15 @@ class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName
public:
LLUrlEntryAgentCompleteName();
private:
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
/*virtual*/ std::string getName(const LLAvatarName& avatar_name) override;
};
class LLUrlEntryAgentLegacyName : public LLUrlEntryAgentName
{
public:
LLUrlEntryAgentLegacyName();
private:
/*virtual*/ std::string getName(const LLAvatarName& avatar_name) override;
};
///
@@ -242,7 +307,7 @@ class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName
public:
LLUrlEntryAgentDisplayName();
private:
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
/*virtual*/ std::string getName(const LLAvatarName& avatar_name) override;
};
///
@@ -255,7 +320,7 @@ class LLUrlEntryAgentUserName : public LLUrlEntryAgentName
public:
LLUrlEntryAgentUserName();
private:
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
/*virtual*/ std::string getName(const LLAvatarName& avatar_name) override;
};
///
@@ -266,9 +331,9 @@ class LLUrlEntryGroup : public LLUrlEntryBase
{
public:
LLUrlEntryGroup();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
//*virtual*/ LLStyle::Params getStyle() const;
/*virtual*/ LLUUID getID(const std::string &string) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
///*virtual*/ LLStyle::Params getStyle() const override;
/*virtual*/ LLUUID getID(const std::string &string) const override;
private:
void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group);
};
@@ -281,7 +346,7 @@ class LLUrlEntryInventory : public LLUrlEntryBase
{
public:
LLUrlEntryInventory();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
private:
};
@@ -293,8 +358,8 @@ class LLUrlEntryObjectIM : public LLUrlEntryBase
{
public:
LLUrlEntryObjectIM();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLocation(const std::string &url) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getLocation(const std::string &url) const override;
private:
};
@@ -317,7 +382,7 @@ public:
LLUrlEntryParcel();
~LLUrlEntryParcel();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
// Sends a parcel info request to sim.
void sendParcelInfoRequest(const LLUUID& parcel_id);
@@ -353,8 +418,8 @@ class LLUrlEntryPlace : public LLUrlEntryBase
{
public:
LLUrlEntryPlace();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLocation(const std::string &url) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getLocation(const std::string &url) const override;
};
///
@@ -365,8 +430,8 @@ class LLUrlEntryRegion : public LLUrlEntryBase
{
public:
LLUrlEntryRegion();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLocation(const std::string &url) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getLocation(const std::string &url) const override;
};
///
@@ -377,8 +442,8 @@ class LLUrlEntryTeleport : public LLUrlEntryBase
{
public:
LLUrlEntryTeleport();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLocation(const std::string &url) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getLocation(const std::string &url) const override;
};
///
@@ -389,7 +454,7 @@ class LLUrlEntrySL : public LLUrlEntryBase
{
public:
LLUrlEntrySL();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
};
///
@@ -400,10 +465,10 @@ class LLUrlEntrySLLabel : public LLUrlEntryBase
{
public:
LLUrlEntrySLLabel();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getUrl(const std::string &string) const;
/*virtual*/ std::string getTooltip(const std::string &string) const;
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getUrl(const std::string &string) const override;
/*virtual*/ std::string getTooltip(const std::string &string) const override;
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const override;
};
///
@@ -414,8 +479,8 @@ class LLUrlEntryWorldMap : public LLUrlEntryBase
{
public:
LLUrlEntryWorldMap();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getLocation(const std::string &url) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getLocation(const std::string &url) const override;
};
///
@@ -425,9 +490,9 @@ class LLUrlEntryNoLink : public LLUrlEntryBase
{
public:
LLUrlEntryNoLink();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getUrl(const std::string &string) const;
//*virtual*/ LLStyle::Params getStyle() const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getUrl(const std::string &string) const override;
///*virtual*/ LLStyle::Params getStyle() const override;
};
///
@@ -437,10 +502,35 @@ class LLUrlEntryIcon : public LLUrlEntryBase
{
public:
LLUrlEntryIcon();
/*virtual*/ std::string getUrl(const std::string &string) const;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getIcon(const std::string &url);
/*virtual*/ std::string getUrl(const std::string &string) const override;
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getIcon(const std::string &url) override;
};
///
/// LLUrlEntryEmail Describes a generic mailto: Urls
///
class LLUrlEntryEmail : public LLUrlEntryBase
{
public:
LLUrlEntryEmail();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getUrl(const std::string &string) const override;
};
// <alchemy>
///
/// LLUrlEntryJira describes a Jira Issue
///
class LLUrlEntryJira : public LLUrlEntryBase
{
public:
LLUrlEntryJira();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override;
/*virtual*/ std::string getTooltip(const std::string &string) const override;
/*virtual*/ std::string getUrl(const std::string &string) const override;
};
// </alchemy>
#endif

View File

@@ -1,3 +1,5 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
* @file llurlmatch.cpp
* @author Martin Reddy
@@ -37,20 +39,22 @@ LLUrlMatch::LLUrlMatch() :
mIcon(""),
mMenuName(""),
mLocation(""),
mUnderlineOnHoverOnly(false)
mUnderlineOnHoverOnly(false),
mTrusted(false)
{
}
void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
const std::string &label, const std::string &tooltip,
void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std::string &label,
const std::string& query, const std::string &tooltip,
const std::string &icon, /*const LLStyle::Params& style,*/
const std::string &menu, const std::string &location,
const LLUUID& id, bool underline_on_hover_only)
const LLUUID& id, bool underline_on_hover_only, bool trusted)
{
mStart = start;
mEnd = end;
mUrl = url;
mLabel = label;
mQuery = query;
mTooltip = tooltip;
mIcon = icon;
//mStyle = style;
@@ -59,4 +63,5 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
mLocation = location;
mID = id;
mUnderlineOnHoverOnly = underline_on_hover_only;
mTrusted = trusted;
}

View File

@@ -30,8 +30,6 @@
//#include "linden_common.h"
#include <string>
#include <vector>
#include "llstyle.h"
///
@@ -62,6 +60,9 @@ public:
/// return a label that can be used for the display of this Url
std::string getLabel() const { return mLabel; }
/// return a right part of url which should be drawn in grey
std::string getQuery() const { return mQuery; }
/// return a message that could be displayed in a tooltip or status bar
std::string getTooltip() const { return mTooltip; }
@@ -80,12 +81,15 @@ public:
/// Should this link text be underlined only when mouse is hovered over it?
bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; }
/// Return true if Url is trusted.
bool isTrusted() const { return mTrusted; }
/// Change the contents of this match object (used by LLUrlRegistry)
void setValues(U32 start, U32 end, const std::string &url, const std::string &label,
const std::string &tooltip, const std::string &icon,
/*const LLStyle::Params& style, */const std::string &menu,
const std::string& query, const std::string &tooltip, const std::string &icon,
/*const LLStyle::Params& style,*/ const std::string &menu,
const std::string &location, const LLUUID& id,
bool underline_on_hover_only = false );
bool underline_on_hover_only = false, bool trusted = false);
const LLUUID& getID() const { return mID; }
private:
@@ -93,6 +97,7 @@ private:
U32 mEnd;
std::string mUrl;
std::string mLabel;
std::string mQuery;
std::string mTooltip;
std::string mIcon;
std::string mMenuName;
@@ -100,6 +105,7 @@ private:
LLUUID mID;
//LLStyle::Params mStyle;
bool mUnderlineOnHoverOnly;
bool mTrusted;
};
#endif

View File

@@ -1,3 +1,5 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
* @file llurlregistry.cpp
* @author Martin Reddy
@@ -27,6 +29,7 @@
#include "linden_common.h"
#include "llurlregistry.h"
#include "lluriparser.h"
#include <boost/regex.hpp>
@@ -37,15 +40,26 @@ void LLUrlRegistryNullCallback(const std::string &url, const std::string &label,
LLUrlRegistry::LLUrlRegistry()
{
mUrlEntry.reserve(20);
mUrlEntry.reserve(23); // <alchemy/>
// Urls are matched in the order that they were registered
registerUrl(new LLUrlEntryNoLink());
registerUrl(new LLUrlEntryIcon());
mUrlEntryIcon = new LLUrlEntryIcon();
registerUrl(mUrlEntryIcon);
mLLUrlEntryInvalidSLURL = new LLUrlEntryInvalidSLURL();
registerUrl(mLLUrlEntryInvalidSLURL);
registerUrl(new LLUrlEntrySLURL());
// decorated links for host names like: secondlife.com and lindenlab.com
mUrlEntryTrusted = new LLUrlEntrySecondlifeURL();
registerUrl(mUrlEntryTrusted);
registerUrl(new LLUrlEntrySimpleSecondlifeURL());
registerUrl(new LLUrlEntryHTTP());
registerUrl(new LLUrlEntryHTTPLabel());
mUrlEntryHTTPLabel = new LLUrlEntryHTTPLabel();
registerUrl(mUrlEntryHTTPLabel);
registerUrl(new LLUrlEntryAgentCompleteName());
registerUrl(new LLUrlEntryAgentLegacyName());
registerUrl(new LLUrlEntryAgentDisplayName());
registerUrl(new LLUrlEntryAgentUserName());
// LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since
@@ -59,14 +73,17 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntryObjectIM());
registerUrl(new LLUrlEntryPlace());
registerUrl(new LLUrlEntryInventory());
registerUrl(new LLUrlEntryObjectIM());
//LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern,
//so it should be registered in the end of list
registerUrl(new LLUrlEntrySL());
registerUrl(new LLUrlEntrySLLabel());
// most common pattern is a URL without any protocol,
// e.g., "secondlife.com"
registerUrl(new LLUrlEntryHTTPNoProtocol());
mUrlEntrySLLabel = new LLUrlEntrySLLabel();
registerUrl(mUrlEntrySLLabel);
registerUrl(new LLUrlEntryEmail());
// Parse teh jiras!
registerUrl(new LLUrlEntryJira()); // <alchemy/>
// most common pattern is a URL without any protocol starting with "www",
// e.g., "www.secondlife.com"
registerUrl(new LLUrlEntryHTTPNoProtocol());
}
LLUrlRegistry::~LLUrlRegistry()
@@ -90,7 +107,7 @@ void LLUrlRegistry::registerUrl(LLUrlEntryBase *url, bool force_front)
}
}
static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &end)
static bool matchRegex(const char *text, const boost::regex& regex, U32 &start, U32 &end)
{
boost::cmatch result;
bool found;
@@ -100,7 +117,7 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en
{
found = boost::regex_search(text, result, regex);
}
catch (std::runtime_error &)
catch (const std::runtime_error &)
{
return false;
}
@@ -127,6 +144,11 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en
end--;
}
else if (text[end] == ']' && std::string(text+start, end-start).find('[') == std::string::npos)
{
end--;
}
return true;
}
@@ -142,32 +164,77 @@ static bool stringHasUrl(const std::string &text)
text.find(".edu") != std::string::npos ||
text.find(".org") != std::string::npos ||
text.find("<nolink>") != std::string::npos ||
text.find("<icon") != std::string::npos);
text.find("<icon") != std::string::npos ||
text.find('@') != std::string::npos);
}
bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb)
// <alchemy>
static bool stringHasJira(const std::string &text)
{
// fast heuristic test for a URL in a string. This is used
// to avoid lots of costly regex calls, BUT it needs to be
// kept in sync with the LLUrlEntry regexes we support.
return (text.find("ALCH") != std::string::npos ||
text.find("SV") != std::string::npos ||
text.find("BUG") != std::string::npos ||
text.find("CHOP") != std::string::npos ||
text.find("FIRE") != std::string::npos ||
text.find("MAINT") != std::string::npos ||
text.find("OPEN") != std::string::npos ||
text.find("SCR") != std::string::npos ||
text.find("STORM") != std::string::npos ||
text.find("SVC") != std::string::npos ||
text.find("VWR") != std::string::npos ||
text.find("WEB") != std::string::npos);
}
// </alchemy>
bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted)
{
// avoid costly regexes if there is clearly no URL in the text
if (! stringHasUrl(text))
if (!(stringHasUrl(text) || stringHasJira(text))) // <alchemy/>
{
return false;
}
// find the first matching regex from all url entries in the registry
U32 match_start = 0, match_end = 0;
LLUrlEntryBase *match_entry = NULL;
LLUrlEntryBase *match_entry = nullptr;
std::vector<LLUrlEntryBase *>::iterator it;
for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it)
{
//Skip for url entry icon if content is not trusted
if(!is_content_trusted && (mUrlEntryIcon == *it))
{
continue;
}
LLUrlEntryBase *url_entry = *it;
U32 start = 0, end = 0;
if (matchRegex(text.c_str(), url_entry->getPattern(), start, end))
{
// does this match occur in the string before any other match
if (start < match_start || match_entry == NULL)
if (start < match_start || match_entry == nullptr)
{
if (mLLUrlEntryInvalidSLURL == *it)
{
if(url_entry && url_entry->isSLURLvalid(text.substr(start, end - start + 1)))
{
continue;
}
}
if((mUrlEntryHTTPLabel == *it) || (mUrlEntrySLLabel == *it))
{
if(url_entry && !url_entry->isWikiLinkCorrect(text.substr(start, end - start + 1)))
{
continue;
}
}
match_start = start;
match_end = end;
match_entry = url_entry;
@@ -178,18 +245,32 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
// did we find a match? if so, return its details in the match object
if (match_entry)
{
// Skip if link is an email with an empty username (starting with @). See MAINT-5371.
if (match_start > 0 && text.substr(match_start - 1, 1) == "@")
return false;
// fill in the LLUrlMatch object and return it
std::string url = text.substr(match_start, match_end - match_start + 1);
if (match_entry == mUrlEntryTrusted)
{
LLUriParser up(url);
up.normalize();
url = up.normalizedUri();
}
match.setValues(match_start, match_end,
match_entry->getUrl(url),
match_entry->getLabel(url, cb),
match_entry->getQuery(url),
match_entry->getTooltip(url),
match_entry->getIcon(url),
//match_entry->getStyle(),
match_entry->getMenuName(),
match_entry->getLocation(url),
match_entry->getID(url),
match_entry->underlineOnHoverOnly(url));
match_entry->underlineOnHoverOnly(url),
match_entry->isTrusted());
return true;
}
@@ -209,7 +290,7 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
// character encoding, so we need to update the start
// and end values to be correct for the wide string.
LLWString wurl = utf8str_to_wstring(match.getUrl());
S32 start = text.find(wurl);
size_t start = text.find(wurl);
if (start == std::string::npos)
{
return false;
@@ -218,6 +299,7 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
match.setValues(start, end, match.getUrl(),
match.getLabel(),
match.getQuery(),
match.getTooltip(),
match.getIcon(),
//match.getStyle(),

View File

@@ -33,9 +33,6 @@
#include "llsingleton.h"
#include "llstring.h"
#include <string>
#include <vector>
/// This default callback for findUrl() simply ignores any label updates
void LLUrlRegistryNullCallback(const std::string &url,
const std::string &label,
@@ -73,7 +70,8 @@ public:
/// get the next Url in an input string, starting at a given character offset
/// your callback is invoked if the matched Url's label changes in the future
bool findUrl(const std::string &text, LLUrlMatch &match,
const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback);
const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback,
bool is_content_trusted = false);
/// a slightly less efficient version of findUrl for wide strings
bool findUrl(const LLWString &text, LLUrlMatch &match,
@@ -92,6 +90,11 @@ private:
friend class LLSingleton<LLUrlRegistry>;
std::vector<LLUrlEntryBase *> mUrlEntry;
LLUrlEntryBase* mUrlEntryTrusted;
LLUrlEntryBase* mUrlEntryIcon;
LLUrlEntryBase* mLLUrlEntryInvalidSLURL;
LLUrlEntryBase* mUrlEntryHTTPLabel;
LLUrlEntryBase* mUrlEntrySLLabel;
};
#endif

View File

@@ -49,8 +49,8 @@ LLSplashScreen *gSplashScreenp = NULL;
BOOL gDebugClicks = FALSE;
BOOL gDebugWindowProc = FALSE;
const S32 gURLProtocolWhitelistCount = 4;
const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:"/*, "file:"*/ };
const S32 gURLProtocolWhitelistCount = 5;
const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:", "mailto:" };
// CP: added a handler list - this is what's used to open the protocol and is based on registry entry
// only meaningful difference currently is that file: protocols are opened using http:

View File

@@ -43,6 +43,7 @@ include(UI)
include(ViewerMiscLibs)
include(WinManifest)
include(ZLIB)
include(URIPARSER)
if (MSVC)
use_prebuilt_binary(vcredist)
@@ -1635,6 +1636,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${LLCOMMON_LIBRARIES}
${NDOF_LIBRARY}
${NVAPI_LIBRARY}
${URIPARSER_LIBRARY}
${viewer_LIBRARIES}
${Boost_CONTEXT_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}

View File

@@ -535,7 +535,7 @@ bool cmd_line_chat(std::string data, EChatType type)
LLAvatarActions::showProfile(id);
return false;
}
LLUrlAction::clickAction(sub);
LLUrlAction::clickAction(sub, true);
}
return false;
}

View File

@@ -507,14 +507,40 @@ Section "Viewer"
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.
WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell" "" "open"
!ifdef WIN64_BIN_BUILD
WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open" "FriendlyAppName" "$INSTSHORTCUT (64 bit) Viewer"
!else
WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open" "FriendlyAppName" "$INSTSHORTCUT Viewer"
!endif
WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" "$\"$INSTDIR\$INSTEXE$\" -url $\"%1$\""
DeleteRegKey HKEY_CLASSES_ROOT "x-grid-info"
WriteRegStr HKEY_CLASSES_ROOT "x-grid-info" "" "URL:Hypergrid"
WriteRegStr HKEY_CLASSES_ROOT "x-grid-info" "URL Protocol" ""
WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\DefaultIcon" "" "$INSTDIR\$INSTEXE"
;; URL param must be last item passed to viewer, it ignores subsequent params
;; to avoid parameter injection attacks.
WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell" "" "open"
!ifdef WIN64_BIN_BUILD
WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT (64 bit) Viewer"
!else
WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT Viewer"
!endif
WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-info\shell\open\command" "" "$\"$INSTDIR\$INSTEXE$\" -url $\"%1$\""
DeleteRegKey HKEY_CLASSES_ROOT "x-grid-location-info"
WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "" "URL:Hypergrid legacy"
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.
WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell" "" "open"
!ifdef WIN64_BIN_BUILD
WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT (64 bit) Viewer"
!else
WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT Viewer"
!endif
WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" "$\"$INSTDIR\$INSTEXE$\" -url $\"%1$\""
;Create uninstaller

View File

@@ -79,7 +79,7 @@ BOOL LLFloaterObjectIMInfo::postBuild()
{
getChild<LLUICtrl>("Mute")->setCommitCallback(boost::bind(&LLFloaterObjectIMInfo::onClickMute, this));
getChild<LLTextBox>("OwnerName")->setClickedCallback(boost::bind(boost::ref(mGroupOwned) ? boost::bind(LLGroupActions::show, boost::ref(mOwnerID)) : boost::bind(show_avatar_profile, boost::ref(mOwnerID))));
getChild<LLTextBox>("Slurl")->setClickedCallback(boost::bind(LLUrlAction::executeSLURL, boost::bind(std::plus<std::string>(), "secondlife:///app/worldmap/", boost::ref(mSLurl))));
getChild<LLTextBox>("Slurl")->setClickedCallback(boost::bind(LLUrlAction::executeSLURL, boost::bind(std::plus<std::string>(), "secondlife:///app/worldmap/", boost::ref(mSLurl)), true));
return true;
}

View File

@@ -1,5 +1,7 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
* @file llurlsimstring.cpp (was llsimurlstring.cpp)
* @file llslurl.cpp (was llsimurlstring.cpp)
* @brief Handles "SLURL fragments" like Ahern/123/45 for
* startup processing, login screen, prefs, etc.
*
@@ -48,7 +50,8 @@ const char* LLSLURL::SLURL_COM = "slurl.com";
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_X_GRID_INFO_SCHEME = "x-grid-info";
const char* LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME = "x-grid-location-info"; // <- deprecated!
const char* LLSLURL::SLURL_APP_PATH = "app";
const char* LLSLURL::SLURL_REGION_PATH = "region";
const char* LLSLURL::SIM_LOCATION_HOME = "home";
@@ -214,7 +217,8 @@ LLSLURL::LLSLURL(const std::string& slurl)
}
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))
(slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_INFO_SCHEME) ||
(slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME)) // deprecated legacy
{
// We're dealing with either a Standalone style slurl or slurl.com slurl
if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) ||
@@ -239,7 +243,7 @@ LLSLURL::LLSLURL(const std::string& slurl)
// 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();
mGrid = slurl_uri.hostNameAndPort();
}
if (path_array.size() == 0)
{
@@ -266,7 +270,7 @@ LLSLURL::LLSLURL(const std::string& slurl)
}
else
{
// not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL
// not a valid https/http/x-grid-info slurl, so it'll likely just be a URL
return;
}
}
@@ -304,7 +308,14 @@ LLSLURL::LLSLURL(const std::string& slurl)
// 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());
if(LLStringUtil::containsNonprintable(mRegion))
{
LLStringUtil::stripNonprintable(mRegion);
}
path_array.erase(0);
// parse the x, y, and optionally z
@@ -313,11 +324,11 @@ LLSLURL::LLSLURL(const std::string& slurl)
mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)
if((F32(mPosition[VX]) < 0.f) ||
(mPosition[VX] > 8192.f/*REGION_WIDTH_METERS*/) ||
(mPosition[VX] > 8192.f) ||
(F32(mPosition[VY]) < 0.f) ||
(mPosition[VY] > 8192.f/*REGION_WIDTH_METERS*/) ||
(mPosition[VY] > 8192.f) ||
(F32(mPosition[VZ]) < 0.f) ||
(mPosition[VZ] > 8192.f/*REGION_HEIGHT_METERS*/))
(mPosition[VZ] > 8192.f))
{
mType = INVALID;
return;
@@ -444,9 +455,9 @@ std::string LLSLURL::getSLURLString() const
app_url << SYSTEM_GRID_APP_SLURL_BASE << "/" << mAppCmd;
else
app_url << llformat(DEFAULT_APP_SLURL_BASE, gHippoGridManager->getCurrentGridNick().c_str()) << "/" << mAppCmd;
for(LLSD::array_const_iterator i = mAppPath.beginArray();
for(auto i = mAppPath.beginArray();
i != mAppPath.endArray();
i++)
++i)
{
app_url << "/" << i->asString();
}

View File

@@ -44,6 +44,7 @@ public:
static const char* WWW_SLURL_COM;
static const char* SECONDLIFE_COM;
static const char* MAPS_SECONDLIFE_COM;
static const char* SLURL_X_GRID_INFO_SCHEME;
static const char* SLURL_X_GRID_LOCATION_INFO_SCHEME;
static LLSLURL START_LOCATION;
static const char* SIM_LOCATION_HOME;

View File

@@ -144,7 +144,7 @@ bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl,
bool LLURLDispatcherImpl::dispatchRightClick(const LLSLURL& slurl)
{
const bool right_click = true;
LLMediaCtrl* web = NULL;
LLMediaCtrl* web = nullptr;
const bool trusted_browser = false;
return dispatchCore(slurl, "clicked", right_click, web, trusted_browser);
}
@@ -187,11 +187,18 @@ bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, const std::string
LLPanelLogin::setLocation(slurl);
return true;
}
LLSLURL _slurl = slurl;
const std::string& grid = slurl.getGrid();
const std::string& current_grid = gHippoGridManager->getCurrentGrid()->getGridName();
if (grid != current_grid)
{
_slurl = LLSLURL(llformat("%s:%s", grid.c_str(), slurl.getRegion().c_str()), slurl.getPosition());
}
// Request a region handle by name
LLWorldMapMessage::getInstance()->sendNamedRegionRequest(slurl.getRegion(),
LLURLDispatcherImpl::regionNameCallback,
slurl.getSLURLString(),
_slurl.getSLURLString(),
LLUI::sConfigGroup->getBOOL("SLURLTeleportDirectly")); // don't teleport
return true;
}
@@ -263,7 +270,8 @@ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL&
//---------------------------------------------------------------------------
// Teleportation links are handled here because they are tightly coupled
// to URL parsing and sim-fragment parsing
// to SLURL parsing and sim-fragment parsing
class LLTeleportHandler : public LLCommandHandler
{
public:
@@ -272,8 +280,9 @@ public:
// cause a constant teleport loop. JC
LLTeleportHandler() : LLCommandHandler("teleport", UNTRUSTED_THROTTLE) { }
bool handle(const LLSD& tokens, const LLSD& query_map,
LLMediaCtrl* web)
LLMediaCtrl* web) override
{
// construct a "normal" SLURL, resolve the region to
// a global position, and teleport to it
@@ -287,12 +296,11 @@ public:
tokens[3].asReal());
}
LLSD args;
args["LOCATION"] = tokens[0];
// Region names may be %20 escaped.
std::string region_name = LLURI::unescape(tokens[0]);
LLSD args;
args["LOCATION"] = region_name;
LLSD payload;
payload["region_name"] = region_name;
@@ -351,7 +359,7 @@ bool LLURLDispatcher::dispatchRightClick(const std::string& slurl)
}
// static
bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl)
bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl, bool trusted_content)
{
// *NOTE: Text editors are considered sources of trusted URLs
// in order to make avatar profile links in chat history work.
@@ -359,9 +367,9 @@ bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl)
// receiving resident will see it and must affirmatively
// click on it.
// *TODO: Make this trust model more refined. JC
const bool trusted_browser = true;
LLMediaCtrl* web = NULL;
return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), "clicked", web, trusted_browser);
LLMediaCtrl* web = nullptr;
return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), "clicked", web, trusted_content);
}

View File

@@ -2,36 +2,29 @@
* @file llurldispatcher.h
* @brief Central registry for all SL URL handlers
*
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Copyright (c) 2007-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* 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
* Copyright (C) 2010, Linden Research, Inc.
*
* 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
* 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.
*
* 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.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
#ifndef LLURLDISPATCHER_H
#define LLURLDISPATCHER_H
class LLMediaCtrl;
@@ -49,6 +42,8 @@ public:
// secondlife://RegionName/123/45/67/
// secondlife:///app/agent/3d6181b0-6a4b-97ef-18d8-722652995cf1/show
// sl://app/foo/bar
// @param nav_type
// type of navigation type (see LLQtWebKit::LLWebPage::acceptNavigationRequest)
// @param web
// Pointer to LLMediaCtrl sending URL, can be NULL
// @param trusted_browser
@@ -58,7 +53,7 @@ public:
static bool dispatchRightClick(const std::string& slurl);
static bool dispatchFromTextEditor(const std::string& slurl);
static bool dispatchFromTextEditor(const std::string& slurl, bool trusted_content);
};
#endif

View File

@@ -125,6 +125,9 @@
<string name="TooltipMapUrl">Klicken, um diese Position auf der Karte anzuzeigen</string>
<string name="TooltipSLAPP">Anklicken, um Befehl secondlife:// auszuführen</string>
<string name="CurrentURL" value=" CurrentURL: [CurrentURL]"/>
<string name="TooltipEmail">
Klicken, um eine E-Mail zu verfassen
</string>
<!-- text for SLURL labels -->
<string name="SLurlLabelTeleport">Teleportieren zu</string>

View File

@@ -141,6 +141,7 @@ Make sure you entered the correct Login URI. An example of a Login URI is: \"htt
<string name="TooltipMapUrl">Click to view this location on a map</string>
<string name="TooltipSLAPP">Click to run the secondlife:// command</string>
<string name="CurrentURL" value=" CurrentURL: [CurrentURL]" />
<string name="TooltipEmail">Click to compose an email</string>
<!-- text for SLURL labels -->
<string name="SLurlLabelTeleport">Teleport to</string>

View File

@@ -133,6 +133,9 @@ Asegurate que has ingresado el URI de inicio de sesión correcto. Un ejemplo de
<string name="TooltipMapUrl">Pulsa para ver esta ubicación en el mapa</string>
<string name="TooltipSLAPP">Pulsa para ejecutar el comando secondlife://</string>
<string name="CurrentURL" value=" CurrentURL: [CurrentURL]" />
<string name="TooltipEmail">
Haz clic para redactar un correo electrónico
</string>
<!-- text for SLURL labels -->
<string name="SLurlLabelTeleport">Teleportar a</string>

View File

@@ -403,6 +403,9 @@ Pessoas com contas gratuitas não poderão acessar o Second Life no momento para
Clique para ativar no secondlife:// comando
</string>
<string name="CurrentURL" value="URL atual: [CurrentURL]"/>
<string name="TooltipEmail">
Clique para escrever um email
</string>
<string name="SLurlLabelTeleport">
Teletransportar para
</string>
@@ -427,6 +430,9 @@ Pessoas com contas gratuitas não poderão acessar o Second Life no momento para
<string name="SLappAgentRequestFriend">
Pedido de amizade
</string>
<string name="SLappAgentRemoveFriend">
Remoção de amigo
</string>
<string name="BUTTON_CLOSE_DARWIN">
Fechar (⌘W)
</string>