diff options
31 files changed, 552 insertions, 316 deletions
| diff --git a/doc/contributions.txt b/doc/contributions.txt index 5930bab04f..bcdc5a63d2 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -177,6 +177,8 @@ Ardy Lay  	VWR-24917  Argent Stonecutter  	VWR-68 +ArminWeatherHax +	STORM-1532  Armin Weatherwax  	VWR-8436  ArminasX Saiman @@ -568,6 +570,7 @@ Jonathan Yap  	STORM-1276  	STORM-1462  	STORM-1459 +	STORM-1297  	STORM-1522  	STORM-1567  	STORM-1572 diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index cc6bddc4da..60d4cfe6d3 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -322,6 +322,7 @@ if (LL_TESTS)    LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}"                            "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/setpython.py") +  LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}")                              LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}") diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index f576204511..5dc3ea5d7b 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -35,14 +35,15 @@  //static   void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)  { -	static std::map<std::string, void *> instances; +	typedef std::map<std::string, void *> InstancesMap; +	static InstancesMap instances; -	std::string k = info.name(); -	if(instances.find(k) == instances.end()) -	{ -		instances[k] = NULL; -	} - -	return instances[k]; +	// std::map::insert() is just what we want here. You attempt to insert a +	// (key, value) pair. If the specified key doesn't yet exist, it inserts +	// the pair and returns a std::pair of (iterator, true). If the specified +	// key DOES exist, insert() simply returns (iterator, false). One lookup +	// handles both cases. +	return instances.insert(InstancesMap::value_type(info.name(), +													 InstancesMap::mapped_type())) +		.first->second;  } - diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index afb714c71c..5a3990a8df 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -29,6 +29,7 @@  #define LL_LLINSTANCETRACKER_H  #include <map> +#include <typeinfo>  #include "string_table.h"  #include <boost/utility.hpp> @@ -37,10 +38,40 @@  #include <boost/iterator/transform_iterator.hpp>  #include <boost/iterator/indirect_iterator.hpp> +/** + * Base class manages "class-static" data that must actually have singleton + * semantics: one instance per process, rather than one instance per module as + * sometimes happens with data simply declared static. + */  class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable  { -	protected: -		static void * & getInstances(std::type_info const & info); +protected: +	/// Get a process-unique void* pointer slot for the specified type_info +	static void * & getInstances(std::type_info const & info); + +	/// Find or create a STATICDATA instance for the specified TRACKED class. +	/// STATICDATA must be default-constructible. +	template<typename STATICDATA, class TRACKED> +	static STATICDATA& getStatic() +	{ +		void *& instances = getInstances(typeid(TRACKED)); +		if (! instances) +		{ +			instances = new STATICDATA; +		} +		return *static_cast<STATICDATA*>(instances); +	} + +    /// It's not essential to derive your STATICDATA (for use with +    /// getStatic()) from StaticBase; it's just that both known +    /// implementations do. +    struct StaticBase +    { +        StaticBase(): +            sIterationNestDepth(0) +        {} +        S32 sIterationNestDepth; +    };  };  /// This mix-in class adds support for tracking all instances of the specified class parameter T @@ -50,8 +81,15 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable  template<typename T, typename KEY = T*>  class LLInstanceTracker : public LLInstanceTrackerBase  { -	typedef typename std::map<KEY, T*> InstanceMap;  	typedef LLInstanceTracker<T, KEY> MyT; +	typedef typename std::map<KEY, T*> InstanceMap; +	struct StaticData: public StaticBase +	{ +		InstanceMap sMap; +	}; +	static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } +	static InstanceMap& getMap_() { return getStatic().sMap; } +  public:  	class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>  	{ @@ -61,12 +99,12 @@ public:  		instance_iter(const typename InstanceMap::iterator& it)  		:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~instance_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		} @@ -95,18 +133,18 @@ public:  		key_iter(typename InstanceMap::iterator it)  			:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		key_iter(const key_iter& other)  			:	mIterator(other.mIterator)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~key_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		} @@ -159,8 +197,8 @@ protected:  	virtual ~LLInstanceTracker()   	{   		// it's unsafe to delete instances of this type while all instances are being iterated over. -		llassert(sIterationNestDepth == 0); -		remove_(); 		 +		llassert_always(getStatic().sIterationNestDepth == 0); +		remove_();		  	}  	virtual void setKey(KEY key) { remove_(); add_(key); }  	virtual const KEY& getKey() const { return mInstanceKey; } @@ -176,31 +214,24 @@ private:  		getMap_().erase(mInstanceKey);  	} -    static InstanceMap& getMap_() -    { -		void * & instances = getInstances(typeid(MyT)); -        if (! instances) -        { -            instances = new InstanceMap; -        } -        return * static_cast<InstanceMap*>(instances); -    } -  private: -  	KEY mInstanceKey; -	static S32 sIterationNestDepth;  }; -template <typename T, typename KEY> S32 LLInstanceTracker<T, KEY>::sIterationNestDepth = 0; -  /// explicit specialization for default case where KEY is T*  /// use a simple std::set<T*>  template<typename T>  class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase  { -	typedef typename std::set<T*> InstanceSet;  	typedef LLInstanceTracker<T, T*> MyT; +	typedef typename std::set<T*> InstanceSet; +	struct StaticData: public StaticBase +	{ +		InstanceSet sSet; +	}; +	static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } +	static InstanceSet& getSet_() { return getStatic().sSet; } +  public:  	/// for completeness of analogy with the generic implementation @@ -213,18 +244,18 @@ public:  		instance_iter(const typename InstanceSet::iterator& it)  		:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		instance_iter(const instance_iter& other)  		:	mIterator(other.mIterator)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~instance_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		}  	private: @@ -250,13 +281,13 @@ public:  protected:  	LLInstanceTracker()  	{ -		// it's safe but unpredictable to create instances of this type while all instances are being iterated over.  I hate unpredictable.  This assert will probably be turned on early in the next development cycle. +		// it's safe but unpredictable to create instances of this type while all instances are being iterated over.  I hate unpredictable.	 This assert will probably be turned on early in the next development cycle.  		getSet_().insert(static_cast<T*>(this));  	}  	virtual ~LLInstanceTracker()  	{  		// it's unsafe to delete instances of this type while all instances are being iterated over. -		llassert(sIterationNestDepth == 0); +		llassert_always(getStatic().sIterationNestDepth == 0);  		getSet_().erase(static_cast<T*>(this));  	} @@ -264,20 +295,6 @@ protected:  	{  		getSet_().insert(static_cast<T*>(this));  	} - -	static InstanceSet& getSet_() -	{ -		void * & instances = getInstances(typeid(MyT)); -		if (! instances) -		{ -			instances = new InstanceSet; -		} -		return * static_cast<InstanceSet *>(instances); -	} - -	static S32 sIterationNestDepth;  }; -template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0; -  #endif diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 00757be277..49d99f2cd0 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -114,8 +114,7 @@ private:  		~SingletonInstanceData()  		{ -			SingletonInstanceData& data = getData(); -			if (data.mInitState != DELETED) +			if (mInitState != DELETED)  			{  				deleteSingleton();  			} @@ -130,7 +129,26 @@ public:  		data.mInitState = DELETED;  	} -	// Can be used to control when the singleton is deleted.  Not normally needed. +	/** +	 * @brief Immediately delete the singleton. +	 * +	 * A subsequent call to LLProxy::getInstance() will construct a new +	 * instance of the class. +	 * +	 * LLSingletons are normally destroyed after main() has exited and the C++ +	 * runtime is cleaning up statically-constructed objects. Some classes +	 * derived from LLSingleton have objects that are part of a runtime system +	 * that is terminated before main() exits. Calling the destructor of those +	 * objects after the termination of their respective systems can cause +	 * crashes and other problems during termination of the project. Using this +	 * method to destroy the singleton early can prevent these crashes. +	 * +	 * An example where this is needed is for a LLSingleton that has an APR +	 * object as a member that makes APR calls on destruction. The APR system is +	 * shut down explicitly before main() exits. This causes a crash on exit. +	 * Using this method before the call to apr_terminate() and NOT calling +	 * getInstance() again will prevent the crash. +	 */  	static void deleteSingleton()  	{  		delete getData().mSingletonInstance; diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 80b35bbdc3..b34d1c5fd3 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -40,6 +40,7 @@  #include <boost/scoped_ptr.hpp>  // other Linden headers  #include "../test/lltut.h" +#include "wrapllerrs.h"  struct Keyed: public LLInstanceTracker<Keyed, std::string>  { @@ -165,4 +166,67 @@ namespace tut          ensure_equals("unreported instance", instances.size(), 0);      } + +    template<> template<> +    void object::test<5>() +    { +        set_test_name("delete Keyed with outstanding instance_iter"); +        std::string what; +        Keyed* keyed = new Keyed("one"); +        { +            WrapLL_ERRS wrapper; +            Keyed::instance_iter i(Keyed::beginInstances()); +            try +            { +                delete keyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    } + +    template<> template<> +    void object::test<6>() +    { +        set_test_name("delete Keyed with outstanding key_iter"); +        std::string what; +        Keyed* keyed = new Keyed("one"); +        { +            WrapLL_ERRS wrapper; +            Keyed::key_iter i(Keyed::beginKeys()); +            try +            { +                delete keyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    } + +    template<> template<> +    void object::test<7>() +    { +        set_test_name("delete Unkeyed with outstanding instance_iter"); +        std::string what; +        Unkeyed* unkeyed = new Unkeyed; +        { +            WrapLL_ERRS wrapper; +            Unkeyed::instance_iter i(Unkeyed::beginInstances()); +            try +            { +                delete unkeyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    }  } // namespace tut diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp new file mode 100644 index 0000000000..385289aefe --- /dev/null +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -0,0 +1,76 @@ +/**  + * @file llsingleton_test.cpp + * @date 2011-08-11 + * @brief Unit test for the LLSingleton class + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llsingleton.h" +#include "../test/lltut.h" + +namespace tut +{ +	struct singleton +	{ +		// We need a class created with the LLSingleton template to test with. +		class LLSingletonTest: public LLSingleton<LLSingletonTest> +		{ + +		}; +	}; + +	typedef test_group<singleton> singleton_t; +	typedef singleton_t::object singleton_object_t; +	tut::singleton_t tut_singleton("LLSingleton"); + +	template<> template<> +	void singleton_object_t::test<1>() +	{ + +	} +	template<> template<> +	void singleton_object_t::test<2>() +	{ +		LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); +		ensure(singleton_test); +	} +	template<> template<> +	void singleton_object_t::test<3>() +	{ +		//Construct the instance +		LLSingletonTest::getInstance(); +		ensure(LLSingletonTest::instanceExists()); + +		//Delete the instance +		LLSingletonTest::deleteSingleton(); +		ensure(LLSingletonTest::destroyed()); +		ensure(!LLSingletonTest::instanceExists()); + +		//Construct it again. +		LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); +		ensure(singleton_test); +		ensure(LLSingletonTest::instanceExists()); +	} +} diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index a3de178d78..14e169c6b1 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -499,7 +499,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	//don't verify host name so urls with scrubbed host names will work (improves DNS performance)  	setopt(CURLOPT_SSL_VERIFYHOST, 0); -	setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT); +	setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));  	setoptString(CURLOPT_URL, url); @@ -1213,3 +1213,13 @@ void LLCurl::cleanupClass()  }  const unsigned int LLCurl::MAX_REDIRECTS = 5; + +// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace. +void LLCurlFF::check_easy_code(CURLcode code) +{ +	check_curl_code(code); +} +void LLCurlFF::check_multi_code(CURLMcode code) +{ +	check_curl_multi_code(code); +} diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 5ab4dc35b9..213b281e72 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -371,7 +371,11 @@ private:  	bool mResultReturned;  }; -void check_curl_code(CURLcode code); -void check_curl_multi_code(CURLMcode code); +// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace. +namespace LLCurlFF +{ +	void check_easy_code(CURLcode code); +	void check_multi_code(CURLMcode code); +}  #endif // LL_LLCURL_H diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 7628984de4..fc6e9c5193 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -228,13 +228,13 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)  		if (LLProxy::isSOCKSProxyEnabled())  		{  			U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; -			packet_size = receive_packet(socket, reinterpret_cast<char *>(buffer)); +			packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer)));  			if (packet_size > SOCKS_HEADER_SIZE)  			{  				// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)  				memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE); -				proxywrap_t * header = reinterpret_cast<proxywrap_t *>(buffer); +				proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));  				mLastSender.setAddress(header->addr);  				mLastSender.setPort(ntohs(header->port)); @@ -353,14 +353,20 @@ BOOL LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 bu  		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());  	} -	proxywrap_t *socks_header = reinterpret_cast<proxywrap_t *>(&mProxyWrappedSendBuffer); +	char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; + +	proxywrap_t *socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer));  	socks_header->rsv   = 0;  	socks_header->addr  = host.getAddress();  	socks_header->port  = htons(host.getPort());  	socks_header->atype = ADDRESS_IPV4;  	socks_header->frag  = 0; -	memcpy(mProxyWrappedSendBuffer + SOCKS_HEADER_SIZE, send_buffer, buf_size); +	memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size); -	return send_packet(h_socket, (const char*) mProxyWrappedSendBuffer, buf_size + 10, LLProxy::getInstance()->getUDPProxy().getAddress(), LLProxy::getInstance()->getUDPProxy().getPort()); +	return send_packet(	h_socket, +						headered_send_buffer, +						buf_size + SOCKS_HEADER_SIZE, +						LLProxy::getInstance()->getUDPProxy().getAddress(), +						LLProxy::getInstance()->getUDPProxy().getPort());  } diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index 7edcc834db..b214271e78 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -83,9 +83,6 @@ protected:  	LLHost mLastSender;  	LLHost mLastReceivingIF; - -	U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; -  private:  	BOOL sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);  }; diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 19f1fc6545..4a7d326c0e 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -43,7 +43,7 @@  bool LLProxy::sUDPProxyEnabled = false;  // Some helpful TCP static functions. -static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake +static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake  static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host  static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel @@ -63,14 +63,13 @@ LLProxy::LLProxy():  LLProxy::~LLProxy()  {  	stopSOCKSProxy(); -	sUDPProxyEnabled  = false; -	mHTTPProxyEnabled = false; +	disableHTTPProxy();  }  /**   * @brief Open the SOCKS 5 TCP control channel.   * - * Perform a SOCKS 5 authentication and UDP association to the proxy server. + * Perform a SOCKS 5 authentication and UDP association with the proxy server.   *   * @param proxy The SOCKS 5 server to connect to.   * @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h. @@ -83,11 +82,15 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	socks_auth_request_t  socks_auth_request;  	socks_auth_response_t socks_auth_response; -	socks_auth_request.version     = SOCKS_VERSION;       // SOCKS version 5 -	socks_auth_request.num_methods = 1;                   // Sending 1 method. -	socks_auth_request.methods     = getSelectedAuthMethod(); // Send only the selected method. +	socks_auth_request.version		= SOCKS_VERSION;				// SOCKS version 5 +	socks_auth_request.num_methods	= 1;							// Sending 1 method. +	socks_auth_request.methods		= getSelectedAuthMethod();		// Send only the selected method. -	result = tcp_handshake(mProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request), (char*)&socks_auth_response, sizeof(socks_auth_response)); +	result = tcp_blocking_handshake(mProxyControlChannel, +									static_cast<char*>(static_cast<void*>(&socks_auth_request)), +									sizeof(socks_auth_request), +									static_cast<char*>(static_cast<void*>(&socks_auth_response)), +									sizeof(socks_auth_response));  	if (result != APR_SUCCESS)  	{  		LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL; @@ -97,12 +100,12 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)  	{ -		LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods" << LL_ENDL; +		LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods." << LL_ENDL;  		stopSOCKSProxy();  		return SOCKS_NOT_ACCEPTABLE;  	} -	// SOCKS 5 USERNAME/PASSWORD authentication +	/* SOCKS 5 USERNAME/PASSWORD authentication */  	if (socks_auth_response.method == METHOD_PASSWORD)  	{  		// The server has requested a username/password combination @@ -114,11 +117,15 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  		password_auth[1] = socks_username.size();  		memcpy(&password_auth[2], socks_username.c_str(), socks_username.size());  		password_auth[socks_username.size() + 2] = socks_password.size(); -		memcpy(&password_auth[socks_username.size()+3], socks_password.c_str(), socks_password.size()); +		memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size());  		authmethod_password_reply_t password_reply; -		result = tcp_handshake(mProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(password_reply)); +		result = tcp_blocking_handshake(mProxyControlChannel, +										password_auth, +										request_size, +										static_cast<char*>(static_cast<void*>(&password_reply)), +										sizeof(password_reply));  		delete[] password_auth;  		if (result != APR_SUCCESS) @@ -150,7 +157,11 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	// "If the client is not in possession of the information at the time of the UDP ASSOCIATE,  	//  the client MUST use a port number and address of all zeros. RFC 1928" -	result = tcp_handshake(mProxyControlChannel, (char*)&connect_request, sizeof(connect_request), (char*)&connect_reply, sizeof(connect_reply)); +	result = tcp_blocking_handshake(mProxyControlChannel, +									static_cast<char*>(static_cast<void*>(&connect_request)), +									sizeof(connect_request), +									static_cast<char*>(static_cast<void*>(&connect_reply)), +									sizeof(connect_reply));  	if (result != APR_SUCCESS)  	{  		LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL; @@ -169,6 +180,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	mUDPProxy.setAddress(proxy.getAddress());  	// The connection was successful. We now have the UDP port to send requests that need forwarding to.  	LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL; +  	return SOCKS_OK;  } @@ -176,7 +188,8 @@ S32 LLProxy::proxyHandshake(LLHost proxy)   * @brief Initiates a SOCKS 5 proxy session.   *   * Performs basic checks on host to verify that it is a valid address. Opens the control channel - * and then negotiates the proxy connection with the server. + * and then negotiates the proxy connection with the server. Closes any existing SOCKS + * connection before proceeding. Also disables an HTTP proxy if it is using SOCKS as the proxy.   *   *   * @param host Socks server to connect to. @@ -184,43 +197,37 @@ S32 LLProxy::proxyHandshake(LLHost proxy)   */  S32 LLProxy::startSOCKSProxy(LLHost host)  { -	S32 status = SOCKS_OK; -  	if (host.isOk())  	{  		mTCPProxy = host;  	}  	else  	{ -		status = SOCKS_INVALID_HOST; +		return SOCKS_INVALID_HOST;  	} -	if (mProxyControlChannel && status == SOCKS_OK) -	{ -		tcp_close_channel(&mProxyControlChannel); -	} +	// Close any running SOCKS connection. +	stopSOCKSProxy(); -	if (status == SOCKS_OK) +	mProxyControlChannel = tcp_open_channel(mTCPProxy); +	if (!mProxyControlChannel)  	{ -		mProxyControlChannel = tcp_open_channel(mTCPProxy); -		if (!mProxyControlChannel) -		{ -			status = SOCKS_HOST_CONNECT_FAILED; -		} +		return SOCKS_HOST_CONNECT_FAILED;  	} -	if (status == SOCKS_OK) -	{ -		status = proxyHandshake(mTCPProxy); -	} -	if (status == SOCKS_OK) +	S32 status = proxyHandshake(mTCPProxy); + +	if (status != SOCKS_OK)  	{ -		sUDPProxyEnabled = true; +		// Shut down the proxy if any of the above steps failed. +		stopSOCKSProxy();  	}  	else  	{ -		stopSOCKSProxy(); +		// Connection was successful. +		sUDPProxyEnabled = true;  	} +  	return status;  } @@ -241,7 +248,7 @@ void LLProxy::stopSOCKSProxy()  	if (LLPROXY_SOCKS == getHTTPProxyType())  	{ -		void disableHTTPProxy(); +		disableHTTPProxy();  	}  	if (mProxyControlChannel) @@ -350,16 +357,6 @@ void LLProxy::disableHTTPProxy()  }  /** - * @brief Get the HTTP proxy address and port - */ -// -LLHost LLProxy::getHTTPProxy() const -{ -	LLMutexLock lock(&mProxyMutex); -	return mHTTPProxy; -} - -/**   * @brief Get the currently selected HTTP proxy type   */  LLHttpProxyType LLProxy::getHTTPProxyType() const @@ -440,21 +437,21 @@ void LLProxy::applyProxySettings(CURL* handle)  		// Now test again to verify that the proxy wasn't disabled between the first check and the lock.  		if (mHTTPProxyEnabled)  		{ -			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str())); -			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort())); +			LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str())); +			LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));  			if (mProxyType == LLPROXY_SOCKS)  			{ -				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5)); +				LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));  				if (mAuthMethodSelected == METHOD_PASSWORD)  				{  					std::string auth_string = mSocksUsername + ":" + mSocksPassword; -					check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str())); +					LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));  				}  			}  			else  			{ -				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP)); +				LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));  			}  		}  	} @@ -473,7 +470,7 @@ void LLProxy::applyProxySettings(CURL* handle)   * @param maxinlen		Maximum possible length of received data.  Short reads are allowed.   * @return 				Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received.   */ -static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen) +static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen)  {  	apr_socket_t* apr_socket = handle->getSocket();  	apr_status_t rv = APR_SUCCESS; @@ -522,7 +519,6 @@ static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outl   *   * Checks for a successful connection, and makes sure the connection is closed if it fails.   * - * @param pool		APR pool to pass into the LLSocket.   * @param host		The host to open the connection to.   * @return			The created socket.  Will evaluate as NULL if the connection is unsuccessful.   */ @@ -541,7 +537,7 @@ static LLSocket::ptr_t tcp_open_channel(LLHost host)  /**   * @brief Close the socket.   * - * @param handle_ptr A pointer-to-pointer to avoid increasing the use count. + * @param handle_ptr The handle of the socket being closed. A pointer-to-pointer to avoid increasing the use count.   */  static void tcp_close_channel(LLSocket::ptr_t* handle_ptr)  { diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index 621debb61d..a919370540 100644 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -36,7 +36,6 @@  #include <string>  // SOCKS error codes returned from the StartProxy method -  #define SOCKS_OK 0  #define SOCKS_CONNECT_ERROR (-1)  #define SOCKS_NOT_PERMITTED (-2) @@ -46,7 +45,6 @@  #define SOCKS_HOST_CONNECT_FAILED (-6)  #define SOCKS_INVALID_HOST (-7) -  #ifndef MAXHOSTNAMELEN  #define	MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */  #endif @@ -225,62 +223,71 @@ class LLProxy: public LLSingleton<LLProxy>  {  	LOG_CLASS(LLProxy);  public: -	// METHODS THAT DO NOT LOCK mProxyMutex! - +	/*########################################################################################### +	METHODS THAT DO NOT LOCK mProxyMutex! +	###########################################################################################*/ +	// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.  	LLProxy(); -	// static check for enabled status for UDP packets +	// Static check for enabled status for UDP packets. Call from main thread only.  	static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; } -	// check for enabled status for HTTP packets -	// mHTTPProxyEnabled is atomic, so no locking is required for thread safety. -	bool isHTTPProxyEnabled() const { return mHTTPProxyEnabled; } - -	// Get the UDP proxy address and port +	// Get the UDP proxy address and port. Call from main thread only.  	LLHost getUDPProxy() const { return mUDPProxy; } -	// Get the SOCKS 5 TCP control channel address and port -	LLHost getTCPProxy() const { return mTCPProxy; } +	/*########################################################################################### +	END OF NON-LOCKING METHODS +	###########################################################################################*/ -	// END OF NON-LOCKING METHODS +	/*########################################################################################### +	METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	###########################################################################################*/ +	// Destructor, closes open connections. Do not call directly, use cleanupClass(). +	~LLProxy(); -	// METHODS THAT DO LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be +	// destroyed before the call to apr_terminate. Call from main thread only. +	static void cleanupClass(); -	~LLProxy(); +	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. +	// Safe to call from any thread. +	void applyProxySettings(CURL* handle); +	void applyProxySettings(LLCurl::Easy* handle); +	void applyProxySettings(LLCurlEasyRequest* handle); -	// Start a connection to the SOCKS 5 proxy +	// Start a connection to the SOCKS 5 proxy. Call from main thread only.  	S32 startSOCKSProxy(LLHost host); -	// Disconnect and clean up any connection to the SOCKS 5 proxy +	// Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only.  	void stopSOCKSProxy(); -	// Delete LLProxy singleton, destroying the APR pool used by the control channel. -	static void cleanupClass(); - -	// Set up to use Password auth when connecting to the SOCKS proxy +	// Use Password auth when connecting to the SOCKS proxy. Call from main thread only.  	bool setAuthPassword(const std::string &username, const std::string &password); -	// Set up to use No Auth when connecting to the SOCKS proxy +	// Disable authentication when connecting to the SOCKS proxy. Call from main thread only.  	void setAuthNone(); -	// Get the currently selected auth method. -	LLSocks5AuthType getSelectedAuthMethod() const; - -	// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy -	// as specified in type +	// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy. +	// as specified in type. Call from main thread only.  	bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);  	bool enableHTTPProxy(); -	// Stop proxying HTTP packets +	// Stop proxying HTTP packets. Call from main thread only.  	void disableHTTPProxy(); -	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. -	void applyProxySettings(CURL* handle); -	void applyProxySettings(LLCurl::Easy* handle); -	void applyProxySettings(LLCurlEasyRequest* handle); +	/*########################################################################################### +	END OF LOCKING METHODS +	###########################################################################################*/ +private: +	/*########################################################################################### +	METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	###########################################################################################*/ -	// Get the HTTP proxy address and port -	LLHost getHTTPProxy() const; +	// Perform a SOCKS 5 authentication and UDP association with the proxy server. +	S32 proxyHandshake(LLHost proxy); + +	// Get the currently selected auth method. +	LLSocks5AuthType getSelectedAuthMethod() const;  	// Get the currently selected HTTP proxy type  	LLHttpProxyType getHTTPProxyType() const; @@ -288,21 +295,21 @@ public:  	std::string getSocksPwd() const;  	std::string getSocksUser() const; -	// END OF LOCKING METHODS -private: -	// Open a communication channel to the SOCKS 5 proxy proxy, at port messagePort -	S32 proxyHandshake(LLHost proxy); +	/*########################################################################################### +	END OF LOCKING METHODS +	###########################################################################################*/  private: -	// Is the HTTP proxy enabled? -	// Safe to read in any thread, do not write directly, -	// use enableHTTPProxy() and disableHTTPProxy() instead. +	// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly. +	// Instead use enableHTTPProxy() and disableHTTPProxy() instead.  	mutable LLAtomic32<bool> mHTTPProxyEnabled; -	// Mutex to protect shared members in non-main thread calls to applyProxySettings() +	// Mutex to protect shared members in non-main thread calls to applyProxySettings().  	mutable LLMutex mProxyMutex; -	// MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! +	/*########################################################################################### +	MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! +	###########################################################################################*/  	// Is the UDP proxy enabled?  	static bool sUDPProxyEnabled; @@ -315,9 +322,13 @@ private:  	// socket handle to proxy TCP control channel  	LLSocket::ptr_t mProxyControlChannel; -	// END OF UNSHARED MEMBERS +	/*########################################################################################### +	END OF UNSHARED MEMBERS +	###########################################################################################*/ -	// MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! +	/*########################################################################################### +	MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! +	###########################################################################################*/  	// HTTP proxy address and port  	LLHost mHTTPProxy; @@ -325,7 +336,7 @@ private:  	// Currently selected HTTP proxy type. Can be web or socks.  	LLHttpProxyType mProxyType; -	// SOCKS 5 auth method selected +	// SOCKS 5 selected authentication method.  	LLSocks5AuthType mAuthMethodSelected;  	// SOCKS 5 username @@ -333,7 +344,9 @@ private:  	// SOCKS 5 password  	std::string mSocksPassword; -	// END OF SHARED MEMBERS +	/*########################################################################################### +	END OF SHARED MEMBERS +	###########################################################################################*/  };  #endif diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index b44b4c36b6..fe3f688fc5 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -223,6 +223,15 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)  	return FALSE;  } +BOOL LLScrollContainer::handleUnicodeCharHere(llwchar uni_char) +{ +	if (mScrolledView && mScrolledView->handleUnicodeCharHere(uni_char)) +	{ +		return TRUE; +	} +	return FALSE; +} +  BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )  {  	// Give event to my child views - they may have scroll bars diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index 46a71a7e30..3aa79cc255 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -103,6 +103,7 @@ public:  	// LLView functionality  	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);  	virtual BOOL	handleKeyHere(KEY key, MASK mask); +	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);  	virtual BOOL	handleScrollWheel( S32 x, S32 y, S32 clicks );  	virtual BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  								   EDragAndDropType cargo_type, diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7ab9f36b87..60025707a4 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1858,7 +1858,7 @@      <key>Type</key>      <string>Boolean</string>      <key>Value</key> -    <integer>0</integer> +    <integer>1</integer>    </map>      <key>Cursor3D</key>      <map> @@ -4059,7 +4059,7 @@        <key>Type</key>        <string>String</string>        <key>Value</key> -      <string>http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]</string> +      <string>http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD]</string>      </map>      <key>WebProfileURL</key>      <map> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 7e597fe5dc..4e1ef59765 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -786,6 +786,12 @@ bool LLAppViewer::init()  		&LLUI::sGLScaleFactor);  	LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; +	// Setup paths and LLTrans after LLUI::initClass has been called. +	LLUI::setupPaths(); +	LLTransUtil::parseStrings("strings.xml", default_trans_args); +	LLTransUtil::parseLanguageStrings("language_settings.xml"); + +	// Setup notifications after LLUI::setupPaths() has been called.  	LLNotifications::instance();  	LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; @@ -831,12 +837,6 @@ bool LLAppViewer::init()  		LLError::setPrintLocation(true);  	} - -	// Setup paths and LLTrans after LLUI::initClass has been called -	LLUI::setupPaths(); -	LLTransUtil::parseStrings("strings.xml", default_trans_args);		 -	LLTransUtil::parseLanguageStrings("language_settings.xml"); -	  	// LLKeyboard relies on LLUI to know what some accelerator keys are called.  	LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString ); diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 79e6c7b66b..c8cfe5b51e 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -201,7 +201,8 @@ public:  };  LLBottomTray::LLBottomTray(const LLSD&) -:	mChicletPanel(NULL), +:	mDesiredNearbyChatWidth(0), +	mChicletPanel(NULL),  	mSpeakPanel(NULL),  	mSpeakBtn(NULL),  	mNearbyChatBar(NULL), @@ -1095,33 +1096,35 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)  	if (still_should_be_processed)  	{  		processShrinkButtons(delta_width, buttons_freed_width); +		still_should_be_processed = delta_width < 0;  	} +  	// 3. Decreasing width of nearby chat.  	const S32 chatbar_panel_min_width = get_panel_min_width(mToolbarStack, mChatBarContainer);  	const S32 chatbar_panel_width = mChatBarContainer->getRect().getWidth();  	if (still_should_be_processed && chatbar_panel_width > chatbar_panel_min_width)  	{  		// we have some space to decrease chatbar panel -		S32 panel_delta_min = chatbar_panel_width - chatbar_panel_min_width; +		S32 chatbar_shrink_headroom = chatbar_panel_width - chatbar_panel_min_width; -		S32 delta_panel = llmin(-delta_width, panel_delta_min); +		S32 shrink_by = llmin(-delta_width, chatbar_shrink_headroom);  		// is chatbar panel wide enough to process resizing? -		delta_width += panel_delta_min; +		delta_width += chatbar_shrink_headroom;  		still_should_be_processed = delta_width < 0;  		// chatbar should only be shrunk here, not stretched -		if(delta_panel > 0) +		if (shrink_by > 0)  		{ -			lldebugs << "Shrinking nearby chat bar by " << delta_panel << " px " << llendl; -			mChatBarContainer->reshape(mNearbyChatBar->getRect().getWidth() - delta_panel, mChatBarContainer->getRect().getHeight()); +			lldebugs << "Shrinking nearby chat bar by " << shrink_by << " px " << llendl; +			mChatBarContainer->reshape(mNearbyChatBar->getRect().getWidth() - shrink_by, mChatBarContainer->getRect().getHeight());  		}  		log(mNearbyChatBar, "after processing panel decreasing via nearby chatbar panel");  		lldebugs << "RS_CHATBAR_INPUT" -			<< ", delta_panel: " << delta_panel +			<< ", shrink_by: " << shrink_by  			<< ", delta_width: " << delta_width  			<< llendl;  	} @@ -1200,16 +1203,16 @@ void LLBottomTray::processWidthIncreased(S32 delta_width)  		<< ", mDesiredNearbyChatWidth = " << mDesiredNearbyChatWidth << llendl;  	if (delta_width > 0 && chatbar_panel_width < mDesiredNearbyChatWidth)  	{ -		S32 delta_panel_max = mDesiredNearbyChatWidth - chatbar_panel_width; -		S32 delta_panel = llmin(delta_width, delta_panel_max); -		lldebugs << "Unprocesed delta width: " << delta_width -			<< ", can be applied to chatbar: " << delta_panel_max -			<< ", will be applied: " << delta_panel +		S32 extend_by_max = mDesiredNearbyChatWidth - chatbar_panel_width; +		S32 extend_by = llmin(delta_width, extend_by_max); +		lldebugs << "Unprocessed delta width: " << delta_width +			<< " px, chatbar can be extended by " << extend_by_max +			<< " px, extending it by " << extend_by << " px"  			<< llendl; -		delta_width -= delta_panel_max; -		lldebugs << "Extending nearby chat bar by " << delta_panel << " px " << llendl; -		mChatBarContainer->reshape(chatbar_panel_width + delta_panel, mChatBarContainer->getRect().getHeight()); +		delta_width -= extend_by_max; +		lldebugs << "Extending nearby chat bar by " << extend_by << " px " << llendl; +		mChatBarContainer->reshape(chatbar_panel_width + extend_by, mChatBarContainer->getRect().getHeight());  		log(mNearbyChatBar, "applied unprocessed delta width");  	} diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h index 62718531ef..e26b0792e9 100644 --- a/indra/newview/llbottomtray.h +++ b/indra/newview/llbottomtray.h @@ -323,7 +323,7 @@ private:  	void processExtendButtons(S32& available_width);  	/** -	 * Extends the Speak button if there is anough headroom. +	 * Extends the Speak button if there is enough headroom.  	 *  	 * Unlike other buttons, the Speak buttons has only two possible widths:  	 * the minimal one (without label) and the maximal (default) one. diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 23cc23376f..2a946b1edf 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -27,26 +27,16 @@  #include "llviewerprecompiledheaders.h" -#include "llappviewer.h" -#include "llbase64.h"  #include "llcommandhandler.h"  #include "llfloaterreg.h"  #include "llfloatersearch.h"  #include "llmediactrl.h"  #include "llnotificationsutil.h" -#include "llparcel.h" -#include "llplugincookiestore.h"  #include "lllogininstance.h"  #include "lluri.h"  #include "llagent.h" -#include "llsdserialize.h"  #include "llui.h"  #include "llviewercontrol.h" -#include "llviewerregion.h" -#include "llversioninfo.h" -#include "llviewermedia.h" -#include "llviewernetwork.h" -#include "llviewerparcelmgr.h"  #include "llweb.h"  // support secondlife:///app/search/{CATEGORY}/{QUERY} SLapps @@ -178,14 +168,12 @@ void LLFloaterSearch::search(const SearchQuery &p)  	// add the permissions token that login.cgi gave us  	// We use "search_token", and fallback to "auth_token" if not present. -	LLSD search_cookie; -  	LLSD search_token = LLLoginInstance::getInstance()->getResponse("search_token");  	if (search_token.asString().empty())  	{  		search_token = LLLoginInstance::getInstance()->getResponse("auth_token");  	} -	search_cookie["AUTH_TOKEN"] = search_token.asString(); +	subs["AUTH_TOKEN"] = search_token.asString();  	// add the user's preferred maturity (can be changed via prefs)  	std::string maturity; @@ -201,57 +189,10 @@ void LLFloaterSearch::search(const SearchQuery &p)  	{  		maturity = "13";  // PG  	} -	search_cookie["MATURITY"] = maturity; +	subs["MATURITY"] = maturity;  	// add the user's god status -	search_cookie["GODLIKE"] = gAgent.isGodlike() ? "1" : "0"; -	search_cookie["VERSION"] = LLVersionInfo::getVersion(); -	search_cookie["VERSION_MAJOR"] = LLVersionInfo::getMajor(); -	search_cookie["VERSION_MINOR"] = LLVersionInfo::getMinor(); -	search_cookie["VERSION_PATCH"] = LLVersionInfo::getPatch(); -	search_cookie["VERSION_BUILD"] = LLVersionInfo::getBuild(); -	search_cookie["CHANNEL"] = LLVersionInfo::getChannel(); -	search_cookie["GRID"] = LLGridManager::getInstance()->getGridLabel(); -	search_cookie["OS"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); -	search_cookie["SESSION_ID"] = gAgent.getSessionID(); -	search_cookie["FIRST_LOGIN"] = gAgent.isFirstLogin(); - -	std::string lang = LLUI::getLanguage(); -	if (lang == "en-us") -	{ -		lang = "en"; -	} -	search_cookie["LANGUAGE"] = lang; - -	// find the region ID -	LLUUID region_id; -	LLViewerRegion *region = gAgent.getRegion(); -	if (region) -	{ -		region_id = region->getRegionID(); -	} -	search_cookie["REGION_ID"] = region_id; - -	// find the parcel local ID -	S32 parcel_id = 0; -	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); -	if (parcel) -	{ -		parcel_id = parcel->getLocalID(); -	} -	search_cookie["PARCEL_ID"] = llformat("%d", parcel_id); - -	std::stringstream cookie_string_stream; -	LLSDSerialize::toXML(search_cookie, cookie_string_stream); -	std::string cookie_string = cookie_string_stream.str(); - -	U8* cookie_string_buffer = (U8*)cookie_string.c_str(); -	std::string cookie_value = LLBase64::encode(cookie_string_buffer, cookie_string.size()); - -	// for staging services -	LLViewerMedia::getCookieStore()->setCookiesFromHost(std::string("viewer_session_info=") + cookie_value, ".lindenlab.com"); -	// for live services -	LLViewerMedia::getCookieStore()->setCookiesFromHost(std::string("viewer_session_info=") + cookie_value, ".secondlife.com"); +	subs["GODLIKE"] = gAgent.isGodlike() ? "1" : "0";  	// get the search URL and expand all of the substitutions  	// (also adds things like [LANGUAGE], [VERSION], [OS], etc.) diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 8b72d83830..9ba5f827e2 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1723,7 +1723,7 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char)  	}  	BOOL handled = FALSE; -	if (gFocusMgr.childHasKeyboardFocus(getRoot())) +	if (mParentPanel->hasFocus())  	{  		// SL-51858: Key presses are not being passed to the Popup menu.  		// A proper fix is non-trivial so instead just close the menu. diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 2888f779f4..622dcfe8dd 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -282,9 +282,9 @@ void LLFolderViewItem::refreshFromListener()  		setToolTip(mLabel);  		setIcon(mListener->getIcon());  		time_t creation_date = mListener->getCreationDate(); -		if (mCreationDate != creation_date) +		if ((creation_date > 0) && (mCreationDate != creation_date))  		{ -			setCreationDate(mListener->getCreationDate()); +			setCreationDate(creation_date);  			dirtyFilter();  		}  		if (mRoot->useLabelSuffix()) diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 1576ccccdf..bc594b5517 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -579,6 +579,11 @@ void LLPanelGroupGeneral::update(LLGroupChange gc)  	} +	// After role member data was changed in Roles->Members +	// need to update role titles. See STORM-918. +	if (gc == GC_ROLE_MEMBER_DATA) +		LLGroupMgr::getInstance()->sendGroupTitlesRequest(mGroupID); +  	// If this was just a titles update, we are done.  	if (gc == GC_TITLES) return; diff --git a/indra/newview/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp index f525dbf434..faba6dc0cf 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.cpp +++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp @@ -192,10 +192,13 @@ void LLInboxFolderViewFolder::draw()  void LLInboxFolderViewFolder::computeFreshness()  { -	const U32 last_expansion = gSavedPerAccountSettings.getU32("LastInventoryInboxActivity"); +	const U32 last_expansion_utc = gSavedPerAccountSettings.getU32("LastInventoryInboxActivity"); -	if (last_expansion > 0) +	if (last_expansion_utc > 0)  	{ +		const U32 time_offset_for_pdt = 7 * 60 * 60; +		const U32 last_expansion = last_expansion_utc - time_offset_for_pdt; +  		mFresh = (mCreationDate > last_expansion);  #if DEBUGGING_FRESHNESS diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 68745d5aeb..6435904fee 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1299,29 +1299,12 @@ bool highlight_offered_object(const LLUUID& obj_id)  void inventory_offer_mute_callback(const LLUUID& blocked_id,  								   const std::string& full_name, -								   bool is_group, -								   boost::shared_ptr<LLNotificationResponderInterface> offer_ptr) +								   bool is_group)  { -	LLOfferInfo* offer =  dynamic_cast<LLOfferInfo*>(offer_ptr.get()); -	 -	std::string from_name = full_name; -	LLMute::EType type; -	if (is_group) -	{ -		type = LLMute::GROUP; -	} -	else if(offer && offer->mFromObject) -	{ -		//we have to block object by name because blocked_id is an id of owner -		type = LLMute::BY_NAME; -	} -	else -	{ -		type = LLMute::AGENT; -	} +	// *NOTE: blocks owner if the offer came from an object +	LLMute::EType mute_type = is_group ? LLMute::GROUP : LLMute::AGENT; -	// id should be null for BY_NAME mute, see  LLMuteList::add for details   -	LLMute mute(type == LLMute::BY_NAME ? LLUUID::null : blocked_id, from_name, type); +	LLMute mute(blocked_id, full_name, mute_type);  	if (LLMuteList::getInstance()->add(mute))  	{  		LLPanelBlockedList::showPanelAndSelect(blocked_id); @@ -1335,6 +1318,7 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id,  		bool matches(const LLNotificationPtr notification) const  		{  			if(notification->getName() == "ObjectGiveItem"  +				|| notification->getName() == "OwnObjectGiveItem"  				|| notification->getName() == "UserGiveItem")  			{  				return (notification->getPayload()["from_id"].asUUID() == blocked_id); @@ -1495,7 +1479,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&  		llassert(notification_ptr != NULL);  		if (notification_ptr != NULL)  		{ -			gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr())); +			gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback, _1, _2, _3));  		}  	} @@ -1640,7 +1624,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const  		llassert(notification_ptr != NULL);  		if (notification_ptr != NULL)  		{ -			gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr())); +			gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback, _1, _2, _3));  		}  	} @@ -1818,6 +1802,7 @@ void LLOfferInfo::initRespondFunctionMap()  	if(mRespondFunctions.empty())  	{  		mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); +		mRespondFunctions["OwnObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2);  		mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2);  	}  } @@ -1905,7 +1890,7 @@ void inventory_offer_handler(LLOfferInfo* info)  	std::string verb = "select?name=" + LLURI::escape(msg);  	args["ITEM_SLURL"] = LLSLURL("inventory", info->mObjectID, verb.c_str()).getSLURLString(); -	LLNotification::Params p("ObjectGiveItem"); +	LLNotification::Params p;  	// Object -> Agent Inventory Offer  	if (info->mFromObject) @@ -1915,7 +1900,10 @@ void inventory_offer_handler(LLOfferInfo* info)  		// Note: sets inventory_task_offer_callback as the callback  		p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));  		info->mPersist = true; -		p.name = "ObjectGiveItem"; + +		// Offers from your own objects need a special notification template. +		p.name = info->mFromID == gAgentID ? "OwnObjectGiveItem" : "ObjectGiveItem"; +  		// Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory.  	    LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, info->mFromGroup == TRUE);  	} @@ -2594,8 +2582,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  				bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0];  				info->mType = (LLAssetType::EType) bucketp->asset_type;  				info->mObjectID = bucketp->object_id; +				info->mFromObject = FALSE;  			} -			else +			else // IM_TASK_INVENTORY_OFFERED  			{  				if (sizeof(S8) != binary_bucket_size)  				{ @@ -2605,6 +2594,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  				}  				info->mType = (LLAssetType::EType) binary_bucket[0];  				info->mObjectID = LLUUID::null; +				info->mFromObject = TRUE;  			}  			info->mIM = dialog; @@ -2613,14 +2603,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  			info->mTransactionID = session_id;  			info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); -			if (dialog == IM_TASK_INVENTORY_OFFERED) -			{ -				info->mFromObject = TRUE; -			} -			else -			{ -				info->mFromObject = FALSE; -			}  			info->mFromName = name;  			info->mDesc = message;  			info->mHost = msg->getSender(); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 8b942fbc6a..90a05cd9e5 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -4498,17 +4498,25 @@ bool LLVivoxVoiceClient::parcelVoiceInfoReceived(state requesting_state)  bool LLVivoxVoiceClient::requestParcelVoiceInfo()  { -	LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL; - -	// grab the cap for parcel voice info from the region.    	LLViewerRegion * region = gAgent.getRegion(); -	if (region == NULL) +	if (region == NULL || !region->capabilitiesReceived())  	{ +		// we don't have the cap yet, so return false so the caller can try again later. + +		LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest capability not yet available, deferring" << LL_ENDL;  		return false;  	} +  	// grab the cap.  	std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest"); -	if (!url.empty()) +	if (url.empty()) +	{ +		// Region dosn't have the cap. Stop probing. +		LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest capability not available in this region" << LL_ENDL; +		setState(stateDisableCleanup); +		return false; +	} +	else   	{  		// if we've already retrieved the cap from the region, go ahead and make the request,  		// and return true so we can go into the state that waits for the response. @@ -4517,18 +4525,11 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo()  		LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;  		LLHTTPClient::post( -						   url, -						   data, -						   new LLVivoxVoiceClientCapResponder(getState())); +						url, +						data, +						new LLVivoxVoiceClientCapResponder(getState()));  		return true;  	} -	else  -	{ -		 -		// we don't have the cap yet, so return false so the caller can try again later. -		LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest cap not yet available, deferring" << LL_ENDL; -		return false; -	}  }  void LLVivoxVoiceClient::switchChannel( diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 9d42a40e85..41a90f5984 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5628,7 +5628,7 @@ You can be hurt here. If you die, you will be teleported to your home location.     persist="true"     type="notify">      <unique/> -    <tag>fail</tag> +   <tag>fail</tag>  This area has flying disabled.  You can't fly here.    </notification> @@ -5951,7 +5951,25 @@ An object named <nolink>[OBJECTFROMNAME]</nolink> owned by [NAME_SLU        <button         index="2"         name="Mute" -       text="Block"/> +       text="Block Owner"/> +    </form> +  </notification> + +  <notification +   icon="notify.tga" +   name="OwnObjectGiveItem" +   type="offer"> +Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you this [OBJECTTYPE]: +<nolink>[ITEM_SLURL]</nolink> +    <form name="form"> +      <button +       index="0" +       name="Keep" +       text="Keep"/> +      <button +       index="1" +       name="Discard" +       text="Discard"/>      </form>    </notification> @@ -5963,7 +5981,7 @@ An object named <nolink>[OBJECTFROMNAME]</nolink> owned by [NAME_SLU  [ITEM_SLURL]      <form name="form">        <button -       index="4" +       index="3"         name="Show"         text="Show"/>        <button @@ -7082,7 +7100,7 @@ Mute everyone?       notext="Cancel">        <unique/>      </usetemplate> -    </notification> +  </notification>    <notification    name="HintChat"    label="Chat" diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index c8f8d07701..ec5853649e 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -47,13 +47,13 @@           mouse_opaque="false"  		 name="chat_bar_layout_panel"           user_resize="true" -     width="310" > +     width="250" >            <panel              name="chat_bar"              filename="panel_nearby_chat_bar.xml"              left="0"              height="28" -        width="308" +        width="248"              top="0"              mouse_opaque="false"              follows="left|right" @@ -341,7 +341,7 @@ Disabled for now.           height="28"           layout="topleft"           min_height="28" -     min_width="52" +     min_width="62"           mouse_opaque="false"           name="mini_map_btn_panel"           user_resize="false" diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 0a21d8714c..f0bee2bfee 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -66,12 +66,14 @@ class ViewerManifest(LLManifest):                  # include the extracted list of contributors                  contributor_names = self.extract_names("../../doc/contributions.txt")                  self.put_in_file(contributor_names, "contributors.txt") +                self.file_list.append(["../../doc/contributions.txt",self.dst_path_of("contributors.txt")])                  # include the extracted list of translators                  translator_names = self.extract_names("../../doc/translations.txt")                  self.put_in_file(translator_names, "translators.txt") +                self.file_list.append(["../../doc/translations.txt",self.dst_path_of("translators.txt")])                  # include the list of Lindens (if any)                  #   see https://wiki.lindenlab.com/wiki/Generated_Linden_Credits -                linden_names_path = os.getenv("linden_credits") +                linden_names_path = os.getenv("LINDEN_CREDITS")                  if linden_names_path :                      try:                          linden_file = open(linden_names_path,'r') @@ -79,9 +81,13 @@ class ViewerManifest(LLManifest):                          linden_names = ', '.join(linden_file.readlines())                          self.put_in_file(linden_names, "lindens.txt")                          linden_file.close() +                        print "Linden names extracted from '%s'" % linden_names_path +                        self.file_list.append([linden_names_path,self.dst_path_of("lindens.txt")])                      except IOError:                          print "No Linden names found at '%s', using built-in list" % linden_names_path                          pass +                else : +                    print "No 'LINDEN_CREDITS' specified in environment, using built-in list"                  # ... and the entire windlight directory                  self.path("windlight") diff --git a/scripts/templates/template-cpp.cpp b/scripts/templates/template-cpp.cpp new file mode 100644 index 0000000000..35d8441c87 --- /dev/null +++ b/scripts/templates/template-cpp.cpp @@ -0,0 +1,30 @@ +/**  +* @file #filename#.cpp +* @brief Implementation of #filename# +* @author #getpass.getuser()#@lindenlab.com +* +* $LicenseInfo:firstyear=#datetime.datetime.now().year#&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) #datetime.datetime.now().year#, 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$ +*/ + + +#'' if ( skip_h ) else '%cinclude "%s.h"' % (35,filename)# + diff --git a/scripts/templates/template-h.h b/scripts/templates/template-h.h new file mode 100644 index 0000000000..ce7b4ddc87 --- /dev/null +++ b/scripts/templates/template-h.h @@ -0,0 +1,31 @@ +/**  +* @file   #filename#.h +* @brief  Header file for #filename# +* @author #getpass.getuser()#@lindenlab.com +* +* $LicenseInfo:firstyear=#datetime.datetime.now().year#&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) #datetime.datetime.now().year#, 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$ +*/ +#'%c'%35#ifndef LL_#filename.upper().replace('-','_')#_H +#'%c'%35#define LL_#filename.upper().replace('-','_')#_H + + +#'%c'%35#endif // LL_#filename.upper().replace('-','_')#_H | 
