diff options
189 files changed, 2376 insertions, 7352 deletions
| @@ -520,3 +520,4 @@ e9d350764dfbf5a46229e627547ef5c1b1eeef00 4.0.2-release  33981d8130f031597b4c7f4c981b18359afb61a0 4.0.7-release  45eaee56883df7a439ed3300c44d3126f7e3a41e 4.0.8-release  b280a1c797a3891e68dbc237e73de9cf19f426e9 4.1.1-release +bfbba2244320dc2ae47758cd7edd8fa3b67dc756 4.1.2-release @@ -1,6 +1,6 @@  Second Life Viewer  ==================== - +   This project manages the source code for the  [Second Life](https://www.secondlife.com) Viewer. diff --git a/autobuild.xml b/autobuild.xml index 34ea70cb11..a92fdfd4d7 100755..100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2054,11 +2054,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>db992d58c46c80df7d4d31f8a4784b98</string> +              <string>2845033912eb947a1401847ece1469ce</string>                <key>hash_algorithm</key>                <string>md5</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/317959/arch/Darwin/installer/llceflib-1.5.3.317959-darwin-317959.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/321153/arch/Darwin/installer/llceflib-1.5.3.321153-darwin-321153.tar.bz2</string>              </map>              <key>name</key>              <string>darwin</string> @@ -2068,11 +2068,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>bb3818628131a99cd789febfad9dc2c2</string> +              <string>1156121b4ccbb4aa29bc01f15c589f98</string>                <key>hash_algorithm</key>                <string>md5</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/317959/arch/CYGWIN/installer/llceflib-1.5.3.317959-windows-317959.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/321153/arch/CYGWIN/installer/llceflib-1.5.3.321153-windows-321153.tar.bz2</string>              </map>              <key>name</key>              <string>windows</string> @@ -3545,14 +3545,6 @@                  <key>arguments</key>                  <array>                    <string>..\indra</string> -                  <string>&&</string> -                  <string>..\indra\tools\vstool\VSTool.exe</string> -                  <string>--solution</string> -                  <string>SecondLife.sln</string> -                  <string>--config</string> -                  <string>RelWithDebInfo</string> -                  <string>--startup</string> -                  <string>secondlife-bin</string>                  </array>                  <key>options</key>                  <array> @@ -3591,20 +3583,11 @@                  <key>arguments</key>                  <array>                    <string>..\indra</string> -                  <string>&&</string> -                  <string>..\indra\tools\vstool\VSTool.exe</string> -                  <string>--solution</string> -                  <string>SecondLife.sln</string> -                  <string>--config</string> -                  <string>RelWithDebInfo</string> -                  <string>--startup</string> -                  <string>secondlife-bin</string>                  </array>                  <key>options</key>                  <array>                    <string>-G</string>                    <string>"Visual Studio 12"</string> -                  <string>-DUNATTENDED:BOOL=ON</string>                    <string>-DINSTALL_PROPRIETARY=FALSE</string>                    <string>-DUSE_KDU=FALSE</string>                  </array> @@ -3633,14 +3616,6 @@                  <key>arguments</key>                  <array>                    <string>..\indra</string> -                  <string>&&</string> -                  <string>..\indra\tools\vstool\VSTool.exe</string> -                  <string>--solution</string> -                  <string>SecondLife.sln</string> -                  <string>--config</string> -                  <string>Release</string> -                  <string>--startup</string> -                  <string>secondlife-bin</string>                  </array>                  <key>options</key>                  <array> @@ -3677,20 +3652,11 @@                  <key>arguments</key>                  <array>                    <string>..\indra</string> -                  <string>&&</string> -                  <string>..\indra\tools\vstool\VSTool.exe</string> -                  <string>--solution</string> -                  <string>SecondLife.sln</string> -                  <string>--config</string> -                  <string>Release</string> -                  <string>--startup</string> -                  <string>secondlife-bin</string>                  </array>                  <key>options</key>                  <array>                    <string>-G</string>                    <string>"Visual Studio 12"</string> -                  <string>-DUNATTENDED:BOOL=ON</string>                    <string>-DINSTALL_PROPRIETARY=FALSE</string>                    <string>-DUSE_KDU=FALSE</string>                  </array> @@ -97,6 +97,7 @@ pre_build()      "$autobuild" configure --quiet -c $variant -- \       -DPACKAGE:BOOL=ON \ +     -DUNATTENDED:BOOL=ON \       -DRELEASE_CRASH_REPORTING:BOOL=ON \       -DVIEWER_CHANNEL:STRING="\"$viewer_channel\"" \       -DGRID:STRING="\"$viewer_grid\"" \ diff --git a/doc/contributions.txt b/doc/contributions.txt index 8ed41ddc34..f7d1ece72f 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -190,9 +190,19 @@ Ansariel Hiller  	STORM-2094  	MAINT-5756  	MAINT-4677 +	MAINT-6300 +	MAINT-6397  	MAINT-6432 +	MAINT-6513 +	MAINT-6514 +	MAINT-6552  	STORM-2133  	MAINT-6511 +	MAINT-6612 +	MAINT-6637 +	MAINT-6636 +	MAINT-6744 +	MAINT-6752  Aralara Rajal  Arare Chantilly  	CHUIBUG-191 @@ -790,6 +800,7 @@ Kitty Barnett  	MAINT-6152  	MAINT-6153  	MAINT-6154 +	MAINT-6568  Kolor Fall  Komiko Okamoto  Korvel Noh @@ -1021,6 +1032,7 @@ Nicky Dasmijn  	OPEN-187      STORM-2010  	STORM-2082 +	MAINT-6665  Nicky Perian  	OPEN-1  	STORM-1087 diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 86fc2dfff5..adc134c48c 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -83,8 +83,8 @@ if (WINDOWS)      add_definitions(/WX)    endif (NOT VS_DISABLE_FATAL_WARNINGS) -  # configure win32 API for windows XP+ compatibility -  set(WINVER "0x0501" CACHE STRING "Win32 API Target version (see http://msdn.microsoft.com/en-us/library/aa383745%28v=VS.85%29.aspx)") +  # configure Win32 API for Windows Vista+ compatibility +  set(WINVER "0x0600" CACHE STRING "Win32 API Target version (see http://msdn.microsoft.com/en-us/library/aa383745%28v=VS.85%29.aspx)")    add_definitions("/DWINVER=${WINVER}" "/D_WIN32_WINNT=${WINVER}")  endif (WINDOWS) diff --git a/indra/lib/python/indra/base/__init__.py b/indra/lib/python/indra/base/__init__.py deleted file mode 100755 index 2904fd3380..0000000000 --- a/indra/lib/python/indra/base/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -"""\ -@file __init__.py -@brief Initialization file for the indra.base module. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" diff --git a/indra/lib/python/indra/base/cllsd_test.py b/indra/lib/python/indra/base/cllsd_test.py deleted file mode 100755 index 1f06898ffd..0000000000 --- a/indra/lib/python/indra/base/cllsd_test.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python -##  -## $LicenseInfo:firstyear=2011&license=viewerlgpl$ -## Second Life Viewer Source Code -## Copyright (C) 2011, 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$ -from indra.base import llsd, lluuid -from datetime import datetime -import cllsd -import time, sys - -class myint(int): -    pass - -values = ( -    '&<>', -    u'\u81acj', -    llsd.uri('http://foo<'), -    lluuid.UUID(), -    llsd.LLSD(['thing']), -    1, -    myint(31337), -    sys.maxint + 10, -    llsd.binary('foo'), -    [], -    {}, -    {u'f&\u1212': 3}, -    3.1, -    True, -    None, -    datetime.fromtimestamp(time.time()), -    ) - -def valuator(values): -    for v in values: -        yield v - -longvalues = () # (values, list(values), iter(values), valuator(values)) - -for v in values + longvalues: -    print '%r => %r' % (v, cllsd.llsd_to_xml(v)) - -a = [[{'a':3}]] * 1000000 - -s = time.time() -print hash(cllsd.llsd_to_xml(a)) -e = time.time() -t1 = e - s -print t1 - -s = time.time() -print hash(llsd.LLSDXMLFormatter()._format(a)) -e = time.time() -t2 = e - s -print t2 - -print 'Speedup:', t2 / t1 diff --git a/indra/lib/python/indra/base/config.py b/indra/lib/python/indra/base/config.py deleted file mode 100755 index adafa29b51..0000000000 --- a/indra/lib/python/indra/base/config.py +++ /dev/null @@ -1,266 +0,0 @@ -"""\ -@file config.py -@brief Utility module for parsing and accessing the indra.xml config file. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import copy -import errno -import os -import traceback -import time -import types - -from os.path import dirname, getmtime, join, realpath -from indra.base import llsd - -_g_config = None - -class IndraConfig(object): -    """ -    IndraConfig loads a 'indra' xml configuration file -    and loads into memory.  This representation in memory -    can get updated to overwrite values or add new values. - -    The xml configuration file is considered a live file and changes -    to the file are checked and reloaded periodically.  If a value had -    been overwritten via the update or set method, the loaded values -    from the file are ignored (the values from the update/set methods -    override) -    """ -    def __init__(self, indra_config_file): -        self._indra_config_file = indra_config_file -        self._reload_check_interval = 30 # seconds -        self._last_check_time = 0 -        self._last_mod_time = 0 - -        self._config_overrides = {} -        self._config_file_dict = {} -        self._combined_dict = {} - -        self._load() - -    def _load(self): -        # if you initialize the IndraConfig with None, no attempt -        # is made to load any files -        if self._indra_config_file is None: -            return - -        config_file = open(self._indra_config_file) -        self._config_file_dict = llsd.parse(config_file.read()) -        self._combine_dictionaries() -        config_file.close() - -        self._last_mod_time = self._get_last_modified_time() -        self._last_check_time = time.time() # now - -    def _get_last_modified_time(self): -        """ -        Returns the mtime (last modified time) of the config file, -        if such exists. -        """ -        if self._indra_config_file is not None: -            return os.path.getmtime(self._indra_config_file) - -        return 0 - -    def _combine_dictionaries(self): -        self._combined_dict = {} -        self._combined_dict.update(self._config_file_dict) -        self._combined_dict.update(self._config_overrides) - -    def _reload_if_necessary(self): -        now = time.time() - -        if (now - self._last_check_time) > self._reload_check_interval: -            self._last_check_time = now -            try: -                modtime = self._get_last_modified_time() -                if modtime > self._last_mod_time: -                    self._load() -            except OSError, e: -                if e.errno == errno.ENOENT: # file not found -                    # someone messed with our internal state -                    # or removed the file - -                    print 'WARNING: Configuration file has been removed ' + (self._indra_config_file) -                    print 'Disabling reloading of configuration file.' - -                    traceback.print_exc() - -                    self._indra_config_file = None -                    self._last_check_time = 0 -                    self._last_mod_time = 0 -                else: -                    raise  # pass the exception along to the caller - -    def __getitem__(self, key): -        self._reload_if_necessary() - -        return self._combined_dict[key] - -    def get(self, key, default = None): -        try: -            return self.__getitem__(key) -        except KeyError: -            return default - -    def __setitem__(self, key, value): -        """ -        Sets the value of the config setting of key to be newval - -        Once any key/value pair is changed via the set method, -        that key/value pair will remain set with that value until -        change via the update or set method -        """ -        self._config_overrides[key] = value -        self._combine_dictionaries() - -    def set(self, key, newval): -        return self.__setitem__(key, newval) - -    def update(self, new_conf): -        """ -        Load an XML file and apply its map as overrides or additions -        to the existing config.  Update can be a file or a dict. - -        Once any key/value pair is changed via the update method, -        that key/value pair will remain set with that value until -        change via the update or set method -        """ -        if isinstance(new_conf, dict): -            overrides = new_conf -        else: -            # assuming that it is a filename -            config_file = open(new_conf) -            overrides = llsd.parse(config_file.read()) -            config_file.close() -   -        self._config_overrides.update(overrides) -        self._combine_dictionaries() - -    def as_dict(self): -        """ -        Returns immutable copy of the IndraConfig as a dictionary -        """ -        return copy.deepcopy(self._combined_dict) - -def load(config_xml_file = None): -    global _g_config - -    load_default_files = config_xml_file is None -    if load_default_files: -        ## going from: -        ## "/opt/linden/indra/lib/python/indra/base/config.py" -        ## to: -        ## "/opt/linden/etc/indra.xml" -        config_xml_file = realpath( -            dirname(realpath(__file__)) + "../../../../../../etc/indra.xml") - -    try: -        _g_config = IndraConfig(config_xml_file) -    except IOError: -        # Failure to load passed in file -        # or indra.xml default file -        if load_default_files: -            try: -                config_xml_file = realpath( -                    dirname(realpath(__file__)) + "../../../../../../etc/globals.xml") -                _g_config = IndraConfig(config_xml_file) -                return -            except IOError: -                # Failure to load globals.xml -                # fall to code below -                pass - -        # Either failed to load passed in file -        # or failed to load all default files -        _g_config = IndraConfig(None) - -def dump(indra_xml_file, indra_cfg = None, update_in_mem=False): -    ''' -    Dump config contents into a file -    Kindof reverse of load. -    Optionally takes a new config to dump. -    Does NOT update global config unless requested. -    ''' -    global _g_config - -    if not indra_cfg: -        if _g_config is None: -            return - -        indra_cfg = _g_config.as_dict() - -    if not indra_cfg: -        return - -    config_file = open(indra_xml_file, 'w') -    _config_xml = llsd.format_xml(indra_cfg) -    config_file.write(_config_xml) -    config_file.close() - -    if update_in_mem: -        update(indra_cfg) - -def update(new_conf): -    global _g_config - -    if _g_config is None: -        # To keep with how this function behaved -        # previously, a call to update -        # before the global is defined -        # make a new global config which does not -        # load data from a file. -        _g_config = IndraConfig(None) - -    return _g_config.update(new_conf) - -def get(key, default = None): -    global _g_config - -    if _g_config is None: -        load() - -    return _g_config.get(key, default) - -def set(key, newval): -    """ -    Sets the value of the config setting of key to be newval - -    Once any key/value pair is changed via the set method, -    that key/value pair will remain set with that value until -    change via the update or set method or program termination -    """ -    global _g_config - -    if _g_config is None: -        _g_config = IndraConfig(None) - -    _g_config.set(key, newval) - -def get_config(): -    global _g_config -    return _g_config diff --git a/indra/lib/python/indra/base/llsd.py b/indra/lib/python/indra/base/llsd.py deleted file mode 100755 index 4527b115f9..0000000000 --- a/indra/lib/python/indra/base/llsd.py +++ /dev/null @@ -1,1052 +0,0 @@ -"""\ -@file llsd.py -@brief Types as well as parsing and formatting functions for handling LLSD. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import datetime -import base64 -import string -import struct -import time -import types -import re - -from indra.util.fastest_elementtree import ElementTreeError, fromstring -from indra.base import lluuid - -# cllsd.c in server/server-1.25 has memory leaks, -#   so disabling cllsd for now -#try: -#    import cllsd -#except ImportError: -#    cllsd = None -cllsd = None - -int_regex = re.compile(r"[-+]?\d+") -real_regex = re.compile(r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?") -alpha_regex = re.compile(r"[a-zA-Z]+") -date_regex = re.compile(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})T" -                        r"(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})" -                        r"(?P<second_float>(\.\d+)?)Z") -#date: d"YYYY-MM-DDTHH:MM:SS.FFFFFFZ" - -class LLSDParseError(Exception): -    pass - -class LLSDSerializationError(TypeError): -    pass - - -class binary(str): -    pass - -class uri(str): -    pass - - -BOOL_TRUE = ('1', '1.0', 'true') -BOOL_FALSE = ('0', '0.0', 'false', '') - - -def format_datestr(v): -    """ Formats a datetime or date object into the string format shared by xml and notation serializations.""" -    if hasattr(v, 'microsecond'): -        return v.isoformat() + 'Z' -    else: -        return v.strftime('%Y-%m-%dT%H:%M:%SZ') - -def parse_datestr(datestr): -    """Parses a datetime object from the string format shared by xml and notation serializations.""" -    if datestr == "": -        return datetime.datetime(1970, 1, 1) -     -    match = re.match(date_regex, datestr) -    if not match: -        raise LLSDParseError("invalid date string '%s'." % datestr) -     -    year = int(match.group('year')) -    month = int(match.group('month')) -    day = int(match.group('day')) -    hour = int(match.group('hour')) -    minute = int(match.group('minute')) -    second = int(match.group('second')) -    seconds_float = match.group('second_float') -    microsecond = 0 -    if seconds_float: -        microsecond = int(float('0' + seconds_float) * 1e6) -    return datetime.datetime(year, month, day, hour, minute, second, microsecond) - - -def bool_to_python(node): -    val = node.text or '' -    if val in BOOL_TRUE: -        return True -    else: -        return False - -def int_to_python(node): -    val = node.text or '' -    if not val.strip(): -        return 0 -    return int(val) - -def real_to_python(node): -    val = node.text or '' -    if not val.strip(): -        return 0.0 -    return float(val) - -def uuid_to_python(node): -    return lluuid.UUID(node.text) - -def str_to_python(node): -    return node.text or '' - -def bin_to_python(node): -    return binary(base64.decodestring(node.text or '')) - -def date_to_python(node): -    val = node.text or '' -    if not val: -        val = "1970-01-01T00:00:00Z" -    return parse_datestr(val) -     - -def uri_to_python(node): -    val = node.text or '' -    if not val: -        return None -    return uri(val) - -def map_to_python(node): -    result = {} -    for index in range(len(node))[::2]: -        result[node[index].text] = to_python(node[index+1]) -    return result - -def array_to_python(node): -    return [to_python(child) for child in node] - - -NODE_HANDLERS = dict( -    undef=lambda x: None, -    boolean=bool_to_python, -    integer=int_to_python, -    real=real_to_python, -    uuid=uuid_to_python, -    string=str_to_python, -    binary=bin_to_python, -    date=date_to_python, -    uri=uri_to_python, -    map=map_to_python, -    array=array_to_python, -    ) - -def to_python(node): -    return NODE_HANDLERS[node.tag](node) - -class Nothing(object): -    pass - - -class LLSDXMLFormatter(object): -    def __init__(self): -        self.type_map = { -            type(None) : self.UNDEF, -            bool : self.BOOLEAN, -            int : self.INTEGER, -            long : self.INTEGER, -            float : self.REAL, -            lluuid.UUID : self.UUID, -            binary : self.BINARY, -            str : self.STRING, -            unicode : self.STRING, -            uri : self.URI, -            datetime.datetime : self.DATE, -            datetime.date : self.DATE, -            list : self.ARRAY, -            tuple : self.ARRAY, -            types.GeneratorType : self.ARRAY, -            dict : self.MAP, -            LLSD : self.LLSD -        } - -    def elt(self, name, contents=None): -        if(contents is None or contents is ''): -            return "<%s />" % (name,) -        else: -            if type(contents) is unicode: -                contents = contents.encode('utf-8') -            return "<%s>%s</%s>" % (name, contents, name) - -    def xml_esc(self, v): -        if type(v) is unicode: -            v = v.encode('utf-8') -        return v.replace('&', '&').replace('<', '<').replace('>', '>') - -    def LLSD(self, v): -        return self.generate(v.thing) -    def UNDEF(self, v): -        return self.elt('undef') -    def BOOLEAN(self, v): -        if v: -            return self.elt('boolean', 'true') -        else: -            return self.elt('boolean', 'false') -    def INTEGER(self, v): -        return self.elt('integer', v) -    def REAL(self, v): -        return self.elt('real', v) -    def UUID(self, v): -        if(v.isNull()): -            return self.elt('uuid') -        else: -            return self.elt('uuid', v) -    def BINARY(self, v): -        return self.elt('binary', base64.encodestring(v)) -    def STRING(self, v): -        return self.elt('string', self.xml_esc(v)) -    def URI(self, v): -        return self.elt('uri', self.xml_esc(str(v))) -    def DATE(self, v): -        return self.elt('date', format_datestr(v)) -    def ARRAY(self, v): -        return self.elt('array', ''.join([self.generate(item) for item in v])) -    def MAP(self, v): -        return self.elt( -            'map', -            ''.join(["%s%s" % (self.elt('key', self.xml_esc(str(key))), self.generate(value)) -             for key, value in v.items()])) - -    typeof = type -    def generate(self, something): -        t = self.typeof(something) -        if self.type_map.has_key(t): -            return self.type_map[t](something) -        else: -            raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % ( -                t, something)) - -    def _format(self, something): -        return '<?xml version="1.0" ?>' + self.elt("llsd", self.generate(something)) - -    def format(self, something): -        if cllsd: -            return cllsd.llsd_to_xml(something) -        return self._format(something) - -_g_xml_formatter = None -def format_xml(something): -    global _g_xml_formatter -    if _g_xml_formatter is None: -        _g_xml_formatter = LLSDXMLFormatter() -    return _g_xml_formatter.format(something) - -class LLSDXMLPrettyFormatter(LLSDXMLFormatter): -    def __init__(self, indent_atom = None): -        # Call the super class constructor so that we have the type map -        super(LLSDXMLPrettyFormatter, self).__init__() - -        # Override the type map to use our specialized formatters to -        # emit the pretty output. -        self.type_map[list] = self.PRETTY_ARRAY -        self.type_map[tuple] = self.PRETTY_ARRAY -        self.type_map[types.GeneratorType] = self.PRETTY_ARRAY, -        self.type_map[dict] = self.PRETTY_MAP - -        # Private data used for indentation. -        self._indent_level = 1 -        if indent_atom is None: -            self._indent_atom = '  ' -        else: -            self._indent_atom = indent_atom - -    def _indent(self): -        "Return an indentation based on the atom and indentation level." -        return self._indent_atom * self._indent_level - -    def PRETTY_ARRAY(self, v): -        rv = [] -        rv.append('<array>\n') -        self._indent_level = self._indent_level + 1 -        rv.extend(["%s%s\n" % -                   (self._indent(), -                    self.generate(item)) -                   for item in v]) -        self._indent_level = self._indent_level - 1 -        rv.append(self._indent()) -        rv.append('</array>') -        return ''.join(rv) - -    def PRETTY_MAP(self, v): -        rv = [] -        rv.append('<map>\n') -        self._indent_level = self._indent_level + 1 -        keys = v.keys() -        keys.sort() -        rv.extend(["%s%s\n%s%s\n" % -                   (self._indent(), -                    self.elt('key', key), -                    self._indent(), -                    self.generate(v[key])) -                   for key in keys]) -        self._indent_level = self._indent_level - 1 -        rv.append(self._indent()) -        rv.append('</map>') -        return ''.join(rv) - -    def format(self, something): -        data = [] -        data.append('<?xml version="1.0" ?>\n<llsd>') -        data.append(self.generate(something)) -        data.append('</llsd>\n') -        return '\n'.join(data) - -def format_pretty_xml(something): -    """@brief Serialize a python object as 'pretty' llsd xml. - -    The output conforms to the LLSD DTD, unlike the output from the -    standard python xml.dom DOM::toprettyxml() method which does not -    preserve significant whitespace.  -    This function is not necessarily suited for serializing very large -    objects. It is not optimized by the cllsd module, and sorts on -    dict (llsd map) keys alphabetically to ease human reading. -    """ -    return LLSDXMLPrettyFormatter().format(something) - -class LLSDNotationFormatter(object): -    def __init__(self): -        self.type_map = { -            type(None) : self.UNDEF, -            bool : self.BOOLEAN, -            int : self.INTEGER, -            long : self.INTEGER, -            float : self.REAL, -            lluuid.UUID : self.UUID, -            binary : self.BINARY, -            str : self.STRING, -            unicode : self.STRING, -            uri : self.URI, -            datetime.datetime : self.DATE, -            datetime.date : self.DATE, -            list : self.ARRAY, -            tuple : self.ARRAY, -            types.GeneratorType : self.ARRAY, -            dict : self.MAP, -            LLSD : self.LLSD -        } - -    def LLSD(self, v): -        return self.generate(v.thing) -    def UNDEF(self, v): -        return '!' -    def BOOLEAN(self, v): -        if v: -            return 'true' -        else: -            return 'false' -    def INTEGER(self, v): -        return "i%s" % v -    def REAL(self, v): -        return "r%s" % v -    def UUID(self, v): -        return "u%s" % v -    def BINARY(self, v): -        return 'b64"' + base64.encodestring(v) + '"' -    def STRING(self, v): -        if isinstance(v, unicode): -            v = v.encode('utf-8') -        return "'%s'" % v.replace("\\", "\\\\").replace("'", "\\'") -    def URI(self, v): -        return 'l"%s"' % str(v).replace("\\", "\\\\").replace('"', '\\"') -    def DATE(self, v): -        return 'd"%s"' % format_datestr(v) -    def ARRAY(self, v): -        return "[%s]" % ','.join([self.generate(item) for item in v]) -    def MAP(self, v): -        def fix(key): -            if isinstance(key, unicode): -                return key.encode('utf-8') -            return key -        return "{%s}" % ','.join(["'%s':%s" % (fix(key).replace("\\", "\\\\").replace("'", "\\'"), self.generate(value)) -             for key, value in v.items()]) - -    def generate(self, something): -        t = type(something) -        handler = self.type_map.get(t) -        if handler: -            return handler(something) -        else: -            try: -                return self.ARRAY(iter(something)) -            except TypeError: -                raise LLSDSerializationError( -                    "Cannot serialize unknown type: %s (%s)" % (t, something)) - -    def format(self, something): -        return self.generate(something) - -def format_notation(something): -    return LLSDNotationFormatter().format(something) - -def _hex_as_nybble(hex): -    if (hex >= '0') and (hex <= '9'): -        return ord(hex) - ord('0') -    elif (hex >= 'a') and (hex <='f'): -        return 10 + ord(hex) - ord('a') -    elif (hex >= 'A') and (hex <='F'): -        return 10 + ord(hex) - ord('A'); - -class LLSDBinaryParser(object): -    def __init__(self): -        pass - -    def parse(self, buffer, ignore_binary = False): -        """ -        This is the basic public interface for parsing. - -        @param buffer the binary data to parse in an indexable sequence. -        @param ignore_binary parser throws away data in llsd binary nodes. -        @return returns a python object. -        """ -        self._buffer = buffer -        self._index = 0 -        self._keep_binary = not ignore_binary -        return self._parse() - -    def _parse(self): -        cc = self._buffer[self._index] -        self._index += 1 -        if cc == '{': -            return self._parse_map() -        elif cc == '[': -            return self._parse_array() -        elif cc == '!': -            return None -        elif cc == '0': -            return False -        elif cc == '1': -            return True -        elif cc == 'i': -            # 'i' = integer -            idx = self._index -            self._index += 4 -            return struct.unpack("!i", self._buffer[idx:idx+4])[0] -        elif cc == ('r'): -            # 'r' = real number -            idx = self._index -            self._index += 8 -            return struct.unpack("!d", self._buffer[idx:idx+8])[0] -        elif cc == 'u': -            # 'u' = uuid -            idx = self._index -            self._index += 16 -            return lluuid.uuid_bits_to_uuid(self._buffer[idx:idx+16]) -        elif cc == 's': -            # 's' = string -            return self._parse_string() -        elif cc in ("'", '"'): -            # delimited/escaped string -            return self._parse_string_delim(cc) -        elif cc == 'l': -            # 'l' = uri -            return uri(self._parse_string()) -        elif cc == ('d'): -            # 'd' = date in seconds since epoch -            idx = self._index -            self._index += 8 -            seconds = struct.unpack("!d", self._buffer[idx:idx+8])[0] -            return datetime.datetime.fromtimestamp(seconds) -        elif cc == 'b': -            binary = self._parse_string() -            if self._keep_binary: -                return binary -            # *NOTE: maybe have a binary placeholder which has the -            # length. -            return None -        else: -            raise LLSDParseError("invalid binary token at byte %d: %d" % ( -                self._index - 1, ord(cc))) - -    def _parse_map(self): -        rv = {} -        size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] -        self._index += 4 -        count = 0 -        cc = self._buffer[self._index] -        self._index += 1 -        key = '' -        while (cc != '}') and (count < size): -            if cc == 'k': -                key = self._parse_string() -            elif cc in ("'", '"'): -                key = self._parse_string_delim(cc) -            else: -                raise LLSDParseError("invalid map key at byte %d." % ( -                    self._index - 1,)) -            value = self._parse() -            rv[key] = value -            count += 1 -            cc = self._buffer[self._index] -            self._index += 1 -        if cc != '}': -            raise LLSDParseError("invalid map close token at byte %d." % ( -                self._index,)) -        return rv - -    def _parse_array(self): -        rv = [] -        size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] -        self._index += 4 -        count = 0 -        cc = self._buffer[self._index] -        while (cc != ']') and (count < size): -            rv.append(self._parse()) -            count += 1 -            cc = self._buffer[self._index] -        if cc != ']': -            raise LLSDParseError("invalid array close token at byte %d." % ( -                self._index,)) -        self._index += 1 -        return rv - -    def _parse_string(self): -        size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] -        self._index += 4 -        rv = self._buffer[self._index:self._index+size] -        self._index += size -        return rv - -    def _parse_string_delim(self, delim): -        list = [] -        found_escape = False -        found_hex = False -        found_digit = False -        byte = 0 -        while True: -            cc = self._buffer[self._index] -            self._index += 1 -            if found_escape: -                if found_hex: -                    if found_digit: -                        found_escape = False -                        found_hex = False -                        found_digit = False -                        byte <<= 4 -                        byte |= _hex_as_nybble(cc) -                        list.append(chr(byte)) -                        byte = 0 -                    else: -                        found_digit = True -                        byte = _hex_as_nybble(cc) -                elif cc == 'x': -                    found_hex = True -                else: -                    if cc == 'a': -                        list.append('\a') -                    elif cc == 'b': -                        list.append('\b') -                    elif cc == 'f': -                        list.append('\f') -                    elif cc == 'n': -                        list.append('\n') -                    elif cc == 'r': -                        list.append('\r') -                    elif cc == 't': -                        list.append('\t') -                    elif cc == 'v': -                        list.append('\v') -                    else: -                        list.append(cc) -                    found_escape = False -            elif cc == '\\': -                found_escape = True -            elif cc == delim: -                break -            else: -                list.append(cc) -        return ''.join(list) - -class LLSDNotationParser(object): -    """ Parse LLSD notation: -    map: { string:object, string:object } -    array: [ object, object, object ] -    undef: ! -    boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE -    integer: i#### -    real: r#### -    uuid: u#### -    string: "g\'day" | 'have a "nice" day' | s(size)"raw data" -    uri: l"escaped" -    date: d"YYYY-MM-DDTHH:MM:SS.FFZ" -    binary: b##"ff3120ab1" | b(size)"raw data" -    """ -    def __init__(self): -        pass - -    def parse(self, buffer, ignore_binary = False): -        """ -        This is the basic public interface for parsing. - -        @param buffer the notation string to parse. -        @param ignore_binary parser throws away data in llsd binary nodes. -        @return returns a python object. -        """ -        if buffer == "": -            return False - -        self._buffer = buffer -        self._index = 0 -        return self._parse() - -    def _parse(self): -        cc = self._buffer[self._index] -        self._index += 1 -        if cc == '{': -            return self._parse_map() -        elif cc == '[': -            return self._parse_array() -        elif cc == '!': -            return None -        elif cc == '0': -            return False -        elif cc == '1': -            return True -        elif cc in ('F', 'f'): -            self._skip_alpha() -            return False -        elif cc in ('T', 't'): -            self._skip_alpha() -            return True -        elif cc == 'i': -            # 'i' = integer -            return self._parse_integer() -        elif cc == ('r'): -            # 'r' = real number -            return self._parse_real() -        elif cc == 'u': -            # 'u' = uuid -            return self._parse_uuid() -        elif cc in ("'", '"', 's'): -            return self._parse_string(cc) -        elif cc == 'l': -            # 'l' = uri -            delim = self._buffer[self._index] -            self._index += 1 -            val = uri(self._parse_string(delim)) -            if len(val) == 0: -                return None -            return val -        elif cc == ('d'): -            # 'd' = date in seconds since epoch -            return self._parse_date() -        elif cc == 'b': -            return self._parse_binary() -        else: -            raise LLSDParseError("invalid token at index %d: %d" % ( -                self._index - 1, ord(cc))) - -    def _parse_binary(self): -        i = self._index -        if self._buffer[i:i+2] == '64': -            q = self._buffer[i+2] -            e = self._buffer.find(q, i+3) -            try: -                return base64.decodestring(self._buffer[i+3:e]) -            finally: -                self._index = e + 1 -        else: -            raise LLSDParseError('random horrible binary format not supported') - -    def _parse_map(self): -        """ map: { string:object, string:object } """ -        rv = {} -        cc = self._buffer[self._index] -        self._index += 1 -        key = '' -        found_key = False -        while (cc != '}'): -            if not found_key: -                if cc in ("'", '"', 's'): -                    key = self._parse_string(cc) -                    found_key = True -                elif cc.isspace() or cc == ',': -                    cc = self._buffer[self._index] -                    self._index += 1 -                else: -                    raise LLSDParseError("invalid map key at byte %d." % ( -                                        self._index - 1,)) -            elif cc.isspace() or cc == ':': -                cc = self._buffer[self._index] -                self._index += 1 -                continue -            else: -                self._index += 1 -                value = self._parse() -                rv[key] = value -                found_key = False -                cc = self._buffer[self._index] -                self._index += 1 - -        return rv - -    def _parse_array(self): -        """ array: [ object, object, object ] """ -        rv = [] -        cc = self._buffer[self._index] -        while (cc != ']'): -            if cc.isspace() or cc == ',': -                self._index += 1 -                cc = self._buffer[self._index] -                continue -            rv.append(self._parse()) -            cc = self._buffer[self._index] - -        if cc != ']': -            raise LLSDParseError("invalid array close token at index %d." % ( -                self._index,)) -        self._index += 1 -        return rv - -    def _parse_uuid(self): -        match = re.match(lluuid.UUID.uuid_regex, self._buffer[self._index:]) -        if not match: -            raise LLSDParseError("invalid uuid token at index %d." % self._index) - -        (start, end) = match.span() -        start += self._index -        end += self._index -        self._index = end -        return lluuid.UUID(self._buffer[start:end]) - -    def _skip_alpha(self): -        match = re.match(alpha_regex, self._buffer[self._index:]) -        if match: -            self._index += match.end() -             -    def _parse_date(self): -        delim = self._buffer[self._index] -        self._index += 1 -        datestr = self._parse_string(delim) -        return parse_datestr(datestr) - -    def _parse_real(self): -        match = re.match(real_regex, self._buffer[self._index:]) -        if not match: -            raise LLSDParseError("invalid real token at index %d." % self._index) - -        (start, end) = match.span() -        start += self._index -        end += self._index -        self._index = end -        return float( self._buffer[start:end] ) - -    def _parse_integer(self): -        match = re.match(int_regex, self._buffer[self._index:]) -        if not match: -            raise LLSDParseError("invalid integer token at index %d." % self._index) - -        (start, end) = match.span() -        start += self._index -        end += self._index -        self._index = end -        return int( self._buffer[start:end] ) - -    def _parse_string(self, delim): -        """ string: "g\'day" | 'have a "nice" day' | s(size)"raw data" """ -        rv = "" - -        if delim in ("'", '"'): -            rv = self._parse_string_delim(delim) -        elif delim == 's': -            rv = self._parse_string_raw() -        else: -            raise LLSDParseError("invalid string token at index %d." % self._index) - -        return rv - - -    def _parse_string_delim(self, delim): -        """ string: "g'day 'un" | 'have a "nice" day' """ -        list = [] -        found_escape = False -        found_hex = False -        found_digit = False -        byte = 0 -        while True: -            cc = self._buffer[self._index] -            self._index += 1 -            if found_escape: -                if found_hex: -                    if found_digit: -                        found_escape = False -                        found_hex = False -                        found_digit = False -                        byte <<= 4 -                        byte |= _hex_as_nybble(cc) -                        list.append(chr(byte)) -                        byte = 0 -                    else: -                        found_digit = True -                        byte = _hex_as_nybble(cc) -                elif cc == 'x': -                    found_hex = True -                else: -                    if cc == 'a': -                        list.append('\a') -                    elif cc == 'b': -                        list.append('\b') -                    elif cc == 'f': -                        list.append('\f') -                    elif cc == 'n': -                        list.append('\n') -                    elif cc == 'r': -                        list.append('\r') -                    elif cc == 't': -                        list.append('\t') -                    elif cc == 'v': -                        list.append('\v') -                    else: -                        list.append(cc) -                    found_escape = False -            elif cc == '\\': -                found_escape = True -            elif cc == delim: -                break -            else: -                list.append(cc) -        return ''.join(list) - -    def _parse_string_raw(self): -        """ string: s(size)"raw data" """ -        # Read the (size) portion. -        cc = self._buffer[self._index] -        self._index += 1 -        if cc != '(': -            raise LLSDParseError("invalid string token at index %d." % self._index) - -        rparen = self._buffer.find(')', self._index) -        if rparen == -1: -            raise LLSDParseError("invalid string token at index %d." % self._index) - -        size = int(self._buffer[self._index:rparen]) - -        self._index = rparen + 1 -        delim = self._buffer[self._index] -        self._index += 1 -        if delim not in ("'", '"'): -            raise LLSDParseError("invalid string token at index %d." % self._index) - -        rv = self._buffer[self._index:(self._index + size)] -        self._index += size -        cc = self._buffer[self._index] -        self._index += 1 -        if cc != delim: -            raise LLSDParseError("invalid string token at index %d." % self._index) - -        return rv -         -def format_binary(something): -    return '<?llsd/binary?>\n' + _format_binary_recurse(something) - -def _format_binary_recurse(something): -    def _format_list(something): -        array_builder = [] -        array_builder.append('[' + struct.pack('!i', len(something))) -        for item in something: -            array_builder.append(_format_binary_recurse(item)) -        array_builder.append(']') -        return ''.join(array_builder) - -    if something is None: -        return '!' -    elif isinstance(something, LLSD): -        return _format_binary_recurse(something.thing) -    elif isinstance(something, bool): -        if something: -            return '1' -        else: -            return '0' -    elif isinstance(something, (int, long)): -        return 'i' + struct.pack('!i', something) -    elif isinstance(something, float): -        return 'r' + struct.pack('!d', something) -    elif isinstance(something, lluuid.UUID): -        return 'u' + something._bits -    elif isinstance(something, binary): -        return 'b' + struct.pack('!i', len(something)) + something -    elif isinstance(something, str): -        return 's' + struct.pack('!i', len(something)) + something -    elif isinstance(something, unicode): -        something = something.encode('utf-8') -        return 's' + struct.pack('!i', len(something)) + something -    elif isinstance(something, uri): -        return 'l' + struct.pack('!i', len(something)) + something -    elif isinstance(something, datetime.datetime): -        seconds_since_epoch = time.mktime(something.timetuple()) -        return 'd' + struct.pack('!d', seconds_since_epoch) -    elif isinstance(something, (list, tuple)): -        return _format_list(something) -    elif isinstance(something, dict): -        map_builder = [] -        map_builder.append('{' + struct.pack('!i', len(something))) -        for key, value in something.items(): -            if isinstance(key, unicode): -                key = key.encode('utf-8') -            map_builder.append('k' + struct.pack('!i', len(key)) + key) -            map_builder.append(_format_binary_recurse(value)) -        map_builder.append('}') -        return ''.join(map_builder) -    else: -        try: -            return _format_list(list(something)) -        except TypeError: -            raise LLSDSerializationError( -                "Cannot serialize unknown type: %s (%s)" % -                (type(something), something)) - - -def parse_binary(binary): -    if binary.startswith('<?llsd/binary?>'): -        just_binary = binary.split('\n', 1)[1] -    else: -        just_binary = binary -    return LLSDBinaryParser().parse(just_binary) - -def parse_xml(something): -    try: -        return to_python(fromstring(something)[0]) -    except ElementTreeError, err: -        raise LLSDParseError(*err.args) - -def parse_notation(something): -    return LLSDNotationParser().parse(something) - -def parse(something): -    try: -        something = string.lstrip(something)   #remove any pre-trailing whitespace -        if something.startswith('<?llsd/binary?>'): -            return parse_binary(something) -        # This should be better. -        elif something.startswith('<'): -            return parse_xml(something) -        else: -            return parse_notation(something) -    except KeyError, e: -        raise Exception('LLSD could not be parsed: %s' % (e,)) - -class LLSD(object): -    def __init__(self, thing=None): -        self.thing = thing - -    def __str__(self): -        return self.toXML(self.thing) - -    parse = staticmethod(parse) -    toXML = staticmethod(format_xml) -    toPrettyXML = staticmethod(format_pretty_xml) -    toBinary = staticmethod(format_binary) -    toNotation = staticmethod(format_notation) - - -undef = LLSD(None) - -XML_MIME_TYPE = 'application/llsd+xml' -BINARY_MIME_TYPE = 'application/llsd+binary' - -# register converters for llsd in mulib, if it is available -try: -    from mulib import stacked, mu -    stacked.NoProducer()  # just to exercise stacked -    mu.safe_load(None)    # just to exercise mu -except: -    # mulib not available, don't print an error message since this is normal -    pass -else: -    mu.add_parser(parse, XML_MIME_TYPE) -    mu.add_parser(parse, 'application/llsd+binary') - -    def llsd_convert_xml(llsd_stuff, request): -        request.write(format_xml(llsd_stuff)) - -    def llsd_convert_binary(llsd_stuff, request): -        request.write(format_binary(llsd_stuff)) - -    for typ in [LLSD, dict, list, tuple, str, int, long, float, bool, unicode, type(None)]: -        stacked.add_producer(typ, llsd_convert_xml, XML_MIME_TYPE) -        stacked.add_producer(typ, llsd_convert_xml, 'application/xml') -        stacked.add_producer(typ, llsd_convert_xml, 'text/xml') - -        stacked.add_producer(typ, llsd_convert_binary, 'application/llsd+binary') - -    stacked.add_producer(LLSD, llsd_convert_xml, '*/*') - -    # in case someone is using the legacy mu.xml wrapper, we need to -    # tell mu to produce application/xml or application/llsd+xml -    # (based on the accept header) from raw xml. Phoenix 2008-07-21 -    stacked.add_producer(mu.xml, mu.produce_raw, XML_MIME_TYPE) -    stacked.add_producer(mu.xml, mu.produce_raw, 'application/xml') - - - -# mulib wsgi stuff -# try: -#     from mulib import mu, adapters -# -#     # try some known attributes from mulib to be ultra-sure we've imported it -#     mu.get_current -#     adapters.handlers -# except: -#     # mulib not available, don't print an error message since this is normal -#     pass -# else: -#     def llsd_xml_handler(content_type): -#         def handle_llsd_xml(env, start_response): -#             llsd_stuff, _ = mu.get_current(env) -#             result = format_xml(llsd_stuff) -#             start_response("200 OK", [('Content-Type', content_type)]) -#             env['mu.negotiated_type'] = content_type -#             yield result -#         return handle_llsd_xml -#     -#     def llsd_binary_handler(content_type): -#         def handle_llsd_binary(env, start_response): -#             llsd_stuff, _ = mu.get_current(env) -#             result = format_binary(llsd_stuff) -#             start_response("200 OK", [('Content-Type', content_type)]) -#             env['mu.negotiated_type'] = content_type -#             yield result -#         return handle_llsd_binary -# -#     adapters.DEFAULT_PARSERS[XML_MIME_TYPE] = parse -     -#     for typ in [LLSD, dict, list, tuple, str, int, float, bool, unicode, type(None)]: -#         for content_type in (XML_MIME_TYPE, 'application/xml'): -#             adapters.handlers.set_handler(typ, llsd_xml_handler(content_type), content_type) -# -#         adapters.handlers.set_handler(typ, llsd_binary_handler(BINARY_MIME_TYPE), BINARY_MIME_TYPE) -# -#     adapters.handlers.set_handler(LLSD, llsd_xml_handler(XML_MIME_TYPE), '*/*') diff --git a/indra/lib/python/indra/base/lluuid.py b/indra/lib/python/indra/base/lluuid.py deleted file mode 100755 index 7413ffe10d..0000000000 --- a/indra/lib/python/indra/base/lluuid.py +++ /dev/null @@ -1,319 +0,0 @@ -"""\ -@file lluuid.py -@brief UUID parser/generator. - -$LicenseInfo:firstyear=2004&license=mit$ - -Copyright (c) 2004-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import random, socket, string, time, re -import uuid -try: -    # Python 2.6 -    from hashlib import md5 -except ImportError: -    # Python 2.5 and earlier -    from md5 import new as md5 - -def _int2binstr(i,l): -    s='' -    for a in range(l): -        s=chr(i&0xFF)+s -        i>>=8 -    return s - -def _binstr2int(s): -    i = long(0) -    for c in s: -        i = (i<<8) + ord(c) -    return i - -class UUID(object): -    """ -    A class which represents a 16 byte integer. Stored as a 16 byte 8 -    bit character string. - -    The string version is to be of the form: -    AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC  (a 128-bit number in hex) -    where A=network address, B=timestamp, C=random. -    """ - -    NULL_STR = "00000000-0000-0000-0000-000000000000" - -    # the UUIDREGEX_STRING is helpful for parsing UUID's in text -    hex_wildcard = r"[0-9a-fA-F]" -    word = hex_wildcard + r"{4,4}-" -    long_word = hex_wildcard + r"{8,8}-" -    very_long_word = hex_wildcard + r"{12,12}" -    UUID_REGEX_STRING = long_word + word + word + word + very_long_word -    uuid_regex = re.compile(UUID_REGEX_STRING) - -    rand = random.Random() -    ip = '' -    try: -        ip = socket.gethostbyname(socket.gethostname()) -    except(socket.gaierror, socket.error): -        # no ip address, so just default to somewhere in 10.x.x.x -        ip = '10' -        for i in range(3): -            ip += '.' + str(rand.randrange(1,254)) -    hexip = ''.join(["%04x" % long(i) for i in ip.split('.')]) -    lastid = '' - -    def __init__(self, possible_uuid=None): -        """ -        Initialize to first valid UUID in argument (if a string), -        or to null UUID if none found or argument is not supplied. - -        If the argument is a UUID, the constructed object will be a copy of it. -        """ -        self._bits = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" -        if possible_uuid is None: -            return - -        if isinstance(possible_uuid, type(self)): -            self.set(possible_uuid) -            return - -        uuid_match = UUID.uuid_regex.search(possible_uuid) -        if uuid_match: -            uuid_string = uuid_match.group() -            s = string.replace(uuid_string, '-', '') -            self._bits = _int2binstr(string.atol(s[:8],16),4) + \ -                         _int2binstr(string.atol(s[8:16],16),4) + \ -                         _int2binstr(string.atol(s[16:24],16),4) + \ -                         _int2binstr(string.atol(s[24:],16),4)  - -    def __len__(self): -        """ -        Used by the len() builtin. -        """ -        return 36 - -    def __nonzero__(self): -        return self._bits != "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - -    def __str__(self): -        uuid_string = self.toString() -        return uuid_string - -    __repr__ = __str__ - -    def __getitem__(self, index): -        return str(self)[index] - -    def __eq__(self, other): -        if isinstance(other, (str, unicode)): -            return other == str(self) -        return self._bits == getattr(other, '_bits', '') - -    def __ne__(self, other): -        return not self.__eq__(other) - -    def __le__(self, other): -        return self._bits <= other._bits - -    def __ge__(self, other): -        return self._bits >= other._bits - -    def __lt__(self, other): -        return self._bits < other._bits - -    def __gt__(self, other): -        return self._bits > other._bits - -    def __hash__(self): -        return hash(self._bits) - -    def set(self, uuid): -        self._bits = uuid._bits - -    def setFromString(self, uuid_string): -        """ -        Given a string version of a uuid, set self bits -        appropriately. Returns self. -        """ -        s = string.replace(uuid_string, '-', '') -        self._bits = _int2binstr(string.atol(s[:8],16),4) + \ -                     _int2binstr(string.atol(s[8:16],16),4) + \ -                     _int2binstr(string.atol(s[16:24],16),4) + \ -                     _int2binstr(string.atol(s[24:],16),4)  -        return self - -    def setFromMemoryDump(self, gdb_string): -        """ -        We expect to get gdb_string as four hex units. eg: -        0x147d54db      0xc34b3f1b      0x714f989b      0x0a892fd2 -        Which will be translated to: -        db547d14-1b3f4bc3-9b984f71-d22f890a -        Returns self. -        """ -        s = string.replace(gdb_string, '0x', '') -        s = string.replace(s, ' ', '') -        t = '' -        for i in range(8,40,8): -            for j in range(0,8,2): -                t = t + s[i-j-2:i-j] -        self.setFromString(t) - -    def toString(self): -        """ -        Return as a string matching the LL standard -        AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC  (a 128-bit number in hex) -        where A=network address, B=timestamp, C=random. -        """ -        return uuid_bits_to_string(self._bits) - -    def getAsString(self): -        """ -        Return a different string representation of the form -        AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC  (a 128-bit number in hex) -        where A=network address, B=timestamp, C=random. -        """ -        i1 = _binstr2int(self._bits[0:4]) -        i2 = _binstr2int(self._bits[4:8]) -        i3 = _binstr2int(self._bits[8:12]) -        i4 = _binstr2int(self._bits[12:16]) -        return '%08lx-%08lx-%08lx-%08lx' % (i1,i2,i3,i4) - -    def generate(self): -        """ -        Generate a new uuid. This algorithm is slightly different -        from c++ implementation for portability reasons. -        Returns self. -        """ -        m = md5() -        m.update(uuid.uuid1().bytes) -        self._bits = m.digest() -        return self - -    def isNull(self): -        """ -        Returns 1 if the uuid is null - ie, equal to default uuid. -        """ -        return (self._bits == "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0") - -    def xor(self, rhs): -        """ -        xors self with rhs. -        """ -        v1 = _binstr2int(self._bits[0:4]) ^ _binstr2int(rhs._bits[0:4]) -        v2 = _binstr2int(self._bits[4:8]) ^ _binstr2int(rhs._bits[4:8]) -        v3 = _binstr2int(self._bits[8:12]) ^ _binstr2int(rhs._bits[8:12]) -        v4 = _binstr2int(self._bits[12:16]) ^ _binstr2int(rhs._bits[12:16]) -        self._bits = _int2binstr(v1,4) + \ -                     _int2binstr(v2,4) + \ -                     _int2binstr(v3,4) + \ -                     _int2binstr(v4,4)  - - -# module-level null constant -NULL = UUID() - -def printTranslatedMemory(four_hex_uints): -    """ -    We expect to get the string as four hex units. eg: -    0x147d54db      0xc34b3f1b      0x714f989b      0x0a892fd2 -    Which will be translated to: -    db547d14-1b3f4bc3-9b984f71-d22f890a -    """ -    uuid = UUID() -    uuid.setFromMemoryDump(four_hex_uints) -    print uuid.toString() - -def isUUID(id_str): -    """ -    This function returns: -    - 1 if the string passed is a UUID -    - 0 is the string passed is not a UUID -    - None if it neither of the if's below is satisfied -    """ -    if not id_str or len(id_str) <  5 or len(id_str) > 36: -        return 0 - -    if isinstance(id_str, UUID) or UUID.uuid_regex.match(id_str): -        return 1 - -    return None - -def isPossiblyID(id_str): -    """ -    This function returns 1 if the string passed has some uuid-like -    characteristics. Otherwise returns 0. -    """ - -    is_uuid = isUUID(id_str) -    if is_uuid is not None: -        return is_uuid - -    # build a string which matches every character. -    hex_wildcard = r"[0-9a-fA-F]" -    chars = len(id_str) -    next = min(chars, 8) -    matcher = hex_wildcard+"{"+str(next)+","+str(next)+"}" -    chars = chars - next -    if chars > 0: -        matcher = matcher + "-" -        chars = chars - 1 -    for block in range(3): -        next = max(min(chars, 4), 0) -        if next: -            matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}" -            chars = chars - next -        if chars > 0: -            matcher = matcher + "-" -            chars = chars - 1 -    if chars > 0: -        next = min(chars, 12) -        matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}" -    #print matcher -    uuid_matcher = re.compile(matcher) -    if uuid_matcher.match(id_str): -        return 1 -    return 0 - -def uuid_bits_to_string(bits): -    i1 = _binstr2int(bits[0:4]) -    i2 = _binstr2int(bits[4:6]) -    i3 = _binstr2int(bits[6:8]) -    i4 = _binstr2int(bits[8:10]) -    i5 = _binstr2int(bits[10:12]) -    i6 = _binstr2int(bits[12:16]) -    return '%08lx-%04lx-%04lx-%04lx-%04lx%08lx' % (i1,i2,i3,i4,i5,i6) - -def uuid_bits_to_uuid(bits): -    return UUID(uuid_bits_to_string(bits)) - - -try: -    from mulib import stacked -    stacked.NoProducer()  # just to exercise stacked -except: -    #print "Couldn't import mulib.stacked, not registering UUID converter" -    pass -else: -    def convertUUID(uuid, req): -        req.write(str(uuid)) - -    stacked.add_producer(UUID, convertUUID, "*/*") -    stacked.add_producer(UUID, convertUUID, "text/html") diff --git a/indra/lib/python/indra/base/metrics.py b/indra/lib/python/indra/base/metrics.py deleted file mode 100755 index ff8380265f..0000000000 --- a/indra/lib/python/indra/base/metrics.py +++ /dev/null @@ -1,121 +0,0 @@ -"""\ -@file metrics.py -@author Phoenix -@date 2007-11-27 -@brief simple interface for logging metrics - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys -try: -    import syslog -except ImportError: -    # Windows -    import sys -    class syslog(object): -        # wrap to a lame syslog for windows -        _logfp = sys.stderr -        def syslog(msg): -            _logfp.write(msg) -            if not msg.endswith('\n'): -                _logfp.write('\n') -        syslog = staticmethod(syslog) - -from indra.base.llsd import format_notation - -def record_metrics(table, stats): -    "Write a standard metrics log" -    _log("LLMETRICS", table, stats) - -def record_event(table, data): -    "Write a standard logmessage log" -    _log("LLLOGMESSAGE", table, data) - -def set_destination(dest): -    """Set the destination of metrics logs for this process. - -    If you do not call this function prior to calling a logging -    method, that function will open sys.stdout as a destination. -    Attempts to set dest to None will throw a RuntimeError. -    @param dest a file-like object which will be the destination for logs.""" -    if dest is None: -        raise RuntimeError("Attempt to unset metrics destination.") -    global _destination -    _destination = dest - -def destination(): -    """Get the destination of the metrics logs for this process. -    Returns None if no destination is set""" -    global _destination -    return _destination - -class SysLogger(object): -    "A file-like object which writes to syslog." -    def __init__(self, ident='indra', logopt = None, facility = None): -        try: -            if logopt is None: -                logopt = syslog.LOG_CONS | syslog.LOG_PID -            if facility is None: -                facility = syslog.LOG_LOCAL0 -            syslog.openlog(ident, logopt, facility) -            import atexit -            atexit.register(syslog.closelog) -        except AttributeError: -            # No syslog module on Windows -            pass - -    def write(str): -        syslog.syslog(str) -    write = staticmethod(write) - -    def flush(): -        pass -    flush = staticmethod(flush) - -# -# internal API -# -_sequence_id = 0 -_destination = None - -def _next_id(): -    global _sequence_id -    next = _sequence_id -    _sequence_id += 1 -    return next - -def _dest(): -    global _destination -    if _destination is None: -        # this default behavior is documented in the metrics functions above. -        _destination = sys.stdout -    return _destination -     -def _log(header, table, data): -    log_line = "%s (%d) %s %s" \ -               % (header, _next_id(), table, format_notation(data)) -    dest = _dest() -    dest.write(log_line) -    dest.flush() diff --git a/indra/lib/python/indra/ipc/httputil.py b/indra/lib/python/indra/ipc/httputil.py deleted file mode 100755 index d53f34a771..0000000000 --- a/indra/lib/python/indra/ipc/httputil.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python -## $LicenseInfo:firstyear=2011&license=viewerlgpl$ -## Second Life Viewer Source Code -## Copyright (C) 2011, 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$ - -import warnings - -warnings.warn("indra.ipc.httputil has been deprecated; use eventlet.httpc instead", DeprecationWarning, 2) - -from eventlet.httpc import * - - -makeConnection = make_connection diff --git a/indra/lib/python/indra/ipc/llsdhttp.py b/indra/lib/python/indra/ipc/llsdhttp.py deleted file mode 100755 index cbe8ee1eca..0000000000 --- a/indra/lib/python/indra/ipc/llsdhttp.py +++ /dev/null @@ -1,100 +0,0 @@ -"""\ -@file llsdhttp.py -@brief Functions to ease moving llsd over http -  -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" -  -import os.path -import os -import urlparse - -from indra.base import llsd - -from eventlet import httpc - -suite = httpc.HttpSuite(llsd.format_xml, llsd.parse, 'application/llsd+xml') -delete = suite.delete -delete_ = suite.delete_ -get = suite.get -get_ = suite.get_ -head = suite.head -head_ = suite.head_ -post = suite.post -post_ = suite.post_ -put = suite.put -put_ = suite.put_ -request = suite.request -request_ = suite.request_ - -# import every httpc error exception into our namespace for convenience -for x in httpc.status_to_error_map.itervalues(): -    globals()[x.__name__] = x -ConnectionError = httpc.ConnectionError -Retriable = httpc.Retriable - -for x in (httpc.ConnectionError,): -    globals()[x.__name__] = x - - -def postFile(url, filename): -    f = open(filename) -    body = f.read() -    f.close() -    llsd_body = llsd.parse(body) -    return post_(url, llsd_body) - - -# deprecated in favor of get_ -def getStatus(url, use_proxy=False): -    status, _headers, _body = get_(url, use_proxy=use_proxy) -    return status - -# deprecated in favor of put_ -def putStatus(url, data): -    status, _headers, _body = put_(url, data) -    return status - -# deprecated in favor of delete_ -def deleteStatus(url): -    status, _headers, _body = delete_(url) -    return status - -# deprecated in favor of post_ -def postStatus(url, data): -    status, _headers, _body = post_(url, data) -    return status - - -def postFileStatus(url, filename): -    status, _headers, body = postFile(url, filename) -    return status, body - - -def getFromSimulator(path, use_proxy=False): -    return get('http://' + simulatorHostAndPort + path, use_proxy=use_proxy) - - -def postToSimulator(path, data=None): -    return post('http://' + simulatorHostAndPort + path, data) diff --git a/indra/lib/python/indra/ipc/mysql_pool.py b/indra/lib/python/indra/ipc/mysql_pool.py deleted file mode 100755 index e5855a3091..0000000000 --- a/indra/lib/python/indra/ipc/mysql_pool.py +++ /dev/null @@ -1,81 +0,0 @@ -"""\ -@file mysql_pool.py -@brief Thin wrapper around eventlet.db_pool that chooses MySQLdb and Tpool. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import MySQLdb -from eventlet import db_pool - -class DatabaseConnector(db_pool.DatabaseConnector): -    def __init__(self, credentials, *args, **kwargs): -        super(DatabaseConnector, self).__init__(MySQLdb, credentials, -                                                conn_pool=db_pool.ConnectionPool, -                                                *args, **kwargs) - -    # get is extended relative to eventlet.db_pool to accept a port argument -    def get(self, host, dbname, port=3306): -        key = (host, dbname, port) -        if key not in self._databases: -            new_kwargs = self._kwargs.copy() -            new_kwargs['db'] = dbname -            new_kwargs['host'] = host -            new_kwargs['port'] = port -            new_kwargs.update(self.credentials_for(host)) -            dbpool = ConnectionPool(*self._args, **new_kwargs) -            self._databases[key] = dbpool - -        return self._databases[key] - -class ConnectionPool(db_pool.TpooledConnectionPool): -    """A pool which gives out saranwrapped MySQLdb connections from a pool -    """ - -    def __init__(self, *args, **kwargs): -        super(ConnectionPool, self).__init__(MySQLdb, *args, **kwargs) - -    def get(self): -        conn = super(ConnectionPool, self).get() -        # annotate the connection object with the details on the -        # connection; this is used elsewhere to check that you haven't -        # suddenly changed databases in midstream while making a -        # series of queries on a connection. -        arg_names = ['host','user','passwd','db','port','unix_socket','conv','connect_timeout', -         'compress', 'named_pipe', 'init_command', 'read_default_file', 'read_default_group', -         'cursorclass', 'use_unicode', 'charset', 'sql_mode', 'client_flag', 'ssl', -         'local_infile'] -        # you could have constructed this connectionpool with a mix of -        # keyword and non-keyword arguments, but we want to annotate -        # the connection object with a dict so it's easy to check -        # against so here we are converting the list of non-keyword -        # arguments (in self._args) into a dict of keyword arguments, -        # and merging that with the actual keyword arguments -        # (self._kwargs).  The arg_names variable lists the -        # constructor arguments for MySQLdb Connection objects. -        converted_kwargs = dict([ (arg_names[i], arg) for i, arg in enumerate(self._args) ]) -        converted_kwargs.update(self._kwargs) -        conn.connection_parameters = converted_kwargs -        return conn - diff --git a/indra/lib/python/indra/ipc/russ.py b/indra/lib/python/indra/ipc/russ.py deleted file mode 100755 index ac780f128b..0000000000 --- a/indra/lib/python/indra/ipc/russ.py +++ /dev/null @@ -1,165 +0,0 @@ -"""\ -@file russ.py -@brief Recursive URL Substitution Syntax helpers -@author Phoenix - -Many details on how this should work is available on the wiki: -https://wiki.secondlife.com/wiki/Recursive_URL_Substitution_Syntax - -Adding features to this should be reflected in that page in the -implementations section. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import urllib -from indra.ipc import llsdhttp - -class UnbalancedBraces(Exception): -    pass - -class UnknownDirective(Exception): -    pass - -class BadDirective(Exception): -    pass - -def format_value_for_path(value): -    if type(value) in [list, tuple]: -        # *NOTE: treat lists as unquoted path components so that the quoting -        # doesn't get out-of-hand.  This is a workaround for the fact that -        # russ always quotes, even if the data it's given is already quoted, -        # and it's not safe to simply unquote a path directly, so if we want -        # russ to substitute urls parts inside other url parts we always -        # have to do so via lists of unquoted path components. -        return '/'.join([urllib.quote(str(item)) for item in value]) -    else: -        return urllib.quote(str(value)) - -def format(format_str, context): -    """@brief Format format string according to rules for RUSS. -@see https://osiris.lindenlab.com/mediawiki/index.php/Recursive_URL_Substitution_Syntax -@param format_str The input string to format. -@param context A map used for string substitutions. -@return Returns the formatted string. If no match, the braces remain intact. -""" -    while True: -        #print "format_str:", format_str -        all_matches = _find_sub_matches(format_str) -        if not all_matches: -            break -        substitutions = 0 -        while True: -            matches = all_matches.pop() -            # we work from right to left to make sure we do not -            # invalidate positions earlier in format_str -            matches.reverse() -            for pos in matches: -                # Use index since _find_sub_matches should have raised -                # an exception, and failure to find now is an exception. -                end = format_str.index('}', pos) -                #print "directive:", format_str[pos+1:pos+5] -                if format_str[pos + 1] == '$': -                    value = context[format_str[pos + 2:end]] -                    if value is not None: -                        value = format_value_for_path(value) -                elif format_str[pos + 1] == '%': -                    value = _build_query_string( -                        context.get(format_str[pos + 2:end])) -                elif format_str[pos+1:pos+5] == 'http' or format_str[pos+1:pos+5] == 'file': -                    value = _fetch_url_directive(format_str[pos + 1:end]) -                else: -                    raise UnknownDirective, format_str[pos:end + 1] -                if value is not None: -                    format_str = format_str[:pos]+str(value)+format_str[end+1:] -                    substitutions += 1 - -            # If there were any substitutions at this depth, re-parse -            # since this may have revealed new things to substitute -            if substitutions: -                break -            if not all_matches: -                break - -        # If there were no substitutions at all, and we have exhausted -        # the possible matches, bail. -        if not substitutions: -            break -    return format_str - -def _find_sub_matches(format_str): -    """@brief Find all of the substitution matches. -@param format_str the RUSS conformant format string.     -@return Returns an array of depths of arrays of positional matches in input. -""" -    depth = 0 -    matches = [] -    for pos in range(len(format_str)): -        if format_str[pos] == '{': -            depth += 1 -            if not len(matches) == depth: -                matches.append([]) -            matches[depth - 1].append(pos) -            continue -        if format_str[pos] == '}': -            depth -= 1 -            continue -    if not depth == 0: -        raise UnbalancedBraces, format_str -    return matches - -def _build_query_string(query_dict): -    """\ -    @breif given a dict, return a query string. utility wrapper for urllib. -    @param query_dict input query dict -    @returns Returns an urlencoded query string including leading '?'. -    """ -    if query_dict: -        keys = query_dict.keys() -        keys.sort() -        def stringize(value): -            if type(value) in (str,unicode): -                return value -            else: -                return str(value) -        query_list = [urllib.quote(str(key)) + '=' + urllib.quote(stringize(query_dict[key])) for key in keys] -        return '?' + '&'.join(query_list) -    else: -        return '' - -def _fetch_url_directive(directive): -    "*FIX: This only supports GET" -    commands = directive.split('|') -    resource = llsdhttp.get(commands[0]) -    if len(commands) == 3: -        resource = _walk_resource(resource, commands[2]) -    return resource - -def _walk_resource(resource, path): -    path = path.split('/') -    for child in path: -        if not child: -            continue -        resource = resource[child] -    return resource diff --git a/indra/lib/python/indra/ipc/servicebuilder.py b/indra/lib/python/indra/ipc/servicebuilder.py deleted file mode 100755 index 0a0ce2b4e2..0000000000 --- a/indra/lib/python/indra/ipc/servicebuilder.py +++ /dev/null @@ -1,134 +0,0 @@ -"""\ -@file servicebuilder.py -@author Phoenix -@brief Class which will generate service urls. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from indra.base import config -from indra.ipc import llsdhttp -from indra.ipc import russ - -# *NOTE: agent presence relies on this variable existing and being current, it is a huge hack -services_config = {} -try: -    services_config = llsdhttp.get(config.get('services-config')) -except: -    pass - -_g_builder = None -def _builder(): -    global _g_builder -    if _g_builder is None: -        _g_builder = ServiceBuilder() -    return _g_builder - -def build(name, context={}, **kwargs): -    """ Convenience method for using a global, singleton, service builder.  Pass arguments either via a dict or via python keyword arguments, or both! - -    Example use: -     > context = {'channel':'Second Life Release', 'version':'1.18.2.0'} -     > servicebuilder.build('version-manager-version', context) -       'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0' -     > servicebuilder.build('version-manager-version', channel='Second Life Release', version='1.18.2.0') -       'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0' -     > servicebuilder.build('version-manager-version', context, version='1.18.1.2') -       'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.1.2' -    """ -    global _g_builder -    if _g_builder is None: -        _g_builder = ServiceBuilder() -    return _g_builder.buildServiceURL(name, context, **kwargs) - -def build_path(name, context={}, **kwargs): -    context = context.copy()  # shouldn't modify the caller's dictionary -    context.update(kwargs) -    return _builder().buildPath(name, context) - -class ServiceBuilder(object): -    def __init__(self, services_definition = services_config): -        """\ -        @brief -        @brief Create a ServiceBuilder. -        @param services_definition Complete services definition, services.xml. -        """ -        # no need to keep a copy of the services section of the -        # complete services definition, but it doesn't hurt much. -        self.services = services_definition['services'] -        self.builders = {} -        for service in self.services: -            service_builder = service.get('service-builder') -            if not service_builder: -                continue -            if isinstance(service_builder, dict): -                # We will be constructing several builders -                for name, builder in service_builder.iteritems(): -                    full_builder_name = service['name'] + '-' + name -                    self.builders[full_builder_name] = builder -            else: -                self.builders[service['name']] = service_builder - -    def buildPath(self, name, context): -        """\ -        @brief given the environment on construction, return a service path. -        @param name The name of the service. -        @param context A dict of name value lookups for the service. -        @returns Returns the  -        """ -        return russ.format(self.builders[name], context) - -    def buildServiceURL(self, name, context={}, **kwargs): -        """\ -        @brief given the environment on construction, return a service URL. -        @param name The name of the service. -        @param context A dict of name value lookups for the service. -        @param kwargs Any keyword arguments are treated as members of the -            context, this allows you to be all 31337 by writing shit like: -            servicebuilder.build('name', param=value) -        @returns Returns the  -        """ -        context = context.copy()  # shouldn't modify the caller's dictionary -        context.update(kwargs) -        base_url = config.get('services-base-url') -        svc_path = russ.format(self.builders[name], context) -        return base_url + svc_path - - -def on_in(query_name, host_key, schema_key): -    """\ -    @brief Constructs an on/in snippet (for running named queries) -    from a schema name and two keys referencing values stored in -    indra.xml. - -    @param query_name Name of the query. -    @param host_key Logical name of destination host.  Will be -        looked up in indra.xml. -    @param schema_key Logical name of destination schema.  Will -        be looked up in indra.xml. -    """ -    return "on/config:%s/in/config:%s/%s" % (host_key.strip('/'), -                                             schema_key.strip('/'), -                                             query_name.lstrip('/')) - diff --git a/indra/lib/python/indra/ipc/siesta.py b/indra/lib/python/indra/ipc/siesta.py deleted file mode 100755 index d867e71537..0000000000 --- a/indra/lib/python/indra/ipc/siesta.py +++ /dev/null @@ -1,468 +0,0 @@ -"""\ -@file siesta.py -@brief A tiny llsd based RESTful web services framework - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from indra.base import config -from indra.base import llsd -from webob import exc -import webob -import re, socket - -try: -    from cStringIO import StringIO -except ImportError: -    from StringIO import StringIO - -try: -    import cjson -    json_decode = cjson.decode -    json_encode = cjson.encode -    JsonDecodeError = cjson.DecodeError -    JsonEncodeError = cjson.EncodeError -except ImportError: -    import simplejson -    json_decode = simplejson.loads -    json_encode = simplejson.dumps -    JsonDecodeError = ValueError -    JsonEncodeError = TypeError - - -llsd_parsers = { -    'application/json': json_decode, -    llsd.BINARY_MIME_TYPE: llsd.parse_binary, -    'application/llsd+notation': llsd.parse_notation, -    llsd.XML_MIME_TYPE: llsd.parse_xml, -    'application/xml': llsd.parse_xml, -    } - - -def mime_type(content_type): -    '''Given a Content-Type header, return only the MIME type.''' - -    return content_type.split(';', 1)[0].strip().lower() -     -class BodyLLSD(object): -    '''Give a webob Request or Response an llsd based "content" property. - -    Getting the content property parses the body, and caches the result. - -    Setting the content property formats a payload, and the body property -    is set.''' - -    def _llsd__get(self): -        '''Get, set, or delete the LLSD value stored in this object.''' - -        try: -            return self._llsd -        except AttributeError: -            if not self.body: -                raise AttributeError('No llsd attribute has been set') -            else: -                mtype = mime_type(self.content_type) -                try: -                    parser = llsd_parsers[mtype] -                except KeyError: -                    raise exc.HTTPUnsupportedMediaType( -                        'Content type %s not supported' % mtype).exception -                try: -                    self._llsd = parser(self.body) -                except (llsd.LLSDParseError, JsonDecodeError, TypeError), err: -                    raise exc.HTTPBadRequest( -                        'Could not parse body: %r' % err.args).exception -            return self._llsd - -    def _llsd__set(self, val): -        req = getattr(self, 'request', None) -        if req is not None: -            formatter, ctype = formatter_for_request(req) -            self.content_type = ctype -        else: -            formatter, ctype = formatter_for_mime_type( -                mime_type(self.content_type)) -        self.body = formatter(val) - -    def _llsd__del(self): -        if hasattr(self, '_llsd'): -            del self._llsd - -    content = property(_llsd__get, _llsd__set, _llsd__del) - - -class Response(webob.Response, BodyLLSD): -    '''Response class with LLSD support. - -    A sensible default content type is used. - -    Setting the llsd property also sets the body.  Getting the llsd -    property parses the body if necessary. - -    If you set the body property directly, the llsd property will be -    deleted.''' - -    default_content_type = 'application/llsd+xml' - -    def _body__set(self, body): -        if hasattr(self, '_llsd'): -            del self._llsd -        super(Response, self)._body__set(body) - -    def cache_forever(self): -        self.cache_expires(86400 * 365) - -    body = property(webob.Response._body__get, _body__set, -                    webob.Response._body__del, -                    webob.Response._body__get.__doc__) - - -class Request(webob.Request, BodyLLSD): -    '''Request class with LLSD support. - -    Sensible content type and accept headers are used by default. - -    Setting the content property also sets the body. Getting the content -    property parses the body if necessary. - -    If you set the body property directly, the content property will be -    deleted.''' -     -    default_content_type = 'application/llsd+xml' -    default_accept = ('application/llsd+xml; q=0.5, ' -                      'application/llsd+notation; q=0.3, ' -                      'application/llsd+binary; q=0.2, ' -                      'application/xml; q=0.1, ' -                      'application/json; q=0.0') - -    def __init__(self, environ=None, *args, **kwargs): -        if environ is None: -            environ = {} -        else: -            environ = environ.copy() -        if 'CONTENT_TYPE' not in environ: -            environ['CONTENT_TYPE'] = self.default_content_type -        if 'HTTP_ACCEPT' not in environ: -            environ['HTTP_ACCEPT'] = self.default_accept -        super(Request, self).__init__(environ, *args, **kwargs) - -    def _body__set(self, body): -        if hasattr(self, '_llsd'): -            del self._llsd -        super(Request, self)._body__set(body) - -    def path_urljoin(self, *parts): -        return '/'.join([path_url.rstrip('/')] + list(parts)) - -    body = property(webob.Request._body__get, _body__set, -                    webob.Request._body__del, webob.Request._body__get.__doc__) - -    def create_response(self, content=None, status='200 OK', -                        conditional_response=webob.NoDefault): -        resp = self.ResponseClass(status=status, request=self, -                                  conditional_response=conditional_response) -        resp.content = content -        return resp - -    def curl(self): -        '''Create and fill out a pycurl easy object from this request.''' -  -        import pycurl -        c = pycurl.Curl() -        c.setopt(pycurl.URL, self.url()) -        if self.headers: -            c.setopt(pycurl.HTTPHEADER, -                     ['%s: %s' % (k, self.headers[k]) for k in self.headers]) -        c.setopt(pycurl.FOLLOWLOCATION, True) -        c.setopt(pycurl.AUTOREFERER, True) -        c.setopt(pycurl.MAXREDIRS, 16) -        c.setopt(pycurl.NOSIGNAL, True) -        c.setopt(pycurl.READFUNCTION, self.body_file.read) -        c.setopt(pycurl.SSL_VERIFYHOST, 2) -         -        if self.method == 'POST': -            c.setopt(pycurl.POST, True) -            post301 = getattr(pycurl, 'POST301', None) -            if post301 is not None: -                # Added in libcurl 7.17.1. -                c.setopt(post301, True) -        elif self.method == 'PUT': -            c.setopt(pycurl.PUT, True) -        elif self.method != 'GET': -            c.setopt(pycurl.CUSTOMREQUEST, self.method) -        return c - -Request.ResponseClass = Response -Response.RequestClass = Request - - -llsd_formatters = { -    'application/json': json_encode, -    'application/llsd+binary': llsd.format_binary, -    'application/llsd+notation': llsd.format_notation, -    'application/llsd+xml': llsd.format_xml, -    'application/xml': llsd.format_xml, -    } - -formatter_qualities = ( -    ('application/llsd+xml', 1.0), -    ('application/llsd+notation', 0.5), -    ('application/llsd+binary', 0.4), -    ('application/xml', 0.3), -    ('application/json', 0.2), -    ) - -def formatter_for_mime_type(mime_type): -    '''Return a formatter that encodes to the given MIME type. - -    The result is a pair of function and MIME type.''' -    try: -        return llsd_formatters[mime_type], mime_type -    except KeyError: -        raise exc.HTTPInternalServerError( -            'Could not use MIME type %r to format response' % -            mime_type).exception - - -def formatter_for_request(req): -    '''Return a formatter that encodes to the preferred type of the client. - -    The result is a pair of function and actual MIME type.''' -    ctype = req.accept.best_match(formatter_qualities) -    try: -        return llsd_formatters[ctype], ctype -    except KeyError: -        raise exc.HTTPNotAcceptable().exception - - -def wsgi_adapter(func, environ, start_response): -    '''Adapt a Siesta callable to act as a WSGI application.''' -    # Process the request as appropriate. -    try: -        req = Request(environ) -        #print req.urlvars -        resp = func(req, **req.urlvars) -        if not isinstance(resp, webob.Response): -            try: -                formatter, ctype = formatter_for_request(req) -                resp = req.ResponseClass(formatter(resp), content_type=ctype) -                resp._llsd = resp -            except (JsonEncodeError, TypeError), err: -                resp = exc.HTTPInternalServerError( -                    detail='Could not format response') -    except exc.HTTPException, e: -        resp = e -    except socket.error, e: -        resp = exc.HTTPInternalServerError(detail=e.args[1]) -    return resp(environ, start_response) - - -def llsd_callable(func): -    '''Turn a callable into a Siesta application.''' - -    def replacement(environ, start_response): -        return wsgi_adapter(func, environ, start_response) - -    return replacement - - -def llsd_method(http_method, func): -    def replacement(environ, start_response): -        if environ['REQUEST_METHOD'] == http_method: -            return wsgi_adapter(func, environ, start_response) -        return exc.HTTPMethodNotAllowed()(environ, start_response) - -    return replacement - - -http11_methods = 'OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT'.split() -http11_methods.sort() - -def llsd_class(cls): -    '''Turn a class into a Siesta application. - -    A new instance is created for each request.  A HTTP method FOO is -    turned into a call to the handle_foo method of the instance.''' - -    def foo(req, **kwargs): -        instance = cls() -        method = req.method.lower() -        try: -            handler = getattr(instance, 'handle_' + method) -        except AttributeError: -            allowed = [m for m in http11_methods -                       if hasattr(instance, 'handle_' + m.lower())] -            raise exc.HTTPMethodNotAllowed( -                headers={'Allow': ', '.join(allowed)}).exception -        #print "kwargs: ", kwargs -        return handler(req, **kwargs) - -    def replacement(environ, start_response): -        return wsgi_adapter(foo, environ, start_response) - -    return replacement - - -def curl(reqs): -    import pycurl - -    m = pycurl.CurlMulti() -    curls = [r.curl() for r in reqs] -    io = {} -    for c in curls: -        fp = StringIO() -        hdr = StringIO() -        c.setopt(pycurl.WRITEFUNCTION, fp.write) -        c.setopt(pycurl.HEADERFUNCTION, hdr.write) -        io[id(c)] = fp, hdr -    m.handles = curls -    try: -        while True: -            ret, num_handles = m.perform() -            if ret != pycurl.E_CALL_MULTI_PERFORM: -                break -    finally: -        m.close() - -    for req, c in zip(reqs, curls): -        fp, hdr = io[id(c)] -        hdr.seek(0) -        status = hdr.readline().rstrip() -        headers = [] -        name, values = None, None - -        # XXX We don't currently handle bogus header data. - -        for line in hdr.readlines(): -            if not line[0].isspace(): -                if name: -                    headers.append((name, ' '.join(values))) -                name, value = line.strip().split(':', 1) -                value = [value] -            else: -                values.append(line.strip()) -        if name: -            headers.append((name, ' '.join(values))) - -        resp = c.ResponseClass(fp.getvalue(), status, headers, request=req) - - -route_re = re.compile(r''' -    \{                 # exact character "{" -    (\w*)              # "config" or variable (restricted to a-z, 0-9, _) -    (?:([:~])([^}]+))? # optional :type or ~regex part -    \}                 # exact character "}" -    ''', re.VERBOSE) - -predefined_regexps = { -    'uuid': r'[a-f0-9][a-f0-9-]{31,35}', -    'int': r'\d+', -    'host': r'[a-z0-9][a-z0-9\-\.]*', -    } - -def compile_route(route): -    fp = StringIO() -    last_pos = 0 -    for match in route_re.finditer(route): -        #print "matches: ", match.groups() -        fp.write(re.escape(route[last_pos:match.start()])) -        var_name = match.group(1) -        sep = match.group(2) -        expr = match.group(3) -        if var_name == 'config': -            expr = re.escape(str(config.get(var_name))) -        else: -            if expr: -                if sep == ':': -                    expr = predefined_regexps[expr] -                # otherwise, treat what follows '~' as a regexp -            else: -                expr = '[^/]+' -            if var_name != '': -                expr = '(?P<%s>%s)' % (var_name, expr) -            else: -                expr = '(%s)' % (expr,) -        fp.write(expr) -        last_pos = match.end() -    fp.write(re.escape(route[last_pos:])) -    compiled_route = '^%s$' % fp.getvalue() -    #print route, "->", compiled_route -    return compiled_route - -class Router(object): -    '''WSGI routing class.  Parses a URL and hands off a request to -    some other WSGI application.  If no suitable application is found, -    responds with a 404.''' - -    def __init__(self): -        self._new_routes = [] -        self._routes = [] -        self._paths = [] - -    def add(self, route, app, methods=None): -        self._new_routes.append((route, app, methods)) - -    def _create_routes(self): -        for route, app, methods in self._new_routes: -            self._paths.append(route) -            self._routes.append( -                (re.compile(compile_route(route)), -                 app, -                 methods and dict.fromkeys(methods))) -        self._new_routes = [] - -    def __call__(self, environ, start_response): -        # load up the config from the config file. Only needs to be -        # done once per interpreter. This is the entry point of all -        # siesta applications, so this is where we trap it. -        _conf = config.get_config() -        if _conf is None: -            import os.path -            fname = os.path.join( -                environ.get('ll.config_dir', '/local/linden/etc'), -                'indra.xml') -            config.load(fname) - -        # proceed with handling the request -        self._create_routes() -        path_info = environ['PATH_INFO'] -        request_method = environ['REQUEST_METHOD'] -        allowed = [] -        for regex, app, methods in self._routes: -            m = regex.match(path_info) -            if m: -                #print "groupdict:",m.groupdict() -                if not methods or request_method in methods: -                    environ['paste.urlvars'] = m.groupdict() -                    return app(environ, start_response) -                else: -                    allowed += methods -        if allowed: -            allowed = dict.fromkeys(allows).keys() -            allowed.sort() -            resp = exc.HTTPMethodNotAllowed( -                headers={'Allow': ', '.join(allowed)}) -        else: -            resp = exc.HTTPNotFound() -        return resp(environ, start_response) diff --git a/indra/lib/python/indra/ipc/siesta_test.py b/indra/lib/python/indra/ipc/siesta_test.py deleted file mode 100755 index a35eed2460..0000000000 --- a/indra/lib/python/indra/ipc/siesta_test.py +++ /dev/null @@ -1,235 +0,0 @@ -#!/usr/bin/python -## $LicenseInfo:firstyear=2011&license=viewerlgpl$ -## Second Life Viewer Source Code -## Copyright (C) 2011, 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$ -from indra.base import llsd, lluuid -from indra.ipc import siesta -import datetime, math, unittest -from webob import exc - - -class ClassApp(object): -    def handle_get(self, req): -        pass - -    def handle_post(self, req): -        return req.llsd -     - -def callable_app(req): -    if req.method == 'UNDERPANTS': -        raise exc.HTTPMethodNotAllowed() -    elif req.method == 'GET': -        return None -    return req.llsd - - -class TestBase: -    def test_basic_get(self): -        req = siesta.Request.blank('/') -        self.assertEquals(req.get_response(self.server).body, -                          llsd.format_xml(None)) -         -    def test_bad_method(self): -        req = siesta.Request.blank('/') -        req.environ['REQUEST_METHOD'] = 'UNDERPANTS' -        self.assertEquals(req.get_response(self.server).status_int, -                          exc.HTTPMethodNotAllowed.code) -         -    json_safe = { -        'none': None, -        'bool_true': True, -        'bool_false': False, -        'int_zero': 0, -        'int_max': 2147483647, -        'int_min': -2147483648, -        'long_zero': 0, -        'long_max': 2147483647L, -        'long_min': -2147483648L, -        'float_zero': 0, -        'float': math.pi, -        'float_huge': 3.14159265358979323846e299, -        'str_empty': '', -        'str': 'foo', -        u'unic\u1e51de_empty': u'', -        u'unic\u1e51de': u'\u1e4exx\u10480', -        } -    json_safe['array'] = json_safe.values() -    json_safe['tuple'] = tuple(json_safe.values()) -    json_safe['dict'] = json_safe.copy() - -    json_unsafe = { -        'uuid_empty': lluuid.UUID(), -        'uuid_full': lluuid.UUID('dc61ab0530200d7554d23510559102c1a98aab1b'), -        'binary_empty': llsd.binary(), -        'binary': llsd.binary('f\0\xff'), -        'uri_empty': llsd.uri(), -        'uri': llsd.uri('http://www.secondlife.com/'), -        'datetime_empty': datetime.datetime(1970,1,1), -        'datetime': datetime.datetime(1999,9,9,9,9,9), -        } -    json_unsafe.update(json_safe) -    json_unsafe['array'] = json_unsafe.values() -    json_unsafe['tuple'] = tuple(json_unsafe.values()) -    json_unsafe['dict'] = json_unsafe.copy() -    json_unsafe['iter'] = iter(json_unsafe.values()) - -    def _test_client_content_type_good(self, content_type, ll): -        def run(ll): -            req = siesta.Request.blank('/') -            req.environ['REQUEST_METHOD'] = 'POST' -            req.content_type = content_type -            req.llsd = ll -            req.accept = content_type -            resp = req.get_response(self.server) -            self.assertEquals(resp.status_int, 200) -            return req, resp -         -        if False and isinstance(ll, dict): -            def fixup(v): -                if isinstance(v, float): -                    return '%.5f' % v -                if isinstance(v, long): -                    return int(v) -                if isinstance(v, (llsd.binary, llsd.uri)): -                    return v -                if isinstance(v, (tuple, list)): -                    return [fixup(i) for i in v] -                if isinstance(v, dict): -                    return dict([(k, fixup(i)) for k, i in v.iteritems()]) -                return v -            for k, v in ll.iteritems(): -                l = [k, v] -                req, resp = run(l) -                self.assertEquals(fixup(resp.llsd), fixup(l)) - -        run(ll) - -    def test_client_content_type_json_good(self): -        self._test_client_content_type_good('application/json', self.json_safe) - -    def test_client_content_type_llsd_xml_good(self): -        self._test_client_content_type_good('application/llsd+xml', -                                            self.json_unsafe) - -    def test_client_content_type_llsd_notation_good(self): -        self._test_client_content_type_good('application/llsd+notation', -                                            self.json_unsafe) - -    def test_client_content_type_llsd_binary_good(self): -        self._test_client_content_type_good('application/llsd+binary', -                                            self.json_unsafe) - -    def test_client_content_type_xml_good(self): -        self._test_client_content_type_good('application/xml', -                                            self.json_unsafe) - -    def _test_client_content_type_bad(self, content_type): -        req = siesta.Request.blank('/') -        req.environ['REQUEST_METHOD'] = 'POST' -        req.body = '\0invalid nonsense under all encodings' -        req.content_type = content_type -        self.assertEquals(req.get_response(self.server).status_int, -                          exc.HTTPBadRequest.code) -         -    def test_client_content_type_json_bad(self): -        self._test_client_content_type_bad('application/json') - -    def test_client_content_type_llsd_xml_bad(self): -        self._test_client_content_type_bad('application/llsd+xml') - -    def test_client_content_type_llsd_notation_bad(self): -        self._test_client_content_type_bad('application/llsd+notation') - -    def test_client_content_type_llsd_binary_bad(self): -        self._test_client_content_type_bad('application/llsd+binary') - -    def test_client_content_type_xml_bad(self): -        self._test_client_content_type_bad('application/xml') - -    def test_client_content_type_bad(self): -        req = siesta.Request.blank('/') -        req.environ['REQUEST_METHOD'] = 'POST' -        req.body = 'XXX' -        req.content_type = 'application/nonsense' -        self.assertEquals(req.get_response(self.server).status_int, -                          exc.HTTPUnsupportedMediaType.code) - -    def test_request_default_content_type(self): -        req = siesta.Request.blank('/') -        self.assertEquals(req.content_type, req.default_content_type) - -    def test_request_default_accept(self): -        req = siesta.Request.blank('/') -        from webob import acceptparse -        self.assertEquals(str(req.accept).replace(' ', ''), -                          req.default_accept.replace(' ', '')) - -    def test_request_llsd_auto_body(self): -        req = siesta.Request.blank('/') -        req.llsd = {'a': 2} -        self.assertEquals(req.body, '<?xml version="1.0" ?><llsd><map>' -                          '<key>a</key><integer>2</integer></map></llsd>') - -    def test_request_llsd_mod_body_changes_llsd(self): -        req = siesta.Request.blank('/') -        req.llsd = {'a': 2} -        req.body = '<?xml version="1.0" ?><llsd><integer>1337</integer></llsd>' -        self.assertEquals(req.llsd, 1337) - -    def test_request_bad_llsd_fails(self): -        def crashme(ctype): -            def boom(): -                class foo(object): pass -                req = siesta.Request.blank('/') -                req.content_type = ctype -                req.llsd = foo() -        for mime_type in siesta.llsd_parsers: -            self.assertRaises(TypeError, crashme(mime_type)) - - -class ClassServer(TestBase, unittest.TestCase): -    def __init__(self, *args, **kwargs): -        unittest.TestCase.__init__(self, *args, **kwargs) -        self.server = siesta.llsd_class(ClassApp) - - -class CallableServer(TestBase, unittest.TestCase): -    def __init__(self, *args, **kwargs): -        unittest.TestCase.__init__(self, *args, **kwargs) -        self.server = siesta.llsd_callable(callable_app) - - -class RouterServer(unittest.TestCase): -    def test_router(self): -        def foo(req, quux): -            print quux - -        r = siesta.Router() -        r.add('/foo/{quux:int}', siesta.llsd_callable(foo), methods=['GET']) -        req = siesta.Request.blank('/foo/33') -        req.get_response(r) - -        req = siesta.Request.blank('/foo/bar') -        self.assertEquals(req.get_response(r).status_int, -                          exc.HTTPNotFound.code) -     -if __name__ == '__main__': -    unittest.main() diff --git a/indra/lib/python/indra/ipc/webdav.py b/indra/lib/python/indra/ipc/webdav.py deleted file mode 100755 index 98b8499b6a..0000000000 --- a/indra/lib/python/indra/ipc/webdav.py +++ /dev/null @@ -1,597 +0,0 @@ -""" -@file webdav.py -@brief Classes to make manipulation of a webdav store easier. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys, os, httplib, urlparse -import socket, time -import xml.dom.minidom -import syslog -# import signal - -__revision__ = '0' - -dav_debug = False - - -# def urlsafe_b64decode (enc): -#     return base64.decodestring (enc.replace ('_', '/').replace ('-', '+')) - -# def urlsafe_b64encode (str): -#     return base64.encodestring (str).replace ('+', '-').replace ('/', '_') - - -class DAVError (Exception): -    """ Base class for exceptions in this module. """ -    def __init__ (self, status=0, message='', body='', details=''): -        self.status = status -        self.message = message -        self.body = body -        self.details = details -        Exception.__init__ (self, '%d:%s:%s%s' % (self.status, self.message, -                                                   self.body, self.details)) - -    def print_to_stderr (self): -        """ print_to_stderr docstring """ -        print >> sys.stderr, str (self.status) + ' ' + self.message -        print >> sys.stderr, str (self.details) - - -class Timeout (Exception): -    """ Timeout docstring """ -    def __init__ (self, arg=''): -        Exception.__init__ (self, arg) - - -def alarm_handler (signum, frame): -    """ alarm_handler docstring """ -    raise Timeout ('caught alarm') - - -class WebDAV: -    """ WebDAV docstring """ -    def __init__ (self, url, proxy=None, retries_before_fail=6): -        self.init_url = url -        self.init_proxy = proxy -        self.retries_before_fail = retries_before_fail -        url_parsed = urlparse.urlsplit (url) - -        self.top_path = url_parsed[ 2 ] -        # make sure top_path has a trailing / -        if self.top_path == None or self.top_path == '': -            self.top_path = '/' -        elif len (self.top_path) > 1 and self.top_path[-1:] != '/': -            self.top_path += '/' - -        if dav_debug: -            syslog.syslog ('new WebDAV %s : %s' % (str (url), str (proxy))) - -        if proxy: -            proxy_parsed = urlparse.urlsplit (proxy) -            self.host_header = url_parsed[ 1 ] -            host_and_port = proxy_parsed[ 1 ].split (':') -            self.host = host_and_port[ 0 ] -            if len (host_and_port) > 1: -                self.port = int(host_and_port[ 1 ]) -            else: -                self.port = 80 -        else: # no proxy -            host_and_port = url_parsed[ 1 ].split (':') -            self.host_header = None -            self.host = host_and_port[ 0 ] -            if len (host_and_port) > 1: -                self.port = int(host_and_port[ 1 ]) -            else: -                self.port = 80 - -        self.connection = False -        self.connect () - - -    def log (self, msg, depth=0): -        """ log docstring """ -        if dav_debug and depth == 0: -            host = str (self.init_url) -            if host == 'http://int.tuco.lindenlab.com:80/asset/': -                host = 'tuco' -            if host == 'http://harriet.lindenlab.com/asset-keep/': -                host = 'harriet/asset-keep' -            if host == 'http://harriet.lindenlab.com/asset-flag/': -                host = 'harriet/asset-flag' -            if host == 'http://harriet.lindenlab.com/asset/': -                host = 'harriet/asset' -            if host == 'http://ozzy.lindenlab.com/asset/': -                host = 'ozzy/asset' -            if host == 'http://station11.lindenlab.com:12041/:': -                host = 'station11:12041' -            proxy = str (self.init_proxy) -            if proxy == 'None': -                proxy = '' -            if proxy == 'http://int.tuco.lindenlab.com:3128/': -                proxy = 'tuco' -            syslog.syslog ('WebDAV (%s:%s) %s' % (host, proxy, str (msg))) - - -    def connect (self): -        """ connect docstring """ -        self.log ('connect') -        self.connection = httplib.HTTPConnection (self.host, self.port) - -    def __err (self, response, details): -        """ __err docstring """ -        raise DAVError (response.status, response.reason, response.read (), -                        str (self.init_url) + ':' + \ -                        str (self.init_proxy) + ':' + str (details)) - -    def request (self, method, path, body=None, headers=None, -                 read_all=True, body_hook = None, recurse=0, allow_cache=True): -        """ request docstring """ -        # self.log ('request %s %s' % (method, path)) -        if headers == None: -            headers = {} -        if not allow_cache: -            headers['Pragma'] = 'no-cache' -            headers['cache-control'] = 'no-cache' -        try: -            if method.lower () != 'purge': -                if path.startswith ('/'): -                    path = path[1:] -                if self.host_header: # use proxy -                    headers[ 'host' ] = self.host_header -                    fullpath = 'http://%s%s%s' % (self.host_header, -                                                  self.top_path, path) -                else: # no proxy -                    fullpath = self.top_path + path -            else: -                fullpath = path - -            self.connection.request (method, fullpath, body, headers) -            if body_hook: -                body_hook () - -            # signal.signal (signal.SIGALRM, alarm_handler) -            # try: -            #     signal.alarm (120) -            #     signal.alarm (0) -            # except Timeout, e: -            #     if recurse < 6: -            #         return self.retry_request (method, path, body, headers, -            #                                    read_all, body_hook, recurse) -            #     else: -            #         raise DAVError (0, 'timeout', self.host, -            #                         (method, path, body, headers, recurse)) - -            response = self.connection.getresponse () - -            if read_all: -                while len (response.read (1024)) > 0: -                    pass -            if (response.status == 500 or \ -                response.status == 503 or \ -                response.status == 403) and \ -                recurse < self.retries_before_fail: -                return self.retry_request (method, path, body, headers, -                                           read_all, body_hook, recurse) -            return response -        except (httplib.ResponseNotReady, -                httplib.BadStatusLine, -                socket.error): -            # if the server hangs up on us (keepalive off, broken pipe), -            # we need to reconnect and try again. -            if recurse < self.retries_before_fail: -                return self.retry_request (method, path, body, headers, -                                           read_all, body_hook, recurse) -            raise DAVError (0, 'reconnect failed', self.host, -                            (method, path, body, headers, recurse)) - - -    def retry_request (self, method, path, body, headers, -                       read_all, body_hook, recurse): -        """ retry_request docstring """ -        time.sleep (10.0 * recurse) -        self.connect () -        return self.request (method, path, body, headers, -                             read_all, body_hook, recurse+1) - - - -    def propfind (self, path, body=None, depth=1): -        """ propfind docstring """ -        # self.log ('propfind %s' % path) -        headers = {'Content-Type':'text/xml; charset="utf-8"', -                   'Depth':str(depth)} -        response = self.request ('PROPFIND', path, body, headers, False) -        if response.status == 207: -            return response # Multi-Status -        self.__err (response, ('PROPFIND', path, body, headers, 0)) - - -    def purge (self, path): -        """ issue a squid purge command """ -        headers = {'Accept':'*/*'} -        response = self.request ('PURGE', path, None, headers) -        if response.status == 200 or response.status == 404: -            # 200 if it was purge, 404 if it wasn't there. -            return response -        self.__err (response, ('PURGE', path, None, headers)) - - -    def get_file_size (self, path): -        """ -        Use propfind to ask a webdav server what the size of -        a file is.  If used on a directory (collection) return 0 -        """ -        self.log ('get_file_size %s' % path) -        # "getcontentlength" property -        # 8.1.1 Example - Retrieving Named Properties -        # http://docs.python.org/lib/module-xml.dom.html -        nsurl = 'http://apache.org/dav/props/' -        doc = xml.dom.minidom.Document () -        propfind_element = doc.createElementNS (nsurl, "D:propfind") -        propfind_element.setAttributeNS (nsurl, 'xmlns:D', 'DAV:') -        doc.appendChild (propfind_element) -        prop_element = doc.createElementNS (nsurl, "D:prop") -        propfind_element.appendChild (prop_element) -        con_len_element = doc.createElementNS (nsurl, "D:getcontentlength") -        prop_element.appendChild (con_len_element) - -        response = self.propfind (path, doc.toxml ()) -        doc.unlink () - -        resp_doc = xml.dom.minidom.parseString (response.read ()) -        cln = resp_doc.getElementsByTagNameNS ('DAV:','getcontentlength')[ 0 ] -        try: -            content_length = int (cln.childNodes[ 0 ].nodeValue) -        except IndexError: -            return 0 -        resp_doc.unlink () -        return content_length - - -    def file_exists (self, path): -        """ -        do an http head on the given file.  return True if it succeeds -        """ -        self.log ('file_exists %s' % path) -        expect_gzip = path.endswith ('.gz') -        response = self.request ('HEAD', path) -        got_gzip = response.getheader ('Content-Encoding', '').strip () -        if got_gzip.lower () == 'x-gzip' and expect_gzip == False: -            # the asset server fakes us out if we ask for the non-gzipped -            # version of an asset, but the server has the gzipped version. -            return False -        return response.status == 200 - - -    def mkdir (self, path): -        """ mkdir docstring """ -        self.log ('mkdir %s' % path) -        headers = {} -        response = self.request ('MKCOL', path, None, headers) -        if response.status == 201: -            return # success -        if response.status == 405: -            return # directory already existed? -        self.__err (response, ('MKCOL', path, None, headers, 0)) - - -    def delete (self, path): -        """ delete docstring """ -        self.log ('delete %s' % path) -        headers = {'Depth':'infinity'} # collections require infinity -        response = self.request ('DELETE', path, None, headers) -        if response.status == 204: -            return # no content -        if response.status == 404: -            return # hmm -        self.__err (response, ('DELETE', path, None, headers, 0)) - - -    def list_directory (self, path, dir_filter=None, allow_cache=True, -                        minimum_cache_time=False): -        """ -        Request an http directory listing and parse the filenames out of lines -        like: '<LI><A HREF="X"> X</A>'. If a filter function is provided, -        only return filenames that the filter returns True for. - -        This is sort of grody, but it seems faster than other ways of getting -        this information from an isilon. -        """ -        self.log ('list_directory %s' % path) - -        def try_match (lline, before, after): -            """ try_match docstring """ -            try: -                blen = len (before) -                asset_start_index = lline.index (before) -                asset_end_index = lline.index (after, asset_start_index + blen) -                asset = line[ asset_start_index + blen : asset_end_index ] - -                if not dir_filter or dir_filter (asset): -                    return [ asset ] -                return [] -            except ValueError: -                return [] - -        if len (path) > 0 and path[-1:] != '/': -            path += '/' - -        response = self.request ('GET', path, None, {}, False, -                                 allow_cache=allow_cache) - -        if allow_cache and minimum_cache_time: # XXX -            print response.getheader ('Date') -            # s = "2005-12-06T12:13:14" -            # from datetime import datetime -            # from time import strptime -            # datetime(*strptime(s, "%Y-%m-%dT%H:%M:%S")[0:6]) -            # datetime.datetime(2005, 12, 6, 12, 13, 14) - -        if response.status != 200: -            self.__err (response, ('GET', path, None, {}, 0)) -        assets = [] -        for line in response.read ().split ('\n'): -            lline = line.lower () -            if lline.find ("parent directory") == -1: -                # isilon file -                assets += try_match (lline, '<li><a href="', '"> ') -                # apache dir -                assets += try_match (lline, 'alt="[dir]"> <a href="', '/">') -                # apache file -                assets += try_match (lline, 'alt="[   ]"> <a href="', '">') -        return assets - - -    def __tmp_filename (self, path_and_file): -        """ __tmp_filename docstring """ -        head, tail = os.path.split (path_and_file) -        if head != '': -            return head + '/.' + tail + '.' + str (os.getpid ()) -        else: -            return head + '.' + tail + '.' + str (os.getpid ()) - - -    def __put__ (self, filesize, body_hook, remotefile): -        """ __put__ docstring """ -        headers = {'Content-Length' : str (filesize)} -        remotefile_tmp = self.__tmp_filename (remotefile) -        response = self.request ('PUT', remotefile_tmp, None, -                                 headers, True, body_hook) -        if not response.status in (201, 204): # created, no content -            self.__err (response, ('PUT', remotefile, None, headers, 0)) -        if filesize != self.get_file_size (remotefile_tmp): -            try: -                self.delete (remotefile_tmp) -            except: -                pass -            raise DAVError (0, 'tmp upload error', remotefile_tmp) -        # move the file to its final location -        try: -            self.rename (remotefile_tmp, remotefile) -        except DAVError, exc: -            if exc.status == 403: # try to clean up the tmp file -                try: -                    self.delete (remotefile_tmp) -                except: -                    pass -            raise -        if filesize != self.get_file_size (remotefile): -            raise DAVError (0, 'file upload error', str (remotefile_tmp)) - - -    def put_string (self, strng, remotefile): -        """ put_string docstring """ -        self.log ('put_string %d -> %s' % (len (strng), remotefile)) -        filesize = len (strng) -        def body_hook (): -            """ body_hook docstring """ -            self.connection.send (strng) -        self.__put__ (filesize, body_hook, remotefile) - - -    def put_file (self, localfile, remotefile): -        """ -        Send a local file to a remote webdav store.  First, upload to -        a temporary filename.  Next make sure the file is the size we -        expected.  Next, move the file to its final location.  Next, -        check the file size at the final location. -        """ -        self.log ('put_file %s -> %s' % (localfile, remotefile)) -        filesize = os.path.getsize (localfile) -        def body_hook (): -            """ body_hook docstring """ -            handle = open (localfile) -            while True: -                data = handle.read (1300) -                if len (data) == 0: -                    break -                self.connection.send (data) -            handle.close () -        self.__put__ (filesize, body_hook, remotefile) - - -    def create_empty_file (self, remotefile): -        """ create an empty file """ -        self.log ('touch_file %s' % (remotefile)) -        headers = {'Content-Length' : '0'} -        response = self.request ('PUT', remotefile, None, headers) -        if not response.status in (201, 204): # created, no content -            self.__err (response, ('PUT', remotefile, None, headers, 0)) -        if self.get_file_size (remotefile) != 0: -            raise DAVError (0, 'file upload error', str (remotefile)) - - -    def __get_file_setup (self, remotefile, check_size=True): -        """ __get_file_setup docstring """ -        if check_size: -            remotesize = self.get_file_size (remotefile) -        response = self.request ('GET', remotefile, None, {}, False) -        if response.status != 200: -            self.__err (response, ('GET', remotefile, None, {}, 0)) -        try: -            content_length = int (response.getheader ("Content-Length")) -        except TypeError: -            content_length = None -        if check_size: -            if content_length != remotesize: -                raise DAVError (0, 'file DL size error', remotefile) -        return (response, content_length) - - -    def __get_file_read (self, writehandle, response, content_length): -        """ __get_file_read docstring """ -        if content_length != None: -            so_far_length = 0 -            while so_far_length < content_length: -                data = response.read (content_length - so_far_length) -                if len (data) == 0: -                    raise DAVError (0, 'short file download') -                so_far_length += len (data) -                writehandle.write (data) -            while len (response.read ()) > 0: -                pass -        else: -            while True: -                data = response.read () -                if (len (data) < 1): -                    break -                writehandle.write (data) - - -    def get_file (self, remotefile, localfile, check_size=True): -        """ -        Get a remote file from a webdav server.  Download to a local -        tmp file, then move into place.  Sanity check file sizes as -        we go. -        """ -        self.log ('get_file %s -> %s' % (remotefile, localfile)) -        (response, content_length) = \ -                   self.__get_file_setup (remotefile, check_size) -        localfile_tmp = self.__tmp_filename (localfile) -        handle = open (localfile_tmp, 'w') -        self.__get_file_read (handle, response, content_length) -        handle.close () -        if check_size: -            if content_length != os.path.getsize (localfile_tmp): -                raise DAVError (0, 'file DL size error', -                                remotefile+','+localfile) -        os.rename (localfile_tmp, localfile) - - -    def get_file_as_string (self, remotefile, check_size=True): -        """ -        download a file from a webdav server and return it as a string. -        """ -        self.log ('get_file_as_string %s' % remotefile) -        (response, content_length) = \ -                   self.__get_file_setup (remotefile, check_size) -        # (tmp_handle, tmp_filename) = tempfile.mkstemp () -        tmp_handle = os.tmpfile () -        self.__get_file_read (tmp_handle, response, content_length) -        tmp_handle.seek (0) -        ret = tmp_handle.read () -        tmp_handle.close () -        # os.unlink (tmp_filename) -        return ret - - -    def get_post_as_string (self, remotefile, body): -        """ -        Do an http POST, send body, get response and return it. -        """ -        self.log ('get_post_as_string %s' % remotefile) -        # headers = {'Content-Type':'application/x-www-form-urlencoded'} -        headers = {'Content-Type':'text/xml; charset="utf-8"'} -        # b64body = urlsafe_b64encode (asset_url) -        response = self.request ('POST', remotefile, body, headers, False) -        if response.status != 200: -            self.__err (response, ('POST', remotefile, body, headers, 0)) -        try: -            content_length = int (response.getheader ('Content-Length')) -        except TypeError: -            content_length = None -        tmp_handle = os.tmpfile () -        self.__get_file_read (tmp_handle, response, content_length) -        tmp_handle.seek (0) -        ret = tmp_handle.read () -        tmp_handle.close () -        return ret - - -    def __destination_command (self, verb, remotesrc, dstdav, remotedst): -        """ -        self and dstdav should point to the same http server. -        """ -        if len (remotedst) > 0 and remotedst[ 0 ] == '/': -            remotedst = remotedst[1:] -        headers = {'Destination': 'http://%s:%d%s%s' % (dstdav.host, -                                                        dstdav.port, -                                                        dstdav.top_path, -                                                        remotedst)} -        response = self.request (verb, remotesrc, None, headers) -        if response.status == 201: -            return # created -        if response.status == 204: -            return # no content -        self.__err (response, (verb, remotesrc, None, headers, 0)) - - -    def rename (self, remotesrc, remotedst): -        """ rename a file on a webdav server """ -        self.log ('rename %s -> %s' % (remotesrc, remotedst)) -        self.__destination_command ('MOVE', remotesrc, self, remotedst) -    def xrename (self, remotesrc, dstdav, remotedst): -        """ rename a file on a webdav server """ -        self.log ('xrename %s -> %s' % (remotesrc, remotedst)) -        self.__destination_command ('MOVE', remotesrc, dstdav, remotedst) - - -    def copy (self, remotesrc, remotedst): -        """ copy a file on a webdav server """ -        self.log ('copy %s -> %s' % (remotesrc, remotedst)) -        self.__destination_command ('COPY', remotesrc, self, remotedst) -    def xcopy (self, remotesrc, dstdav, remotedst): -        """ copy a file on a webdav server """ -        self.log ('xcopy %s -> %s' % (remotesrc, remotedst)) -        self.__destination_command ('COPY', remotesrc, dstdav, remotedst) - - -def put_string (data, url): -    """ -    upload string s to a url -    """ -    url_parsed = urlparse.urlsplit (url) -    dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ])) -    dav.put_string (data, url_parsed[ 2 ]) - - -def get_string (url, check_size=True): -    """ -    return the contents of a url as a string -    """ -    url_parsed = urlparse.urlsplit (url) -    dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ])) -    return dav.get_file_as_string (url_parsed[ 2 ], check_size) diff --git a/indra/lib/python/indra/ipc/xml_rpc.py b/indra/lib/python/indra/ipc/xml_rpc.py deleted file mode 100755 index 47536c10c3..0000000000 --- a/indra/lib/python/indra/ipc/xml_rpc.py +++ /dev/null @@ -1,273 +0,0 @@ -"""\ -@file xml_rpc.py -@brief An implementation of a parser/generator for the XML-RPC xml format. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - - -from greenlet import greenlet - -from mulib import mu - -from xml.sax import handler -from xml.sax import parseString - - -# States -class Expected(object): -    def __init__(self, tag): -        self.tag = tag - -    def __getattr__(self, name): -        return type(self)(name) - -    def __repr__(self): -        return '%s(%r)' % ( -            type(self).__name__, self.tag) - - -class START(Expected): -    pass - - -class END(Expected): -    pass - - -class STR(object): -    tag = '' - - -START = START('') -END = END('') - - -class Malformed(Exception): -    pass - - -class XMLParser(handler.ContentHandler): -    def __init__(self, state_machine, next_states): -        handler.ContentHandler.__init__(self) -        self.state_machine = state_machine -        if not isinstance(next_states, tuple): -            next_states = (next_states, ) -        self.next_states = next_states -        self._character_buffer = '' - -    def assertState(self, state, name, *rest): -        if not isinstance(self.next_states, tuple): -            self.next_states = (self.next_states, ) -        for next in self.next_states: -            if type(state) == type(next): -                if next.tag and next.tag != name: -                    raise Malformed( -                        "Expected %s, got %s %s %s" % ( -                            next, state, name, rest)) -                break -        else: -            raise Malformed( -                "Expected %s, got %s %s %s" % ( -                    self.next_states, state, name, rest)) - -    def startElement(self, name, attrs): -        self.assertState(START, name.lower(), attrs) -        self.next_states = self.state_machine.switch(START, (name.lower(), dict(attrs))) - -    def endElement(self, name): -        if self._character_buffer.strip(): -            characters = self._character_buffer.strip() -            self._character_buffer = '' -            self.assertState(STR, characters) -            self.next_states = self.state_machine.switch(characters) -        self.assertState(END, name.lower()) -        self.next_states = self.state_machine.switch(END, name.lower()) - -    def error(self, exc): -        self.bozo = 1 -        self.exc = exc - -    def fatalError(self, exc): -        self.error(exc) -        raise exc - -    def characters(self, characters): -        self._character_buffer += characters - - -def parse(what): -    child = greenlet(xml_rpc) -    me = greenlet.getcurrent() -    startup_states = child.switch(me) -    parser = XMLParser(child, startup_states) -    try: -        parseString(what, parser) -    except Malformed: -        print what -        raise -    return child.switch() - - -def xml_rpc(yielder): -    yielder.switch(START.methodcall) -    yielder.switch(START.methodname) -    methodName = yielder.switch(STR) -    yielder.switch(END.methodname) - -    yielder.switch(START.params) - -    root = None -    params = [] -    while True: -        state, _ = yielder.switch(START.param, END.params) -        if state == END: -            break - -        yielder.switch(START.value) -         -        params.append( -            handle(yielder)) - -        yielder.switch(END.value) -        yielder.switch(END.param) - -    yielder.switch(END.methodcall) -    ## Resume parse -    yielder.switch() -    ## Return result to parse -    return methodName.strip(), params - - -def handle(yielder): -    _, (tag, attrs) = yielder.switch(START) -    if tag in ['int', 'i4']: -        result = int(yielder.switch(STR)) -    elif tag == 'boolean': -        result = bool(int(yielder.switch(STR))) -    elif tag == 'string': -        result = yielder.switch(STR) -    elif tag == 'double': -        result = float(yielder.switch(STR)) -    elif tag == 'datetime.iso8601': -        result = yielder.switch(STR) -    elif tag == 'base64': -        result = base64.b64decode(yielder.switch(STR)) -    elif tag == 'struct': -        result = {} -        while True: -            state, _ = yielder.switch(START.member, END.struct) -            if state == END: -                break - -            yielder.switch(START.name) -            key = yielder.switch(STR) -            yielder.switch(END.name) - -            yielder.switch(START.value) -            result[key] = handle(yielder) -            yielder.switch(END.value) - -            yielder.switch(END.member) -        ## We already handled </struct> above, don't want to handle it below -        return result -    elif tag == 'array': -        result = [] -        yielder.switch(START.data) -        while True: -            state, _ = yielder.switch(START.value, END.data) -            if state == END: -                break - -            result.append(handle(yielder)) - -            yielder.switch(END.value) - -    yielder.switch(getattr(END, tag)) - -    return result - - -VALUE = mu.tag_factory('value') -BOOLEAN = mu.tag_factory('boolean') -INT = mu.tag_factory('int') -STRUCT = mu.tag_factory('struct') -MEMBER = mu.tag_factory('member') -NAME = mu.tag_factory('name') -ARRAY = mu.tag_factory('array') -DATA = mu.tag_factory('data') -STRING = mu.tag_factory('string') -DOUBLE = mu.tag_factory('double') -METHODRESPONSE = mu.tag_factory('methodResponse') -PARAMS = mu.tag_factory('params') -PARAM = mu.tag_factory('param') - -mu.inline_elements['string'] = True -mu.inline_elements['boolean'] = True -mu.inline_elements['name'] = True - - -def _generate(something): -    if isinstance(something, dict): -        result = STRUCT() -        for key, value in something.items(): -            result[ -                MEMBER[ -                    NAME[key], _generate(value)]] -        return VALUE[result] -    elif isinstance(something, list): -        result = DATA() -        for item in something: -            result[_generate(item)] -        return VALUE[ARRAY[[result]]] -    elif isinstance(something, basestring): -        return VALUE[STRING[something]] -    elif isinstance(something, bool): -        if something: -            return VALUE[BOOLEAN['1']] -        return VALUE[BOOLEAN['0']] -    elif isinstance(something, int): -        return VALUE[INT[something]] -    elif isinstance(something, float): -        return VALUE[DOUBLE[something]] - -def generate(*args): -    params = PARAMS() -    for arg in args: -        params[PARAM[_generate(arg)]] -    return METHODRESPONSE[params] - - -if __name__ == '__main__': -    print parse("""<?xml version="1.0"?> <methodCall>  <methodName>examples.getStateName</methodName>  <params>  <param>  <value><i4>41</i4></value>  </param>  </params>  </methodCall> -""") -     -         -         -         -         -         -         -         -         diff --git a/indra/lib/python/indra/util/fastest_elementtree.py b/indra/lib/python/indra/util/fastest_elementtree.py deleted file mode 100755 index 4fcf662dd9..0000000000 --- a/indra/lib/python/indra/util/fastest_elementtree.py +++ /dev/null @@ -1,64 +0,0 @@ -"""\ -@file fastest_elementtree.py -@brief Concealing some gnarly import logic in here.  This should export the interface of elementtree. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -# The parsing exception raised by the underlying library depends -# on the ElementTree implementation we're using, so we provide an -# alias here. -# -# Use ElementTreeError as the exception type for catching parsing -# errors. - - -# Using cElementTree might cause some unforeseen problems, so here's a -# convenient off switch. -use_celementree = True - -try: -    if not use_celementree: -        raise ImportError() -    # Python 2.3 and 2.4. -    from cElementTree import * -    ElementTreeError = SyntaxError -except ImportError: -    try: -        if not use_celementree: -            raise ImportError() -        # Python 2.5 and above. -        from xml.etree.cElementTree import * -        ElementTreeError = SyntaxError -    except ImportError: -        # Pure Python code. -        try: -            # Python 2.3 and 2.4. -            from elementtree.ElementTree import * -        except ImportError: -            # Python 2.5 and above. -            from xml.etree.ElementTree import * - -        # The pure Python ElementTree module uses Expat for parsing. -        from xml.parsers.expat import ExpatError as ElementTreeError diff --git a/indra/lib/python/indra/util/helpformatter.py b/indra/lib/python/indra/util/helpformatter.py deleted file mode 100755 index ba5c9b67d1..0000000000 --- a/indra/lib/python/indra/util/helpformatter.py +++ /dev/null @@ -1,52 +0,0 @@ -"""\ -@file helpformatter.py -@author Phoenix -@brief Class for formatting optparse descriptions. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import optparse -import textwrap - -class Formatter(optparse.IndentedHelpFormatter): -    def __init__( -        self,  -        p_indentIncrement = 2,  -        p_maxHelpPosition = 24, -        p_width = 79, -        p_shortFirst = 1) : -        optparse.HelpFormatter.__init__( -            self,  -            p_indentIncrement, -            p_maxHelpPosition,  -            p_width,  -            p_shortFirst) -    def format_description(self, p_description): -        t_descWidth = self.width - self.current_indent -        t_indent = " " * (self.current_indent + 2) -        return "\n".join( -            [textwrap.fill(descr, t_descWidth, initial_indent = t_indent, -                           subsequent_indent = t_indent) -             for descr in p_description.split("\n")] ) diff --git a/indra/lib/python/indra/util/iterators.py b/indra/lib/python/indra/util/iterators.py deleted file mode 100755 index 9013fa6303..0000000000 --- a/indra/lib/python/indra/util/iterators.py +++ /dev/null @@ -1,63 +0,0 @@ -"""\ -@file iterators.py -@brief Useful general-purpose iterators. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from __future__ import nested_scopes - -def iter_chunks(rows, aggregate_size=100): -    """ -    Given an iterable set of items (@p rows), produces lists of up to @p -    aggregate_size items at a time, for example: -     -    iter_chunks([1,2,3,4,5,6,7,8,9,10], 3) - -    Values for @p aggregate_size < 1 will raise ValueError. - -    Will return a generator that produces, in the following order: -    - [1, 2, 3] -    - [4, 5, 6] -    - [7, 8, 9] -    - [10] -    """ -    if aggregate_size < 1: -        raise ValueError() - -    def iter_chunks_inner(): -        row_iter = iter(rows) -        done = False -        agg = [] -        while not done: -            try: -                row = row_iter.next() -                agg.append(row) -            except StopIteration: -                done = True -            if agg and (len(agg) >= aggregate_size or done): -                yield agg -                agg = [] -     -    return iter_chunks_inner() diff --git a/indra/lib/python/indra/util/iterators_test.py b/indra/lib/python/indra/util/iterators_test.py deleted file mode 100755 index 66928c8e7d..0000000000 --- a/indra/lib/python/indra/util/iterators_test.py +++ /dev/null @@ -1,72 +0,0 @@ -"""\ -@file iterators_test.py -@brief Test cases for iterators module. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import unittest - -from indra.util.iterators import iter_chunks - -class TestIterChunks(unittest.TestCase): -    """Unittests for iter_chunks""" -    def test_bad_agg_size(self): -        rows = [1,2,3,4] -        self.assertRaises(ValueError, iter_chunks, rows, 0) -        self.assertRaises(ValueError, iter_chunks, rows, -1) - -        try: -            for i in iter_chunks(rows, 0): -                pass -        except ValueError: -            pass -        else: -            self.fail() -         -        try: -            result = list(iter_chunks(rows, 0)) -        except ValueError: -            pass -        else: -            self.fail() -    def test_empty(self): -        rows = [] -        result = list(iter_chunks(rows)) -        self.assertEqual(result, []) -    def test_small(self): -        rows = [[1]] -        result = list(iter_chunks(rows, 2)) -        self.assertEqual(result, [[[1]]]) -    def test_size(self): -        rows = [[1],[2]] -        result = list(iter_chunks(rows, 2)) -        self.assertEqual(result, [[[1],[2]]]) -    def test_multi_agg(self): -        rows = [[1],[2],[3],[4],[5]] -        result = list(iter_chunks(rows, 2)) -        self.assertEqual(result, [[[1],[2]],[[3],[4]],[[5]]]) - -if __name__ == "__main__": -    unittest.main() diff --git a/indra/lib/python/indra/util/llperformance.py b/indra/lib/python/indra/util/llperformance.py deleted file mode 100755 index 57dd64de3f..0000000000 --- a/indra/lib/python/indra/util/llperformance.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python -"""\ -@file   llperformance.py - -$LicenseInfo:firstyear=2010&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2010-2011, 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$ -""" - -# ------------------------------------------------ -# Sim metrics utility functions. - -import glob, os, time, sys, stat, exceptions - -from indra.base import llsd - -gBlockMap = {}              #Map of performance metric data with function hierarchy information. -gCurrentStatPath = "" - -gIsLoggingEnabled=False - -class LLPerfStat: -    def __init__(self,key): -        self.mTotalTime = 0 -        self.mNumRuns = 0 -        self.mName=key -        self.mTimeStamp = int(time.time()*1000) -        self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) - -    def __str__(self): -        return "%f" %  self.mTotalTime - -    def start(self): -        self.mStartTime = int(time.time() * 1000000) -        self.mNumRuns += 1 - -    def stop(self): -        execution_time = int(time.time() * 1000000) - self.mStartTime -        self.mTotalTime += execution_time - -    def get_map(self): -        results={} -        results['name']=self.mName -        results['utc_time']=self.mUTCTime -        results['timestamp']=self.mTimeStamp -        results['us']=self.mTotalTime -        results['count']=self.mNumRuns -        return results - -class PerfError(exceptions.Exception): -    def __init__(self): -        return - -    def __Str__(self): -        print "","Unfinished LLPerfBlock" - -class LLPerfBlock: -    def __init__( self, key ): -        global gBlockMap -        global gCurrentStatPath -        global gIsLoggingEnabled - -        #Check to see if we're running metrics right now. -        if gIsLoggingEnabled: -            self.mRunning = True        #Mark myself as running. -     -            self.mPreviousStatPath = gCurrentStatPath -            gCurrentStatPath += "/" + key -            if gCurrentStatPath not in gBlockMap: -                gBlockMap[gCurrentStatPath] = LLPerfStat(key) - -            self.mStat = gBlockMap[gCurrentStatPath] -            self.mStat.start() -     -    def finish( self ): -        global gBlockMap -        global gIsLoggingEnabled - -        if gIsLoggingEnabled: -            self.mStat.stop() -            self.mRunning = False -            gCurrentStatPath = self.mPreviousStatPath - -#    def __del__( self ): -#        if self.mRunning: -#            #SPATTERS FIXME -#            raise PerfError - -class LLPerformance: -    #-------------------------------------------------- -    # Determine whether or not we want to log statistics - -    def __init__( self, process_name = "python" ): -        self.process_name = process_name -        self.init_testing() -        self.mTimeStamp = int(time.time()*1000) -        self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) - -    def init_testing( self ): -        global gIsLoggingEnabled - -        host_performance_file = "/dev/shm/simperf/simperf_proc_config.llsd" -     -        #If file exists, open -        if os.path.exists(host_performance_file): -            file = open (host_performance_file,'r') -     -            #Read serialized LLSD from file. -            body = llsd.parse(file.read()) -     -            #Calculate time since file last modified. -            stats = os.stat(host_performance_file) -            now = time.time() -            mod = stats[stat.ST_MTIME] -            age = now - mod -     -            if age < ( body['duration'] ): -                gIsLoggingEnabled = True -     - -    def get ( self ): -        global gIsLoggingEnabled -        return gIsLoggingEnabled - -    #def output(self,ptr,path): -    #    if 'stats' in ptr: -    #        stats = ptr['stats'] -    #        self.mOutputPtr[path] = stats.get_map() - -    #    if 'children' in ptr: -    #        children=ptr['children'] - -    #        curptr = self.mOutputPtr -    #        curchildren={} -    #        curptr['children'] = curchildren - -    #        for key in children: -    #            curchildren[key]={} -    #            self.mOutputPtr = curchildren[key] -    #            self.output(children[key],path + '/' + key) -     -    def done(self): -        global gBlockMap - -        if not self.get(): -            return - -        output_name = "/dev/shm/simperf/%s_proc.%d.llsd" % (self.process_name, os.getpid()) -        output_file = open(output_name, 'w') -        process_info = { -            "name"  :   self.process_name, -            "pid"   :   os.getpid(), -            "ppid"  :   os.getppid(), -            "timestamp" :   self.mTimeStamp, -            "utc_time"  :   self.mUTCTime, -            } -        output_file.write(llsd.format_notation(process_info)) -        output_file.write('\n') - -        for key in gBlockMap.keys(): -            gBlockMap[key] = gBlockMap[key].get_map() -        output_file.write(llsd.format_notation(gBlockMap)) -        output_file.write('\n') -        output_file.close() - diff --git a/indra/lib/python/indra/util/llsubprocess.py b/indra/lib/python/indra/util/llsubprocess.py deleted file mode 100755 index 7e0e115d14..0000000000 --- a/indra/lib/python/indra/util/llsubprocess.py +++ /dev/null @@ -1,117 +0,0 @@ -"""\ -@file llsubprocess.py -@author Phoenix -@date 2008-01-18 -@brief The simplest possible wrapper for a common sub-process paradigm. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import os -import popen2 -import time -import select - -class Timeout(RuntimeError): -    "Exception raised when a subprocess times out." -    pass - -def run(command, args=None, data=None, timeout=None): -    """\ -@brief Run command with arguments - -This is it. This is the function I want to run all the time when doing -subprocces, but end up copying the code everywhere. none of the -standard commands are secure and provide a way to specify input, get -all the output, and get the result. -@param command A string specifying a process to launch. -@param args Arguments to be passed to command. Must be list, tuple or None. -@param data input to feed to the command. -@param timeout Maximum number of many seconds to run. -@return Returns (result, stdout, stderr) from process. -""" -    cmd = [command] -    if args: -        cmd.extend([str(arg) for arg in args]) -    #print  "cmd: ","' '".join(cmd) -    child = popen2.Popen3(cmd, True) -    #print child.pid -    out = [] -    err = [] -    result = -1 -    time_left = timeout -    tochild = [child.tochild.fileno()] -    while True: -        time_start = time.time() -        #print "time:",time_left -        p_in, p_out, p_err = select.select( -            [child.fromchild.fileno(), child.childerr.fileno()], -            tochild, -            [], -            time_left) -        if p_in: -            new_line = os.read(child.fromchild.fileno(), 32 * 1024) -            if new_line: -                #print "line:",new_line -                out.append(new_line) -            new_line = os.read(child.childerr.fileno(), 32 * 1024) -            if new_line: -                #print "error:", new_line -                err.append(new_line) -        if p_out: -            if data: -                #print "p_out" -                bytes = os.write(child.tochild.fileno(), data) -                data = data[bytes:] -                if len(data) == 0: -                    data = None -                    tochild = [] -                    child.tochild.close() -        result = child.poll() -        if result != -1: -            # At this point, the child process has exited and result -            # is the return value from the process. Between the time -            # we called select() and poll() the process may have -            # exited so read all the data left on the child process -            # stdout and stderr. -            last = child.fromchild.read() -            if last: -                out.append(last) -            last = child.childerr.read() -            if last: -                err.append(last) -            child.tochild.close() -            child.fromchild.close() -            child.childerr.close() -            break -        if time_left is not None: -            time_left -= (time.time() - time_start) -            if time_left < 0: -                raise Timeout -    #print "result:",result -    out = ''.join(out) -    #print "stdout:", out -    err = ''.join(err) -    #print "stderr:", err -    return result, out, err diff --git a/indra/lib/python/indra/util/named_query.py b/indra/lib/python/indra/util/named_query.py deleted file mode 100755 index 6bf956107d..0000000000 --- a/indra/lib/python/indra/util/named_query.py +++ /dev/null @@ -1,592 +0,0 @@ -"""\ -@file named_query.py -@author Ryan Williams, Phoenix -@date 2007-07-31 -@brief An API for running named queries. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import errno -import MySQLdb -import MySQLdb.cursors -import os -import os.path -import re -import time - -from indra.base import llsd -from indra.base import config - -DEBUG = False -NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq') -NQ_FILE_SUFFIX_LEN  = len(NQ_FILE_SUFFIX) - -_g_named_manager = None - -def _init_g_named_manager(sql_dir = None): -    """Initializes a global NamedManager object to point at a -    specified named queries hierarchy. - -    This function is intended entirely for testing purposes, -    because it's tricky to control the config from inside a test.""" -    global NQ_FILE_SUFFIX -    NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq') -    global NQ_FILE_SUFFIX_LEN -    NQ_FILE_SUFFIX_LEN  = len(NQ_FILE_SUFFIX) - -    if sql_dir is None: -        sql_dir = config.get('named-query-base-dir') - -    # extra fallback directory in case config doesn't return what we want -    if sql_dir is None: -        sql_dir = os.path.abspath( -            os.path.join( -            os.path.realpath(os.path.dirname(__file__)), "..", "..", "..", "..", "web", "dataservice", "sql")) - -    global _g_named_manager -    _g_named_manager = NamedQueryManager( -        os.path.abspath(os.path.realpath(sql_dir))) - -def get(name, schema = None): -    "Get the named query object to be used to perform queries" -    if _g_named_manager is None: -        _init_g_named_manager() -    return _g_named_manager.get(name).for_schema(schema) - -def sql(connection, name, params): -    # use module-global NamedQuery object to perform default substitution -    return get(name).sql(connection, params) - -def run(connection, name, params, expect_rows = None): -    """\ -@brief given a connection, run a named query with the params - -Note that this function will fetch ALL rows. -@param connection The connection to use -@param name The name of the query to run -@param params The parameters passed into the query -@param expect_rows The number of rows expected. Set to 1 if return_as_map is true.  Raises ExpectationFailed if the number of returned rows doesn't exactly match.  Kind of a hack. -@return Returns the result set as a list of dicts. -""" -    return get(name).run(connection, params, expect_rows) - -class ExpectationFailed(Exception): -    """ Exception that is raised when an expectation for an sql query -    is not met.""" -    def __init__(self, message): -        Exception.__init__(self, message) -        self.message = message - -class NamedQuery(object): -    def __init__(self, name, filename): -        """ Construct a NamedQuery object.  The name argument is an -        arbitrary name as a handle for the query, and the filename is -        a path to a file or a file-like object containing an llsd named -        query document.""" -        self._stat_interval_seconds = 5  # 5 seconds -        self._name = name -        if (filename is not None and isinstance(filename, (str, unicode)) -            and NQ_FILE_SUFFIX != filename[-NQ_FILE_SUFFIX_LEN:]): -            filename = filename + NQ_FILE_SUFFIX -        self._location = filename -        self._alternative = dict() -        self._last_mod_time = 0 -        self._last_check_time = 0 -        self.deleted = False -        self.load_contents() - -    def name(self): -        """ The name of the query. """ -        return self._name - -    def get_modtime(self): -        """ Returns the mtime (last modified time) of the named query -        filename. For file-like objects, expect a modtime of 0""" -        if self._location and isinstance(self._location, (str, unicode)): -            return os.path.getmtime(self._location) -        return 0 - -    def load_contents(self): -        """ Loads and parses the named query file into self.  Does -        nothing if self.location is nonexistant.""" -        if self._location: -            if isinstance(self._location, (str, unicode)): -                contents = llsd.parse(open(self._location).read()) -            else: -                # we probably have a file-like object. Godspeed! -                contents = llsd.parse(self._location.read()) -            self._reference_contents(contents) -            # Check for alternative implementations -            try: -                for name, alt in self._contents['alternative'].items(): -                    nq = NamedQuery(name, None) -                    nq._reference_contents(alt) -                    self._alternative[name] = nq -            except KeyError, e: -                pass -            self._last_mod_time = self.get_modtime() -            self._last_check_time = time.time() - -    def _reference_contents(self, contents): -        "Helper method which builds internal structure from parsed contents" -        self._contents = contents -        self._ttl = int(self._contents.get('ttl', 0)) -        self._return_as_map = bool(self._contents.get('return_as_map', False)) -        self._legacy_dbname = self._contents.get('legacy_dbname', None) - -        # reset these before doing the sql conversion because we will -        # read them there. reset these while loading so we pick up -        # changes. -        self._around = set() -        self._append = set() -        self._integer = set() -        self._options = self._contents.get('dynamic_where', {}) -        for key in self._options: -            if isinstance(self._options[key], basestring): -                self._options[key] = self._convert_sql(self._options[key]) -            elif isinstance(self._options[key], list): -                lines = [] -                for line in self._options[key]: -                    lines.append(self._convert_sql(line)) -                self._options[key] = lines -            else: -                moreopt = {} -                for kk in self._options[key]: -                    moreopt[kk] = self._convert_sql(self._options[key][kk])  -                self._options[key] = moreopt -        self._base_query = self._convert_sql(self._contents['base_query']) -        self._query_suffix = self._convert_sql( -            self._contents.get('query_suffix', '')) - -    def _convert_sql(self, sql): -        """convert the parsed sql into a useful internal structure. - -        This function has to turn the named query format into a pyformat -        style. It also has to look for %:name% and :name% and -        ready them for use in LIKE statements""" -        if sql: -            # This first sub is to properly escape any % signs that -            # are meant to be literally passed through to mysql in the -            # query.  It leaves any %'s that are used for -            # like-expressions. -            expr = re.compile("(?<=[^a-zA-Z0-9_-])%(?=[^:])") -            sql = expr.sub('%%', sql) - -            # This should tackle the rest of the %'s in the query, by -            # converting them to LIKE clauses. -            expr = re.compile("(%?):([a-zA-Z][a-zA-Z0-9_-]*)%") -            sql = expr.sub(self._prepare_like, sql) -            expr = re.compile("#:([a-zA-Z][a-zA-Z0-9_-]*)") -            sql = expr.sub(self._prepare_integer, sql) -            expr = re.compile(":([a-zA-Z][a-zA-Z0-9_-]*)") -            sql = expr.sub("%(\\1)s", sql) -        return sql - -    def _prepare_like(self, match): -        """This function changes LIKE statement replace behavior - -        It works by turning %:name% to %(_name_around)s and :name% to -        %(_name_append)s. Since a leading '_' is not a valid keyname -        input (enforced via unit tests), it will never clash with -        existing keys. Then, when building the statement, the query -        runner will generate corrected strings.""" -        if match.group(1) == '%': -            # there is a leading % so this is treated as prefix/suffix -            self._around.add(match.group(2)) -            return "%(" + self._build_around_key(match.group(2)) + ")s" -        else: -            # there is no leading %, so this is suffix only -            self._append.add(match.group(2)) -            return "%(" + self._build_append_key(match.group(2)) + ")s" - -    def _build_around_key(self, key): -        return "_" + key + "_around" - -    def _build_append_key(self, key): -        return "_" + key + "_append" - -    def _prepare_integer(self, match): -        """This function adjusts the sql for #:name replacements - -        It works by turning #:name to %(_name_as_integer)s. Since a -        leading '_' is not a valid keyname input (enforced via unit -        tests), it will never clash with existing keys. Then, when -        building the statement, the query runner will generate -        corrected strings.""" -        self._integer.add(match.group(1)) -        return "%(" + self._build_integer_key(match.group(1)) + ")s" - -    def _build_integer_key(self, key): -        return "_" + key + "_as_integer" - -    def _strip_wildcards_to_list(self, value): -        """Take string, and strip out the LIKE special characters. - -        Technically, this is database dependant, but postgresql and -        mysql use the same wildcards, and I am not aware of a general -        way to handle this. I think you need a sql statement of the -        form: - -        LIKE_STRING( [ANY,ONE,str]... ) - -        which would treat ANY as their any string, and ONE as their -        single glyph, and str as something that needs database -        specific encoding to not allow any % or _ to affect the query. - -        As it stands, I believe it's impossible to write a named query -        style interface which uses like to search the entire space of -        text available. Imagine the query: - -        % of brain used by average linden - -        In order to search for %, it must be escaped, so once you have -        escaped the string to not do wildcard searches, and be escaped -        for the database, and then prepended the wildcard you come -        back with one of: - -        1) %\% of brain used by average linden -        2) %%% of brain used by average linden - -        Then, when passed to the database to be escaped to be database -        safe, you get back: -         -        1) %\\% of brain used by average linden -        : which means search for any character sequence, followed by a -          backslash, followed by any sequence, followed by ' of -          brain...' -        2) %%% of brain used by average linden -        : which (I believe) means search for a % followed by any -          character sequence followed by 'of brain...' - -        Neither of which is what we want! - -        So, we need a vendor (or extention) for LIKE_STRING. Anyone -        want to write it?""" -        if isinstance(value, unicode): -            utf8_value = value -        else: -            utf8_value = unicode(value, "utf-8") -        esc_list = [] -        remove_chars = set(u"%_") -        for glyph in utf8_value: -            if glyph in remove_chars: -                continue -            esc_list.append(glyph.encode("utf-8")) -        return esc_list - -    def delete(self): -        """ Makes this query unusable by deleting all the members and -        setting the deleted member.  This is desired when the on-disk -        query has been deleted but the in-memory copy remains.""" -        # blow away all members except _name, _location, and deleted -        name, location = self._name, self._location -        for key in self.__dict__.keys(): -            del self.__dict__[key] -        self.deleted = True -        self._name, self._location = name, location - -    def ttl(self): -        """ Estimated time to live of this query. Used for web -        services to set the Expires header.""" -        return self._ttl - -    def legacy_dbname(self): -        return self._legacy_dbname - -    def return_as_map(self): -        """ Returns true if this query is configured to return its -        results as a single map (as opposed to a list of maps, the -        normal behavior).""" -         -        return self._return_as_map - -    def for_schema(self, db_name): -        "Look trough the alternates and return the correct query" -        if db_name is None: -            return self -        try: -            return self._alternative[db_name] -        except KeyError, e: -            pass -        return self - -    def run(self, connection, params, expect_rows = None, use_dictcursor = True): -        """given a connection, run a named query with the params - -        Note that this function will fetch ALL rows. We do this because it -        opens and closes the cursor to generate the values, and this  -        isn't a generator so the cursor has no life beyond the method call. - -        @param cursor The connection to use (this generates its own cursor for the query) -        @param name The name of the query to run -        @param params The parameters passed into the query -        @param expect_rows The number of rows expected. Set to 1 if return_as_map is true.  Raises ExpectationFailed if the number of returned rows doesn't exactly match.  Kind of a hack. -        @param use_dictcursor Set to false to use a normal cursor and manually convert the rows to dicts. -        @return Returns the result set as a list of dicts, or, if the named query has return_as_map set to true, returns a single dict. -        """ -        if use_dictcursor: -            cursor = connection.cursor(MySQLdb.cursors.DictCursor) -        else: -            cursor = connection.cursor() - -        full_query, params = self._construct_sql(params) -        if DEBUG: -            print "SQL:", self.sql(connection, params) -        rows = cursor.execute(full_query, params) - -        # *NOTE: the expect_rows argument is a very cheesy way to get some -        # validation on the result set.  If you want to add more expectation -        # logic, do something more object-oriented and flexible. Or use an ORM. -        if(self._return_as_map): -            expect_rows = 1 -        if expect_rows is not None and rows != expect_rows: -            cursor.close() -            raise ExpectationFailed("Statement expected %s rows, got %s.  Sql: '%s' %s" % ( -                expect_rows, rows, full_query, params)) - -        # convert to dicts manually if we're not using a dictcursor -        if use_dictcursor: -            result_set = cursor.fetchall() -        else: -            if cursor.description is None: -                # an insert or something -                x = cursor.fetchall() -                cursor.close() -                return x - -            names = [x[0] for x in cursor.description] - -            result_set = [] -            for row in cursor.fetchall(): -                converted_row = {} -                for idx, col_name in enumerate(names): -                    converted_row[col_name] = row[idx] -                result_set.append(converted_row) - -        cursor.close() -        if self._return_as_map: -            return result_set[0] -        return result_set - -    def _construct_sql(self, params): -        """ Returns a query string and a dictionary of parameters, -        suitable for directly passing to the execute() method.""" -        self.refresh() - -        # build the query from the options available and the params -        base_query = [] -        base_query.append(self._base_query) -        for opt, extra_where in self._options.items(): -            if type(extra_where) in (dict, list, tuple): -                if opt in params: -                    base_query.append(extra_where[params[opt]]) -            else: -                if opt in params and params[opt]: -                    base_query.append(extra_where) -        if self._query_suffix: -            base_query.append(self._query_suffix) -        full_query = '\n'.join(base_query) - -        # Go through the query and rewrite all of the ones with the -        # @:name syntax. -        rewrite = _RewriteQueryForArray(params) -        expr = re.compile("@%\(([a-zA-Z][a-zA-Z0-9_-]*)\)s") -        full_query = expr.sub(rewrite.operate, full_query) -        params.update(rewrite.new_params) - -        # build out the params for like. We only have to do this -        # parameters which were detected to have ued the where syntax -        # during load. -        # -        # * treat the incoming string as utf-8 -        # * strip wildcards -        # * append or prepend % as appropriate -        new_params = {} -        for key in params: -            if key in self._around: -                new_value = ['%'] -                new_value.extend(self._strip_wildcards_to_list(params[key])) -                new_value.append('%') -                new_params[self._build_around_key(key)] = ''.join(new_value) -            if key in self._append: -                new_value = self._strip_wildcards_to_list(params[key]) -                new_value.append('%') -                new_params[self._build_append_key(key)] = ''.join(new_value) -            if key in self._integer: -                new_params[self._build_integer_key(key)] = int(params[key]) -        params.update(new_params) - -        return full_query, params - -    def sql(self, connection, params): -        """ Generates an SQL statement from the named query document -        and a dictionary of parameters. - -        *NOTE: Only use for debugging, because it uses the -         non-standard MySQLdb 'literal' method. -        """ -        if not DEBUG: -            import warnings -            warnings.warn("Don't use named_query.sql() when not debugging.  Used on %s" % self._location) -        # do substitution using the mysql (non-standard) 'literal' -        # function to do the escaping. -        full_query, params = self._construct_sql(params) -        return full_query % connection.literal(params) -         - -    def refresh(self): -        """ Refresh self from the file on the filesystem. - -        This is optimized to be callable as frequently as you wish, -        without adding too much load.  It does so by only stat-ing the -        file every N seconds, where N defaults to 5 and is -        configurable through the member _stat_interval_seconds.  If the stat -        reveals that the file has changed, refresh will re-parse the -        contents of the file and use them to update the named query -        instance.  If the stat reveals that the file has been deleted, -        refresh will call self.delete to make the in-memory -        representation unusable.""" -        now = time.time() -        if(now - self._last_check_time > self._stat_interval_seconds): -            self._last_check_time = now -            try: -                modtime = self.get_modtime() -                if(modtime > self._last_mod_time): -                    self.load_contents() -            except OSError, e: -                if e.errno == errno.ENOENT: # file not found -                    self.delete() # clean up self -                raise  # pass the exception along to the caller so they know that this query disappeared - -class NamedQueryManager(object): -    """ Manages the lifespan of NamedQuery objects, drawing from a -    directory hierarchy of named query documents. - -    In practice this amounts to a memory cache of NamedQuery objects.""" -     -    def __init__(self, named_queries_dir): -        """ Initializes a manager to look for named queries in a -        directory.""" -        self._dir = os.path.abspath(os.path.realpath(named_queries_dir)) -        self._cached_queries = {} - -    def sql(self, connection, name, params): -        nq = self.get(name) -        return nq.sql(connection, params) -         -    def get(self, name): -        """ Returns a NamedQuery instance based on the name, either -        from memory cache, or by parsing from disk. - -        The name is simply a relative path to the directory associated -        with the manager object.  Before returning the instance, the -        NamedQuery object is cached in memory, so that subsequent -        accesses don't have to read from disk or do any parsing.  This -        means that NamedQuery objects returned by this method are -        shared across all users of the manager object. -        NamedQuery.refresh is used to bring the NamedQuery objects in -        sync with the actual files on disk.""" -        nq = self._cached_queries.get(name) -        if nq is None: -            nq = NamedQuery(name, os.path.join(self._dir, name)) -            self._cached_queries[name] = nq -        else: -            try: -                nq.refresh() -            except OSError, e: -                if e.errno == errno.ENOENT: # file not found -                    del self._cached_queries[name] -                raise # pass exception along to caller so they know that the query disappeared - -        return nq - -class _RewriteQueryForArray(object): -    "Helper class for rewriting queries with the @:name syntax" -    def __init__(self, params): -        self.params = params -        self.new_params = dict() - -    def operate(self, match): -        "Given a match, return the string that should be in use" -        key = match.group(1) -        value = self.params[key] -        if type(value) in (list,tuple): -            rv = [] -            for idx in range(len(value)): -                # if the value@idx is array-like, we are -                # probably dealing with a VALUES -                new_key = "_%s_%s"%(key, str(idx)) -                val_item = value[idx] -                if type(val_item) in (list, tuple, dict): -                    if type(val_item) is dict: -                        # this is because in Python, the order of  -                        # key, value retrieval from the dict is not -                        # guaranteed to match what the input intended -                        # and for VALUES, order is important. -                        # TODO: Implemented ordered dict in LLSD parser? -                        raise ExpectationFailed('Only lists/tuples allowed,\ -                                received dict') -                    values_keys = [] -                    for value_idx, item in enumerate(val_item): -                        # we want a key of the format : -                        # key_#replacement_#value_row_#value_col -                        # ugh... so if we are replacing 10 rows in user_note,  -                        # the first values clause would read (for @:user_notes) :- -                        # ( :_user_notes_0_1_1,  :_user_notes_0_1_2, :_user_notes_0_1_3 ) -                        # the input LLSD for VALUES will look like: -                        # <llsd>... -                        # <map> -                        #  <key>user_notes</key> -                        #      <array> -                        #      <array> <!-- row 1 for VALUES --> -                        #          <string>...</string> -                        #          <string>...</string> -                        #          <string>...</string> -                        #      </array> -                        # ... -                        #      </array> -                        # </map> -                        # ... </llsd> -                        values_key = "%s_%s"%(new_key, value_idx) -                        self.new_params[values_key] = item -                        values_keys.append("%%(%s)s"%values_key) -                    # now collapse all these new place holders enclosed in () -                    # from [':_key_0_1_1', ':_key_0_1_2', ':_key_0_1_3,...]  -                    # rv will have [ '(:_key_0_1_1, :_key_0_1_2, :_key_0_1_3)', ] -                    # which is flattened a few lines below join(rv) -                    rv.append('(%s)' % ','.join(values_keys)) -                else: -                    self.new_params[new_key] = val_item -                    rv.append("%%(%s)s"%new_key) -            return ','.join(rv) -        else: -            # not something that can be expanded, so just drop the -            # leading @ in the front of the match. This will mean that -            # the single value we have, be it a string, int, whatever -            # (other than dict) will correctly show up, eg: -            # -            # where foo in (@:foobar) -- foobar is a string, so we get -            # where foo in (:foobar) -            return match.group(0)[1:] diff --git a/indra/lib/python/indra/util/shutil2.py b/indra/lib/python/indra/util/shutil2.py deleted file mode 100755 index 9e2e7a6ded..0000000000 --- a/indra/lib/python/indra/util/shutil2.py +++ /dev/null @@ -1,84 +0,0 @@ -''' -@file shutil2.py -@brief a better shutil.copytree replacement - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -''' - -# -# shutil2.py -# Taken from http://www.scons.org/wiki/AccumulateBuilder -# the stock copytree sucks because it insists that the -# target dir not exist -# - -import os.path -import shutil - -def copytree(src, dest, symlinks=False): -    """My own copyTree which does not fail if the directory exists. -     -    Recursively copy a directory tree using copy2(). - -    If the optional symlinks flag is true, symbolic links in the -    source tree result in symbolic links in the destination tree; if -    it is false, the contents of the files pointed to by symbolic -    links are copied. -     -    Behavior is meant to be identical to GNU 'cp -R'.     -    """ -    def copyItems(src, dest, symlinks=False): -        """Function that does all the work. -         -        It is necessary to handle the two 'cp' cases: -        - destination does exist -        - destination does not exist -         -        See 'cp -R' documentation for more details -        """ -        for item in os.listdir(src): -           srcPath = os.path.join(src, item) -           if os.path.isdir(srcPath): -               srcBasename = os.path.basename(srcPath) -               destDirPath = os.path.join(dest, srcBasename) -               if not os.path.exists(destDirPath): -                   os.makedirs(destDirPath) -               copyItems(srcPath, destDirPath) -           elif os.path.islink(item) and symlinks: -               linkto = os.readlink(item) -               os.symlink(linkto, dest) -           else: -               shutil.copy2(srcPath, dest) - -    # case 'cp -R src/ dest/' where dest/ already exists -    if os.path.exists(dest): -       destPath = os.path.join(dest, os.path.basename(src)) -       if not os.path.exists(destPath): -           os.makedirs(destPath) -    # case 'cp -R src/ dest/' where dest/ does not exist -    else: -       os.makedirs(dest) -       destPath = dest -    # actually copy the files -    copyItems(src, destPath) diff --git a/indra/lib/python/indra/util/simperf_host_xml_parser.py b/indra/lib/python/indra/util/simperf_host_xml_parser.py deleted file mode 100755 index 672c1050c2..0000000000 --- a/indra/lib/python/indra/util/simperf_host_xml_parser.py +++ /dev/null @@ -1,338 +0,0 @@ -#!/usr/bin/env python -"""\ -@file simperf_host_xml_parser.py -@brief Digest collector's XML dump and convert to simple dict/list structure - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys, os, getopt, time -import simplejson -from xml import sax - - -def usage(): -    print "Usage:" -    print sys.argv[0] + " [options]" -    print "  Convert RRD's XML dump to JSON.  Script to convert the simperf_host_collector-" -    print "  generated RRD dump into JSON.  Steps include converting selected named" -    print "  fields from GAUGE type to COUNTER type by computing delta with preceding" -    print "  values.  Top-level named fields are:" -    print  -    print "     lastupdate      Time (javascript timestamp) of last data sample" -    print "     step            Time in seconds between samples" -    print "     ds              Data specification (name/type) for each column" -    print "     database        Table of data samples, one time step per row" -    print  -    print "Options:" -    print "  -i, --in      Input settings filename.  (Default:  stdin)" -    print "  -o, --out     Output settings filename.  (Default:  stdout)" -    print "  -h, --help    Print this message and exit." -    print -    print "Example: %s -i rrddump.xml -o rrddump.json" % sys.argv[0] -    print -    print "Interfaces:" -    print "   class SimPerfHostXMLParser()         # SAX content handler" -    print "   def simperf_host_xml_fixup(parser)   # post-parse value fixup" - -class SimPerfHostXMLParser(sax.handler.ContentHandler): - -    def __init__(self): -        pass -         -    def startDocument(self): -        self.rrd_last_update = 0         # public -        self.rrd_step = 0                # public -        self.rrd_ds = []                 # public -        self.rrd_records = []            # public -        self._rrd_level = 0 -        self._rrd_parse_state = 0 -        self._rrd_chars = "" -        self._rrd_capture = False -        self._rrd_ds_val = {} -        self._rrd_data_row = [] -        self._rrd_data_row_has_nan = False -         -    def endDocument(self): -        pass - -    # Nasty little ad-hoc state machine to extract the elements that are -    # necessary from the 'rrdtool dump' XML output.  The same element -    # name '<ds>' is used for two different data sets so we need to pay -    # some attention to the actual structure to get the ones we want -    # and ignore the ones we don't. -     -    def startElement(self, name, attrs): -        self._rrd_level = self._rrd_level + 1 -        self._rrd_capture = False -        if self._rrd_level == 1: -            if name == "rrd" and self._rrd_parse_state == 0: -                self._rrd_parse_state = 1     # In <rrd> -                self._rrd_capture = True -                self._rrd_chars = "" -        elif self._rrd_level == 2: -            if self._rrd_parse_state == 1: -                if name == "lastupdate": -                    self._rrd_parse_state = 2         # In <rrd><lastupdate> -                    self._rrd_capture = True -                    self._rrd_chars = "" -                elif name == "step": -                    self._rrd_parse_state = 3         # In <rrd><step> -                    self._rrd_capture = True -                    self._rrd_chars = "" -                elif name == "ds": -                    self._rrd_parse_state = 4         # In <rrd><ds> -                    self._rrd_ds_val = {} -                    self._rrd_chars = "" -                elif name == "rra": -                    self._rrd_parse_state = 5         # In <rrd><rra> -        elif self._rrd_level == 3: -            if self._rrd_parse_state == 4: -                if name == "name": -                    self._rrd_parse_state = 6         # In <rrd><ds><name> -                    self._rrd_capture = True -                    self._rrd_chars = "" -                elif name == "type": -                    self._rrd_parse_state = 7         # In <rrd><ds><type> -                    self._rrd_capture = True -                    self._rrd_chars = "" -            elif self._rrd_parse_state == 5: -                if name == "database": -                    self._rrd_parse_state = 8         # In <rrd><rra><database> -        elif self._rrd_level == 4: -            if self._rrd_parse_state == 8: -                if name == "row": -                    self._rrd_parse_state = 9         # In <rrd><rra><database><row> -                    self._rrd_data_row = [] -                    self._rrd_data_row_has_nan = False -        elif self._rrd_level == 5: -            if self._rrd_parse_state == 9: -                if name == "v": -                    self._rrd_parse_state = 10        # In <rrd><rra><database><row><v> -                    self._rrd_capture = True -                    self._rrd_chars = "" - -    def endElement(self, name): -        self._rrd_capture = False -        if self._rrd_parse_state == 10: -            self._rrd_capture = self._rrd_level == 6 -            if self._rrd_level == 5: -                if self._rrd_chars == "NaN": -                    self._rrd_data_row_has_nan = True -                else: -                    self._rrd_data_row.append(self._rrd_chars) -                self._rrd_parse_state = 9              # In <rrd><rra><database><row> -        elif self._rrd_parse_state == 9: -            if self._rrd_level == 4: -                if not self._rrd_data_row_has_nan: -                    self.rrd_records.append(self._rrd_data_row) -                self._rrd_parse_state = 8              # In <rrd><rra><database> -        elif self._rrd_parse_state == 8: -            if self._rrd_level == 3: -                self._rrd_parse_state = 5              # In <rrd><rra> -        elif self._rrd_parse_state == 7: -            if self._rrd_level == 3: -                self._rrd_ds_val["type"] = self._rrd_chars -                self._rrd_parse_state = 4              # In <rrd><ds> -        elif self._rrd_parse_state == 6: -            if self._rrd_level == 3: -                self._rrd_ds_val["name"] = self._rrd_chars -                self._rrd_parse_state = 4              # In <rrd><ds> -        elif self._rrd_parse_state == 5: -            if self._rrd_level == 2: -                self._rrd_parse_state = 1              # In <rrd> -        elif self._rrd_parse_state == 4: -            if self._rrd_level == 2: -                self.rrd_ds.append(self._rrd_ds_val) -                self._rrd_parse_state = 1              # In <rrd> -        elif self._rrd_parse_state == 3: -            if self._rrd_level == 2: -                self.rrd_step = long(self._rrd_chars) -                self._rrd_parse_state = 1              # In <rrd> -        elif self._rrd_parse_state == 2: -            if self._rrd_level == 2: -                self.rrd_last_update = long(self._rrd_chars) -                self._rrd_parse_state = 1              # In <rrd> -        elif self._rrd_parse_state == 1: -            if self._rrd_level == 1: -                self._rrd_parse_state = 0              # At top -                 -        if self._rrd_level: -            self._rrd_level = self._rrd_level - 1 - -    def characters(self, content): -        if self._rrd_capture: -            self._rrd_chars = self._rrd_chars + content.strip() - -def _make_numeric(value): -    try: -        value = float(value) -    except: -        value = "" -    return value - -def simperf_host_xml_fixup(parser, filter_start_time = None, filter_end_time = None): -    # Fixup for GAUGE fields that are really COUNTS.  They -    # were forced to GAUGE to try to disable rrdtool's -    # data interpolation/extrapolation for non-uniform time -    # samples. -    fixup_tags = [ "cpu_user", -                   "cpu_nice", -                   "cpu_sys", -                   "cpu_idle", -                   "cpu_waitio", -                   "cpu_intr", -                   # "file_active", -                   # "file_free", -                   # "inode_active", -                   # "inode_free", -                   "netif_in_kb", -                   "netif_in_pkts", -                   "netif_in_errs", -                   "netif_in_drop", -                   "netif_out_kb", -                   "netif_out_pkts", -                   "netif_out_errs", -                   "netif_out_drop", -                   "vm_page_in", -                   "vm_page_out", -                   "vm_swap_in", -                   "vm_swap_out", -                   #"vm_mem_total", -                   #"vm_mem_used", -                   #"vm_mem_active", -                   #"vm_mem_inactive", -                   #"vm_mem_free", -                   #"vm_mem_buffer", -                   #"vm_swap_cache", -                   #"vm_swap_total", -                   #"vm_swap_used", -                   #"vm_swap_free", -                   "cpu_interrupts", -                   "cpu_switches", -                   "cpu_forks" ] - -    col_count = len(parser.rrd_ds) -    row_count = len(parser.rrd_records) - -    # Process the last row separately, just to make all values numeric. -    for j in range(col_count): -        parser.rrd_records[row_count - 1][j] = _make_numeric(parser.rrd_records[row_count - 1][j]) - -    # Process all other row/columns. -    last_different_row = row_count - 1 -    current_row = row_count - 2 -    while current_row >= 0: -        # Check for a different value than the previous row.  If everything is the same -        # then this is probably just a filler/bogus entry. -        is_different = False -        for j in range(col_count): -            parser.rrd_records[current_row][j] = _make_numeric(parser.rrd_records[current_row][j]) -            if parser.rrd_records[current_row][j] != parser.rrd_records[last_different_row][j]: -                # We're good.  This is a different row. -                is_different = True - -        if not is_different: -            # This is a filler/bogus entry.  Just ignore it. -            for j in range(col_count): -                parser.rrd_records[current_row][j] = float('nan') -        else: -            # Some tags need to be converted into deltas. -            for j in range(col_count): -                if parser.rrd_ds[j]["name"] in fixup_tags: -                    parser.rrd_records[last_different_row][j] = \ -                        parser.rrd_records[last_different_row][j] - parser.rrd_records[current_row][j] -            last_different_row = current_row - -        current_row -= 1 - -    # Set fixup_tags in the first row to 'nan' since they aren't useful anymore. -    for j in range(col_count): -        if parser.rrd_ds[j]["name"] in fixup_tags: -            parser.rrd_records[0][j] = float('nan') - -    # Add a timestamp to each row and to the catalog.  Format and name -    # chosen to match other simulator logging (hopefully). -    start_time = parser.rrd_last_update - (parser.rrd_step * (row_count - 1)) -    # Build a filtered list of rrd_records if we are limited to a time range. -    filter_records = False -    if filter_start_time is not None or filter_end_time is not None: -        filter_records = True -        filtered_rrd_records = [] -        if filter_start_time is None: -            filter_start_time = start_time * 1000 -        if filter_end_time is None: -            filter_end_time = parser.rrd_last_update * 1000 -         -    for i in range(row_count): -        record_timestamp = (start_time + (i * parser.rrd_step)) * 1000 -        parser.rrd_records[i].insert(0, record_timestamp) -        if filter_records: -            if filter_start_time <= record_timestamp and record_timestamp <= filter_end_time: -                filtered_rrd_records.append(parser.rrd_records[i]) - -    if filter_records: -        parser.rrd_records = filtered_rrd_records - -    parser.rrd_ds.insert(0, {"type": "GAUGE", "name": "javascript_timestamp"}) - - -def main(argv=None): -    opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"]) -    input_file = sys.stdin -    output_file = sys.stdout -    for o, a in opts: -        if o in ("-i", "--in"): -            input_file = open(a, 'r') -        if o in ("-o", "--out"): -            output_file = open(a, 'w') -        if o in ("-h", "--help"): -            usage() -            sys.exit(0) - -    # Using the SAX parser as it is at least 4X faster and far, far -    # smaller on this dataset than the DOM-based interface in xml.dom.minidom. -    # With SAX and a 5.4MB xml file, this requires about seven seconds of -    # wall-clock time and 32MB VSZ.  With the DOM interface, about 22 seconds -    # and over 270MB VSZ. - -    handler = SimPerfHostXMLParser() -    sax.parse(input_file, handler) -    if input_file != sys.stdin: -        input_file.close() - -    # Various format fixups:  string-to-num, gauge-to-counts, add -    # a time stamp, etc. -    simperf_host_xml_fixup(handler) -     -    # Create JSONable dict with interesting data and format/print it -    print >>output_file, simplejson.dumps({ "step" : handler.rrd_step, -                                            "lastupdate": handler.rrd_last_update * 1000, -                                            "ds" : handler.rrd_ds, -                                            "database" : handler.rrd_records }) - -    return 0 - -if __name__ == "__main__": -    sys.exit(main()) diff --git a/indra/lib/python/indra/util/simperf_oprof_interface.py b/indra/lib/python/indra/util/simperf_oprof_interface.py deleted file mode 100755 index 547d2f9980..0000000000 --- a/indra/lib/python/indra/util/simperf_oprof_interface.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env python -"""\ -@file simperf_oprof_interface.py -@brief Manage OProfile data collection on a host - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys, os, getopt -import simplejson - - -def usage(): -    print "Usage:" -    print sys.argv[0] + " [options]" -    print "  Digest the OProfile report forms that come out of the" -    print "  simperf_oprof_ctl program's -r/--report command.  The result" -    print "  is an array of dictionaires with the following keys:" -    print  -    print "     symbol        Name of sampled, calling, or called procedure" -    print "     file          Executable or library where symbol resides" -    print "     percentage    Percentage contribution to profile, calls or called" -    print "     samples       Sample count" -    print "     calls         Methods called by the method in question (full only)" -    print "     called_by     Methods calling the method (full only)" -    print  -    print "  For 'full' reports the two keys 'calls' and 'called_by' are" -    print "  themselves arrays of dictionaries based on the first four keys." -    print -    print "Return Codes:" -    print "  None.  Aggressively digests everything.  Will likely mung results" -    print "  if a program or library has whitespace in its name." -    print -    print "Options:" -    print "  -i, --in      Input settings filename.  (Default:  stdin)" -    print "  -o, --out     Output settings filename.  (Default:  stdout)" -    print "  -h, --help    Print this message and exit." -    print -    print "Interfaces:" -    print "   class SimPerfOProfileInterface()" -     -class SimPerfOProfileInterface: -    def __init__(self): -        self.isBrief = True             # public -        self.isValid = False            # public -        self.result = []                # public - -    def parse(self, input): -        in_samples = False -        for line in input: -            if in_samples: -                if line[0:6] == "------": -                    self.isBrief = False -                    self._parseFull(input) -                else: -                    self._parseBrief(input, line) -                self.isValid = True -                return -            try: -                hd1, remain = line.split(None, 1) -                if hd1 == "samples": -                    in_samples = True -            except ValueError: -                pass - -    def _parseBrief(self, input, line1): -        try: -            fld1, fld2, fld3, fld4 = line1.split(None, 3) -            self.result.append({"samples" : fld1, -                                "percentage" : fld2, -                                "file" : fld3, -                                "symbol" : fld4.strip("\n")}) -        except ValueError: -            pass -        for line in input: -            try: -                fld1, fld2, fld3, fld4 = line.split(None, 3) -                self.result.append({"samples" : fld1, -                                    "percentage" : fld2, -                                    "file" : fld3, -                                    "symbol" : fld4.strip("\n")}) -            except ValueError: -                pass - -    def _parseFull(self, input): -        state = 0       # In 'called_by' section -        calls = [] -        called_by = [] -        current = {} -        for line in input: -            if line[0:6] == "------": -                if len(current): -                    current["calls"] = calls -                    current["called_by"] = called_by -                    self.result.append(current) -                state = 0 -                calls = [] -                called_by = [] -                current = {} -            else: -                try: -                    fld1, fld2, fld3, fld4 = line.split(None, 3) -                    tmp = {"samples" : fld1, -                           "percentage" : fld2, -                           "file" : fld3, -                           "symbol" : fld4.strip("\n")} -                except ValueError: -                    continue -                if line[0] != " ": -                    current = tmp -                    state = 1       # In 'calls' section -                elif state == 0: -                    called_by.append(tmp) -                else: -                    calls.append(tmp) -        if len(current): -            current["calls"] = calls -            current["called_by"] = called_by -            self.result.append(current) - - -def main(argv=None): -    opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"]) -    input_file = sys.stdin -    output_file = sys.stdout -    for o, a in opts: -        if o in ("-i", "--in"): -            input_file = open(a, 'r') -        if o in ("-o", "--out"): -            output_file = open(a, 'w') -        if o in ("-h", "--help"): -            usage() -            sys.exit(0) - -    oprof = SimPerfOProfileInterface() -    oprof.parse(input_file) -    if input_file != sys.stdin: -        input_file.close() - -    # Create JSONable dict with interesting data and format/print it -    print >>output_file, simplejson.dumps(oprof.result) - -    return 0 - -if __name__ == "__main__": -    sys.exit(main()) diff --git a/indra/lib/python/indra/util/simperf_proc_interface.py b/indra/lib/python/indra/util/simperf_proc_interface.py deleted file mode 100755 index de061f68cc..0000000000 --- a/indra/lib/python/indra/util/simperf_proc_interface.py +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env python -"""\ -@file simperf_proc_interface.py -@brief Utility to extract log messages from *.<pid>.llsd files containing performance statistics. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -# ---------------------------------------------------- -# Utility to extract log messages from *.<pid>.llsd -# files that contain performance statistics. - -# ---------------------------------------------------- -import sys, os - -if os.path.exists("setup-path.py"): -    execfile("setup-path.py") - -from indra.base import llsd - -DEFAULT_PATH="/dev/shm/simperf/" - - -# ---------------------------------------------------- -# Pull out the stats and return a single document -def parse_logfile(filename, target_column=None, verbose=False): -    full_doc = [] -    # Open source temp log file.  Let exceptions percolate up. -    sourcefile = open( filename,'r') -         -    if verbose: -        print "Reading " + filename   -     -    # Parse and output all lines from the temp file -    for line in sourcefile.xreadlines(): -        partial_doc = llsd.parse(line) -        if partial_doc is not None: -            if target_column is None: -                full_doc.append(partial_doc) -            else: -                trim_doc = { target_column: partial_doc[target_column] } -                if target_column != "fps": -                    trim_doc[ 'fps' ] = partial_doc[ 'fps' ] -                trim_doc[ '/total_time' ] = partial_doc[ '/total_time' ] -                trim_doc[ 'utc_time' ] = partial_doc[ 'utc_time' ] -                full_doc.append(trim_doc) - -    sourcefile.close() -    return full_doc - -# Extract just the meta info line, and the timestamp of the first/last frame entry. -def parse_logfile_info(filename, verbose=False): -    # Open source temp log file.  Let exceptions percolate up. -    sourcefile = open(filename, 'rU') # U is to open with Universal newline support -         -    if verbose: -        print "Reading " + filename   - -    # The first line is the meta info line. -    info_line = sourcefile.readline() -    if not info_line: -        sourcefile.close() -        return None - -    # The rest of the lines are frames.  Read the first and last to get the time range. -    info = llsd.parse( info_line ) -    info['start_time'] = None -    info['end_time'] = None -    first_frame = sourcefile.readline() -    if first_frame: -        try: -            info['start_time'] = int(llsd.parse(first_frame)['timestamp']) -        except: -            pass - -    # Read the file backwards to find the last two lines. -    sourcefile.seek(0, 2) -    file_size = sourcefile.tell() -    offset = 1024 -    num_attempts = 0 -    end_time = None -    if file_size < offset: -        offset = file_size -    while 1: -        sourcefile.seek(-1*offset, 2) -        read_str = sourcefile.read(offset) -        # Remove newline at the end -        if read_str[offset - 1] == '\n': -            read_str = read_str[0:-1] -        lines = read_str.split('\n') -        full_line = None -        if len(lines) > 2:  # Got two line -            try: -                end_time = llsd.parse(lines[-1])['timestamp'] -            except: -                # We couldn't parse this line.  Try once more. -                try: -                    end_time = llsd.parse(lines[-2])['timestamp'] -                except: -                    # Nope.  Just move on. -                    pass -            break -        if len(read_str) == file_size:   # Reached the beginning -            break -        offset += 1024 - -    info['end_time'] = int(end_time) - -    sourcefile.close() -    return info -     - -def parse_proc_filename(filename): -    try: -        name_as_list = filename.split(".") -        cur_stat_type = name_as_list[0].split("_")[0] -        cur_pid = name_as_list[1] -    except IndexError, ValueError: -        return (None, None) -    return (cur_pid, cur_stat_type) - -# ---------------------------------------------------- -def get_simstats_list(path=None): -    """ Return stats (pid, type) listed in <type>_proc.<pid>.llsd """ -    if path is None: -        path = DEFAULT_PATH -    simstats_list = [] -    for file_name in os.listdir(path): -        if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": -            simstats_info = parse_logfile_info(path + file_name) -            if simstats_info is not None: -                simstats_list.append(simstats_info) -    return simstats_list - -def get_log_info_list(pid=None, stat_type=None, path=None, target_column=None, verbose=False): -    """ Return data from all llsd files matching the pid and stat type """ -    if path is None: -        path = DEFAULT_PATH -    log_info_list = {} -    for file_name in os.listdir ( path ): -        if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": -            (cur_pid, cur_stat_type) = parse_proc_filename(file_name) -            if cur_pid is None: -                continue -            if pid is not None and pid != cur_pid: -                continue -            if stat_type is not None and stat_type != cur_stat_type: -                continue -            log_info_list[cur_pid] = parse_logfile(path + file_name, target_column, verbose) -    return log_info_list - -def delete_simstats_files(pid=None, stat_type=None, path=None): -    """ Delete *.<pid>.llsd files """ -    if path is None: -        path = DEFAULT_PATH -    del_list = [] -    for file_name in os.listdir(path): -        if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": -            (cur_pid, cur_stat_type) = parse_proc_filename(file_name) -            if cur_pid is None: -                continue -            if pid is not None and pid != cur_pid: -                continue -            if stat_type is not None and stat_type != cur_stat_type: -                continue -            del_list.append(cur_pid) -            # Allow delete related exceptions to percolate up if this fails. -            os.unlink(os.path.join(DEFAULT_PATH, file_name)) -    return del_list - diff --git a/indra/lib/python/indra/util/term.py b/indra/lib/python/indra/util/term.py deleted file mode 100755 index 8c316a1f12..0000000000 --- a/indra/lib/python/indra/util/term.py +++ /dev/null @@ -1,222 +0,0 @@ -''' -@file term.py -@brief a better shutil.copytree replacement - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -''' - -#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116 - -import sys, re - -class TerminalController: -    """ -    A class that can be used to portably generate formatted output to -    a terminal.   -     -    `TerminalController` defines a set of instance variables whose -    values are initialized to the control sequence necessary to -    perform a given action.  These can be simply included in normal -    output to the terminal: - -        >>> term = TerminalController() -        >>> print 'This is '+term.GREEN+'green'+term.NORMAL - -    Alternatively, the `render()` method can used, which replaces -    '${action}' with the string required to perform 'action': - -        >>> term = TerminalController() -        >>> print term.render('This is ${GREEN}green${NORMAL}') - -    If the terminal doesn't support a given action, then the value of -    the corresponding instance variable will be set to ''.  As a -    result, the above code will still work on terminals that do not -    support color, except that their output will not be colored. -    Also, this means that you can test whether the terminal supports a -    given action by simply testing the truth value of the -    corresponding instance variable: - -        >>> term = TerminalController() -        >>> if term.CLEAR_SCREEN: -        ...     print 'This terminal supports clearning the screen.' - -    Finally, if the width and height of the terminal are known, then -    they will be stored in the `COLS` and `LINES` attributes. -    """ -    # Cursor movement: -    BOL = ''             #: Move the cursor to the beginning of the line -    UP = ''              #: Move the cursor up one line -    DOWN = ''            #: Move the cursor down one line -    LEFT = ''            #: Move the cursor left one char -    RIGHT = ''           #: Move the cursor right one char - -    # Deletion: -    CLEAR_SCREEN = ''    #: Clear the screen and move to home position -    CLEAR_EOL = ''       #: Clear to the end of the line. -    CLEAR_BOL = ''       #: Clear to the beginning of the line. -    CLEAR_EOS = ''       #: Clear to the end of the screen - -    # Output modes: -    BOLD = ''            #: Turn on bold mode -    BLINK = ''           #: Turn on blink mode -    DIM = ''             #: Turn on half-bright mode -    REVERSE = ''         #: Turn on reverse-video mode -    NORMAL = ''          #: Turn off all modes - -    # Cursor display: -    HIDE_CURSOR = ''     #: Make the cursor invisible -    SHOW_CURSOR = ''     #: Make the cursor visible - -    # Terminal size: -    COLS = None          #: Width of the terminal (None for unknown) -    LINES = None         #: Height of the terminal (None for unknown) - -    # Foreground colors: -    BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = '' -     -    # Background colors: -    BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = '' -    BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = '' -     -    _STRING_CAPABILITIES = """ -    BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1 -    CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold -    BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0 -    HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split() -    _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split() -    _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split() - -    def __init__(self, term_stream=sys.stdout): -        """ -        Create a `TerminalController` and initialize its attributes -        with appropriate values for the current terminal. -        `term_stream` is the stream that will be used for terminal -        output; if this stream is not a tty, then the terminal is -        assumed to be a dumb terminal (i.e., have no capabilities). -        """ -        # Curses isn't available on all platforms -        try: import curses -        except: return - -        # If the stream isn't a tty, then assume it has no capabilities. -        if not term_stream.isatty(): return - -        # Check the terminal type.  If we fail, then assume that the -        # terminal has no capabilities. -        try: curses.setupterm() -        except: return - -        # Look up numeric capabilities. -        self.COLS = curses.tigetnum('cols') -        self.LINES = curses.tigetnum('lines') -         -        # Look up string capabilities. -        for capability in self._STRING_CAPABILITIES: -            (attrib, cap_name) = capability.split('=') -            setattr(self, attrib, self._tigetstr(cap_name) or '') - -        # Colors -        set_fg = self._tigetstr('setf') -        if set_fg: -            for i,color in zip(range(len(self._COLORS)), self._COLORS): -                setattr(self, color, curses.tparm(set_fg, i) or '') -        set_fg_ansi = self._tigetstr('setaf') -        if set_fg_ansi: -            for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): -                setattr(self, color, curses.tparm(set_fg_ansi, i) or '') -        set_bg = self._tigetstr('setb') -        if set_bg: -            for i,color in zip(range(len(self._COLORS)), self._COLORS): -                setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '') -        set_bg_ansi = self._tigetstr('setab') -        if set_bg_ansi: -            for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): -                setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '') - -    def _tigetstr(self, cap_name): -        # String capabilities can include "delays" of the form "$<2>". -        # For any modern terminal, we should be able to just ignore -        # these, so strip them out. -        import curses -        cap = curses.tigetstr(cap_name) or '' -        return re.sub(r'\$<\d+>[/*]?', '', cap) - -    def render(self, template): -        """ -        Replace each $-substitutions in the given template string with -        the corresponding terminal control string (if it's defined) or -        '' (if it's not). -        """ -        return re.sub(r'\$\$|\${\w+}', self._render_sub, template) - -    def _render_sub(self, match): -        s = match.group() -        if s == '$$': return s -        else: return getattr(self, s[2:-1]) - -####################################################################### -# Example use case: progress bar -####################################################################### - -class ProgressBar: -    """ -    A 3-line progress bar, which looks like:: -     -                                Header -        20% [===========----------------------------------] -                           progress message - -    The progress bar is colored, if the terminal supports color -    output; and adjusts to the width of the terminal. -    """ -    BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n' -    HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n' -         -    def __init__(self, term, header): -        self.term = term -        if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL): -            raise ValueError("Terminal isn't capable enough -- you " -                             "should use a simpler progress dispaly.") -        self.width = self.term.COLS or 75 -        self.bar = term.render(self.BAR) -        self.header = self.term.render(self.HEADER % header.center(self.width)) -        self.cleared = 1 #: true if we haven't drawn the bar yet. -        self.update(0, '') - -    def update(self, percent, message): -        if self.cleared: -            sys.stdout.write(self.header) -            self.cleared = 0 -        n = int((self.width-10)*percent) -        sys.stdout.write( -            self.term.BOL + self.term.UP + self.term.CLEAR_EOL + -            (self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) + -            self.term.CLEAR_EOL + message.center(self.width)) - -    def clear(self): -        if not self.cleared: -            sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + -                             self.term.UP + self.term.CLEAR_EOL + -                             self.term.UP + self.term.CLEAR_EOL) -            self.cleared = 1 diff --git a/indra/lib/python/uuid.py b/indra/lib/python/uuid.py deleted file mode 100755 index e956383cca..0000000000 --- a/indra/lib/python/uuid.py +++ /dev/null @@ -1,508 +0,0 @@ -#!/usr/bin/python -## $LicenseInfo:firstyear=2011&license=viewerlgpl$ -## Second Life Viewer Source Code -## Copyright (C) 2011, 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$ -r"""UUID objects (universally unique identifiers) according to RFC 4122. - -This module provides immutable UUID objects (class UUID) and the functions -uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5 -UUIDs as specified in RFC 4122. - -If all you want is a unique ID, you should probably call uuid1() or uuid4(). -Note that uuid1() may compromise privacy since it creates a UUID containing -the computer's network address.  uuid4() creates a random UUID. - -Typical usage: - -    >>> import uuid - -    # make a UUID based on the host ID and current time -    >>> uuid.uuid1() -    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') - -    # make a UUID using an MD5 hash of a namespace UUID and a name -    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') -    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') - -    # make a random UUID -    >>> uuid.uuid4() -    UUID('16fd2706-8baf-433b-82eb-8c7fada847da') - -    # make a UUID using a SHA-1 hash of a namespace UUID and a name -    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') -    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') - -    # make a UUID from a string of hex digits (braces and hyphens ignored) -    >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') - -    # convert a UUID to a string of hex digits in standard form -    >>> str(x) -    '00010203-0405-0607-0809-0a0b0c0d0e0f' - -    # get the raw 16 bytes of the UUID -    >>> x.bytes -    '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' - -    # make a UUID from a 16-byte string -    >>> uuid.UUID(bytes=x.bytes) -    UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') - -This module works with Python 2.3 or higher.""" - -__author__ = 'Ka-Ping Yee <ping@zesty.ca>' -__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-') -__version__ = '$Revision: 1.30 $'.split()[1] - -RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ -    'reserved for NCS compatibility', 'specified in RFC 4122', -    'reserved for Microsoft compatibility', 'reserved for future definition'] - -class UUID(object): -    """Instances of the UUID class represent UUIDs as specified in RFC 4122. -    UUID objects are immutable, hashable, and usable as dictionary keys. -    Converting a UUID to a string with str() yields something in the form -    '12345678-1234-1234-1234-123456789abc'.  The UUID constructor accepts -    four possible forms: a similar string of hexadecimal digits, or a -    string of 16 raw bytes as an argument named 'bytes', or a tuple of -    six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and -    48-bit values respectively) as an argument named 'fields', or a single -    128-bit integer as an argument named 'int'. -     -    UUIDs have these read-only attributes: - -        bytes       the UUID as a 16-byte string - -        fields      a tuple of the six integer fields of the UUID, -                    which are also available as six individual attributes -                    and two derived attributes: - -            time_low                the first 32 bits of the UUID -            time_mid                the next 16 bits of the UUID -            time_hi_version         the next 16 bits of the UUID -            clock_seq_hi_variant    the next 8 bits of the UUID -            clock_seq_low           the next 8 bits of the UUID -            node                    the last 48 bits of the UUID - -            time                    the 60-bit timestamp -            clock_seq               the 14-bit sequence number - -        hex         the UUID as a 32-character hexadecimal string - -        int         the UUID as a 128-bit integer - -        urn         the UUID as a URN as specified in RFC 4122 - -        variant     the UUID variant (one of the constants RESERVED_NCS, -                    RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE) - -        version     the UUID version number (1 through 5, meaningful only -                    when the variant is RFC_4122) -    """ - -    def __init__(self, hex=None, bytes=None, fields=None, int=None, -                       version=None): -        r"""Create a UUID from either a string of 32 hexadecimal digits, -        a string of 16 bytes as the 'bytes' argument, a tuple of six -        integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version, -        8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as -        the 'fields' argument, or a single 128-bit integer as the 'int' -        argument.  When a string of hex digits is given, curly braces, -        hyphens, and a URN prefix are all optional.  For example, these -        expressions all yield the same UUID: - -        UUID('{12345678-1234-5678-1234-567812345678}') -        UUID('12345678123456781234567812345678') -        UUID('urn:uuid:12345678-1234-5678-1234-567812345678') -        UUID(bytes='\x12\x34\x56\x78'*4) -        UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678)) -        UUID(int=0x12345678123456781234567812345678) - -        Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given. -        The 'version' argument is optional; if given, the resulting UUID -        will have its variant and version number set according to RFC 4122, -        overriding bits in the given 'hex', 'bytes', 'fields', or 'int'. -        """ - -        if [hex, bytes, fields, int].count(None) != 3: -            raise TypeError('need just one of hex, bytes, fields, or int') -        if hex is not None: -            hex = hex.replace('urn:', '').replace('uuid:', '') -            hex = hex.strip('{}').replace('-', '') -            if len(hex) != 32: -                raise ValueError('badly formed hexadecimal UUID string') -            int = long(hex, 16) -        if bytes is not None: -            if len(bytes) != 16: -                raise ValueError('bytes is not a 16-char string') -            int = long(('%02x'*16) % tuple(map(ord, bytes)), 16) -        if fields is not None: -            if len(fields) != 6: -                raise ValueError('fields is not a 6-tuple') -            (time_low, time_mid, time_hi_version, -             clock_seq_hi_variant, clock_seq_low, node) = fields -            if not 0 <= time_low < 1<<32L: -                raise ValueError('field 1 out of range (need a 32-bit value)') -            if not 0 <= time_mid < 1<<16L: -                raise ValueError('field 2 out of range (need a 16-bit value)') -            if not 0 <= time_hi_version < 1<<16L: -                raise ValueError('field 3 out of range (need a 16-bit value)') -            if not 0 <= clock_seq_hi_variant < 1<<8L: -                raise ValueError('field 4 out of range (need an 8-bit value)') -            if not 0 <= clock_seq_low < 1<<8L: -                raise ValueError('field 5 out of range (need an 8-bit value)') -            if not 0 <= node < 1<<48L: -                raise ValueError('field 6 out of range (need a 48-bit value)') -            clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low -            int = ((time_low << 96L) | (time_mid << 80L) | -                   (time_hi_version << 64L) | (clock_seq << 48L) | node) -        if int is not None: -            if not 0 <= int < 1<<128L: -                raise ValueError('int is out of range (need a 128-bit value)') -        if version is not None: -            if not 1 <= version <= 5: -                raise ValueError('illegal version number') -            # Set the variant to RFC 4122. -            int &= ~(0xc000 << 48L) -            int |= 0x8000 << 48L -            # Set the version number. -            int &= ~(0xf000 << 64L) -            int |= version << 76L -        self.__dict__['int'] = int - -    def __cmp__(self, other): -        if isinstance(other, UUID): -            return cmp(self.int, other.int) -        return NotImplemented - -    def __hash__(self): -        return hash(self.int) - -    def __int__(self): -        return self.int - -    def __repr__(self): -        return 'UUID(%r)' % str(self) - -    def __setattr__(self, name, value): -        raise TypeError('UUID objects are immutable') - -    def __str__(self): -        hex = '%032x' % self.int -        return '%s-%s-%s-%s-%s' % ( -            hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:]) - -    def get_bytes(self): -        bytes = '' -        for shift in range(0, 128, 8): -            bytes = chr((self.int >> shift) & 0xff) + bytes -        return bytes - -    bytes = property(get_bytes) - -    def get_fields(self): -        return (self.time_low, self.time_mid, self.time_hi_version, -                self.clock_seq_hi_variant, self.clock_seq_low, self.node) - -    fields = property(get_fields) - -    def get_time_low(self): -        return self.int >> 96L -    -    time_low = property(get_time_low) - -    def get_time_mid(self): -        return (self.int >> 80L) & 0xffff - -    time_mid = property(get_time_mid) - -    def get_time_hi_version(self): -        return (self.int >> 64L) & 0xffff -     -    time_hi_version = property(get_time_hi_version) - -    def get_clock_seq_hi_variant(self): -        return (self.int >> 56L) & 0xff - -    clock_seq_hi_variant = property(get_clock_seq_hi_variant) -     -    def get_clock_seq_low(self): -        return (self.int >> 48L) & 0xff - -    clock_seq_low = property(get_clock_seq_low) - -    def get_time(self): -        return (((self.time_hi_version & 0x0fffL) << 48L) | -                (self.time_mid << 32L) | self.time_low) - -    time = property(get_time) - -    def get_clock_seq(self): -        return (((self.clock_seq_hi_variant & 0x3fL) << 8L) | -                self.clock_seq_low) - -    clock_seq = property(get_clock_seq) -     -    def get_node(self): -        return self.int & 0xffffffffffff - -    node = property(get_node) - -    def get_hex(self): -        return '%032x' % self.int - -    hex = property(get_hex) - -    def get_urn(self): -        return 'urn:uuid:' + str(self) - -    urn = property(get_urn) - -    def get_variant(self): -        if not self.int & (0x8000 << 48L): -            return RESERVED_NCS -        elif not self.int & (0x4000 << 48L): -            return RFC_4122 -        elif not self.int & (0x2000 << 48L): -            return RESERVED_MICROSOFT -        else: -            return RESERVED_FUTURE - -    variant = property(get_variant) - -    def get_version(self): -        # The version bits are only meaningful for RFC 4122 UUIDs. -        if self.variant == RFC_4122: -            return int((self.int >> 76L) & 0xf) - -    version = property(get_version) - -def _ifconfig_getnode(): -    """Get the hardware address on Unix by running ifconfig.""" -    import os -    for dir in ['', '/sbin/', '/usr/sbin']: -        try: -            path = os.path.join(dir, 'ifconfig') -            if os.path.exists(path): -                pipe = os.popen(path) -            else: -                continue -        except IOError: -            continue -        for line in pipe: -            words = line.lower().split() -            for i in range(len(words)): -                if words[i] in ['hwaddr', 'ether']: -                    return int(words[i + 1].replace(':', ''), 16) - -def _ipconfig_getnode(): -    """Get the hardware address on Windows by running ipconfig.exe.""" -    import os, re -    dirs = ['', r'c:\windows\system32', r'c:\winnt\system32'] -    try: -        import ctypes -        buffer = ctypes.create_string_buffer(300) -        ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300) -        dirs.insert(0, buffer.value.decode('mbcs')) -    except: -        pass -    for dir in dirs: -        try: -            pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all') -        except IOError: -            continue -        for line in pipe: -            value = line.split(':')[-1].strip().lower() -            if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value): -                return int(value.replace('-', ''), 16) - -def _netbios_getnode(): -    """Get the hardware address on Windows using NetBIOS calls. -    See http://support.microsoft.com/kb/118623 for details.""" -    import win32wnet, netbios -    ncb = netbios.NCB() -    ncb.Command = netbios.NCBENUM -    ncb.Buffer = adapters = netbios.LANA_ENUM() -    adapters._pack() -    if win32wnet.Netbios(ncb) != 0: -        return -    adapters._unpack() -    for i in range(adapters.length): -        ncb.Reset() -        ncb.Command = netbios.NCBRESET -        ncb.Lana_num = ord(adapters.lana[i]) -        if win32wnet.Netbios(ncb) != 0: -            continue -        ncb.Reset() -        ncb.Command = netbios.NCBASTAT -        ncb.Lana_num = ord(adapters.lana[i]) -        ncb.Callname = '*'.ljust(16) -        ncb.Buffer = status = netbios.ADAPTER_STATUS() -        if win32wnet.Netbios(ncb) != 0: -            continue -        status._unpack() -        bytes = map(ord, status.adapter_address) -        return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) + -                (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5]) - -# Thanks to Thomas Heller for ctypes and for his help with its use here. - -# If ctypes is available, use it to find system routines for UUID generation. -_uuid_generate_random = _uuid_generate_time = _UuidCreate = None -try: -    import ctypes, ctypes.util -    _buffer = ctypes.create_string_buffer(16) - -    # The uuid_generate_* routines are provided by libuuid on at least -    # Linux and FreeBSD, and provided by libc on Mac OS X. -    for libname in ['uuid', 'c']: -        try: -            lib = ctypes.CDLL(ctypes.util.find_library(libname)) -        except: -            continue -        if hasattr(lib, 'uuid_generate_random'): -            _uuid_generate_random = lib.uuid_generate_random -        if hasattr(lib, 'uuid_generate_time'): -            _uuid_generate_time = lib.uuid_generate_time - -    # On Windows prior to 2000, UuidCreate gives a UUID containing the -    # hardware address.  On Windows 2000 and later, UuidCreate makes a -    # random UUID and UuidCreateSequential gives a UUID containing the -    # hardware address.  These routines are provided by the RPC runtime. -    try: -        lib = ctypes.windll.rpcrt4 -    except: -        lib = None -    _UuidCreate = getattr(lib, 'UuidCreateSequential', -                          getattr(lib, 'UuidCreate', None)) -except: -    pass - -def _unixdll_getnode(): -    """Get the hardware address on Unix using ctypes.""" -    _uuid_generate_time(_buffer) -    return UUID(bytes=_buffer.raw).node - -def _windll_getnode(): -    """Get the hardware address on Windows using ctypes.""" -    if _UuidCreate(_buffer) == 0: -        return UUID(bytes=_buffer.raw).node - -def _random_getnode(): -    """Get a random node ID, with eighth bit set as suggested by RFC 4122.""" -    import random -    return random.randrange(0, 1<<48L) | 0x010000000000L - -_node = None - -def getnode(): -    """Get the hardware address as a 48-bit integer.  The first time this -    runs, it may launch a separate program, which could be quite slow.  If -    all attempts to obtain the hardware address fail, we choose a random -    48-bit number with its eighth bit set to 1 as recommended in RFC 4122.""" - -    global _node -    if _node is not None: -        return _node - -    import sys -    if sys.platform == 'win32': -        getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] -    else: -        getters = [_unixdll_getnode, _ifconfig_getnode] - -    for getter in getters + [_random_getnode]: -        try: -            _node = getter() -        except: -            continue -        if _node is not None: -            return _node - -def uuid1(node=None, clock_seq=None): -    """Generate a UUID from a host ID, sequence number, and the current time. -    If 'node' is not given, getnode() is used to obtain the hardware -    address.  If 'clock_seq' is given, it is used as the sequence number; -    otherwise a random 14-bit sequence number is chosen.""" - -    # When the system provides a version-1 UUID generator, use it (but don't -    # use UuidCreate here because its UUIDs don't conform to RFC 4122). -    if _uuid_generate_time and node is clock_seq is None: -        _uuid_generate_time(_buffer) -        return UUID(bytes=_buffer.raw) - -    import time -    nanoseconds = int(time.time() * 1e9) -    # 0x01b21dd213814000 is the number of 100-ns intervals between the -    # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. -    timestamp = int(nanoseconds/100) + 0x01b21dd213814000L -    if clock_seq is None: -        import random -        clock_seq = random.randrange(1<<14L) # instead of stable storage -    time_low = timestamp & 0xffffffffL -    time_mid = (timestamp >> 32L) & 0xffffL -    time_hi_version = (timestamp >> 48L) & 0x0fffL -    clock_seq_low = clock_seq & 0xffL -    clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL -    if node is None: -        node = getnode() -    return UUID(fields=(time_low, time_mid, time_hi_version, -                        clock_seq_hi_variant, clock_seq_low, node), version=1) - -def uuid3(namespace, name): -    """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" -    try: -        # Python 2.6 -        from hashlib import md5 -    except ImportError: -        # Python 2.5 and earlier -        from md5 import new as md5 -         -    hash = md5(namespace.bytes + name).digest() -    return UUID(bytes=hash[:16], version=3) - -def uuid4(): -    """Generate a random UUID.""" - -    # When the system provides a version-4 UUID generator, use it. -    if _uuid_generate_random: -        _uuid_generate_random(_buffer) -        return UUID(bytes=_buffer.raw) - -    # Otherwise, get randomness from urandom or the 'random' module. -    try: -        import os -        return UUID(bytes=os.urandom(16), version=4) -    except: -        import random -        bytes = [chr(random.randrange(256)) for i in range(16)] -        return UUID(bytes=bytes, version=4) - -def uuid5(namespace, name): -    """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" -    import sha -    hash = sha.sha(namespace.bytes + name).digest() -    return UUID(bytes=hash[:16], version=5) - -# The following standard UUIDs are for use with uuid3() or uuid5(). - -NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index cd201a65b4..e786dfff86 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -2149,7 +2149,7 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,  	LLCharacter* character = *char_iter;  	// look for an existing instance of this motion -	LLKeyframeMotion* motionp = (LLKeyframeMotion*) character->findMotion(asset_uuid); +	LLKeyframeMotion* motionp = dynamic_cast<LLKeyframeMotion*> (character->findMotion(asset_uuid));  	if (motionp)  	{  		if (0 == status) diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index a548c96002..86f407cdb0 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -294,9 +294,11 @@ void LLScopedLock::unlock()  bool ll_apr_warn_status(apr_status_t status)  {  	if(APR_SUCCESS == status) return false; +#if !LL_LINUX  	char buf[MAX_STRING];	/* Flawfinder: ignore */  	apr_strerror(status, buf, sizeof(buf));  	LL_WARNS("APR") << "APR: " << buf << LL_ENDL; +#endif  	return true;  } diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 5ed348e13c..6a62860c3f 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -921,11 +921,6 @@ namespace  			std::ostringstream message_stream; -			if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)) -			{ -				message_stream << site.mLocationString << " "; -			} -  			if (show_time && r->wantsTime() && s->mTimeFunction != NULL)  			{  				message_stream << s->mTimeFunction() << " "; @@ -933,17 +928,17 @@ namespace  			if (show_level && r->wantsLevel())              { -				message_stream << site.mLevelString; +				message_stream << site.mLevelString << " ";              }  			if (show_tags && r->wantsTags())  			{  				message_stream << site.mTagString;  			} -			if ((show_level && r->wantsLevel())|| -                (show_tags && r->wantsTags())) + +            if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation))              { -                message_stream << " "; +                message_stream << site.mLocationString << " ";              }  			if (show_function && r->wantsFunctionName()) diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 19d700a3b0..97270e4931 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -276,6 +276,8 @@ LLEventPumps::~LLEventPumps()  #pragma warning (push)  #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally  #endif +const std::string LLEventPump::ANONYMOUS = std::string(); +  LLEventPump::LLEventPump(const std::string& name, bool tweak):      // Register every new instance with LLEventPumps @@ -314,145 +316,162 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL                                           const NameList& after,                                           const NameList& before)  { -    // Check for duplicate name before connecting listener to mSignal -    ConnectionMap::const_iterator found = mConnections.find(name); -    // In some cases the user might disconnect a connection explicitly -- or -    // might use LLEventTrackable to disconnect implicitly. Either way, we can -    // end up retaining in mConnections a zombie connection object that's -    // already been disconnected. Such a connection object can't be -    // reconnected -- nor, in the case of LLEventTrackable, would we want to -    // try, since disconnection happens with the destruction of the listener -    // object. That means it's safe to overwrite a disconnected connection -    // object with the new one we're attempting. The case we want to prevent -    // is only when the existing connection object is still connected. -    if (found != mConnections.end() && found->second.connected()) +    float nodePosition = 1.0; + +    // if the supplied name is empty we are not interested in the ordering mechanism  +    // and can bypass attempting to find the optimal location to insert the new  +    // listener.  We'll just tack it on to the end. +    if (!name.empty()) // should be the same as testing against ANONYMOUS      { +        // Check for duplicate name before connecting listener to mSignal +        ConnectionMap::const_iterator found = mConnections.find(name); +        // In some cases the user might disconnect a connection explicitly -- or +        // might use LLEventTrackable to disconnect implicitly. Either way, we can +        // end up retaining in mConnections a zombie connection object that's +        // already been disconnected. Such a connection object can't be +        // reconnected -- nor, in the case of LLEventTrackable, would we want to +        // try, since disconnection happens with the destruction of the listener +        // object. That means it's safe to overwrite a disconnected connection +        // object with the new one we're attempting. The case we want to prevent +        // is only when the existing connection object is still connected. +        if (found != mConnections.end() && found->second.connected()) +        {          LLTHROW(DupListenerName("Attempt to register duplicate listener name '" + name +                                  "' on " + typeid(*this).name() + " '" + getName() + "'")); -    } -    // Okay, name is unique, try to reconcile its dependencies. Specify a new -    // "node" value that we never use for an mSignal placement; we'll fix it -    // later. -    DependencyMap::node_type& newNode = mDeps.add(name, -1.0, after, before); -    // What if this listener has been added, removed and re-added? In that -    // case newNode already has a non-negative value because we never remove a -    // listener from mDeps. But keep processing uniformly anyway in case the -    // listener was added back with different dependencies. Then mDeps.sort() -    // would put it in a different position, and the old newNode placement -    // value would be wrong, so we'd have to reassign it anyway. Trust that -    // re-adding a listener with the same dependencies is the trivial case for -    // mDeps.sort(): it can just replay its cache. -    DependencyMap::sorted_range sorted_range; -    try -    { -        // Can we pick an order that works including this new entry? -        sorted_range = mDeps.sort(); -    } -    catch (const DependencyMap::Cycle& e) -    { -        // No: the new node's after/before dependencies have made mDeps -        // unsortable. If we leave the new node in mDeps, it will continue -        // to screw up all future attempts to sort()! Pull it out. -        mDeps.remove(name); +        } +        // Okay, name is unique, try to reconcile its dependencies. Specify a new +        // "node" value that we never use for an mSignal placement; we'll fix it +        // later. +        DependencyMap::node_type& newNode = mDeps.add(name, -1.0, after, before); +        // What if this listener has been added, removed and re-added? In that +        // case newNode already has a non-negative value because we never remove a +        // listener from mDeps. But keep processing uniformly anyway in case the +        // listener was added back with different dependencies. Then mDeps.sort() +        // would put it in a different position, and the old newNode placement +        // value would be wrong, so we'd have to reassign it anyway. Trust that +        // re-adding a listener with the same dependencies is the trivial case for +        // mDeps.sort(): it can just replay its cache. +        DependencyMap::sorted_range sorted_range; +        try +        { +            // Can we pick an order that works including this new entry? +            sorted_range = mDeps.sort(); +        } +        catch (const DependencyMap::Cycle& e) +        { +            // No: the new node's after/before dependencies have made mDeps +            // unsortable. If we leave the new node in mDeps, it will continue +            // to screw up all future attempts to sort()! Pull it out. +            mDeps.remove(name);          LLTHROW(Cycle("New listener '" + name + "' on " + typeid(*this).name() +                        " '" + getName() + "' would cause cycle: " + e.what())); -    } -    // Walk the list to verify that we haven't changed the order. -    float previous = 0.0, myprev = 0.0; -    DependencyMap::sorted_iterator mydmi = sorted_range.end(); // need this visible after loop -    for (DependencyMap::sorted_iterator dmi = sorted_range.begin(); -         dmi != sorted_range.end(); ++dmi) -    { -        // Since we've added the new entry with an invalid placement, -        // recognize it and skip it. -        if (dmi->first == name) -        { -            // Remember the iterator belonging to our new node, and which -            // placement value was 'previous' at that point. -            mydmi = dmi; -            myprev = previous; -            continue;          } -        // If the new node has rearranged the existing nodes, we'll find -        // that their placement values are no longer in increasing order. -        if (dmi->second < previous) +        // Walk the list to verify that we haven't changed the order. +        float previous = 0.0, myprev = 0.0; +        DependencyMap::sorted_iterator mydmi = sorted_range.end(); // need this visible after loop +        for (DependencyMap::sorted_iterator dmi = sorted_range.begin(); +            dmi != sorted_range.end(); ++dmi)          { -            // This is another scenario in which we'd better back out the -            // newly-added node from mDeps -- but don't do it yet, we want to -            // traverse the existing mDeps to report on it! -            // Describe the change to the order of our listeners. Copy -            // everything but the newest listener to a vector we can sort to -            // obtain the old order. -            typedef std::vector< std::pair<float, std::string> > SortNameList; -            SortNameList sortnames; -            for (DependencyMap::sorted_iterator cdmi(sorted_range.begin()), cdmend(sorted_range.end()); -                 cdmi != cdmend; ++cdmi) +            // Since we've added the new entry with an invalid placement, +            // recognize it and skip it. +            if (dmi->first == name)              { -                if (cdmi->first != name) -                { -                    sortnames.push_back(SortNameList::value_type(cdmi->second, cdmi->first)); -                } +                // Remember the iterator belonging to our new node, and which +                // placement value was 'previous' at that point. +                mydmi = dmi; +                myprev = previous; +                continue;              } -            std::sort(sortnames.begin(), sortnames.end()); -            std::ostringstream out; -            out << "New listener '" << name << "' on " << typeid(*this).name() << " '" << getName() -                << "' would move previous listener '" << dmi->first << "'\nwas: "; -            SortNameList::const_iterator sni(sortnames.begin()), snend(sortnames.end()); -            if (sni != snend) +            // If the new node has rearranged the existing nodes, we'll find +            // that their placement values are no longer in increasing order. +            if (dmi->second < previous)              { -                out << sni->second; -                while (++sni != snend) +                // This is another scenario in which we'd better back out the +                // newly-added node from mDeps -- but don't do it yet, we want to +                // traverse the existing mDeps to report on it! +                // Describe the change to the order of our listeners. Copy +                // everything but the newest listener to a vector we can sort to +                // obtain the old order. +                typedef std::vector< std::pair<float, std::string> > SortNameList; +                SortNameList sortnames; +                for (DependencyMap::sorted_iterator cdmi(sorted_range.begin()), cdmend(sorted_range.end()); +                    cdmi != cdmend; ++cdmi)                  { -                    out << ", " << sni->second; +                    if (cdmi->first != name) +                    { +                        sortnames.push_back(SortNameList::value_type(cdmi->second, cdmi->first)); +                    }                  } -            } -            out << "\nnow: "; -            DependencyMap::sorted_iterator ddmi(sorted_range.begin()), ddmend(sorted_range.end()); -            if (ddmi != ddmend) -            { -                out << ddmi->first; -                while (++ddmi != ddmend) +                std::sort(sortnames.begin(), sortnames.end()); +                std::ostringstream out; +                out << "New listener '" << name << "' on " << typeid(*this).name() << " '" << getName() +                    << "' would move previous listener '" << dmi->first << "'\nwas: "; +                SortNameList::const_iterator sni(sortnames.begin()), snend(sortnames.end()); +                if (sni != snend)                  { -                    out << ", " << ddmi->first; +                    out << sni->second; +                    while (++sni != snend) +                    { +                        out << ", " << sni->second; +                    }                  } -            } -            // NOW remove the offending listener node. -            mDeps.remove(name); -            // Having constructed a description of the order change, inform caller. +                out << "\nnow: "; +                DependencyMap::sorted_iterator ddmi(sorted_range.begin()), ddmend(sorted_range.end()); +                if (ddmi != ddmend) +                { +                    out << ddmi->first; +                    while (++ddmi != ddmend) +                    { +                        out << ", " << ddmi->first; +                    } +                } +                // NOW remove the offending listener node. +                mDeps.remove(name); +                // Having constructed a description of the order change, inform caller.              LLTHROW(OrderChange(out.str())); +            } +            // This node becomes the previous one. +            previous = dmi->second;          } -        // This node becomes the previous one. -        previous = dmi->second; -    } -    // We just got done with a successful mDeps.add(name, ...) call. We'd -    // better have found 'name' somewhere in that sorted list! -    assert(mydmi != sorted_range.end()); -    // Four cases: -    // 0. name is the only entry: placement 1.0 -    // 1. name is the first of several entries: placement (next placement)/2 -    // 2. name is between two other entries: placement (myprev + (next placement))/2 -    // 3. name is the last entry: placement ceil(myprev) + 1.0 -    // Since we've cleverly arranged for myprev to be 0.0 if name is the -    // first entry, this folds down to two cases. Case 1 is subsumed by -    // case 2, and case 0 is subsumed by case 3. So we need only handle -    // cases 2 and 3, which means we need only detect whether name is the -    // last entry. Increment mydmi to see if there's anything beyond. -    if (++mydmi != sorted_range.end()) -    { -        // The new node isn't last. Place it between the previous node and -        // the successor. -        newNode = (myprev + mydmi->second)/2.f; -    } -    else -    { -        // The new node is last. Bump myprev up to the next integer, add -        // 1.0 and use that. -        newNode = std::ceil(myprev) + 1.f; +        // We just got done with a successful mDeps.add(name, ...) call. We'd +        // better have found 'name' somewhere in that sorted list! +        assert(mydmi != sorted_range.end()); +        // Four cases: +        // 0. name is the only entry: placement 1.0 +        // 1. name is the first of several entries: placement (next placement)/2 +        // 2. name is between two other entries: placement (myprev + (next placement))/2 +        // 3. name is the last entry: placement ceil(myprev) + 1.0 +        // Since we've cleverly arranged for myprev to be 0.0 if name is the +        // first entry, this folds down to two cases. Case 1 is subsumed by +        // case 2, and case 0 is subsumed by case 3. So we need only handle +        // cases 2 and 3, which means we need only detect whether name is the +        // last entry. Increment mydmi to see if there's anything beyond. +        if (++mydmi != sorted_range.end()) +        { +            // The new node isn't last. Place it between the previous node and +            // the successor. +            newNode = (myprev + mydmi->second) / 2.f; +        } +        else +        { +            // The new node is last. Bump myprev up to the next integer, add +            // 1.0 and use that. +            newNode = std::ceil(myprev) + 1.f; +        } + +        nodePosition = newNode;      }      // Now that newNode has a value that places it appropriately in mSignal,      // connect it. -    LLBoundListener bound = mSignal->connect(newNode, listener); -    mConnections[name] = bound; +    LLBoundListener bound = mSignal->connect(nodePosition, listener); +     +    if (!name.empty()) +    {   // note that we are not tracking anonymous listeners here either. +        // This means that it is the caller's responsibility to either assign  +        // to a TempBoundListerer (scoped_connection) or manually disconnect  +        // when done.  +        mConnections[name] = bound; +    }      return bound;  } diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 1526128725..a3b9ec02e0 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -385,6 +385,8 @@ typedef boost::signals2::trackable LLEventTrackable;  class LL_COMMON_API LLEventPump: public LLEventTrackable  {  public: +    static const std::string ANONYMOUS; // constant for anonymous listeners. +      /**       * Exception thrown by LLEventPump(). You are trying to instantiate an       * LLEventPump (subclass) using the same name as some other instance, and @@ -496,6 +498,12 @@ public:       * instantiate your listener, then passing the same name on each listen()       * call, allows us to optimize away the second and subsequent dependency       * sorts. +     *  +     * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire  +     * dependency and ordering calculation. In this case, it is critical that  +     * the result be assigned to a LLTempBoundListener or the listener is  +     * manually disconnected when no longer needed since there will be no +     * way to later find and disconnect this listener manually.       *       * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a       * listener, listen() will inspect the components of that expression. If a diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index 82d0dc8b4b..c275b90120 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -205,9 +205,9 @@ void LLUriParser::glue(std::string& uri) const  	uri = first_part + second_part;  } -void LLUriParser::glueFirst(std::string& uri) const +void LLUriParser::glueFirst(std::string& uri, bool use_scheme) const  { -	if (mScheme.size()) +	if (use_scheme && mScheme.size())  	{  		uri = mScheme;  		uri += "://"; diff --git a/indra/llcommon/lluriparser.h b/indra/llcommon/lluriparser.h index 2df8085ae6..cfbf54f3c8 100644 --- a/indra/llcommon/lluriparser.h +++ b/indra/llcommon/lluriparser.h @@ -60,7 +60,7 @@ public:  	void extractParts();  	void glue(std::string& uri) const; -	void glueFirst(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(); diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index 8bace8ac41..20de205454 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -564,9 +564,9 @@ namespace tut  					function;  		writeReturningLocationAndFunction(location, function); -		ensure_equals("order is location time type function message", +		ensure_equals("order is time location type function message",  			message(0), -			location + roswell() + " INFO: " + function + ": apple"); +			roswell() + " INFO: " + location + function + ": apple");  	}  	template<> template<> diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index d342dece84..c387da6c48 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -110,10 +110,7 @@ namespace tut                     // finding indra/lib/python. Use our __FILE__, with                     // raw-string syntax to deal with Windows pathnames.                     "mydir = os.path.dirname(r'" << __FILE__ << "')\n" -                   // We expect mydir to be .../indra/llcommon/tests. -                   "sys.path.insert(0,\n" -                   "    os.path.join(mydir, os.pardir, os.pardir, 'lib', 'python'))\n" -                   "from indra.base import llsd\n" +                   "from llbase import llsd\n"                     "\n"                     "class ProtocolError(Exception):\n"                     "    def __init__(self, msg, data):\n" diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index 6fbb9abfc0..81b930e1e2 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1518,10 +1518,7 @@ namespace tut              // scanner.              import_llsd("import os.path\n"                          "import sys\n" -                        "sys.path.insert(0,\n" -                        "    os.path.join(os.path.dirname(r'" __FILE__ "'),\n" -                        "                 os.pardir, os.pardir, 'lib', 'python'))\n" -                        "from indra.base import llsd\n") +                        "from llbase import llsd\n")          {}          ~TestPythonCompatible() {} diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py index 04cde651c4..6c5f37d407 100755 --- a/indra/llcorehttp/tests/test_llcorehttp_peer.py +++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py @@ -42,10 +42,8 @@ except ImportError:  from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler  from SocketServer import ThreadingMixIn -mydir = os.path.dirname(__file__)       # expected to be .../indra/llcorehttp/tests/ -sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python")) -from indra.util.fastest_elementtree import parse as xml_parse -from indra.base import llsd +from llbase.fastest_elementtree import parse as xml_parse +from llbase import llsd  from testrunner import freeport, run, debug, VERBOSE  class TestHTTPRequestHandler(BaseHTTPRequestHandler): diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index d932eb53a0..567ad9a414 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2143,19 +2143,22 @@ BOOL LLVolume::generate()  	F32 profile_detail = mDetail;  	F32 path_detail = mDetail; -	 -	U8 path_type = mParams.getPathParams().getCurveType(); -	U8 profile_type = mParams.getProfileParams().getCurveType(); -	 -	if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) -	{ //cylinders don't care about Z-Axis -		mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); -	} -	else if (path_type == LL_PCODE_PATH_CIRCLE)  -	{	 -		mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); + +	if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) +	{ +		U8 path_type = mParams.getPathParams().getCurveType(); +		U8 profile_type = mParams.getProfileParams().getCurveType(); +		if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) +		{ +			//cylinders don't care about Z-Axis +			mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); +		} +		else if (path_type == LL_PCODE_PATH_CIRCLE) +		{ +			mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); +		}  	} -	 +  	BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split);  	BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 7742cbc182..9bf38fb336 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -642,7 +642,7 @@ HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request)      mHttpRequest(request)  {      mBoundListener = LLEventPumps::instance().obtain("mainloop"). -        listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1)); +        listen(LLEventPump::ANONYMOUS, boost::bind(&HttpRequestPumper::pollRequest, this, _1));  }  HttpRequestPumper::~HttpRequestPumper() diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index 4aba5cae72..e0590dfdff 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -294,7 +294,7 @@ S32 LLXfer::processEOF()  	}  	else  	{ -		LL_INFOS() << "xfer from " << mRemoteHost << " failed, code " +		LL_INFOS() << "xfer from " << mRemoteHost << " failed or aborted, code "  				<< mCallbackResult << ": " << getFileName() << LL_ENDL;  	} diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 0ab67b8dda..272dbbc785 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -401,7 +401,7 @@ U64 LLXferManager::registerXfer(const void *datap, const S32 length)  /////////////////////////////////////////////////////////// -void LLXferManager::requestFile(const std::string& local_filename, +U64 LLXferManager::requestFile(const std::string& local_filename,  								const std::string& remote_filename,  								ELLPath remote_path,  								const LLHost& remote_host, @@ -424,10 +424,12 @@ void LLXferManager::requestFile(const std::string& local_filename,  		{  			// cout << "requested a xfer already in progress" << endl; -			return; +			return xferp->mID;  		}  	} +	U64 xfer_id = 0; +  	S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1;  	xferp = (LLXfer *) new LLXfer_File(chunk_size);  	if (xferp) @@ -438,13 +440,15 @@ void LLXferManager::requestFile(const std::string& local_filename,  		// around.  		// Note: according to AaronB, this is here to deal with locks on files that were  		// in transit during a crash, -		if(delete_remote_on_completion && -		   (remote_filename.substr(remote_filename.length()-4) == ".tmp")) +		if( delete_remote_on_completion +			&& (remote_filename.substr(remote_filename.length()-4) == ".tmp") +			&& gDirUtilp->fileExists(local_filename))  		{  			LLFile::remove(local_filename);  		} +		xfer_id = getNextID();  		((LLXfer_File *)xferp)->initializeRequest( -			getNextID(), +			xfer_id,  			local_filename,  			remote_filename,  			remote_path, @@ -457,6 +461,7 @@ void LLXferManager::requestFile(const std::string& local_filename,  	{  		LL_ERRS() << "Xfer allocation error" << LL_ENDL;  	} +	return xfer_id;  }  void LLXferManager::requestFile(const std::string& remote_filename, @@ -616,7 +621,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user  	if (!xferp)   	{  		char U64_BUF[MAX_STRING];		/* Flawfinder : ignore */ -		LL_WARNS() << "received xfer data from " << mesgsys->getSender() +		LL_INFOS() << "received xfer data from " << mesgsys->getSender()  			<< " for non-existent xfer id: "  			<< U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << LL_ENDL;  		return; @@ -1103,6 +1108,29 @@ void LLXferManager::retransmitUnackedPackets ()  	}  } +/////////////////////////////////////////////////////////// + +void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code) +{ +	LLXfer * xferp = findXfer(xfer_id, mReceiveList); +	if (xferp) +	{ +		if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) +		{ +			// causes processAbort(); +			xferp->abort(result_code); +		} +		else +		{ +			xferp->mCallbackResult = result_code; +			xferp->processEOF(); //should notify requester +			removeXfer(xferp, &mReceiveList); +		} +		// Since already removed or marked as aborted no need +		// to wait for processAbort() to start new download +		startPendingDownloads(); +	} +}  /////////////////////////////////////////////////////////// diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index b3d110e7a1..d258f0a5ce 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -140,7 +140,7 @@ class LLXferManager  // file requesting routines  // .. to file -	virtual void requestFile(const std::string& local_filename, +	virtual U64 requestFile(const std::string& local_filename,  							 const std::string& remote_filename,  							 ELLPath remote_path,  							 const LLHost& remote_host, @@ -202,6 +202,7 @@ class LLXferManager  	virtual void retransmitUnackedPackets ();  // error handling +	void abortRequestById(U64 xfer_id, S32 result_code);  	virtual void processAbort (LLMessageSystem *mesgsys, void **user_data);  }; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index cecb2021e7..290b67feb3 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -4007,7 +4007,7 @@ void LLMessageSystem::sendUntrustedSimulatorMessageCoro(std::string url, std::st  {      LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);      LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t -        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("untrustedSimulatorMessage", httpPolicy));      LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);      LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index e45249b1cb..bac18fa374 100755 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -34,10 +34,8 @@ import sys  from threading import Thread  from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler -mydir = os.path.dirname(__file__)       # expected to be .../indra/llmessage/tests/ -sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python")) -from indra.util.fastest_elementtree import parse as xml_parse -from indra.base import llsd +from llbase.fastest_elementtree import parse as xml_parse +from llbase import llsd  from testrunner import freeport, run, debug, VERBOSE  import time diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index d672650658..f1b6fe0a12 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -73,6 +73,7 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s  	// Queue up the media init message -- it will be sent after all the currently queued messages.  	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");  	message.setValue("target", mTarget); +	message.setValueReal("factor", mZoomFactor);  	sendMessage(message);  	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); @@ -1259,7 +1260,7 @@ void LLPluginClassMedia::focus(bool focused)  	sendMessage(message);  } -void LLPluginClassMedia::set_page_zoom_factor( double factor ) +void LLPluginClassMedia::set_page_zoom_factor( F64 factor )  {  	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_page_zoom_factor"); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index fc27b7bea3..3b0739d044 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -68,6 +68,7 @@ public:  	int getTextureHeight() const;  	int getFullWidth() const { return mFullMediaWidth; };  	int getFullHeight() const { return mFullMediaHeight; }; +	F64 getZoomFactor() const { return mZoomFactor; };  	// This may return NULL.  Callers need to check for and handle this case.  	unsigned char* getBitsData(); @@ -83,7 +84,8 @@ public:  	void setSize(int width, int height);  	void setAutoScale(bool auto_scale); -	 +	void setZoomFactor(F64 zoom_factor) { mZoomFactor = zoom_factor; } +  	void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; };  	void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; @@ -204,7 +206,7 @@ public:  	bool pluginSupportsMediaBrowser(void);  	void focus(bool focused); -	void set_page_zoom_factor( double factor ); +	void set_page_zoom_factor( F64 factor );  	void clear_cache();  	void clear_cookies();  	void set_cookies(const std::string &cookies); @@ -367,6 +369,8 @@ protected:  	int			mTextureHeight;  	int			mMediaWidth;  	int			mMediaHeight; + +	F64			mZoomFactor;  	float		mRequestedVolume; diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 00bde8dbc3..8071d716da 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1071,7 +1071,7 @@ bool LLDAELoader::OpenFile(const std::string& filename)  std::string LLDAELoader::preprocessDAE(std::string filename)  {  	// Open a DAE file for some preprocessing (like removing space characters in IDs), see MAINT-5678 -	std::ifstream inFile; +	llifstream inFile;  	inFile.open(filename.c_str(), std::ios_base::in);  	std::stringstream strStream;  	strStream << inFile.rdbuf(); diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 0e2946632a..cf0a117567 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -364,12 +364,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  	if (right_x)  	{ -        F32 cr_x = (cur_x - origin.mV[VX]) / sScaleX; -        if (*right_x < cr_x) -        { -            // rightmost edge of previously drawn text, don't draw over previous text -            *right_x = cr_x; -        } +		*right_x = (cur_x - origin.mV[VX]) / sScaleX;  	}  	//FIXME: add underline as glyph? diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index ebed454271..81a5537f78 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -487,14 +487,15 @@ bool LLImageGL::checkSize(S32 width, S32 height)  	return check_power_of_two(width) && check_power_of_two(height);  } -void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level) +bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level)  {  	if (width != mWidth || height != mHeight || ncomponents != mComponents)  	{  		// Check if dimensions are a power of two!  		if (!checkSize(width,height))  		{ -			LL_ERRS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL; +			LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL; +			return false;  		}  		if (mTexName) @@ -529,6 +530,8 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve  			mMaxDiscardLevel = MAX_DISCARD_LEVEL;  		}  	} + +	return true;  }  //---------------------------------------------------------------------------- @@ -909,7 +912,11 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)  	S32 h = raw_image->getHeight() << discard_level;  	// setSize may call destroyGLTexture if the size does not match -	setSize(w, h, raw_image->getComponents(), discard_level); +	if (!setSize(w, h, raw_image->getComponents(), discard_level)) +	{ +		LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; +		return FALSE; +	}  	if( !mHasExplicitFormat )  	{ @@ -1273,7 +1280,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S  	S32 h = raw_h << discard_level;  	// setSize may call destroyGLTexture if the size does not match -	setSize(w, h, imageraw->getComponents(), discard_level); +	if (!setSize(w, h, imageraw->getComponents(), discard_level)) +	{ +		LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; +		return FALSE; +	}  	if( !mHasExplicitFormat )  	{ diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 21982eab1d..ad2aea9067 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -94,7 +94,7 @@ protected:  public:  	virtual void dump();	// debugging info to LL_INFOS() -	void setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level = -1); +	bool setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level = -1);  	void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;}  	void setAllowCompression(bool allow) { mAllowCompression = allow; } diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 1d18cb2bb0..06fac190ed 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -123,7 +123,15 @@ bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool u  // Concatenate the input string to the LL and the system clipboard  bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary)  { -	mString = src.substr(pos, len); +	try +	{ +		mString = src.substr(pos, len); +	} +	catch (const std::exception& e) +	{ +		LL_WARNS() << "Can't add the substring to clipboard: " << e.what() << LL_ENDL; +		return false; +	}  	return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString));  } diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 8166ef6a07..f9664e0658 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -684,6 +684,13 @@ void LLFolderView::draw()  		}  	} +	if (mRenameItem && mRenamer && mRenamer->getVisible() && !getVisibleRect().overlaps(mRenamer->getRect())) +	{ +		// renamer is not connected to the item we are renaming in any form so manage it manually +		// TODO: consider stopping on any scroll action instead of when out of visible area +		finishRenamingItem(); +	} +  	// skip over LLFolderViewFolder::draw since we don't want the folder icon, label,   	// and arrow for the root folder  	LLView::draw(); diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 5eb5ca4f82..3d618548c4 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -127,6 +127,8 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)  	mIsSelected( FALSE ),  	mIsCurSelection( FALSE ),  	mSelectPending(FALSE), +	mIsItemCut(false), +	mCutGeneration(0),  	mLabelStyle( LLFontGL::NORMAL ),  	mHasVisibleChildren(FALSE),  	mIsFolderComplete(true), @@ -694,6 +696,19 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L  	return mIsCurSelection;  } +/*virtual*/ bool LLFolderViewItem::isFadeItem() +{ +    LLClipboard& clipboard = LLClipboard::instance(); +    if (mCutGeneration != clipboard.getGeneration()) +    { +        mCutGeneration = clipboard.getGeneration(); +        mIsItemCut = clipboard.isCutMode() +                     && ((getParentFolder() && getParentFolder()->isFadeItem()) +                        || getViewModelItem()->isCutToClipboard()); +    } +    return mIsItemCut; +} +  void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor,                                                            const LLUIColor &focusOutlineColor, const LLUIColor &mouseOverColor)  { @@ -875,6 +890,12 @@ void LLFolderViewItem::draw()      }      LLColor4 color = (mIsSelected && filled) ? mFontHighlightColor : mFontColor; + +    if (isFadeItem()) +    { +         // Fade out item color to indicate it's being cut +         color.mV[VALPHA] *= 0.5f; +    }      drawLabel(font, text_left, y, color, right_x);  	//--------------------------------------------------------------------------------// @@ -882,7 +903,7 @@ void LLFolderViewItem::draw()  	//  	if (!mLabelSuffix.empty())  	{ -		font->renderUTF8( mLabelSuffix, 0, right_x, y, sSuffixColor, +		font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,  						  LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,  						  S32_MAX, S32_MAX, &right_x, FALSE );  	} diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 0322c8836d..61c39e0175 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -121,8 +121,11 @@ protected:  								mIsMouseOverTitle,  								mAllowWear,                                  mAllowDrop, -								mSelectPending; -	 +								mSelectPending, +								mIsItemCut; + +	S32							mCutGeneration; +  	LLUIColor                   mFontColor;  	LLUIColor                   mFontHighlightColor; @@ -145,6 +148,7 @@ protected:  	virtual void addFolder(LLFolderViewFolder*) { }  	virtual bool isHighlightAllowed();  	virtual bool isHighlightActive(); +	virtual bool isFadeItem();  	virtual bool isFlashing() { return false; }  	virtual void setFlashState(bool) { } diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index a395af537a..641241a88c 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -173,6 +173,7 @@ public:  	virtual BOOL isItemCopyable() const = 0;  	virtual BOOL copyToClipboard() const = 0;  	virtual BOOL cutToClipboard() = 0; +	virtual bool isCutToClipboard() { return false; };  	virtual BOOL isClipboardPasteable() const = 0;  	virtual void pasteFromClipboard() = 0; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 492c9315d1..c89e1dac1d 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -2636,10 +2636,17 @@ void LLLineEditor::showContextMenu(S32 x, S32 y)  void LLLineEditor::setContextMenu(LLContextMenu* new_context_menu)  { -	if (new_context_menu) -		mContextMenuHandle = new_context_menu->getHandle(); -	else -		mContextMenuHandle.markDead(); +    LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); +    if (menu) +    { +        menu->die(); +        mContextMenuHandle.markDead(); +    } + +    if (new_context_menu) +    { +        mContextMenuHandle = new_context_menu->getHandle(); +    }  }  void LLLineEditor::setFont(const LLFontGL* font) diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index c6d472f59b..ccbd305a16 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -272,7 +272,7 @@ public:  	void			setReplaceNewlinesWithSpaces(BOOL replace); -	void			setContextMenu(LLContextMenu* new_context_menu); +	void			resetContextMenu() { setContextMenu(NULL); };  private:  	// private helper methods @@ -308,6 +308,8 @@ private:  	virtual S32		getPreeditFontSize() const;  	virtual LLWString getPreeditString() const { return getWText(); } +	void			setContextMenu(LLContextMenu* new_context_menu); +  protected:  	LLUIString		mText;					// The string being edited.  	std::string		mPrevText;				// Saved string for 'ESC' revert diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index c7d7535f87..20be739286 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -181,7 +181,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)  	mMaxTextByteLength( p.max_text_length ),  	mFont(p.font),  	mFontShadow(p.font_shadow), -	mPopupMenu(NULL), +	mPopupMenuHandle(),  	mReadOnly(p.read_only),  	mSpellCheck(p.spellcheck),  	mSpellCheckStart(-1), @@ -1263,9 +1263,10 @@ void LLTextBase::setReadOnlyColor(const LLColor4 &c)  //virtual  void LLTextBase::onVisibilityChange( BOOL new_visibility )  { -	if(!new_visibility && mPopupMenu) +	LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); +	if(!new_visibility && menu)  	{ -		mPopupMenu->hide(); +		menu->hide();  	}  	LLUICtrl::onVisibilityChange(new_visibility);  } @@ -1956,41 +1957,48 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)  	registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url));  	// create and return the context menu from the XUI file -	delete mPopupMenu; + +    LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); +    if (menu) +    { +        menu->die(); +        mPopupMenuHandle.markDead(); +    }  	llassert(LLMenuGL::sMenuContainer != NULL); -	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer, -																		 LLMenuHolderGL::child_registry_t::instance());	 -	if (mIsFriendSignal) -	{ -		bool isFriend = *(*mIsFriendSignal)(LLUUID(LLUrlAction::getUserID(url))); -		LLView* addFriendButton = mPopupMenu->getChild<LLView>("add_friend"); -		LLView* removeFriendButton = mPopupMenu->getChild<LLView>("remove_friend"); +    menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer, +																		 LLMenuHolderGL::child_registry_t::instance()); +    if (menu) +    { +        mPopupMenuHandle = menu->getHandle(); -		if (addFriendButton && removeFriendButton) -		{ -			addFriendButton->setEnabled(!isFriend); -			removeFriendButton->setEnabled(isFriend); -		} -	} +        if (mIsFriendSignal) +        { +            bool isFriend = *(*mIsFriendSignal)(LLUUID(LLUrlAction::getUserID(url))); +            LLView* addFriendButton = menu->getChild<LLView>("add_friend"); +            LLView* removeFriendButton = menu->getChild<LLView>("remove_friend"); -	if (mIsObjectBlockedSignal) -	{ -		bool is_blocked = *(*mIsObjectBlockedSignal)(LLUUID(LLUrlAction::getObjectId(url)), LLUrlAction::getObjectName(url)); -		LLView* blockButton = mPopupMenu->getChild<LLView>("block_object"); -		LLView* unblockButton = mPopupMenu->getChild<LLView>("unblock_object"); +            if (addFriendButton && removeFriendButton) +            { +                addFriendButton->setEnabled(!isFriend); +                removeFriendButton->setEnabled(isFriend); +            } +        } -		if (blockButton && unblockButton) -		{ -			blockButton->setVisible(!is_blocked); -			unblockButton->setVisible(is_blocked); -		} -	} -	 -	if (mPopupMenu) -	{ -		mPopupMenu->show(x, y); -		LLMenuGL::showPopup(this, mPopupMenu, x, y); -	} +        if (mIsObjectBlockedSignal) +        { +            bool is_blocked = *(*mIsObjectBlockedSignal)(LLUUID(LLUrlAction::getObjectId(url)), LLUrlAction::getObjectName(url)); +            LLView* blockButton = menu->getChild<LLView>("block_object"); +            LLView* unblockButton = menu->getChild<LLView>("unblock_object"); + +            if (blockButton && unblockButton) +            { +                blockButton->setVisible(!is_blocked); +                unblockButton->setVisible(is_blocked); +            } +        } +        menu->show(x, y); +        LLMenuGL::showPopup(this, menu, x, y); +    }  }  void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 85641fd899..3d3a6ca869 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -673,7 +673,7 @@ protected:  	S32							mMaxTextByteLength;	// Maximum length mText is allowed to be in bytes  	// support widgets -	LLContextMenu*				mPopupMenu; +	LLHandle<LLContextMenu>		mPopupMenuHandle;  	LLView*						mDocumentView;  	LLScrollContainer*			mScroller; diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 324ceb7fba..bfe0a5bb5d 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -328,6 +328,15 @@ namespace LLTextValidate  		return rv;  	} +	bool validateASCIINoLeadingSpace(const LLWString &str) +	{ +		if (LLStringOps::isSpace(str[0])) +		{ +			return FALSE; +		} +		return validateASCII(str); +	} +  	// Used for multiline text stored on the server.  	// Example is landmark description in Places SP.  	bool validateASCIIWithNewLine(const LLWString &str) diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index 5c830d7db3..e2b6c313d6 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -52,6 +52,7 @@ namespace LLTextValidate  	bool	validateASCIIPrintableNoPipe(const LLWString &str);   	bool	validateASCIIPrintableNoSpace(const LLWString &str);  	bool	validateASCII(const LLWString &str); +	bool	validateASCIINoLeadingSpace(const LLWString &str);  	bool	validateASCIIWithNewLine(const LLWString &str);  } diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index aabc7ed2e4..f790d8e005 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -522,7 +522,7 @@ const LLView* LLUI::resolvePath(const LLView* context, const std::string& path)  		else  		{  			std::string part(ti->begin(), ti->end()); -			context = context->findChildView(part, recurse); +			context = context->findChildView(LLURI::unescape(part), recurse);  			recurse = false;  		}  	} diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index e4848362a7..27a2456deb 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -183,8 +183,9 @@ bool LLUrlEntryBase::isLinkDisabled() const  bool LLUrlEntryBase::isWikiLinkCorrect(std::string url)  { -	std::string label = getLabelFromWikiLink(url); -	return (LLUrlRegistry::instance().hasUrl(label)) ? false : true; +	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 @@ -205,9 +206,15 @@ std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const  	std::string label;  	up.extractParts(); -	up.glueFirst(label); -	std::string query = url.substr(label.size()); -	return query; +	up.glueFirst(label, false); + +	size_t pos = url.find(label); +	if (pos == std::string::npos) +	{ +		return ""; +	} +	pos += label.size(); +	return url.substr(pos);  } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index fd7406b653..9604e5ce10 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -391,7 +391,27 @@ static void buildPathname(std::ostream& out, const LLView* view)  	buildPathname(out, view->getParent());  	// Build pathname into ostream on the way back from recursion. -	out << '/' << view->getName(); +	out << '/'; + +	// substitute all '/' in name with appropriate code +	std::string name = view->getName(); +	std::size_t found = name.find('/'); +	std::size_t start = 0; +	while (found != std::string::npos) +	{ +		std::size_t sub_len = found - start; +		if (sub_len > 0) +		{ +			out << name.substr(start, sub_len); +		} +		out << "%2F"; +		start = found + 1; +		found = name.find('/', start); +	} +	if (start < name.size()) +	{ +		out << name.substr(start, name.size() - start); +	}  }  std::string LLView::getPathname() const diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 5f4fb8f4a0..86a15f2ef2 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -531,6 +531,13 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd  	case LL_PATH_PER_ACCOUNT_CHAT_LOGS:  		prefix = getPerAccountChatLogsDir(); +		if (prefix.empty()) +		{ +			// potentially directory was not set yet +			// intentionally return a blank string to the caller +			LL_DEBUGS("LLDir") << "Conversation log directory is not yet set" << LL_ENDL; +			return std::string(); +		}  		break;  	case LL_PATH_LOGS: diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 0a30f4c807..a05ba8cbba 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -166,6 +166,8 @@ public:  	// Provide native key event data  	virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } +	// Get system UI size based on DPI (for 96 DPI UI size should be 1.0) +	virtual F32 getSystemUISize() { return 1.0; }  protected:  	LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags);  	virtual ~LLWindow(); diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index d2afb3f91b..474953d3a4 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -175,6 +175,11 @@ BOOL LLWindowCallbacks::handleDeviceChange(LLWindow *window)  	return FALSE;  } +void LLWindowCallbacks::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) +{ + +} +  void LLWindowCallbacks::handlePingWatchdog(LLWindow *window, const char * msg)  { diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 6a7137e593..de789a71d9 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -65,6 +65,7 @@ public:  	virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data);  	virtual BOOL handleTimerEvent(LLWindow *window);  	virtual BOOL handleDeviceChange(LLWindow *window); +	virtual void handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height);  	enum DragNDropAction {  		DNDA_START_TRACKING = 0,// Start tracking an incoming drag diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 875ffe4cd4..4086db8e52 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -60,24 +60,50 @@  #include <dinput.h>  #include <Dbt.h.> -// culled from winuser.h -#ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ -const S32	WM_MOUSEWHEEL = 0x020A; -#endif -#ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */ -const S32	WHEEL_DELTA = 120;     /* Value for rolling one detent */ -#endif  const S32	MAX_MESSAGE_PER_UPDATE = 20;  const S32	BITS_PER_PIXEL = 32;  const S32	MAX_NUM_RESOLUTIONS = 32;  const F32	ICON_FLASH_TIME = 0.5f; +#ifndef WM_DPICHANGED +#define WM_DPICHANGED 0x02E0 +#endif +  extern BOOL gDebugWindowProc;  LPWSTR gIconResource = IDI_APPLICATION;  LLW32MsgCallback gAsyncMsgCallback = NULL; +#ifndef DPI_ENUMS_DECLARED + +typedef enum PROCESS_DPI_AWARENESS { +	PROCESS_DPI_UNAWARE = 0, +	PROCESS_SYSTEM_DPI_AWARE = 1, +	PROCESS_PER_MONITOR_DPI_AWARE = 2 +} PROCESS_DPI_AWARENESS; + +typedef enum MONITOR_DPI_TYPE { +	MDT_EFFECTIVE_DPI = 0, +	MDT_ANGULAR_DPI = 1, +	MDT_RAW_DPI = 2, +	MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; + +#endif + +typedef HRESULT(STDAPICALLTYPE *SetProcessDpiAwarenessType)(_In_ PROCESS_DPI_AWARENESS value); + +typedef HRESULT(STDAPICALLTYPE *GetProcessDpiAwarenessType)( +	_In_ HANDLE hprocess, +	_Out_ PROCESS_DPI_AWARENESS *value); + +typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( +	_In_ HMONITOR hmonitor, +	_In_ MONITOR_DPI_TYPE dpiType, +	_Out_ UINT *dpiX, +	_Out_ UINT *dpiY); +  //  // LLWindowWin32  // @@ -2593,6 +2619,24 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_  				return 0;  			} +         +		case WM_DPICHANGED: +			{ +				LPRECT lprc_new_scale; +				F32 new_scale = LOWORD(w_param) / USER_DEFAULT_SCREEN_DPI; +				lprc_new_scale = (LPRECT)l_param; +				S32 new_width = lprc_new_scale->right - lprc_new_scale->left; +				S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top; +				window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height); +				SetWindowPos(h_wnd, +					HWND_TOP, +					lprc_new_scale->left, +					lprc_new_scale->top, +					new_width, +					new_height, +					SWP_NOZORDER | SWP_NOACTIVATE); +					return 0; +			}  		case WM_SETFOCUS:  			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); @@ -3879,6 +3923,92 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)  }  //static +void LLWindowWin32::setDPIAwareness() +{ +	HMODULE hShcore = LoadLibrary(L"shcore.dll"); +	if (hShcore != NULL) +	{ +		SetProcessDpiAwarenessType pSPDA; +		pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness"); +		if (pSPDA) +		{ +			 +			HRESULT hr = pSPDA(PROCESS_PER_MONITOR_DPI_AWARE); +			if (hr != S_OK) +			{ +				LL_WARNS() << "SetProcessDpiAwareness() function returned an error. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; +			} +		} +		FreeLibrary(hShcore);	 +	} +	else +	{ +		LL_WARNS() << "Could not load shcore.dll library (included by <ShellScalingAPI.h> from Win 8.1 SDK. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; +	} +} + +F32 LLWindowWin32::getSystemUISize() +{ +	float scale_value = 0; +	HWND hWnd = (HWND)getPlatformWindow(); +	HDC hdc = GetDC(hWnd); +	HMONITOR hMonitor; +	HANDLE hProcess = GetCurrentProcess(); +	PROCESS_DPI_AWARENESS dpi_awareness; + +	HMODULE hShcore = LoadLibrary(L"shcore.dll"); + +	if (hShcore != NULL) +	{ +		GetProcessDpiAwarenessType pGPDA; +		pGPDA = (GetProcessDpiAwarenessType)GetProcAddress(hShcore, "GetProcessDpiAwareness"); +		GetDpiForMonitorType pGDFM; +		pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor"); +		if (pGPDA != NULL && pGDFM != NULL) +		{ +			pGPDA(hProcess, &dpi_awareness); +			if (dpi_awareness == PROCESS_PER_MONITOR_DPI_AWARE) +			{ +				POINT    pt; +				UINT     dpix = 0, dpiy = 0; +				HRESULT  hr = E_FAIL; +				RECT     rect; + +				GetWindowRect(hWnd, &rect); +				// Get the DPI for the monitor, on which the center of window is displayed and set the scaling factor +				pt.x = (rect.left + rect.right) / 2; +				pt.y = (rect.top + rect.bottom) / 2; +				hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); +				hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy); +				if (hr == S_OK) +				{ +					scale_value = dpix / USER_DEFAULT_SCREEN_DPI; +				} +				else +				{ +					LL_WARNS() << "Could not determine DPI for monitor. Setting scale to default 100 %" << LL_ENDL; +					scale_value = 1.0f; +				} +			} +			else +			{ +				LL_WARNS() << "Process is not per-monitor DPI-aware. Setting scale to default 100 %" << LL_ENDL; +				scale_value = 1.0f; +			} +		} +		FreeLibrary(hShcore); +	} +	else +	{ +		LL_WARNS() << "Could not load shcore.dll library (included by <ShellScalingAPI.h> from Win 8.1 SDK). Using legacy DPI awareness API of Win XP/7" << LL_ENDL; +		scale_value = GetDeviceCaps(hdc, LOGPIXELSX) / USER_DEFAULT_SCREEN_DPI; +	} + +	ReleaseDC(hWnd, hdc); +	return scale_value; +} + +//static  std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()  {  	// Fonts previously in getFontListSans() have moved to fonts.xml. diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 1a775eadaf..39ef9b31a4 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -110,10 +110,12 @@ public:  	/*virtual*/ void interruptLanguageTextInput();  	/*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); +	/*virtual*/ F32 getSystemUISize(); +  	LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url );  	static std::vector<std::string> getDynamicFallbackFontList(); - +	static void setDPIAwareness();  protected:  	LLWindowWin32(LLWindowCallbacks* callbacks,  		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,  diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 28a8a5886a..4eb29c98f9 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -501,6 +501,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)  				LLCEFLib::LLCEFLibSettings settings;  				settings.initial_width = 1024;  				settings.initial_height = 1024; +				settings.page_zoom_factor = message_in.getValueReal("factor");  				settings.plugins_enabled = mPluginsEnabled;  				settings.media_stream_enabled = false; // MAINT-6060 - WebRTC media removed until we can add granualrity/query UI  				settings.javascript_enabled = mJavascriptEnabled; diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 4d0dcda01c..de197cc337 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -4.1.2 +4.1.3 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 53a826bc18..e12b8cfecd 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4515,28 +4515,6 @@        <key>Value</key>        <string>http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD]</string>      </map> -    <key>WebProfileURL</key> -    <map> -      <key>Comment</key> -      <string>URL for Web Profiles</string> -      <key>Persist</key> -      <integer>0</integer> -      <key>Type</key> -      <string>String</string> -      <key>Value</key> -      <string>https://my.secondlife.com/[AGENT_NAME]</string> -    </map> -	<key>WebProfileNonProductionURL</key> -	<map> -		<key>Comment</key> -		<string>URL for Web Profiles on Non-Production grids</string> -		<key>Persist</key> -		<integer>0</integer> -		<key>Type</key> -		<string>String</string> -		<key>Value</key> -		<string>https://my-demo.secondlife.com/[AGENT_NAME]</string> -	</map>      <key>HighResSnapshot</key>      <map>        <key>Comment</key> @@ -4881,7 +4859,7 @@      <key>InventoryTrashMaxCapacity</key>      <map>          <key>Comment</key> -        <string>Maximum capacity of the Trash folder. User will ve offered to clean it up when exceeded.</string> +        <string>Maximum capacity of the Trash folder. User will be offered to clean it up when exceeded.</string>          <key>Persist</key>          <integer>1</integer>          <key>Type</key> @@ -7940,6 +7918,17 @@        <key>Value</key>        <integer>100000</integer>      </map> +    <key>PrimTextMaxDrawDistance</key> +    <map> +      <key>Comment</key> +      <string>Maximum draw distance beyond which PRIM_TEXT won't be rendered</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>64.0</real> +    </map>      <key>ProbeHardwareOnStartup</key>      <map>        <key>Comment</key> @@ -10092,6 +10081,17 @@      <key>Value</key>      <integer>10</integer>    </map> +  <key>ComplexityChangesPopUpDelay</key> +  <map> +    <key>Comment</key> +    <string>Delay before viewer will show avatar complexity notice again</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>U32</string> +    <key>Value</key> +    <integer>300</integer> +  </map>    <key>RenderAvatarMaxComplexity</key>    <map>      <key>Comment</key> @@ -10104,6 +10104,50 @@      <key>Value</key>      <integer>0</integer>    </map> +  <key>RenderHUDObjectsWarning</key> +  <map> +    <key>Comment</key> +    <string>Viewer will warn user about HUD containing to many objects if objects count is above this value</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>U32</string> +    <key>Value</key> +    <integer>1000</integer> +  </map> +  <key>RenderHUDTexturesWarning</key> +  <map> +    <key>Comment</key> +    <string>Viewer will warn user about HUD containing to many textures if texture count is above this value</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>U32</string> +    <key>Value</key> +    <integer>200</integer> +  </map> +  <key>RenderHUDOversizedTexturesWarning</key> +  <map> +    <key>Comment</key> +    <string>How many textures with size 1024 * 1024 or bigger HUD can contain before notifying user</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>U32</string> +    <key>Value</key> +    <integer>6</integer> +  </map> +  <key>RenderHUDTexturesMemoryWarning</key> +  <map> +    <key>Comment</key> +    <string>Viewer will warn user about HUD textures using memory above this value (in bytes)</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>U32</string> +    <key>Value</key> +    <integer>32000000</integer> +  </map>    <key>RenderAutoMuteSurfaceAreaLimit</key>    <map>      <key>Comment</key> @@ -12792,6 +12836,17 @@        <key>Value</key>        <real>1.0</real>      </map> +    <key>LastSystemUIScaleFactor</key> +    <map> +      <key>Comment</key> +      <string>Size of system UI during last run. On Windows 100% (96 DPI) system setting is 1.0 UI size</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.0</real> +    </map>      <key>UIScrollbarSize</key>      <map>        <key>Comment</key> @@ -13287,6 +13342,17 @@        <key>Value</key>        <string>1</string>      </map> +    <key>UpdaterShowReleaseNotes</key> +    <map> +        <key>Comment</key> +        <string>Enables displaying of the Release notes in a web floater after update.</string> +        <key>Persist</key> +        <integer>1</integer> +        <key>Type</key> +        <string>Boolean</string> +        <key>Value</key> +        <integer>1</integer> +    </map>      <key>UploadBakedTexOld</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index d933537d2e..d8b0787852 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3895,11 +3895,17 @@ void LLAgent::handleTeleportFinished()  		mIsMaturityRatingChangingDuringTeleport = false;  	} -    // Init SLM Marketplace connection so we know which UI should be used for the user as a merchant -    // Note: Eventually, all merchant will be migrated to the new SLM system and there will be no reason to show the old UI at all. -    // Note: Some regions will not support the SLM cap for a while so we need to do that check for each teleport. -    // *TODO : Suppress that line from here once the whole grid migrated to SLM and move it to idle_startup() (llstartup.cpp) -    check_merchant_status(); +    if (mRegionp) +    { +        if (mRegionp->capabilitiesReceived()) +        { +            onCapabilitiesReceivedAfterTeleport(); +        } +        else +        { +            mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::onCapabilitiesReceivedAfterTeleport)); +        } +    }  }  void LLAgent::handleTeleportFailed() @@ -3931,6 +3937,14 @@ void LLAgent::handleTeleportFailed()  	}  } +/*static*/ +void LLAgent::onCapabilitiesReceivedAfterTeleport() +{ + +    check_merchant_status(); +} + +  void LLAgent::teleportRequest(  	const U64& region_handle,  	const LLVector3& pos_local, diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 3a533c2cba..d82ff7a67f 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -676,6 +676,8 @@ private:  	void            handleTeleportFinished();  	void            handleTeleportFailed(); +    static void     onCapabilitiesReceivedAfterTeleport(); +  	//--------------------------------------------------------------------  	// Teleport State  	//-------------------------------------------------------------------- diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index b76a66ab39..170e4063a1 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -62,23 +62,37 @@ using namespace LLAvatarAppearanceDefines;  /////////////////////////////////////////////////////////////////////////////// -// Callback to wear and start editing an item that has just been created. -void wear_and_edit_cb(const LLUUID& inv_item) +void set_default_permissions(LLViewerInventoryItem* item)  { -	if (inv_item.isNull()) return; -	 -		LLViewerInventoryItem* item = gInventory.getItem(inv_item); -		if (!item) return; - -		LLPermissions perm = item->getPermissions(); +	llassert(item); +	LLPermissions perm = item->getPermissions(); +	if (perm.getMaskNextOwner() != LLFloaterPerms::getNextOwnerPerms("Wearables") +		|| perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms("Wearables") +		|| perm.getMaskGroup() != LLFloaterPerms::getGroupPerms("Wearables")) +	{  		perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables"));  		perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables"));  		perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables")); +  		item->setPermissions(perm);  		item->updateServer(FALSE); -		gInventory.updateItem(item); -		gInventory.notifyObservers(); +	} +} + +// Callback to wear and start editing an item that has just been created. +void wear_and_edit_cb(const LLUUID& inv_item) +{ +	if (inv_item.isNull()) return; +	 +	LLViewerInventoryItem* item = gInventory.getItem(inv_item); +	if (!item) return; + +	set_default_permissions(item); + +	// item was just created, update even if permissions did not changed +	gInventory.updateItem(item); +	gInventory.notifyObservers();  	// Request editing the item after it gets worn.  	gAgentWearables.requestEditingWearable(inv_item); @@ -94,13 +108,8 @@ void wear_cb(const LLUUID& inv_item)  		LLViewerInventoryItem* item = gInventory.getItem(inv_item);  		if (item)  		{ -			LLPermissions perm = item->getPermissions(); -			perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables")); -			perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables")); -			perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables")); -			item->setPermissions(perm); +			set_default_permissions(item); -			item->updateServer(FALSE);  			gInventory.updateItem(item);  			gInventory.notifyObservers();  		} @@ -253,6 +262,7 @@ void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& i  	{  		LLAppearanceMgr::instance().addCOFItemLink(inv_item,   			new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription); +		editWearable(inv_item);  	}  } @@ -423,7 +433,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type,  	// old_wearable may still be referred to by other inventory items. Revert  	// unsaved changes so other inventory items aren't affected by the changes  	// that were just saved. -	old_wearable->revertValues(); +	old_wearable->revertValuesWithoutUpdate();  }  void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index) @@ -1364,6 +1374,30 @@ void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array  	// LL_INFOS() << "remove " << remove_count << " add " << add_count << LL_ENDL;  } +std::vector<LLViewerObject*> LLAgentWearables::getTempAttachments() +{ +	llvo_vec_t temp_attachs; +	if (isAgentAvatarValid()) +	{ +		for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); iter != gAgentAvatarp->mAttachmentPoints.end();) +		{ +			LLVOAvatar::attachment_map_t::iterator curiter = iter++; +			LLViewerJointAttachment* attachment = curiter->second; +			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +				attachment_iter != attachment->mAttachedObjects.end(); +				++attachment_iter) +			{ +				LLViewerObject *objectp = (*attachment_iter); +				if (objectp && objectp->isTempAttachment()) +				{ +					temp_attachs.push_back(objectp); +				} +			} +		} +	} +	return temp_attachs; +} +  void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove)  {  	if (!isAgentAvatarValid()) return; diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 1004482020..b27698fd8f 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -185,6 +185,8 @@ public:  	static void		userRemoveMultipleAttachments(llvo_vec_t& llvo_array);  	static void		userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); +	static llvo_vec_t getTempAttachments(); +  	//--------------------------------------------------------------------  	// Signals  	//-------------------------------------------------------------------- diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index ff5439d610..92e3cd0279 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1875,15 +1875,15 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)  		return false;  	} -	// Check whether the outfit contains any wearables we aren't wearing already (STORM-702). +	// Check whether the outfit contains any wearables  	LLInventoryModel::cat_array_t cats;  	LLInventoryModel::item_array_t items; -	LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); +	LLFindWearables is_wearable;  	gInventory.collectDescendentsIf(outfit_cat_id,  		cats,  		items,  		LLInventoryModel::EXCLUDE_TRASH, -		is_worn); +		is_wearable);  	return items.size() > 0;  } @@ -3477,13 +3477,13 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd          }          else          { -            if (cofVersion < lastRcv) +            if (cofVersion <= lastRcv)              {                  LL_WARNS("Avatar") << "Have already received update for cof version " << lastRcv                      << " but requesting for " << cofVersion << LL_ENDL;                  return;              } -            if (lastReq > cofVersion) +            if (lastReq >= cofVersion)              {                  LL_WARNS("Avatar") << "Request already in flight for cof version " << lastReq                      << " but requesting for " << cofVersion << LL_ENDL; @@ -3503,7 +3503,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd              LL_WARNS("Avatar") << "Forcing version failure on COF Baking" << LL_ENDL;          } -        LL_INFOS() << "Requesting bake for COF version " << cofVersion << LL_ENDL; +        LL_INFOS("Avatar") << "Requesting bake for COF version " << cofVersion << LL_ENDL;          LLSD postData;          if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) @@ -3969,6 +3969,10 @@ void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)  	LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL;  	mAttachmentInvLinkEnabled = val;  } +boost::signals2::connection LLAppearanceMgr::setAttachmentsChangedCallback(attachments_changed_callback_t cb) +{ +	return mAttachmentsChangeSignal.connect(cb); +}  void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)  { @@ -3995,6 +3999,8 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)  	gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);  	LLAttachmentsMgr::instance().onAttachmentArrived(item_id); + +	mAttachmentsChangeSignal();  }  void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) @@ -4015,6 +4021,8 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)  	{  		//LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL;  	} + +	mAttachmentsChangeSignal();  }  BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 2e570b9188..f0d3f80f59 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -229,6 +229,10 @@ public:  	void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; }  	std::string getAppearanceServiceURL() const; +	typedef boost::function<void ()> attachments_changed_callback_t; +	typedef boost::signals2::signal<void ()> attachments_changed_signal_t; +	boost::signals2::connection setAttachmentsChangedCallback(attachments_changed_callback_t cb); +  private: @@ -272,6 +276,8 @@ private:  	LLTimer mInFlightTimer;  	static bool mActive; +	attachments_changed_signal_t		mAttachmentsChangeSignal; +	  	LLUUID mCOFImageID;  	std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 76d0d46997..9db03a7438 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -701,7 +701,8 @@ LLAppViewer::LLAppViewer()  	mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),  	mFastTimerLogThread(NULL),  	mUpdater(new LLUpdaterService()), -	mSettingsLocationList(NULL) +	mSettingsLocationList(NULL), +	mIsFirstRun(false)  {  	if(NULL != sInstance)  	{ @@ -1124,17 +1125,23 @@ bool LLAppViewer::init()  #if LL_WINDOWS  	if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion())  	{ +		std::string url;  		if (gGLManager.mIsIntel)  		{ -			LLNotificationsUtil::add("IntelOldDriver"); +			url = LLTrans::getString("IntelDriverPage");  		}  		else if (gGLManager.mIsNVIDIA)  		{ -			LLNotificationsUtil::add("NVIDIAOldDriver"); +			url = LLTrans::getString("NvidiaDriverPage");  		}  		else if (gGLManager.mIsATI)  		{ -			LLNotificationsUtil::add("AMDOldDriver"); +			url = LLTrans::getString("AMDDriverPage"); +		} + +		if (!url.empty()) +		{ +			LLNotificationsUtil::add("OldGPUDriver", LLSD().with("URL", url));  		}  	}  #endif @@ -1222,6 +1229,8 @@ bool LLAppViewer::init()          boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1),          boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS)); +	showReleaseNotesIfRequired(); +  	/*----------------------------------------------------------------------*/  	// nat 2016-06-29 moved the following here from the former mainLoop().  	mMainloopTimeout = new LLWatchdogTimeout(); @@ -2473,7 +2482,10 @@ bool LLAppViewer::initConfiguration()  	if (gSavedSettings.getBOOL("FirstRunThisInstall"))  	{ -		// Note that the "FirstRunThisInstall" settings is currently unused. +		// Set firstrun flag to indicate that some further init actiona should be taken  +		// like determining screen DPI value and so on +		mIsFirstRun = true; +  		gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);  	} @@ -3130,7 +3142,8 @@ bool LLAppViewer::initWindow()  		.min_width(gSavedSettings.getU32("MinWindowWidth"))  		.min_height(gSavedSettings.getU32("MinWindowHeight"))  		.fullscreen(gSavedSettings.getBOOL("FullScreen")) -		.ignore_pixel_depth(ignorePixelDepth); +		.ignore_pixel_depth(ignorePixelDepth) +		.first_run(mIsFirstRun);  	gViewerWindow = new LLViewerWindow(window_params); @@ -5801,6 +5814,20 @@ void LLAppViewer::launchUpdater()  	// LLAppViewer::instance()->forceQuit();  } +/** +* Check if user is running a new version of the viewer. +* Display the Release Notes if it's not overriden by the "UpdaterShowReleaseNotes" setting. +*/ +void LLAppViewer::showReleaseNotesIfRequired() +{ +	if (LLVersionInfo::getChannelAndVersion() != gLastRunVersion +		&& gSavedSettings.getBOOL("UpdaterShowReleaseNotes") +		&& !gSavedSettings.getBOOL("FirstLoginThisInstall")) +	{ +		LLSD info(getViewerInfo()); +		LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]); +	} +}  //virtual  void LLAppViewer::setMasterSystemAudioMute(bool mute) diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index f7c1bb58b4..948d316009 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -254,6 +254,8 @@ private:      void sendLogoutRequest();      void disconnectViewer(); + +	void showReleaseNotesIfRequired();  	// *FIX: the app viewer class should be some sort of singleton, no?  	// Perhaps its child class is the singleton and this should be an abstract base. @@ -315,6 +317,7 @@ private:  	// llcorehttp library init/shutdown helper  	LLAppCoreHttp mAppCoreHttp; +	bool mIsFirstRun;  	//---------------------------------------------  	//*NOTE: Mani - legacy updater stuff  	// Still useable? diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index af0cd27fd5..5107030476 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -231,6 +231,8 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,  	DWORD heap_enable_lfh_error[MAX_HEAPS];  	S32 num_heaps = 0; +	LLWindowWin32::setDPIAwareness(); +  #if WINDOWS_CRT_MEM_CHECKS && !INCLUDE_VLD  	_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); // dump memory leaks on exit  #elif 0 @@ -567,7 +569,7 @@ bool LLAppViewerWin32::initHardwareTest()  	// Do driver verification and initialization based on DirectX  	// hardware polling and driver versions  	// -	if (FALSE == gSavedSettings.getBOOL("NoHardwareProbe")) +	if (TRUE == gSavedSettings.getBOOL("ProbeHardwareOnStartup") && FALSE == gSavedSettings.getBOOL("NoHardwareProbe"))  	{  		// per DEV-11631 - disable hardware probing for everything  		// but vram. diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index a6e745448a..7b8c630837 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -950,15 +950,22 @@ bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NUL  	const std::set<LLFolderViewItem*> inventory_selected = root_folder->getSelectionList();  	if (inventory_selected.empty()) return false; // nothing selected +	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);  	bool can_share = true;  	std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin();  	const std::set<LLFolderViewItem*>::const_iterator it_end = inventory_selected.end();  	for (; it != it_end; ++it)  	{ -		LLViewerInventoryCategory* inv_cat = gInventory.getCategory(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); -		// any category can be offered. +		LLUUID cat_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID(); +		LLViewerInventoryCategory* inv_cat = gInventory.getCategory(cat_id); +		// any category can be offered if it's not in trash.  		if (inv_cat)  		{ +			if ((cat_id == trash_id) || gInventory.isObjectDescendentOf(cat_id, trash_id)) +			{ +				can_share = false; +				break; +			}  			continue;  		} diff --git a/indra/newview/llavatarrendernotifier.cpp b/indra/newview/llavatarrendernotifier.cpp index 24934fdb73..94584a623b 100644 --- a/indra/newview/llavatarrendernotifier.cpp +++ b/indra/newview/llavatarrendernotifier.cpp @@ -38,6 +38,7 @@  #include "llnotifications.h"  #include "llnotificationsutil.h"  #include "llnotificationtemplate.h" +#include "llslurl.h"  #include "lltimer.h"  #include "llvoavatarself.h"  #include "llviewercontrol.h" @@ -51,6 +52,11 @@ static const F32 RENDER_ALLOWED_CHANGE_PCT = 0.1;  // wait seconds before processing over limit updates after last complexity change  static const U32 OVER_LIMIT_UPDATE_DELAY = 70; +static const U32 WARN_HUD_OBJECTS_LIMIT = 1000; +static const U32 WARN_HUD_TEXTURES_LIMIT = 200; +static const U32 WARN_HUD_OVERSIZED_TEXTURES_LIMIT = 6; +static const U32 WARN_HUD_TEXTURE_MEMORY_LIMIT = 32000000; // in bytes +  LLAvatarRenderNotifier::LLAvatarRenderNotifier() :  mAgentsCount(0), @@ -264,3 +270,220 @@ void LLAvatarRenderNotifier::updateNotificationAgent(U32 agentComplexity)      }  } +// LLHUDRenderNotifier + +static const char* e_hud_messages[] = +{ +    "hud_render_textures_warning", +    "hud_render_cramped_warning", +    "hud_render_heavy_textures_warning", +    "hud_render_cost_warning", +    "hud_render_memory_warning", +}; + +LLHUDRenderNotifier::LLHUDRenderNotifier() : +mReportedHUDWarning(WARN_NONE) +{ +} + +LLHUDRenderNotifier::~LLHUDRenderNotifier() +{ +} + +void LLHUDRenderNotifier::updateNotificationHUD(hud_complexity_list_t complexity) +{ +    if (!isAgentAvatarValid() || !gAgentWearables.areWearablesLoaded()) +    { +        // data not ready. +        return; +    } + +    // TODO: +    // Find a way to show message with list of issues, but without making it too large +    // and intrusive. + +    LLHUDComplexity new_total_complexity; +    LLHUDComplexity report_complexity; + +    hud_complexity_list_t::iterator iter = complexity.begin(); +    hud_complexity_list_t::iterator end = complexity.end(); +    EWarnLevel warning_level = WARN_NONE; +    for (; iter != end; ++iter) +    { +        LLHUDComplexity object_complexity = *iter; +        EWarnLevel object_level = getWarningType(object_complexity, report_complexity); +        if (object_level >= 0) +        { +            warning_level = object_level; +            report_complexity = object_complexity; +        } +        new_total_complexity.objectsCost += object_complexity.objectsCost; +        new_total_complexity.objectsCount += object_complexity.objectsCount; +        new_total_complexity.texturesCost += object_complexity.texturesCost; +        new_total_complexity.texturesCount += object_complexity.texturesCount; +        new_total_complexity.largeTexturesCount += object_complexity.largeTexturesCount; +        new_total_complexity.texturesMemoryTotal += object_complexity.texturesMemoryTotal; +    } + +    if (mHUDPopUpDelayTimer.hasExpired() || isNotificationVisible()) +    { +        if (warning_level >= 0) +        { +            // Display info about most complex HUD object +            // make sure it shown only once unless object's complexity or object itself changed +            if (mReportedHUDComplexity.objectId != report_complexity.objectId +                || mReportedHUDWarning != warning_level) +            { +                displayHUDNotification(warning_level, report_complexity.objectId, report_complexity.objectName, report_complexity.jointName); +                mReportedHUDComplexity = report_complexity; +                mReportedHUDWarning = warning_level; +            } +        } +        else +        { +            // Check if total complexity is above threshold and above previous warning +            // Show warning with highest importance (5m delay between warnings by default) +            if (!mReportedHUDComplexity.objectId.isNull()) +            { +                mReportedHUDComplexity.reset(); +                mReportedHUDWarning = WARN_NONE; +            } + +            warning_level = getWarningType(new_total_complexity, mReportedHUDComplexity); +            if (warning_level >= 0 && mReportedHUDWarning != warning_level) +            { +                displayHUDNotification(warning_level); +            } +            mReportedHUDComplexity = new_total_complexity; +            mReportedHUDWarning = warning_level; +        } +    } +    else if (warning_level >= 0) +    { +        LL_DEBUGS("HUDdetail") << "HUD individual warning postponed" << LL_ENDL; +    } + +    if (mLatestHUDComplexity.objectsCost != new_total_complexity.objectsCost +        || mLatestHUDComplexity.objectsCount != new_total_complexity.objectsCount +        || mLatestHUDComplexity.texturesCost != new_total_complexity.texturesCost +        || mLatestHUDComplexity.texturesCount != new_total_complexity.texturesCount +        || mLatestHUDComplexity.largeTexturesCount != new_total_complexity.largeTexturesCount +        || mLatestHUDComplexity.texturesMemoryTotal != new_total_complexity.texturesMemoryTotal) +    { +        LL_INFOS("HUDdetail") << "HUD textures count: " << new_total_complexity.texturesCount +            << " HUD textures cost: " << new_total_complexity.texturesCost +            << " Large textures: " << new_total_complexity.largeTexturesCount +            << " HUD objects cost: " << new_total_complexity.objectsCost +            << " HUD objects count: " << new_total_complexity.objectsCount << LL_ENDL; + +        mLatestHUDComplexity = new_total_complexity; +    } +} + +bool LLHUDRenderNotifier::isNotificationVisible() +{ +    return mHUDNotificationPtr != NULL && mHUDNotificationPtr->isActive(); +} + +// private static +LLHUDRenderNotifier::EWarnLevel LLHUDRenderNotifier::getWarningType(LLHUDComplexity object_complexity, LLHUDComplexity cmp_complexity) +{ +    static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U); // ties max HUD cost to avatar cost +    static LLCachedControl<U32> max_objects_count(gSavedSettings, "RenderHUDObjectsWarning", WARN_HUD_OBJECTS_LIMIT); +    static LLCachedControl<U32> max_textures_count(gSavedSettings, "RenderHUDTexturesWarning", WARN_HUD_TEXTURES_LIMIT); +    static LLCachedControl<U32> max_oversized_count(gSavedSettings, "RenderHUDOversizedTexturesWarning", WARN_HUD_OVERSIZED_TEXTURES_LIMIT); +    static LLCachedControl<U32> max_texture_memory(gSavedSettings, "RenderHUDTexturesMemoryWarning", WARN_HUD_TEXTURE_MEMORY_LIMIT); + +    if (cmp_complexity.texturesMemoryTotal < object_complexity.texturesMemoryTotal +        && object_complexity.texturesMemoryTotal > (F64Bytes)max_texture_memory) +    { +        // Note: Memory might not be accurate since texture is still loading or discard level changes + +        LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " memory usage over limit, " +            << " was " << cmp_complexity.texturesMemoryTotal +            << " is " << object_complexity.texturesMemoryTotal << LL_ENDL; + +        return WARN_MEMORY; +    } +    else if ((cmp_complexity.objectsCost < object_complexity.objectsCost +        || cmp_complexity.texturesCost < object_complexity.texturesCost) +        && max_render_cost > 0 +        && object_complexity.objectsCost + object_complexity.texturesCost > max_render_cost) +    { +        LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " complexity over limit," +            << " HUD textures cost: " << object_complexity.texturesCost +            << " HUD objects cost: " << object_complexity.objectsCost << LL_ENDL; + +        return WARN_COST; +    } +    else if (cmp_complexity.largeTexturesCount < object_complexity.largeTexturesCount +        && object_complexity.largeTexturesCount > max_oversized_count) +    { +        LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains to many large textures: " +            << object_complexity.largeTexturesCount << LL_ENDL; + +        return WARN_HEAVY; +    } +    else if (cmp_complexity.texturesCount < object_complexity.texturesCount +        && object_complexity.texturesCount > max_textures_count) +    { +        LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains too many textures: " +            << object_complexity.texturesCount << LL_ENDL; + +        return WARN_CRAMPED; +    } +    else if (cmp_complexity.objectsCount < object_complexity.objectsCount +        && object_complexity.objectsCount > max_objects_count) +    { +        LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains too many objects: " +            << object_complexity.objectsCount << LL_ENDL; + +        return WARN_TEXTURES; +    } +    return WARN_NONE; +} + +void LLHUDRenderNotifier::displayHUDNotification(EWarnLevel warn_type, LLUUID obj_id, std::string obj_name, std::string joint_name) +{ +    static LLCachedControl<U32> pop_up_delay(gSavedSettings, "ComplexityChangesPopUpDelay", 300); +    static LLCachedControl<U32> expire_delay(gSavedSettings, "ShowMyComplexityChanges", 20); +    LLDate expire_date(LLDate::now().secondsSinceEpoch() + expire_delay); + +    // Since we need working "ignoretext" there is no other way but to +    // use single notification while constructing it from multiple pieces +    LLSD reason_args; +    if (obj_id.isNull()) +    { +        reason_args["HUD_DETAILS"] = LLTrans::getString("hud_description_total"); +    } +    else +    { +        if (obj_name.empty()) +        { +            LL_WARNS("HUDdetail") << "Object name not assigned" << LL_ENDL; +        } +        if (joint_name.empty()) +        { +            std::string verb = "select?name=" + LLURI::escape(obj_name); +            reason_args["HUD_DETAILS"] = LLSLURL("inventory", obj_id, verb.c_str()).getSLURLString(); +        } +        else +        { +            LLSD object_args; +            std::string verb = "select?name=" + LLURI::escape(obj_name); +            object_args["OBJ_NAME"] = LLSLURL("inventory", obj_id, verb.c_str()).getSLURLString(); +            object_args["JNT_NAME"] = LLTrans::getString(joint_name); +            reason_args["HUD_DETAILS"] = LLTrans::getString("hud_name_with_joint", object_args); +        } +    } + +    LLSD msg_args; +    msg_args["HUD_REASON"] = LLTrans::getString(e_hud_messages[warn_type], reason_args); + +    mHUDNotificationPtr = LLNotifications::instance().add(LLNotification::Params() +        .name("HUDComplexityWarning") +        .expiry(expire_date) +        .substitutions(msg_args)); +    mHUDPopUpDelayTimer.resetWithExpiry(pop_up_delay); +} + diff --git a/indra/newview/llavatarrendernotifier.h b/indra/newview/llavatarrendernotifier.h index 2a2704de28..a169baef40 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -33,6 +33,36 @@  class LLViewerRegion; +struct LLHUDComplexity +{ +    LLHUDComplexity() +    { +        reset(); +    } +    void reset() +    { +        objectId = LLUUID::null; +        objectName = ""; +        objectsCost = 0; +        objectsCount = 0; +        texturesCost = 0; +        texturesCount = 0; +        largeTexturesCount = 0; +        texturesMemoryTotal = (F64Bytes)0; +    } +    LLUUID objectId; +    std::string objectName; +    std::string jointName; +    U32 objectsCost; +    U32 objectsCount; +    U32 texturesCost; +    U32 texturesCount; +    U32 largeTexturesCount; +    F64Bytes texturesMemoryTotal; +}; + +typedef std::list<LLHUDComplexity> hud_complexity_list_t; +  // Class to notify user about drastic changes in agent's render weights or if other agents  // reported that user's agent is too 'heavy' for their settings  class LLAvatarRenderNotifier : public LLSingleton<LLAvatarRenderNotifier> @@ -81,4 +111,36 @@ private:      S32 mLastOutfitRezStatus;  }; +// Class to notify user about heavy set of HUD +class LLHUDRenderNotifier : public LLSingleton<LLHUDRenderNotifier> +{ +public: +    LLHUDRenderNotifier(); +    ~LLHUDRenderNotifier(); + +    void updateNotificationHUD(hud_complexity_list_t complexity); +    bool isNotificationVisible(); + +private: +    enum EWarnLevel +    { +        WARN_NONE = -1, +        WARN_TEXTURES = 0, // least important +        WARN_CRAMPED, +        WARN_HEAVY, +        WARN_COST, +        WARN_MEMORY, //most important +    }; + +    LLNotificationPtr mHUDNotificationPtr; + +    static EWarnLevel getWarningType(LLHUDComplexity object_complexity, LLHUDComplexity cmp_complexity); +    void displayHUDNotification(EWarnLevel warn_type, LLUUID obj_id = LLUUID::null,  std::string object_name = "", std::string joint_name = ""); + +    LLHUDComplexity mReportedHUDComplexity; +    EWarnLevel mReportedHUDWarning; +    LLHUDComplexity mLatestHUDComplexity; +    LLFrameTimer mHUDPopUpDelayTimer; +}; +  #endif /* ! defined(LL_llavatarrendernotifier_H) */ diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 00fa6dd979..54c6c985d6 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -311,7 +311,8 @@ LLWString LLChatBar::stripChannelNumber(const LLWString &mesg, S32* channel)  	}  	else if (mesg[0] == '/'  			 && mesg[1] -			 && LLStringOps::isDigit(mesg[1])) +			 && (LLStringOps::isDigit(mesg[1]) +				 || (mesg[1] == '-' && mesg[2] && LLStringOps::isDigit(mesg[2]))))  	{  		// This a special "/20" speak on a channel  		S32 pos = 0; @@ -325,7 +326,7 @@ LLWString LLChatBar::stripChannelNumber(const LLWString &mesg, S32* channel)  			channel_string.push_back(c);  			pos++;  		} -		while(c && pos < 64 && LLStringOps::isDigit(c)); +		while(c && pos < 64 && (LLStringOps::isDigit(c) || (pos == 1 && c == '-')));  		// Move the pointer forward to the first non-whitespace char  		// Check isspace before looping, so we can handle "/33foo" diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 05c7e6caa5..4e69896b69 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -448,7 +448,12 @@ bool LLConversationLog::moveLog(const std::string &originDirectory, const std::s  std::string LLConversationLog::getFileName()  {  	std::string filename = "conversation"; -	return gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename) + ".log"; +	std::string log_address = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename); +	if (!log_address.empty()) +	{ +		log_address += ".log"; +	} +	return log_address;  }  bool LLConversationLog::saveToFile(const std::string& filename) diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index bababca652..c2d0d9f06b 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -108,6 +108,7 @@ private:  	static const std::string sCheckUpdateListenerName;      static void startFetchServerReleaseNotes(); +    static void fetchServerReleaseNotesCoro(const std::string& cap_url);      static void handleServerReleaseNotes(LLSD results);  }; @@ -224,35 +225,62 @@ void LLFloaterAbout::startFetchServerReleaseNotes()      // an URL suitable for external browsers in the "Location:" HTTP header.      std::string cap_url = region->getCapability("ServerReleaseNotes"); -    LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(cap_url, -        &LLFloaterAbout::handleServerReleaseNotes, &LLFloaterAbout::handleServerReleaseNotes); +    LLCoros::instance().launch("fetchServerReleaseNotesCoro", boost::bind(&LLFloaterAbout::fetchServerReleaseNotesCoro, cap_url));  }  /*static*/ +void LLFloaterAbout::fetchServerReleaseNotesCoro(const std::string& cap_url) +{ +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("fetchServerReleaseNotesCoro", LLCore::HttpRequest::DEFAULT_POLICY_ID)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    LLSD result = httpAdapter->getAndSuspend(httpRequest, cap_url, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        handleServerReleaseNotes(httpResults); +    } +    else +    { +        handleServerReleaseNotes(result); +    } +} + +/*static*/  void LLFloaterAbout::handleServerReleaseNotes(LLSD results)  { -//     LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about"); -//     if (floater_about) -//     { -        LLSD http_headers; -        if (results.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS)) -        { -            LLSD http_results = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; -            http_headers = http_results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; -        } -        else -        { -            http_headers = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; -        } -         -        std::string location = http_headers[HTTP_IN_HEADER_LOCATION].asString(); -        if (location.empty()) -        { -            location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); -        } -        LLAppViewer::instance()->setServerReleaseNotesURL(location); -//    } +    LLSD http_headers; +    if (results.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS)) +    { +        LLSD http_results = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +        http_headers = http_results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; +    } +    else +    { +        http_headers = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; +    } + +    std::string location = http_headers[HTTP_IN_HEADER_LOCATION].asString(); +    if (location.empty()) +    { +        location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); +    } +    LLAppViewer::instance()->setServerReleaseNotesURL(location); + +    LLFloaterAbout* floater_about = LLFloaterReg::findTypedInstance<LLFloaterAbout>("sl_about"); +    if (floater_about) +    { +        floater_about->setSupportText(location); +    }  }  class LLFloaterAboutListener: public LLEventAPI diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 72892b47a4..aa7bfbfdb7 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -55,6 +55,8 @@  //#include "llsdserialize.h" +static const U32 AVATAR_PICKER_SEARCH_TIMEOUT = 180U; +  //put it back as a member once the legacy path is out?  static std::map<LLUUID, LLAvatarName> sAvatarNameMap; @@ -463,10 +465,13 @@ void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::strin      LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t          httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));      LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);      LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; -    LLSD result = httpAdapter->getAndSuspend(httpRequest, url); +    httpOpts->setTimeout(AVATAR_PICKER_SEARCH_TIMEOUT); + +    LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);      LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];      LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index e21a8594bc..91436e52fe 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -280,7 +280,7 @@ void LLFloaterBuyCurrencyUI::onClickCancel()  void LLFloaterBuyCurrencyUI::onClickErrorWeb()  { -	LLWeb::loadURLExternal(mManager.errorURI()); +	LLWeb::loadURL(mManager.errorURI());  	closeFloater();  	// Update L$ balance  	LLStatusBar::sendMoneyBalanceRequest(); diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index d842106146..b840d37c4d 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -328,7 +328,7 @@ void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gestur  		element["columns"][0]["font"]["name"] = "SANSSERIF";  		element["columns"][0]["font"]["style"] = font_style; -		std::string key_string = LLKeyboard::stringFromKey(gesture->mKey); +		std::string key_string;  		std::string buffer;  		if (gesture->mKey == KEY_NONE) @@ -338,6 +338,7 @@ void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gestur  		}  		else  		{ +			key_string = LLKeyboard::stringFromKey(gesture->mKey);  			buffer = LLKeyboard::stringFromAccelerator(gesture->mMask,  					gesture->mKey);  		} diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 7a989806a1..257b39a7dd 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -798,7 +798,8 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32*  	}  	else if (mesg[0] == '/'  			 && mesg[1] -			 && LLStringOps::isDigit(mesg[1])) +			 && (LLStringOps::isDigit(mesg[1]) +				 || (mesg[1] == '-' && mesg[2] && LLStringOps::isDigit(mesg[2]))))  	{  		// This a special "/20" speak on a channel  		S32 pos = 0; @@ -812,7 +813,7 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32*  			channel_string.push_back(c);  			pos++;  		} -		while(c && pos < 64 && LLStringOps::isDigit(c)); +		while(c && pos < 64 && (LLStringOps::isDigit(c) || (pos==1 && c =='-')));  		// Move the pointer forward to the first non-whitespace char  		// Check isspace before looping, so we can handle "/33foo" @@ -837,19 +838,36 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32*  void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel)  { -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_ChatFromViewer); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	msg->nextBlockFast(_PREHASH_ChatData); -	msg->addStringFast(_PREHASH_Message, utf8_out_text); -	msg->addU8Fast(_PREHASH_Type, type); -	msg->addS32("Channel", channel); - -	gAgent.sendReliableMessage(); - -	add(LLStatViewer::CHAT_COUNT, 1); +    LLMessageSystem* msg = gMessageSystem; + +    if (channel >= 0) +    { +        msg->newMessageFast(_PREHASH_ChatFromViewer); +        msg->nextBlockFast(_PREHASH_AgentData); +        msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +        msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +        msg->nextBlockFast(_PREHASH_ChatData); +        msg->addStringFast(_PREHASH_Message, utf8_out_text); +        msg->addU8Fast(_PREHASH_Type, type); +        msg->addS32("Channel", channel); + +    } +    else +    { +        // Hack: ChatFromViewer doesn't allow negative channels +        msg->newMessage("ScriptDialogReply"); +        msg->nextBlock("AgentData"); +        msg->addUUID("AgentID", gAgentID); +        msg->addUUID("SessionID", gAgentSessionID); +        msg->nextBlock("Data"); +        msg->addUUID("ObjectID", gAgentID); +        msg->addS32("ChatChannel", channel); +        msg->addS32("ButtonIndex", 0); +        msg->addString("ButtonLabel", utf8_out_text); +    } + +    gAgent.sendReliableMessage(); +    add(LLStatViewer::CHAT_COUNT, 1);  }  class LLChatCommandHandler : public LLCommandHandler diff --git a/indra/newview/llfloaterpay.cpp b/indra/newview/llfloaterpay.cpp index 31245db344..dfe462c8d1 100644 --- a/indra/newview/llfloaterpay.cpp +++ b/indra/newview/llfloaterpay.cpp @@ -72,6 +72,8 @@ struct LLGiveMoneyInfo  		mFloater(floater), mAmount(amount){}  }; +typedef boost::shared_ptr<LLGiveMoneyInfo> give_money_ptr; +  ///----------------------------------------------------------------------------  /// Class LLFloaterPay  ///---------------------------------------------------------------------------- @@ -94,18 +96,18 @@ public:  							bool is_group);  	static bool payConfirmationCallback(const LLSD& notification,  										const LLSD& response, -										LLGiveMoneyInfo* info); +										give_money_ptr info);  private:  	static void onCancel(void* data);  	static void onKeystroke(LLLineEditor* editor, void* data); -	static void onGive(void* data); +	static void onGive(give_money_ptr info);  	void give(S32 amount);  	static void processPayPriceReply(LLMessageSystem* msg, void **userdata);  	void finishPayUI(const LLUUID& target_id, BOOL is_group);  protected: -	std::vector<LLGiveMoneyInfo*> mCallbackData; +	std::vector<give_money_ptr> mCallbackData;  	money_callback mCallback;  	LLTextBox* mObjectNameText;  	LLUUID mTargetUUID; @@ -113,7 +115,7 @@ protected:  	BOOL mHaveName;  	LLButton* mQuickPayButton[MAX_PAY_BUTTONS]; -	LLGiveMoneyInfo* mQuickPayInfo[MAX_PAY_BUTTONS]; +	give_money_ptr mQuickPayInfo[MAX_PAY_BUTTONS];  	LLSafeHandle<LLObjectSelection> mObjectSelection;  }; @@ -136,7 +138,11 @@ LLFloaterPay::LLFloaterPay(const LLSD& key)  // Destroys the object  LLFloaterPay::~LLFloaterPay()  { -	std::for_each(mCallbackData.begin(), mCallbackData.end(), DeletePointer()); +    std::vector<give_money_ptr>::iterator iter; +    for (iter = mCallbackData.begin(); iter != mCallbackData.end(); ++iter) +    { +        (*iter)->mFloater = NULL; +    }  	mCallbackData.clear();  	// Name callbacks will be automatically disconnected since LLFloater is trackable @@ -148,40 +154,40 @@ BOOL LLFloaterPay::postBuild()  {  	S32 i = 0; -	LLGiveMoneyInfo* info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_0); +	give_money_ptr info = give_money_ptr(new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_0));  	mCallbackData.push_back(info); -	childSetAction("fastpay 1",&LLFloaterPay::onGive,info); +	childSetAction("fastpay 1", boost::bind(LLFloaterPay::onGive, info));  	getChildView("fastpay 1")->setVisible(FALSE);  	mQuickPayButton[i] = getChild<LLButton>("fastpay 1");  	mQuickPayInfo[i] = info;  	++i; -	info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_1); +	info = give_money_ptr(new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_1));  	mCallbackData.push_back(info); -	childSetAction("fastpay 5",&LLFloaterPay::onGive,info); +	childSetAction("fastpay 5", boost::bind(LLFloaterPay::onGive, info));  	getChildView("fastpay 5")->setVisible(FALSE);  	mQuickPayButton[i] = getChild<LLButton>("fastpay 5");  	mQuickPayInfo[i] = info;  	++i; -	info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_2); +	info = give_money_ptr(new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_2));  	mCallbackData.push_back(info); -	childSetAction("fastpay 10",&LLFloaterPay::onGive,info); +	childSetAction("fastpay 10", boost::bind(LLFloaterPay::onGive, info));  	getChildView("fastpay 10")->setVisible(FALSE);  	mQuickPayButton[i] = getChild<LLButton>("fastpay 10");  	mQuickPayInfo[i] = info;  	++i; -	info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_3); +	info = give_money_ptr(new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_3));  	mCallbackData.push_back(info); -	childSetAction("fastpay 20",&LLFloaterPay::onGive,info); +	childSetAction("fastpay 20", boost::bind(LLFloaterPay::onGive, info));  	getChildView("fastpay 20")->setVisible(FALSE);  	mQuickPayButton[i] = getChild<LLButton>("fastpay 20"); @@ -195,10 +201,10 @@ BOOL LLFloaterPay::postBuild()  	getChild<LLLineEditor>("amount")->setKeystrokeCallback(&LLFloaterPay::onKeystroke, this);  	getChild<LLLineEditor>("amount")->setPrevalidate(LLTextValidate::validateNonNegativeS32); -	info = new LLGiveMoneyInfo(this, 0); +	info = give_money_ptr(new LLGiveMoneyInfo(this, 0));  	mCallbackData.push_back(info); -	childSetAction("pay btn",&LLFloaterPay::onGive,info); +	childSetAction("pay btn", boost::bind(LLFloaterPay::onGive, info));  	setDefaultBtn("pay btn");  	getChildView("pay btn")->setVisible(FALSE);  	getChildView("pay btn")->setEnabled(FALSE); @@ -415,9 +421,9 @@ void LLFloaterPay::payDirectly(money_callback callback,  	floater->finishPayUI(target_id, is_group);  } -bool LLFloaterPay::payConfirmationCallback(const LLSD& notification, const LLSD& response, LLGiveMoneyInfo* info) +bool LLFloaterPay::payConfirmationCallback(const LLSD& notification, const LLSD& response, give_money_ptr info)  { -	if (!info || !info->mFloater) +	if (!info.get() || !info->mFloater)  	{  		return false;  	} @@ -479,54 +485,61 @@ void LLFloaterPay::onKeystroke(LLLineEditor*, void* data)  }  // static -void LLFloaterPay::onGive(void* data) +void LLFloaterPay::onGive(give_money_ptr info)  { -	LLGiveMoneyInfo* info = reinterpret_cast<LLGiveMoneyInfo*>(data); -	LLFloaterPay* floater = info->mFloater; -	if(info && floater) -	{ -		S32 amount = info->mAmount; -		if(amount == 0) -		{ -			amount = atoi(floater->getChild<LLUICtrl>("amount")->getValue().asString().c_str()); -		} -		if (amount > PAY_AMOUNT_NOTIFICATION && gStatusBar && gStatusBar->getBalance() > amount) -		{ -			LLUUID payee_id = LLUUID::null; -			BOOL is_group = false; -			if (floater->mObjectSelection.notNull()) -			{ -				LLSelectNode* node = floater->mObjectSelection->getFirstRootNode(); -				if (node) -				{ -					node->mPermissions->getOwnership(payee_id, is_group); -				} -				else -				{ -					// object no longer exists -					LLNotificationsUtil::add("PayObjectFailed"); -					floater->closeFloater(); -					return; -				} -			} -			else -			{ -				is_group = floater->mTargetIsGroup; -				payee_id = floater->mTargetUUID; -			} - -			LLSD args; -			args["TARGET"] = LLSLURL( is_group ? "group" : "agent", payee_id, "completename").getSLURLString(); -			args["AMOUNT"] = amount; - -			LLNotificationsUtil::add("PayConfirmation", args, LLSD(), boost::bind(&LLFloaterPay::payConfirmationCallback, _1, _2, info)); -		} -		else -		{ -			floater->give(amount); -			floater->closeFloater(); -		} -	} +    if (!info.get() || !info->mFloater) +    { +        return; +    } + +    LLFloaterPay* floater = info->mFloater; +    S32 amount = info->mAmount; +    if (amount == 0) +    { +        LLUICtrl* text_field = floater->getChild<LLUICtrl>("amount"); +        if (!text_field) +        { +            return; +        } +        amount = atoi(text_field->getValue().asString().c_str()); +    } + +    if (amount > PAY_AMOUNT_NOTIFICATION && gStatusBar && gStatusBar->getBalance() > amount) +    { +        LLUUID payee_id = LLUUID::null; +        BOOL is_group = false; +        if (floater->mObjectSelection.notNull()) +        { +            LLSelectNode* node = floater->mObjectSelection->getFirstRootNode(); +            if (node) +            { +                node->mPermissions->getOwnership(payee_id, is_group); +            } +            else +            { +                // object no longer exists +                LLNotificationsUtil::add("PayObjectFailed"); +                floater->closeFloater(); +                return; +            } +        } +        else +        { +            is_group = floater->mTargetIsGroup; +            payee_id = floater->mTargetUUID; +        } + +        LLSD args; +        args["TARGET"] = LLSLURL(is_group ? "group" : "agent", payee_id, "completename").getSLURLString(); +        args["AMOUNT"] = amount; + +        LLNotificationsUtil::add("PayConfirmation", args, LLSD(), boost::bind(&LLFloaterPay::payConfirmationCallback, _1, _2, info)); +    } +    else +    { +        floater->give(amount); +        floater->closeFloater(); +    }  }  void LLFloaterPay::give(S32 amount) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 36bdcf4d89..75f5e87a2b 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1232,6 +1232,9 @@ void LLFloaterPreference::refreshEnabledState()  						(ctrl_wind_light->get()) ? TRUE : FALSE;  	ctrl_deferred->setEnabled(enabled); + +	// Cannot have floater active until caps have been received +	getChild<LLButton>("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true);  }  void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() @@ -1369,9 +1372,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()  	disableUnavailableSettings();  	getChildView("block_list")->setEnabled(LLLoginInstance::getInstance()->authSuccess()); - -	// Cannot have floater active until caps have been received -	getChild<LLButton>("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true);  }  // static @@ -1411,7 +1411,7 @@ void LLAvatarComplexityControls::setIndirectMaxArc()  	else  	{  		// This is the inverse of the calculation in updateMaxComplexity -		indirect_max_arc = (U32)((log(max_arc) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE) + MIN_INDIRECT_ARC_LIMIT; +		indirect_max_arc = (U32)ll_round(((log(F32(max_arc)) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE)) + MIN_INDIRECT_ARC_LIMIT;  	}  	gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc);  } @@ -1930,7 +1930,7 @@ void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* valu  	{  		// if this is changed, the inverse calculation in setIndirectMaxArc  		// must be changed to match -		max_arc = (U32)exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT))); +		max_arc = (U32)ll_round(exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT))));  	}  	gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index ed6f4ede9f..a6ce0ba678 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -192,7 +192,6 @@ BOOL LLFloaterReporter::postBuild()  	mOwnerName = LLStringUtil::null;  	getChild<LLUICtrl>("summary_edit")->setFocus(TRUE); -	getChild<LLCheckBoxCtrl>("screen_check")->set(TRUE);  	mDefaultSummary = getChild<LLUICtrl>("details_edit")->getValue().asString(); @@ -246,8 +245,6 @@ LLFloaterReporter::~LLFloaterReporter()  // virtual  void LLFloaterReporter::draw()  { -	getChildView("screen_check")->setEnabled(TRUE ); -  	LLFloater::draw();  } @@ -255,7 +252,6 @@ void LLFloaterReporter::enableControls(BOOL enable)  {  	getChildView("category_combo")->setEnabled(enable);  	getChildView("chat_check")->setEnabled(enable); -	getChildView("screen_check")->setEnabled(enable);  	getChildView("screenshot")->setEnabled(FALSE);  	getChildView("pick_btn")->setEnabled(enable);  	getChildView("summary_edit")->setEnabled(enable); @@ -448,23 +444,15 @@ void LLFloaterReporter::onClickSend(void *userdata)  		if(!url.empty() || !sshot_url.empty())  		{  			self->sendReportViaCaps(url, sshot_url, self->gatherReport()); +			LLNotificationsUtil::add("HelpReportAbuseConfirm");  			self->closeFloater();  		}  		else  		{ -			if(self->getChild<LLUICtrl>("screen_check")->getValue()) -			{ -				self->getChildView("send_btn")->setEnabled(FALSE); -				self->getChildView("cancel_btn")->setEnabled(FALSE); -				// the callback from uploading the image calls sendReportViaLegacy() -				self->uploadImage(); -			} -			else -			{ -				self->sendReportViaLegacy(self->gatherReport()); -				LLUploadDialog::modalUploadFinished(); -				self->closeFloater(); -			} +			self->getChildView("send_btn")->setEnabled(FALSE); +			self->getChildView("cancel_btn")->setEnabled(FALSE); +			// the callback from uploading the image calls sendReportViaLegacy() +			self->uploadImage();  		}  	}  } @@ -713,10 +701,7 @@ LLSD LLFloaterReporter::gatherReport()  	// only send a screenshot ID if we're asked to and the email is   	// going to LL - Estate Owners cannot see the screenshot asset  	LLUUID screenshot_id = LLUUID::null; -	if (getChild<LLUICtrl>("screen_check")->getValue()) -	{ -		screenshot_id = getChild<LLUICtrl>("screenshot")->getValue(); -	}; +	screenshot_id = getChild<LLUICtrl>("screenshot")->getValue();  	LLSD report = LLSD::emptyMap();  	report["report-type"] = (U8) mReportType; @@ -770,7 +755,7 @@ void LLFloaterReporter::finishedARPost(const LLSD &)  void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report)  { -	if(getChild<LLUICtrl>("screen_check")->getValue().asBoolean() && !sshot_url.empty()) +	if(!sshot_url.empty())      {  		// try to upload screenshot          LLResourceUploadInfo::ptr_t uploadInfo(new  LLARScreenShotUploader(report, mResourceDatap->mAssetInfo.mUuid, mResourceDatap->mAssetInfo.mType)); @@ -885,6 +870,7 @@ void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data,  		self->mScreenID = uuid;  		LL_INFOS() << "Got screen shot " << uuid << LL_ENDL;  		self->sendReportViaLegacy(self->gatherReport()); +		LLNotificationsUtil::add("HelpReportAbuseConfirm");  		self->closeFloater();  	}  } diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 7b8fc5b35b..eae16b9f03 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -660,6 +660,8 @@ BOOL LLPanelScriptLimitsRegionMemory::postBuild()  	{  		return FALSE;  	} +	list->setCommitCallback(boost::bind(&LLPanelScriptLimitsRegionMemory::checkButtonsEnabled, this)); +	checkButtonsEnabled();  	//set all columns to resizable mode even if some columns will be empty  	for(S32 column = 0; column < list->getNumColumns(); column++) @@ -750,6 +752,14 @@ void LLPanelScriptLimitsRegionMemory::clearList()  	getChild<LLUICtrl>("parcels_listed")->setValue(LLSD(msg_empty_string));  	mObjectListItems.clear(); +	checkButtonsEnabled(); +} + +void LLPanelScriptLimitsRegionMemory::checkButtonsEnabled() +{ +	LLScrollListCtrl* list = getChild<LLScrollListCtrl>("scripts_list"); +	getChild<LLButton>("highlight_btn")->setEnabled(list->getNumSelected() > 0); +	getChild<LLButton>("return_btn")->setEnabled(list->getNumSelected() > 0);  }  // static diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index e3cbbd185f..2ac3862b4f 100644 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -113,6 +113,7 @@ public:  	void showBeacon();  	void returnObjectsFromParcel(S32 local_id);  	void returnObjects(); +	void checkButtonsEnabled();  private:  	void onNameCache(const LLUUID& id, diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index 0cb37dabe7..b139e5daf5 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -257,7 +257,6 @@ void LLFloaterSellLandUI::setBadge(const char* id, Badge badge)  	static std::string badgeOK("badge_ok.j2c");  	static std::string badgeNote("badge_note.j2c");  	static std::string badgeWarn("badge_warn.j2c"); -	static std::string badgeError("badge_error.j2c");  	std::string badgeName;  	switch (badge) @@ -266,7 +265,7 @@ void LLFloaterSellLandUI::setBadge(const char* id, Badge badge)  		case BADGE_OK:		badgeName = badgeOK;	break;  		case BADGE_NOTE:	badgeName = badgeNote;	break;  		case BADGE_WARN:	badgeName = badgeWarn;	break; -		case BADGE_ERROR:	badgeName = badgeError;	break; +		case BADGE_ERROR:	badgeName = badgeWarn;	break;  	}  	getChild<LLUICtrl>(id)->setValue(badgeName); diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index ff7594a531..b5ba64716d 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1375,7 +1375,7 @@ const LLVector3d& LLFloaterSnapshotBase::getPosTakenGlobal()  // static  void LLFloaterSnapshot::setAgentEmail(const std::string& email)  { -	LLFloaterSnapshot* instance = getInstance(); +	LLFloaterSnapshot* instance = findInstance();  	if (instance)  	{  		LLSideTrayPanelContainer* panel_container = instance->getChild<LLSideTrayPanelContainer>("panel_container"); diff --git a/indra/newview/llgroupiconctrl.cpp b/indra/newview/llgroupiconctrl.cpp index 271dd44c1f..7c2a3cad43 100644 --- a/indra/newview/llgroupiconctrl.cpp +++ b/indra/newview/llgroupiconctrl.cpp @@ -74,9 +74,16 @@ LLGroupIconCtrl::~LLGroupIconCtrl()  	LLGroupMgr::getInstance()->removeObserver(this);  } -void LLGroupIconCtrl::setIconId(const LLSD& value) +void LLGroupIconCtrl::setIconId(const LLUUID& icon_id)  { -    LLIconCtrl::setValue(value); +    if (icon_id.notNull()) +    { +        LLIconCtrl::setValue(icon_id); +    } +    else +    { +        LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); +    }  }  void LLGroupIconCtrl::setValue(const LLSD& value) @@ -122,14 +129,7 @@ bool LLGroupIconCtrl::updateFromCache()  	LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mGroupId);  	if (!group_data) return false; -	if (group_data->mInsigniaID.notNull()) -	{ -		LLIconCtrl::setValue(group_data->mInsigniaID); -	} -	else -	{ -		LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); -	} +	setIconId(group_data->mInsigniaID);  	if (mDrawTooltip && !group_data->mName.empty())  	{ diff --git a/indra/newview/llgroupiconctrl.h b/indra/newview/llgroupiconctrl.h index f8b22cf581..43e384d3e2 100644 --- a/indra/newview/llgroupiconctrl.h +++ b/indra/newview/llgroupiconctrl.h @@ -66,7 +66,13 @@ public:  	 */  	virtual void setValue(const LLSD& value); -	void setIconId(const LLSD& value); +	/** +	 * Sets icon_id as icon value directly. Avoids LLGroupMgr cache checks for group id +	 * Uses default icon in case id is null. +	 * +	 * @params icon_id - it is processed as icon id, default image will be used in case id is null. +	 */ +	void setIconId(const LLUUID& icon_id);  	// LLGroupMgrObserver observer trigger  	virtual void changed(LLGroupChange gc); diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 6126db2988..62414d3bbb 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -379,10 +379,7 @@ void LLGroupListItem::setGroupID(const LLUUID& group_id)  void LLGroupListItem::setGroupIconID(const LLUUID& group_icon_id)  { -	if (group_icon_id.notNull()) -	{ -		mGroupIcon->setIconId(group_icon_id); -	} +	mGroupIcon->setIconId(group_icon_id);  }  void LLGroupListItem::setGroupIconVisible(bool visible) diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 52e83fe412..6b1e196182 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -53,7 +53,7 @@ const F32 VERTICAL_PADDING = 12.f;  const F32 BUFFER_SIZE = 2.f;  const F32 HUD_TEXT_MAX_WIDTH = 190.f;  const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f; -const F32 MAX_DRAW_DISTANCE = 64.f; +const F32 MAX_DRAW_DISTANCE = 300.f;  std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects;  std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects; @@ -394,7 +394,20 @@ void LLHUDText::updateVisibility()  	LLVector3 pos_agent_center = gAgent.getPosAgentFromGlobal(mPositionGlobal) - dir_from_camera;  	F32 last_distance_center = (pos_agent_center - LLViewerCamera::getInstance()->getOrigin()).magVec(); -	if(last_distance_center > MAX_DRAW_DISTANCE) +	F32 max_draw_distance = gSavedSettings.getF32("PrimTextMaxDrawDistance"); + +	if(max_draw_distance < 0) +	{ +		max_draw_distance = 0; +		gSavedSettings.setF32("PrimTextMaxDrawDistance", max_draw_distance); +	} +	else if(max_draw_distance > MAX_DRAW_DISTANCE) +	{ +		max_draw_distance = MAX_DRAW_DISTANCE; +		gSavedSettings.setF32("PrimTextMaxDrawDistance", MAX_DRAW_DISTANCE); +	} + +	if(last_distance_center > max_draw_distance)  	{  		mVisible = FALSE;  		return; diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp index 8e91af321e..a4fce36783 100644 --- a/indra/newview/llinspectgroup.cpp +++ b/indra/newview/llinspectgroup.cpp @@ -41,6 +41,7 @@  #include "lltooltip.h"	// positionViewNearMouse()  #include "lltrans.h"  #include "lluictrl.h" +#include "llgroupiconctrl.h"  //////////////////////////////////////////////////////////////////////////////  // LLInspectGroup @@ -233,7 +234,7 @@ void LLInspectGroup::processGroupData()  		getChild<LLUICtrl>("group_details")->setValue( LLSD(data->mCharter) ); -		getChild<LLUICtrl>("group_icon")->setValue( LLSD(data->mInsigniaID) ); +		getChild<LLGroupIconCtrl>("group_icon")->setIconId(data->mInsigniaID);  		std::string cost;  		bool is_member = LLGroupActions::isInGroup(mGroupID); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 9f0b35fc8c..eebb6a0384 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -286,6 +286,16 @@ BOOL LLInvFVBridge::cutToClipboard()  	return FALSE;  } +// virtual +bool LLInvFVBridge::isCutToClipboard() +{ +    if (LLClipboard::instance().isCutMode()) +    { +        return LLClipboard::instance().isOnClipboard(mUUID); +    } +    return false; +} +  // Callback for cutToClipboard if DAMA required...  BOOL LLInvFVBridge::callback_cutToClipboard(const LLSD& notification, const LLSD& response)  { @@ -307,9 +317,7 @@ BOOL LLInvFVBridge::perform_cutToClipboard()  	if (obj && isItemMovable() && isItemRemovable())  	{  		LLClipboard::instance().setCutMode(true); -		BOOL added_to_clipboard = LLClipboard::instance().addToClipboard(mUUID); -        removeObject(&gInventory, mUUID);   // Always perform the remove even if the object couldn't make it to the clipboard -        return added_to_clipboard; +		return LLClipboard::instance().addToClipboard(mUUID);  	}  	return FALSE;  } @@ -1390,6 +1398,12 @@ bool LLInvFVBridge::canShare() const  				// Categories can be given.  				can_share = (model->getCategory(mUUID) != NULL);  			} + +			const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); +			if ((mUUID == trash_id) || gInventory.isObjectDescendentOf(mUUID, trash_id)) +			{ +				can_share = false; +			}  		}  	} @@ -1925,13 +1939,15 @@ BOOL LLItemBridge::removeItem()  	}  	// move it to the trash -	LLPreview::hide(mUUID, TRUE);  	LLInventoryModel* model = getInventoryModel();  	if(!model) return FALSE;  	const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);  	LLViewerInventoryItem* item = getItem();  	if (!item) return FALSE; - +	if (item->getType() != LLAssetType::AT_LSL_TEXT) +	{ +		LLPreview::hide(mUUID, TRUE); +	}  	// Already in trash  	if (model->isObjectDescendentOf(mUUID, trash_id)) return FALSE; diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 9053c61171..df25e01688 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -116,6 +116,7 @@ public:  	virtual BOOL isItemCopyable() const { return FALSE; }  	virtual BOOL copyToClipboard() const;  	virtual BOOL cutToClipboard(); +	virtual bool isCutToClipboard();  	virtual BOOL isClipboardPasteable() const;  	virtual BOOL isClipboardPasteableAsLink() const;  	virtual void pasteFromClipboard() {} diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 003bbcafed..e995c138b4 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -84,21 +84,18 @@ LLInventoryFilter::LLInventoryFilter(const Params& p)  bool LLInventoryFilter::check(const LLFolderViewModelItem* item)   {  	const LLFolderViewModelItemInventory* listener = dynamic_cast<const LLFolderViewModelItemInventory*>(item); -	// Clipboard cut items are *always* filtered so we need this value upfront -	const BOOL passed_clipboard = (listener ? checkAgainstClipboard(listener->getUUID()) : TRUE);  	// If it's a folder and we're showing all folders, return automatically.  	const BOOL is_folder = listener->getInventoryType() == LLInventoryType::IT_CATEGORY;  	if (is_folder && (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS))  	{ -		return passed_clipboard; +		return true;  	}  	bool passed = (mFilterSubString.size() ? listener->getSearchableName().find(mFilterSubString) != std::string::npos : true);  	passed = passed && checkAgainstFilterType(listener);  	passed = passed && checkAgainstPermissions(listener);  	passed = passed && checkAgainstFilterLinks(listener); -	passed = passed && passed_clipboard;  	return passed;  } @@ -108,9 +105,8 @@ bool LLInventoryFilter::check(const LLInventoryItem* item)  	const bool passed_string = (mFilterSubString.size() ? item->getName().find(mFilterSubString) != std::string::npos : true);  	const bool passed_filtertype = checkAgainstFilterType(item);  	const bool passed_permissions = checkAgainstPermissions(item); -	const bool passed_clipboard = checkAgainstClipboard(item->getUUID()); -	return passed_filtertype && passed_permissions && passed_clipboard && passed_string; +	return passed_filtertype && passed_permissions && passed_string;  }  bool LLInventoryFilter::checkFolder(const LLFolderViewModelItem* item) const @@ -129,13 +125,10 @@ bool LLInventoryFilter::checkFolder(const LLFolderViewModelItem* item) const  bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const  { -	// Always check against the clipboard -	const BOOL passed_clipboard = checkAgainstClipboard(folder_id); -	  	// we're showing all folders, overriding filter  	if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)  	{ -		return passed_clipboard; +		return true;  	}  	// when applying a filter, matching folders get their contents downloaded first @@ -201,7 +194,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const  	LLViewerInventoryItem* item = gInventory.getItem(folder_id);  	if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER)  	{ -		return passed_clipboard; +		return true;  	}  	if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY) @@ -216,7 +209,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const  			return false;  	} -	return passed_clipboard; +	return true;  }  bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewModelItemInventory* listener) const diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9a33e210ff..503fa28a33 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -582,7 +582,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  	// Add the category to the internal representation  	LLPointer<LLViewerInventoryCategory> cat =  		new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); -	cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); +	cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1  	cat->setDescendentCount(0);  	LLCategoryUpdate update(cat->getParentUUID(), 1);  	accountForUpdate(update); @@ -640,7 +640,7 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv          result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(),          result["name"].asString(), gAgent.getID()); -    cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); +    cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1      cat->setDescendentCount(0);      LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); @@ -914,8 +914,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask)  			item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id);  			if( item_array )  			{ +				LLInventoryModel::LLCategoryUpdate update(category_id, 1); +				gInventory.accountForUpdate(update); +  				// *FIX: bit of a hack to call update server from here... -				new_item->updateServer(TRUE); +				new_item->updateParentOnServer(FALSE);  				item_array->push_back(new_item);  			}  			else @@ -956,9 +959,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask)  				item_array = get_ptr_in_map(mParentChildItemTree, parent_id);  				if(item_array)  				{ +					LLInventoryModel::LLCategoryUpdate update(parent_id, 1); +					gInventory.accountForUpdate(update);  					// *FIX: bit of a hack to call update server from  					// here... -					new_item->updateServer(TRUE); +					new_item->updateParentOnServer(FALSE);  					item_array->push_back(new_item);  				}  				else @@ -1045,7 +1050,6 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32  	if(old_cat)  	{  		// We already have an old category, modify its values -		U32 mask = LLInventoryObserver::NONE;  		LLUUID old_parent_id = old_cat->getParentUUID();  		LLUUID new_parent_id = cat->getParentUUID();  		if(old_parent_id != new_parent_id) @@ -1100,7 +1104,8 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32  		item_array_t* itemsp = new item_array_t;  		mParentChildCategoryTree[new_cat->getUUID()] = catsp;  		mParentChildItemTree[new_cat->getUUID()] = itemsp; -		addChangedMask(LLInventoryObserver::ADD, cat->getUUID()); +		mask |= LLInventoryObserver::ADD; +		addChangedMask(mask, cat->getUUID());  	}  } @@ -1390,7 +1395,11 @@ void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool f  		}  		// From purgeObject() -		LLPreview::hide(object_id); +		LLViewerInventoryItem *item = getItem(object_id); +		if (item && (item->getType() != LLAssetType::AT_LSL_TEXT)) +		{ +			LLPreview::hide(object_id, TRUE); +		}  		deleteObject(object_id, fix_broken_links, do_notify_observers);  	}  } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index aa934f95a1..a55938f334 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -181,7 +181,12 @@ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate)  		if (gDirUtilp->fileExists(mFilename))  		{  			// verifying that the file has indeed been modified + +#ifndef LL_WINDOWS  			const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); +#else +			const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename))); +#endif  			LLSD new_last_modified = asctime(localtime(&temp_time));  			if (mLastModified.asString() != new_last_modified.asString()) diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 53b2ca2b74..11bc1425f9 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -243,7 +243,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)  	params.commit_on_focus_lost(false);  	params.follows.flags(FOLLOWS_ALL);  	mTextEntry = LLUICtrlFactory::create<LLURLLineEditor>(params); -	mTextEntry->setContextMenu(NULL); +	mTextEntry->resetContextMenu();  	addChild(mTextEntry);  	// LLLineEditor is replaced with LLLocationLineEditor diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 639641d1c2..485d4677b1 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -244,7 +244,10 @@ std::string LLLogChat::makeLogFileName(std::string filename)  	filename = cleanFileName(filename);  	filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename); -	filename += '.' + LL_TRANSCRIPT_FILE_EXTENSION; +	if (!filename.empty()) +	{ +		filename += '.' + LL_TRANSCRIPT_FILE_EXTENSION; +	}  	return filename;  } diff --git a/indra/newview/llmanip.h b/indra/newview/llmanip.h index 1fb05e047a..69881e8589 100644 --- a/indra/newview/llmanip.h +++ b/indra/newview/llmanip.h @@ -1,4 +1,4 @@ -/**  +/**    * @file llmanip.h   * @brief LLManip class definition   * @@ -37,7 +37,7 @@ class LLToolComposite;  class LLVector3;  class LLObjectSelection; -const S32 MIN_DIVISION_PIXEL_WIDTH = 9; +const S32 MIN_DIVISION_PIXEL_WIDTH = 3;  class LLManip : public LLTool  { diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index b4259a456c..3975d3980b 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1,4 +1,4 @@ -/**  +/**    * @file llmaniptranslate.cpp   * @brief LLManipTranslate class implementation   * @@ -548,12 +548,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask)  		if (off_axis_magnitude > mSnapOffsetMeters)  		{  			mInSnapRegime = TRUE; -			LLVector3 mouse_down_offset(mDragCursorStartGlobal - mDragSelectionStartGlobal);  			LLVector3 cursor_snap_agent = gAgent.getPosAgentFromGlobal(cursor_point_snap_line); -			if (!gSavedSettings.getBOOL("SnapToMouseCursor")) -			{ -				cursor_snap_agent -= mouse_down_offset; -			}  			F32 cursor_grid_dist = (cursor_snap_agent - mGridOrigin) * axis_f; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 6cc7a0fc99..54f95520db 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -773,7 +773,9 @@ void LLMarketplaceData::getMerchantStatusCoro()      std::string url = getSLMConnectURL("/merchant");      if (url.empty())      { -        LL_INFOS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL; +        LL_WARNS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL; +        setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); +        return;      }      LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 9cf3249983..00043d1e72 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -1007,7 +1007,11 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			std::string uuid = self->getClickUUID();  			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL; -			LLWeb::loadURL(url, target, std::string()); +			// try as slurl first +			if (!LLURLDispatcher::dispatch(url, "clicked", NULL, mTrusted)) +			{ +				LLWeb::loadURL(url, target, std::string()); +			}  			// CP: removing this code because we no longer support popups so this breaks the flow.  			//     replaced with a bare call to LLWeb::LoadURL(...) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 54f8fb93d0..e42647739f 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1753,6 +1753,11 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat  bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size)  { +	if (data == NULL || data_size == 0) +	{ +		return false; +	} +  	LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));  	std::string mesh_string((char*) data, data_size);  	std::istringstream stream(mesh_string); @@ -3010,12 +3015,23 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  	}  	else if (data && data_size > 0)  	{ -		// header was successfully retrieved from sim, cache in vfs -		LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id]; +		// header was successfully retrieved from sim and parsed, cache in vfs +		S32 header_bytes = 0; +		LLSD header; -		S32 version = header["version"].asInteger(); +		gMeshRepo.mThread->mHeaderMutex->lock(); +		LLMeshRepoThread::mesh_header_map::iterator iter = gMeshRepo.mThread->mMeshHeader.find(mesh_id); +		if (iter != gMeshRepo.mThread->mMeshHeader.end()) +		{ +			header_bytes = (S32)gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; +			header = iter->second; +		} +		gMeshRepo.mThread->mHeaderMutex->unlock(); -		if (version <= MAX_MESH_VERSION) +		if (header_bytes > 0 +			&& !header.has("404") +			&& header.has("version") +			&& header["version"].asInteger() <= MAX_MESH_VERSION)  		{  			std::stringstream str; @@ -3064,6 +3080,17 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  				}  			}  		} +		else +		{ +			LL_WARNS(LOG_MESH) << "Trying to cache nonexistent mesh, mesh id: " << mesh_id << LL_ENDL; + +			// headerReceived() parsed header, but header's data is invalid so none of the LODs will be available +			LLMutexLock lock(gMeshRepo.mThread->mMutex); +			for (int i(0); i < 4; ++i) +			{ +				gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); +			} +		}  	}  } @@ -4115,7 +4142,7 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32  		}  	} -	F32 max_area = 102932.f; //area of circle that encompasses region +	F32 max_area = 102944.f; //area of circle that encompasses region (see MAINT-6559)  	F32 min_area = 1.f;  	F32 high_area = llmin(F_PI*dmid*dmid, max_area); diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 70035bcc74..c3dd08c327 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -252,7 +252,7 @@ void LLFloaterMove::setSittingMode(BOOL bSitting)  			LLPanelStandStopFlying::setStandStopFlyingMode(LLPanelStandStopFlying::SSFM_STOP_FLYING);  		}  	} -	enableInstance(!bSitting); +	enableInstance();  }  // protected  @@ -459,7 +459,7 @@ void LLFloaterMove::showModeButtons(BOOL bShow)  }  //static -void LLFloaterMove::enableInstance(BOOL bEnable) +void LLFloaterMove::enableInstance()  {  	LLFloaterMove* instance = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview");  	if (instance) @@ -470,7 +470,7 @@ void LLFloaterMove::enableInstance(BOOL bEnable)  		}  		else  		{ -			instance->showModeButtons(bEnable); +            instance->showModeButtons(isAgentAvatarValid() && !gAgentAvatarp->isSitting());  		}  	}  } @@ -566,7 +566,7 @@ BOOL LLPanelStandStopFlying::postBuild()  {  	mStandButton = getChild<LLButton>("stand_btn");  	mStandButton->setCommitCallback(boost::bind(&LLPanelStandStopFlying::onStandButtonClick, this)); -	mStandButton->setCommitCallback(boost::bind(&LLFloaterMove::enableInstance, TRUE)); +	mStandButton->setCommitCallback(boost::bind(&LLFloaterMove::enableInstance));  	mStandButton->setVisible(FALSE);  	LLHints::registerHintTarget("stand_btn", mStandButton->getHandle()); @@ -685,8 +685,7 @@ void LLPanelStandStopFlying::onStandButtonClick()  	LLSelectMgr::getInstance()->deselectAllForStandingUp();  	gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); -	setFocus(FALSE); // EXT-482 -	mStandButton->setVisible(FALSE); // force visibility changing to avoid seeing Stand & Move buttons at once. +	setFocus(FALSE);   }  void LLPanelStandStopFlying::onStopFlyingButtonClick() @@ -694,7 +693,6 @@ void LLPanelStandStopFlying::onStopFlyingButtonClick()  	gAgent.setFlying(FALSE);  	setFocus(FALSE); // EXT-482 -	mStopFlyingButton->setVisible(FALSE);  }  /** diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h index c525d9dfdb..4a31f2a814 100644 --- a/indra/newview/llmoveview.h +++ b/indra/newview/llmoveview.h @@ -56,7 +56,7 @@ public:  	static void setAlwaysRunMode(bool run);  	void setAlwaysRunModeImpl(bool run);  	static void setSittingMode(BOOL bSitting); -	static void enableInstance(BOOL bEnable); +	static void enableInstance();  	/*virtual*/ void onOpen(const LLSD& key);  	static void sUpdateFlyingStatus(); diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 2657b84ef3..63ab88da42 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -96,17 +96,21 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification)  			LLUUID from_id = notification->getPayload()["from_id"]; -			//Will not play a notification sound for inventory and teleport offer based upon chat preference -			bool playSound = (!notification->isDND() -							  && ((notification->getName() == "UserGiveItem" -			                  && gSavedSettings.getBOOL("PlaySoundInventoryOffer")) -			                  || (notification->getName() == "TeleportOffered" -			                  && gSavedSettings.getBOOL("PlaySoundTeleportOffer")))); - -			            if(playSound) -			            { -			                notification->playSound(); -			            } +			if (!notification->isDND()) +			{ +				//Will not play a notification sound for inventory and teleport offer based upon chat preference +				bool playSound = (notification->getName() == "UserGiveItem" +								  && gSavedSettings.getBOOL("PlaySoundInventoryOffer")) +								 || ((notification->getName() == "TeleportOffered" +								     || notification->getName() == "TeleportOffered_MaturityExceeded" +								     || notification->getName() == "TeleportOffered_MaturityBlocked") +								    && gSavedSettings.getBOOL("PlaySoundTeleportOffer")); + +				if (playSound) +				{ +					notification->playSound(); +				} +			}  			LLHandlerUtil::spawnIMSession(name, from_id);  			LLHandlerUtil::addNotifPanelToIM(notification); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 65fd3f95ab..de6a36ce2f 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -999,7 +999,7 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id)          }      } -    if (mGalleryCreated) +    if (mGalleryCreated && !LLApp::isQuitting())      {          reArrangeRows();      } diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index b2164c1f21..d17f5494a0 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -199,7 +199,7 @@ void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group)  	mGroupNameEditor = panel_group->getChild<LLLineEditor>("group_name_editor"); -	mGroupNameEditor->setPrevalidate( LLTextValidate::validateASCII ); +	mGroupNameEditor->setPrevalidate( LLTextValidate::validateASCIINoLeadingSpace );  } diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 8331c152e2..8b9941c0ca 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1059,9 +1059,6 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)  		case LLAssetType::AT_BODYPART:  			applyListViewFilter(LVIT_BODYPART);  			break; -		case LLAssetType::AT_GESTURE: -			applyListViewFilter(LVIT_GESTURES); -			break;  		case LLAssetType::AT_CLOTHING:  		default:  			applyListViewFilter(LVIT_CLOTHING); diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 841bb4337a..30870daf40 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -80,7 +80,6 @@ public:  	{  		LVIT_ALL = 0,  		LVIT_CLOTHING, -		LVIT_GESTURES,  		LVIT_BODYPART,  		LVIT_ATTACHMENT,  		LVIT_SHAPE, diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 184238c40c..8afa35efa0 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -44,19 +44,11 @@ static const std::string PANEL_PICKS = "panel_picks";  std::string getProfileURL(const std::string& agent_name)  { -	std::string url; - -	if (LLGridManager::getInstance()->isInProductionGrid()) -	{ -		url = gSavedSettings.getString("WebProfileURL"); -	} -	else -	{ -		url = gSavedSettings.getString("WebProfileNonProductionURL"); -	} +	std::string url = "[WEB_PROFILE_URL][AGENT_NAME]";  	LLSD subs; +	subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL();  	subs["AGENT_NAME"] = agent_name; -	url = LLWeb::expandURLSubstitutions(url,subs); +	url = LLWeb::expandURLSubstitutions(url, subs);  	LLStringUtil::toLower(url);  	return url;  } diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index d0353259a5..796372ba04 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -30,13 +30,19 @@  #include "lltoggleablemenu.h" +#include "llagent.h" +#include "llaccordionctrl.h" +#include "llaccordionctrltab.h"  #include "llappearancemgr.h"  #include "llfloatersidepanelcontainer.h"  #include "llinventoryfunctions.h" +#include "llinventoryicon.h"  #include "llinventorymodel.h"  #include "llinventoryobserver.h"  #include "llmenubutton.h" +#include "llscrolllistctrl.h"  #include "llviewermenu.h" +#include "llviewerregion.h"  #include "llwearableitemslist.h"  #include "llsdserialize.h"  #include "llclipboard.h" @@ -146,11 +152,47 @@ protected:  		menu->setItemVisible("detach",		allow_detach);  		menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach);  		menu->setItemVisible("show_original", mUUIDs.size() == 1); +		menu->setItemVisible("edit_item", FALSE);  	}  };  ////////////////////////////////////////////////////////////////////////// +class LLTempAttachmentsContextMenu : public LLListContextMenu +{ +public: +	LLTempAttachmentsContextMenu(LLPanelWearing* panel_wearing) +		:	mPanelWearing(panel_wearing) +	{} +protected: +	/* virtual */ LLContextMenu* createMenu() +	{ +		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + +		registrar.add("Wearing.EditItem", boost::bind(&LLPanelWearing::onEditAttachment, mPanelWearing)); +		registrar.add("Wearing.Detach", boost::bind(&LLPanelWearing::onRemoveAttachment, mPanelWearing)); +		LLContextMenu* menu = createFromFile("menu_wearing_tab.xml"); + +		updateMenuItemsVisibility(menu); + +		return menu; +	} + +	void updateMenuItemsVisibility(LLContextMenu* menu) +	{ +		menu->setItemVisible("take_off", FALSE); +		menu->setItemVisible("detach", TRUE); +		menu->setItemVisible("edit_outfit_separator", TRUE); +		menu->setItemVisible("show_original", FALSE); +		menu->setItemVisible("edit_item", TRUE); +		menu->setItemVisible("edit", FALSE); +	} + +	LLPanelWearing* 		mPanelWearing; +}; + +////////////////////////////////////////////////////////////////////////// +  std::string LLPanelAppearanceTab::sFilterSubString = LLStringUtil::null;  static LLPanelInjector<LLPanelWearing> t_panel_wearing("panel_wearing"); @@ -159,30 +201,47 @@ LLPanelWearing::LLPanelWearing()  	:	LLPanelAppearanceTab()  	,	mCOFItemsList(NULL)  	,	mIsInitialized(false) +	,	mAttachmentsChangedConnection()  {  	mCategoriesObserver = new LLInventoryCategoriesObserver();  	mGearMenu = new LLWearingGearMenu(this);  	mContextMenu = new LLWearingContextMenu(); +	mAttachmentsMenu = new LLTempAttachmentsContextMenu(this);  }  LLPanelWearing::~LLPanelWearing()  {  	delete mGearMenu;  	delete mContextMenu; +	delete mAttachmentsMenu;  	if (gInventory.containsObserver(mCategoriesObserver))  	{  		gInventory.removeObserver(mCategoriesObserver);  	}  	delete mCategoriesObserver; + +	if (mAttachmentsChangedConnection.connected()) +	{ +		mAttachmentsChangedConnection.disconnect(); +	}  }  BOOL LLPanelWearing::postBuild()  { +	mAccordionCtrl = getChild<LLAccordionCtrl>("wearables_accordion"); +	mWearablesTab = getChild<LLAccordionCtrlTab>("tab_wearables"); +	mAttachmentsTab = getChild<LLAccordionCtrlTab>("tab_temp_attachments"); +	mAttachmentsTab->setDropDownStateChangedCallback(boost::bind(&LLPanelWearing::onAccordionTabStateChanged, this)); +  	mCOFItemsList = getChild<LLWearableItemsList>("cof_items_list");  	mCOFItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onWearableItemsListRightClick, this, _1, _2, _3)); +	mTempItemsList = getChild<LLScrollListCtrl>("temp_attachments_list"); +	mTempItemsList->setFgUnselectedColor(LLColor4::white); +	mTempItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onTempAttachmentsListRightClick, this, _1, _2, _3)); +  	LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");  	menu_gear_btn->setMenu(mGearMenu->getMenu()); @@ -223,6 +282,44 @@ void LLPanelWearing::onOpen(const LLSD& /*info*/)  	}  } +void LLPanelWearing::draw() +{ +	if (mUpdateTimer.getStarted() && (mUpdateTimer.getElapsedTimeF32() > 0.1)) +	{ +		mUpdateTimer.stop(); +		updateAttachmentsList(); +	} +	LLPanel::draw(); +} + +void LLPanelWearing::onAccordionTabStateChanged() +{ +	if(mAttachmentsTab->isExpanded()) +	{ +		startUpdateTimer(); +		mAttachmentsChangedConnection = LLAppearanceMgr::instance().setAttachmentsChangedCallback(boost::bind(&LLPanelWearing::startUpdateTimer, this)); +	} +	else +	{ +		if (mAttachmentsChangedConnection.connected()) +		{ +			mAttachmentsChangedConnection.disconnect(); +		} +	} +} + +void LLPanelWearing::startUpdateTimer() +{ +	if (!mUpdateTimer.getStarted()) +	{ +		mUpdateTimer.start(); +	} +	else +	{ +		mUpdateTimer.reset(); +	} +} +  // virtual  void LLPanelWearing::setFilterSubString(const std::string& string)  { @@ -251,6 +348,124 @@ bool LLPanelWearing::isActionEnabled(const LLSD& userdata)  	return false;  } +void LLPanelWearing::updateAttachmentsList() +{ +	std::vector<LLViewerObject*> attachs = LLAgentWearables::getTempAttachments(); +	mTempItemsList->deleteAllItems(); +	mAttachmentsMap.clear(); +	if(!attachs.empty()) +	{ +		if(!populateAttachmentsList()) +		{ +			requestAttachmentDetails(); +		} +	} +	else +	{ +		std::string no_attachments = getString("no_attachments"); +		LLSD row; +		row["columns"][0]["column"] = "text"; +		row["columns"][0]["value"] = no_attachments; +		row["columns"][0]["font"] = "SansSerifBold"; +		mTempItemsList->addElement(row); +	} +} + +bool LLPanelWearing::populateAttachmentsList(bool update) +{ +	bool populated = true; +	if(mTempItemsList) +	{ +		mTempItemsList->deleteAllItems(); +		mAttachmentsMap.clear(); +		std::vector<LLViewerObject*> attachs = LLAgentWearables::getTempAttachments(); + +		std::string icon_name = LLInventoryIcon::getIconName(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT); +		for (std::vector<LLViewerObject*>::iterator iter = attachs.begin(); +				iter != attachs.end(); ++iter) +		{ +			LLViewerObject *attachment = *iter; +			LLSD row; +			row["id"] = attachment->getID(); +			row["columns"][0]["column"] = "icon"; +			row["columns"][0]["type"] = "icon"; +			row["columns"][0]["value"] = icon_name; +			row["columns"][1]["column"] = "text"; +			if(mObjectNames.count(attachment->getID()) && !mObjectNames[attachment->getID()].empty()) +			{ +				row["columns"][1]["value"] = mObjectNames[attachment->getID()]; +			} +			else if(update) +			{ +				row["columns"][1]["value"] = attachment->getID(); +				populated = false; +			} +			else +			{ +				row["columns"][1]["value"] = "Loading..."; +				populated = false; +			} +			mTempItemsList->addElement(row); +			mAttachmentsMap[attachment->getID()] = attachment; +		} +	} +	return populated; +} + +void LLPanelWearing::requestAttachmentDetails() +{ +	LLSD body; +	std::string url = gAgent.getRegion()->getCapability("AttachmentResources"); +	if (!url.empty()) +	{ +		LLCoros::instance().launch("LLPanelWearing::getAttachmentLimitsCoro", +		boost::bind(&LLPanelWearing::getAttachmentLimitsCoro, this, url)); +	} +} + +void LLPanelWearing::getAttachmentLimitsCoro(std::string url) +{ +	LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +	LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +	httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy)); +	LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +	LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + +	LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +	LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +	if (!status) +	{ +		LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL; +		return; +	} + +	result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +	setAttachmentDetails(result); +} + + +void LLPanelWearing::setAttachmentDetails(LLSD content) +{ +	mObjectNames.clear(); +	S32 number_attachments = content["attachments"].size(); +	for(int i = 0; i < number_attachments; i++) +	{ +		S32 number_objects = content["attachments"][i]["objects"].size(); +		for(int j = 0; j < number_objects; j++) +		{ +			LLUUID task_id = content["attachments"][i]["objects"][j]["id"].asUUID(); +			std::string name = content["attachments"][i]["objects"][j]["name"].asString(); +			mObjectNames[task_id] = name; +		} +	} +	if(!mObjectNames.empty()) +	{ +		populateAttachmentsList(true); +	} +} +  boost::signals2::connection LLPanelWearing::setSelectionChangeCallback(commit_callback_t cb)  {  	if (!mCOFItemsList) return boost::signals2::connection(); @@ -270,6 +485,20 @@ void LLPanelWearing::onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y)  	mContextMenu->show(ctrl, selected_uuids, x, y);  } +void LLPanelWearing::onTempAttachmentsListRightClick(LLUICtrl* ctrl, S32 x, S32 y) +{ +	LLScrollListCtrl* list = dynamic_cast<LLScrollListCtrl*>(ctrl); +	if (!list) return; +	list->selectItemAt(x, y, MASK_NONE); +	uuid_vec_t selected_uuids; + +	if(list->getCurrentID().notNull()) +	{ +		selected_uuids.push_back(list->getCurrentID()); +		mAttachmentsMenu->show(ctrl, selected_uuids, x, y); +	} +} +  bool LLPanelWearing::hasItemSelected()  {  	return mCOFItemsList->getSelectedItem() != NULL; @@ -280,6 +509,28 @@ void LLPanelWearing::getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const  	mCOFItemsList->getSelectedUUIDs(selected_uuids);  } +void LLPanelWearing::onEditAttachment() +{ +	LLScrollListItem* item = mTempItemsList->getFirstSelected(); +	if (item) +	{ +		LLSelectMgr::getInstance()->deselectAll(); +		LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]); +		handle_object_edit(); +	} +} + +void LLPanelWearing::onRemoveAttachment() +{ +	LLScrollListItem* item = mTempItemsList->getFirstSelected(); +	if (item) +	{ +		LLSelectMgr::getInstance()->deselectAll(); +		LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]); +		LLSelectMgr::getInstance()->sendDropAttachment(); +	} +} +  void LLPanelWearing::copyToClipboard()  {  	std::string text; diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h index 9a212b3cca..c5cb79092a 100644 --- a/indra/newview/llpanelwearing.h +++ b/indra/newview/llpanelwearing.h @@ -31,9 +31,14 @@  // newview  #include "llpanelappearancetab.h" +#include "llselectmgr.h" +#include "lltimer.h" +class LLAccordionCtrl; +class LLAccordionCtrlTab;  class LLInventoryCategoriesObserver;  class LLListContextMenu; +class LLScrollListCtrl;  class LLWearableItemsList;  class LLWearingGearMenu; @@ -52,6 +57,8 @@ public:  	/*virtual*/ BOOL postBuild(); +	/*virtual*/ void draw(); +  	/*virtual*/ void onOpen(const LLSD& info);  	/*virtual*/ void setFilterSubString(const std::string& string); @@ -62,17 +69,43 @@ public:  	/*virtual*/ void copyToClipboard(); +	void startUpdateTimer(); +	void updateAttachmentsList(); +  	boost::signals2::connection setSelectionChangeCallback(commit_callback_t cb);  	bool hasItemSelected(); +	bool populateAttachmentsList(bool update = false); +	void onAccordionTabStateChanged(); +	void setAttachmentDetails(LLSD content); +	void requestAttachmentDetails(); +	void onEditAttachment(); +	void onRemoveAttachment(); +  private:  	void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y); +	void onTempAttachmentsListRightClick(LLUICtrl* ctrl, S32 x, S32 y); + +	void getAttachmentLimitsCoro(std::string url);  	LLInventoryCategoriesObserver* 	mCategoriesObserver;  	LLWearableItemsList* 			mCOFItemsList; +	LLScrollListCtrl*				mTempItemsList;  	LLWearingGearMenu*				mGearMenu;  	LLListContextMenu*				mContextMenu; +	LLListContextMenu*				mAttachmentsMenu; + +	LLAccordionCtrlTab* 			mWearablesTab; +	LLAccordionCtrlTab* 			mAttachmentsTab; +	LLAccordionCtrl*				mAccordionCtrl; + +	std::map<LLUUID, LLViewerObject*> mAttachmentsMap; + +	std::map<LLUUID, std::string> 	mObjectNames; + +	boost::signals2::connection 	mAttachmentsChangedConnection; +	LLFrameTimer					mUpdateTimer;  	bool							mIsInitialized;  }; diff --git a/indra/newview/llpathfindinglinksetlist.cpp b/indra/newview/llpathfindinglinksetlist.cpp index b886e46765..eb7b95552e 100644 --- a/indra/newview/llpathfindinglinksetlist.cpp +++ b/indra/newview/llpathfindinglinksetlist.cpp @@ -204,7 +204,10 @@ void LLPathfindingLinksetList::parseLinksetListData(const LLSD& pLinksetListData  	{  		const std::string& uuid(linksetDataIter->first);  		const LLSD& linksetData = linksetDataIter->second; -		LLPathfindingObjectPtr linksetPtr(new LLPathfindingLinkset(uuid, linksetData)); -		objectMap.insert(std::pair<std::string, LLPathfindingObjectPtr>(uuid, linksetPtr)); +		if(linksetData.size() != 0) +		{ +			LLPathfindingObjectPtr linksetPtr(new LLPathfindingLinkset(uuid, linksetData)); +			objectMap.insert(std::pair<std::string, LLPathfindingObjectPtr>(uuid, linksetPtr)); +		}  	}  } diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp index 9957039f72..836f63bffa 100644 --- a/indra/newview/llpresetsmanager.cpp +++ b/indra/newview/llpresetsmanager.cpp @@ -104,8 +104,7 @@ void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_nam  		if (found)  		{  			std::string path = gDirUtilp->add(dir, file); -			std::string name = gDirUtilp->getBaseFileName(LLURI::unescape(path), /*strip_exten = */ true); - +			std::string name = LLURI::unescape(gDirUtilp->getBaseFileName(path, /*strip_exten = */ true));              LL_DEBUGS() << "  Found preset '" << name << "'" << LL_ENDL;  			if (PRESETS_DEFAULT != name) diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index ba9845ef04..510d91839d 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -437,6 +437,23 @@ void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId,      }  } +void LLPreviewNotecard::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId) +{ + +    LLSD floater_key; +    floater_key["taskid"] = taskId; +    floater_key["itemid"] = itemId; +    LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", floater_key); +    if (nc) +    { +        if (nc->hasEmbeddedInventory()) +        { +            gVFS->removeFile(newAssetId, LLAssetType::AT_NOTECARD); +        } +        nc->setAssetId(newAssetId); +        nc->refreshFromInventory(); +    } +}  bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)  { @@ -485,7 +502,7 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)                  else if (!mObjectUUID.isNull() && !task_url.empty())                  {                      uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer,  -                        boost::bind(&LLPreviewNotecard::finishInventoryUpload, _1, _3, LLUUID::null))); +                        boost::bind(&LLPreviewNotecard::finishTaskUpload, _1, _3, mObjectUUID)));                      url = task_url;                  } diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index ba571995f6..017c4485ba 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -96,6 +96,7 @@ protected:  	bool handleConfirmDeleteDialog(const LLSD& notification, const LLSD& response);      static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId); +    static void finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId);  protected:  	LLViewerTextEditor* mEditor; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 5b1b356597..f28ffce602 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -375,7 +375,8 @@ LLScriptEdCore::LLScriptEdCore(  	mLiveFile(NULL),  	mLive(live),  	mContainer(container), -	mHasScriptData(FALSE) +	mHasScriptData(FALSE), +	mScriptRemoved(FALSE)  {  	setFollowsAll();  	setBorderVisible(FALSE); @@ -666,7 +667,7 @@ bool LLScriptEdCore::hasChanged()  void LLScriptEdCore::draw()  {  	BOOL script_changed	= hasChanged(); -	getChildView("Save_btn")->setEnabled(script_changed); +	getChildView("Save_btn")->setEnabled(script_changed && !mScriptRemoved);  	if( mEditor->hasFocus() )  	{ @@ -840,7 +841,7 @@ void LLScriptEdCore::addHelpItemToHistory(const std::string& help_string)  BOOL LLScriptEdCore::canClose()  { -	if(mForceClose || !hasChanged()) +	if(mForceClose || !hasChanged() || mScriptRemoved)  	{  		return TRUE;  	} @@ -1511,6 +1512,17 @@ BOOL LLPreviewLSL::postBuild()  	return LLPreview::postBuild();  } +void LLPreviewLSL::draw() +{ +	const LLInventoryItem* item = getItem(); +	if(!item) +	{ +		setTitle(LLTrans::getString("ScriptWasDeleted")); +		mScriptEd->setItemRemoved(TRUE); +	} + +	LLPreview::draw(); +}  // virtual  void LLPreviewLSL::callbackLSLCompileSucceeded()  { diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index a8c6a6eeeb..6b31125641 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -119,6 +119,8 @@ public:  	void 			setScriptName(const std::string& name){mScriptName = name;}; +	void 			setItemRemoved(bool script_removed){mScriptRemoved = script_removed;}; +  private:  	void		onBtnHelp();  	void		onBtnDynamicHelp(); @@ -163,6 +165,7 @@ private:  	BOOL			mHasScriptData;  	LLLiveLSLFile*	mLiveFile;  	LLUUID			mAssociatedExperience; +	BOOL			mScriptRemoved;  	LLScriptEdContainer* mContainer; // parent view @@ -198,6 +201,7 @@ public:  	/*virtual*/ BOOL postBuild();  protected: +	virtual void draw();  	virtual BOOL canClose();  	void closeIfNeeded(); diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 86135ee6e8..f07f0ed86c 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -383,7 +383,7 @@ void LLSidepanelAppearance::toggleOutfitEditPanel(BOOL visible, BOOL disable_cam  void LLSidepanelAppearance::toggleWearableEditPanel(BOOL visible, LLViewerWearable *wearable, BOOL disable_camera_switch)  { -	if (!mEditWearable || mEditWearable->getVisible() == visible) +	if (!mEditWearable || ((mEditWearable->getWearable() == wearable) && mEditWearable->getVisible() == visible))  	{  		// visibility isn't changing, hence nothing to do  		return; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a2c8e7772e..4e81d78455 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -771,7 +771,11 @@ bool idle_startup()  					LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL;  				}  			} - +			display_startup(); +			if (gViewerWindow->getSystemUIScaleFactorChanged()) +			{ +				LLViewerWindow::showSystemUIScaleFactorChanged(); +			}  			LLStartUp::setStartupState( STATE_LOGIN_WAIT );		// Wait for user input  		}  		else diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 37cc908e84..36c4f0d516 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1928,6 +1928,12 @@ bool LLTextureCache::writeToFastCache(S32 id, LLPointer<LLImageRaw> raw, S32 dis  		{  			//make a duplicate to keep the original raw image untouched.  			raw = raw->duplicate(); +			if (raw->isBufferInvalid()) +			{ +				LL_WARNS() << "Invalid image duplicate buffer" << LL_ENDL; +				return false; +			} +  			raw->scale(w, h) ;  			discardlevel += i ; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index ad4f903dff..24bc55c998 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1327,7 +1327,7 @@ void LLTextureCtrl::setOnTextureSelectedCallback(texture_selected_callback cb)  void	LLTextureCtrl::setImageAssetName(const std::string& name)  { -	LLPointer<LLUIImage> imagep = LLUI::getUIImage(name, LLGLTexture::BOOST_PREVIEW); +	LLPointer<LLUIImage> imagep = LLUI::getUIImage(name);  	if(imagep)  	{  		LLViewerFetchedTexture* pTexture = dynamic_cast<LLViewerFetchedTexture*>(imagep->getImage().get()); diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index c4696c3a01..caa055e5e0 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -223,6 +223,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)  		}  		if (!(pick_info.mKeyMask & MASK_ALT) && +			!LLFloaterCamera::inFreeCameraMode() &&  			gAgentCamera.cameraThirdPerson() &&  			gViewerWindow->getLeftMouseDown() &&   			!gSavedSettings.getBOOL("FreezeTime") && diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index b0e3b5bf89..f6eb290bc3 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -267,7 +267,7 @@ bool LLToolMgr::canEdit()  bool LLToolMgr::buildEnabledOrActive()  { -	return inEdit() || canEdit(); +	return LLFloaterReg::instanceVisible("build") || canEdit();  }  void LLToolMgr::toggleBuildMode(const LLSD& sdname) diff --git a/indra/newview/llviewchildren.cpp b/indra/newview/llviewchildren.cpp index 5c5bbdc8f5..32b2f7e9f5 100644 --- a/indra/newview/llviewchildren.cpp +++ b/indra/newview/llviewchildren.cpp @@ -79,8 +79,9 @@ void LLViewChildren::setBadge(const std::string& id, Badge badge, bool visible)  			default:  			case BADGE_OK:		child->setValue(std::string("badge_ok.j2c"));	break;  			case BADGE_NOTE:	child->setValue(std::string("badge_note.j2c"));	break; -			case BADGE_WARN:	child->setValue(std::string("badge_warn.j2c"));	break; -			case BADGE_ERROR:	child->setValue(std::string("badge_error.j2c"));	break; +			case BADGE_WARN: +			case BADGE_ERROR: +				child->setValue(std::string("badge_warn.j2c"));	break;  		}  	}  } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index d0813544f8..0bbe9fa2c2 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1007,6 +1007,22 @@ void activate_gesture_cb(const LLUUID& inv_item)  	LLGestureMgr::instance().activateGesture(inv_item);  } +void set_default_permissions(LLViewerInventoryItem* item, std::string perm_type) +{ +	llassert(item); +	LLPermissions perm = item->getPermissions(); +	if (perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms(perm_type) +		|| perm.getMaskGroup() != LLFloaterPerms::getGroupPerms(perm_type)) +	{ +		perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms(perm_type)); +		perm.setMaskGroup(LLFloaterPerms::getGroupPerms(perm_type)); + +		item->setPermissions(perm); + +		item->updateServer(FALSE); +	} +} +  void create_script_cb(const LLUUID& inv_item)  {  	if (!inv_item.isNull()) @@ -1014,13 +1030,9 @@ void create_script_cb(const LLUUID& inv_item)  		LLViewerInventoryItem* item = gInventory.getItem(inv_item);  		if (item)  		{ -			LLPermissions perm = item->getPermissions(); -			perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Scripts")); -			perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Scripts")); - -			item->setPermissions(perm); +			set_default_permissions(item, "Scripts"); -			item->updateServer(FALSE); +			// item was just created, update even if permissions did not changed  			gInventory.updateItem(item);  			gInventory.notifyObservers();  		} @@ -1036,13 +1048,8 @@ void create_gesture_cb(const LLUUID& inv_item)  		LLViewerInventoryItem* item = gInventory.getItem(inv_item);  		if (item)  		{ -			LLPermissions perm = item->getPermissions(); -			perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Gestures")); -			perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Gestures")); +			set_default_permissions(item, "Gestures"); -			item->setPermissions(perm); - -			item->updateServer(FALSE);  			gInventory.updateItem(item);  			gInventory.notifyObservers(); @@ -1061,13 +1068,8 @@ void create_notecard_cb(const LLUUID& inv_item)  		LLViewerInventoryItem* item = gInventory.getItem(inv_item);  		if (item)  		{ -			LLPermissions perm = item->getPermissions(); -			perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Notecards")); -			perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Notecards")); - -			item->setPermissions(perm); +			set_default_permissions(item, "Notecards"); -			item->updateServer(FALSE);  			gInventory.updateItem(item);  			gInventory.notifyObservers();  		} diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6ed063e066..78c4d98d55 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1490,7 +1490,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()  		// The null owner will keep the browser plugin from fully initializing  		// (specifically, it keeps LLPluginClassMedia from negotiating a size change,  		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) -		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0); +		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0, 1.0);  	}  } @@ -1762,7 +1762,7 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)  //////////////////////////////////////////////////////////////////////////////////////////  /*static*/ -LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target, bool clean_browser) +LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target, bool clean_browser)  {  	std::string plugin_basename = LLMIMETypes::implType(media_type);  	LLPluginClassMedia* media_source = NULL; @@ -1779,6 +1779,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_  			media_source->setOwner(owner);  			media_source->setTarget(target);  			media_source->setSize(default_width, default_height); +			media_source->setZoomFactor(zoom_factor);  			return media_source;  		} @@ -1827,6 +1828,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_  			media_source->setSize(default_width, default_height);  			media_source->setUserDataPath(user_data_path_cache, user_data_path_cookies);  			media_source->setLanguageCode(LLUI::getLanguage()); +			media_source->setZoomFactor(zoom_factor);  			// collect 'cookies enabled' setting from prefs and send to embedded browser  			bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); @@ -1883,6 +1885,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)  		// Save the previous media source's last set size before destroying it.  		mMediaWidth = mMediaSource->getSetWidth();  		mMediaHeight = mMediaSource->getSetHeight(); +		mZoomFactor = mMediaSource->getZoomFactor();  	}  	// Always delete the old media impl first. @@ -1905,7 +1908,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)  	// Save the MIME type that really caused the plugin to load  	mCurrentMimeType = mMimeType; -	LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget, mCleanBrowser); +	LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mZoomFactor, mTarget, mCleanBrowser);  	if (media_source)  	{ diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 48f0d9dc4d..1fecf15fc9 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -299,7 +299,7 @@ public:  	void setTarget(const std::string& target) { mTarget = target; }  	// utility function to create a ready-to-use media instance from a desired media type. -	static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target = LLStringUtil::null, bool clean_browser = false); +	static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target = LLStringUtil::null, bool clean_browser = false);  	// Internally set our desired browser user agent string, including  	// the Second Life version and skin name.  Used because we can diff --git a/indra/newview/llviewermedia_streamingaudio.cpp b/indra/newview/llviewermedia_streamingaudio.cpp index c107e8472c..3ccf3070ab 100644 --- a/indra/newview/llviewermedia_streamingaudio.cpp +++ b/indra/newview/llviewermedia_streamingaudio.cpp @@ -154,7 +154,8 @@ LLPluginClassMedia* LLStreamingAudio_MediaPlugins::initializeMedia(const std::st  {  	LLPluginClassMediaOwner* owner = NULL;  	S32 default_size = 1; // audio-only - be minimal, doesn't matter -	LLPluginClassMedia* media_source = LLViewerMediaImpl::newSourceFromMediaType(media_type, owner, default_size, default_size); +	F64 default_zoom = 1.0; +	LLPluginClassMedia* media_source = LLViewerMediaImpl::newSourceFromMediaType(media_type, owner, default_size, default_size, default_zoom);  	if (media_source)  	{ diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 697199df6b..39059fc01e 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -397,13 +397,15 @@ void set_merchant_SLM_menu()  	gToolBarView->enableCommand(command->id(), true);  } -void check_merchant_status() +void check_merchant_status(bool force)  {      if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth"))      { -        // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() -        LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); -         +        if (force) +        { +            // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() +            LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); +        }          // Hide SLM related menu item          gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(FALSE); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index b7bdf00157..a553bb79a2 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -83,7 +83,7 @@ BOOL enable_god_full(void* user_data);  BOOL enable_god_liaison(void* user_data);  BOOL enable_god_basic(void* user_data);  void set_underclothes_menu_options(); -void check_merchant_status(); +void check_merchant_status(bool force = false);  void exchange_callingcard(const LLUUID& dest_id); @@ -108,6 +108,7 @@ void handle_look_at_selection(const LLSD& param);  void handle_zoom_to_object(LLUUID object_id);  void handle_object_return();  void handle_object_delete(); +void handle_object_edit();  void handle_buy_land(); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 54b12cae12..b48b45502b 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -508,8 +508,8 @@ class LLFileEnableCloseAllWindows : public view_listener_t  {  	bool handleEvent(const LLSD& userdata)  	{ -		LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::getInstance(); -		LLFloaterOutfitSnapshot* floater_outfit_snapshot = LLFloaterOutfitSnapshot::getInstance(); +		LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); +		LLFloaterOutfitSnapshot* floater_outfit_snapshot = LLFloaterOutfitSnapshot::findInstance();  		bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain())  			|| (floater_outfit_snapshot && floater_outfit_snapshot->isInVisibleChain());  		bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened; @@ -523,10 +523,10 @@ class LLFileCloseAllWindows : public view_listener_t  	{  		bool app_quitting = false;  		gFloaterView->closeAllChildren(app_quitting); -		LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::getInstance(); +		LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();  		if (floater_snapshot)  			floater_snapshot->closeFloater(app_quitting); -		LLFloaterOutfitSnapshot* floater_outfit_snapshot = LLFloaterOutfitSnapshot::getInstance(); +		LLFloaterOutfitSnapshot* floater_outfit_snapshot = LLFloaterOutfitSnapshot::findInstance();  		if (floater_outfit_snapshot)  			floater_outfit_snapshot->closeFloater(app_quitting);  		if (gMenuHolder) gMenuHolder->hideMenus(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 92df3866f7..f472db080f 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1639,7 +1639,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&  			LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID);  			discard_agent_offer->startFetch(); -			if (catp || (itemp && itemp->isFinished())) +			if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished()))  			{  				discard_agent_offer->done();  			} @@ -4719,7 +4719,9 @@ void process_sound_trigger(LLMessageSystem *msg, void **)  {  	if (!gAudiop)  	{ +#if !LL_LINUX  		LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; +#endif  		return;  	} @@ -4781,7 +4783,9 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data)  {  	if (!gAudiop)  	{ +#if !LL_LINUX  		LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; +#endif  		return;  	} @@ -6601,6 +6605,11 @@ void process_script_question(LLMessageSystem *msg, void **user_data)  				if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit)  					continue; +                if (script_perm.question == "JoinAnExperience") +                { // Some experience only permissions do not have an explicit permission bit.  Add them here. +                    script_question += "    " + LLTrans::getString("ForceSitAvatar") + "\n"; +                } +  				script_question += "    " + LLTrans::getString(script_perm.question) + "\n";  			}  		} diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index 6666aecca2..2525886222 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -49,6 +49,8 @@ const std::string  GRID_UPDATE_SERVICE_URL = "update_query_url_base";  const std::string  GRID_HELPER_URI_VALUE = "helper_uri";  /// the splash page url  const std::string  GRID_LOGIN_PAGE_VALUE = "login_page"; +/// url for the web profile site +const std::string  GRID_WEB_PROFILE_VALUE = "web_profile_url";  /// internal data on system grids  const std::string  GRID_IS_SYSTEM_GRID_VALUE = "system_grid";  /// whether this is single or double names @@ -70,6 +72,8 @@ const std::string SL_UPDATE_QUERY_URL = "https://update.secondlife.com/update";  const std::string MAIN_GRID_SLURL_BASE = "http://maps.secondlife.com/secondlife/";  const std::string SYSTEM_GRID_APP_SLURL_BASE = "secondlife:///app"; +const std::string MAIN_GRID_WEB_PROFILE_URL = "https://my.secondlife.com/"; +  const char* SYSTEM_GRID_SLURL_BASE = "secondlife://%s/secondlife/";  const char* DEFAULT_SLURL_BASE = "https://%s/region/";  const char* DEFAULT_APP_SLURL_BASE = "x-grid-location-info://%s/app"; @@ -125,6 +129,7 @@ void LLGridManager::initialize(const std::string& grid_file)  				  "https://secondlife.com/helpers/",  				  DEFAULT_LOGIN_PAGE,  				  SL_UPDATE_QUERY_URL, +				  MAIN_GRID_WEB_PROFILE_URL,  				  "Agni");  	addSystemGrid(LLTrans::getString("AditiGridLabel"),  				  "util.aditi.lindenlab.com", @@ -132,6 +137,7 @@ void LLGridManager::initialize(const std::string& grid_file)  				  "http://aditi-secondlife.webdev.lindenlab.com/helpers/",  				  DEFAULT_LOGIN_PAGE,  				  SL_UPDATE_QUERY_URL, +				  "https://my.aditi.lindenlab.com/",  				  "Aditi");  	LLSD other_grids; @@ -288,6 +294,10 @@ bool LLGridManager::addGrid(LLSD& grid_data)  				{  					grid_data[GRID_HELPER_URI_VALUE] = std::string("https://") + grid + "/helpers/";  				} +				if (!grid_data.has(GRID_WEB_PROFILE_VALUE)) +				{ +					grid_data[GRID_WEB_PROFILE_VALUE] = std::string("https://") + grid + "/"; +				}  				if (!grid_data.has(GRID_LOGIN_IDENTIFIER_TYPES))  				{ @@ -302,7 +312,8 @@ bool LLGridManager::addGrid(LLSD& grid_data)  										 <<"  id:          "<<grid_data[GRID_ID_VALUE].asString()<<"\n"  										 <<"  label:       "<<grid_data[GRID_LABEL_VALUE].asString()<<"\n"  										 <<"  login page:  "<<grid_data[GRID_LOGIN_PAGE_VALUE].asString()<<"\n" -										 <<"  helper page: "<<grid_data[GRID_HELPER_URI_VALUE].asString()<<"\n"; +										 <<"  helper page: "<<grid_data[GRID_HELPER_URI_VALUE].asString()<<"\n" +										 <<"  web profile: "<<grid_data[GRID_WEB_PROFILE_VALUE].asString()<<"\n";  				/* still in LL_DEBUGS */   				for (LLSD::array_const_iterator login_uris = grid_data[GRID_LOGIN_URI_VALUE].beginArray();  					 login_uris != grid_data[GRID_LOGIN_URI_VALUE].endArray(); @@ -339,6 +350,7 @@ void LLGridManager::addSystemGrid(const std::string& label,  								  const std::string& helper,  								  const std::string& login_page,  								  const std::string& update_url_base, +								  const std::string& web_profile_url,  								  const std::string& login_id)  {  	LLSD grid = LLSD::emptyMap(); @@ -349,6 +361,7 @@ void LLGridManager::addSystemGrid(const std::string& label,  	grid[GRID_LOGIN_URI_VALUE].append(login_uri);  	grid[GRID_LOGIN_PAGE_VALUE] = login_page;  	grid[GRID_UPDATE_SERVICE_URL] = update_url_base; +	grid[GRID_WEB_PROFILE_VALUE] = web_profile_url;  	grid[GRID_IS_SYSTEM_GRID_VALUE] = true;  	grid[GRID_LOGIN_IDENTIFIER_TYPES] = LLSD::emptyArray();  	grid[GRID_LOGIN_IDENTIFIER_TYPES].append(CRED_IDENTIFIER_TYPE_AGENT); @@ -535,6 +548,21 @@ std::string LLGridManager::getLoginPage()  	return login_page;  } +std::string LLGridManager::getWebProfileURL(const std::string& grid) +{ +	std::string web_profile_url; +	std::string grid_name = getGrid(grid); +	if (!grid_name.empty()) +	{ +		web_profile_url = mGridList[grid_name][GRID_WEB_PROFILE_VALUE].asString(); +	} +	else +	{ +		LL_WARNS("GridManager")<<"invalid grid '"<<grid<<"'"<<LL_ENDL; +	} +	return web_profile_url; +} +  void LLGridManager::getLoginIdentifierTypes(LLSD& idTypes)  {  	idTypes = mGridList[mGrid][GRID_LOGIN_IDENTIFIER_TYPES]; diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h index 8526c0ba7f..228303d8e2 100644 --- a/indra/newview/llviewernetwork.h +++ b/indra/newview/llviewernetwork.h @@ -166,6 +166,13 @@ class LLGridManager : public LLSingleton<LLGridManager>  	/// Return the application URL prefix for the selected grid  	std::string getAppSLURLBase() { return getAppSLURLBase(mGrid); }	 +	/// Return the url of the resident profile web site for the given grid +	std::string getWebProfileURL(const std::string& grid); + +	/// Return the url of the resident profile web site for the selected grid +	std::string getWebProfileURL() { return getWebProfileURL(mGrid); } + +  	//@}  	/* ================================================================ @@ -216,6 +223,7 @@ class LLGridManager : public LLSingleton<LLGridManager>  					   const std::string& helper,  					   const std::string& login_page,  					   const std::string& update_url_base, +					   const std::string& web_profile_url,  					   const std::string& login_id = "");	 diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 5edc3c9745..7964bf1848 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -244,9 +244,10 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe  	mPixelArea(1024.f),  	mInventory(NULL),  	mInventorySerialNum(0), -	mRegionp( regionp ), -	mInventoryPending(FALSE), +	mInvRequestState(INVENTORY_REQUEST_STOPPED), +	mInvRequestXFerId(0),  	mInventoryDirty(FALSE), +	mRegionp(regionp),  	mDead(FALSE),  	mOrphaned(FALSE),  	mUserSelected(FALSE), @@ -1434,10 +1435,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  					setChanged(MOVED | SILHOUETTE);  				} -				else if (mText.notNull()) +				else  				{ -					mText->markDead(); -					mText = NULL; +					if (mText.notNull()) +					{ +						mText->markDead(); +						mText = NULL; +					} +					mHudText.clear();  				}  				std::string media_url; @@ -1812,10 +1817,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  					setChanged(TEXTURE);  				} -				else if(mText.notNull()) +				else  				{ -					mText->markDead(); -					mText = NULL; +					if (mText.notNull()) +					{ +						mText->markDead(); +						mText = NULL; +					} +					mHudText.clear();  				}                  std::string media_url; @@ -2832,6 +2841,11 @@ void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener)  	}  } +BOOL LLViewerObject::isInventoryPending() +{ +    return mInvRequestState != INVENTORY_REQUEST_STOPPED; +} +  void LLViewerObject::clearInventoryListeners()  {  	for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer()); @@ -2870,7 +2884,7 @@ void LLViewerObject::requestInventory()  void LLViewerObject::fetchInventoryFromServer()  { -	if (!mInventoryPending) +	if (!isInventoryPending())  	{  		delete mInventory;  		LLMessageSystem* msg = gMessageSystem; @@ -2883,7 +2897,7 @@ void LLViewerObject::fetchInventoryFromServer()  		msg->sendReliable(mRegionp->getHost());  		// this will get reset by dirtyInventory or doInventoryCallback -		mInventoryPending = TRUE; +		mInvRequestState = INVENTORY_REQUEST_PENDING;  	}  } @@ -2944,7 +2958,7 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)  	std::string unclean_filename;  	msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);  	ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); -	 +  	if(ft->mFilename.empty())  	{  		LL_DEBUGS() << "Task has no inventory" << LL_ENDL; @@ -2966,13 +2980,27 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)  		delete ft;  		return;  	} -	gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename),  +	U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename),   								ft->mFilename, LL_PATH_CACHE,  								object->mRegionp->getHost(),  								TRUE,  								&LLViewerObject::processTaskInvFile,  								(void**)ft,  								LLXferManager::HIGH_PRIORITY); +	if (object->mInvRequestState == INVENTORY_XFER) +	{ +		if (new_id > 0 && new_id != object->mInvRequestXFerId) +		{ +			// we started new download. +			gXferManager->abortRequestById(object->mInvRequestXFerId, -1); +			object->mInvRequestXFerId = new_id; +		} +	} +	else +	{ +		object->mInvRequestState = INVENTORY_XFER; +		object->mInvRequestXFerId = new_id; +	}  }  void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) @@ -3099,7 +3127,10 @@ void LLViewerObject::doInventoryCallback()  			mInventoryCallbacks.erase(curiter);  		}  	} -	mInventoryPending = FALSE; + +	// release inventory loading state +	mInvRequestXFerId = 0; +	mInvRequestState = INVENTORY_REQUEST_STOPPED;  }  void LLViewerObject::removeInventory(const LLUUID& item_id) @@ -4990,8 +5021,26 @@ void LLViewerObject::initHudText()  void LLViewerObject::restoreHudText()  { -    if(mText) +    if (mHudText.empty())      { +        if (mText) +        { +            mText->markDead(); +            mText = NULL; +        } +    } +    else +    { +        if (!mText) +        { +            initHudText(); +        } +        else +        { +            // Restore default values +            mText->setZCompare(TRUE); +            mText->setDoFade(TRUE); +        }          mText->setColor(mHudTextColor);          mText->setString(mHudText);      } @@ -6271,7 +6320,7 @@ const LLUUID &LLViewerObject::extractAttachmentItemID()  	return getAttachmentItemID();  } -const std::string& LLViewerObject::getAttachmentItemName() +const std::string& LLViewerObject::getAttachmentItemName() const  {  	static std::string empty;  	LLInventoryItem *item = gInventory.getItem(getAttachmentItemID()); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index cb8acfdcf8..1e8f3f4ec2 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -172,7 +172,7 @@ public:  	void			setOnActiveList(BOOL on_active)		{ mOnActiveList = on_active; }  	virtual BOOL	isAttachment() const { return FALSE; } -	const std::string& getAttachmentItemName(); +	const std::string& getAttachmentItemName() const;  	virtual LLVOAvatar* getAvatar() const;  //get the avatar this object is attached to, or NULL if object is not an attachment  	virtual BOOL	isHUDAttachment() const { return FALSE; } @@ -437,7 +437,7 @@ public:  	// viewer object has the inventory stored locally.  	void registerInventoryListener(LLVOInventoryListener* listener, void* user_data);  	void removeInventoryListener(LLVOInventoryListener* listener); -	BOOL isInventoryPending() { return mInventoryPending; } +	BOOL isInventoryPending();  	void clearInventoryListeners();  	bool hasInventoryListeners();  	void requestInventory(); @@ -720,6 +720,7 @@ private:  	void deleteTEImages(); // correctly deletes list of images  protected: +  	typedef std::map<char *, LLNameValue *> name_value_map_t;  	name_value_map_t mNameValuePairs;	// Any name-value pairs stored by script @@ -756,9 +757,17 @@ protected:  	callback_list_t mInventoryCallbacks;  	S16 mInventorySerialNum; +	enum EInventoryRequestState +	{ +		INVENTORY_REQUEST_STOPPED, +		INVENTORY_REQUEST_PENDING, +		INVENTORY_XFER +	}; +	EInventoryRequestState	mInvRequestState; +	U64						mInvRequestXFerId; +	BOOL					mInventoryDirty; +  	LLViewerRegion	*mRegionp;					// Region that this object belongs to. -	BOOL			mInventoryPending; -	BOOL			mInventoryDirty;  	BOOL			mDead;  	BOOL			mOrphaned;					// This is an orphaned child  	BOOL			mUserSelected;				// Cached user select information diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ed719ae418..178aa1e646 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1200,7 +1200,7 @@ void LLViewerFetchedTexture::loadFromFastCache()              {                  S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS;                  S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; -                if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) +                if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height))                  {                      // scale oversized icon, no need to give more work to gl                      mRawImage->scale(expected_width, expected_height); @@ -1981,7 +1981,7 @@ bool LLViewerFetchedTexture::updateFetch()                  {                      S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS;                      S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; -                    if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) +                    if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height))                      {                          // scale oversized icon, no need to give more work to gl                          mRawImage->scale(expected_width, expected_height); diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index 0f73515b5d..88eb13e7cd 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -451,7 +451,7 @@ void LLViewerWearable::copyDataFrom(const LLViewerWearable* src)  	// Probably reduntant, but ensure that the newly created wearable is not dirty by setting current value of params in new wearable  	// to be the same as the saved values (which were loaded from src at param->cloneParam(this)) -	revertValues(); +	revertValuesWithoutUpdate();  }  void LLViewerWearable::setItemID(const LLUUID& item_id) @@ -471,6 +471,11 @@ void LLViewerWearable::revertValues()  	}  } +void LLViewerWearable::revertValuesWithoutUpdate() +{ +	LLWearable::revertValues(); +} +  void LLViewerWearable::saveValues()  {  	LLWearable::saveValues(); diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index 62cd5e21ad..cc99f6af2f 100644 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -85,6 +85,8 @@ public:  	/*virtual*/ void	revertValues();  	/*virtual*/ void	saveValues(); +	void 				revertValuesWithoutUpdate(); +  	// Something happened that requires the wearable's label to be updated (e.g. worn/unworn).  	/*virtual*/void		setUpdated() const; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index cd9ab3e672..9e68bb78e0 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -251,6 +251,11 @@ BOOL				gDisplayBadge = FALSE;  static const U8 NO_FACE = 255;  BOOL gQuietSnapshot = FALSE; +// Minimum value for UIScaleFactor, also defined in preferences, ui_scale_slider +static const F32 MIN_UI_SCALE = 0.75f; +// 4.0 in preferences, but win10 supports larger scaling and value is used more as +// sanity check, so leaving space for larger values from DPI updates. +static const F32 MAX_UI_SCALE = 7.0f;  static const F32 MIN_DISPLAY_SCALE = 0.75f;  std::string	LLViewerWindow::sSnapshotBaseName; @@ -1593,6 +1598,20 @@ BOOL LLViewerWindow::handleDeviceChange(LLWindow *window)  	return FALSE;  } +void LLViewerWindow::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) +{ +    if (ui_scale_factor >= MIN_UI_SCALE && ui_scale_factor <= MAX_UI_SCALE) +    { +        gSavedSettings.setF32("UIScaleFactor", ui_scale_factor); +        LLViewerWindow::reshape(window_width, window_height); +        mResDirty = true; +    } +    else +    { +        LL_WARNS() << "DPI change caused UI scale to go out of bounds: " << ui_scale_factor << LL_ENDL; +    } +} +  void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg)  {  	LLAppViewer::instance()->pingMainloopTimeout(msg); @@ -1655,7 +1674,8 @@ LLViewerWindow::LLViewerWindow(const Params& p)  	mResDirty(false),  	mStatesDirty(false),  	mCurrResolutionIndex(0), -	mProgressView(NULL) +	mProgressView(NULL), +	mSystemUIScaleFactorChanged(false)  {  	// gKeyboard is still NULL, so it doesn't do LLWindowListener any good to  	// pass its value right now. Instead, pass it a nullary function that @@ -1743,9 +1763,24 @@ LLViewerWindow::LLViewerWindow(const Params& p)  		gSavedSettings.setS32("FullScreenHeight",scr.mY);      } + +	F32 system_scale_factor = mWindow->getSystemUISize(); +	if (system_scale_factor < MIN_UI_SCALE || system_scale_factor > MAX_UI_SCALE) +	{ +		// reset to default; +		system_scale_factor = 1.f; +	} +	if (p.first_run || gSavedSettings.getF32("LastSystemUIScaleFactor") != system_scale_factor) +	{ +		mSystemUIScaleFactorChanged = !p.first_run; +		gSavedSettings.setF32("LastSystemUIScaleFactor", system_scale_factor); +		gSavedSettings.setF32("UIScaleFactor", system_scale_factor); +	} + +  	// Get the real window rect the window was created with (since there are various OS-dependent reasons why  	// the size of a window or fullscreen context may have been adjusted slightly...) -	F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); +	F32 ui_scale_factor = llclamp(gSavedSettings.getF32("UIScaleFactor"), MIN_UI_SCALE, MAX_UI_SCALE);  	mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));  	mDisplayScale *= ui_scale_factor; @@ -1838,6 +1873,28 @@ LLViewerWindow::LLViewerWindow(const Params& p)  	mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);  } +//static +void LLViewerWindow::showSystemUIScaleFactorChanged() +{ +	LLNotificationsUtil::add("SystemUIScaleFactorChanged", LLSD(), LLSD(), onSystemUIScaleFactorChanged); +} + +//static +bool LLViewerWindow::onSystemUIScaleFactorChanged(const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	if(option == 0) +	{ +		LLFloaterReg::toggleInstanceOrBringToFront("preferences"); +		LLFloater* pref_floater = LLFloaterReg::getInstance("preferences"); +		LLTabContainer* tab_container = pref_floater->getChild<LLTabContainer>("pref core"); +		tab_container->selectTabByName("advanced1"); + +	} +	return false;  +} + +  void LLViewerWindow::initGLDefaults()  {  	gGL.setSceneBlendType(LLRender::BT_ALPHA); @@ -5211,7 +5268,7 @@ F32	LLViewerWindow::getWorldViewAspectRatio() const  void LLViewerWindow::calcDisplayScale()  { -	F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); +	F32 ui_scale_factor = llclamp(gSavedSettings.getF32("UIScaleFactor"), MIN_UI_SCALE, MAX_UI_SCALE);  	LLVector2 display_scale;  	display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));  	display_scale *= ui_scale_factor; @@ -5224,7 +5281,7 @@ void LLViewerWindow::calcDisplayScale()  	if (display_scale != mDisplayScale)  	{ -		LL_INFOS() << "Setting display scale to " << display_scale << LL_ENDL; +		LL_INFOS() << "Setting display scale to " << display_scale << " for ui scale: " << ui_scale_factor << LL_ENDL;  		mDisplayScale = display_scale;  		// Init default fonts diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index cdf5b686a7..72b7370621 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -156,7 +156,8 @@ public:  									min_width,  									min_height;  		Optional<bool>				fullscreen, -									ignore_pixel_depth; +									ignore_pixel_depth, +									first_run;  		Params();  	}; @@ -210,6 +211,7 @@ public:  	/*virtual*/ void handleDataCopy(LLWindow *window, S32 data_type, void *data);  	/*virtual*/ BOOL handleTimerEvent(LLWindow *window);  	/*virtual*/ BOOL handleDeviceChange(LLWindow *window); +	/*virtual*/ void handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height);  	/*virtual*/ void handlePingWatchdog(LLWindow *window, const char * msg);  	/*virtual*/ void handlePauseWatchdog(LLWindow *window); @@ -415,6 +417,9 @@ public:  	void			calcDisplayScale();  	static LLRect 	calcScaledRect(const LLRect & rect, const LLVector2& display_scale); +	bool getSystemUIScaleFactorChanged() { return mSystemUIScaleFactorChanged; } +	static void showSystemUIScaleFactorChanged(); +  private:  	bool                    shouldShowToolTipFor(LLMouseHandler *mh); @@ -428,6 +433,7 @@ private:  	S32				getChatConsoleBottomPad(); // Vertical padding for child console rect, varied by bottom clutter  	LLRect			getChatConsoleRect(); // Get optimal cosole rect. +	static bool onSystemUIScaleFactorChanged(const LLSD& notification, const LLSD& response);  private:  	LLWindow*		mWindow;						// graphical window object  	bool			mActive; @@ -506,6 +512,7 @@ private:  	LLPointer<LLViewerObject>	mDragHoveredObject;  	static LLTrace::SampleStatHandle<>	sMouseVelocityStat; +	bool mSystemUIScaleFactorChanged; // system UI scale factor changed from last run  };  // diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index cdc7e20c2c..1425b3d42e 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -186,6 +186,7 @@ const F32 NAMETAG_VERTICAL_SCREEN_OFFSET = 25.f;  const F32 NAMETAG_VERT_OFFSET_WEIGHT = 0.17f;  const U32 LLVOAvatar::VISUAL_COMPLEXITY_UNKNOWN = 0; +const F64 HUD_OVERSIZED_TEXTURE_DATA_SIZE = 1024 * 1024;  enum ERenderName  { @@ -7391,16 +7392,13 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  	// No backsies zone - if we get here, the message should be valid and usable, will be processed.      LL_INFOS("Avatar") << "Processing appearance message version " << thisAppearanceVersion << LL_ENDL; -    if (isSelf()) -    { -        // Note: -        // locally the COF is maintained via LLInventoryModel::accountForUpdate -        // which is called from various places.  This should match the simhost's  -        // idea of what the COF version is.  AIS however maintains its own version -        // of the COF that should be considered canonical.  -        mLastUpdateReceivedCOFVersion = thisAppearanceVersion; -    } -		 +    // Note: +    // locally the COF is maintained via LLInventoryModel::accountForUpdate +    // which is called from various places.  This should match the simhost's  +    // idea of what the COF version is.  AIS however maintains its own version +    // of the COF that should be considered canonical.  +    mLastUpdateReceivedCOFVersion = thisAppearanceVersion; +      if (applyParsedTEMessage(contents.mTEContents) > 0 && isChanged(TEXTURE))      {          updateVisualComplexity(); @@ -8356,6 +8354,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity()  	{  		U32 cost = VISUAL_COMPLEXITY_UNKNOWN;  		LLVOVolume::texture_cost_t textures; +		hud_complexity_list_t hud_complexity_list;  		for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)  		{ @@ -8432,6 +8431,63 @@ void LLVOAvatar::calculateUpdateRenderComplexity()  						}  					}  				} +                if (isSelf() +                    && attached_object +                    && attached_object->isHUDAttachment() +                    && !attached_object->isTempAttachment() +                    && attached_object->mDrawable) +                { +                    textures.clear(); + +                    const LLVOVolume* volume = attached_object->mDrawable->getVOVolume(); +                    if (volume) +                    { +                        LLHUDComplexity hud_object_complexity; +                        hud_object_complexity.objectName = attached_object->getAttachmentItemName(); +                        hud_object_complexity.objectId = attached_object->getAttachmentItemID(); +                        std::string joint_name; +                        gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); +                        hud_object_complexity.jointName = joint_name; +                        // get cost and individual textures +                        hud_object_complexity.objectsCost += volume->getRenderCost(textures); +                        hud_object_complexity.objectsCount++; + +                        LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); +                        for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +                            iter != child_list.end(); ++iter) +                        { +                            LLViewerObject* childp = *iter; +                            const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp); +                            if (chld_volume) +                            { +                                // get cost and individual textures +                                hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures); +                                hud_object_complexity.objectsCount++; +                            } +                        } + +                        hud_object_complexity.texturesCount += textures.size(); + +                        for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); +                            volume_texture != textures.end(); +                            ++volume_texture) +                        { +                            // add the cost of each individual texture (ignores duplicates) +                            hud_object_complexity.texturesCost += volume_texture->second; +                            LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first); +                            if (tex) +                            { +                                // Note: Texture memory might be incorect since texture might be still loading. +                                hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory(); +                                if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) +                                { +                                    hud_object_complexity.largeTexturesCount++; +                                } +                            } +                        } +                        hud_complexity_list.push_back(hud_object_complexity); +                    } +                }  			}  		} @@ -8493,11 +8549,15 @@ void LLVOAvatar::calculateUpdateRenderComplexity()          static LLCachedControl<U32> show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20); -		if (isSelf() && show_my_complexity_changes) -		{ -			LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity); -		} -	} +        if (isSelf() && show_my_complexity_changes) +        { +            // Avatar complexity +            LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity); + +            // HUD complexity +            LLHUDRenderNotifier::getInstance()->updateNotificationHUD(hud_complexity_list); +        } +    }  }  void LLVOAvatar::setVisualMuteSettings(VisualMuteSettings set) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e69a8d1d1d..8c026bae21 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4429,7 +4429,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,  	LL_RECORD_BLOCK_TIME(FTM_REGISTER_FACE);  	if (type == LLRenderPass::PASS_ALPHA && facep->getTextureEntry()->getMaterialParams().notNull() && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT))  	{ -		LL_WARNS("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; +		LL_WARNS_ONCE("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL;  	}  	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 97a9eb7f5f..cc3645131d 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -322,7 +322,7 @@ public:          mBoundListener =              LLEventPumps::instance().              obtain("mainloop"). -            listen(LLEventPump::inventName(), boost::bind(&Poller::poll, this, _1)); +            listen(LLEventPump::ANONYMOUS, boost::bind(&Poller::poll, this, _1));          LL_INFOS("LLXMLRPCListener") << mMethod << " request sent to " << mUri << LL_ENDL;      } diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 670410c3d4..f2da22256c 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -777,6 +777,9 @@ with the same filename but different name    <texture name="default_land_picture.j2c" />    <texture name="default_profile_picture.j2c" />    <texture name="locked_image.j2c" /> +  <texture name="badge_note.j2c" /> +  <texture name="badge_warn.j2c" /> +  <texture name="badge_ok.j2c" />    <texture name="materials_ui_x_24.png" />    <texture name="Progress_1" file_name="icons/Progress_1.png" preload="true" /> diff --git a/indra/newview/skins/default/xui/de/panel_status_bar.xml b/indra/newview/skins/default/xui/de/panel_status_bar.xml index d3d85de3c3..b0cb1e0592 100644 --- a/indra/newview/skins/default/xui/de/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/de/panel_status_bar.xml @@ -5,7 +5,7 @@  	<panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string>  	<panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string>  	<panel.string name="buycurrencylabel">[AMT] L$</panel.string> -	<panel left="-415" name="balance_bg" width="205"> +	<panel left="-436" name="balance_bg" width="205">  		<text name="balance" tool_tip="Klicken, um L$-Guthaben zu aktualisieren" value="L$ ??"/>  		<button label="L$ kaufen" name="buyL" tool_tip="Hier klicken, um mehr L$ zu kaufen"/>  		<button label="Einkaufen" name="goShop" tool_tip="Second Life-Marktplatz öffnen" width="85"/> diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 2bd3aa8bcc..c6b91a8b2f 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -117,7 +117,7 @@    <slider      control_name="IndirectMaxComplexity" -    tool_tip="Controls at what point a visually complex avatar is drawn as a jelly doll" +    tool_tip="Controls at what point a visually complex avatar is drawn as a JellyDoll"      follows="left|top"      height="16"      initial_value="101" diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml index af62c7a9bc..225266af86 100644 --- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml +++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml @@ -21,14 +21,6 @@       name="screenshot"       top="15"       width="220" /> -    <check_box -     height="15" -     label="Use this screenshot" -     layout="topleft" -     left="8" -     name="screen_check" -     top_pad="-12" -     width="116" />      <text       type="string"       length="1" @@ -39,7 +31,7 @@       layout="topleft"       left="10"       name="reporter_title" -     top_pad="0" +     top_pad="-2"       width="100">          Reporter:      </text> diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml index 5d05ecf127..550af03683 100644 --- a/indra/newview/skins/default/xui/en/fonts.xml +++ b/indra/newview/skins/default/xui/en/fonts.xml @@ -10,6 +10,7 @@        <file>ArialUni.ttf</file>      </os>      <os name="Mac"> +      <file>ヒラギノ角ゴシック W3.ttc</file>          <file>ヒラギノ角ゴ Pro W3.otf</file>        <file>ヒラギノ角ゴ ProN W3.otf</file>        <file>ヒラギノ明朝 ProN W3.ttc</file> diff --git a/indra/newview/skins/default/xui/en/inspect_group.xml b/indra/newview/skins/default/xui/en/inspect_group.xml index 324ff3eabd..a69585074c 100644 --- a/indra/newview/skins/default/xui/en/inspect_group.xml +++ b/indra/newview/skins/default/xui/en/inspect_group.xml @@ -66,7 +66,7 @@ Fear the moose!  Fear it!  And the mongoose too!     width="220">  L$123 to join    </text> -  <icon +  <group_icon       follows="all"       height="38"       right="-10" diff --git a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml index 44b2727671..75c1de24aa 100644 --- a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml @@ -28,6 +28,13 @@           function="Wearing.Edit" />      </menu_item_call>      <menu_item_call +     label="Edit" +     layout="topleft" +     name="edit_item"> +        <on_click +         function="Wearing.EditItem" /> +    </menu_item_call> +    <menu_item_call       label="Show Original"       layout="topleft"       name="show_original"> diff --git a/indra/newview/skins/default/xui/en/mime_types.xml b/indra/newview/skins/default/xui/en/mime_types.xml index c27fac6731..8d8d546b24 100644 --- a/indra/newview/skins/default/xui/en/mime_types.xml +++ b/indra/newview/skins/default/xui/en/mime_types.xml @@ -130,7 +130,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_cef +			media_plugin_libvlc  		</impl>  	</scheme>    <scheme name="libvlc"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index b2425649a4..804235518e 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -832,6 +832,13 @@ If you no longer wish to have these abilities granted to this role, disable them    </notification>    <notification +    icon="notify.tga" +    name="GroupBanUserOnBanlist" +    type="notify"> +Some residents have not been sent an invite due to being banned from the group. +  </notification> + +  <notification     icon="alertmodal.tga"     name="AttachmentDrop"     type="alertmodal"> @@ -1476,6 +1483,7 @@ Save Changes?     icon="alertmodal.tga"     name="DeleteNotecard"     type="alertmodal"> +   <unique/>  Delete Notecard?      <tag>confirm</tag>      <usetemplate @@ -1631,14 +1639,14 @@ Visit [_URL] for more information?    <notification     icon="alertmodal.tga" -   name="IntelOldDriver" +   name="OldGPUDriver"     type="alertmodal">       There is likely a newer driver for your graphics chip.  Updating graphics drivers can substantially improve performance. -    Visit [_URL] to check for driver updates? +    Visit [URL] to check for driver updates?      <tag>confirm</tag>      <url option="0" name="url"> -      http://www.intel.com/p/en_US/support/detect/graphics +    [URL]      </url>      <usetemplate       ignoretext="My graphics driver is out of date" @@ -1650,45 +1658,6 @@ Visit [_URL] for more information?    <notification     icon="alertmodal.tga" -   name="AMDOldDriver" -   type="alertmodal"> -    There is likely a newer driver for your graphics chip.  Updating graphics drivers can substantially improve performance. - -    Visit [_URL] to check for driver updates? -    <tag>confirm</tag> -    <url option="0" name="url"> -      http://support.amd.com/us/Pages/AMDSupportHub.aspx -    </url> -    <usetemplate -     ignoretext="My graphics driver is out of date" -     name="okcancelignore" -     notext="No" -     yestext="Yes"/> -    <tag>fail</tag> -  </notification> - -  <notification - icon="alertmodal.tga" - name="NVIDIAOldDriver" - type="alertmodal"> -    There is likely a newer driver for your graphics chip.  Updating graphics drivers can substantially improve performance. - -    Visit [_URL] to check for driver updates? -    <tag>confirm</tag> -    <url option="0" name="url"> -      http://www.nvidia.com/Download/index.aspx?lang=en-us -    </url> -    <usetemplate -     ignoretext="My graphics driver is out of date" -     name="okcancelignore" -     notext="No" -     yestext="Yes"/> -    <tag>fail</tag> -  </notification> - - -  <notification -   icon="alertmodal.tga"     name="UnknownGPU"     type="alertmodal">  Your system contains a graphics card that [APP_NAME] doesn't recognize. @@ -3349,6 +3318,23 @@ Your [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Renderin       <context>AgentComplexityNotice</context>     </unique>  Your [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 avatar complexity] is [AGENT_COMPLEXITY]. +    <usetemplate +     ignoretext="Warn me about my avatar complexity changes" +     name="notifyignore"/> +  </notification> + +  <notification +   icon = "notifytip.tga" +   name = "HUDComplexityWarning" +   type = "notifytip" +   log_to_chat = "false"> +    <unique combine = "cancel_old"> +      <context>HUDComplexityWarning</context> +    </unique> +    [HUD_REASON], it is likely to negatively affect your performance. +    <usetemplate +     ignoretext="Warn me when my HUD complexity is too high" +     name="notifyignore"/>    </notification>    <notification @@ -3665,6 +3651,13 @@ Can't add estate owner to estate 'Banned Resident' list.    <notification     icon="alertmodal.tga" +   name="ProblemAddingEstateManagerBanned" +   type="alertmodal"> +Unable to add banned resident to estate manager list. +  </notification> + +  <notification +   icon="alertmodal.tga"     name="CanNotChangeAppearanceUntilLoaded"     type="alertmodal">  Can't change appearance until clothing and shape are loaded. @@ -4059,6 +4052,18 @@ Do you want to open your Web browser to view this content?    <notification     icon="alertmodal.tga" +   name="SystemUIScaleFactorChanged" +   type="alertmodal"> +System UI size factor has changed since last run. Do you want to open UI size adjustment settings page? +    <tag>confirm</tag> +    <usetemplate +     name="okcancelbuttons" +     notext="Cancel" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga"     name="WebLaunchJoinNow"     type="alertmodal">  Go to your [http://secondlife.com/account/ Dashboard] to manage your account? @@ -4178,6 +4183,14 @@ Leave Group?    </notification>    <notification +   icon="notify.tga" +   name="GroupDepart" +   type="notify"> +You have left the group '[group_name]'. +    <tag>group</tag> +  </notification> + +  <notification     icon="alertmodal.tga"     name="OwnerCannotLeaveGroup"     type="alertmodal"> @@ -4189,6 +4202,17 @@ Leave Group?    </notification>    <notification +   icon="alertmodal.tga" +   name="GroupDepartError" +   type="alertmodal"> +    Unable to leave group. +    <tag>group</tag> +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification     icon="alert.tga"     name="ConfirmKick"     type="alert"> @@ -5310,6 +5334,17 @@ There are too many prims selected.  Please select [MAX_PRIM_COUNT] or fewer prim  	</notification>  	<notification +	  icon="alertmodal.tga" +	  name="TooManyScriptsSelected" +	  type="alertmodal"> +Too many scripts in the objects selected.  Please select fewer objects and try again +  <tag>fail</tag> +		<usetemplate +		 name="okbutton" +		 yestext="OK"/> +	</notification> + +	<notification     icon="alertmodal.tga"     name="ProblemImportingEstateCovenant"     type="alertmodal"> @@ -5728,6 +5763,17 @@ Warning: The 'Pay object' click action has been set, but it will only    <notification     icon="alertmodal.tga" +   name="PaymentBlockedButtonMismatch" +   type="alertmodal"> +    Payment stopped:  the price paid does not match any of the pay buttons set for this object. +    <tag>fail</tag> +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga"     name="OpenObjectCannotCopy"     type="alertmodal">  There are no items in this object that you are allowed to copy. @@ -5830,7 +5876,20 @@ You cannot undo this action.       notext="Cancel"       yestext="Unlink"/>    </notification> - +   +  <notification +   icon="alertmodal.tga" +   name="HelpReportAbuseConfirm" +   type="alertmodal"> +   <unique/> +Thank you for taking the time to inform us of this issue.  +We will review your report for possible violations and take +the appropriate action. +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> +      <notification     icon="alertmodal.tga"     name="HelpReportAbuseSelectCategory" @@ -7339,7 +7398,8 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th     name="TeleportOffered_MaturityExceeded"     log_to_im="true"     log_to_chat="false" -   type="offer"> +   type="offer" +   sound="UISndNewIncomingIMSession">  [NAME_SLURL] has offered to teleport you to their location:  “[MESSAGE]” @@ -7364,7 +7424,8 @@ This region contains [REGION_CONTENT_MATURITY] content, but your current prefere     name="TeleportOffered_MaturityBlocked"     log_to_im="true"     log_to_chat="false" -   type="notifytip"> +   type="notifytip" +   sound="UISndNewIncomingIMSession">  [NAME_SLURL] has offered to teleport you to their location:  “[MESSAGE]” @@ -8804,23 +8865,6 @@ Click and drag anywhere on the world to rotate your view    </notification>    <notification -  name="PopupAttempt" -  icon="Popup_Caution" -  type="browser"> -    A pop-up was prevented from opening. -    <form name="form"> -      <ignore name="ignore" -              control="MediaEnablePopups" -              invert_control="true" -              text="Enable all pop-ups"/> -      <button default="true" -              index="0" -              name="open" -              text="Open pop-up window"/> -    </form> -  </notification> - -  <notification     icon="alertmodal.tga"     name="SOCKS_NOT_PERMITTED"     type="alertmodal"> @@ -9802,6 +9846,14 @@ Can't move object '[OBJECT_NAME]' to    <notification     icon="alertmodal.tga" +   name="NoParcelPermsNoObject" +   type="notify"> +   <tag>fail</tag> +Copy failed because you lack access to that parcel. +  </notification> + +  <notification +   icon="alertmodal.tga"     name="CantMoveObjectRegionVersion"     type="notify">     <tag>fail</tag> @@ -9837,6 +9889,17 @@ You don't have permission to modify that object    <notification     icon="alertmodal.tga" +   name="TooMuchObjectInventorySelected" +   type="alertmodal"> +    <tag>fail</tag> +    Too many objects with large inventory are selected. Please select fewer objects and try again. +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification +   icon="alertmodal.tga"     name="CantEnablePhysObjContributesToNav"     type="notify">     <tag>fail</tag> @@ -9934,6 +9997,22 @@ Cannot save to object contents: This would modify the attachment permissions.    <notification     icon="alertmodal.tga" +   name="AttachmentHasTooMuchInventory" +   type="notify"> +   <tag>fail</tag> +Your attachments contain too much inventory to add more. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="IllegalAttachment" +   type="notify"> +   <tag>fail</tag> +The attachment has requested a nonexistent point on the avatar. It has been attached to the chest instead. +  </notification> + +  <notification +   icon="alertmodal.tga"     name="TooManyScripts"     type="notify">     <tag>fail</tag> @@ -10183,6 +10262,22 @@ You have been teleported by the object '[OBJECT_NAME]' owned by an unknown user.    <notification     icon="alertmodal.tga" +   name="StandDeniedByObject" +   type="notify"> +    <tag>fail</tag> +'[OBJECT_NAME]' will not allow you to stand at this time. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="ResitDeniedByObject" +   type="notify"> +    <tag>fail</tag> +'[OBJECT_NAME]' will not allow you to change your seat at this time. +  </notification> + +  <notification +   icon="alertmodal.tga"     name="CantCreateObjectRegionFull"     type="notify">     <tag>fail</tag> @@ -10972,6 +11067,14 @@ Money transfers to objects are currently disabled in this region.    <notification     icon="alertmodal.tga" +   name="DroppedMoneyTransferRequest" +   type="notify"> +   <tag>fail</tag> +Unable to make payment due to system load. +  </notification> + +  <notification +   icon="alertmodal.tga"     name="CantPayNoAgent"     type="notify">     <tag>fail</tag> diff --git a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml index d85b778db2..42a7974316 100644 --- a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml +++ b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml @@ -9,6 +9,26 @@   name="Wearing"   top="0"   width="312"> +<panel.string +    name="no_attachments"> +    No attachments worn. +   </panel.string> +     <accordion +     fit_parent="true" +     follows="all" +     height="400" +     layout="topleft" +     left="0" +     single_expansion="true" +     top="0" +     name="wearables_accordion" +     background_visible="true" +     bg_alpha_color="DkGray2" +     width="309"> +     <accordion_tab +     layout="topleft" +     name="tab_wearables" +     title="Wearables">      <wearable_items_list       follows="all"       height="400" @@ -20,6 +40,27 @@       top="0"       width="309"       worn_indication_enabled="false" /> +     </accordion_tab> +     <accordion_tab +     layout="topleft" +     name="tab_temp_attachments" +     title="Temporary attachments"> +    <scroll_list +     draw_heading="false" +     left="3" +     width="309" +     height="400" +     follows="all" +     name="temp_attachments_list"> +        <scroll_list.columns +         name="icon" +         width="15" /> +        <scroll_list.columns +         name="text" +         width="210" /> +  </scroll_list> +     </accordion_tab> +     </accordion>      <panel       background_visible="true"       follows="bottom|left|right" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 4a5117adac..0deb1d03cf 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -138,7 +138,7 @@     initial_value="1"     layout="topleft"     left_pad="0" -   max_val="2.0" +   max_val="4.0"     min_val="0.75"     name="ui_scale_slider"     top_pad="-14" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index a9b8e197bc..e002d9dee1 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -233,7 +233,7 @@    <slider      control_name="IndirectMaxComplexity" -    tool_tip="Controls at what point a visually complex avatar is drawn as a jelly doll" +    tool_tip="Controls at what point a visually complex avatar is drawn as a JellyDoll"      follows="left|top"      height="16"      initial_value="101" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 0b605cf6f7..c20f9b2c51 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -273,6 +273,18 @@      name="update_willing_to_test"      width="400"                 top_pad="5"/> +  <check_box +    top_delta="4" +    enabled="true" +    follows="left|top" +    height="14" +    control_name="UpdaterShowReleaseNotes" +    label="Show Release Notes after update" +    left_delta="0" +    mouse_opaque="true" +    name="update_show_release_notes" +    width="400" +    top_pad="5"/>    <text       type="string"       length="1" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index b70ed5c306..9b3fb06bdf 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -500,6 +500,7 @@ Please try logging in again in a minute.</string>  	<string name="TeleportYourAgent">Teleport you</string>  	<string name="ManageEstateSilently">Manage your estates silently</string>  	<string name="ChangeYourDefaultAnimations">Change your default animations</string> +	<string name="ForceSitAvatar">Force your avatar to sit</string>  	<string name="NotConnected">Not Connected</string>  	<string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name --> @@ -2500,6 +2501,15 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f    <string name="av_render_most_of">You may not be rendered by most of those around you.</string>    <string name="av_render_anyone">You may not be rendered by anyone around you.</string> +  <!-- HUD complexity rendering messages, see llavatarrendernotifier. --> +  <string name="hud_description_total">Your HUD</string> +  <string name="hud_name_with_joint">[OBJ_NAME] (worn on [JNT_NAME])</string> +  <string name="hud_render_memory_warning">[HUD_DETAILS] uses a lot of texture memory</string> +  <string name="hud_render_cost_warning">[HUD_DETAILS] contains a lot of expensive objects and textures</string> +  <string name="hud_render_heavy_textures_warning">[HUD_DETAILS] contains a lot of large textures</string> +  <string name="hud_render_cramped_warning">[HUD_DETAILS] contains too many objects</string> +  <string name="hud_render_textures_warning">[HUD_DETAILS] contains too many textures</string> +    <!-- AgeYearsA = singular,         AgeYearsB = plural,         AgeYearsC = plural for non-English languages like Russian @@ -2567,7 +2577,8 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f  	<string name="SaveComplete">Save complete.</string>  	<string name="UploadFailed">File upload failed: </string>  	<string name="ObjectOutOfRange">Script (object out of range)</string> - +	<string name="ScriptWasDeleted">Script (deleted from inventory)</string> +	  	<!-- god tools -->  	<string name="GodToolsObjectOwnedBy">Object [OBJECT] owned by [OWNER]</string> @@ -2835,6 +2846,12 @@ Expected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh  	<string name="Multiple Media">Multiple Media</string>  	<string name="Play Media">Play/Pause Media</string> +	<!-- Drivers support/update pages --> +	<string name="IntelDriverPage">http://www.intel.com/p/en_US/support/detect/graphics</string> +	<string name="NvidiaDriverPage">http://www.nvidia.com/Download/index.aspx?lang=en-us</string> +	<string name="AMDDriverPage">http://support.amd.com/us/Pages/AMDSupportHub.aspx</string> + +  	<!-- OSMessageBox messages -->  	<string name="MBCmdLineError">  		An error was found parsing the command line. diff --git a/indra/newview/skins/default/xui/es/panel_status_bar.xml b/indra/newview/skins/default/xui/es/panel_status_bar.xml index 8ea56c5262..8aaa236475 100644 --- a/indra/newview/skins/default/xui/es/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/es/panel_status_bar.xml @@ -5,7 +5,7 @@  	<panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string>  	<panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string>  	<panel.string name="buycurrencylabel">[AMT] L$</panel.string> -	<panel left="-410" name="balance_bg" width="200"> +	<panel left="-431" name="balance_bg" width="200">  		<text name="balance" tool_tip="Haz clic para actualizar tu saldo en L$" value="L$??"/>  		<button label="Comprar L$" name="buyL" tool_tip="Pulsa para comprar más L$"/>  		<button label="Comprar" name="goShop" tool_tip="Abrir el mercado de Second Life" width="80"/> diff --git a/indra/newview/skins/default/xui/fr/panel_status_bar.xml b/indra/newview/skins/default/xui/fr/panel_status_bar.xml index e2f05a525e..fef0379c2c 100644 --- a/indra/newview/skins/default/xui/fr/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/fr/panel_status_bar.xml @@ -5,7 +5,7 @@  	<panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string>  	<panel.string name="timeTooltip">[weekday, datetime, slt] [sday, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string>  	<panel.string name="buycurrencylabel">[AMT] L$</panel.string> -	<panel left="-405" name="balance_bg" width="195"> +	<panel left="-426" name="balance_bg" width="195">  		<text name="balance" tool_tip="Cliquer sur ce bouton pour actualiser votre solde en L$." value="L$ ??"/>  		<button label="Acheter L$" name="buyL" tool_tip="Cliquer pour acheter plus de L$."/>  		<button label="Achats" name="goShop" tool_tip="Ouvrir la Place du marché Second Life." width="75"/> diff --git a/indra/newview/skins/default/xui/it/panel_status_bar.xml b/indra/newview/skins/default/xui/it/panel_status_bar.xml index 83d2ae5bab..295ca8d9f2 100644 --- a/indra/newview/skins/default/xui/it/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/it/panel_status_bar.xml @@ -5,7 +5,7 @@  	<panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string>  	<panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string>  	<panel.string name="buycurrencylabel">L$ [AMT]</panel.string> -	<panel left="-405" name="balance_bg" width="195"> +	<panel left="-426" name="balance_bg" width="195">  		<text name="balance" tool_tip="Clicca per aggiornare il tuo saldo in L$" value="L$ ??"/>  		<button label="Acquista L$" name="buyL" tool_tip="Clicca per acquistare più L$"/>  		<button label="Acquisti" name="goShop" tool_tip="Apri Mercato Second Life" width="75"/> diff --git a/indra/newview/skins/default/xui/ja/panel_status_bar.xml b/indra/newview/skins/default/xui/ja/panel_status_bar.xml index 2e1446d450..3f3845e491 100644 --- a/indra/newview/skins/default/xui/ja/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/ja/panel_status_bar.xml @@ -5,7 +5,7 @@  	<panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string>  	<panel.string name="timeTooltip">[year, datetime, slt] [month, datetime, slt] [day, datetime, slt] ([weekday, datetime, slt])</panel.string>  	<panel.string name="buycurrencylabel">L$ [AMT]</panel.string> -	<panel left="-370" name="balance_bg" width="160"> +	<panel left="-391" name="balance_bg" width="160">  		<text name="balance" tool_tip="クリックして L$ 残高を更新" value="L$??"/>  		<button label="L$ の購入" name="buyL" tool_tip="クリックして L$ を購入します"/>  		<button label="店" name="goShop" tool_tip="Second Life マーケットプレイスを開く" width="40"/> diff --git a/indra/newview/skins/default/xui/pt/panel_status_bar.xml b/indra/newview/skins/default/xui/pt/panel_status_bar.xml index cfe52ff404..c35863734f 100644 --- a/indra/newview/skins/default/xui/pt/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/pt/panel_status_bar.xml @@ -5,7 +5,7 @@  	<panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string>  	<panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string>  	<panel.string name="buycurrencylabel">L$ [AMT]</panel.string> -	<panel left="-410" name="balance_bg" width="200"> +	<panel left="-431" name="balance_bg" width="200">  		<text name="balance" tool_tip="Atualizar saldo de L$" value="L$??"/>  		<button label="Comprar L$" name="buyL" tool_tip="Comprar mais L$"/>  		<button label="Comprar" name="goShop" tool_tip="Abrir Mercado do Second Life" width="80"/> diff --git a/indra/newview/skins/default/xui/ru/panel_status_bar.xml b/indra/newview/skins/default/xui/ru/panel_status_bar.xml index 630925fa60..49c48ae654 100644 --- a/indra/newview/skins/default/xui/ru/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/ru/panel_status_bar.xml @@ -5,7 +5,7 @@  	<panel.string name="time">[hour, datetime, slt]:[min, datetime, slt] [timezone,datetime, slt]</panel.string>  	<panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string>  	<panel.string name="buycurrencylabel">L$ [AMT]</panel.string> -	<panel left="-450" name="balance_bg" width="240"> +	<panel left="-471" name="balance_bg" width="240">  		<text name="balance" tool_tip="Щелкните для обновления вашего баланса L$" value="L$??"/>  		<button label="Купить L$" name="buyL" tool_tip="Щелкните для покупки L$"/>  		<button label="Торговый центр" name="goShop" tool_tip="Открыть торговый центр Second Life" width="121"/> diff --git a/indra/newview/skins/default/xui/tr/panel_status_bar.xml b/indra/newview/skins/default/xui/tr/panel_status_bar.xml index 9e2669ec2b..7c7bfc7e14 100644 --- a/indra/newview/skins/default/xui/tr/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/tr/panel_status_bar.xml @@ -5,7 +5,7 @@  	<panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string>  	<panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string>  	<panel.string name="buycurrencylabel">L$ [AMT]</panel.string> -	<panel left="-425" name="balance_bg" width="215"> +	<panel left="-446" name="balance_bg" width="215">  		<text name="balance" tool_tip="L$ bakiyenizi yenilemek için buraya tıklayın" value="L$??"/>  		<button label="L$ Satın Al" name="buyL" tool_tip="Daha fazla L$ satın almak için tıklayın"/>  		<button label="Alışveriş yap" name="goShop" tool_tip="Second Life Pazaryeri Aç" width="95"/> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 1b0334498e..b603157ca7 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -136,6 +136,7 @@ void LLGridManager::addSystemGrid(const std::string& label,  								  const std::string& helper,  								  const std::string& login_page,  								  const std::string& update_url_base, +								  const std::string& web_profile_url,  								  const std::string& login_id)  {  } | 
