summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rwxr-xr-xdoc/contributions.txt8
-rwxr-xr-xindra/lib/python/indra/base/__init__.py27
-rwxr-xr-xindra/lib/python/indra/base/cllsd_test.py73
-rwxr-xr-xindra/lib/python/indra/base/config.py266
-rwxr-xr-xindra/lib/python/indra/base/llsd.py1052
-rwxr-xr-xindra/lib/python/indra/base/lluuid.py319
-rwxr-xr-xindra/lib/python/indra/base/metrics.py121
-rwxr-xr-xindra/lib/python/indra/ipc/httputil.py30
-rwxr-xr-xindra/lib/python/indra/ipc/llsdhttp.py100
-rwxr-xr-xindra/lib/python/indra/ipc/mysql_pool.py81
-rwxr-xr-xindra/lib/python/indra/ipc/russ.py165
-rwxr-xr-xindra/lib/python/indra/ipc/servicebuilder.py134
-rwxr-xr-xindra/lib/python/indra/ipc/siesta.py468
-rwxr-xr-xindra/lib/python/indra/ipc/siesta_test.py235
-rwxr-xr-xindra/lib/python/indra/ipc/webdav.py597
-rwxr-xr-xindra/lib/python/indra/ipc/xml_rpc.py273
-rwxr-xr-xindra/lib/python/indra/util/fastest_elementtree.py64
-rwxr-xr-xindra/lib/python/indra/util/helpformatter.py52
-rwxr-xr-xindra/lib/python/indra/util/iterators.py63
-rwxr-xr-xindra/lib/python/indra/util/iterators_test.py72
-rwxr-xr-xindra/lib/python/indra/util/llperformance.py182
-rwxr-xr-xindra/lib/python/indra/util/llsubprocess.py117
-rwxr-xr-xindra/lib/python/indra/util/named_query.py592
-rwxr-xr-xindra/lib/python/indra/util/shutil2.py84
-rwxr-xr-xindra/lib/python/indra/util/simperf_host_xml_parser.py338
-rwxr-xr-xindra/lib/python/indra/util/simperf_oprof_interface.py167
-rwxr-xr-xindra/lib/python/indra/util/simperf_proc_interface.py191
-rwxr-xr-xindra/lib/python/indra/util/term.py222
-rwxr-xr-xindra/lib/python/uuid.py508
-rw-r--r--indra/llcommon/llapr.cpp2
-rw-r--r--indra/llcommon/llevents.cpp265
-rw-r--r--indra/llcommon/llevents.h8
-rw-r--r--indra/llcommon/lluriparser.cpp4
-rw-r--r--indra/llcommon/lluriparser.h2
-rw-r--r--indra/llcommon/tests/llleap_test.cpp5
-rw-r--r--indra/llcommon/tests/llsdserialize_test.cpp5
-rwxr-xr-xindra/llcorehttp/tests/test_llcorehttp_peer.py6
-rw-r--r--indra/llimage/llimage.cpp60
-rw-r--r--indra/llimage/llimage.h3
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp80
-rw-r--r--indra/llmath/llvolume.cpp27
-rw-r--r--indra/llmessage/llcorehttputil.cpp2
-rwxr-xr-xindra/llmessage/tests/test_llsdmessage_peer.py6
-rw-r--r--indra/llui/llclipboard.cpp10
-rw-r--r--indra/llui/llfolderview.cpp7
-rw-r--r--indra/llui/llfolderviewitem.cpp23
-rw-r--r--indra/llui/llfolderviewitem.h8
-rw-r--r--indra/llui/llfolderviewmodel.h1
-rw-r--r--indra/llui/lltextvalidate.cpp9
-rw-r--r--indra/llui/lltextvalidate.h1
-rw-r--r--indra/llui/llui.cpp2
-rw-r--r--indra/llui/llurlentry.cpp12
-rw-r--r--indra/llui/llview.cpp22
-rw-r--r--indra/llvfs/lldir.cpp7
-rw-r--r--indra/llwindow/llwindow.h2
-rw-r--r--indra/llwindow/llwindowwin32.cpp65
-rw-r--r--indra/llwindow/llwindowwin32.h2
-rw-r--r--indra/newview/app_settings/settings.xml35
-rw-r--r--indra/newview/llagent.cpp24
-rw-r--r--indra/newview/llagent.h2
-rw-r--r--indra/newview/llagentwearables.cpp68
-rw-r--r--indra/newview/llagentwearables.h2
-rw-r--r--indra/newview/llappearancemgr.cpp8
-rw-r--r--indra/newview/llappearancemgr.h6
-rw-r--r--indra/newview/llappviewer.cpp38
-rw-r--r--indra/newview/llappviewer.h3
-rw-r--r--indra/newview/llchatbar.cpp5
-rw-r--r--indra/newview/llconversationlog.cpp7
-rw-r--r--indra/newview/llfloaterabout.cpp74
-rw-r--r--indra/newview/llfloateravatarpicker.cpp7
-rw-r--r--indra/newview/llfloaterbuycurrency.cpp2
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp48
-rw-r--r--indra/newview/llfloaterpreference.cpp4
-rw-r--r--indra/newview/llfloaterreporter.cpp28
-rw-r--r--indra/newview/llfloaterscriptlimits.cpp10
-rw-r--r--indra/newview/llfloaterscriptlimits.h1
-rw-r--r--indra/newview/llfloatersellland.cpp3
-rw-r--r--indra/newview/llgiveinventory.cpp4
-rw-r--r--indra/newview/llinventorybridge.cpp20
-rw-r--r--indra/newview/llinventorybridge.h1
-rw-r--r--indra/newview/llinventoryfilter.cpp17
-rw-r--r--indra/newview/llinventorymodel.cpp23
-rw-r--r--indra/newview/lllogchat.cpp5
-rw-r--r--indra/newview/llmanip.h4
-rw-r--r--indra/newview/llmaniptranslate.cpp7
-rw-r--r--indra/newview/llmarketplacefunctions.cpp4
-rw-r--r--indra/newview/llmeshrepository.cpp2
-rw-r--r--indra/newview/llpanelgroupgeneral.cpp2
-rw-r--r--indra/newview/llpaneloutfitedit.cpp3
-rw-r--r--indra/newview/llpaneloutfitedit.h1
-rw-r--r--indra/newview/llpanelwearing.cpp251
-rw-r--r--indra/newview/llpanelwearing.h33
-rw-r--r--indra/newview/llpathfindinglinksetlist.cpp7
-rw-r--r--indra/newview/llpresetsmanager.cpp3
-rw-r--r--indra/newview/llpreviewnotecard.cpp19
-rw-r--r--indra/newview/llpreviewnotecard.h1
-rw-r--r--indra/newview/llpreviewscript.cpp18
-rw-r--r--indra/newview/llpreviewscript.h4
-rw-r--r--indra/newview/llsidepanelappearance.cpp2
-rw-r--r--indra/newview/llstartup.cpp6
-rw-r--r--indra/newview/llviewchildren.cpp5
-rw-r--r--indra/newview/llviewercontrol.cpp7
-rw-r--r--indra/newview/llviewerinventory.cpp38
-rw-r--r--indra/newview/llviewermenu.cpp10
-rw-r--r--indra/newview/llviewermenu.h3
-rw-r--r--indra/newview/llviewermessage.cpp6
-rw-r--r--indra/newview/llviewerobject.cpp58
-rw-r--r--indra/newview/llviewerobject.h4
-rw-r--r--indra/newview/llvieweroctree.cpp2
-rw-r--r--indra/newview/llviewertexture.cpp4
-rw-r--r--indra/newview/llviewerwearable.cpp7
-rw-r--r--indra/newview/llviewerwearable.h2
-rw-r--r--indra/newview/llviewerwindow.cpp35
-rw-r--r--indra/newview/llviewerwindow.h8
-rw-r--r--indra/newview/llvovolume.cpp44
-rw-r--r--indra/newview/llvovolume.h3
-rw-r--r--indra/newview/llwlparamset.cpp17
-rw-r--r--indra/newview/llxmlrpclistener.cpp2
-rw-r--r--indra/newview/skins/default/textures/textures.xml3
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_report_abuse.xml10
-rw-r--r--indra/newview/skins/default/xui/en/fonts.xml1
-rw-r--r--indra/newview/skins/default/xui/en/menu_wearing_tab.xml7
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml181
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_wearing.xml41
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_setup.xml12
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml9
129 files changed, 1510 insertions, 7074 deletions
diff --git a/README.md b/README.md
index ad040fb077..6eddb9aa9e 100644
--- a/README.md
+++ b/README.md
@@ -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/doc/contributions.txt b/doc/contributions.txt
index 8ed41ddc34..d968e80250 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -190,9 +190,15 @@ 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
Aralara Rajal
Arare Chantilly
CHUIBUG-191
@@ -790,6 +796,7 @@ Kitty Barnett
MAINT-6152
MAINT-6153
MAINT-6154
+ MAINT-6568
Kolor Fall
Komiko Okamoto
Korvel Noh
@@ -1265,6 +1272,7 @@ Sovereign Engineer
MAINT-6107
STORM-2107
MAINT-6218
+ MAINT-2141
SpacedOut Frye
VWR-34
VWR-45
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('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
-
- 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/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/llevents.cpp b/indra/llcommon/llevents.cpp
index 645c29d770..e38fc5b2a6 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -275,6 +275,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
@@ -313,145 +315,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())
- {
- throw DupListenerName(std::string("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);
- throw Cycle(std::string("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)
+ 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
{
- // Since we've added the new entry with an invalid placement,
- // recognize it and skip it.
- if (dmi->first == name)
+ // 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())
{
- // Remember the iterator belonging to our new node, and which
- // placement value was 'previous' at that point.
- mydmi = dmi;
- myprev = previous;
- continue;
+ throw DupListenerName(std::string("Attempt to register duplicate listener name '") + name +
+ "' on " + typeid(*this).name() + " '" + getName() + "'");
}
- // 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)
+ // 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
{
- // 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)
+ // 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);
+ throw Cycle(std::string("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)
{
- 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;
+ }
}
+ 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.
+ throw OrderChange(out.str());
}
- // NOW remove the offending listener node.
- mDeps.remove(name);
- // Having constructed a description of the order change, inform caller.
- throw 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 ba4fcd766e..694951e699 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -365,6 +365,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
@@ -476,6 +478,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/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/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 91fa8c6ad1..feb97ec2ab 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -942,6 +942,12 @@ void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a)
{
llassert( getComponents() <= 4 );
// This is fairly bogus, but it'll do for now.
+ if (isBufferInvalid())
+ {
+ LL_WARNS() << "Invalid image buffer" << LL_ENDL;
+ return;
+ }
+
U8 *pos = getData();
U32 x, y;
for (x = 0; x < getWidth(); x++)
@@ -1069,6 +1075,11 @@ void LLImageRaw::composite( LLImageRaw* src )
{
LLImageRaw* dst = this; // Just for clarity.
+ if (!validateSrcAndDst("LLImageRaw::composite", src, dst))
+ {
+ return;
+ }
+
llassert(3 == src->getComponents());
llassert(3 == dst->getComponents());
@@ -1136,7 +1147,6 @@ void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src )
llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
-
U8* src_data = src->getData();
U8* dst_data = dst->getData();
S32 pixels = getWidth() * getHeight();
@@ -1171,6 +1181,11 @@ void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill)
{
LLImageRaw* dst = this; // Just for clarity.
+ if (!validateSrcAndDst("LLImageRaw::copyUnscaledAlphaMask", src, dst))
+ {
+ return;
+ }
+
llassert( 1 == src->getComponents() );
llassert( 4 == dst->getComponents() );
llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
@@ -1193,6 +1208,12 @@ void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill)
// Fill the buffer with a constant color
void LLImageRaw::fill( const LLColor4U& color )
{
+ if (isBufferInvalid())
+ {
+ LL_WARNS() << "Invalid image buffer" << LL_ENDL;
+ return;
+ }
+
S32 pixels = getWidth() * getHeight();
if( 4 == getComponents() )
{
@@ -1231,14 +1252,13 @@ LLPointer<LLImageRaw> LLImageRaw::duplicate()
// Src and dst can be any size. Src and dst can each have 3 or 4 components.
void LLImageRaw::copy(LLImageRaw* src)
{
- if (!src)
+ LLImageRaw* dst = this; // Just for clarity.
+
+ if (!validateSrcAndDst("LLImageRaw::copy", src, dst))
{
- LL_WARNS() << "LLImageRaw::copy called with a null src pointer" << LL_ENDL;
return;
}
- LLImageRaw* dst = this; // Just for clarity.
-
if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
{
// No scaling needed
@@ -1365,6 +1385,11 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
{
LLImageRaw* dst = this; // Just for clarity.
+ if (!validateSrcAndDst("LLImageRaw::copyScaled", src, dst))
+ {
+ return;
+ }
+
llassert_always( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) );
llassert_always( src->getComponents() == dst->getComponents() );
@@ -1403,6 +1428,12 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data )
{
llassert((1 == getComponents()) || (3 == getComponents()) || (4 == getComponents()) );
+ if (isBufferInvalid())
+ {
+ LL_WARNS() << "Invalid image buffer" << LL_ENDL;
+ return false;
+ }
+
S32 old_width = getWidth();
S32 old_height = getHeight();
@@ -1692,6 +1723,25 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3
}
}
+bool LLImageRaw::validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst)
+{
+ if (!src || !dst || src->isBufferInvalid() || dst->isBufferInvalid())
+ {
+ LL_WARNS() << func << ": Source: ";
+ if (!src) LL_CONT << "Null pointer";
+ else if (src->isBufferInvalid()) LL_CONT << "Invalid buffer";
+ else LL_CONT << "OK";
+
+ LL_CONT << "; Destination: ";
+ if (!dst) LL_CONT << "Null pointer";
+ else if (dst->isBufferInvalid()) LL_CONT << "Invalid buffer";
+ else LL_CONT << "OK";
+ LL_CONT << "." << LL_ENDL;
+
+ return false;
+ }
+ return true;
+}
//----------------------------------------------------------------------------
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index adc650d360..9cc7431a9c 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -277,6 +277,9 @@ protected:
public:
static S32 sGlobalRawMemory;
static S32 sRawImageCount;
+
+private:
+ bool validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst);
};
// Compressed representation of image.
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 9347e51b85..025c77b85e 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -31,9 +31,31 @@
#include "llpointer.h"
#include "llmath.h"
#include "llkdumem.h"
+#include "stringize.h"
#include "kdu_block_coding.h"
+#include <stdexcept>
+#include <iostream>
+
+namespace {
+// exception used to keep KDU from terminating entire program -- see comments
+// in LLKDUMessageError::flush()
+struct KDUError: public std::runtime_error
+{
+ KDUError(const std::string& msg): std::runtime_error(msg) {}
+};
+} // anonymous namespace
+
+// stream kdu_dims to std::ostream
+// Turns out this must NOT be in the anonymous namespace!
+inline
+std::ostream& operator<<(std::ostream& out, const kdu_dims& dims)
+{
+ return out << "(" << dims.pos.x << "," << dims.pos.y << "),"
+ "[" << dims.size.x << "x" << dims.size.y << "]";
+}
+
class kdc_flow_control {
public:
@@ -165,9 +187,15 @@ struct LLKDUMessageError : public LLKDUMessage
// terminating handler→flush call."
// So throwing an exception here isn't arbitrary: we MUST throw an
// exception if we want to recover from a KDU error.
+ // Because this confused me: the above quote specifically refers to
+ // the kdu_error class, which is constructed internally within KDU at
+ // the point where a fatal error is discovered and reported. It is NOT
+ // talking about the kdu_message subclass passed to
+ // kdu_customize_errors(). Destroying this static object at program
+ // shutdown will NOT engage the behavior described above.
if (end_of_message)
{
- throw "KDU throwing an exception";
+ throw KDUError("LLKDUMessageError::flush()");
}
}
};
@@ -196,6 +224,10 @@ LLImageJ2CKDU::~LLImageJ2CKDU()
// Stuff for new simple decode
void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision);
+// This is called by the real (private) initDecode() (keep_codestream true)
+// and getMetadata() methods (keep_codestream false). As far as nat can tell,
+// mode is always MODE_FAST. It was called by findDiscardLevelsBoundaries()
+// as well, when that still existed, with keep_codestream true and MODE_FAST.
void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECodeStreamMode mode)
{
S32 data_size = base.getDataSize();
@@ -206,6 +238,12 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
//
mCodeStreamp.reset();
+ // It's not clear to nat under what circumstances we would reuse a
+ // pre-existing LLKDUMemSource instance. As of 2016-08-05, it consists of
+ // two U32s and a pointer, so it's not as if it would be a huge overhead
+ // to allocate a new one every time.
+ // Also -- why is base.getData() tested specifically here? If that returns
+ // NULL, shouldn't we bail out of the whole method?
if (!mInputp && base.getData())
{
// The compressed data has been loaded
@@ -262,13 +300,19 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
S32 components = mCodeStreamp->get_num_components();
- if (components >= 3)
- { // Check that components have consistent dimensions (for PPM file)
- kdu_dims dims1; mCodeStreamp->get_dims(1,dims1);
- kdu_dims dims2; mCodeStreamp->get_dims(2,dims2);
- if ((dims1 != dims) || (dims2 != dims))
+ // Check that components have consistent dimensions (for PPM file)
+ for (int idx = 1; idx < components; ++idx)
+ {
+ kdu_dims other_dims;
+ mCodeStreamp->get_dims(idx, other_dims);
+ if (other_dims != dims)
{
- LL_ERRS() << "Components don't have matching dimensions!" << LL_ENDL;
+ // This method is only called from methods that catch KDUError.
+ // We want to fail the image load, not crash the viewer.
+ throw KDUError(STRINGIZE("Component " << idx << " dimensions "
+ << other_dims
+ << " do not match component 0 dimensions "
+ << dims << "!"));
}
}
@@ -295,6 +339,9 @@ void LLImageJ2CKDU::cleanupCodeStream()
mTileIndicesp.reset();
}
+// This is the protected virtual method called by LLImageJ2C::initDecode().
+// However, as far as nat can tell, LLImageJ2C::initDecode() is called only by
+// llimage_libtest.cpp's load_image() function. No detectable production use.
bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
{
return initDecode(base,raw_image,0.0f,MODE_FAST,0,4,discard_level,region);
@@ -327,6 +374,9 @@ bool LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int bloc
return true;
}
+// This is the real (private) initDecode() called both by the protected
+// initDecode() method and by decodeImpl(). As far as nat can tell, only the
+// decodeImpl() usage matters for production.
bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level, int* region)
{
base.resetLastError();
@@ -384,9 +434,9 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
mTPosp->x = 0;
}
}
- catch (const char* msg)
+ catch (const KDUError& msg)
{
- base.setLastError(ll_safe_string(msg));
+ base.setLastError(msg.what());
return false;
}
catch (...)
@@ -480,9 +530,9 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
return false;
}
}
- catch (const char* msg)
+ catch (const KDUError& msg)
{
- base.setLastError(ll_safe_string(msg));
+ base.setLastError(msg.what());
base.decodeFailed();
cleanupCodeStream();
return true; // done
@@ -673,9 +723,9 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
base.updateData(); // set width, height
delete[] output_buffer;
}
- catch(const char* msg)
+ catch(const KDUError& msg)
{
- base.setLastError(ll_safe_string(msg));
+ base.setLastError(msg.what());
return false;
}
catch( ... )
@@ -697,9 +747,9 @@ bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
setupCodeStream(base, false, MODE_FAST);
return true;
}
- catch (const char* msg)
+ catch (const KDUError& msg)
{
- base.setLastError(ll_safe_string(msg));
+ base.setLastError(msg.what());
return false;
}
catch (...)
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/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/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/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..797fae81c4 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -205,9 +205,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 62c3f401bf..e1d9b1a487 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/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 875ffe4cd4..2a39029eee 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -78,6 +78,31 @@ 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 *GetDpiForMonitorType)(
+ _In_ HMONITOR hmonitor,
+ _In_ MONITOR_DPI_TYPE dpiType,
+ _Out_ UINT *dpiX,
+ _Out_ UINT *dpiY);
+
//
// LLWindowWin32
//
@@ -3878,6 +3903,46 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)
return FALSE;
}
+F32 LLWindowWin32::getSystemUISize()
+{
+ float scale_value = 0;
+ HWND hWnd = (HWND)getPlatformWindow();
+ HDC hdc = GetDC(hWnd);
+ HMONITOR hMonitor;
+
+ HMODULE hShcore = LoadLibrary(L"shcore.dll");
+
+ if (hShcore != NULL)
+ {
+ SetProcessDpiAwarenessType pSPDA;
+ pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness");
+ GetDpiForMonitorType pGDFM;
+ pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor");
+ if (pSPDA != NULL && pGDFM != NULL)
+ {
+ pSPDA(PROCESS_PER_MONITOR_DPI_AWARE);
+ POINT pt;
+ UINT dpix = 0, dpiy = 0;
+ HRESULT hr = E_FAIL;
+
+ // Get the DPI for the main monitor, and set the scaling factor
+ pt.x = 1;
+ pt.y = 1;
+ hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
+ hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy);
+ scale_value = dpix / 96.0f;
+ }
+ }
+ 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) / 96.0f;
+ }
+
+ ReleaseDC(hWnd, hdc);
+ return scale_value;
+}
+
//static
std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
{
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 1a775eadaf..1386321912 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -110,6 +110,8 @@ 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();
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 6ccf89eabe..ca81696a50 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4870,7 +4870,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>
@@ -10218,6 +10218,17 @@
<key>Value</key>
<real>1.0</real>
</map>
+ <key>RenderRiggedFactorMultiplier</key>
+ <map>
+ <key>Comment</key>
+ <string>Affects level of detail for worn rigged meshes</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>6.5</real>
+ </map>
<key>RenderWater</key>
<map>
<key>Comment</key>
@@ -12792,6 +12803,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 +13309,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 a1d9786321..4a4361e94b 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -3916,6 +3916,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)
{
@@ -3942,6 +3946,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)
@@ -3962,6 +3968,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 7069da7352..07ae5fba86 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -225,6 +225,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:
@@ -268,6 +272,8 @@ private:
LLTimer mInFlightTimer;
static bool mActive;
+ attachments_changed_signal_t mAttachmentsChangeSignal;
+
std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer;
// Set of temp attachment UUIDs that should be removed
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 6bc1f67e32..64bc7fb2c4 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -587,6 +587,7 @@ static void settings_to_globals()
LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures");
LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
+ LLVOVolume::sRiggedFactorMultiplier = gSavedSettings.getF32("RenderRiggedFactorMultiplier");
LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor");
@@ -696,7 +697,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)
{
@@ -1122,17 +1124,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
@@ -1220,6 +1228,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();
+
return true;
}
@@ -2483,7 +2493,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);
}
@@ -3140,7 +3153,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);
@@ -5799,6 +5813,18 @@ 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"))
+ {
+ 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 b5e674bd7b..d4af2440be 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.
@@ -316,6 +318,7 @@ private:
// llcorehttp library init/shutdown helper
LLAppCoreHttp mAppCoreHttp;
+ bool mIsFirstRun;
//---------------------------------------------
//*NOTE: Mani - legacy updater stuff
// Still useable?
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/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/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 36bdcf4d89..20d8119606 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -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..5d77972180 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);
@@ -452,19 +448,10 @@ void LLFloaterReporter::onClickSend(void *userdata)
}
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 +700,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 +754,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));
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/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp
index a9bf8a9a50..97cc7684e4 100644
--- a/indra/newview/llgiveinventory.cpp
+++ b/indra/newview/llgiveinventory.cpp
@@ -248,7 +248,7 @@ bool LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent,
gInventory.collectDescendentsIf (cat->getUUID(),
cats,
items,
- LLInventoryModel::EXCLUDE_TRASH,
+ LLInventoryModel::INCLUDE_TRASH,
giveable);
S32 count = cats.size();
bool complete = true;
@@ -499,7 +499,7 @@ bool LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent,
gInventory.collectDescendentsIf (cat->getUUID(),
cats,
items,
- LLInventoryModel::EXCLUDE_TRASH,
+ LLInventoryModel::INCLUDE_TRASH,
giveable);
bool give_successful = true;
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 26c9b40fb1..8d130c08e5 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;
}
@@ -1925,13 +1933,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/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/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 54f8fb93d0..9577b3ab50 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4115,7 +4115,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/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/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/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/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 16f40fb747..5e74e9f019 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -207,6 +207,12 @@ static bool handleVolumeLODChanged(const LLSD& newvalue)
return true;
}
+static bool handleRiggedLODChanged(const LLSD& newvalue)
+{
+ LLVOVolume::sRiggedFactorMultiplier = (F32)newvalue.asReal();
+ return true;
+}
+
static bool handleAvatarLODChanged(const LLSD& newvalue)
{
LLVOAvatar::sLODFactor = (F32) newvalue.asReal();
@@ -619,6 +625,7 @@ void settings_setup_listeners()
gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2));
+ gSavedSettings.getControl("RenderRiggedFactorMultiplier")->getSignal()->connect(boost::bind(&handleRiggedLODChanged, _2));
gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2));
gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _2));
gSavedSettings.getControl("RenderTerrainLODFactor")->getSignal()->connect(boost::bind(&handleTerrainLODChanged, _2));
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/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index f5b06fbd19..46f03f9971 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/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 92df3866f7..3925154c0f 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;
}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 5edc3c9745..72a8595845 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -133,6 +133,7 @@ std::map<std::string, U32> LLViewerObject::sObjectDataMap;
// JC 3/18/2003
const F32 PHYSICS_TIMESTEP = 1.f / 45.f;
+const F64 INV_REQUEST_EXPIRE_TIME_SEC = 60.f;
static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object");
@@ -245,7 +246,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mInventory(NULL),
mInventorySerialNum(0),
mRegionp( regionp ),
- mInventoryPending(FALSE),
+ mInvRequestExpireTime(0.f),
mInventoryDirty(FALSE),
mDead(FALSE),
mOrphaned(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,15 @@ void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener)
}
}
+BOOL LLViewerObject::isInventoryPending()
+{
+ if (mInvRequestExpireTime == 0.f || mInvRequestExpireTime < LLFrameTimer::getTotalSeconds())
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
void LLViewerObject::clearInventoryListeners()
{
for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer());
@@ -2870,7 +2888,7 @@ void LLViewerObject::requestInventory()
void LLViewerObject::fetchInventoryFromServer()
{
- if (!mInventoryPending)
+ if (mInvRequestExpireTime == 0.f || mInvRequestExpireTime < LLFrameTimer::getTotalSeconds())
{
delete mInventory;
LLMessageSystem* msg = gMessageSystem;
@@ -2883,7 +2901,7 @@ void LLViewerObject::fetchInventoryFromServer()
msg->sendReliable(mRegionp->getHost());
// this will get reset by dirtyInventory or doInventoryCallback
- mInventoryPending = TRUE;
+ mInvRequestExpireTime = LLFrameTimer::getTotalSeconds() + INV_REQUEST_EXPIRE_TIME_SEC;
}
}
@@ -3099,7 +3117,7 @@ void LLViewerObject::doInventoryCallback()
mInventoryCallbacks.erase(curiter);
}
}
- mInventoryPending = FALSE;
+ mInvRequestExpireTime = 0.f;
}
void LLViewerObject::removeInventory(const LLUUID& item_id)
@@ -4990,8 +5008,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);
}
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index cb8acfdcf8..b95190c554 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -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();
@@ -757,7 +757,7 @@ protected:
S16 mInventorySerialNum;
LLViewerRegion *mRegionp; // Region that this object belongs to.
- BOOL mInventoryPending;
+ F64 mInvRequestExpireTime;
BOOL mInventoryDirty;
BOOL mDead;
BOOL mOrphaned; // This is an orphaned child
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 023f1b92ba..86591ff4df 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -465,7 +465,7 @@ LLViewerOctreeGroup::LLViewerOctreeGroup(OctreeNode* node)
{
LLVector4a tmp;
tmp.splat(0.f);
- mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =
+ mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[1] =
mObjectExtents[0] = mObjectExtents[1] = tmp;
mBounds[0] = node->getCenter();
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 c17c50fd88..f47a37fcda 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1655,7 +1655,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,6 +1744,16 @@ LLViewerWindow::LLViewerWindow(const Params& p)
gSavedSettings.setS32("FullScreenHeight",scr.mY);
}
+
+ F32 system_scale_factor = mWindow->getSystemUISize();
+ if (p.first_run || gSavedSettings.getF32("LastSystemUIScaleFactor") != system_scale_factor)
+ {
+ mSystemUIScaleFactorChanged = true;
+ 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");
@@ -1838,6 +1849,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);
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index ad06f00234..afe80358ca 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -155,7 +155,8 @@ public:
min_width,
min_height;
Optional<bool> fullscreen,
- ignore_pixel_depth;
+ ignore_pixel_depth,
+ first_run;
Params();
};
@@ -418,6 +419,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);
@@ -431,6 +435,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;
@@ -509,6 +514,7 @@ private:
LLPointer<LLViewerObject> mDragHoveredObject;
static LLTrace::SampleStatHandle<> sMouseVelocityStat;
+ bool mSystemUIScaleFactorChanged; // system UI scale factor changed from last run
};
//
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index e69a8d1d1d..4aef6480cb 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -86,6 +86,7 @@ BOOL gAnimateTextures = TRUE;
//extern BOOL gHideSelectedObjects;
F32 LLVOVolume::sLODFactor = 1.f;
+F32 LLVOVolume::sRiggedFactorMultiplier = 6.f;
F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop
F32 LLVOVolume::sDistanceFactor = 1.0f;
S32 LLVOVolume::sNumLODChanges = 0;
@@ -1213,18 +1214,18 @@ void LLVOVolume::sculpt()
}
}
-S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius)
+S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius, F32 lod_factor)
{
S32 cur_detail;
if (LLPipeline::sDynamicLOD)
{
// We've got LOD in the profile, and in the twist. Use radius.
- F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
+ F32 tan_angle = (lod_factor*radius) / distance;
cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f));
}
else
{
- cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
+ cur_detail = llclamp((S32)(sqrtf(radius)*lod_factor*4.f), 0, 3);
}
return cur_detail;
}
@@ -1240,6 +1241,7 @@ BOOL LLVOVolume::calcLOD()
F32 radius;
F32 distance;
+ F32 lod_factor = LLVOVolume::sLODFactor;
if (mDrawable->isState(LLDrawable::RIGGED))
{
@@ -1251,22 +1253,38 @@ BOOL LLVOVolume::calcLOD()
return FALSE;
}
+ // Note: when changing, take note that a lot of rigged meshes have only one LOD.
+ lod_factor *= LLVOVolume::sRiggedFactorMultiplier;
distance = avatar->mDrawable->mDistanceWRTCamera;
- radius = avatar->getBinRadius();
+ F32 avatar_radius = avatar->getBinRadius();
+ F32 object_radius;
+ if (mDrawable.notNull() && !mDrawable->isDead())
+ {
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
+ LLVector4a diff;
+ diff.setSub(ext[1], ext[0]);
+ object_radius = diff.getLength3().getF32();
+ }
+ else
+ {
+ object_radius = getVolume() ? getVolume()->mLODScaleBias.scaledVec(getScale()).length() : getScale().length();
+ }
+ radius = object_radius * LLVOVolume::sRiggedFactorMultiplier;
+ radius = llmin(radius, avatar_radius);
}
else
{
distance = mDrawable->mDistanceWRTCamera;
radius = getVolume() ? getVolume()->mLODScaleBias.scaledVec(getScale()).length() : getScale().length();
}
-
+
//hold onto unmodified distance for debugging
//F32 debug_distance = distance;
-
+
distance *= sDistanceFactor;
- F32 rampDist = LLVOVolume::sLODFactor * 2;
-
+ F32 rampDist = lod_factor * 2;
+
if (distance < rampDist)
{
// Boost LOD when you're REALLY close
@@ -1279,7 +1297,8 @@ BOOL LLVOVolume::calcLOD()
distance *= F_PI/3.f;
cur_detail = computeLODDetail(ll_round(distance, 0.01f),
- ll_round(radius, 0.01f));
+ ll_round(radius, 0.01f),
+ lod_factor);
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) &&
@@ -1753,7 +1772,10 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
compiled = TRUE;
lodOrSculptChanged(drawable, compiled);
- genBBoxes(FALSE);
+ if (!mLODChanged)
+ {
+ genBBoxes(FALSE);
+ }
}
// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
else
@@ -4429,7 +4451,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/llvovolume.h b/indra/newview/llvovolume.h
index a331908320..ca9917069b 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -327,7 +327,7 @@ public:
void clearRiggedVolume();
protected:
- S32 computeLODDetail(F32 distance, F32 radius);
+ S32 computeLODDetail(F32 distance, F32 radius, F32 lod_factor);
BOOL calcLOD();
LLFace* addFace(S32 face_index);
void updateTEData();
@@ -379,6 +379,7 @@ private:
public:
static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop
static F32 sLODFactor; // LOD scale factor
+ static F32 sRiggedFactorMultiplier; // Worn rigged LOD scale factor multiplier
static F32 sDistanceFactor; // LOD distance factor
static LLPointer<LLObjectMediaDataClient> sObjectMediaClient;
diff --git a/indra/newview/llwlparamset.cpp b/indra/newview/llwlparamset.cpp
index 066cb9a0ac..482a2a61e2 100644
--- a/indra/newview/llwlparamset.cpp
+++ b/indra/newview/llwlparamset.cpp
@@ -288,14 +288,6 @@ void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight)
{
// set up the iterators
- // keep cloud positions and coverage the same
- /// TODO masking will do this later
- F32 cloudPos1X = (F32) mParamValues["cloud_pos_density1"][0].asReal();
- F32 cloudPos1Y = (F32) mParamValues["cloud_pos_density1"][1].asReal();
- F32 cloudPos2X = (F32) mParamValues["cloud_pos_density2"][0].asReal();
- F32 cloudPos2Y = (F32) mParamValues["cloud_pos_density2"][1].asReal();
- F32 cloudCover = (F32) mParamValues["cloud_shadow"][0].asReal();
-
LLSD srcVal;
LLSD destVal;
@@ -379,15 +371,6 @@ void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight)
setSunAngle((1 - weight) * srcSunAngle + weight * destSunAngle);
setEastAngle((1 - weight) * srcEastAngle + weight * destEastAngle);
-
- // now setup the sun properly
-
- // reset those cloud positions
- mParamValues["cloud_pos_density1"][0] = cloudPos1X;
- mParamValues["cloud_pos_density1"][1] = cloudPos1Y;
- mParamValues["cloud_pos_density2"][0] = cloudPos2X;
- mParamValues["cloud_pos_density2"][1] = cloudPos2Y;
- mParamValues["cloud_shadow"][0] = cloudCover;
}
void LLWLParamSet::updateCloudScrolling(void)
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 72037a84b3..85f4ae587a 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -774,6 +774,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/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/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/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index dfde38bc5f..6fdeedc8ae 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">
@@ -1631,14 +1638,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 +1657,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.
@@ -3665,6 +3633,13 @@ Can&apos;t add estate owner to estate &apos;Banned Resident&apos; 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&apos;t change appearance until clothing and shape are loaded.
@@ -4059,6 +4034,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 +4165,14 @@ Leave Group?
</notification>
<notification
+ icon="notify.tga"
+ name="GroupDepart"
+ type="notify">
+You have left the group &apos;[group_name]&apos;.
+ <tag>group</tag>
+ </notification>
+
+ <notification
icon="alertmodal.tga"
name="OwnerCannotLeaveGroup"
type="alertmodal">
@@ -4189,6 +4184,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 +5316,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 +5745,17 @@ Warning: The &apos;Pay object&apos; 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.
@@ -6901,6 +6929,15 @@ This area has building disabled. You can&apos;t build or rez objects here.
</notification>
<notification
+ icon="notify.tga"
+ name="AutopilotCanceled"
+ persist="true"
+ type="notify">
+ <unique/>
+Autopilot canceled
+ </notification>
+
+ <notification
icon="notify.tga"
name="PathfindingDirty"
persist="true"
@@ -8804,23 +8841,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 +9822,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 +9865,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 +9973,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>
@@ -10972,6 +11027,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_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 b19c6756bc..27c08f560f 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -2566,7 +2566,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>
@@ -2834,6 +2835,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.