From 23811df3cf466928a19e93e2587038159ec03fdf Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Sun, 19 Feb 2012 06:43:04 -0500 Subject: [PATCH 1/9] Adding to Ignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bfe820c87..c56bf2a54 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ *.rej *.bak *~ +*.DS_Store /LICENSES/ /edited-files.txt qtcreator-build/ From 925c42294f451b1118f6d8e5183364329d360ce3 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Sun, 19 Feb 2012 11:30:27 -0500 Subject: [PATCH 2/9] OS X Builds now. Fixed building on OS X. Fixed line endings. Need to find better way to do fmodwrapper thing. --- indra/newview/fmodwrapper.cpp | 22 +- indra/newview/llstartup.cpp | 2 +- indra/newview/sgversion.cpp | 3 + indra/newview/sgversion.h | 3 + indra/newview/viewer_manifest.py | 1758 +++++++++++++++--------------- 5 files changed, 899 insertions(+), 889 deletions(-) diff --git a/indra/newview/fmodwrapper.cpp b/indra/newview/fmodwrapper.cpp index d14c9134f..b544785b7 100644 --- a/indra/newview/fmodwrapper.cpp +++ b/indra/newview/fmodwrapper.cpp @@ -30,26 +30,30 @@ * $/LicenseInfo$ */ +//Hack to build Darwin. +//Need to find a better way to do this later. +#define LL_FMOD + extern "C" { -#if LL_FMODEX +#ifdef LL_FMODEX void FSOUND_Sound_Init(void); #endif -#if LL_FMOD + +#ifdef LL_FMOD void FSOUND_Init(void); #endif } void* fmodwrapper(void) -{ +{ // When building the fmodwrapper library, the linker doesn't seem to want to bring in libfmod.a unless I explicitly // reference at least one symbol in the library. This seemed like the simplest way. - void *ret = NULL; -#if LL_FMODEX - ret = (void*)&FSOUND_Sound_Init; +#ifdef LL_FMODEX + return (void*)&FSOUND_Sound_Init; #endif -#if LL_FMOD - ret = (void*)&FSOUND_Init; + +#ifdef LL_FMOD + return (void*)&FSOUND_Init; #endif - return ret; } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 4feeee42f..011c10cac 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3492,7 +3492,7 @@ bool update_dialog_callback(const LLSD& notification, const LLSD& response) LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \""; LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle(); LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -bundleid \""; - LLAppViewer::sUpdaterInfo->mUpdateExePath += LL_VERSION_BUNDLE_ID; + LLAppViewer::sUpdaterInfo->mUpdateExePath += gVersionBundleID; LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &"; LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL; diff --git a/indra/newview/sgversion.cpp b/indra/newview/sgversion.cpp index 07f4c251d..615064f27 100644 --- a/indra/newview/sgversion.cpp +++ b/indra/newview/sgversion.cpp @@ -28,3 +28,6 @@ const S32 gVersionBuild = LL_VERSION_BUILD; const char* gVersionChannel = LL_CHANNEL; +#if LL_DARWIN +const char* gVersionBundleID = LL_VERSION_BUNDLE_ID; +#endif \ No newline at end of file diff --git a/indra/newview/sgversion.h b/indra/newview/sgversion.h index 42231fc07..afdc8b51a 100644 --- a/indra/newview/sgversion.h +++ b/indra/newview/sgversion.h @@ -25,5 +25,8 @@ extern const S32 gVersionBuild; extern const char* gVersionChannel; +#if LL_DARWIN +extern const char* gVersionBundleID; +#endif #endif diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 2b11cd32b..b492ddaef 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1,879 +1,879 @@ -#!/usr/bin/python -# @file viewer_manifest.py -# @author Ryan Williams -# @brief Description of all installer viewer files, and methods for packaging -# them into installers for all supported platforms. -# -# $LicenseInfo:firstyear=2006&license=viewergpl$ -# -# Copyright (c) 2006-2009, Linden Research, Inc. -# -# Second Life Viewer Source Code -# The source code in this file ("Source Code") is provided by Linden Lab -# to you under the terms of the GNU General Public License, version 2.0 -# ("GPL"), unless you have obtained a separate licensing agreement -# ("Other License"), formally executed by you and Linden Lab. Terms of -# the GPL can be found in doc/GPL-license.txt in this distribution, or -# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 -# -# There are special exceptions to the terms and conditions of the GPL as -# it is applied to this Source Code. View the full text of the exception -# in the file doc/FLOSS-exception.txt in this software distribution, or -# online at -# http://secondlifegrid.net/programs/open_source/licensing/flossexception -# -# By copying, modifying or distributing this software, you acknowledge -# that you have read and understood your obligations described above, -# and agree to abide by those obligations. -# -# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -# COMPLETENESS OR PERFORMANCE. -# $/LicenseInfo$ -import sys -import os.path -import re -import tarfile -viewer_dir = os.path.dirname(__file__) -# add llmanifest library to our path so we don't have to muck with PYTHONPATH -sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util')) -from llmanifest import LLManifest, main, proper_windows_path, path_ancestors - -class ViewerManifest(LLManifest): - def construct(self): - super(ViewerManifest, self).construct() - self.exclude("*.svn*") - self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") - self.path(src="../../etc/message.xml", dst="app_settings/message.xml") - - if self.prefix(src="app_settings"): - self.exclude("logcontrol.xml") - self.exclude("logcontrol-dev.xml") - self.path("*.pem") - self.path("*.ini") - self.path("*.xml") - self.path("*.db2") - - # include the entire shaders directory recursively - self.path("shaders") - # ... and the entire windlight directory - self.path("windlight") - # ... and the hunspell dictionaries - self.path("dictionaries") - self.end_prefix("app_settings") - - if self.prefix(src="character"): - self.path("*.llm") - self.path("*.xml") - self.path("*.tga") - self.end_prefix("character") - - # Include our fonts - if self.prefix(src="fonts"): - self.path("*.ttf") - self.path("*.txt") - self.end_prefix("fonts") - - # skins - if self.prefix(src="skins"): - self.path("paths.xml") - # include the entire textures directory recursively - if self.prefix(src="default/textures"): - self.path("*.tga") - self.path("*.j2c") - self.path("*.jpg") - self.path("*.png") - self.path("textures.xml") - self.end_prefix("default/textures") - self.path("default/xui/*/*.xml") - self.path("Default.xml") - self.path("default/*.xml") - if self.prefix(src="dark/textures"): - self.path("*.tga") - self.path("*.j2c") - self.path("*.jpg") - self.path("*.png") - self.path("textures.xml") - self.end_prefix("dark/textures") - self.path("dark.xml") - self.path("dark/*.xml") - - # Local HTML files (e.g. loading screen) - if self.prefix(src="*/html"): - self.path("*.png") - self.path("*/*/*.html") - self.path("*/*/*.gif") - self.end_prefix("*/html") - self.end_prefix("skins") - - # Files in the newview/ directory - self.path("gpu_table.txt") - - def login_channel(self): - """Channel reported for login and upgrade purposes ONLY; - used for A/B testing""" - # NOTE: Do not return the normal channel if login_channel - # is not specified, as some code may branch depending on - # whether or not this is present - return self.args.get('login_channel') - - def buildtype(self): - return self.args['buildtype'] - def standalone(self): - return self.args['standalone'] == "ON" - def grid(self): - return self.args['grid'] - def channel(self): - return self.args['channel'] - def channel_unique(self): - return self.channel().replace("Second Life", "").strip() - def channel_oneword(self): - return "".join(self.channel_unique().split()) - def channel_lowerword(self): - return self.channel_oneword().lower() - def viewer_branding_id(self): - return self.args['branding_id'] - def installer_prefix(self): - mapping={"secondlife":'SecondLife_', - "snowglobe":'Snowglobe_', - "singularity":'Singularity_'} - return mapping[self.viewer_branding_id()] - - def flags_list(self): - """ Convenience function that returns the command-line flags - for the grid""" - - # Set command line flags relating to the target grid - grid_flags = '' - if not self.default_grid(): - grid_flags = "--grid %(grid)s "\ - "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\ - {'grid':self.grid()} - - # set command line flags for channel - channel_flags = '' - if self.login_channel() and self.login_channel() != self.channel(): - # Report a special channel during login, but use default - channel_flags = '--channel "%s"' % (self.login_channel()) - else: - channel_flags = '--channel "%s"' % self.channel() - - # Deal with settings - if self.default_channel() and self.default_grid(): - setting_flags = '' - elif self.default_grid(): - setting_flags = '--settings settings_%s.xml'\ - % self.channel_lowerword() - else: - setting_flags = '--settings settings_%s_%s.xml'\ - % (self.grid(), self.channel_lowerword()) - - return " ".join((channel_flags, grid_flags, setting_flags)).strip() - -class WindowsManifest(ViewerManifest): - def final_exe(self): - return self.channel_oneword() + 'Viewer.exe' - - - def construct(self): - super(WindowsManifest, self).construct() - # the final exe is complicated because we're not sure where it's coming from, - # nor do we have a fixed name for the executable - self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) - - # Plugin host application - self.path(os.path.join(os.pardir, - 'llplugin', 'slplugin', self.args['configuration'], "SLPlugin.exe"), - "SLPlugin.exe") - - # need to get the kdu dll from any of the build directories as well - #~ try: - #~ self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'], - #~ '../../libraries/i686-win32/lib/release/llkdu.dll'), - #~ dst='llkdu.dll') - #~ pass - #~ except: - #~ print "Skipping llkdu.dll" - #~ pass - self.path(src="licenses-win32.txt", dst="licenses.txt") - - self.path("featuretable.txt") - - # For spellchecking - if self.prefix(src=self.args['configuration'], dst=""): - self.path("libhunspell.dll") - self.end_prefix() - - # For use in crash reporting (generates minidumps) - self.path("dbghelp.dll") - - # For using FMOD for sound... DJS - #~if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - #~try: - #~self.path("fmod.dll") - #~pass - #~except: - #~print "Skipping fmod.dll - not found" - #~ pass - #~self.end_prefix() - - # For textures - #if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - # self.path("openjpeg.dll") - # self.end_prefix() - - # Plugins - FilePicker - if self.prefix(src='../plugins/filepicker/%s' % self.args['configuration'], dst="llplugin"): - self.path("basic_plugin_filepicker.dll") - self.end_prefix() - - # Media plugins - QuickTime - if self.prefix(src='../plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): - self.path("media_plugin_quicktime.dll") - self.end_prefix() - - # Media plugins - WebKit/Qt - if self.prefix(src='../plugins/webkit/%s' % self.args['configuration'], dst="llplugin"): - self.path("media_plugin_webkit.dll") - self.end_prefix() - - # For WebKit/Qt plugin runtimes - if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"): - self.path("libeay32.dll") - self.path("qtcore4.dll") - self.path("qtgui4.dll") - self.path("qtnetwork4.dll") - self.path("qtopengl4.dll") - self.path("qtwebkit4.dll") - self.path("qtxmlpatterns4.dll") - self.path("ssleay32.dll") - self.end_prefix() - - # For WebKit/Qt plugin runtimes (image format plugins) - if self.prefix(src="../../libraries/i686-win32/lib/release/imageformats", dst="llplugin/imageformats"): - self.path("qgif4.dll") - self.path("qico4.dll") - self.path("qjpeg4.dll") - self.path("qmng4.dll") - self.path("qsvg4.dll") - self.path("qtiff4.dll") - self.end_prefix() - - if self.prefix(src="../../libraries/i686-win32/lib/release/codecs", dst="llplugin/codecs"): - self.path("qcncodecs4.dll") - self.path("qjpcodecs4.dll") - self.path("qkrcodecs4.dll") - self.path("qtwcodecs4.dll") - self.end_prefix() - - # Get llcommon and deps. If missing assume static linkage and continue. - if self.prefix(src=self.args['configuration'], dst=""): - try: - self.path('llcommon.dll') - except RuntimeError, err: - print err.message - print "Skipping llcommon.dll (assuming llcommon was linked statically)" - self.end_prefix() - if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - try: - self.path('libapr-1.dll') - self.path('libaprutil-1.dll') - self.path('libapriconv-1.dll') - except RuntimeError, err: - pass - self.end_prefix() - - # For google-perftools tcmalloc allocator. - self.path("../../libraries/i686-win32/lib/release/libtcmalloc_minimal.dll", dst="libtcmalloc_minimal.dll") - - try: - if self.prefix("../../libraries/i686-win32/lib/release/msvcrt", dst=""): - self.path("*.dll") - self.path("*.manifest") - self.end_prefix() - except: - pass - - - # These need to be installed as a SxS assembly, currently a 'private' assembly. - # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx - #~ if self.prefix(src=self.args['configuration'], dst=""): - #~ if self.args['configuration'] == 'Debug': - #~ self.path("msvcr80d.dll") - #~ self.path("msvcp80d.dll") - #~ self.path("Microsoft.VC80.DebugCRT.manifest") - #~ else: - #~ self.path("msvcr80.dll") - #~ self.path("msvcp80.dll") - #~ self.path("Microsoft.VC80.CRT.manifest") - #~ self.end_prefix() - - # The config file name needs to match the exe's name. - #~ self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config") - - # Vivox runtimes - if self.prefix(src="vivox-runtime/i686-win32", dst=""): - self.path("SLVoice.exe") - self.path("alut.dll") - self.path("vivoxsdk.dll") - self.path("ortp.dll") - self.path("wrap_oal.dll") - self.end_prefix() - - if self.args['extra_libraries'] != None: - print self.args['extra_libraries'] - path_list = self.args['extra_libraries'].split('|') - for path in path_list: - path_pair = path.rsplit('/', 1) - if self.prefix(src=path_pair[0], dst=""): - self.path(path_pair[1]) - self.end_prefix() - - # pull in the crash logger and updater from other projects - self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], dst="win_crash_logger.exe") - self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], dst="updater.exe") - - - def nsi_file_commands(self, install=True): - def wpath(path): - if path.endswith('/') or path.endswith(os.path.sep): - path = path[:-1] - path = path.replace('/', '\\') - return path - - result = "" - dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])] - # sort deepest hierarchy first - dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b)) - dest_files.reverse() - out_path = None - for pkg_file in dest_files: - rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,'')) - installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file))) - pkg_file = wpath(os.path.normpath(pkg_file)) - if installed_dir != out_path: - if install: - out_path = installed_dir - result += 'SetOutPath ' + out_path + '\n' - if install: - result += 'File ' + pkg_file + '\n' - else: - result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n' - # at the end of a delete, just rmdir all the directories - if not install: - deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list] - # find all ancestors so that we don't skip any dirs that happened to have no non-dir children - deleted_dirs = [] - for d in deleted_file_dirs: - deleted_dirs.extend(path_ancestors(d)) - # sort deepest hierarchy first - deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b)) - deleted_dirs.reverse() - prev = None - for d in deleted_dirs: - if d != prev: # skip duplicates - result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n' - prev = d - - return result - - def package_finish(self): - # a standard map of strings for replacing in the templates - substitution_strings = { - 'version' : '.'.join(self.args['version']), - 'version_short' : '.'.join(self.args['version'][:-1]), - 'version_dashes' : '-'.join(self.args['version']), - 'final_exe' : self.final_exe(), - 'grid':self.args['grid'], - 'grid_caps':self.args['grid'].upper(), - # escape quotes becase NSIS doesn't handle them well - 'flags':self.flags_list().replace('"', '$\\"'), - 'channel':self.channel(), - 'channel_oneword':self.channel_oneword(), - 'channel_unique':self.channel_unique(), - } - - version_vars = """ - !define INSTEXE "%(final_exe)s" - !define VERSION "%(version_short)s" - !define VERSION_LONG "%(version)s" - !define VERSION_DASHES "%(version_dashes)s" - """ % substitution_strings - installer_file = "%(channel_oneword)s_%(version_dashes)s_Setup.exe" - grid_vars_template = """ - OutFile "%(installer_file)s" - !define VIEWERNAME "%(channel)s" - !define INSTFLAGS "%(flags)s" - !define INSTNAME "%(channel_oneword)s" - !define SHORTCUT "%(channel)s Viewer" - !define URLNAME "secondlife" - !define INSTALL_ICON "install_icon_singularity.ico" - !define UNINSTALL_ICON "install_icon_singularity.ico" - Caption "${VIEWERNAME} ${VERSION_LONG}" - """ - if 'installer_name' in self.args: - installer_file = self.args['installer_name'] - else: - installer_file = installer_file % substitution_strings - substitution_strings['installer_file'] = installer_file - - tempfile = "secondlife_setup_tmp.nsi" - # the following replaces strings in the nsi template - # it also does python-style % substitution - self.replace_in("installers/windows/installer_template.nsi", tempfile, { - "%%VERSION%%":version_vars, - "%%SOURCE%%":self.get_src_prefix(), - "%%GRID_VARS%%":grid_vars_template % substitution_strings, - "%%INSTALL_FILES%%":self.nsi_file_commands(True), - "%%DELETE_FILES%%":self.nsi_file_commands(False)}) - - # We use the Unicode version of NSIS, available from - # http://www.scratchpaper.com/ - try: - import _winreg as reg - NSIS_path = reg.QueryValue(reg.HKEY_LOCAL_MACHINE, r"SOFTWARE\NSIS\Unicode") + '\\makensis.exe' - self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) - except: - try: - NSIS_path = os.environ['ProgramFiles'] + '\\NSIS\\Unicode\\makensis.exe' - self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) - except: - NSIS_path = os.environ['ProgramFiles(X86)'] + '\\NSIS\\Unicode\\makensis.exe' - self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) - # self.remove(self.dst_path_of(tempfile)) - # If we're on a build machine, sign the code using our Authenticode certificate. JC - sign_py = os.path.expandvars("{SIGN_PY}") - if sign_py == "" or sign_py == "{SIGN_PY}": - sign_py = 'C:\\buildscripts\\code-signing\\sign.py' - if os.path.exists(sign_py): - self.run_command('python ' + sign_py + ' ' + self.dst_path_of(installer_file)) - else: - print "Skipping code signing,", sign_py, "does not exist" - self.created_path(self.dst_path_of(installer_file)) - self.package_file = installer_file - - -class DarwinManifest(ViewerManifest): - def construct(self): - # copy over the build result (this is a no-op if run within the xcode script) - self.path(self.args['configuration'] + "/" + self.app_name() + ".app", dst="") - - if self.prefix(src="", dst="Contents"): # everything goes in Contents - self.path(self.info_plist_name(), dst="Info.plist") - - # copy additional libs in /Contents/MacOS/ - self.path("../../libraries/universal-darwin/lib_release/libhunspell-1.2.dylib", dst="MacOS/libhunspell-1.2.dylib") - self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") - #self.path("../../libraries/universal-darwin/lib_release/libvorbisenc.2.dylib", dst="MacOS/libvorbisenc.2.dylib") - #self.path("../../libraries/universal-darwin/lib_release/libvorbisfile.3.dylib", dst="MacOS/libvorbisfile.3.dylib") - #self.path("../../libraries/universal-darwin/lib_release/libvorbis.0.dylib", dst="MacOS/libvorbis.0.dylib") - #self.path("../../libraries/universal-darwin/lib_release/libogg.0.dylib", dst="MacOS/libogg.0.dylib") - - # most everything goes in the Resources directory - if self.prefix(src="", dst="Resources"): - super(DarwinManifest, self).construct() - - if self.prefix("cursors_mac"): - self.path("*.tif") - self.end_prefix("cursors_mac") - - self.path("licenses-mac.txt", dst="licenses.txt") - self.path("featuretable_mac.txt") - self.path("SecondLife.nib") - - # SG:TODO - self.path("../newview/res/singularity.icns", dst="singularity.icns") - - # Translations - self.path("English.lproj") - self.path("German.lproj") - self.path("Japanese.lproj") - self.path("Korean.lproj") - self.path("da.lproj") - self.path("es.lproj") - self.path("fr.lproj") - self.path("hu.lproj") - self.path("it.lproj") - self.path("nl.lproj") - self.path("pl.lproj") - self.path("pt.lproj") - self.path("ru.lproj") - self.path("tr.lproj") - self.path("uk.lproj") - self.path("zh-Hans.lproj") - - # SLVoice and vivox lols - self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib") - self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib") - self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib") - self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") - self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") - - self.path("../llcommon/" + self.args['configuration'] + "/libllcommon.dylib", "libllcommon.dylib") - - libfile = "lib%s.dylib" - libdir = "../../libraries/universal-darwin/lib_release" - - for libfile in ("libapr-1.0.3.7.dylib", - "libaprutil-1.0.3.8.dylib", - "libexpat.0.5.0.dylib"): - self.path(os.path.join(libdir, libfile), libfile) - - # For using FMOD for sound...but, fmod is proprietary so some might not use it... - try: - self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") - pass - except: - print "Skipping libfmodwrapper.dylib - not found" - pass - - # our apps - try: - self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") - self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") - except: - pass - - # plugin launcher - self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app") - - # dependencies on shared libs - mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources") - slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources") - for libfile in ("libllcommon.dylib", - "libapr-1.0.3.7.dylib", - "libaprutil-1.0.3.8.dylib", - "libexpat.0.5.0.dylib"): - target_lib = os.path.join('../../..', libfile) - self.run_command("ln -sf %(target)r %(link)r" % - {'target': target_lib, - 'link' : os.path.join(slplugin_res_path, libfile)} - ) - #self.run_command("ln -sf %(target)r %(link)r" % - # {'target': target_lib, - # 'link' : os.path.join(mac_crash_logger_res_path, libfile)} - # ) - - # plugins - if self.prefix(src="", dst="llplugin"): - self.path("../plugins/filepicker/" + self.args['configuration'] + "/basic_plugin_filepicker.dylib", "basic_plugin_filepicker.dylib") - self.path("../plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") - self.path("../plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") - self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") - - self.end_prefix("llplugin") - - # command line arguments for connecting to the proper grid - self.put_in_file(self.flags_list(), 'arguments.txt') - - self.end_prefix("Resources") - - self.end_prefix("Contents") - - # NOTE: the -S argument to strip causes it to keep enough info for - # annotated backtraces (i.e. function names in the crash log). 'strip' with no - # arguments yields a slightly smaller binary but makes crash logs mostly useless. - # This may be desirable for the final release. Or not. - if self.buildtype().lower()=='release': - if ("package" in self.args['actions'] or - "unpacked" in self.args['actions']): - self.run_command('strip -S "%(viewer_binary)s"' % - { 'viewer_binary' : self.dst_path_of('Contents/MacOS/'+self.app_name())}) - - def app_name(self): - return "Singularity" - - def info_plist_name(self): - return "Info-Singularity.plist" - - def package_finish(self): - channel_standin = self.app_name() - if not self.default_channel_for_brand(): - channel_standin = self.channel() - - imagename=self.installer_prefix() + '_'.join(self.args['version']) - - # See Ambroff's Hack comment further down if you want to create new bundles and dmg - volname=self.app_name() + " Installer" # DO NOT CHANGE without checking Ambroff's Hack comment further down - - if self.default_channel_for_brand(): - if not self.default_grid(): - # beta case - imagename = imagename + '_' + self.args['grid'].upper() - else: - # first look, etc - imagename = imagename + '_' + self.channel_oneword().upper() - - sparsename = imagename + ".sparseimage" - finalname = imagename + ".dmg" - # make sure we don't have stale files laying about - self.remove(sparsename, finalname) - - self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % { - 'sparse':sparsename, - 'vol':volname}) - - # mount the image and get the name of the mount point and device node - hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"') - devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip() - volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip() - - # Copy everything in to the mounted .dmg - - if self.default_channel_for_brand() and not self.default_grid(): - app_name = self.app_name() + " " + self.args['grid'] - else: - app_name = channel_standin.strip() - - # Hack: - # Because there is no easy way to coerce the Finder into positioning - # the app bundle in the same place with different app names, we are - # adding multiple .DS_Store files to svn. There is one for release, - # one for release candidate and one for first look. Any other channels - # will use the release .DS_Store, and will look broken. - # - Ambroff 2008-08-20 - # Added a .DS_Store for snowglobe - Merov 2009-06-17 - - # We have a single branded installer for all snowglobe channels so snowglobe logic is a bit different - if (self.app_name()=="Snowglobe"): - dmg_template = os.path.join ('installers', 'darwin', 'snowglobe-dmg') - else: - dmg_template = os.path.join( - 'installers', - 'darwin', - '%s-dmg' % "".join(self.channel_unique().split()).lower()) - - if not os.path.exists (self.src_path_of(dmg_template)): - dmg_template = os.path.join ('installers', 'darwin', 'release-dmg') - - for s,d in {self.get_dst_prefix():app_name + ".app", - os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns", - os.path.join(dmg_template, "background.jpg"): "background.jpg", - os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items(): - print "Copying to dmg", s, d - self.copy_action(self.src_path_of(s), os.path.join(volpath, d)) - - # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) - self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"') - self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"') - self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"') - - # Create the alias file (which is a resource file) from the .r - self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"') - - # Set the alias file's alias and custom icon bits - self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"') - - # Set the disk image root's custom icon bit - self.run_command('SetFile -a C "' + volpath + '"') - - # Unmount the image - self.run_command('hdiutil detach -force "' + devfile + '"') - - print "Converting temp disk image to final disk image" - self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname}) - # get rid of the temp file - self.package_file = finalname - self.remove(sparsename) - -class LinuxManifest(ViewerManifest): - def construct(self): - super(LinuxManifest, self).construct() - self.path("licenses-linux.txt","licenses.txt") - - self.path("res/"+self.icon_name(),self.icon_name()) - if self.prefix("linux_tools", dst=""): - self.path("client-readme.txt","README-linux.txt") - self.path("client-readme-voice.txt","README-linux-voice.txt") - self.path("client-readme-joystick.txt","README-linux-joystick.txt") - self.path("wrapper.sh",self.wrapper_name()) - self.path("handle_secondlifeprotocol.sh") - self.path("register_secondlifeprotocol.sh") - self.end_prefix("linux_tools") - - # Create an appropriate gridargs.dat for this package, denoting required grid. - self.put_in_file(self.flags_list(), 'gridargs.dat') - - if self.buildtype().lower()=='release': - self.path("secondlife-stripped","bin/"+self.binary_name()) - self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin") - else: - self.path("secondlife-bin","bin/"+self.binary_name()) - self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") - - self.path("linux_tools/launch_url.sh","launch_url.sh") - self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") - if self.prefix("res-sdl"): - self.path("*") - # recurse - self.end_prefix("res-sdl") - - # plugins - if self.prefix(src="", dst="bin/llplugin"): - self.path("../plugins/filepicker/libbasic_plugin_filepicker.so", "libbasic_plugin_filepicker.so") - self.path("../plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") - self.path("../plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so") - self.end_prefix("bin/llplugin") - - self.path("featuretable_linux.txt") - - def wrapper_name(self): - return 'singularity' - - def binary_name(self): - return 'singularity-do-not-run-directly' - - def icon_name(self): - return "singularity_icon.png" - - def package_finish(self): - if 'installer_name' in self.args: - installer_name = self.args['installer_name'] - else: - installer_name_components = [self.installer_prefix(), self.args.get('arch')] - installer_name_components.extend(self.args['version']) - installer_name = "_".join(installer_name_components) - if self.default_channel(): - if not self.default_grid(): - installer_name += '_' + self.args['grid'].upper() - else: - installer_name += '_' + self.channel_oneword().upper() - - if self.args['buildtype'].lower() in ['release', 'releasesse2']: - print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build" - # makes some small assumptions about our packaged dir structure - self.run_command("find %(d)r/bin %(d)r/lib* -type f | xargs --no-run-if-empty strip --strip-unneeded" % {'d': self.get_dst_prefix()} ) - self.run_command("find %(d)r/bin %(d)r/lib* -type f -not -name \\*.so | xargs --no-run-if-empty strip -s" % {'d': self.get_dst_prefix()} ) - - # Fix access permissions - self.run_command(""" - find '%(dst)s' -type d -print0 | xargs -0 --no-run-if-empty chmod 755; - find '%(dst)s' -type f -perm 0700 -print0 | xargs -0 --no-run-if-empty chmod 0755; - find '%(dst)s' -type f -perm 0500 -print0 | xargs -0 --no-run-if-empty chmod 0555; - find '%(dst)s' -type f -perm 0600 -print0 | xargs -0 --no-run-if-empty chmod 0644; - find '%(dst)s' -type f -perm 0400 -print0 | xargs -0 --no-run-if-empty chmod 0444; - true""" % {'dst':self.get_dst_prefix() }) - self.package_file = installer_name + '.tar.bz2' - - # temporarily move directory tree so that it has the right - # name in the tarfile - self.run_command("mv '%(dst)s' '%(inst)s'" % { - 'dst': self.get_dst_prefix(), - 'inst': self.build_path_of(installer_name)}) - try: - # --numeric-owner hides the username of the builder for - # security etc. - # I'm leaving this disabled for speed - #self.run_command("tar -C '%(dir)s' --numeric-owner -cjf " - # "'%(inst_path)s.tar.bz2' %(inst_name)s" % { - # 'dir': self.get_build_prefix(), - # 'inst_name': installer_name, - # 'inst_path':self.build_path_of(installer_name)}) - print '' - finally: - self.run_command("mv '%(inst)s' '%(dst)s'" % { - 'dst': self.get_dst_prefix(), - 'inst': self.build_path_of(installer_name)}) - - -class Linux_i686Manifest(LinuxManifest): - def construct(self): - super(Linux_i686Manifest, self).construct() - - self.path("../llcommon/libllcommon.so", "lib/libllcommon.so") - - if (not self.standalone()) and self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): - - try: - self.path("libkdu_v42R.so", "libkdu.so") - pass - except: - print "Skipping libkdu_v42R.so - not found" - pass - - try: - self.path("libfmod-3.75.so") - pass - except: - print "Skipping libfmod-3.75.so - not found" - pass - - self.path("libapr-1.so.0") - self.path("libaprutil-1.so.0") - self.path("libdb-4.2.so") - self.path("libcrypto.so.0.9.7") - self.path("libexpat.so.1") - self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0") - self.path("libssl.so.0.9.7") - #self.path("libuuid.so.1") - self.path("libSDL-1.2.so.0") - self.path("libELFIO.so") - #self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3") - self.path("libalut.so") - self.path("libopenal.so.1") - self.path("libtcmalloc_minimal.so.0") - self.path("libtcmalloc_minimal.so.0.2.2") - self.end_prefix("lib") - - - # Vivox runtimes - if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): - self.path("SLVoice") - self.end_prefix() - if self.prefix(src="vivox-runtime/i686-linux", dst="lib"): - self.path("libortp.so") - self.path("libvivoxsdk.so") - self.end_prefix("lib") - - -class Linux_x86_64Manifest(LinuxManifest): - def construct(self): - super(Linux_x86_64Manifest, self).construct() - - self.path("../llcommon/libllcommon.so", "lib64/libllcommon.so") - - if (not self.standalone()) and self.prefix("../../libraries/x86_64-linux/lib_release_client", dst="lib64"): - self.path("libapr-1.so.0") - self.path("libaprutil-1.so.0") - self.path("libdb-4.2.so") - self.path("libcrypto.so.0.9.8") - self.path("libexpat.so.1") - self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0") - self.path("libssl.so.0.9.8") - self.path("libuuid.so", "libuuid.so.1") - self.path("libSDL-1.2.so.0") - self.path("libELFIO.so") - self.path("libjpeg.so.7") - self.path("libpng12.so.0") - self.path("libopenjpeg.so.2") - self.path("libxml2.so.2") - #self.path("libz.so.1") #not needed - - # OpenAL - self.path("libopenal.so.1") - self.path("libalut.so.0") - - self.end_prefix("lib64") - - # Vivox runtimes and libs - if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): - self.path("SLVoice") - self.end_prefix("bin") - - if self.prefix(src="vivox-runtime/i686-linux", dst="lib32"): - #self.path("libalut.so") - self.path("libortp.so") - self.path("libvivoxsdk.so") - self.end_prefix("lib32") - - # 32bit libs needed for voice - if self.prefix("../../libraries/x86_64-linux/lib_release_client/32bit-compat", dst="lib32"): - self.path("libalut.so") - self.path("libidn.so.11") - self.path("libopenal.so.1") - # self.path("libortp.so") - self.path("libuuid.so.1") - self.end_prefix("lib32") - -if __name__ == "__main__": - main() +#!/usr/bin/python +# @file viewer_manifest.py +# @author Ryan Williams +# @brief Description of all installer viewer files, and methods for packaging +# them into installers for all supported platforms. +# +# $LicenseInfo:firstyear=2006&license=viewergpl$ +# +# Copyright (c) 2006-2009, Linden Research, Inc. +# +# Second Life Viewer Source Code +# The source code in this file ("Source Code") is provided by Linden Lab +# to you under the terms of the GNU General Public License, version 2.0 +# ("GPL"), unless you have obtained a separate licensing agreement +# ("Other License"), formally executed by you and Linden Lab. Terms of +# the GPL can be found in doc/GPL-license.txt in this distribution, or +# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +# +# There are special exceptions to the terms and conditions of the GPL as +# it is applied to this Source Code. View the full text of the exception +# in the file doc/FLOSS-exception.txt in this software distribution, or +# online at +# http://secondlifegrid.net/programs/open_source/licensing/flossexception +# +# By copying, modifying or distributing this software, you acknowledge +# that you have read and understood your obligations described above, +# and agree to abide by those obligations. +# +# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +# COMPLETENESS OR PERFORMANCE. +# $/LicenseInfo$ +import sys +import os.path +import re +import tarfile +viewer_dir = os.path.dirname(__file__) +# add llmanifest library to our path so we don't have to muck with PYTHONPATH +sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util')) +from llmanifest import LLManifest, main, proper_windows_path, path_ancestors + +class ViewerManifest(LLManifest): + def construct(self): + super(ViewerManifest, self).construct() + self.exclude("*.svn*") + self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") + self.path(src="../../etc/message.xml", dst="app_settings/message.xml") + + if self.prefix(src="app_settings"): + self.exclude("logcontrol.xml") + self.exclude("logcontrol-dev.xml") + self.path("*.pem") + self.path("*.ini") + self.path("*.xml") + self.path("*.db2") + + # include the entire shaders directory recursively + self.path("shaders") + # ... and the entire windlight directory + self.path("windlight") + # ... and the hunspell dictionaries + self.path("dictionaries") + self.end_prefix("app_settings") + + if self.prefix(src="character"): + self.path("*.llm") + self.path("*.xml") + self.path("*.tga") + self.end_prefix("character") + + # Include our fonts + if self.prefix(src="fonts"): + self.path("*.ttf") + self.path("*.txt") + self.end_prefix("fonts") + + # skins + if self.prefix(src="skins"): + self.path("paths.xml") + # include the entire textures directory recursively + if self.prefix(src="default/textures"): + self.path("*.tga") + self.path("*.j2c") + self.path("*.jpg") + self.path("*.png") + self.path("textures.xml") + self.end_prefix("default/textures") + self.path("default/xui/*/*.xml") + self.path("Default.xml") + self.path("default/*.xml") + if self.prefix(src="dark/textures"): + self.path("*.tga") + self.path("*.j2c") + self.path("*.jpg") + self.path("*.png") + self.path("textures.xml") + self.end_prefix("dark/textures") + self.path("dark.xml") + self.path("dark/*.xml") + + # Local HTML files (e.g. loading screen) + if self.prefix(src="*/html"): + self.path("*.png") + self.path("*/*/*.html") + self.path("*/*/*.gif") + self.end_prefix("*/html") + self.end_prefix("skins") + + # Files in the newview/ directory + self.path("gpu_table.txt") + + def login_channel(self): + """Channel reported for login and upgrade purposes ONLY; + used for A/B testing""" + # NOTE: Do not return the normal channel if login_channel + # is not specified, as some code may branch depending on + # whether or not this is present + return self.args.get('login_channel') + + def buildtype(self): + return self.args['buildtype'] + def standalone(self): + return self.args['standalone'] == "ON" + def grid(self): + return self.args['grid'] + def channel(self): + return self.args['channel'] + def channel_unique(self): + return self.channel().replace("Second Life", "").strip() + def channel_oneword(self): + return "".join(self.channel_unique().split()) + def channel_lowerword(self): + return self.channel_oneword().lower() + def viewer_branding_id(self): + return self.args['branding_id'] + def installer_prefix(self): + mapping={"secondlife":'SecondLife_', + "snowglobe":'Snowglobe_', + "singularity":'Singularity_'} + return mapping[self.viewer_branding_id()] + + def flags_list(self): + """ Convenience function that returns the command-line flags + for the grid""" + + # Set command line flags relating to the target grid + grid_flags = '' + if not self.default_grid(): + grid_flags = "--grid %(grid)s "\ + "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\ + {'grid':self.grid()} + + # set command line flags for channel + channel_flags = '' + if self.login_channel() and self.login_channel() != self.channel(): + # Report a special channel during login, but use default + channel_flags = '--channel "%s"' % (self.login_channel()) + else: + channel_flags = '--channel "%s"' % self.channel() + + # Deal with settings + if self.default_channel() and self.default_grid(): + setting_flags = '' + elif self.default_grid(): + setting_flags = '--settings settings_%s.xml'\ + % self.channel_lowerword() + else: + setting_flags = '--settings settings_%s_%s.xml'\ + % (self.grid(), self.channel_lowerword()) + + return " ".join((channel_flags, grid_flags, setting_flags)).strip() + +class WindowsManifest(ViewerManifest): + def final_exe(self): + return self.channel_oneword() + 'Viewer.exe' + + + def construct(self): + super(WindowsManifest, self).construct() + # the final exe is complicated because we're not sure where it's coming from, + # nor do we have a fixed name for the executable + self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) + + # Plugin host application + self.path(os.path.join(os.pardir, + 'llplugin', 'slplugin', self.args['configuration'], "SLPlugin.exe"), + "SLPlugin.exe") + + # need to get the kdu dll from any of the build directories as well + #~ try: + #~ self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'], + #~ '../../libraries/i686-win32/lib/release/llkdu.dll'), + #~ dst='llkdu.dll') + #~ pass + #~ except: + #~ print "Skipping llkdu.dll" + #~ pass + self.path(src="licenses-win32.txt", dst="licenses.txt") + + self.path("featuretable.txt") + + # For spellchecking + if self.prefix(src=self.args['configuration'], dst=""): + self.path("libhunspell.dll") + self.end_prefix() + + # For use in crash reporting (generates minidumps) + self.path("dbghelp.dll") + + # For using FMOD for sound... DJS + #~if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): + #~try: + #~self.path("fmod.dll") + #~pass + #~except: + #~print "Skipping fmod.dll - not found" + #~ pass + #~self.end_prefix() + + # For textures + #if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): + # self.path("openjpeg.dll") + # self.end_prefix() + + # Plugins - FilePicker + if self.prefix(src='../plugins/filepicker/%s' % self.args['configuration'], dst="llplugin"): + self.path("basic_plugin_filepicker.dll") + self.end_prefix() + + # Media plugins - QuickTime + if self.prefix(src='../plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_quicktime.dll") + self.end_prefix() + + # Media plugins - WebKit/Qt + if self.prefix(src='../plugins/webkit/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_webkit.dll") + self.end_prefix() + + # For WebKit/Qt plugin runtimes + if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"): + self.path("libeay32.dll") + self.path("qtcore4.dll") + self.path("qtgui4.dll") + self.path("qtnetwork4.dll") + self.path("qtopengl4.dll") + self.path("qtwebkit4.dll") + self.path("qtxmlpatterns4.dll") + self.path("ssleay32.dll") + self.end_prefix() + + # For WebKit/Qt plugin runtimes (image format plugins) + if self.prefix(src="../../libraries/i686-win32/lib/release/imageformats", dst="llplugin/imageformats"): + self.path("qgif4.dll") + self.path("qico4.dll") + self.path("qjpeg4.dll") + self.path("qmng4.dll") + self.path("qsvg4.dll") + self.path("qtiff4.dll") + self.end_prefix() + + if self.prefix(src="../../libraries/i686-win32/lib/release/codecs", dst="llplugin/codecs"): + self.path("qcncodecs4.dll") + self.path("qjpcodecs4.dll") + self.path("qkrcodecs4.dll") + self.path("qtwcodecs4.dll") + self.end_prefix() + + # Get llcommon and deps. If missing assume static linkage and continue. + if self.prefix(src=self.args['configuration'], dst=""): + try: + self.path('llcommon.dll') + except RuntimeError, err: + print err.message + print "Skipping llcommon.dll (assuming llcommon was linked statically)" + self.end_prefix() + if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): + try: + self.path('libapr-1.dll') + self.path('libaprutil-1.dll') + self.path('libapriconv-1.dll') + except RuntimeError, err: + pass + self.end_prefix() + + # For google-perftools tcmalloc allocator. + self.path("../../libraries/i686-win32/lib/release/libtcmalloc_minimal.dll", dst="libtcmalloc_minimal.dll") + + try: + if self.prefix("../../libraries/i686-win32/lib/release/msvcrt", dst=""): + self.path("*.dll") + self.path("*.manifest") + self.end_prefix() + except: + pass + + + # These need to be installed as a SxS assembly, currently a 'private' assembly. + # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx + #~ if self.prefix(src=self.args['configuration'], dst=""): + #~ if self.args['configuration'] == 'Debug': + #~ self.path("msvcr80d.dll") + #~ self.path("msvcp80d.dll") + #~ self.path("Microsoft.VC80.DebugCRT.manifest") + #~ else: + #~ self.path("msvcr80.dll") + #~ self.path("msvcp80.dll") + #~ self.path("Microsoft.VC80.CRT.manifest") + #~ self.end_prefix() + + # The config file name needs to match the exe's name. + #~ self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config") + + # Vivox runtimes + if self.prefix(src="vivox-runtime/i686-win32", dst=""): + self.path("SLVoice.exe") + self.path("alut.dll") + self.path("vivoxsdk.dll") + self.path("ortp.dll") + self.path("wrap_oal.dll") + self.end_prefix() + + if self.args['extra_libraries'] != None: + print self.args['extra_libraries'] + path_list = self.args['extra_libraries'].split('|') + for path in path_list: + path_pair = path.rsplit('/', 1) + if self.prefix(src=path_pair[0], dst=""): + self.path(path_pair[1]) + self.end_prefix() + + # pull in the crash logger and updater from other projects + self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], dst="win_crash_logger.exe") + self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], dst="updater.exe") + + + def nsi_file_commands(self, install=True): + def wpath(path): + if path.endswith('/') or path.endswith(os.path.sep): + path = path[:-1] + path = path.replace('/', '\\') + return path + + result = "" + dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])] + # sort deepest hierarchy first + dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b)) + dest_files.reverse() + out_path = None + for pkg_file in dest_files: + rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,'')) + installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file))) + pkg_file = wpath(os.path.normpath(pkg_file)) + if installed_dir != out_path: + if install: + out_path = installed_dir + result += 'SetOutPath ' + out_path + '\n' + if install: + result += 'File ' + pkg_file + '\n' + else: + result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n' + # at the end of a delete, just rmdir all the directories + if not install: + deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list] + # find all ancestors so that we don't skip any dirs that happened to have no non-dir children + deleted_dirs = [] + for d in deleted_file_dirs: + deleted_dirs.extend(path_ancestors(d)) + # sort deepest hierarchy first + deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b)) + deleted_dirs.reverse() + prev = None + for d in deleted_dirs: + if d != prev: # skip duplicates + result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n' + prev = d + + return result + + def package_finish(self): + # a standard map of strings for replacing in the templates + substitution_strings = { + 'version' : '.'.join(self.args['version']), + 'version_short' : '.'.join(self.args['version'][:-1]), + 'version_dashes' : '-'.join(self.args['version']), + 'final_exe' : self.final_exe(), + 'grid':self.args['grid'], + 'grid_caps':self.args['grid'].upper(), + # escape quotes becase NSIS doesn't handle them well + 'flags':self.flags_list().replace('"', '$\\"'), + 'channel':self.channel(), + 'channel_oneword':self.channel_oneword(), + 'channel_unique':self.channel_unique(), + } + + version_vars = """ + !define INSTEXE "%(final_exe)s" + !define VERSION "%(version_short)s" + !define VERSION_LONG "%(version)s" + !define VERSION_DASHES "%(version_dashes)s" + """ % substitution_strings + installer_file = "%(channel_oneword)s_%(version_dashes)s_Setup.exe" + grid_vars_template = """ + OutFile "%(installer_file)s" + !define VIEWERNAME "%(channel)s" + !define INSTFLAGS "%(flags)s" + !define INSTNAME "%(channel_oneword)s" + !define SHORTCUT "%(channel)s Viewer" + !define URLNAME "secondlife" + !define INSTALL_ICON "install_icon_singularity.ico" + !define UNINSTALL_ICON "install_icon_singularity.ico" + Caption "${VIEWERNAME} ${VERSION_LONG}" + """ + if 'installer_name' in self.args: + installer_file = self.args['installer_name'] + else: + installer_file = installer_file % substitution_strings + substitution_strings['installer_file'] = installer_file + + tempfile = "secondlife_setup_tmp.nsi" + # the following replaces strings in the nsi template + # it also does python-style % substitution + self.replace_in("installers/windows/installer_template.nsi", tempfile, { + "%%VERSION%%":version_vars, + "%%SOURCE%%":self.get_src_prefix(), + "%%GRID_VARS%%":grid_vars_template % substitution_strings, + "%%INSTALL_FILES%%":self.nsi_file_commands(True), + "%%DELETE_FILES%%":self.nsi_file_commands(False)}) + + # We use the Unicode version of NSIS, available from + # http://www.scratchpaper.com/ + try: + import _winreg as reg + NSIS_path = reg.QueryValue(reg.HKEY_LOCAL_MACHINE, r"SOFTWARE\NSIS\Unicode") + '\\makensis.exe' + self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) + except: + try: + NSIS_path = os.environ['ProgramFiles'] + '\\NSIS\\Unicode\\makensis.exe' + self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) + except: + NSIS_path = os.environ['ProgramFiles(X86)'] + '\\NSIS\\Unicode\\makensis.exe' + self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) + # self.remove(self.dst_path_of(tempfile)) + # If we're on a build machine, sign the code using our Authenticode certificate. JC + sign_py = os.path.expandvars("{SIGN_PY}") + if sign_py == "" or sign_py == "{SIGN_PY}": + sign_py = 'C:\\buildscripts\\code-signing\\sign.py' + if os.path.exists(sign_py): + self.run_command('python ' + sign_py + ' ' + self.dst_path_of(installer_file)) + else: + print "Skipping code signing,", sign_py, "does not exist" + self.created_path(self.dst_path_of(installer_file)) + self.package_file = installer_file + + +class DarwinManifest(ViewerManifest): + def construct(self): + # copy over the build result (this is a no-op if run within the xcode script) + self.path(self.args['configuration'] + "/" + self.app_name() + ".app", dst="") + + if self.prefix(src="", dst="Contents"): # everything goes in Contents + self.path(self.info_plist_name(), dst="Info.plist") + + # copy additional libs in /Contents/MacOS/ + self.path("../../libraries/universal-darwin/lib_release/libhunspell-1.2.dylib", dst="MacOS/libhunspell-1.2.dylib") + self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") + #self.path("../../libraries/universal-darwin/lib_release/libvorbisenc.2.dylib", dst="MacOS/libvorbisenc.2.dylib") + #self.path("../../libraries/universal-darwin/lib_release/libvorbisfile.3.dylib", dst="MacOS/libvorbisfile.3.dylib") + #self.path("../../libraries/universal-darwin/lib_release/libvorbis.0.dylib", dst="MacOS/libvorbis.0.dylib") + #self.path("../../libraries/universal-darwin/lib_release/libogg.0.dylib", dst="MacOS/libogg.0.dylib") + + # most everything goes in the Resources directory + if self.prefix(src="", dst="Resources"): + super(DarwinManifest, self).construct() + + if self.prefix("cursors_mac"): + self.path("*.tif") + self.end_prefix("cursors_mac") + + self.path("licenses-mac.txt", dst="licenses.txt") + self.path("featuretable_mac.txt") + self.path("SecondLife.nib") + + # SG:TODO + self.path("../newview/res/singularity.icns", dst="singularity.icns") + + # Translations + self.path("English.lproj") + self.path("German.lproj") + self.path("Japanese.lproj") + self.path("Korean.lproj") + self.path("da.lproj") + self.path("es.lproj") + self.path("fr.lproj") + self.path("hu.lproj") + self.path("it.lproj") + self.path("nl.lproj") + self.path("pl.lproj") + self.path("pt.lproj") + self.path("ru.lproj") + self.path("tr.lproj") + self.path("uk.lproj") + self.path("zh-Hans.lproj") + + # SLVoice and vivox lols + self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib") + self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib") + self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib") + self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") + self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") + + self.path("../llcommon/" + self.args['configuration'] + "/libllcommon.dylib", "libllcommon.dylib") + + libfile = "lib%s.dylib" + libdir = "../../libraries/universal-darwin/lib_release" + + for libfile in ("libapr-1.0.3.7.dylib", + "libaprutil-1.0.3.8.dylib", + "libexpat.0.5.0.dylib"): + self.path(os.path.join(libdir, libfile), libfile) + + # For using FMOD for sound...but, fmod is proprietary so some might not use it... + try: + self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") + pass + except: + print "Skipping libfmodwrapper.dylib - not found" + pass + + # our apps + try: + self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") + self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") + except: + pass + + # plugin launcher + self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app") + + # dependencies on shared libs + mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources") + slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources") + for libfile in ("libllcommon.dylib", + "libapr-1.0.3.7.dylib", + "libaprutil-1.0.3.8.dylib", + "libexpat.0.5.0.dylib"): + target_lib = os.path.join('../../..', libfile) + self.run_command("ln -sf %(target)r %(link)r" % + {'target': target_lib, + 'link' : os.path.join(slplugin_res_path, libfile)} + ) + #self.run_command("ln -sf %(target)r %(link)r" % + # {'target': target_lib, + # 'link' : os.path.join(mac_crash_logger_res_path, libfile)} + # ) + + # plugins + if self.prefix(src="", dst="llplugin"): + self.path("../plugins/filepicker/" + self.args['configuration'] + "/basic_plugin_filepicker.dylib", "basic_plugin_filepicker.dylib") + self.path("../plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") + self.path("../plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") + self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") + + self.end_prefix("llplugin") + + # command line arguments for connecting to the proper grid + self.put_in_file(self.flags_list(), 'arguments.txt') + + self.end_prefix("Resources") + + self.end_prefix("Contents") + + # NOTE: the -S argument to strip causes it to keep enough info for + # annotated backtraces (i.e. function names in the crash log). 'strip' with no + # arguments yields a slightly smaller binary but makes crash logs mostly useless. + # This may be desirable for the final release. Or not. + if self.buildtype().lower()=='release': + if ("package" in self.args['actions'] or + "unpacked" in self.args['actions']): + self.run_command('strip -S "%(viewer_binary)s"' % + { 'viewer_binary' : self.dst_path_of('Contents/MacOS/'+self.app_name())}) + + def app_name(self): + return "Singularity" + + def info_plist_name(self): + return "Info-Singularity.plist" + + def package_finish(self): + channel_standin = self.app_name() + if not self.default_channel_for_brand(): + channel_standin = self.channel() + + imagename=self.installer_prefix() + '_'.join(self.args['version']) + + # See Ambroff's Hack comment further down if you want to create new bundles and dmg + volname=self.app_name() + " Installer" # DO NOT CHANGE without checking Ambroff's Hack comment further down + + if self.default_channel_for_brand(): + if not self.default_grid(): + # beta case + imagename = imagename + '_' + self.args['grid'].upper() + else: + # first look, etc + imagename = imagename + '_' + self.channel_oneword().upper() + + sparsename = imagename + ".sparseimage" + finalname = imagename + ".dmg" + # make sure we don't have stale files laying about + self.remove(sparsename, finalname) + + self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % { + 'sparse':sparsename, + 'vol':volname}) + + # mount the image and get the name of the mount point and device node + hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"') + devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip() + volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip() + + # Copy everything in to the mounted .dmg + + if self.default_channel_for_brand() and not self.default_grid(): + app_name = self.app_name() + " " + self.args['grid'] + else: + app_name = channel_standin.strip() + + # Hack: + # Because there is no easy way to coerce the Finder into positioning + # the app bundle in the same place with different app names, we are + # adding multiple .DS_Store files to svn. There is one for release, + # one for release candidate and one for first look. Any other channels + # will use the release .DS_Store, and will look broken. + # - Ambroff 2008-08-20 + # Added a .DS_Store for snowglobe - Merov 2009-06-17 + + # We have a single branded installer for all snowglobe channels so snowglobe logic is a bit different + if (self.app_name()=="Snowglobe"): + dmg_template = os.path.join ('installers', 'darwin', 'snowglobe-dmg') + else: + dmg_template = os.path.join( + 'installers', + 'darwin', + '%s-dmg' % "".join(self.channel_unique().split()).lower()) + + if not os.path.exists (self.src_path_of(dmg_template)): + dmg_template = os.path.join ('installers', 'darwin', 'release-dmg') + + for s,d in {self.get_dst_prefix():app_name + ".app", + os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns", + os.path.join(dmg_template, "background.jpg"): "background.jpg", + os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items(): + print "Copying to dmg", s, d + self.copy_action(self.src_path_of(s), os.path.join(volpath, d)) + + # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) + self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"') + self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"') + self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"') + + # Create the alias file (which is a resource file) from the .r + self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"') + + # Set the alias file's alias and custom icon bits + self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"') + + # Set the disk image root's custom icon bit + self.run_command('SetFile -a C "' + volpath + '"') + + # Unmount the image + self.run_command('hdiutil detach -force "' + devfile + '"') + + print "Converting temp disk image to final disk image" + self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname}) + # get rid of the temp file + self.package_file = finalname + self.remove(sparsename) + +class LinuxManifest(ViewerManifest): + def construct(self): + super(LinuxManifest, self).construct() + self.path("licenses-linux.txt","licenses.txt") + + self.path("res/"+self.icon_name(),self.icon_name()) + if self.prefix("linux_tools", dst=""): + self.path("client-readme.txt","README-linux.txt") + self.path("client-readme-voice.txt","README-linux-voice.txt") + self.path("client-readme-joystick.txt","README-linux-joystick.txt") + self.path("wrapper.sh",self.wrapper_name()) + self.path("handle_secondlifeprotocol.sh") + self.path("register_secondlifeprotocol.sh") + self.end_prefix("linux_tools") + + # Create an appropriate gridargs.dat for this package, denoting required grid. + self.put_in_file(self.flags_list(), 'gridargs.dat') + + if self.buildtype().lower()=='release': + self.path("secondlife-stripped","bin/"+self.binary_name()) + self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin") + else: + self.path("secondlife-bin","bin/"+self.binary_name()) + self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") + + self.path("linux_tools/launch_url.sh","launch_url.sh") + self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") + if self.prefix("res-sdl"): + self.path("*") + # recurse + self.end_prefix("res-sdl") + + # plugins + if self.prefix(src="", dst="bin/llplugin"): + self.path("../plugins/filepicker/libbasic_plugin_filepicker.so", "libbasic_plugin_filepicker.so") + self.path("../plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") + self.path("../plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so") + self.end_prefix("bin/llplugin") + + self.path("featuretable_linux.txt") + + def wrapper_name(self): + return 'singularity' + + def binary_name(self): + return 'singularity-do-not-run-directly' + + def icon_name(self): + return "singularity_icon.png" + + def package_finish(self): + if 'installer_name' in self.args: + installer_name = self.args['installer_name'] + else: + installer_name_components = [self.installer_prefix(), self.args.get('arch')] + installer_name_components.extend(self.args['version']) + installer_name = "_".join(installer_name_components) + if self.default_channel(): + if not self.default_grid(): + installer_name += '_' + self.args['grid'].upper() + else: + installer_name += '_' + self.channel_oneword().upper() + + if self.args['buildtype'].lower() in ['release', 'releasesse2']: + print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build" + # makes some small assumptions about our packaged dir structure + self.run_command("find %(d)r/bin %(d)r/lib* -type f | xargs --no-run-if-empty strip --strip-unneeded" % {'d': self.get_dst_prefix()} ) + self.run_command("find %(d)r/bin %(d)r/lib* -type f -not -name \\*.so | xargs --no-run-if-empty strip -s" % {'d': self.get_dst_prefix()} ) + + # Fix access permissions + self.run_command(""" + find '%(dst)s' -type d -print0 | xargs -0 --no-run-if-empty chmod 755; + find '%(dst)s' -type f -perm 0700 -print0 | xargs -0 --no-run-if-empty chmod 0755; + find '%(dst)s' -type f -perm 0500 -print0 | xargs -0 --no-run-if-empty chmod 0555; + find '%(dst)s' -type f -perm 0600 -print0 | xargs -0 --no-run-if-empty chmod 0644; + find '%(dst)s' -type f -perm 0400 -print0 | xargs -0 --no-run-if-empty chmod 0444; + true""" % {'dst':self.get_dst_prefix() }) + self.package_file = installer_name + '.tar.bz2' + + # temporarily move directory tree so that it has the right + # name in the tarfile + self.run_command("mv '%(dst)s' '%(inst)s'" % { + 'dst': self.get_dst_prefix(), + 'inst': self.build_path_of(installer_name)}) + try: + # --numeric-owner hides the username of the builder for + # security etc. + # I'm leaving this disabled for speed + #self.run_command("tar -C '%(dir)s' --numeric-owner -cjf " + # "'%(inst_path)s.tar.bz2' %(inst_name)s" % { + # 'dir': self.get_build_prefix(), + # 'inst_name': installer_name, + # 'inst_path':self.build_path_of(installer_name)}) + print '' + finally: + self.run_command("mv '%(inst)s' '%(dst)s'" % { + 'dst': self.get_dst_prefix(), + 'inst': self.build_path_of(installer_name)}) + + +class Linux_i686Manifest(LinuxManifest): + def construct(self): + super(Linux_i686Manifest, self).construct() + + self.path("../llcommon/libllcommon.so", "lib/libllcommon.so") + + if (not self.standalone()) and self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): + + try: + self.path("libkdu_v42R.so", "libkdu.so") + pass + except: + print "Skipping libkdu_v42R.so - not found" + pass + + try: + self.path("libfmod-3.75.so") + pass + except: + print "Skipping libfmod-3.75.so - not found" + pass + + self.path("libapr-1.so.0") + self.path("libaprutil-1.so.0") + self.path("libdb-4.2.so") + self.path("libcrypto.so.0.9.7") + self.path("libexpat.so.1") + self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0") + self.path("libssl.so.0.9.7") + #self.path("libuuid.so.1") + self.path("libSDL-1.2.so.0") + self.path("libELFIO.so") + #self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3") + self.path("libalut.so") + self.path("libopenal.so.1") + self.path("libtcmalloc_minimal.so.0") + self.path("libtcmalloc_minimal.so.0.2.2") + self.end_prefix("lib") + + + # Vivox runtimes + if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): + self.path("SLVoice") + self.end_prefix() + if self.prefix(src="vivox-runtime/i686-linux", dst="lib"): + self.path("libortp.so") + self.path("libvivoxsdk.so") + self.end_prefix("lib") + + +class Linux_x86_64Manifest(LinuxManifest): + def construct(self): + super(Linux_x86_64Manifest, self).construct() + + self.path("../llcommon/libllcommon.so", "lib64/libllcommon.so") + + if (not self.standalone()) and self.prefix("../../libraries/x86_64-linux/lib_release_client", dst="lib64"): + self.path("libapr-1.so.0") + self.path("libaprutil-1.so.0") + self.path("libdb-4.2.so") + self.path("libcrypto.so.0.9.8") + self.path("libexpat.so.1") + self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0") + self.path("libssl.so.0.9.8") + self.path("libuuid.so", "libuuid.so.1") + self.path("libSDL-1.2.so.0") + self.path("libELFIO.so") + self.path("libjpeg.so.7") + self.path("libpng12.so.0") + self.path("libopenjpeg.so.2") + self.path("libxml2.so.2") + #self.path("libz.so.1") #not needed + + # OpenAL + self.path("libopenal.so.1") + self.path("libalut.so.0") + + self.end_prefix("lib64") + + # Vivox runtimes and libs + if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): + self.path("SLVoice") + self.end_prefix("bin") + + if self.prefix(src="vivox-runtime/i686-linux", dst="lib32"): + #self.path("libalut.so") + self.path("libortp.so") + self.path("libvivoxsdk.so") + self.end_prefix("lib32") + + # 32bit libs needed for voice + if self.prefix("../../libraries/x86_64-linux/lib_release_client/32bit-compat", dst="lib32"): + self.path("libalut.so") + self.path("libidn.so.11") + self.path("libopenal.so.1") + # self.path("libortp.so") + self.path("libuuid.so.1") + self.end_prefix("lib32") + +if __name__ == "__main__": + main() From a4363de59e2130aafe161552ffa2fcf77a9a6390 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Sun, 19 Feb 2012 15:59:47 -0500 Subject: [PATCH 3/9] Updated APR and Zlib prebuilts. --- indra/cmake/APR.cmake | 8 +-- indra/newview/viewer_manifest.py | 8 +-- install.xml | 114 +++++++++++++++---------------- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake index d1f089891..5c434f4bf 100644 --- a/indra/cmake/APR.cmake +++ b/indra/cmake/APR.cmake @@ -29,12 +29,12 @@ else (STANDALONE) ) elseif (DARWIN) set(APR_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.0.3.7.dylib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.3.7.dylib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.0.dylib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.dylib ) set(APRUTIL_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.0.3.8.dylib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.3.8.dylib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.0.dylib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.dylib ) set(APRICONV_LIBRARIES iconv) else (WINDOWS) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index b492ddaef..8f49f94a9 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -514,8 +514,8 @@ class DarwinManifest(ViewerManifest): libfile = "lib%s.dylib" libdir = "../../libraries/universal-darwin/lib_release" - for libfile in ("libapr-1.0.3.7.dylib", - "libaprutil-1.0.3.8.dylib", + for libfile in ("libapr-1.0.dylib", + "libaprutil-1.0.dylib", "libexpat.0.5.0.dylib"): self.path(os.path.join(libdir, libfile), libfile) @@ -541,8 +541,8 @@ class DarwinManifest(ViewerManifest): mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources") slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources") for libfile in ("libllcommon.dylib", - "libapr-1.0.3.7.dylib", - "libaprutil-1.0.3.8.dylib", + "libapr-1.0.dylib", + "libaprutil-1.0.dylib", "libexpat.0.5.0.dylib"): target_lib = os.path.join('../../..', libfile) self.run_command("ln -sf %(target)r %(link)r" % diff --git a/install.xml b/install.xml index d7ce8c54d..23be3cc8d 100644 --- a/install.xml +++ b/install.xml @@ -29,7 +29,7 @@ - freeglut + freeglut copyright Copyright (c) 1999-2000 Pawel W. Olszta. @@ -90,9 +90,9 @@ darwin md5sum - 115d8ac44a91efdb173e9b3e478c46b6 + 2486db13c5ed9340855da3c1c48772af url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.7-darwin-20090805.tar.bz2 + https://github.com/downloads/LightDrake/SingularityViewer/apr_suite-1.4.2-darwin-20110217.tar.bz2 linux @@ -172,7 +172,7 @@ md5sum a2cde4f24bdcc260b661e139846b8acd url - http://imprudenceviewer.org/download/libs/imprudence-artwork-20101026.tar.bz2 + http://imprudenceviewer.org/download/libs/imprudence-artwork-20101026.tar.bz2 @@ -200,14 +200,14 @@ md5sum 2cad51575b429be4fdadb5d63da1c739 url - https://github.com/downloads/siana/SingularityViewer/boost-1.45.0-darwin-20110604.tar.bz2 + https://github.com/downloads/siana/SingularityViewer/boost-1.45.0-darwin-20110604.tar.bz2 linux md5sum a2d2fff5cc5555ffd9865daedfcd0dd5 url - https://github.com/downloads/siana/SingularityViewer/boost-1.45.0-linux-20110604.tar.bz2 + https://github.com/downloads/siana/SingularityViewer/boost-1.45.0-linux-20110604.tar.bz2 windows @@ -218,46 +218,46 @@ - curl - - copyright - Copyright (c) 1996 - 2008, Daniel Stenberg, <daniel@haxx.se>. - description - Client-side URL transfer library. Handles moving data across the net in many different protocols. Used to GET/POST/PUT/DELETE web resources. - license - curl - packages - - darwin - - md5sum - 525f6b18ea5af8fbd691c2ac1769056c - url - https://github.com/downloads/Shyotl/SingularityViewer/curl-7.20.1-darwin-20100606.tar.bz2 - - linux - - md5sum - 6244eec15fb26f9577785625fdb38f78 - url - https://github.com/downloads/Shyotl/SingularityViewer/curl-7.20.1-linux-20100527.tar.bz2 - - linux64 - - md5sum - 8a28849f4b9d99601dbc8db9d6a2f9ba - url - https://github.com/downloads/Shyotl/SingularityViewer/curl-7.16.4a-linux64-20090303.tar.bz2 - - windows - - md5sum - 60ed73408c4050ff9c96f26771fd6b46 - url - https://github.com/downloads/siana/SingularityViewer/curl-7.21.1-windows-20110504.tar.bz2 - - - + curl + + copyright + Copyright (c) 1996 - 2008, Daniel Stenberg, <daniel@haxx.se>. + description + Client-side URL transfer library. Handles moving data across the net in many different protocols. Used to GET/POST/PUT/DELETE web resources. + license + curl + packages + + darwin + + md5sum + 525f6b18ea5af8fbd691c2ac1769056c + url + https://github.com/downloads/Shyotl/SingularityViewer/curl-7.20.1-darwin-20100606.tar.bz2 + + linux + + md5sum + 6244eec15fb26f9577785625fdb38f78 + url + https://github.com/downloads/Shyotl/SingularityViewer/curl-7.20.1-linux-20100527.tar.bz2 + + linux64 + + md5sum + 8a28849f4b9d99601dbc8db9d6a2f9ba + url + https://github.com/downloads/Shyotl/SingularityViewer/curl-7.16.4a-linux64-20090303.tar.bz2 + + windows + + md5sum + 60ed73408c4050ff9c96f26771fd6b46 + url + https://github.com/downloads/siana/SingularityViewer/curl-7.21.1-windows-20110504.tar.bz2 + + + dbghelp copyright @@ -546,14 +546,14 @@ md5sum b190d8a0dce8dd8b514d2adb2c74b8d8 url - http://sldev.free.fr/libraries/google-perftools-1.8.3-linux-20110924.tar.bz2 + http://sldev.free.fr/libraries/google-perftools-1.8.3-linux-20110924.tar.bz2 windows md5sum 4f787437a5e063ccde6637dfb1ebc01d url - https://bitbucket.org/Ansariel/phoenix-prebuilts/downloads/google_perftools-1.8-windows-20111005.tar.bz2 + https://bitbucket.org/Ansariel/phoenix-prebuilts/downloads/google_perftools-1.8-windows-20111005.tar.bz2 @@ -995,7 +995,7 @@ anguage Infrstructure (CLI) international standard md5sum 38abfe002ba073b6824016db98269972 url - http://imprudenceviewer.org/download/libs/ndofdev-linux32-0.3.1-20100817.tar.bz2 + http://imprudenceviewer.org/download/libs/ndofdev-linux32-0.3.1-20100817.tar.bz2 linux64 @@ -1028,14 +1028,14 @@ anguage Infrstructure (CLI) international standard md5sum 5a154313bc30eacd8cfa1acd852ecd3e url - https://github.com/downloads/siana/SingularityViewer/ogg_vorbis-1.2.2-1.3.2-darwin-20110616.tar.bz2 + https://github.com/downloads/siana/SingularityViewer/ogg_vorbis-1.2.2-1.3.2-darwin-20110616.tar.bz2 linux md5sum 712b1d30790e9de83fea84ec3bc8fab0 url - https://github.com/downloads/siana/SingularityViewer/ogg_vorbis-1.2.2-1.3.2-linux-20110616.tar.bz2 + https://github.com/downloads/siana/SingularityViewer/ogg_vorbis-1.2.2-1.3.2-linux-20110616.tar.bz2 linux64 @@ -1227,10 +1227,10 @@ anguage Infrstructure (CLI) international standard 32bitcompatibilitylibs copyright - Copyrights: Libidn: Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - Simon Josefsson. License GPL v3.0. - Freealut, libuuid, openal-soft: see copyright and license of the - according main packages. + Copyrights: Libidn: Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Simon Josefsson. License GPL v3.0. + Freealut, libuuid, openal-soft: see copyright and license of the + according main packages. description 32bit libraries needed for using voice @@ -1300,9 +1300,9 @@ anguage Infrstructure (CLI) international standard darwin md5sum - c844e1b05723ce078dbbd5aea9cdd3ad + 58ef62004b508b234039f6a313d852eb url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.1.4-darwin-20080818.tar.bz2 + https://github.com/downloads/LightDrake/SingularityViewer/zlib-1.2.5-darwin-20110211.tar.bz2 linux From 665569dfc7ae6e01ce7d5788b32414804d5ae989 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Sun, 19 Feb 2012 17:07:42 -0500 Subject: [PATCH 4/9] I forgot why I made these. --- indra/cmake/00-Common.cmake | 6 +++--- indra/cmake/Boost.cmake | 2 +- indra/cmake/DirectX.cmake | 4 ++-- indra/cmake/LLCommon.cmake | 1 + indra/cmake/LLPlugin.cmake | 4 ++-- indra/cmake/Python.cmake | 1 - 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 1f9854be8..18cc4c695 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -158,10 +158,10 @@ if (LINUX) add_definitions(-D_FORTIFY_SOURCE=2) endif (NOT ${GXX_VERSION} MATCHES " 4.1.*Red Hat") endif (${GXX_VERSION} STREQUAL ${CXX_VERSION}) - - #Lets actualy get a numerical version of gxx's version + + #Lets actually get a numerical version of gxx's version STRING(REGEX REPLACE ".* ([0-9])\\.([0-9])\\.([0-9]).*" "\\1\\2\\3" CXX_VERSION ${CXX_VERSION}) - + #gcc 4.3 and above don't like the LL boost if(${CXX_VERSION} GREATER 429) add_definitions(-Wno-parentheses) diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 0cd10bd6c..1275d0547 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -10,7 +10,7 @@ if (STANDALONE) set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt) set(BOOST_REGEX_LIBRARY boost_regex-mt) - set(BOOST_SYSTEM_LIBRARY boost_system-mt) + set(BOOST_SYSTEM_LIBRARY boost_system-mt) else (STANDALONE) use_prebuilt_binary(boost) set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) diff --git a/indra/cmake/DirectX.cmake b/indra/cmake/DirectX.cmake index 5f538c80a..e45575595 100644 --- a/indra/cmake/DirectX.cmake +++ b/indra/cmake/DirectX.cmake @@ -3,7 +3,7 @@ if (VIEWER AND WINDOWS) find_path(DIRECTX_INCLUDE_DIR dxdiag.h "$ENV{DXSDK_DIR}/Include" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Include" + "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Include" "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2009)/Include" "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2008)/Include" "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2008)/Include" @@ -25,7 +25,7 @@ if (VIEWER AND WINDOWS) find_path(DIRECTX_LIBRARY_DIR dxguid.lib "$ENV{DXSDK_DIR}/Lib/x86" - "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Lib/x86" + "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Lib/x86" "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2009)/Lib/x86" "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2008)/Lib/x86" "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2008)/Lib/x86" diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 58316a489..b1bb1b6a9 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -14,6 +14,7 @@ endif (DARWIN) set(LLCOMMON_INCLUDE_DIRS ${LIBS_OPEN_DIR}/cwdebug ${LIBS_OPEN_DIR}/llcommon + ${APRUTIL_INCLUDE_DIR} ${APR_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ) diff --git a/indra/cmake/LLPlugin.cmake b/indra/cmake/LLPlugin.cmake index 7ee404b9b..399cb332d 100644 --- a/indra/cmake/LLPlugin.cmake +++ b/indra/cmake/LLPlugin.cmake @@ -8,7 +8,7 @@ set(LLPLUGIN_INCLUDE_DIRS if (LINUX) # In order to support using ld.gold on linux, we need to explicitely # specify all libraries that llplugin uses. - set(LLPLUGIN_LIBRARIES llplugin pthread) + set(LLPLUGIN_LIBRARIES llplugin pthread) else (LINUX) - set(LLPLUGIN_LIBRARIES llplugin) + set(LLPLUGIN_LIBRARIES llplugin) endif (LINUX) diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake index a84ab64aa..748c8c2be 100644 --- a/indra/cmake/Python.cmake +++ b/indra/cmake/Python.cmake @@ -19,7 +19,6 @@ if (WINDOWS) [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] - ) elseif (EXISTS /etc/debian_version) # On Debian and Ubuntu, avoid Python 2.4 if possible. From c6d6eed7d33121ac2bbd466ac2e49cccd6f6d921 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Sun, 19 Feb 2012 19:43:53 -0500 Subject: [PATCH 5/9] This works for now. Need to do more testing. --- indra/newview/app_settings/settings.xml | 54 ++- indra/newview/lltranslate.cpp | 469 ++++++++++++++++++------ indra/newview/lltranslate.h | 372 ++++++++++++++----- indra/newview/llviewermessage.cpp | 26 +- 4 files changed, 696 insertions(+), 225 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2b521fed4..7553e8816 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1,16 +1,15 @@ - Include - - settings_ascent.xml - settings_ascent_coa.xml - settings_sh.xml - settings_rlv.xml - - - SianaRenderDeferredInvisiprim - + Include + + settings_ascent.xml + settings_ascent_coa.xml + settings_sh.xml + settings_rlv.xml + + SianaRenderDeferredInvisiprim + Comment Support invisiprims in deferred mode Persist @@ -7525,12 +7524,45 @@ Comment Translate incoming chat messages Persist - 0 + 1 Type Boolean Value 0 + TranslationService + + Comment + Translation API to use. (google|bing) + Persist + 1 + Type + String + Value + bing + + GoogleTranslateAPIKey + + Comment + Google Translate API key + Persist + 1 + Type + String + Value + + + BingTranslateAPIKey + + Comment + Bing AppID to use with the Microsoft Translator API + Persist + 1 + Type + String + Value + + LastFeatureVersion Comment diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 5a537ae95..fcff3a0c7 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -2,136 +2,401 @@ * @file lltranslate.cpp * @brief Functions for translating text via Google Translate. * -* $LicenseInfo:firstyear=2009&license=viewergpl$ -* -* Copyright (c) 2009, Linden Research, Inc. -* -* Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 -* -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception -* -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. -* -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. -* $/LicenseInfo$ -*/ + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ #include "llviewerprecompiledheaders.h" -#include "llbufferstream.h" #include "lltranslate.h" + +#include + +#include "llbufferstream.h" +#include "lltrans.h" #include "llui.h" -#include "sgversion.h" +#include "llviewercontrol.h" #include "llweb.h" -// -#include "llviewercontrol.h" -// +#include "sgversion.h" -// These two are concatenated with the language specifiers to form a complete Google Translate URL -const char* LLTranslate::m_GoogleURL = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q="; -const char* LLTranslate::m_GoogleLangSpec = "&langpair="; -float LLTranslate::m_GoogleTimeout = 10; +#include "jsoncpp/reader.h" -LLSD LLTranslate::m_Header; -// These constants are for the GET header. -const char* LLTranslate::m_AcceptHeader = "Accept"; -const char* LLTranslate::m_AcceptType = "text/plain"; -const char* LLTranslate::m_AgentHeader = "User-Agent"; - -// These constants are in the JSON returned from Google -const char* LLTranslate::m_GoogleData = "responseData"; -const char* LLTranslate::m_GoogleTranslation = "translatedText"; -const char* LLTranslate::m_GoogleLanguage = "detectedSourceLanguage"; - -//static -void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg) +// virtual +void LLGoogleTranslationHandler::getTranslateURL( + std::string &url, + const std::string &from_lang, + const std::string &to_lang, + const std::string &text) const { - std::string url; - getTranslateUrl(url, fromLang, toLang, mesg); - -// - std::string user_agent = gCurrentVersion; -// - - if (!m_Header.size()) + url = std::string("https://www.googleapis.com/language/translate/v2?key=") + + getAPIKey() + "&q=" + LLURI::escape(text) + "&target=" + to_lang; + if (!from_lang.empty()) { - m_Header.insert(m_AcceptHeader, LLSD(m_AcceptType)); - m_Header.insert(m_AgentHeader, LLSD(user_agent)); - } - - LLHTTPClient::get(url, result, m_Header, m_GoogleTimeout); -} - -//static -void LLTranslate::getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &mesg) -{ - std::string escaped_mesg = LLWeb::curlEscape(mesg); - - translateUrl = m_GoogleURL - + escaped_mesg + m_GoogleLangSpec - + fromLang // 'from' language; empty string for auto - + "%7C" // | - + toLang; // 'to' language -} - -//static -void LLTranslate::stringReplaceAll(std::string& context, const std::string& from, const std::string& to) -{ - size_t lookHere = 0; - size_t foundHere; - - while((foundHere = context.find(from, lookHere)) - != std::string::npos) { - context.replace(foundHere, from.size(), to); - lookHere = foundHere + to.size(); + url += "&source=" + from_lang; } } -//static -BOOL LLTranslate::parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage) +// virtual +void LLGoogleTranslationHandler::getKeyVerificationURL( + std::string& url, + const std::string& key) const +{ + url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=") + + key + "&target=en"; +} + +// virtual +bool LLGoogleTranslationHandler::parseResponse( + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const { Json::Value root; Json::Reader reader; - BOOL parsingSuccessful = reader.parse(result, root ); - if ( !parsingSuccessful ) + + if (!reader.parse(body, root)) { - LL_WARNS("JSON") << reader.getFormatedErrorMessages() << LL_ENDL; - return FALSE; + err_msg = reader.getFormatedErrorMessages(); + return false; } - translation = root[m_GoogleData].get(m_GoogleTranslation, "").asString(); - detectedLanguage = root[m_GoogleData].get(m_GoogleLanguage, "").asString(); - return TRUE; + if (!root.isObject()) // empty response? should not happen + { + return false; + } + + if (status != STATUS_OK) + { + // Request failed. Extract error message from the response. + parseErrorResponse(root, status, err_msg); + return false; + } + + // Request succeeded, extract translation from the response. + return parseTranslation(root, translation, detected_lang); +} + +// virtual +bool LLGoogleTranslationHandler::isConfigured() const +{ + return !getAPIKey().empty(); +} + +// static +void LLGoogleTranslationHandler::parseErrorResponse( + const Json::Value& root, + int& status, + std::string& err_msg) +{ + const Json::Value& error = root.get("error", 0); + if (!error.isObject() || !error.isMember("message") || !error.isMember("code")) + { + return; + } + + err_msg = error["message"].asString(); + status = error["code"].asInt(); +} + +// static +bool LLGoogleTranslationHandler::parseTranslation( + const Json::Value& root, + std::string& translation, + std::string& detected_lang) +{ + // JsonCpp is prone to aborting the program on failed assertions, + // so be super-careful and verify the response format. + const Json::Value& data = root.get("data", 0); + if (!data.isObject() || !data.isMember("translations")) + { + return false; + } + + const Json::Value& translations = data["translations"]; + if (!translations.isArray() || translations.size() == 0) + { + return false; + } + + const Json::Value& first = translations[0U]; + if (!first.isObject() || !first.isMember("translatedText")) + { + return false; + } + + translation = first["translatedText"].asString(); + detected_lang = first.get("detectedSourceLanguage", "").asString(); + return true; +} + +// static +std::string LLGoogleTranslationHandler::getAPIKey() +{ + return gSavedSettings.getString("GoogleTranslateAPIKey"); +} + +// virtual +void LLBingTranslationHandler::getTranslateURL( + std::string &url, + const std::string &from_lang, + const std::string &to_lang, + const std::string &text) const +{ + url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=") + + getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + to_lang; + if (!from_lang.empty()) + { + url += "&from=" + from_lang; + } +} + +// virtual +void LLBingTranslationHandler::getKeyVerificationURL( + std::string& url, + const std::string& key) const +{ + url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=") + + key; +} + +// virtual +bool LLBingTranslationHandler::parseResponse( + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const +{ + if (status != STATUS_OK) + { + static const std::string MSG_BEGIN_MARKER = "Message: "; + size_t begin = body.find(MSG_BEGIN_MARKER); + if (begin != std::string::npos) + { + begin += MSG_BEGIN_MARKER.size(); + } + else + { + begin = 0; + err_msg.clear(); + } + size_t end = body.find("

", begin); + err_msg = body.substr(begin, end-begin); + LLStringUtil::replaceString(err_msg, " ", ""); // strip CR + return false; + } + + // Sample response: Hola + size_t begin = body.find(">"); + if (begin == std::string::npos || begin >= (body.size() - 1)) + { + begin = 0; + } + else + { + ++begin; + } + + size_t end = body.find("", begin); + + detected_lang = ""; // unsupported by this API + translation = body.substr(begin, end-begin); + LLStringUtil::replaceString(translation, " ", ""); // strip CR + return true; +} + +// virtual +bool LLBingTranslationHandler::isConfigured() const +{ + return !getAPIKey().empty(); +} + +// static +std::string LLBingTranslationHandler::getAPIKey() +{ + return gSavedSettings.getString("BingTranslateAPIKey"); +} + +LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang) +: mFromLang(from_lang) +, mToLang(to_lang) +, mHandler(LLTranslate::getPreferredHandler()) +{ +} + +// virtual +void LLTranslate::TranslationReceiver::completedRaw( + U32 http_status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) +{ + LLBufferStream istr(channels, buffer.get()); + std::stringstream strstrm; + strstrm << istr.rdbuf(); + + const std::string body = strstrm.str(); + std::string translation, detected_lang, err_msg; + int status = http_status; + LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL; + LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL; + if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg)) + { + // Fix up the response + LLStringUtil::replaceString(translation, "<", "<"); + LLStringUtil::replaceString(translation, ">",">"); + LLStringUtil::replaceString(translation, ""","\""); + LLStringUtil::replaceString(translation, "'","'"); + LLStringUtil::replaceString(translation, "&","&"); + LLStringUtil::replaceString(translation, "'","'"); + + handleResponse(translation, detected_lang); + } + else + { + if (err_msg.empty()) + { + err_msg = LLTrans::getString("TranslationResponseParseError"); + } + + llwarns << "Translation request failed: " << err_msg << llendl; + handleFailure(status, err_msg); + } +} + +LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service) +: mService(service) +{ +} + +LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const +{ + return mService; +} + +// virtual +void LLTranslate::KeyVerificationReceiver::completedRaw( + U32 http_status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) +{ + bool ok = (http_status == 200); + setVerificationStatus(ok); +} + +//static +void LLTranslate::translateMessage( + TranslationReceiverPtr &receiver, + const std::string &from_lang, + const std::string &to_lang, + const std::string &mesg) +{ + std::string url; + receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg); + + LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL; + sendRequest(url, receiver); +} + +// static +void LLTranslate::verifyKey( + KeyVerificationReceiverPtr& receiver, + const std::string& key) +{ + std::string url; + const LLTranslationAPIHandler& handler = getHandler(receiver->getService()); + handler.getKeyVerificationURL(url, key); + + LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL; + sendRequest(url, receiver); } //static std::string LLTranslate::getTranslateLanguage() { - std::string language = "en"; - if (LLUI::sConfigGroup) + std::string language = gSavedSettings.getString("TranslateLanguage"); + if (language.empty() || language == "default") { - language = LLUI::sConfigGroup->getString("TranslateLanguage"); - if (language.empty() || language == "default") - { - language = LLUI::getLanguage(); - } + language = LLUI::getLanguage(); } language = language.substr(0,2); return language; } +// static +bool LLTranslate::isTranslationConfigured() +{ + return getPreferredHandler().isConfigured(); +} + +// static +const LLTranslationAPIHandler& LLTranslate::getPreferredHandler() +{ + EService service = SERVICE_BING; + + std::string service_str = gSavedSettings.getString("TranslationService"); + if (service_str == "google") + { + service = SERVICE_GOOGLE; + } + + return getHandler(service); +} + +// static +const LLTranslationAPIHandler& LLTranslate::getHandler(EService service) +{ + static LLGoogleTranslationHandler google; + static LLBingTranslationHandler bing; + + if (service == SERVICE_GOOGLE) + { + return google; + } + + return bing; +} + +// static +void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder) +{ + static const float REQUEST_TIMEOUT = 5; + static LLSD sHeader; + + if (!sHeader.size()) + { + std::string user_agent = llformat("%s %d.%d.%d (%d)", + gVersionChannel, + gVersionMajor, + gVersionMinor, + gVersionPatch, + gVersionBuild); + + sHeader.insert("Accept", "text/plain"); + sHeader.insert("User-Agent", user_agent); + } + + LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT); +} diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index 2723c43ff..870cc1fae 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -2,33 +2,27 @@ * @file lltranslate.h * @brief Human language translation class and JSON response receiver. * -* $LicenseInfo:firstyear=2009&license=viewergpl$ -* -* Copyright (c) 2009, Linden Research, Inc. -* -* Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 -* -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception -* -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. -* -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. -* $/LicenseInfo$ -*/ + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ #ifndef LL_LLTRANSLATE_H #define LL_LLTRANSLATE_H @@ -37,89 +31,273 @@ #include "llbufferstream.h" #include "jsoncpp/reader.h" -class LLTranslate +namespace Json { -public : - class TranslationReceiver: public LLHTTPClient::Responder - { - protected: - TranslationReceiver(const std::string &fromLang, const std::string &toLang) - : m_fromLang(fromLang), - m_toLang(toLang) - { - } + class Value; +} - virtual void handleResponse(const std::string &translation, const std::string &recognizedLang) {} - virtual void handleFailure() {}; +/** + * Handler of an HTTP machine translation service. + * + * Derived classes know the service URL + * and how to parse the translation result. + */ +class LLTranslationAPIHandler +{ +public: + /** + * Get URL for translation of the given string. + * + * Sending HTTP GET request to the URL will initiate translation. + * + * @param[out] url Place holder for the result. + * @param from_lang Source language. Leave empty for auto-detection. + * @param to_lang Target language. + * @param text Text to translate. + */ + virtual void getTranslateURL( + std::string &url, + const std::string &from_lang, + const std::string &to_lang, + const std::string &text) const = 0; - public: - ~TranslationReceiver() - { - } + /** + * Get URL to verify the given API key. + * + * Sending request to the URL verifies the key. + * Positive HTTP response (code 200) means that the key is valid. + * + * @param[out] url Place holder for the URL. + * @param[in] key Key to verify. + */ + virtual void getKeyVerificationURL( + std::string &url, + const std::string &key) const = 0; - virtual void error(U32 status, const std::string& reason) - { - LL_WARNS("Translate") << "URL Request error: " << reason << LL_ENDL; - handleFailure(); - } + /** + * Parse translation response. + * + * @param[in,out] status HTTP status. May be modified while parsing. + * @param body Response text. + * @param[out] translation Translated text. + * @param[out] detected_lang Detected source language. May be empty. + * @param[out] err_msg Error message (in case of error). + */ + virtual bool parseResponse( + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const = 0; - virtual void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - LLBufferStream istr(channels, buffer.get()); + /** + * @return if the handler is configured to function properly + */ + virtual bool isConfigured() const = 0; - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string result = strstrm.str(); + virtual ~LLTranslationAPIHandler() {} - std::string translation; - std::string detectedLanguage; +protected: + static const int STATUS_OK = 200; +}; - if (!parseGoogleTranslate(result, translation, detectedLanguage)) - { - handleFailure(); - return; - } +/// Google Translate v2 API handler. +class LLGoogleTranslationHandler : public LLTranslationAPIHandler +{ + LOG_CLASS(LLGoogleTranslationHandler); - // Fix up the response - stringReplaceAll( translation, "<","<"); - stringReplaceAll( translation, ">",">"); - stringReplaceAll( translation, ""","\""); - stringReplaceAll( translation, "'","'"); - stringReplaceAll( translation, "&","&"); - stringReplaceAll( translation, "'","'"); - - handleResponse(translation, detectedLanguage); - } - - protected: - const std::string m_toLang; - const std::string m_fromLang; - }; - - static void translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg); - static float m_GoogleTimeout; - static std::string getTranslateLanguage(); +public: + /*virtual*/ void getTranslateURL( + std::string &url, + const std::string &from_lang, + const std::string &to_lang, + const std::string &text) const; + /*virtual*/ void getKeyVerificationURL( + std::string &url, + const std::string &key) const; + /*virtual*/ bool parseResponse( + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const; + /*virtual*/ bool isConfigured() const; private: - static void getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &text); - static void stringReplaceAll(std::string& context, const std::string& from, const std::string& to); - static BOOL parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage); + static void parseErrorResponse( + const Json::Value& root, + int& status, + std::string& err_msg); + static bool parseTranslation( + const Json::Value& root, + std::string& translation, + std::string& detected_lang); + static std::string getAPIKey(); +}; - static LLSD m_Header; - static const char* m_GoogleURL; - static const char* m_GoogleLangSpec; - static const char* m_AcceptHeader; - static const char* m_AcceptType; - static const char* m_AgentHeader; - static const char* m_UserAgent; +/// Microsoft Translator v2 API handler. +class LLBingTranslationHandler : public LLTranslationAPIHandler +{ + LOG_CLASS(LLBingTranslationHandler); - static const char* m_GoogleData; - static const char* m_GoogleTranslation; - static const char* m_GoogleLanguage; +public: + /*virtual*/ void getTranslateURL( + std::string &url, + const std::string &from_lang, + const std::string &to_lang, + const std::string &text) const; + /*virtual*/ void getKeyVerificationURL( + std::string &url, + const std::string &key) const; + /*virtual*/ bool parseResponse( + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const; + /*virtual*/ bool isConfigured() const; +private: + static std::string getAPIKey(); +}; + +/** + * Entry point for machine translation services. + * + * Basically, to translate a string, we need to know the URL + * of a translation service, have a valid API for the service + * and be given the target language. + * + * Callers specify the string to translate and the target language, + * LLTranslate takes care of the rest. + * + * API keys for translation are taken from saved settings. + */ +class LLTranslate +{ + LOG_CLASS(LLTranslate); + +public : + + typedef enum e_service { + SERVICE_BING, + SERVICE_GOOGLE, + } EService; + + /** + * Subclasses are supposed to handle translation results (e.g. show them in chat) + */ + class TranslationReceiver: public LLHTTPClient::Responder + { + public: + + /** + * Using mHandler, parse incoming response. + * + * Calls either handleResponse() or handleFailure() + * depending on the HTTP status code and parsing success. + * + * @see handleResponse() + * @see handleFailure() + * @see mHandler + */ + /*virtual*/ void completedRaw( + U32 http_status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + + protected: + friend class LLTranslate; + + /// Remember source and target languages for subclasses to be able to filter inappropriate results. + TranslationReceiver(const std::string& from_lang, const std::string& to_lang); + + /// Override point to handle successful translation. + virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0; + + /// Override point to handle unsuccessful translation. + virtual void handleFailure(int status, const std::string& err_msg) = 0; + + std::string mFromLang; + std::string mToLang; + const LLTranslationAPIHandler& mHandler; + }; + + /** + * Subclasses are supposed to handle API key verification result. + */ + class KeyVerificationReceiver: public LLHTTPClient::Responder + { + public: + EService getService() const; + + protected: + /** + * Save the translation service the key belongs to. + * + * Subclasses need to know it. + * + * @see getService() + */ + KeyVerificationReceiver(EService service); + + /** + * Parse verification response. + * + * Calls setVerificationStatus() with the verification status, + * which is true if HTTP status code is 200. + * + * @see setVerificationStatus() + */ + /*virtual*/ void completedRaw( + U32 http_status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + + /** + * Override point for subclasses to handle key verification status. + */ + virtual void setVerificationStatus(bool ok) = 0; + + EService mService; + }; + + typedef boost::intrusive_ptr TranslationReceiverPtr; + typedef boost::intrusive_ptr KeyVerificationReceiverPtr; + + /** + * Translate given text. + * + * @param receiver Object to pass translation result to. + * @param from_lang Source language. Leave empty for auto-detection. + * @param to_lang Target language. + * @param mesg Text to translate. + */ + static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg); + + /** + * Verify given API key of a translation service. + * + * @param receiver Object to pass verification result to. + * @param key Key to verify. + */ + static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key); + + /** + * @return translation target language + */ + static std::string getTranslateLanguage(); + + /** + * @return true if translation is configured properly. + */ + static bool isTranslationConfigured(); + +private: + static const LLTranslationAPIHandler& getPreferredHandler(); + static const LLTranslationAPIHandler& getHandler(EService service); + static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder); }; #endif diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 97ac3eb05..a060efd09 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2957,23 +2957,23 @@ void process_decline_callingcard(LLMessageSystem* msg, void**) class ChatTranslationReceiver : public LLTranslate::TranslationReceiver { public : - ChatTranslationReceiver(const std::string &fromLang, const std::string &toLang, LLChat *chat, + ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, LLChat *chat, const BOOL history) - : LLTranslate::TranslationReceiver(fromLang, toLang), + : LLTranslate::TranslationReceiver(from_lang, to_lang), m_chat(chat), m_history(history) { } - static boost::intrusive_ptr build(const std::string &fromLang, const std::string &toLang, LLChat *chat, const BOOL history) + static boost::intrusive_ptr build(const std::string &from_lang, const std::string &to_lang, LLChat *chat, const BOOL history) { - return boost::intrusive_ptr(new ChatTranslationReceiver(fromLang, toLang, chat, history)); + return boost::intrusive_ptr(new ChatTranslationReceiver(from_lang, to_lang, chat, history)); } protected: void handleResponse(const std::string &translation, const std::string &detectedLanguage) { - if (m_toLang != detectedLanguage) + if (mToLang != detectedLanguage) m_chat->mText += " (" + translation + ")"; add_floater_chat(*m_chat, m_history); @@ -2981,14 +2981,12 @@ protected: delete m_chat; } - void handleFailure() + void handleFailure(int status, const std::string& err_msg) { - LLTranslate::TranslationReceiver::handleFailure(); + llwarns << "Translation failed for mesg " << m_chat << " toLang " << mToLang << " fromLang " << mFromLang << llendl; m_chat->mText += " (?)"; - add_floater_chat(*m_chat, m_history); - delete m_chat; } @@ -3017,14 +3015,12 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist if (translate && chat.mSourceType != CHAT_SOURCE_SYSTEM) { - // fromLang hardcoded to "" (autodetection) pending implementation of - // SVC-4879 - const std::string &fromLang = ""; - const std::string &toLang = LLTranslate::getTranslateLanguage(); + const std::string &from_lang = ""; + const std::string &to_lang = LLTranslate::getTranslateLanguage(); LLChat *newChat = new LLChat(chat); - LLHTTPClient::ResponderPtr result = ChatTranslationReceiver::build(fromLang, toLang, newChat, history); - LLTranslate::translateMessage(result, fromLang, toLang, mesg); + LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, newChat, history); + LLTranslate::translateMessage(result, from_lang, to_lang, mesg); } else { From 638832455215ff5710d3febf8825aee7c779d316 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Tue, 21 Feb 2012 09:27:10 -0500 Subject: [PATCH 6/9] Revert "This works for now. Need to do more testing." This reverts commit c6d6eed7d33121ac2bbd466ac2e49cccd6f6d921. --- indra/newview/app_settings/settings.xml | 54 +-- indra/newview/lltranslate.cpp | 465 +++++------------------- indra/newview/lltranslate.h | 368 +++++-------------- indra/newview/llviewermessage.cpp | 26 +- 4 files changed, 221 insertions(+), 692 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7553e8816..2b521fed4 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1,15 +1,16 @@ - Include - - settings_ascent.xml - settings_ascent_coa.xml - settings_sh.xml - settings_rlv.xml - - SianaRenderDeferredInvisiprim - + Include + + settings_ascent.xml + settings_ascent_coa.xml + settings_sh.xml + settings_rlv.xml + + + SianaRenderDeferredInvisiprim + Comment Support invisiprims in deferred mode Persist @@ -7524,45 +7525,12 @@ Comment Translate incoming chat messages Persist - 1 + 0 Type Boolean Value 0 - TranslationService - - Comment - Translation API to use. (google|bing) - Persist - 1 - Type - String - Value - bing - - GoogleTranslateAPIKey - - Comment - Google Translate API key - Persist - 1 - Type - String - Value - - - BingTranslateAPIKey - - Comment - Bing AppID to use with the Microsoft Translator API - Persist - 1 - Type - String - Value - - LastFeatureVersion Comment diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index fcff3a0c7..5a537ae95 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -2,401 +2,136 @@ * @file lltranslate.cpp * @brief Functions for translating text via Google Translate. * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ #include "llviewerprecompiledheaders.h" -#include "lltranslate.h" - -#include - #include "llbufferstream.h" -#include "lltrans.h" +#include "lltranslate.h" #include "llui.h" -#include "llviewercontrol.h" +#include "sgversion.h" #include "llweb.h" -#include "sgversion.h" +// +#include "llviewercontrol.h" +// -#include "jsoncpp/reader.h" +// These two are concatenated with the language specifiers to form a complete Google Translate URL +const char* LLTranslate::m_GoogleURL = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q="; +const char* LLTranslate::m_GoogleLangSpec = "&langpair="; +float LLTranslate::m_GoogleTimeout = 10; -// virtual -void LLGoogleTranslationHandler::getTranslateURL( - std::string &url, - const std::string &from_lang, - const std::string &to_lang, - const std::string &text) const +LLSD LLTranslate::m_Header; +// These constants are for the GET header. +const char* LLTranslate::m_AcceptHeader = "Accept"; +const char* LLTranslate::m_AcceptType = "text/plain"; +const char* LLTranslate::m_AgentHeader = "User-Agent"; + +// These constants are in the JSON returned from Google +const char* LLTranslate::m_GoogleData = "responseData"; +const char* LLTranslate::m_GoogleTranslation = "translatedText"; +const char* LLTranslate::m_GoogleLanguage = "detectedSourceLanguage"; + +//static +void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg) { - url = std::string("https://www.googleapis.com/language/translate/v2?key=") - + getAPIKey() + "&q=" + LLURI::escape(text) + "&target=" + to_lang; - if (!from_lang.empty()) + std::string url; + getTranslateUrl(url, fromLang, toLang, mesg); + +// + std::string user_agent = gCurrentVersion; +// + + if (!m_Header.size()) { - url += "&source=" + from_lang; - } -} - -// virtual -void LLGoogleTranslationHandler::getKeyVerificationURL( - std::string& url, - const std::string& key) const -{ - url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=") - + key + "&target=en"; -} - -// virtual -bool LLGoogleTranslationHandler::parseResponse( - int& status, - const std::string& body, - std::string& translation, - std::string& detected_lang, - std::string& err_msg) const -{ - Json::Value root; - Json::Reader reader; - - if (!reader.parse(body, root)) - { - err_msg = reader.getFormatedErrorMessages(); - return false; + m_Header.insert(m_AcceptHeader, LLSD(m_AcceptType)); + m_Header.insert(m_AgentHeader, LLSD(user_agent)); } - if (!root.isObject()) // empty response? should not happen - { - return false; - } - - if (status != STATUS_OK) - { - // Request failed. Extract error message from the response. - parseErrorResponse(root, status, err_msg); - return false; - } - - // Request succeeded, extract translation from the response. - return parseTranslation(root, translation, detected_lang); -} - -// virtual -bool LLGoogleTranslationHandler::isConfigured() const -{ - return !getAPIKey().empty(); -} - -// static -void LLGoogleTranslationHandler::parseErrorResponse( - const Json::Value& root, - int& status, - std::string& err_msg) -{ - const Json::Value& error = root.get("error", 0); - if (!error.isObject() || !error.isMember("message") || !error.isMember("code")) - { - return; - } - - err_msg = error["message"].asString(); - status = error["code"].asInt(); -} - -// static -bool LLGoogleTranslationHandler::parseTranslation( - const Json::Value& root, - std::string& translation, - std::string& detected_lang) -{ - // JsonCpp is prone to aborting the program on failed assertions, - // so be super-careful and verify the response format. - const Json::Value& data = root.get("data", 0); - if (!data.isObject() || !data.isMember("translations")) - { - return false; - } - - const Json::Value& translations = data["translations"]; - if (!translations.isArray() || translations.size() == 0) - { - return false; - } - - const Json::Value& first = translations[0U]; - if (!first.isObject() || !first.isMember("translatedText")) - { - return false; - } - - translation = first["translatedText"].asString(); - detected_lang = first.get("detectedSourceLanguage", "").asString(); - return true; -} - -// static -std::string LLGoogleTranslationHandler::getAPIKey() -{ - return gSavedSettings.getString("GoogleTranslateAPIKey"); -} - -// virtual -void LLBingTranslationHandler::getTranslateURL( - std::string &url, - const std::string &from_lang, - const std::string &to_lang, - const std::string &text) const -{ - url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=") - + getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + to_lang; - if (!from_lang.empty()) - { - url += "&from=" + from_lang; - } -} - -// virtual -void LLBingTranslationHandler::getKeyVerificationURL( - std::string& url, - const std::string& key) const -{ - url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=") - + key; -} - -// virtual -bool LLBingTranslationHandler::parseResponse( - int& status, - const std::string& body, - std::string& translation, - std::string& detected_lang, - std::string& err_msg) const -{ - if (status != STATUS_OK) - { - static const std::string MSG_BEGIN_MARKER = "Message: "; - size_t begin = body.find(MSG_BEGIN_MARKER); - if (begin != std::string::npos) - { - begin += MSG_BEGIN_MARKER.size(); - } - else - { - begin = 0; - err_msg.clear(); - } - size_t end = body.find("

", begin); - err_msg = body.substr(begin, end-begin); - LLStringUtil::replaceString(err_msg, " ", ""); // strip CR - return false; - } - - // Sample response: Hola - size_t begin = body.find(">"); - if (begin == std::string::npos || begin >= (body.size() - 1)) - { - begin = 0; - } - else - { - ++begin; - } - - size_t end = body.find("", begin); - - detected_lang = ""; // unsupported by this API - translation = body.substr(begin, end-begin); - LLStringUtil::replaceString(translation, " ", ""); // strip CR - return true; -} - -// virtual -bool LLBingTranslationHandler::isConfigured() const -{ - return !getAPIKey().empty(); -} - -// static -std::string LLBingTranslationHandler::getAPIKey() -{ - return gSavedSettings.getString("BingTranslateAPIKey"); -} - -LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang) -: mFromLang(from_lang) -, mToLang(to_lang) -, mHandler(LLTranslate::getPreferredHandler()) -{ -} - -// virtual -void LLTranslate::TranslationReceiver::completedRaw( - U32 http_status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) -{ - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - - const std::string body = strstrm.str(); - std::string translation, detected_lang, err_msg; - int status = http_status; - LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL; - LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL; - if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg)) - { - // Fix up the response - LLStringUtil::replaceString(translation, "<", "<"); - LLStringUtil::replaceString(translation, ">",">"); - LLStringUtil::replaceString(translation, ""","\""); - LLStringUtil::replaceString(translation, "'","'"); - LLStringUtil::replaceString(translation, "&","&"); - LLStringUtil::replaceString(translation, "'","'"); - - handleResponse(translation, detected_lang); - } - else - { - if (err_msg.empty()) - { - err_msg = LLTrans::getString("TranslationResponseParseError"); - } - - llwarns << "Translation request failed: " << err_msg << llendl; - handleFailure(status, err_msg); - } -} - -LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service) -: mService(service) -{ -} - -LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const -{ - return mService; -} - -// virtual -void LLTranslate::KeyVerificationReceiver::completedRaw( - U32 http_status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) -{ - bool ok = (http_status == 200); - setVerificationStatus(ok); + LLHTTPClient::get(url, result, m_Header, m_GoogleTimeout); } //static -void LLTranslate::translateMessage( - TranslationReceiverPtr &receiver, - const std::string &from_lang, - const std::string &to_lang, - const std::string &mesg) +void LLTranslate::getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &mesg) { - std::string url; - receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg); + std::string escaped_mesg = LLWeb::curlEscape(mesg); - LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL; - sendRequest(url, receiver); + translateUrl = m_GoogleURL + + escaped_mesg + m_GoogleLangSpec + + fromLang // 'from' language; empty string for auto + + "%7C" // | + + toLang; // 'to' language } -// static -void LLTranslate::verifyKey( - KeyVerificationReceiverPtr& receiver, - const std::string& key) +//static +void LLTranslate::stringReplaceAll(std::string& context, const std::string& from, const std::string& to) { - std::string url; - const LLTranslationAPIHandler& handler = getHandler(receiver->getService()); - handler.getKeyVerificationURL(url, key); + size_t lookHere = 0; + size_t foundHere; - LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL; - sendRequest(url, receiver); + while((foundHere = context.find(from, lookHere)) + != std::string::npos) { + context.replace(foundHere, from.size(), to); + lookHere = foundHere + to.size(); + } +} + +//static +BOOL LLTranslate::parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage) +{ + Json::Value root; + Json::Reader reader; + BOOL parsingSuccessful = reader.parse(result, root ); + if ( !parsingSuccessful ) + { + LL_WARNS("JSON") << reader.getFormatedErrorMessages() << LL_ENDL; + return FALSE; + } + + translation = root[m_GoogleData].get(m_GoogleTranslation, "").asString(); + detectedLanguage = root[m_GoogleData].get(m_GoogleLanguage, "").asString(); + return TRUE; } //static std::string LLTranslate::getTranslateLanguage() { - std::string language = gSavedSettings.getString("TranslateLanguage"); - if (language.empty() || language == "default") + std::string language = "en"; + if (LLUI::sConfigGroup) { - language = LLUI::getLanguage(); + language = LLUI::sConfigGroup->getString("TranslateLanguage"); + if (language.empty() || language == "default") + { + language = LLUI::getLanguage(); + } } language = language.substr(0,2); return language; } -// static -bool LLTranslate::isTranslationConfigured() -{ - return getPreferredHandler().isConfigured(); -} - -// static -const LLTranslationAPIHandler& LLTranslate::getPreferredHandler() -{ - EService service = SERVICE_BING; - - std::string service_str = gSavedSettings.getString("TranslationService"); - if (service_str == "google") - { - service = SERVICE_GOOGLE; - } - - return getHandler(service); -} - -// static -const LLTranslationAPIHandler& LLTranslate::getHandler(EService service) -{ - static LLGoogleTranslationHandler google; - static LLBingTranslationHandler bing; - - if (service == SERVICE_GOOGLE) - { - return google; - } - - return bing; -} - -// static -void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder) -{ - static const float REQUEST_TIMEOUT = 5; - static LLSD sHeader; - - if (!sHeader.size()) - { - std::string user_agent = llformat("%s %d.%d.%d (%d)", - gVersionChannel, - gVersionMajor, - gVersionMinor, - gVersionPatch, - gVersionBuild); - - sHeader.insert("Accept", "text/plain"); - sHeader.insert("User-Agent", user_agent); - } - - LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT); -} diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index 870cc1fae..2723c43ff 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -2,27 +2,33 @@ * @file lltranslate.h * @brief Human language translation class and JSON response receiver. * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ #ifndef LL_LLTRANSLATE_H #define LL_LLTRANSLATE_H @@ -31,273 +37,89 @@ #include "llbufferstream.h" #include "jsoncpp/reader.h" -namespace Json -{ - class Value; -} - -/** - * Handler of an HTTP machine translation service. - * - * Derived classes know the service URL - * and how to parse the translation result. - */ -class LLTranslationAPIHandler -{ -public: - /** - * Get URL for translation of the given string. - * - * Sending HTTP GET request to the URL will initiate translation. - * - * @param[out] url Place holder for the result. - * @param from_lang Source language. Leave empty for auto-detection. - * @param to_lang Target language. - * @param text Text to translate. - */ - virtual void getTranslateURL( - std::string &url, - const std::string &from_lang, - const std::string &to_lang, - const std::string &text) const = 0; - - /** - * Get URL to verify the given API key. - * - * Sending request to the URL verifies the key. - * Positive HTTP response (code 200) means that the key is valid. - * - * @param[out] url Place holder for the URL. - * @param[in] key Key to verify. - */ - virtual void getKeyVerificationURL( - std::string &url, - const std::string &key) const = 0; - - /** - * Parse translation response. - * - * @param[in,out] status HTTP status. May be modified while parsing. - * @param body Response text. - * @param[out] translation Translated text. - * @param[out] detected_lang Detected source language. May be empty. - * @param[out] err_msg Error message (in case of error). - */ - virtual bool parseResponse( - int& status, - const std::string& body, - std::string& translation, - std::string& detected_lang, - std::string& err_msg) const = 0; - - /** - * @return if the handler is configured to function properly - */ - virtual bool isConfigured() const = 0; - - virtual ~LLTranslationAPIHandler() {} - -protected: - static const int STATUS_OK = 200; -}; - -/// Google Translate v2 API handler. -class LLGoogleTranslationHandler : public LLTranslationAPIHandler -{ - LOG_CLASS(LLGoogleTranslationHandler); - -public: - /*virtual*/ void getTranslateURL( - std::string &url, - const std::string &from_lang, - const std::string &to_lang, - const std::string &text) const; - /*virtual*/ void getKeyVerificationURL( - std::string &url, - const std::string &key) const; - /*virtual*/ bool parseResponse( - int& status, - const std::string& body, - std::string& translation, - std::string& detected_lang, - std::string& err_msg) const; - /*virtual*/ bool isConfigured() const; - -private: - static void parseErrorResponse( - const Json::Value& root, - int& status, - std::string& err_msg); - static bool parseTranslation( - const Json::Value& root, - std::string& translation, - std::string& detected_lang); - static std::string getAPIKey(); -}; - -/// Microsoft Translator v2 API handler. -class LLBingTranslationHandler : public LLTranslationAPIHandler -{ - LOG_CLASS(LLBingTranslationHandler); - -public: - /*virtual*/ void getTranslateURL( - std::string &url, - const std::string &from_lang, - const std::string &to_lang, - const std::string &text) const; - /*virtual*/ void getKeyVerificationURL( - std::string &url, - const std::string &key) const; - /*virtual*/ bool parseResponse( - int& status, - const std::string& body, - std::string& translation, - std::string& detected_lang, - std::string& err_msg) const; - /*virtual*/ bool isConfigured() const; -private: - static std::string getAPIKey(); -}; - -/** - * Entry point for machine translation services. - * - * Basically, to translate a string, we need to know the URL - * of a translation service, have a valid API for the service - * and be given the target language. - * - * Callers specify the string to translate and the target language, - * LLTranslate takes care of the rest. - * - * API keys for translation are taken from saved settings. - */ class LLTranslate { - LOG_CLASS(LLTranslate); - public : - - typedef enum e_service { - SERVICE_BING, - SERVICE_GOOGLE, - } EService; - - /** - * Subclasses are supposed to handle translation results (e.g. show them in chat) - */ class TranslationReceiver: public LLHTTPClient::Responder { - public: + protected: + TranslationReceiver(const std::string &fromLang, const std::string &toLang) + : m_fromLang(fromLang), + m_toLang(toLang) + { + } - /** - * Using mHandler, parse incoming response. - * - * Calls either handleResponse() or handleFailure() - * depending on the HTTP status code and parsing success. - * - * @see handleResponse() - * @see handleFailure() - * @see mHandler - */ - /*virtual*/ void completedRaw( - U32 http_status, + virtual void handleResponse(const std::string &translation, const std::string &recognizedLang) {} + virtual void handleFailure() {}; + + public: + ~TranslationReceiver() + { + } + + virtual void error(U32 status, const std::string& reason) + { + LL_WARNS("Translate") << "URL Request error: " << reason << LL_ENDL; + handleFailure(); + } + + virtual void completedRaw( + U32 status, const std::string& reason, const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + const LLIOPipe::buffer_ptr_t& buffer) + { + LLBufferStream istr(channels, buffer.get()); + + std::stringstream strstrm; + strstrm << istr.rdbuf(); + const std::string result = strstrm.str(); + + std::string translation; + std::string detectedLanguage; + + if (!parseGoogleTranslate(result, translation, detectedLanguage)) + { + handleFailure(); + return; + } + + // Fix up the response + stringReplaceAll( translation, "<","<"); + stringReplaceAll( translation, ">",">"); + stringReplaceAll( translation, ""","\""); + stringReplaceAll( translation, "'","'"); + stringReplaceAll( translation, "&","&"); + stringReplaceAll( translation, "'","'"); + + handleResponse(translation, detectedLanguage); + } protected: - friend class LLTranslate; - - /// Remember source and target languages for subclasses to be able to filter inappropriate results. - TranslationReceiver(const std::string& from_lang, const std::string& to_lang); - - /// Override point to handle successful translation. - virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0; - - /// Override point to handle unsuccessful translation. - virtual void handleFailure(int status, const std::string& err_msg) = 0; - - std::string mFromLang; - std::string mToLang; - const LLTranslationAPIHandler& mHandler; + const std::string m_toLang; + const std::string m_fromLang; }; - /** - * Subclasses are supposed to handle API key verification result. - */ - class KeyVerificationReceiver: public LLHTTPClient::Responder - { - public: - EService getService() const; - - protected: - /** - * Save the translation service the key belongs to. - * - * Subclasses need to know it. - * - * @see getService() - */ - KeyVerificationReceiver(EService service); - - /** - * Parse verification response. - * - * Calls setVerificationStatus() with the verification status, - * which is true if HTTP status code is 200. - * - * @see setVerificationStatus() - */ - /*virtual*/ void completedRaw( - U32 http_status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); - - /** - * Override point for subclasses to handle key verification status. - */ - virtual void setVerificationStatus(bool ok) = 0; - - EService mService; - }; - - typedef boost::intrusive_ptr TranslationReceiverPtr; - typedef boost::intrusive_ptr KeyVerificationReceiverPtr; - - /** - * Translate given text. - * - * @param receiver Object to pass translation result to. - * @param from_lang Source language. Leave empty for auto-detection. - * @param to_lang Target language. - * @param mesg Text to translate. - */ - static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg); - - /** - * Verify given API key of a translation service. - * - * @param receiver Object to pass verification result to. - * @param key Key to verify. - */ - static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key); - - /** - * @return translation target language - */ + static void translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg); + static float m_GoogleTimeout; static std::string getTranslateLanguage(); - /** - * @return true if translation is configured properly. - */ - static bool isTranslationConfigured(); - private: - static const LLTranslationAPIHandler& getPreferredHandler(); - static const LLTranslationAPIHandler& getHandler(EService service); - static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder); + static void getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &text); + static void stringReplaceAll(std::string& context, const std::string& from, const std::string& to); + static BOOL parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage); + + static LLSD m_Header; + static const char* m_GoogleURL; + static const char* m_GoogleLangSpec; + static const char* m_AcceptHeader; + static const char* m_AcceptType; + static const char* m_AgentHeader; + static const char* m_UserAgent; + + static const char* m_GoogleData; + static const char* m_GoogleTranslation; + static const char* m_GoogleLanguage; }; #endif diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index a060efd09..97ac3eb05 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2957,23 +2957,23 @@ void process_decline_callingcard(LLMessageSystem* msg, void**) class ChatTranslationReceiver : public LLTranslate::TranslationReceiver { public : - ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, LLChat *chat, + ChatTranslationReceiver(const std::string &fromLang, const std::string &toLang, LLChat *chat, const BOOL history) - : LLTranslate::TranslationReceiver(from_lang, to_lang), + : LLTranslate::TranslationReceiver(fromLang, toLang), m_chat(chat), m_history(history) { } - static boost::intrusive_ptr build(const std::string &from_lang, const std::string &to_lang, LLChat *chat, const BOOL history) + static boost::intrusive_ptr build(const std::string &fromLang, const std::string &toLang, LLChat *chat, const BOOL history) { - return boost::intrusive_ptr(new ChatTranslationReceiver(from_lang, to_lang, chat, history)); + return boost::intrusive_ptr(new ChatTranslationReceiver(fromLang, toLang, chat, history)); } protected: void handleResponse(const std::string &translation, const std::string &detectedLanguage) { - if (mToLang != detectedLanguage) + if (m_toLang != detectedLanguage) m_chat->mText += " (" + translation + ")"; add_floater_chat(*m_chat, m_history); @@ -2981,12 +2981,14 @@ protected: delete m_chat; } - void handleFailure(int status, const std::string& err_msg) + void handleFailure() { - llwarns << "Translation failed for mesg " << m_chat << " toLang " << mToLang << " fromLang " << mFromLang << llendl; + LLTranslate::TranslationReceiver::handleFailure(); m_chat->mText += " (?)"; + add_floater_chat(*m_chat, m_history); + delete m_chat; } @@ -3015,12 +3017,14 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist if (translate && chat.mSourceType != CHAT_SOURCE_SYSTEM) { - const std::string &from_lang = ""; - const std::string &to_lang = LLTranslate::getTranslateLanguage(); + // fromLang hardcoded to "" (autodetection) pending implementation of + // SVC-4879 + const std::string &fromLang = ""; + const std::string &toLang = LLTranslate::getTranslateLanguage(); LLChat *newChat = new LLChat(chat); - LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, newChat, history); - LLTranslate::translateMessage(result, from_lang, to_lang, mesg); + LLHTTPClient::ResponderPtr result = ChatTranslationReceiver::build(fromLang, toLang, newChat, history); + LLTranslate::translateMessage(result, fromLang, toLang, mesg); } else { From 803011582cb98435042cb534d44032977e33111c Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Tue, 21 Feb 2012 10:53:47 -0500 Subject: [PATCH 7/9] Further OS X changes. --- indra/cmake/Variables.cmake | 4 +-- indra/newview/CMakeLists.txt | 55 ++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 964c9d684..0428ae87d 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -78,15 +78,15 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") #SDK Compiler and Deployment targets for XCode if (${XCODE_VERSION} VERSION_LESS 4.0.0) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5) set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk) set(CMAKE_XCODE_ATTIBUTE_GCC_VERSION "4.2") else (${XCODE_VERSION} VERSION_LESS 4.0.0) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6) set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk) set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42") endif (${XCODE_VERSION} VERSION_LESS 4.0.0) - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5) - # NOTE: To attempt an i386/PPC Universal build, add this on the configure line: # -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc' # Build only for i386 by default, system default on MacOSX 10.6 is x86_64 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 66b5b4b3a..014a63461 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1338,39 +1338,40 @@ if (OPENAL) endif (OPENAL) if (FMOD OR FMODEX) - if(FMODEX) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") - endif(FMODEX) - if(FMOD) + if (FMODEX) + set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") + endif (FMODEX) + if (FMOD) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD") - endif(FMOD) + endif (FMOD) - if (NOT WINDOWS) + if (DARWIN) set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp) add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES}) - if(FMOD AND FMODEX) - set(fmodwrapper_needed_LIBRARIES "${FMODEX_LIBRARY} ${FMOD_LIBRARY}") - else(FMOD AND FMODEX) - if(FMODEX) - set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY}) - endif(FMODEX) - if(FMOD) - set(fmodwrapper_needed_LIBRARIES "${FMOD_LIBRARY}") - endif(FMOD) - endif(FMOD AND FMODEX) - if (DARWIN) - list(APPEND fmodwrapper_needed_LIBRARIES ${CARBON_LIBRARY}) - set_target_properties( - fmodwrapper - PROPERTIES - BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path/../Resources" - LINK_FLAGS "-unexported_symbols_list \"${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp\"" - ) - endif (DARWIN) + if (FMODEX) + set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY} ${CARBON_LIBRARY}) + endif (FMODEX) + if (FMOD) + set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY}) + endif (FMOD) + set_target_properties( + fmodwrapper + PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path/../Resources" + LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp" + ) set(FMODWRAPPER_LIBRARY fmodwrapper) target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES}) - endif (NOT WINDOWS) + else (DARWIN) + # fmodwrapper unnecessary on linux or windows, for fmod and fmodex + if (FMODEX) + set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) + endif (FMODEX) + if (FMOD) + set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY}) + endif (FMOD) + endif (DARWIN) endif (FMOD OR FMODEX) set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") From 3250725aaec50444a1ef85a956291b224bcd3d3e Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Tue, 21 Feb 2012 10:56:27 -0500 Subject: [PATCH 8/9] Annoying Crash Fix. This fixes that thing where saving scripts in deleted object makes viewer go FFFFFF. --- indra/newview/llpreviewscript.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 6682a6e8c..b4b8ef4d2 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -2301,6 +2301,13 @@ void LLLiveLSLEditor::saveIfNeeded() return; } +// [RLVa:KB] - Checked: 2010-11-25 (RLVa-1.2.2b) | Modified: RLVa-1.2.2b + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return; + } +// [/RLVa:KB] + // get the latest info about it. We used to be losing the script // name on save, because the viewer object version of the item, // and the editor version would get out of synch. Here's a good @@ -2607,14 +2614,6 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save) { LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; -// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a - const LLViewerObject* pObject = gObjectList.findObject(self->mObjectID); - if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(pObject->getRootEdit())) ) - { - return; - } -// [/RLVa:KB] - self->mCloseAfterSave = close_after_save; self->saveIfNeeded(); } From edbc22961e197bed9c0840b3527736e9fbd89960 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Wed, 22 Feb 2012 05:49:38 -0500 Subject: [PATCH 9/9] Revert "Further OS X changes." This reverts commit 803011582cb98435042cb534d44032977e33111c. --- indra/cmake/Variables.cmake | 4 +-- indra/newview/CMakeLists.txt | 55 ++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 0428ae87d..964c9d684 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -78,15 +78,15 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") #SDK Compiler and Deployment targets for XCode if (${XCODE_VERSION} VERSION_LESS 4.0.0) - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5) set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk) set(CMAKE_XCODE_ATTIBUTE_GCC_VERSION "4.2") else (${XCODE_VERSION} VERSION_LESS 4.0.0) - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6) set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk) set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42") endif (${XCODE_VERSION} VERSION_LESS 4.0.0) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5) + # NOTE: To attempt an i386/PPC Universal build, add this on the configure line: # -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc' # Build only for i386 by default, system default on MacOSX 10.6 is x86_64 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 014a63461..66b5b4b3a 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1338,40 +1338,39 @@ if (OPENAL) endif (OPENAL) if (FMOD OR FMODEX) - if (FMODEX) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") - endif (FMODEX) - if (FMOD) + if(FMODEX) + set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") + endif(FMODEX) + if(FMOD) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD") - endif (FMOD) + endif(FMOD) - if (DARWIN) + if (NOT WINDOWS) set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp) add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES}) - if (FMODEX) - set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY} ${CARBON_LIBRARY}) - endif (FMODEX) - if (FMOD) - set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY}) - endif (FMOD) - set_target_properties( - fmodwrapper - PROPERTIES - BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path/../Resources" - LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp" - ) + if(FMOD AND FMODEX) + set(fmodwrapper_needed_LIBRARIES "${FMODEX_LIBRARY} ${FMOD_LIBRARY}") + else(FMOD AND FMODEX) + if(FMODEX) + set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY}) + endif(FMODEX) + if(FMOD) + set(fmodwrapper_needed_LIBRARIES "${FMOD_LIBRARY}") + endif(FMOD) + endif(FMOD AND FMODEX) + if (DARWIN) + list(APPEND fmodwrapper_needed_LIBRARIES ${CARBON_LIBRARY}) + set_target_properties( + fmodwrapper + PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path/../Resources" + LINK_FLAGS "-unexported_symbols_list \"${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp\"" + ) + endif (DARWIN) set(FMODWRAPPER_LIBRARY fmodwrapper) target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES}) - else (DARWIN) - # fmodwrapper unnecessary on linux or windows, for fmod and fmodex - if (FMODEX) - set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) - endif (FMODEX) - if (FMOD) - set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY}) - endif (FMOD) - endif (DARWIN) + endif (NOT WINDOWS) endif (FMOD OR FMODEX) set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")