diff options
| author | Rider Linden <none@none> | 2015-03-25 11:31:11 -0700 | 
|---|---|---|
| committer | Rider Linden <none@none> | 2015-03-25 11:31:11 -0700 | 
| commit | e140118fc41b79e403b299cabe1653af1971e87a (patch) | |
| tree | a67ab5d98aaec4e6be50ddf67c537a799fcc8d15 /indra | |
| parent | 3c46c6bcf2afcac5e0d6f435480cbee5c3136f63 (diff) | |
Replace appearance responder with new LLCore Appearance Handler.
Prep for some slight cleanup of the code.
Add AP_AVATAR Policy
Diffstat (limited to 'indra')
| -rwxr-xr-x | indra/llcorehttp/httpcommon.cpp | 4 | ||||
| -rwxr-xr-x | indra/llcorehttp/httpcommon.h | 13 | ||||
| -rw-r--r-- | indra/llmessage/llhttpsdhandler.cpp | 4 | ||||
| -rwxr-xr-x | indra/newview/llappcorehttp.cpp | 5 | ||||
| -rwxr-xr-x | indra/newview/llappcorehttp.h | 13 | ||||
| -rwxr-xr-x | indra/newview/llappearancemgr.cpp | 8282 | ||||
| -rwxr-xr-x | indra/newview/llappearancemgr.h | 20 | ||||
| -rwxr-xr-x | indra/newview/llmaterialmgr.cpp | 2 | ||||
| -rwxr-xr-x | indra/newview/llxmlrpctransaction.cpp | 8 | 
9 files changed, 4200 insertions, 4151 deletions
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index d923dfa5d6..99238ea920 100755 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -149,6 +149,10 @@ std::string HttpStatus::toString() const  	default:  		if (isHttpStatus())  		{ +			// special handling for status 499 "Linden Catchall" +			if ((getType() == 499) && (!getMessage().empty())) +				return getMessage(); +  			// Binary search for the error code and string  			int bottom(0), top(http_errors_count);  			while (true) diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h index e673d7b589..64075f5f20 100755 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -286,6 +286,8 @@ enum HttpError  /// 5.  Construct an HTTP 301 status code to be treated as success:  ///				HttpStatus(301, HE_SUCCESS);  /// +/// 6.	Construct a failed status of HTTP Status 499 with a custom error message +///				HttpStatus(499, "Failed LLSD Response");  struct HttpStatus  { @@ -307,6 +309,14 @@ struct HttpStatus  				(http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR);  			llassert(http_status >= 100 && http_status <= 999);  		} + +	HttpStatus(int http_status, const std::string &message) +		{ +			mDetails = new Details(http_status, +				(http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR); +			llassert(http_status >= 100 && http_status <= 999); +			mDetails->mMessage = message; +		}  	HttpStatus(const HttpStatus & rhs)  		{ @@ -420,9 +430,6 @@ struct HttpStatus  		return mDetails->mType;  	} -	// TODO: There must be a better way to do this.  Don't want to set these  -	// values here since they increase the size of a structure that is already  -	// being passed on the stack.  Consider my options  	/// Returns an optional error message if one has been set.  	///  	std::string getMessage() const diff --git a/indra/llmessage/llhttpsdhandler.cpp b/indra/llmessage/llhttpsdhandler.cpp index aa9801cebc..18daf443ee 100644 --- a/indra/llmessage/llhttpsdhandler.cpp +++ b/indra/llmessage/llhttpsdhandler.cpp @@ -76,7 +76,9 @@ void LLHttpSDHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons  		this->onSuccess(response, resplsd);  	} -	// The handler must destroy itself when it is done. +	// The handler must destroy itself when it is done.  +	// *TODO: I'm not fond of this pattern. A class shooting itself in the head  +	// outside of a smart pointer always makes me nervous.  	delete this;  } diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index 420d37369f..8da78a45a6 100755 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -102,6 +102,11 @@ static const struct  		2,		1,		8,		0,		false,  		"RenderMaterials",  		"material manager requests" +	}, +	{ // AP_AVATAR +		2,		1,		32,		0,		true, +		"Avatar", +		"Avatar requests"  	}  }; diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h index b636c3b43c..95b56100a6 100755 --- a/indra/newview/llappcorehttp.h +++ b/indra/newview/llappcorehttp.h @@ -175,7 +175,18 @@ public:  		/// Request rate:    low  		/// Pipelined:       no  		AP_MATERIALS, -		 + +		/// Appearance resource requests and puts.   +		/// +		/// Destination:     simhost:12043 +		/// Protocol:        https: +		/// Transfer size:   KB +		/// Long poll:       no +		/// Concurrency:     mid +		/// Request rate:    low +		/// Pipelined:       yes +		AP_AVATAR, +  		AP_COUNT						// Must be last  	}; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 9e8479eeef..077e944925 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1,4138 +1,4150 @@ -/**  - * @file llappearancemgr.cpp - * @brief Manager for initiating appearance changes on the viewer - * - * $LicenseInfo:firstyear=2004&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 <boost/lexical_cast.hpp> -#include "llaccordionctrltab.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "llattachmentsmgr.h" -#include "llcommandhandler.h" -#include "lleventtimer.h" -#include "llfloatersidepanelcontainer.h" -#include "llgesturemgr.h" -#include "llinventorybridge.h" -#include "llinventoryfunctions.h" -#include "llinventoryobserver.h" -#include "llnotificationsutil.h" -#include "lloutfitobserver.h" -#include "lloutfitslist.h" -#include "llselectmgr.h" -#include "llsidepanelappearance.h" -#include "llviewerobjectlist.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "llviewerregion.h" -#include "llwearablelist.h" -#include "llsdutil.h" -#include "llsdserialize.h" -#include "llhttpretrypolicy.h" -#include "llaisapi.h" - -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif - -std::string self_av_string() -{ -	// On logout gAgentAvatarp can already be invalid -	return isAgentAvatarValid() ? gAgentAvatarp->avString() : ""; -} - -// RAII thingy to guarantee that a variable gets reset when the Setter -// goes out of scope.  More general utility would be handy - TODO: -// check boost. -class BoolSetter -{ -public: -	BoolSetter(bool& var): -		mVar(var) -	{ -		mVar = true; -	} -	~BoolSetter() -	{ -		mVar = false;  -	} -private: -	bool& mVar; -}; - -char ORDER_NUMBER_SEPARATOR('@'); - -class LLOutfitUnLockTimer: public LLEventTimer -{ -public: -	LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) -	{ -		// restart timer on BOF changed event -		LLOutfitObserver::instance().addBOFChangedCallback(boost::bind( -				&LLOutfitUnLockTimer::reset, this)); -		stop(); -	} - -	/*virtual*/ -	BOOL tick() -	{ -		if(mEventTimer.hasExpired()) -		{ -			LLAppearanceMgr::instance().setOutfitLocked(false); -		} -		return FALSE; -	} -	void stop() { mEventTimer.stop(); } -	void start() { mEventTimer.start(); } -	void reset() { mEventTimer.reset(); } -	BOOL getStarted() { return mEventTimer.getStarted(); } - -	LLTimer&  getEventTimer() { return mEventTimer;} -}; - -// support for secondlife:///app/appearance SLapps -class LLAppearanceHandler : public LLCommandHandler -{ -public: -	// requests will be throttled from a non-trusted browser -	LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {} - -	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) -	{ -		// support secondlife:///app/appearance/show, but for now we just -		// make all secondlife:///app/appearance SLapps behave this way -		if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAppearance")) -		{ -			LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); -			return true; -		} - -		LLFloaterSidePanelContainer::showPanel("appearance", LLSD()); +/** 
 + * @file llappearancemgr.cpp
 + * @brief Manager for initiating appearance changes on the viewer
 + *
 + * $LicenseInfo:firstyear=2004&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 <boost/lexical_cast.hpp>
 +#include "llaccordionctrltab.h"
 +#include "llagent.h"
 +#include "llagentcamera.h"
 +#include "llagentwearables.h"
 +#include "llappearancemgr.h"
 +#include "llattachmentsmgr.h"
 +#include "llcommandhandler.h"
 +#include "lleventtimer.h"
 +#include "llfloatersidepanelcontainer.h"
 +#include "llgesturemgr.h"
 +#include "llinventorybridge.h"
 +#include "llinventoryfunctions.h"
 +#include "llinventoryobserver.h"
 +#include "llnotificationsutil.h"
 +#include "lloutfitobserver.h"
 +#include "lloutfitslist.h"
 +#include "llselectmgr.h"
 +#include "llsidepanelappearance.h"
 +#include "llviewerobjectlist.h"
 +#include "llvoavatar.h"
 +#include "llvoavatarself.h"
 +#include "llviewerregion.h"
 +#include "llwearablelist.h"
 +#include "llsdutil.h"
 +#include "llsdserialize.h"
 +#include "llhttpretrypolicy.h"
 +#include "llaisapi.h"
 +#include "llhttpsdhandler.h"
 +#include "llcorehttputil.h"
 +#include "llappviewer.h"
 +
 +#if LL_MSVC
 +// disable boost::lexical_cast warning
 +#pragma warning (disable:4702)
 +#endif
 +
 +std::string self_av_string()
 +{
 +	// On logout gAgentAvatarp can already be invalid
 +	return isAgentAvatarValid() ? gAgentAvatarp->avString() : "";
 +}
 +
 +// RAII thingy to guarantee that a variable gets reset when the Setter
 +// goes out of scope.  More general utility would be handy - TODO:
 +// check boost.
 +class BoolSetter
 +{
 +public:
 +	BoolSetter(bool& var):
 +		mVar(var)
 +	{
 +		mVar = true;
 +	}
 +	~BoolSetter()
 +	{
 +		mVar = false; 
 +	}
 +private:
 +	bool& mVar;
 +};
 +
 +char ORDER_NUMBER_SEPARATOR('@');
 +
 +class LLOutfitUnLockTimer: public LLEventTimer
 +{
 +public:
 +	LLOutfitUnLockTimer(F32 period) : LLEventTimer(period)
 +	{
 +		// restart timer on BOF changed event
 +		LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(
 +				&LLOutfitUnLockTimer::reset, this));
 +		stop();
 +	}
 +
 +	/*virtual*/
 +	BOOL tick()
 +	{
 +		if(mEventTimer.hasExpired())
 +		{
 +			LLAppearanceMgr::instance().setOutfitLocked(false);
 +		}
 +		return FALSE;
 +	}
 +	void stop() { mEventTimer.stop(); }
 +	void start() { mEventTimer.start(); }
 +	void reset() { mEventTimer.reset(); }
 +	BOOL getStarted() { return mEventTimer.getStarted(); }
 +
 +	LLTimer&  getEventTimer() { return mEventTimer;}
 +};
 +
 +// support for secondlife:///app/appearance SLapps
 +class LLAppearanceHandler : public LLCommandHandler
 +{
 +public:
 +	// requests will be throttled from a non-trusted browser
 +	LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {}
 +
 +	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
 +	{
 +		// support secondlife:///app/appearance/show, but for now we just
 +		// make all secondlife:///app/appearance SLapps behave this way
 +		if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAppearance"))
 +		{
 +			LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
 +			return true;
 +		}
 +
 +		LLFloaterSidePanelContainer::showPanel("appearance", LLSD());
 +		return true;
 +	}
 +};
 +
 +LLAppearanceHandler gAppearanceHandler;
 +
 +
 +LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name)
 +{
 +	LLInventoryModel::cat_array_t cat_array;
 +	LLInventoryModel::item_array_t item_array;
 +	LLNameCategoryCollector has_name(name);
 +	gInventory.collectDescendentsIf(parent_id,
 +									cat_array,
 +									item_array,
 +									LLInventoryModel::EXCLUDE_TRASH,
 +									has_name);
 +	if (0 == cat_array.size())
 +		return LLUUID();
 +	else
 +	{
 +		LLViewerInventoryCategory *cat = cat_array.at(0);
 +		if (cat)
 +			return cat->getUUID();
 +		else
 +		{
 +			LL_WARNS() << "null cat" << LL_ENDL;
 +			return LLUUID();
 +		}
 +	}
 +}
 +
 +// We want this to be much lower (e.g. 15.0 is usually fine), bumping
 +// up for now until we can diagnose some cases of very slow response
 +// to requests.
 +const F32 DEFAULT_RETRY_AFTER_INTERVAL = 300.0;
 +
 +// Given the current back-end problems, retrying is causing too many
 +// duplicate items. Bump this back to 2 once they are resolved (or can
 +// leave at 0 if the operations become actually reliable).
 +const S32 DEFAULT_MAX_RETRIES = 0;
 +
 +class LLCallAfterInventoryBatchMgr: public LLEventTimer 
 +{
 +public:
 +	LLCallAfterInventoryBatchMgr(const LLUUID& dst_cat_id,
 +								 const std::string& phase_name,
 +								 nullary_func_t on_completion_func,
 +								 nullary_func_t on_failure_func = no_op,
 +								 F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL,
 +								 S32 max_retries = DEFAULT_MAX_RETRIES
 +		):
 +		mDstCatID(dst_cat_id),
 +		mTrackingPhase(phase_name),
 +		mOnCompletionFunc(on_completion_func),
 +		mOnFailureFunc(on_failure_func),
 +		mRetryAfter(retry_after),
 +		mMaxRetries(max_retries),
 +		mPendingRequests(0),
 +		mFailCount(0),
 +		mCompletionOrFailureCalled(false),
 +		mRetryCount(0),
 +		LLEventTimer(5.0)
 +	{
 +		if (!mTrackingPhase.empty())
 +		{
 +			selfStartPhase(mTrackingPhase);
 +		}
 +	}
 +
 +	void addItems(LLInventoryModel::item_array_t& src_items)
 +	{
 +		for (LLInventoryModel::item_array_t::const_iterator it = src_items.begin();
 +			 it != src_items.end();
 +			 ++it)
 +		{
 +			LLViewerInventoryItem* item = *it;
 +			llassert(item);
 +			addItem(item->getUUID());
 +		}
 +	}
 +
 +	// Request or re-request operation for specified item.
 +	void addItem(const LLUUID& item_id)
 +	{
 +		LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL;
 +		if (!requestOperation(item_id))
 +		{
 +			LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL;
 +			return;
 +		}
 +
 +		mPendingRequests++;
 +		// On a re-request, this will reset the timer.
 +		mWaitTimes[item_id] = LLTimer();
 +		if (mRetryCounts.find(item_id) == mRetryCounts.end())
 +		{
 +			mRetryCounts[item_id] = 0;
 +		}
 +		else
 +		{
 +			mRetryCounts[item_id]++;
 +		}
 +	}
 +
 +	virtual bool requestOperation(const LLUUID& item_id) = 0;
 +
 +	void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp)
 +	{
 +		if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate"))
 +		{
 +			LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL;
 +			doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp),
 +							mRetryAfter);
 +			return;
 +		}
 +		mPendingRequests--;
 +		F32 elapsed = timestamp.getElapsedTimeF32();
 +		LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << LL_ENDL;
 +		if (mWaitTimes.find(src_id) == mWaitTimes.end())
 +		{
 +			// No longer waiting for this item - either serviced
 +			// already or gave up after too many retries.
 +			LL_WARNS() << "duplicate or late operation, src_id " << src_id << "dst_id " << dst_id
 +					<< " elapsed " << elapsed << " after end " << (S32) mCompletionOrFailureCalled << LL_ENDL;
 +		}
 +		mTimeStats.push(elapsed);
 +		mWaitTimes.erase(src_id);
 +		if (mWaitTimes.empty() && !mCompletionOrFailureCalled)
 +		{
 +			onCompletionOrFailure();
 +		}
 +	}
 +
 +	void onCompletionOrFailure()
 +	{
 +		assert (!mCompletionOrFailureCalled);
 +		mCompletionOrFailureCalled = true;
 +		
 +		// Will never call onCompletion() if any item has been flagged as
 +		// a failure - otherwise could wind up with corrupted
 +		// outfit, involuntary nudity, etc.
 +		reportStats();
 +		if (!mTrackingPhase.empty())
 +		{
 +			selfStopPhase(mTrackingPhase);
 +		}
 +		if (!mFailCount)
 +		{
 +			onCompletion();
 +		}
 +		else
 +		{
 +			onFailure();
 +		}
 +	}
 +
 +	void onFailure()
 +	{
 +		LL_INFOS() << "failed" << LL_ENDL;
 +		mOnFailureFunc();
 +	}
 +
 +	void onCompletion()
 +	{
 +		LL_INFOS() << "done" << LL_ENDL;
 +		mOnCompletionFunc();
 +	}
 +	
 +	// virtual
 +	// Will be deleted after returning true - only safe to do this if all callbacks have fired.
 +	BOOL tick()
 +	{
 +		// mPendingRequests will be zero if all requests have been
 +		// responded to.  mWaitTimes.empty() will be true if we have
 +		// received at least one reply for each UUID.  If requests
 +		// have been dropped and retried, these will not necessarily
 +		// be the same.  Only safe to return true if all requests have
 +		// been serviced, since it will result in this object being
 +		// deleted.
 +		bool all_done = (mPendingRequests==0);
 +
 +		if (!mWaitTimes.empty())
 +		{
 +			LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL;
 +			for (std::map<LLUUID,LLTimer>::iterator it = mWaitTimes.begin();
 +				 it != mWaitTimes.end();)
 +			{
 +				// Use a copy of iterator because it may be erased/invalidated.
 +				std::map<LLUUID,LLTimer>::iterator curr_it = it;
 +				++it;
 +				
 +				F32 time_waited = curr_it->second.getElapsedTimeF32();
 +				S32 retries = mRetryCounts[curr_it->first];
 +				if (time_waited > mRetryAfter)
 +				{
 +					if (retries < mMaxRetries)
 +					{
 +						LL_DEBUGS("Avatar") << "Waited " << time_waited <<
 +							" for " << curr_it->first << ", retrying" << LL_ENDL;
 +						mRetryCount++;
 +						addItem(curr_it->first);
 +					}
 +					else
 +					{
 +						LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL;
 +						mWaitTimes.erase(curr_it);
 +						mFailCount++;
 +					}
 +				}
 +				if (mWaitTimes.empty())
 +				{
 +					onCompletionOrFailure();
 +				}
 +
 +			}
 +		}
 +		return all_done;
 +	}
 +
 +	void reportStats()
 +	{
 +		LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << LL_ENDL;
 +		LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << LL_ENDL;
 +		LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << LL_ENDL;
 +		LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL;
 +		LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL;
 +	}
 +	
 +	virtual ~LLCallAfterInventoryBatchMgr()
 +	{
 +		LL_DEBUGS("Avatar") << "deleting" << LL_ENDL;
 +	}
 +
 +protected:
 +	std::string mTrackingPhase;
 +	std::map<LLUUID,LLTimer> mWaitTimes;
 +	std::map<LLUUID,S32> mRetryCounts;
 +	LLUUID mDstCatID;
 +	nullary_func_t mOnCompletionFunc;
 +	nullary_func_t mOnFailureFunc;
 +	F32 mRetryAfter;
 +	S32 mMaxRetries;
 +	S32 mPendingRequests;
 +	S32 mFailCount;
 +	S32 mRetryCount;
 +	bool mCompletionOrFailureCalled;
 +	LLViewerStats::StatsAccumulator mTimeStats;
 +};
 +
 +class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr
 +{
 +public:
 +	LLCallAfterInventoryCopyMgr(LLInventoryModel::item_array_t& src_items,
 +								const LLUUID& dst_cat_id,
 +								const std::string& phase_name,
 +								nullary_func_t on_completion_func,
 +								nullary_func_t on_failure_func = no_op,
 +								 F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL,
 +								 S32 max_retries = DEFAULT_MAX_RETRIES
 +		):
 +		LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries)
 +	{
 +		addItems(src_items);
 +		sInstanceCount++;
 +	}
 +
 +	~LLCallAfterInventoryCopyMgr()
 +	{
 +		sInstanceCount--;
 +	}
 +	
 +	virtual bool requestOperation(const LLUUID& item_id)
 +	{
 +		LLViewerInventoryItem *item = gInventory.getItem(item_id);
 +		llassert(item);
 +		LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL;
 +		if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
 +		{
 +			LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL;
 +			return true;
 +		}
 +		copy_inventory_item(
 +			gAgent.getID(),
 +			item->getPermissions().getOwner(),
 +			item->getUUID(),
 +			mDstCatID,
 +			std::string(),
 +			new LLBoostFuncInventoryCallback(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))
 +			);
 +		return true;
 +	}
 +
 +	static S32 getInstanceCount() { return sInstanceCount; }
 +	
 +private:
 +	static S32 sInstanceCount;
 +};
 +
 +S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0;
 +
 +class LLWearCategoryAfterCopy: public LLInventoryCallback
 +{
 +public:
 +	LLWearCategoryAfterCopy(bool append):
 +		mAppend(append)
 +	{}
 +
 +	// virtual
 +	void fire(const LLUUID& id)
 +	{
 +		// Wear the inventory category.
 +		LLInventoryCategory* cat = gInventory.getCategory(id);
 +		LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend);
 +	}
 +
 +private:
 +	bool mAppend;
 +};
 +
 +class LLTrackPhaseWrapper : public LLInventoryCallback
 +{
 +public:
 +	LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL):
 +		mTrackingPhase(phase_name),
 +		mCB(cb)
 +	{
 +		selfStartPhase(mTrackingPhase);
 +	}
 +
 +	// virtual
 +	void fire(const LLUUID& id)
 +	{
 +		if (mCB)
 +		{
 +			mCB->fire(id);
 +		}
 +	}
 +
 +	// virtual
 +	~LLTrackPhaseWrapper()
 +	{
 +		selfStopPhase(mTrackingPhase);
 +	}
 +
 +protected:
 +	std::string mTrackingPhase;
 +	LLPointer<LLInventoryCallback> mCB;
 +};
 +
 +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions,
 +														 bool enforce_ordering,
 +														 nullary_func_t post_update_func 
 +	):
 +	mFireCount(0),
 +	mEnforceItemRestrictions(enforce_item_restrictions),
 +	mEnforceOrdering(enforce_ordering),
 +	mPostUpdateFunc(post_update_func)
 +{
 +	selfStartPhase("update_appearance_on_destroy");
 +}
 +
 +void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item)
 +{
 +	LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item);
 +	const std::string item_name = item ? item->getName() : "ITEM NOT FOUND";
 +#ifndef LL_RELEASE_FOR_DOWNLOAD
 +	LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL;
 +#endif
 +	mFireCount++;
 +}
 +
 +LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
 +{
 +	if (!LLApp::isExiting())
 +	{
 +		// speculative fix for MAINT-1150
 +		LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL;
 +
 +		selfStopPhase("update_appearance_on_destroy");
 +
 +		LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions,
 +															mEnforceOrdering,
 +															mPostUpdateFunc);
 +	}
 +}
 +
 +LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id):
 +	mItemID(item_id)
 +{
 +}
 +
 +void edit_wearable_and_customize_avatar(LLUUID item_id)
 +{
 +	// Start editing the item if previously requested.
 +	gAgentWearables.editWearableIfRequested(item_id);
 +	
 +	// TODO: camera mode may not be changed if a debug setting is tweaked
 +	if( gAgentCamera.cameraCustomizeAvatar() )
 +	{
 +		// If we're in appearance editing mode, the current tab may need to be refreshed
 +		LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(
 +			LLFloaterSidePanelContainer::getPanel("appearance"));
 +		if (panel)
 +		{
 +			panel->showDefaultSubpart();
 +		}
 +	}
 +}
 +
 +LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy()
 +{
 +	if (!LLApp::isExiting())
 +	{
 +		LLAppearanceMgr::instance().updateAppearanceFromCOF(
 +			true,true,
 +			boost::bind(edit_wearable_and_customize_avatar, mItemID));
 +	}
 +}
 +
 +
 +struct LLFoundData
 +{
 +	LLFoundData() :
 +		mAssetType(LLAssetType::AT_NONE),
 +		mWearableType(LLWearableType::WT_INVALID),
 +		mWearable(NULL) {}
 +
 +	LLFoundData(const LLUUID& item_id,
 +				const LLUUID& asset_id,
 +				const std::string& name,
 +				const LLAssetType::EType& asset_type,
 +				const LLWearableType::EType& wearable_type,
 +				const bool is_replacement = false
 +		) :
 +		mItemID(item_id),
 +		mAssetID(asset_id),
 +		mName(name),
 +		mAssetType(asset_type),
 +		mWearableType(wearable_type),
 +		mIsReplacement(is_replacement),
 +		mWearable( NULL ) {}
 +	
 +	LLUUID mItemID;
 +	LLUUID mAssetID;
 +	std::string mName;
 +	LLAssetType::EType mAssetType;
 +	LLWearableType::EType mWearableType;
 +	LLViewerWearable* mWearable;
 +	bool mIsReplacement;
 +};
 +
 +	
 +class LLWearableHoldingPattern
 +{
 +	LOG_CLASS(LLWearableHoldingPattern);
 +
 +public:
 +	LLWearableHoldingPattern();
 +	~LLWearableHoldingPattern();
 +
 +	bool pollFetchCompletion();
 +	void onFetchCompletion();
 +	bool isFetchCompleted();
 +	bool isTimedOut();
 +
 +	void checkMissingWearables();
 +	bool pollMissingWearables();
 +	bool isMissingCompleted();
 +	void recoverMissingWearable(LLWearableType::EType type);
 +	void clearCOFLinksForMissingWearables();
 +	
 +	void onWearableAssetFetch(LLViewerWearable *wearable);
 +	void onAllComplete();
 +
 +	typedef std::list<LLFoundData> found_list_t;
 +	found_list_t& getFoundList();
 +	void eraseTypeToLink(LLWearableType::EType type);
 +	void eraseTypeToRecover(LLWearableType::EType type);
 +	void setObjItems(const LLInventoryModel::item_array_t& items);
 +	void setGestItems(const LLInventoryModel::item_array_t& items);
 +	bool isMostRecent();
 +	void handleLateArrivals();
 +	void resetTime(F32 timeout);
 +	static S32 countActive() { return sActiveHoldingPatterns.size(); }
 +	S32 index() { return mIndex; }
 +	
 +private:
 +	found_list_t mFoundList;
 +	LLInventoryModel::item_array_t mObjItems;
 +	LLInventoryModel::item_array_t mGestItems;
 +	typedef std::set<S32> type_set_t;
 +	type_set_t mTypesToRecover;
 +	type_set_t mTypesToLink;
 +	S32 mResolved;
 +	LLTimer mWaitTime;
 +	bool mFired;
 +	typedef std::set<LLWearableHoldingPattern*> type_set_hp;
 +	static type_set_hp sActiveHoldingPatterns;
 +	static S32 sNextIndex;
 +	S32 mIndex;
 +	bool mIsMostRecent;
 +	std::set<LLViewerWearable*> mLateArrivals;
 +	bool mIsAllComplete;
 +};
 +
 +LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns;
 +S32 LLWearableHoldingPattern::sNextIndex = 0;
 +
 +LLWearableHoldingPattern::LLWearableHoldingPattern():
 +	mResolved(0),
 +	mFired(false),
 +	mIsMostRecent(true),
 +	mIsAllComplete(false)
 +{
 +	if (countActive()>0)
 +	{
 +		LL_INFOS() << "Creating LLWearableHoldingPattern when "
 +				   << countActive()
 +				   << " other attempts are active."
 +				   << " Flagging others as invalid."
 +				   << LL_ENDL;
 +		for (type_set_hp::iterator it = sActiveHoldingPatterns.begin();
 +			 it != sActiveHoldingPatterns.end();
 +			 ++it)
 +		{
 +			(*it)->mIsMostRecent = false;
 +		}
 +			 
 +	}
 +	mIndex = sNextIndex++;
 +	sActiveHoldingPatterns.insert(this);
 +	LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL;
 +	selfStartPhase("holding_pattern");
 +}
 +
 +LLWearableHoldingPattern::~LLWearableHoldingPattern()
 +{
 +	sActiveHoldingPatterns.erase(this);
 +	if (isMostRecent())
 +	{
 +		selfStopPhase("holding_pattern");
 +	}
 +	LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL;
 +}
 +
 +bool LLWearableHoldingPattern::isMostRecent()
 +{
 +	return mIsMostRecent;
 +}
 +
 +LLWearableHoldingPattern::found_list_t& LLWearableHoldingPattern::getFoundList()
 +{
 +	return mFoundList;
 +}
 +
 +void LLWearableHoldingPattern::eraseTypeToLink(LLWearableType::EType type)
 +{
 +	mTypesToLink.erase(type);
 +}
 +
 +void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type)
 +{
 +	mTypesToRecover.erase(type);
 +}
 +
 +void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items)
 +{
 +	mObjItems = items;
 +}
 +
 +void LLWearableHoldingPattern::setGestItems(const LLInventoryModel::item_array_t& items)
 +{
 +	mGestItems = items;
 +}
 +
 +bool LLWearableHoldingPattern::isFetchCompleted()
 +{
 +	return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for?
 +}
 +
 +bool LLWearableHoldingPattern::isTimedOut()
 +{
 +	return mWaitTime.hasExpired();
 +}
 +
 +void LLWearableHoldingPattern::checkMissingWearables()
 +{
 +	if (!isMostRecent())
 +	{
 +		// runway why don't we actually skip here?
 +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +	}
 +
 +	std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0);
 +	std::vector<S32> requested_by_type(LLWearableType::WT_COUNT,0);
 +	for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it)
 +	{
 +		LLFoundData &data = *it;
 +		if (data.mWearableType < LLWearableType::WT_COUNT)
 +			requested_by_type[data.mWearableType]++;
 +		if (data.mWearable)
 +			found_by_type[data.mWearableType]++;
 +	}
 +
 +	for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type)
 +	{
 +		if (requested_by_type[type] > found_by_type[type])
 +		{
 +			LL_WARNS() << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << LL_ENDL;
 +		}
 +		if (found_by_type[type] > 0)
 +			continue;
 +		if (
 +			// If at least one wearable of certain types (pants/shirt/skirt)
 +			// was requested but none was found, create a default asset as a replacement.
 +			// In all other cases, don't do anything.
 +			// For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud 
 +			// due to logic in LLVOAvatarSelf::getIsCloud().
 +			// For non-critical types (tatoo, socks, etc.) the wearable will just be missing.
 +			(requested_by_type[type] > 0) &&  
 +			((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT)))
 +		{
 +			mTypesToRecover.insert(type);
 +			mTypesToLink.insert(type);
 +			recoverMissingWearable((LLWearableType::EType)type);
 +			LL_WARNS() << self_av_string() << "need to replace " << type << LL_ENDL; 
 +		}
 +	}
 +
 +	resetTime(60.0F);
 +
 +	if (isMostRecent())
 +	{
 +		selfStartPhase("get_missing_wearables_2");
 +	}
 +	if (!pollMissingWearables())
 +	{
 +		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this));
 +	}
 +}
 +
 +void LLWearableHoldingPattern::onAllComplete()
 +{
 +	if (isAgentAvatarValid())
 +	{
 +		gAgentAvatarp->outputRezTiming("Agent wearables fetch complete");
 +	}
 +
 +	if (!isMostRecent())
 +	{
 +		// runway need to skip here?
 +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +	}
 +
 +	// Activate all gestures in this folder
 +	if (mGestItems.size() > 0)
 +	{
 +		LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.size() << " gestures" << LL_ENDL;
 +		
 +		LLGestureMgr::instance().activateGestures(mGestItems);
 +		
 +		// Update the inventory item labels to reflect the fact
 +		// they are active.
 +		LLViewerInventoryCategory* catp =
 +			gInventory.getCategory(LLAppearanceMgr::instance().getCOF());
 +		
 +		if (catp)
 +		{
 +			gInventory.updateCategory(catp);
 +			gInventory.notifyObservers();
 +		}
 +	}
 +
 +	if (isAgentAvatarValid())
 +	{
 +		LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL;
 +		LLAgentWearables::llvo_vec_t objects_to_remove;
 +		LLAgentWearables::llvo_vec_t objects_to_retain;
 +		LLInventoryModel::item_array_t items_to_add;
 +
 +		LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems,
 +													   objects_to_remove,
 +													   objects_to_retain,
 +													   items_to_add);
 +
 +		LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size()
 +							<< " attachments" << LL_ENDL;
 +
 +		// Here we remove the attachment pos overrides for *all*
 +		// attachments, even those that are not being removed. This is
 +		// needed to get joint positions all slammed down to their
 +		// pre-attachment states.
 +		gAgentAvatarp->clearAttachmentPosOverrides();
 +
 +		// Take off the attachments that will no longer be in the outfit.
 +		LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove);
 +		
 +		// Update wearables.
 +		LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with "
 +						   << mResolved << " wearable items " << LL_ENDL;
 +		LLAppearanceMgr::instance().updateAgentWearables(this);
 +		
 +		// Restore attachment pos overrides for the attachments that
 +		// are remaining in the outfit.
 +		for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin();
 +			 it != objects_to_retain.end();
 +			 ++it)
 +		{
 +			LLViewerObject *objectp = *it;
 +			gAgentAvatarp->addAttachmentPosOverridesForObject(objectp);
 +		}
 +		
 +		// Add new attachments to match those requested.
 +		LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL;
 +		LLAgentWearables::userAttachMultipleAttachments(items_to_add);
 +	}
 +
 +	if (isFetchCompleted() && isMissingCompleted())
 +	{
 +		// Only safe to delete if all wearable callbacks and all missing wearables completed.
 +		delete this;
 +	}
 +	else
 +	{
 +		mIsAllComplete = true;
 +		handleLateArrivals();
 +	}
 +}
 +
 +void LLWearableHoldingPattern::onFetchCompletion()
 +{
 +	if (isMostRecent())
 +	{
 +		selfStopPhase("get_wearables_2");
 +	}
 +		
 +	if (!isMostRecent())
 +	{
 +		// runway skip here?
 +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +	}
 +
 +	checkMissingWearables();
 +}
 +
 +// Runs as an idle callback until all wearables are fetched (or we time out).
 +bool LLWearableHoldingPattern::pollFetchCompletion()
 +{
 +	if (!isMostRecent())
 +	{
 +		// runway skip here?
 +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +	}
 +
 +	bool completed = isFetchCompleted();
 +	bool timed_out = isTimedOut();
 +	bool done = completed || timed_out;
 +
 +	if (done)
 +	{
 +		LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out
 +				<< " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL;
 +
 +		mFired = true;
 +		
 +		if (timed_out)
 +		{
 +			LL_WARNS() << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << LL_ENDL;
 +		}
 +
 +		onFetchCompletion();
 +	}
 +	return done;
 +}
 +
 +void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)
 +{
 +	if (!holder->isMostRecent())
 +	{
 +		LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +		// runway skip here?
 +	}
 +
 +	LL_INFOS() << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL;
 +	holder->eraseTypeToLink(type);
 +	// Add wearable to FoundData for actual wearing
 +	LLViewerInventoryItem *item = gInventory.getItem(item_id);
 +	LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
 +
 +	if (linked_item)
 +	{
 +		gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID());
 +			
 +		if (item)
 +		{
 +			LLFoundData found(linked_item->getUUID(),
 +							  linked_item->getAssetUUID(),
 +							  linked_item->getName(),
 +							  linked_item->getType(),
 +							  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID,
 +							  true // is replacement
 +				);
 +			found.mWearable = wearable;
 +			holder->getFoundList().push_front(found);
 +		}
 +		else
 +		{
 +			LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL;
 +		}
 +	}
 +	else
 +	{
 +		LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL;
 +	}
 +}
 +
 +void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)
 +{
 +	if (!holder->isMostRecent())
 +	{
 +		// runway skip here?
 +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +	}
 +
 +	LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL;
 +	LLConstPointer<LLInventoryObject> itemp = gInventory.getItem(item_id);
 +	wearable->setItemID(item_id);
 +	holder->eraseTypeToRecover(type);
 +	llassert(itemp);
 +	if (itemp)
 +	{
 +		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder));
 +
 +		link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb);
 +	}
 +}
 +
 +void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type)
 +{
 +	if (!isMostRecent())
 +	{
 +		// runway skip here?
 +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +	}
 +	
 +		// Try to recover by replacing missing wearable with a new one.
 +	LLNotificationsUtil::add("ReplacedMissingWearable");
 +	LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type)
 +				<< " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL;
 +	LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
 +
 +	// Add a new one in the lost and found folder.
 +	const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
 +	LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_cb,_1,type,wearable,this));
 +
 +	create_inventory_item(gAgent.getID(),
 +						  gAgent.getSessionID(),
 +						  lost_and_found_id,
 +						  wearable->getTransactionID(),
 +						  wearable->getName(),
 +						  wearable->getDescription(),
 +						  wearable->getAssetType(),
 +						  LLInventoryType::IT_WEARABLE,
 +						  wearable->getType(),
 +						  wearable->getPermissions().getMaskNextOwner(),
 +						  cb);
 +}
 +
 +bool LLWearableHoldingPattern::isMissingCompleted()
 +{
 +	return mTypesToLink.size()==0 && mTypesToRecover.size()==0;
 +}
 +
 +void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()
 +{
 +	for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it)
 +	{
 +		LLFoundData &data = *it;
 +		if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable))
 +		{
 +			// Wearable link that was never resolved; remove links to it from COF
 +			LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL;
 +			LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID);
 +		}
 +	}
 +}
 +
 +bool LLWearableHoldingPattern::pollMissingWearables()
 +{
 +	if (!isMostRecent())
 +	{
 +		// runway skip here?
 +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +	}
 +	
 +	bool timed_out = isTimedOut();
 +	bool missing_completed = isMissingCompleted();
 +	bool done = timed_out || missing_completed;
 +
 +	if (!done)
 +	{
 +		LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size()
 +				<< " links " << mTypesToLink.size()
 +				<< " wearables, timed out " << timed_out
 +				<< " elapsed " << mWaitTime.getElapsedTimeF32()
 +				<< " done " << done << LL_ENDL;
 +	}
 +
 +	if (done)
 +	{
 +		if (isMostRecent())
 +		{
 +			selfStopPhase("get_missing_wearables_2");
 +		}
 +
 +		gAgentAvatarp->debugWearablesLoaded();
 +
 +		// BAP - if we don't call clearCOFLinksForMissingWearables()
 +		// here, we won't have to add the link back in later if the
 +		// wearable arrives late.  This is to avoid corruption of
 +		// wearable ordering info.  Also has the effect of making
 +		// unworn item links visible in the COF under some
 +		// circumstances.
 +
 +		//clearCOFLinksForMissingWearables();
 +		onAllComplete();
 +	}
 +	return done;
 +}
 +
 +// Handle wearables that arrived after the timeout period expired.
 +void LLWearableHoldingPattern::handleLateArrivals()
 +{
 +	// Only safe to run if we have previously finished the missing
 +	// wearables and other processing - otherwise we could be in some
 +	// intermediate state - but have not been superceded by a later
 +	// outfit change request.
 +	if (mLateArrivals.size() == 0)
 +	{
 +		// Nothing to process.
 +		return;
 +	}
 +	if (!isMostRecent())
 +	{
 +		LL_WARNS() << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << LL_ENDL;
 +	}
 +	if (!mIsAllComplete)
 +	{
 +		LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL;
 +	}
 +
 +	LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL;
 +
 +	// Update mFoundList using late-arriving wearables.
 +	std::set<LLWearableType::EType> replaced_types;
 +	for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin();
 +		 iter != getFoundList().end(); ++iter)
 +	{
 +		LLFoundData& data = *iter;
 +		for (std::set<LLViewerWearable*>::iterator wear_it = mLateArrivals.begin();
 +			 wear_it != mLateArrivals.end();
 +			 ++wear_it)
 +		{
 +			LLViewerWearable *wearable = *wear_it;
 +
 +			if(wearable->getAssetID() == data.mAssetID)
 +			{
 +				data.mWearable = wearable;
 +
 +				replaced_types.insert(data.mWearableType);
 +
 +				// BAP - if we didn't call
 +				// clearCOFLinksForMissingWearables() earlier, we
 +				// don't need to restore the link here.  Fixes
 +				// wearable ordering problems.
 +
 +				// LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false);
 +
 +				// BAP failing this means inventory or asset server
 +				// are corrupted in a way we don't handle.
 +				llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType));
 +				break;
 +			}
 +		}
 +	}
 +
 +	// Remove COF links for any default wearables previously used to replace the late arrivals.
 +	// All this pussyfooting around with a while loop and explicit
 +	// iterator incrementing is to allow removing items from the list
 +	// without clobbering the iterator we're using to navigate.
 +	LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin();
 +	while (iter != getFoundList().end())
 +	{
 +		LLFoundData& data = *iter;
 +
 +		// If an item of this type has recently shown up, removed the corresponding replacement wearable from COF.
 +		if (data.mWearable && data.mIsReplacement &&
 +			replaced_types.find(data.mWearableType) != replaced_types.end())
 +		{
 +			LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID);
 +			std::list<LLFoundData>::iterator clobber_ator = iter;
 +			++iter;
 +			getFoundList().erase(clobber_ator);
 +		}
 +		else
 +		{
 +			++iter;
 +		}
 +	}
 +
 +	// Clear contents of late arrivals.
 +	mLateArrivals.clear();
 +
 +	// Update appearance based on mFoundList
 +	LLAppearanceMgr::instance().updateAgentWearables(this);
 +}
 +
 +void LLWearableHoldingPattern::resetTime(F32 timeout)
 +{
 +	mWaitTime.reset();
 +	mWaitTime.setTimerExpirySec(timeout);
 +}
 +
 +void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable)
 +{
 +	if (!isMostRecent())
 +	{
 +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
 +	}
 +	
 +	mResolved += 1;  // just counting callbacks, not successes.
 +	LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL;
 +	if (!wearable)
 +	{
 +		LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL;
 +	}
 +
 +	if (mFired)
 +	{
 +		LL_WARNS() << self_av_string() << "called after holder fired" << LL_ENDL;
 +		if (wearable)
 +		{
 +			mLateArrivals.insert(wearable);
 +			if (mIsAllComplete)
 +			{
 +				handleLateArrivals();
 +			}
 +		}
 +		return;
 +	}
 +
 +	if (!wearable)
 +	{
 +		return;
 +	}
 +
 +	for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin();
 +		 iter != getFoundList().end(); ++iter)
 +	{
 +		LLFoundData& data = *iter;
 +		if(wearable->getAssetID() == data.mAssetID)
 +		{
 +			// Failing this means inventory or asset server are corrupted in a way we don't handle.
 +			if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType))
 +			{
 +				LL_WARNS() << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << LL_ENDL;
 +				break;
 +			}
 +
 +			data.mWearable = wearable;
 +		}
 +	}
 +}
 +
 +static void onWearableAssetFetch(LLViewerWearable* wearable, void* data)
 +{
 +	LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
 +	holder->onWearableAssetFetch(wearable);
 +}
 +
 +
 +static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
 +{
 +	LLInventoryModel::item_array_t new_items;
 +	std::set<LLUUID> items_seen;
 +	std::deque<LLViewerInventoryItem*> tmp_list;
 +	// Traverse from the front and keep the first of each item
 +	// encountered, so we actually keep the *last* of each duplicate
 +	// item.  This is needed to give the right priority when adding
 +	// duplicate items to an existing outfit.
 +	for (S32 i=items.size()-1; i>=0; i--)
 +	{
 +		LLViewerInventoryItem *item = items.at(i);
 +		LLUUID item_id = item->getLinkedUUID();
 +		if (items_seen.find(item_id)!=items_seen.end())
 +			continue;
 +		items_seen.insert(item_id);
 +		tmp_list.push_front(item);
 +	}
 +	for (std::deque<LLViewerInventoryItem*>::iterator it = tmp_list.begin();
 +		 it != tmp_list.end();
 +		 ++it)
 +	{
 +		new_items.push_back(*it);
 +	}
 +	items = new_items;
 +}
 +
 +const LLUUID LLAppearanceMgr::getCOF() const
 +{
 +	return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
 +}
 +
 +S32 LLAppearanceMgr::getCOFVersion() const
 +{
 +	LLViewerInventoryCategory *cof = gInventory.getCategory(getCOF());
 +	if (cof)
 +	{
 +		return cof->getVersion();
 +	}
 +	else
 +	{
 +		return LLViewerInventoryCategory::VERSION_UNKNOWN;
 +	}
 +}
 +
 +const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()
 +{
 +	const LLUUID& current_outfit_cat = getCOF();
 +	LLInventoryModel::cat_array_t cat_array;
 +	LLInventoryModel::item_array_t item_array;
 +	// Can't search on FT_OUTFIT since links to categories return FT_CATEGORY for type since they don't
 +	// return preferred type.
 +	LLIsType is_category( LLAssetType::AT_CATEGORY ); 
 +	gInventory.collectDescendentsIf(current_outfit_cat,
 +									cat_array,
 +									item_array,
 +									false,
 +									is_category);
 +	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
 +		 iter != item_array.end();
 +		 iter++)
 +	{
 +		const LLViewerInventoryItem *item = (*iter);
 +		const LLViewerInventoryCategory *cat = item->getLinkedCategory();
 +		if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
 +		{
 +			const LLUUID parent_id = cat->getParentUUID();
 +			LLViewerInventoryCategory*  parent_cat =  gInventory.getCategory(parent_id);
 +			// if base outfit moved to trash it means that we don't have base outfit
 +			if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH)
 +			{
 +				return NULL;
 +			}
 +			return item;
 +		}
 +	}
 +	return NULL;
 +}
 +
 +bool LLAppearanceMgr::getBaseOutfitName(std::string& name)
 +{
 +	const LLViewerInventoryItem* outfit_link = getBaseOutfitLink();
 +	if(outfit_link)
 +	{
 +		const LLViewerInventoryCategory *cat = outfit_link->getLinkedCategory();
 +		if (cat)
 +		{
 +			name = cat->getName();
 +			return true;
 +		}
 +	}
 +	return false;
 +}
 +
 +const LLUUID LLAppearanceMgr::getBaseOutfitUUID()
 +{
 +	const LLViewerInventoryItem* outfit_link = getBaseOutfitLink();
 +	if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null;
 +
 +	const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory();
 +	if (!outfit_cat) return LLUUID::null;
 +
 +	if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT)
 +	{
 +		LL_WARNS() << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << LL_ENDL;
 +		return LLUUID::null;
 +	}
 +
 +	return outfit_cat->getUUID();
 +}
 +
 +void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false)
 +{
 +	if (inv_item.isNull())
 +		return;
 +	
 +	LLViewerInventoryItem *item = gInventory.getItem(inv_item);
 +	if (item)
 +	{
 +		LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, do_replace);
 +	}
 +}
 +
 +bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear,
 +									   bool do_update,
 +									   bool replace,
 +									   LLPointer<LLInventoryCallback> cb)
 +{
 +
 +	if (item_id_to_wear.isNull()) return false;
 +
 +	// *TODO: issue with multi-wearable should be fixed:
 +	// in this case this method will be called N times - loading started for each item
 +	// and than N times will be called - loading completed for each item.
 +	// That means subscribers will be notified that loading is done after first item in a batch is worn.
 +	// (loading indicator disappears for example before all selected items are worn)
 +	// Have not fix this issue for 2.1 because of stability reason. EXT-7777.
 +
 +	// Disabled for now because it is *not* acceptable to call updateAppearanceFromCOF() multiple times
 +//	gAgentWearables.notifyLoadingStarted();
 +
 +	LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
 +	if (!item_to_wear) return false;
 +
 +	if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
 +	{
 +		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
 +		copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
 +		return false;
 +	} 
 +	else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
 +	{
 +		return false; // not in library and not in agent's inventory
 +	}
 +	else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
 +	{
 +		LLNotificationsUtil::add("CannotWearTrash");
 +		return false;
 +	}
 +	else if (isLinkedInCOF(item_to_wear->getUUID())) // EXT-84911
 +	{
 +		return false;
 +	}
 +
 +	switch (item_to_wear->getType())
 +	{
 +		case LLAssetType::AT_CLOTHING:
 +		if (gAgentWearables.areWearablesLoaded())
 +		{
 +			if (!cb && do_update)
 +			{
 +				cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
 +			}
 +			S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType());
 +			if ((replace && wearable_count != 0) ||
 +				(wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) )
 +			{
 +				LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(),
 +																   wearable_count-1);
 +				removeCOFItemLinks(item_id, cb);
 +			}
 +
 +			addCOFItemLink(item_to_wear, cb);
 +		} 
 +		break;
 +
 +		case LLAssetType::AT_BODYPART:
 +		// TODO: investigate wearables may not be loaded at this point EXT-8231
 +		
 +		// Remove the existing wearables of the same type.
 +		// Remove existing body parts anyway because we must not be able to wear e.g. two skins.
 +		removeCOFLinksOfType(item_to_wear->getWearableType());
 +		if (!cb && do_update)
 +		{
 +			cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
 +		}
 +		addCOFItemLink(item_to_wear, cb);
 +		break;
 +
 +		case LLAssetType::AT_OBJECT:
 +		rez_attachment(item_to_wear, NULL, replace);
 +		break;
 +
 +		default: return false;;
 +	}
 +
 +	return true;
 +}
 +
 +// Update appearance from outfit folder.
 +void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool append)
 +{
 +	if (!proceed)
 +		return;
 +	LLAppearanceMgr::instance().updateCOF(category,append);
 +}
 +
 +void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit)
 +{
 +	LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit);
 +	wearInventoryCategory(cat, false, false);
 +}
 +
 +// Open outfit renaming dialog.
 +void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id)
 +{
 +	LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id);
 +	if (!cat)
 +	{
 +		return;
 +	}
 +
 +	LLSD args;
 +	args["NAME"] = cat->getName();
 +
 +	LLSD payload;
 +	payload["cat_id"] = outfit_id;
 +
 +	LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2));
 +}
 +
 +// User typed new outfit name.
 +// static
 +void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response)
 +{
 +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 +	if (option != 0) return; // canceled
 +
 +	std::string outfit_name = response["new_name"].asString();
 +	LLStringUtil::trim(outfit_name);
 +	if (!outfit_name.empty())
 +	{
 +		LLUUID cat_id = notification["payload"]["cat_id"].asUUID();
 +		rename_category(&gInventory, cat_id, outfit_name);
 +	}
 +}
 +
 +void LLAppearanceMgr::setOutfitLocked(bool locked)
 +{
 +	if (mOutfitLocked == locked)
 +	{
 +		return;
 +	}
 +
 +	mOutfitLocked = locked;
 +	if (locked)
 +	{
 +		mUnlockOutfitTimer->reset();
 +		mUnlockOutfitTimer->start();
 +	}
 +	else
 +	{
 +		mUnlockOutfitTimer->stop();
 +	}
 +
 +	LLOutfitObserver::instance().notifyOutfitLockChanged();
 +}
 +
 +void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id)
 +{
 +	LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
 +	wearInventoryCategory(cat, false, true);
 +}
 +
 +void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id)
 +{
 +	LLInventoryModel::cat_array_t cats;
 +	LLInventoryModel::item_array_t items;
 +	LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false);
 +
 +	gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector);
 +
 +	LLInventoryModel::item_array_t::const_iterator it = items.begin();
 +	const LLInventoryModel::item_array_t::const_iterator it_end = items.end();
 +	uuid_vec_t uuids_to_remove;
 +	for( ; it_end != it; ++it)
 +	{
 +		LLViewerInventoryItem* item = *it;
 +		uuids_to_remove.push_back(item->getUUID());
 +	}
 +	removeItemsFromAvatar(uuids_to_remove);
 +
 +	// deactivate all gestures in the outfit folder
 +	LLInventoryModel::item_array_t gest_items;
 +	getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE);
 +	for(S32 i = 0; i  < gest_items.size(); ++i)
 +	{
 +		LLViewerInventoryItem *gest_item = gest_items[i];
 +		if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) )
 +		{
 +			LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() );
 +		}
 +	}
 +}
 +
 +// Create a copy of src_id + contents as a subfolder of dst_id.
 +void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
 +											  LLPointer<LLInventoryCallback> cb)
 +{
 +	LLInventoryCategory *src_cat = gInventory.getCategory(src_id);
 +	if (!src_cat)
 +	{
 +		LL_WARNS() << "folder not found for src " << src_id.asString() << LL_ENDL;
 +		return;
 +	}
 +	LL_INFOS() << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << LL_ENDL;
 +	LLUUID parent_id = dst_id;
 +	if(parent_id.isNull())
 +	{
 +		parent_id = gInventory.getRootFolderID();
 +	}
 +	LLUUID subfolder_id = gInventory.createNewCategory( parent_id,
 +														LLFolderType::FT_NONE,
 +														src_cat->getName());
 +	shallowCopyCategoryContents(src_id, subfolder_id, cb);
 +
 +	gInventory.notifyObservers();
 +}
 +
 +void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id,
 +										bool include_folder_links, LLPointer<LLInventoryCallback> cb)
 +{
 +	LLInventoryModel::cat_array_t* cats;
 +	LLInventoryModel::item_array_t* items;
 +	LLSD contents = LLSD::emptyArray();
 +	gInventory.getDirectDescendentsOf(src_id, cats, items);
 +	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL;
 +	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();
 +		 iter != items->end();
 +		 ++iter)
 +	{
 +		const LLViewerInventoryItem* item = (*iter);
 +		switch (item->getActualType())
 +		{
 +			case LLAssetType::AT_LINK:
 +			{
 +				LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL;
 +				//getActualDescription() is used for a new description 
 +				//to propagate ordering information saved in descriptions of links
 +				LLSD item_contents;
 +				item_contents["name"] = item->getName();
 +				item_contents["desc"] = item->getActualDescription();
 +				item_contents["linked_id"] = item->getLinkedUUID();
 +				item_contents["type"] = LLAssetType::AT_LINK; 
 +				contents.append(item_contents);
 +				break;
 +			}
 +			case LLAssetType::AT_LINK_FOLDER:
 +			{
 +				LLViewerInventoryCategory *catp = item->getLinkedCategory();
 +				if (catp && include_folder_links)
 +				{
 +					LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL;
 +					LLSD base_contents;
 +					base_contents["name"] = catp->getName();
 +					base_contents["desc"] = ""; // categories don't have descriptions.
 +					base_contents["linked_id"] = catp->getLinkedUUID();
 +					base_contents["type"] = LLAssetType::AT_LINK_FOLDER; 
 +					contents.append(base_contents);
 +				}
 +				break;
 +			}
 +			default:
 +			{
 +				// Linux refuses to compile unless all possible enums are handled. Really, Linux?
 +				break;
 +			}
 +		}
 +	}
 +	slam_inventory_folder(dst_id, contents, cb);
 +}
 +// Copy contents of src_id to dst_id.
 +void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
 +													  LLPointer<LLInventoryCallback> cb)
 +{
 +	LLInventoryModel::cat_array_t* cats;
 +	LLInventoryModel::item_array_t* items;
 +	gInventory.getDirectDescendentsOf(src_id, cats, items);
 +	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL;
 +	LLInventoryObject::const_object_list_t link_array;
 +	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();
 +		 iter != items->end();
 +		 ++iter)
 +	{
 +		const LLViewerInventoryItem* item = (*iter);
 +		switch (item->getActualType())
 +		{
 +			case LLAssetType::AT_LINK:
 +			{
 +				LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL;
 +				link_array.push_back(LLConstPointer<LLInventoryObject>(item));
 +				break;
 +			}
 +			case LLAssetType::AT_LINK_FOLDER:
 +			{
 +				LLViewerInventoryCategory *catp = item->getLinkedCategory();
 +				// Skip copying outfit links.
 +				if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT)
 +				{
 +					LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL;
 +					link_array.push_back(LLConstPointer<LLInventoryObject>(item));
 +				}
 +				break;
 +			}
 +			case LLAssetType::AT_CLOTHING:
 +			case LLAssetType::AT_OBJECT:
 +			case LLAssetType::AT_BODYPART:
 +			case LLAssetType::AT_GESTURE:
 +			{
 +				LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL;
 +				copy_inventory_item(gAgent.getID(),
 +									item->getPermissions().getOwner(),
 +									item->getUUID(),
 +									dst_id,
 +									item->getName(),
 +									cb);
 +				break;
 +			}
 +			default:
 +				// Ignore non-outfit asset types
 +				break;
 +		}
 +	}
 +	if (!link_array.empty())
 +	{
 +		link_inventory_array(dst_id, link_array, cb);
 +	}
 +}
 +
 +BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
 +{
 +	// These are the wearable items that are required for considering this
 +	// folder as containing a complete outfit.
 +	U32 required_wearables = 0;
 +	required_wearables |= 1LL << LLWearableType::WT_SHAPE;
 +	required_wearables |= 1LL << LLWearableType::WT_SKIN;
 +	required_wearables |= 1LL << LLWearableType::WT_HAIR;
 +	required_wearables |= 1LL << LLWearableType::WT_EYES;
 +
 +	// These are the wearables that the folder actually contains.
 +	U32 folder_wearables = 0;
 +	LLInventoryModel::cat_array_t* cats;
 +	LLInventoryModel::item_array_t* items;
 +	gInventory.getDirectDescendentsOf(folder_id, cats, items);
 +	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();
 +		 iter != items->end();
 +		 ++iter)
 +	{
 +		const LLViewerInventoryItem* item = (*iter);
 +		if (item->isWearableType())
 +		{
 +			const LLWearableType::EType wearable_type = item->getWearableType();
 +			folder_wearables |= 1LL << wearable_type;
 +		}
 +	}
 +
 +	// If the folder contains the required wearables, return TRUE.
 +	return ((required_wearables & folder_wearables) == required_wearables);
 +}
 +
 +bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id)
 +{
 +	// Disallow removing the base outfit.
 +	if (outfit_cat_id == getBaseOutfitUUID())
 +	{
 +		return false;
 +	}
 +
 +	// Check if the outfit folder itself is removable.
 +	if (!get_is_category_removable(&gInventory, outfit_cat_id))
 +	{
 +		return false;
 +	}
 +
 +	// Check for the folder's non-removable descendants.
 +	LLFindNonRemovableObjects filter_non_removable;
 +	LLInventoryModel::cat_array_t cats;
 +	LLInventoryModel::item_array_t items;
 +	LLInventoryModel::item_array_t::const_iterator it;
 +	gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable);
 +	if (!cats.empty() || !items.empty())
 +	{
 +		return false;
 +	}
 +
 +	return true;
 +}
 +
 +// static
 +bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id)
 +{
 +	if (gAgentWearables.isCOFChangeInProgress())
 +	{
 +		return false;
 +	}
 +
 +	LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false);
 +	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, is_worn);
 +}
 +
 +// static
 +bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id)
 +{
 +	if (gAgentWearables.isCOFChangeInProgress())
 +	{
 +		return false;
 +	}
 +
 +	LLInventoryModel::cat_array_t cats;
 +	LLInventoryModel::item_array_t items;
 +	LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
 +	gInventory.collectDescendentsIf(outfit_cat_id,
 +		cats,
 +		items,
 +		LLInventoryModel::EXCLUDE_TRASH,
 +		not_worn);
 +
 +	return items.size() > 0;
 +}
 +
 +bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
 +{
 +	// Don't allow wearing anything while we're changing appearance.
 +	if (gAgentWearables.isCOFChangeInProgress())
 +	{
 +		return false;
 +	}
 +
 +	// Check whether it's the base outfit.
 +	if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID())
 +	{
 +		return false;
 +	}
 +
 +	// Check whether the outfit contains any wearables we aren't wearing already (STORM-702).
 +	LLInventoryModel::cat_array_t cats;
 +	LLInventoryModel::item_array_t items;
 +	LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true);
 +	gInventory.collectDescendentsIf(outfit_cat_id,
 +		cats,
 +		items,
 +		LLInventoryModel::EXCLUDE_TRASH,
 +		is_worn);
 +
 +	return items.size() > 0;
 +}
 +
 +void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb)
 +{
 +	LLInventoryModel::cat_array_t cats;
 +	LLInventoryModel::item_array_t items;
 +	gInventory.collectDescendents(category, cats, items,
 +								  LLInventoryModel::EXCLUDE_TRASH);
 +	for (S32 i = 0; i < items.size(); ++i)
 +	{
 +		LLViewerInventoryItem *item = items.at(i);
 +		if (item->getActualType() != LLAssetType::AT_LINK_FOLDER)
 +			continue;
 +		LLViewerInventoryCategory* catp = item->getLinkedCategory();
 +		if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
 +		{
 +			remove_inventory_item(item->getUUID(), cb);
 +		}
 +	}
 +}
 +
 +// Keep the last N wearables of each type.  For viewer 2.0, N is 1 for
 +// both body parts and clothing items.
 +void LLAppearanceMgr::filterWearableItems(
 +	LLInventoryModel::item_array_t& items, S32 max_per_type)
 +{
 +	// Divvy items into arrays by wearable type.
 +	std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT);
 +	divvyWearablesByType(items, items_by_type);
 +
 +	// rebuild items list, retaining the last max_per_type of each array
 +	items.clear();
 +	for (S32 i=0; i<LLWearableType::WT_COUNT; i++)
 +	{
 +		S32 size = items_by_type[i].size();
 +		if (size <= 0)
 +			continue;
 +		S32 start_index = llmax(0,size-max_per_type);
 +		for (S32 j = start_index; j<size; j++)
 +		{
 +			items.push_back(items_by_type[i][j]);
 +		}
 +	}
 +}
 +
 +void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 +{
 +	LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
 +	if (!pcat)
 +	{
 +		LL_WARNS() << "no category found for id " << category << LL_ENDL;
 +		return;
 +	}
 +	LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;
 +
 +	const LLUUID cof = getCOF();
 +
 +	// Deactivate currently active gestures in the COF, if replacing outfit
 +	if (!append)
 +	{
 +		LLInventoryModel::item_array_t gest_items;
 +		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE);
 +		for(S32 i = 0; i  < gest_items.size(); ++i)
 +		{
 +			LLViewerInventoryItem *gest_item = gest_items.at(i);
 +			if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) )
 +			{
 +				LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() );
 +			}
 +		}
 +	}
 +	
 +	// Collect and filter descendents to determine new COF contents.
 +
 +	// - Body parts: always include COF contents as a fallback in case any
 +	// required parts are missing.
 +	// Preserve body parts from COF if appending.
 +	LLInventoryModel::item_array_t body_items;
 +	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART);
 +	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART);
 +	if (append)
 +		reverse(body_items.begin(), body_items.end());
 +	// Reduce body items to max of one per type.
 +	removeDuplicateItems(body_items);
 +	filterWearableItems(body_items, 1);
 +
 +	// - Wearables: include COF contents only if appending.
 +	LLInventoryModel::item_array_t wear_items;
 +	if (append)
 +		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING);
 +	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING);
 +	// Reduce wearables to max of one per type.
 +	removeDuplicateItems(wear_items);
 +	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
 +
 +	// - Attachments: include COF contents only if appending.
 +	LLInventoryModel::item_array_t obj_items;
 +	if (append)
 +		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
 +	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT);
 +	removeDuplicateItems(obj_items);
 +
 +	// - Gestures: include COF contents only if appending.
 +	LLInventoryModel::item_array_t gest_items;
 +	if (append)
 +		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE);
 +	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE);
 +	removeDuplicateItems(gest_items);
 +	
 +	// Create links to new COF contents.
 +	LLInventoryModel::item_array_t all_items;
 +	std::copy(body_items.begin(), body_items.end(), std::back_inserter(all_items));
 +	std::copy(wear_items.begin(), wear_items.end(), std::back_inserter(all_items));
 +	std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items));
 +	std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items));
 +
 +	// Find any wearables that need description set to enforce ordering.
 +	desc_map_t desc_map;
 +	getWearableOrderingDescUpdates(wear_items, desc_map);
 +
 +	// Will link all the above items.
 +	// link_waiter enforce flags are false because we've already fixed everything up in updateCOF().
 +	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false);
 +	LLSD contents = LLSD::emptyArray();
 +
 +	for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin();
 +		 it != all_items.end(); ++it)
 +	{
 +		LLSD item_contents;
 +		LLInventoryItem *item = *it;
 +
 +		std::string desc;
 +		desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID());
 +		if (desc_iter != desc_map.end())
 +		{
 +			desc = desc_iter->second;
 +			LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc
 +								<< " (was: " << item->getActualDescription() << ")" << LL_ENDL;
 +		}
 +		else
 +		{
 +			desc = item->getActualDescription();
 +		}
 +
 +		item_contents["name"] = item->getName();
 +		item_contents["desc"] = desc;
 +		item_contents["linked_id"] = item->getLinkedUUID();
 +		item_contents["type"] = LLAssetType::AT_LINK; 
 +		contents.append(item_contents);
 +	}
 +	const LLUUID& base_id = append ? getBaseOutfitUUID() : category;
 +	LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id);
 +	if (base_cat)
 +	{
 +		LLSD base_contents;
 +		base_contents["name"] = base_cat->getName();
 +		base_contents["desc"] = "";
 +		base_contents["linked_id"] = base_cat->getLinkedUUID();
 +		base_contents["type"] = LLAssetType::AT_LINK_FOLDER; 
 +		contents.append(base_contents);
 +	}
 +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
 +	{
 +		dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents);
 +	}
 +	slam_inventory_folder(getCOF(), contents, link_waiter);
 +
 +	LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL;
 +}
 +
 +void LLAppearanceMgr::updatePanelOutfitName(const std::string& name)
 +{
 +	LLSidepanelAppearance* panel_appearance =
 +		dynamic_cast<LLSidepanelAppearance *>(LLFloaterSidePanelContainer::getPanel("appearance"));
 +	if (panel_appearance)
 +	{
 +		panel_appearance->refreshCurrentOutfitName(name);
 +	}
 +}
 +
 +void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter)
 +{
 +	const LLUUID cof = getCOF();
 +	LLViewerInventoryCategory* catp = gInventory.getCategory(category);
 +	std::string new_outfit_name = "";
 +
 +	purgeBaseOutfitLink(cof, link_waiter);
 +
 +	if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
 +	{
 +		link_inventory_object(cof, catp, link_waiter);
 +		new_outfit_name = catp->getName();
 +	}
 +	
 +	updatePanelOutfitName(new_outfit_name);
 +}
 +
 +void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder)
 +{
 +	LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL;
 +	LLInventoryItem::item_array_t items;
 +	std::vector< LLViewerWearable* > wearables;
 +	wearables.reserve(32);
 +
 +	// For each wearable type, find the wearables of that type.
 +	for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ )
 +	{
 +		for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->getFoundList().begin();
 +			 iter != holder->getFoundList().end(); ++iter)
 +		{
 +			LLFoundData& data = *iter;
 +			LLViewerWearable* wearable = data.mWearable;
 +			if( wearable && ((S32)wearable->getType() == i) )
 +			{
 +				LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
 +				if( item && (item->getAssetUUID() == wearable->getAssetID()) )
 +				{
 +					items.push_back(item);
 +					wearables.push_back(wearable);
 +				}
 +			}
 +		}
 +	}
 +
 +	if(wearables.size() > 0)
 +	{
 +		gAgentWearables.setWearableOutfit(items, wearables);
 +	}
 +}
 +
 +S32 LLAppearanceMgr::countActiveHoldingPatterns()
 +{
 +	return LLWearableHoldingPattern::countActive();
 +}
 +
 +static void remove_non_link_items(LLInventoryModel::item_array_t &items)
 +{
 +	LLInventoryModel::item_array_t pruned_items;
 +	for (LLInventoryModel::item_array_t::const_iterator iter = items.begin();
 +		 iter != items.end();
 +		 ++iter)
 +	{
 + 		const LLViewerInventoryItem *item = (*iter);
 +		if (item && item->getIsLinkType())
 +		{
 +			pruned_items.push_back((*iter));
 +		}
 +	}
 +	items = pruned_items;
 +}
 +
 +//a predicate for sorting inventory items by actual descriptions
 +bool sort_by_actual_description(const LLInventoryItem* item1, const LLInventoryItem* item2)
 +{
 +	if (!item1 || !item2) 
 +	{
 +		LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL;
 +		return true;
 +	}
 +
 +	return item1->getActualDescription() < item2->getActualDescription();
 +}
 +
 +void item_array_diff(LLInventoryModel::item_array_t& full_list,
 +					 LLInventoryModel::item_array_t& keep_list,
 +					 LLInventoryModel::item_array_t& kill_list)
 +	
 +{
 +	for (LLInventoryModel::item_array_t::iterator it = full_list.begin();
 +		 it != full_list.end();
 +		 ++it)
 +	{
 +		LLViewerInventoryItem *item = *it;
 +		if (std::find(keep_list.begin(), keep_list.end(), item) == keep_list.end())
 +		{
 +			kill_list.push_back(item);
 +		}
 +	}
 +}
 +
 +S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
 +												 LLAssetType::EType type,
 +												 S32 max_items,
 +												 LLInventoryObject::object_list_t& items_to_kill)
 +{
 +	S32 to_kill_count = 0;
 +
 +	LLInventoryModel::item_array_t items;
 +	getDescendentsOfAssetType(cat_id, items, type);
 +	LLInventoryModel::item_array_t curr_items = items;
 +	removeDuplicateItems(items);
 +	if (max_items > 0)
 +	{
 +		filterWearableItems(items, max_items);
 +	}
 +	LLInventoryModel::item_array_t kill_items;
 +	item_array_diff(curr_items,items,kill_items);
 +	for (LLInventoryModel::item_array_t::iterator it = kill_items.begin();
 +		 it != kill_items.end();
 +		 ++it)
 +	{
 +		items_to_kill.push_back(LLPointer<LLInventoryObject>(*it));
 +		to_kill_count++;
 +	}
 +	return to_kill_count;
 +}
 +	
 +
 +void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id,
 +													LLInventoryObject::object_list_t& items_to_kill)
 +{
 +	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART,
 +							   1, items_to_kill);
 +	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING,
 +							   LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
 +	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT,
 +							   -1, items_to_kill);
 +}
 +
 +void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb)
 +{
 +	LLInventoryObject::object_list_t items_to_kill;
 +	findAllExcessOrDuplicateItems(getCOF(), items_to_kill);
 +	if (items_to_kill.size()>0)
 +	{
 +		// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but
 +		// this should catch anything that gets through.
 +		remove_inventory_items(items_to_kill, cb);
 +	}
 +}
 +
 +void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
 +											  bool enforce_ordering,
 +											  nullary_func_t post_update_func)
 +{
 +	if (mIsInUpdateAppearanceFromCOF)
 +	{
 +		LL_WARNS() << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << LL_ENDL;
 +		return;
 +	}
 +
 +	LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL;
 +
 +	if (enforce_item_restrictions)
 +	{
 +		// The point here is just to call
 +		// updateAppearanceFromCOF() again after excess items
 +		// have been removed. That time we will set
 +		// enforce_item_restrictions to false so we don't get
 +		// caught in a perpetual loop.
 +		LLPointer<LLInventoryCallback> cb(
 +			new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func));
 +		enforceCOFItemRestrictions(cb);
 +		return;
 +	}
 +
 +	if (enforce_ordering)
 +	{
 +		//checking integrity of the COF in terms of ordering of wearables, 
 +		//checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state)
 +
 +		// As with enforce_item_restrictions handling above, we want
 +		// to wait for the update callbacks, then (finally!) call
 +		// updateAppearanceFromCOF() with no additional COF munging needed.
 +		LLPointer<LLInventoryCallback> cb(
 +			new LLUpdateAppearanceOnDestroy(false, false, post_update_func));
 +		updateClothingOrderingInfo(LLUUID::null, cb);
 +		return;
 +	}
 +
 +	if (!validateClothingOrderingInfo())
 +	{
 +		LL_WARNS() << "Clothing ordering error" << LL_ENDL;
 +	}
 +
 +	BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF);
 +	selfStartPhase("update_appearance_from_cof");
 +
 +	// update dirty flag to see if the state of the COF matches
 +	// the saved outfit stored as a folder link
 +	updateIsDirty();
 +
 +	// Send server request for appearance update
 +	if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion())
 +	{
 +		requestServerAppearanceUpdate();
 +	}
 +
 +	LLUUID current_outfit_id = getCOF();
 +
 +	// Find all the wearables that are in the COF's subtree.
 +	LL_DEBUGS() << "LLAppearanceMgr::updateFromCOF()" << LL_ENDL;
 +	LLInventoryModel::item_array_t wear_items;
 +	LLInventoryModel::item_array_t obj_items;
 +	LLInventoryModel::item_array_t gest_items;
 +	getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items);
 +	// Get rid of non-links in case somehow the COF was corrupted.
 +	remove_non_link_items(wear_items);
 +	remove_non_link_items(obj_items);
 +	remove_non_link_items(gest_items);
 +
 +	dumpItemArray(wear_items,"asset_dump: wear_item");
 +	dumpItemArray(obj_items,"asset_dump: obj_item");
 +
 +	LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id);
 +	if (!gInventory.isCategoryComplete(current_outfit_id))
 +	{
 +		LL_WARNS() << "COF info is not complete. Version " << cof->getVersion()
 +				<< " descendent_count " << cof->getDescendentCount()
 +				<< " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL;
 +	}
 +	if(!wear_items.size())
 +	{
 +		LLNotificationsUtil::add("CouldNotPutOnOutfit");
 +		return;
 +	}
 +
 +	//preparing the list of wearables in the correct order for LLAgentWearables
 +	sortItemsByActualDescription(wear_items);
 +
 +
 +	LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL;
 +	LLTimer hp_block_timer;
 +	LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
 +
 +	holder->setObjItems(obj_items);
 +	holder->setGestItems(gest_items);
 +		
 +	// Note: can't do normal iteration, because if all the
 +	// wearables can be resolved immediately, then the
 +	// callback will be called (and this object deleted)
 +	// before the final getNextData().
 +
 +	for(S32 i = 0; i  < wear_items.size(); ++i)
 +	{
 +		LLViewerInventoryItem *item = wear_items.at(i);
 +		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
 +
 +		// Fault injection: use debug setting to test asset 
 +		// fetch failures (should be replaced by new defaults in
 +		// lost&found).
 +		U32 skip_type = gSavedSettings.getU32("ForceAssetFail");
 +
 +		if (item && item->getIsLinkType() && linked_item)
 +		{
 +			LLFoundData found(linked_item->getUUID(),
 +							  linked_item->getAssetUUID(),
 +							  linked_item->getName(),
 +							  linked_item->getType(),
 +							  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID
 +				);
 +
 +			if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType)
 +			{
 +				found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB
 +			}
 +			//pushing back, not front, to preserve order of wearables for LLAgentWearables
 +			holder->getFoundList().push_back(found);
 +		}
 +		else
 +		{
 +			if (!item)
 +			{
 +				LL_WARNS() << "Attempt to wear a null item " << LL_ENDL;
 +			}
 +			else if (!linked_item)
 +			{
 +				LL_WARNS() << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << LL_ENDL;
 +			}
 +		}
 +	}
 +
 +	selfStartPhase("get_wearables_2");
 +
 +	for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin();
 +		 it != holder->getFoundList().end(); ++it)
 +	{
 +		LLFoundData& found = *it;
 +
 +		LL_DEBUGS() << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << LL_ENDL;
 +
 +		// Fetch the wearables about to be worn.
 +		LLWearableList::instance().getAsset(found.mAssetID,
 +											found.mName,
 +											gAgentAvatarp,
 +											found.mAssetType,
 +											onWearableAssetFetch,
 +											(void*)holder);
 +
 +	}
 +
 +	holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime"));
 +	if (!holder->pollFetchCompletion())
 +	{
 +		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder));
 +	}
 +	post_update_func();
 +
 +	LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL;
 +}
 +
 +void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category,
 +													LLInventoryModel::item_array_t& items,
 +													LLAssetType::EType type)
 +{
 +	LLInventoryModel::cat_array_t cats;
 +	LLIsType is_of_type(type);
 +	gInventory.collectDescendentsIf(category,
 +									cats,
 +									items,
 +									LLInventoryModel::EXCLUDE_TRASH,
 +									is_of_type);
 +}
 +
 +void LLAppearanceMgr::getUserDescendents(const LLUUID& category, 
 +											 LLInventoryModel::item_array_t& wear_items,
 +											 LLInventoryModel::item_array_t& obj_items,
 +											 LLInventoryModel::item_array_t& gest_items)
 +{
 +	LLInventoryModel::cat_array_t wear_cats;
 +	LLFindWearables is_wearable;
 +	gInventory.collectDescendentsIf(category,
 +									wear_cats,
 +									wear_items,
 +									LLInventoryModel::EXCLUDE_TRASH,
 +									is_wearable);
 +
 +	LLInventoryModel::cat_array_t obj_cats;
 +	LLIsType is_object( LLAssetType::AT_OBJECT );
 +	gInventory.collectDescendentsIf(category,
 +									obj_cats,
 +									obj_items,
 +									LLInventoryModel::EXCLUDE_TRASH,
 +									is_object);
 +
 +	// Find all gestures in this folder
 +	LLInventoryModel::cat_array_t gest_cats;
 +	LLIsType is_gesture( LLAssetType::AT_GESTURE );
 +	gInventory.collectDescendentsIf(category,
 +									gest_cats,
 +									gest_items,
 +									LLInventoryModel::EXCLUDE_TRASH,
 +									is_gesture);
 +}
 +
 +void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append)
 +{
 +	if(!category) return;
 +
 +	selfClearPhases();
 +	selfStartPhase("wear_inventory_category");
 +
 +	gAgentWearables.notifyLoadingStarted();
 +
 +	LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName()
 +			 << " )" << LL_ENDL;
 +
 +	// If we are copying from library, attempt to use AIS to copy the category.
 +	bool ais_ran=false;
 +	if (copy && AISCommand::isAPIAvailable())
 +	{
 +		LLUUID parent_id;
 +		parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
 +		if (parent_id.isNull())
 +		{
 +			parent_id = gInventory.getRootFolderID();
 +		}
 +
 +		LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append);
 +		LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper(
 +													std::string("wear_inventory_category_callback"), copy_cb);
 +		LLPointer<AISCommand> cmd_ptr = new CopyLibraryCategoryCommand(category->getUUID(), parent_id, track_cb);
 +		ais_ran=cmd_ptr->run_command();
 +	}
 +
 +	if (!ais_ran)
 +	{
 +		selfStartPhase("wear_inventory_category_fetch");
 +		callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
 +															   &LLAppearanceMgr::instance(),
 +															   category->getUUID(), copy, append));
 +	}
 +}
 +
 +S32 LLAppearanceMgr::getActiveCopyOperations() const
 +{
 +	return LLCallAfterInventoryCopyMgr::getInstanceCount(); 
 +}
 +
 +void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append)
 +{
 +	LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL;
 +
 +	selfStopPhase("wear_inventory_category_fetch");
 +	
 +	// We now have an outfit ready to be copied to agent inventory. Do
 +	// it, and wear that outfit normally.
 +	LLInventoryCategory* cat = gInventory.getCategory(cat_id);
 +	if(copy_items)
 +	{
 +		LLInventoryModel::cat_array_t* cats;
 +		LLInventoryModel::item_array_t* items;
 +		gInventory.getDirectDescendentsOf(cat_id, cats, items);
 +		std::string name;
 +		if(!cat)
 +		{
 +			// should never happen.
 +			name = "New Outfit";
 +		}
 +		else
 +		{
 +			name = cat->getName();
 +		}
 +		LLViewerInventoryItem* item = NULL;
 +		LLInventoryModel::item_array_t::const_iterator it = items->begin();
 +		LLInventoryModel::item_array_t::const_iterator end = items->end();
 +		LLUUID pid;
 +		for(; it < end; ++it)
 +		{
 +			item = *it;
 +			if(item)
 +			{
 +				if(LLInventoryType::IT_GESTURE == item->getInventoryType())
 +				{
 +					pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
 +				}
 +				else
 +				{
 +					pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
 +				}
 +				break;
 +			}
 +		}
 +		if(pid.isNull())
 +		{
 +			pid = gInventory.getRootFolderID();
 +		}
 +		
 +		LLUUID new_cat_id = gInventory.createNewCategory(
 +			pid,
 +			LLFolderType::FT_NONE,
 +			name);
 +
 +		// Create a CopyMgr that will copy items, manage its own destruction
 +		new LLCallAfterInventoryCopyMgr(
 +			*items, new_cat_id, std::string("wear_inventory_category_callback"),
 +			boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar,
 +						LLAppearanceMgr::getInstance(),
 +						gInventory.getCategory(new_cat_id),
 +						append));
 +
 +		// BAP fixes a lag in display of created dir.
 +		gInventory.notifyObservers();
 +	}
 +	else
 +	{
 +		// Wear the inventory category.
 +		LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, append);
 +	}
 +}
 +
 +// *NOTE: hack to get from avatar inventory to avatar
 +void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append )
 +{
 +	// Avoid unintentionally overwriting old wearables.  We have to do
 +	// this up front to avoid having to deal with the case of multiple
 +	// wearables being dirty.
 +	if (!category) return;
 +
 +	if ( !LLInventoryCallbackManager::is_instantiated() )
 +	{
 +		// shutting down, ignore.
 +		return;
 +	}
 +
 +	LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName()
 +			 << "'" << LL_ENDL;
 +			 	
 +	if (gAgentCamera.cameraCustomizeAvatar())
 +	{
 +		// switching to outfit editor should automagically save any currently edited wearable
 +		LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit"));
 +	}
 +
 +	LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append);
 +}
 +
 +// FIXME do we really want to search entire inventory for matching name?
 +void LLAppearanceMgr::wearOutfitByName(const std::string& name)
 +{
 +	LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL;
 +
 +	LLInventoryModel::cat_array_t cat_array;
 +	LLInventoryModel::item_array_t item_array;
 +	LLNameCategoryCollector has_name(name);
 +	gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
 +									cat_array,
 +									item_array,
 +									LLInventoryModel::EXCLUDE_TRASH,
 +									has_name);
 +	bool copy_items = false;
 +	LLInventoryCategory* cat = NULL;
 +	if (cat_array.size() > 0)
 +	{
 +		// Just wear the first one that matches
 +		cat = cat_array.at(0);
 +	}
 +	else
 +	{
 +		gInventory.collectDescendentsIf(LLUUID::null,
 +										cat_array,
 +										item_array,
 +										LLInventoryModel::EXCLUDE_TRASH,
 +										has_name);
 +		if(cat_array.size() > 0)
 +		{
 +			cat = cat_array.at(0);
 +			copy_items = true;
 +		}
 +	}
 +
 +	if(cat)
 +	{
 +		LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false);
 +	}
 +	else
 +	{
 +		LL_WARNS() << "Couldn't find outfit " <<name<< " in wearOutfitByName()"
 +				<< LL_ENDL;
 +	}
 +}
 +
 +bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventoryItem *b)
 +{
 +	return (a->isWearableType() && b->isWearableType() &&
 +			(a->getWearableType() == b->getWearableType()));
 +}
 +
 +class LLDeferredCOFLinkObserver: public LLInventoryObserver
 +{
 +public:
 +	LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description):
 +		mItemID(item_id),
 +		mCallback(cb),
 +		mDescription(description)
 +	{
 +	}
 +
 +	~LLDeferredCOFLinkObserver()
 +	{
 +	}
 +	
 +	/* virtual */ void changed(U32 mask)
 +	{
 +		const LLInventoryItem *item = gInventory.getItem(mItemID);
 +		if (item)
 +		{
 +			gInventory.removeObserver(this);
 +			LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription);
 +			delete this;
 +		}
 +	}
 +
 +private:
 +	const LLUUID mItemID;
 +	std::string mDescription;
 +	LLPointer<LLInventoryCallback> mCallback;
 +};
 +
 +
 +// BAP - note that this runs asynchronously if the item is not already loaded from inventory.
 +// Dangerous if caller assumes link will exist after calling the function.
 +void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id,
 +									 LLPointer<LLInventoryCallback> cb,
 +									 const std::string description)
 +{
 +	const LLInventoryItem *item = gInventory.getItem(item_id);
 +	if (!item)
 +	{
 +		LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description);
 +		gInventory.addObserver(observer);
 +	}
 +	else
 +	{
 +		addCOFItemLink(item, cb, description);
 +	}
 +}
 +
 +void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
 +									 LLPointer<LLInventoryCallback> cb,
 +									 const std::string description)
 +{
 +	const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);
 +	if (!vitem)
 +	{
 +		LL_WARNS() << "not an llviewerinventoryitem, failed" << LL_ENDL;
 +		return;
 +	}
 +
 +	gInventory.addChangedMask(LLInventoryObserver::LABEL, vitem->getLinkedUUID());
 +
 +	LLInventoryModel::cat_array_t cat_array;
 +	LLInventoryModel::item_array_t item_array;
 +	gInventory.collectDescendents(LLAppearanceMgr::getCOF(),
 +								  cat_array,
 +								  item_array,
 +								  LLInventoryModel::EXCLUDE_TRASH);
 +	bool linked_already = false;
 +	U32 count = 0;
 +	for (S32 i=0; i<item_array.size(); i++)
 +	{
 +		// Are these links to the same object?
 +		const LLViewerInventoryItem* inv_item = item_array.at(i).get();
 +		const LLWearableType::EType wearable_type = inv_item->getWearableType();
 +
 +		const bool is_body_part =    (wearable_type == LLWearableType::WT_SHAPE) 
 +								  || (wearable_type == LLWearableType::WT_HAIR) 
 +								  || (wearable_type == LLWearableType::WT_EYES)
 +								  || (wearable_type == LLWearableType::WT_SKIN);
 +
 +		if (inv_item->getLinkedUUID() == vitem->getLinkedUUID())
 +		{
 +			linked_already = true;
 +		}
 +		// Are these links to different items of the same body part
 +		// type? If so, new item will replace old.
 +		else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type))
 +		{
 +			++count;
 +			if (is_body_part && inv_item->getIsLinkType()  && (vitem->getWearableType() == wearable_type))
 +			{
 +				remove_inventory_item(inv_item->getUUID(), cb);
 +			}
 +			else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
 +			{
 +				// MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE
 +				remove_inventory_item(inv_item->getUUID(), cb);
 +			}
 +		}
 +	}
 +
 +	if (!linked_already)
 +	{
 +		LLViewerInventoryItem *copy_item = new LLViewerInventoryItem;
 +		copy_item->copyViewerItem(vitem);
 +		copy_item->setDescription(description);
 +		link_inventory_object(getCOF(), copy_item, cb);
 +	}
 +}
 +
 +LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id)
 +{
 +
 +	LLInventoryModel::item_array_t result;
 +	const LLViewerInventoryItem *vitem =
 +		dynamic_cast<const LLViewerInventoryItem*>(gInventory.getItem(item_id));
 +
 +	if (vitem)
 +	{
 +		LLInventoryModel::cat_array_t cat_array;
 +		LLInventoryModel::item_array_t item_array;
 +		gInventory.collectDescendents(LLAppearanceMgr::getCOF(),
 +									  cat_array,
 +									  item_array,
 +									  LLInventoryModel::EXCLUDE_TRASH);
 +		for (S32 i=0; i<item_array.size(); i++)
 +		{
 +			const LLViewerInventoryItem* inv_item = item_array.at(i).get();
 +			if (inv_item->getLinkedUUID() == vitem->getLinkedUUID())
 +			{
 +				result.push_back(item_array.at(i));
 +			}
 +		}
 +	}
 +	return result;
 +}
 +
 +bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id)
 +{
 +	LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id);
 +	return links.size() > 0;
 +}
 +
 +void LLAppearanceMgr::removeAllClothesFromAvatar()
 +{
 +	// Fetch worn clothes (i.e. the ones in COF).
 +	LLInventoryModel::item_array_t clothing_items;
 +	LLInventoryModel::cat_array_t dummy;
 +	LLIsType is_clothing(LLAssetType::AT_CLOTHING);
 +	gInventory.collectDescendentsIf(getCOF(),
 +									dummy,
 +									clothing_items,
 +									LLInventoryModel::EXCLUDE_TRASH,
 +									is_clothing);
 +	uuid_vec_t item_ids;
 +	for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin();
 +		it != clothing_items.end(); ++it)
 +	{
 +		item_ids.push_back((*it).get()->getLinkedUUID());
 +	}
 +
 +	// Take them off by removing from COF.
 +	removeItemsFromAvatar(item_ids);
 +}
 +
 +void LLAppearanceMgr::removeAllAttachmentsFromAvatar()
 +{
 +	if (!isAgentAvatarValid()) return;
 +
 +	LLAgentWearables::llvo_vec_t objects_to_remove;
 +	
 +	for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); 
 +		 iter != gAgentAvatarp->mAttachmentPoints.end();)
 +	{
 +		LLVOAvatar::attachment_map_t::iterator curiter = iter++;
 +		LLViewerJointAttachment* attachment = curiter->second;
 +		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
 +			 attachment_iter != attachment->mAttachedObjects.end();
 +			 ++attachment_iter)
 +		{
 +			LLViewerObject *attached_object = (*attachment_iter);
 +			if (attached_object)
 +			{
 +				objects_to_remove.push_back(attached_object);
 +			}
 +		}
 +	}
 +	uuid_vec_t ids_to_remove;
 +	for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_remove.begin();
 +		 it != objects_to_remove.end();
 +		 ++it)
 +	{
 +		ids_to_remove.push_back((*it)->getAttachmentItemID());
 +	}
 +	removeItemsFromAvatar(ids_to_remove);
 +}
 +
 +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb)
 +{
 +	gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
 +
 +	LLInventoryModel::cat_array_t cat_array;
 +	LLInventoryModel::item_array_t item_array;
 +	gInventory.collectDescendents(LLAppearanceMgr::getCOF(),
 +								  cat_array,
 +								  item_array,
 +								  LLInventoryModel::EXCLUDE_TRASH);
 +	for (S32 i=0; i<item_array.size(); i++)
 +	{
 +		const LLInventoryItem* item = item_array.at(i).get();
 +		if (item->getIsLinkType() && item->getLinkedUUID() == item_id)
 +		{
 +			bool immediate_delete = false;
 +			if (item->getType() == LLAssetType::AT_OBJECT)
 +			{
 +				immediate_delete = true;
 +			}
 +			remove_inventory_item(item->getUUID(), cb, immediate_delete);
 +		}
 +	}
 +}
 +
 +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb)
 +{
 +	LLFindWearablesOfType filter_wearables_of_type(type);
 +	LLInventoryModel::cat_array_t cats;
 +	LLInventoryModel::item_array_t items;
 +	LLInventoryModel::item_array_t::const_iterator it;
 +
 +	gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type);
 +	for (it = items.begin(); it != items.end(); ++it)
 +	{
 +		const LLViewerInventoryItem* item = *it;
 +		if (item->getIsLinkType()) // we must operate on links only
 +		{
 +			remove_inventory_item(item->getUUID(), cb);
 +		}
 +	}
 +}
 +
 +bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInventoryItem* item2)
 +{
 +	if (!item1 || !item2)
 +	{
 +		LL_WARNS() << "item1, item2 cannot be null, something is very wrong" << LL_ENDL;
 +		return true;
 +	}
 +
 +	return item1->getLinkedUUID() < item2->getLinkedUUID();
 +}
 +
 +void LLAppearanceMgr::updateIsDirty()
 +{
 +	LLUUID cof = getCOF();
 +	LLUUID base_outfit;
 +
 +	// find base outfit link 
 +	const LLViewerInventoryItem* base_outfit_item = getBaseOutfitLink();
 +	LLViewerInventoryCategory* catp = NULL;
 +	if (base_outfit_item && base_outfit_item->getIsLinkType())
 +	{
 +		catp = base_outfit_item->getLinkedCategory();
 +	}
 +	if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
 +	{
 +		base_outfit = catp->getUUID();
 +	}
 +
 +	// Set dirty to "false" if no base outfit found to disable "Save"
 +	// and leave only "Save As" enabled in My Outfits.
 +	mOutfitIsDirty = false;
 +
 +	if (base_outfit.notNull())
 +	{
 +		LLIsValidItemLink collector;
 +
 +		LLInventoryModel::cat_array_t cof_cats;
 +		LLInventoryModel::item_array_t cof_items;
 +		gInventory.collectDescendentsIf(cof, cof_cats, cof_items,
 +									  LLInventoryModel::EXCLUDE_TRASH, collector);
 +
 +		LLInventoryModel::cat_array_t outfit_cats;
 +		LLInventoryModel::item_array_t outfit_items;
 +		gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items,
 +									  LLInventoryModel::EXCLUDE_TRASH, collector);
 +
 +		if(outfit_items.size() != cof_items.size())
 +		{
 +			LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL;
 +			// Current outfit folder should have one more item than the outfit folder.
 +			// this one item is the link back to the outfit folder itself.
 +			mOutfitIsDirty = true;
 +			return;
 +		}
 +
 +		//"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions)
 +		std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid);
 +		std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid);
 +
 +		for (U32 i = 0; i < cof_items.size(); ++i)
 +		{
 +			LLViewerInventoryItem *item1 = cof_items.at(i);
 +			LLViewerInventoryItem *item2 = outfit_items.at(i);
 +
 +			if (item1->getLinkedUUID() != item2->getLinkedUUID() || 
 +				item1->getName() != item2->getName() ||
 +				item1->getActualDescription() != item2->getActualDescription())
 +			{
 +				if (item1->getLinkedUUID() != item2->getLinkedUUID())
 +				{
 +					LL_DEBUGS("Avatar") << "link id different " << LL_ENDL;
 +				}
 +				else
 +				{
 +					if (item1->getName() != item2->getName())
 +					{
 +						LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL;
 +					}
 +					if (item1->getActualDescription() != item2->getActualDescription())
 +					{
 +						LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription()
 +											<< " " << item2->getActualDescription() 
 +											<< " names " << item1->getName() << " " << item2->getName() << LL_ENDL;
 +					}
 +				}
 +				mOutfitIsDirty = true;
 +				return;
 +			}
 +		}
 +	}
 +	llassert(!mOutfitIsDirty);
 +	LL_DEBUGS("Avatar") << "clean" << LL_ENDL;
 +}
 +
 +// *HACK: Must match name in Library or agent inventory
 +const std::string ROOT_GESTURES_FOLDER = "Gestures";
 +const std::string COMMON_GESTURES_FOLDER = "Common Gestures";
 +const std::string MALE_GESTURES_FOLDER = "Male Gestures";
 +const std::string FEMALE_GESTURES_FOLDER = "Female Gestures";
 +const std::string SPEECH_GESTURES_FOLDER = "Speech Gestures";
 +const std::string OTHER_GESTURES_FOLDER = "Other Gestures";
 +
 +void LLAppearanceMgr::copyLibraryGestures()
 +{
 +	LL_INFOS("Avatar") << self_av_string() << "Copying library gestures" << LL_ENDL;
 +
 +	// Copy gestures
 +	LLUUID lib_gesture_cat_id =
 +		gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE,false);
 +	if (lib_gesture_cat_id.isNull())
 +	{
 +		LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL;
 +	}
 +	LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
 +
 +	std::vector<std::string> gesture_folders_to_copy;
 +	gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER);
 +	gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER);
 +	gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER);
 +	gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER);
 +	gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER);
 +
 +	for(std::vector<std::string>::iterator it = gesture_folders_to_copy.begin();
 +		it != gesture_folders_to_copy.end();
 +		++it)
 +	{
 +		std::string& folder_name = *it;
 +
 +		LLPointer<LLInventoryCallback> cb(NULL);
 +
 +		// After copying gestures, activate Common, Other, plus
 +		// Male and/or Female, depending upon the initial outfit gender.
 +		ESex gender = gAgentAvatarp->getSex();
 +
 +		std::string activate_male_gestures;
 +		std::string activate_female_gestures;
 +		switch (gender) {
 +			case SEX_MALE:
 +				activate_male_gestures = MALE_GESTURES_FOLDER;
 +				break;
 +			case SEX_FEMALE:
 +				activate_female_gestures = FEMALE_GESTURES_FOLDER;
 +				break;
 +			case SEX_BOTH:
 +				activate_male_gestures = MALE_GESTURES_FOLDER;
 +				activate_female_gestures = FEMALE_GESTURES_FOLDER;
 +				break;
 +		}
 +
 +		if (folder_name == activate_male_gestures ||
 +			folder_name == activate_female_gestures ||
 +			folder_name == COMMON_GESTURES_FOLDER ||
 +			folder_name == OTHER_GESTURES_FOLDER)
 +		{
 +			cb = new LLBoostFuncInventoryCallback(activate_gesture_cb);
 +		}
 +
 +		LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name);
 +		if (cat_id.isNull())
 +		{
 +			LL_WARNS() << self_av_string() << "failed to find gesture folder for " << folder_name << LL_ENDL;
 +		}
 +		else
 +		{
 +			LL_DEBUGS("Avatar") << self_av_string() << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << LL_ENDL;
 +			callAfterCategoryFetch(cat_id,
 +								   boost::bind(&LLAppearanceMgr::shallowCopyCategory,
 +											   &LLAppearanceMgr::instance(),
 +											   cat_id, dst_id, cb));
 +		}
 +	}
 +}
 +
 +// Handler for anything that's deferred until avatar de-clouds.
 +void LLAppearanceMgr::onFirstFullyVisible()
 +{
 +	gAgentAvatarp->outputRezTiming("Avatar fully loaded");
 +	gAgentAvatarp->reportAvatarRezTime();
 +	gAgentAvatarp->debugAvatarVisible();
 +
 +	// If this is the first time we've ever logged in,
 +	// then copy default gestures from the library.
 +	if (gAgent.isFirstLogin()) {
 +		copyLibraryGestures();
 +	}
 +}
 +
 +// update "dirty" state - defined outside class to allow for calling
 +// after appearance mgr instance has been destroyed.
 +void appearance_mgr_update_dirty_state()
 +{
 +	if (LLAppearanceMgr::instanceExists())
 +	{
 +		LLAppearanceMgr::getInstance()->updateIsDirty();
 +		LLAppearanceMgr::getInstance()->setOutfitLocked(false);
 +		gAgentWearables.notifyLoadingFinished();
 +	}
 +}
 +
 +void update_base_outfit_after_ordering()
 +{
 +	LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance();
 +	
 +	LLPointer<LLInventoryCallback> dirty_state_updater =
 +		new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state);
 +
 +	//COF contains only links so we copy to the Base Outfit only links
 +	const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID();
 +	bool copy_folder_links = false;
 +	app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater);
 +
 +}
 +
 +// Save COF changes - update the contents of the current base outfit
 +// to match the current COF. Fails if no current base outfit is set.
 +bool LLAppearanceMgr::updateBaseOutfit()
 +{
 +	if (isOutfitLocked())
 +	{
 +		// don't allow modify locked outfit
 +		llassert(!isOutfitLocked());
 +		return false;
 +	}
 +
 +	setOutfitLocked(true);
 +
 +	gAgentWearables.notifyLoadingStarted();
 +
 +	const LLUUID base_outfit_id = getBaseOutfitUUID();
 +	if (base_outfit_id.isNull()) return false;
 +	LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL;
 +
 +	LLPointer<LLInventoryCallback> cb =
 +		new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering);
 +	// Really shouldn't be needed unless there's a race condition -
 +	// updateAppearanceFromCOF() already calls updateClothingOrderingInfo.
 +	updateClothingOrderingInfo(LLUUID::null, cb);
 +
 +	return true;
 +}
 +
 +void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type)
 +{
 +	items_by_type.resize(LLWearableType::WT_COUNT);
 +	if (items.empty()) return;
 +
 +	for (S32 i=0; i<items.size(); i++)
 +	{
 +		LLViewerInventoryItem *item = items.at(i);
 +		if (!item)
 +		{
 +			LL_WARNS("Appearance") << "NULL item found" << LL_ENDL;
 +			continue;
 +		}
 +		// Ignore non-wearables.
 +		if (!item->isWearableType())
 +			continue;
 +		LLWearableType::EType type = item->getWearableType();
 +		if(type < 0 || type >= LLWearableType::WT_COUNT)
 +		{
 +			LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL;
 +			continue;
 +		}
 +		items_by_type[type].push_back(item);
 +	}
 +}
 +
 +std::string build_order_string(LLWearableType::EType type, U32 i)
 +{
 +		std::ostringstream order_num;
 +		order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i;
 +		return order_num.str();
 +}
 +
 +struct WearablesOrderComparator
 +{
 +	LOG_CLASS(WearablesOrderComparator);
 +	WearablesOrderComparator(const LLWearableType::EType type)
 +	{
 +		mControlSize = build_order_string(type, 0).size();
 +	};
 +
 +	bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2)
 +	{
 +		const std::string& desc1 = item1->getActualDescription();
 +		const std::string& desc2 = item2->getActualDescription();
 +		
 +		bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]);
 +		bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]);
 +
 +		if (item1_valid && item2_valid)
 +			return desc1 < desc2;
 +
 +		//we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions,
 +		//items with ordering information but not for the associated wearables type
 +		if (!item1_valid && item2_valid) 
 +			return false;
 +		else if (item1_valid && !item2_valid)
 +			return true;
 +
 +		return item1->getName() < item2->getName();
 +	}
 +
 +	U32 mControlSize;
 +};
 +
 +void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items,
 +													 desc_map_t& desc_map)
 +{
 +	wearables_by_type_t items_by_type(LLWearableType::WT_COUNT);
 +	divvyWearablesByType(wear_items, items_by_type);
 +
 +	for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++)
 +	{
 +		U32 size = items_by_type[type].size();
 +		if (!size) continue;
 +		
 +		//sinking down invalid items which need reordering
 +		std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type));
 +		
 +		//requesting updates only for those links which don't have "valid" descriptions
 +		for (U32 i = 0; i < size; i++)
 +		{
 +			LLViewerInventoryItem* item = items_by_type[type][i];
 +			if (!item) continue;
 +			
 +			std::string new_order_str = build_order_string((LLWearableType::EType)type, i);
 +			if (new_order_str == item->getActualDescription()) continue;
 +			
 +			desc_map[item->getUUID()] = new_order_str;
 +		}
 +	}
 +}
 +
 +bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id)
 +{
 +	// COF is processed if cat_id is not specified
 +	if (cat_id.isNull())
 +	{
 +		cat_id = getCOF();
 +	}
 +
 +	LLInventoryModel::item_array_t wear_items;
 +	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING);
 +
 +	// Identify items for which desc needs to change.
 +	desc_map_t desc_map;
 +	getWearableOrderingDescUpdates(wear_items, desc_map);
 +
 +	for (desc_map_t::const_iterator it = desc_map.begin();
 +		 it != desc_map.end(); ++it)
 +	{
 +		const LLUUID& item_id = it->first;
 +		const std::string& new_order_str = it->second;
 +		LLViewerInventoryItem *item = gInventory.getItem(item_id);
 +		LL_WARNS() << "Order validation fails: " << item->getName()
 +				<< " needs to update desc to: " << new_order_str
 +				<< " (from: " << item->getActualDescription() << ")" << LL_ENDL;
 +	}
 +	
 +	return desc_map.size() == 0;
 +}
 +
 +void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id,
 +												 LLPointer<LLInventoryCallback> cb)
 +{
 +	// COF is processed if cat_id is not specified
 +	if (cat_id.isNull())
 +	{
 +		cat_id = getCOF();
 +	}
 +
 +	LLInventoryModel::item_array_t wear_items;
 +	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING);
 +
 +	// Identify items for which desc needs to change.
 +	desc_map_t desc_map;
 +	getWearableOrderingDescUpdates(wear_items, desc_map);
 +
 +	for (desc_map_t::const_iterator it = desc_map.begin();
 +		 it != desc_map.end(); ++it)
 +	{
 +		LLSD updates;
 +		const LLUUID& item_id = it->first;
 +		const std::string& new_order_str = it->second;
 +		LLViewerInventoryItem *item = gInventory.getItem(item_id);
 +		LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str
 +			<< " (was: " << item->getActualDescription() << ")" << LL_ENDL;
 +		updates["desc"] = new_order_str;
 +		update_inventory_item(item_id,updates,cb);
 +	}
 +		
 +}
 +
 +//=========================================================================
 +class LLAppearanceMgrHttpHandler : public LLHttpSDHandler
 +{
 +public:
 +	LLAppearanceMgrHttpHandler(const std::string& capabilityURL, LLAppearanceMgr *mgr) :
 +		LLHttpSDHandler(capabilityURL),
 +		mManager(mgr)
 +	{ }
 +
 +	virtual ~LLAppearanceMgrHttpHandler()
 +	{ }
 +
 +	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + +protected:
 +	virtual void onSuccess(LLCore::HttpResponse * response, LLSD &content);
 +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
 +
 +private:
 +	static void debugCOF(const LLSD& content);
 +
 +	LLAppearanceMgr *mManager;
 +
 +};
 +
 +//-------------------------------------------------------------------------
 +void LLAppearanceMgrHttpHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) +{ +	mManager->decrementInFlightCounter();
 +
 +	LLHttpSDHandler::onCompleted(handle, response); +} +
 +void LLAppearanceMgrHttpHandler::onSuccess(LLCore::HttpResponse * response, LLSD &content)
 +{
 +	if (!content.isMap())
 +	{
 +		LLCore::HttpStatus status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents");
 +		response->setStatus(status);
 +		onFailure(response, status);
 +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
 +		{
 +			debugCOF(content);
 +		}
 +		return;
 +	}
 +	if (content["success"].asBoolean())
 +	{
 +		LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL;
 +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
 +		{
 +			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);
 +		}
 +	}
 +	else
 +	{
 +		LLCore::HttpStatus status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Non-success response");
 +		response->setStatus(status);
 +		onFailure(response, status);
 +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
 +		{
 +			debugCOF(content);
 +		}
 +		return;
 +	}
 +}
 +
 +void LLAppearanceMgrHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
 +{
 +	LL_WARNS("Avatar") << "Appearance Mgr request failed to " << getUri()
 +		<< ". Reason code: (" << status.toTerseString() << ") "
 +		<< status.toString() << LL_ENDL;
 +}
 +
 +void LLAppearanceMgrHttpHandler::debugCOF(const LLSD& content)
 +{
 +	dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
 +
 +	LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger()
 +		<< " ================================= " << LL_ENDL;
 +	std::set<LLUUID> ais_items, local_items;
 +	const LLSD& cof_raw = content["cof_raw"];
 +	for (LLSD::array_const_iterator it = cof_raw.beginArray();
 +		it != cof_raw.endArray(); ++it)
 +	{
 +		const LLSD& item = *it;
 +		if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF())
 +		{
 +			ais_items.insert(item["item_id"].asUUID());
 +			if (item["type"].asInteger() == 24) // link
 +			{
 +				LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID()
 +					<< " linked_item_id: " << item["asset_id"].asUUID()
 +					<< " name: " << item["name"].asString()
 +					<< LL_ENDL; 
 +			}
 +			else if (item["type"].asInteger() == 25) // folder link
 +			{
 +				LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID()
 +					<< " linked_item_id: " << item["asset_id"].asUUID()
 +					<< " name: " << item["name"].asString()
 +					<< LL_ENDL; 
 +			}
 +			else
 +			{
 +				LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID()
 +					<< " linked_item_id: " << item["asset_id"].asUUID()
 +					<< " name: " << item["name"].asString()
 +					<< " type: " << item["type"].asInteger()
 +					<< LL_ENDL; 
 +			}
 +		}
 +	}
 +	LL_INFOS("Avatar") << LL_ENDL;
 +	LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() 
 +		<< " ================================= " << LL_ENDL;
 +	LLInventoryModel::cat_array_t cat_array;
 +	LLInventoryModel::item_array_t item_array;
 +	gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(),
 +		cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH);
 +	for (S32 i=0; i<item_array.size(); i++)
 +	{
 +		const LLViewerInventoryItem* inv_item = item_array.at(i).get();
 +		local_items.insert(inv_item->getUUID());
 +		LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID()
 +			<< " linked_item_id: " << inv_item->getLinkedUUID()
 +			<< " name: " << inv_item->getName()
 +			<< " parent: " << inv_item->getParentUUID()
 +			<< LL_ENDL;
 +	}
 +	LL_INFOS("Avatar") << " ================================= " << LL_ENDL;
 +	S32 local_only = 0, ais_only = 0;
 +	for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it)
 +	{
 +		if (ais_items.find(*it) == ais_items.end())
 +		{
 +			LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL;
 +			local_only++;
 +		}
 +	}
 +	for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)
 +	{
 +		if (local_items.find(*it) == local_items.end())
 +		{
 +			LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL;
 +			ais_only++;
 +		}
 +	}
 +	if (local_only==0 && ais_only==0)
 +	{
 +		LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req "
 +			<< content["observed"].asInteger()
 +			<< " rcv " << content["expected"].asInteger()
 +			<< ")" << LL_ENDL;
 +	}
 +}
 +
 +//=========================================================================
 +
 +
 +LLSD LLAppearanceMgr::dumpCOF() const
 +{
 +	LLSD links = LLSD::emptyArray();
 +	LLMD5 md5;
 +	
 +	LLInventoryModel::cat_array_t cat_array;
 +	LLInventoryModel::item_array_t item_array;
 +	gInventory.collectDescendents(getCOF(),cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH);
 +	for (S32 i=0; i<item_array.size(); i++)
 +	{
 +		const LLViewerInventoryItem* inv_item = item_array.at(i).get();
 +		LLSD item;
 +		LLUUID item_id(inv_item->getUUID());
 +		md5.update((unsigned char*)item_id.mData, 16);
 +		item["description"] = inv_item->getActualDescription();
 +		md5.update(inv_item->getActualDescription());
 +		item["asset_type"] = inv_item->getActualType();
 +		LLUUID linked_id(inv_item->getLinkedUUID());
 +		item["linked_id"] = linked_id;
 +		md5.update((unsigned char*)linked_id.mData, 16);
 +
 +		if (LLAssetType::AT_LINK == inv_item->getActualType())
 +		{
 +			const LLViewerInventoryItem* linked_item = inv_item->getLinkedItem();
 +			if (NULL == linked_item)
 +			{
 +				LL_WARNS() << "Broken link for item '" << inv_item->getName()
 +						<< "' (" << inv_item->getUUID()
 +						<< ") during requestServerAppearanceUpdate" << LL_ENDL;
 +				continue;
 +			}
 +			// Some assets may be 'hidden' and show up as null in the viewer.
 +			//if (linked_item->getAssetUUID().isNull())
 +			//{
 +			//	LL_WARNS() << "Broken link (null asset) for item '" << inv_item->getName()
 +			//			<< "' (" << inv_item->getUUID()
 +			//			<< ") during requestServerAppearanceUpdate" << LL_ENDL;
 +			//	continue;
 +			//}
 +			LLUUID linked_asset_id(linked_item->getAssetUUID());
 +			md5.update((unsigned char*)linked_asset_id.mData, 16);
 +			U32 flags = linked_item->getFlags();
 +			md5.update(boost::lexical_cast<std::string>(flags));
 +		}
 +		else if (LLAssetType::AT_LINK_FOLDER != inv_item->getActualType())
 +		{
 +			LL_WARNS() << "Non-link item '" << inv_item->getName()
 +					<< "' (" << inv_item->getUUID()
 +					<< ") type " << (S32) inv_item->getActualType()
 +					<< " during requestServerAppearanceUpdate" << LL_ENDL;
 +			continue;
 +		}
 +		links.append(item);
 +	}
 +	LLSD result = LLSD::emptyMap();
 +	result["cof_contents"] = links;
 +	char cof_md5sum[MD5HEX_STR_SIZE];
 +	md5.finalize();
 +	md5.hex_digest(cof_md5sum);
 +	result["cof_md5sum"] = std::string(cof_md5sum);
 +	return result;
 +}
 +
 +void LLAppearanceMgr::requestServerAppearanceUpdate()
 +{
 +
 +	if (!testCOFRequestVersion())
 +	{
 +		// *TODO: LL_LOG message here
 +		return;
 +	}
 +
 +	if ((mInFlightCounter > 0) && (mInFlightTimer.hasExpired()))
 +	{
 +		LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL;
 +		mInFlightCounter = 0;
 +	}
 +
 +	if (gAgentAvatarp->isEditingAppearance())
 +	{
 +		LL_WARNS("Avatar") << "Avatar editing appeance, not sending request." << LL_ENDL;
 +		// don't send out appearance updates if in appearance editing mode
 +		return;
 +	}
 +
 +	if (!gAgent.getRegion())
 +	{
 +		LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL;
 +		return;
 +	}
 +	if (gAgent.getRegion()->getCentralBakeVersion() == 0)
 +	{
 +		LL_WARNS("Avatar") << "Region does not support baking" << LL_ENDL;
 +	}
 +	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");
 +	if (url.empty())
 +	{
 +		LL_WARNS("Avatar") << "No cap for UpdateAvatarAppearance." << LL_ENDL;
 +		return;
 +	}
 +
 +	LLSD postData;
 +	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion();
 +	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
 +	{
 +		postData = LLAppearanceMgr::instance().dumpCOF();
 +	}
 +	else
 +	{
 +		postData["cof_version"] = cof_version;
 +		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
 +		{
 +			postData["cof_version"] = cof_version + 999;
 +		}
 +	}
 +	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL;
 +
 +	LLAppearanceMgrHttpHandler * handler = new LLAppearanceMgrHttpHandler(url, this);
 +
 +	mInFlightCounter++;
 +	mInFlightTimer.setTimerExpirySec(60.0);
 +
 +	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
 +	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
 +
 +	LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
 +		mHttpPolicy, mHttpPriority, url,
 +		postData, mHttpOptions, mHttpHeaders, handler);
 +
 +	if (handle == LLCORE_HTTP_HANDLE_INVALID)
 +	{
 +		delete handler; +		LLCore::HttpStatus status = mHttpRequest->getStatus(); +		LL_WARNS("Avatar") << "Appearance request post failed Reason " << status.toTerseString()
 +			<< " \"" << status.toString() << "\"" << LL_ENDL;
 +	}
 +}
 +
 +bool LLAppearanceMgr::testCOFRequestVersion() const
 +{
 +	// If we have already received an update for this or higher cof version, ignore.
 +	S32 cof_version = getCOFVersion();
 +	S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion;
 +	S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion;
 +
 +	LL_DEBUGS("Avatar") << "cof_version " << cof_version
 +		<< " last_rcv " << last_rcv
 +		<< " last_req " << last_req
 +		<< " in flight " << mInFlightCounter 
 +		<< LL_ENDL;
 +	if (cof_version < last_rcv)
 +	{
 +		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv
 +			<< " will not request for " << cof_version << LL_ENDL;
 +		return false;
 +	}
 +	if (/*mInFlightCounter > 0 &&*/ last_req >= cof_version)
 +	{
 +		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req
 +			<< " will not request for " << cof_version << LL_ENDL;
 +		return false;
 +	}
 +
 +	// Actually send the request.
 +	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL;
 +	return true;
 +}
 +
 +bool LLAppearanceMgr::onIdle() +{ +	if (!LLAppearanceMgr::mActive)  		return true; -	} -}; - -LLAppearanceHandler gAppearanceHandler; - - -LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name) -{ -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	LLNameCategoryCollector has_name(name); -	gInventory.collectDescendentsIf(parent_id, -									cat_array, -									item_array, -									LLInventoryModel::EXCLUDE_TRASH, -									has_name); -	if (0 == cat_array.size()) -		return LLUUID(); -	else -	{ -		LLViewerInventoryCategory *cat = cat_array.at(0); -		if (cat) -			return cat->getUUID(); -		else -		{ -			LL_WARNS() << "null cat" << LL_ENDL; -			return LLUUID(); -		} -	} -} - -// We want this to be much lower (e.g. 15.0 is usually fine), bumping -// up for now until we can diagnose some cases of very slow response -// to requests. -const F32 DEFAULT_RETRY_AFTER_INTERVAL = 300.0; - -// Given the current back-end problems, retrying is causing too many -// duplicate items. Bump this back to 2 once they are resolved (or can -// leave at 0 if the operations become actually reliable). -const S32 DEFAULT_MAX_RETRIES = 0; - -class LLCallAfterInventoryBatchMgr: public LLEventTimer  -{ -public: -	LLCallAfterInventoryBatchMgr(const LLUUID& dst_cat_id, -								 const std::string& phase_name, -								 nullary_func_t on_completion_func, -								 nullary_func_t on_failure_func = no_op, -								 F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, -								 S32 max_retries = DEFAULT_MAX_RETRIES -		): -		mDstCatID(dst_cat_id), -		mTrackingPhase(phase_name), -		mOnCompletionFunc(on_completion_func), -		mOnFailureFunc(on_failure_func), -		mRetryAfter(retry_after), -		mMaxRetries(max_retries), -		mPendingRequests(0), -		mFailCount(0), -		mCompletionOrFailureCalled(false), -		mRetryCount(0), -		LLEventTimer(5.0) -	{ -		if (!mTrackingPhase.empty()) -		{ -			selfStartPhase(mTrackingPhase); -		} -	} - -	void addItems(LLInventoryModel::item_array_t& src_items) -	{ -		for (LLInventoryModel::item_array_t::const_iterator it = src_items.begin(); -			 it != src_items.end(); -			 ++it) -		{ -			LLViewerInventoryItem* item = *it; -			llassert(item); -			addItem(item->getUUID()); -		} -	} - -	// Request or re-request operation for specified item. -	void addItem(const LLUUID& item_id) -	{ -		LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL; -		if (!requestOperation(item_id)) -		{ -			LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL; -			return; -		} - -		mPendingRequests++; -		// On a re-request, this will reset the timer. -		mWaitTimes[item_id] = LLTimer(); -		if (mRetryCounts.find(item_id) == mRetryCounts.end()) -		{ -			mRetryCounts[item_id] = 0; -		} -		else -		{ -			mRetryCounts[item_id]++; -		} -	} - -	virtual bool requestOperation(const LLUUID& item_id) = 0; - -	void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp) -	{ -		if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) -		{ -			LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL; -			doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp), -							mRetryAfter); -			return; -		} -		mPendingRequests--; -		F32 elapsed = timestamp.getElapsedTimeF32(); -		LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << LL_ENDL; -		if (mWaitTimes.find(src_id) == mWaitTimes.end()) -		{ -			// No longer waiting for this item - either serviced -			// already or gave up after too many retries. -			LL_WARNS() << "duplicate or late operation, src_id " << src_id << "dst_id " << dst_id -					<< " elapsed " << elapsed << " after end " << (S32) mCompletionOrFailureCalled << LL_ENDL; -		} -		mTimeStats.push(elapsed); -		mWaitTimes.erase(src_id); -		if (mWaitTimes.empty() && !mCompletionOrFailureCalled) -		{ -			onCompletionOrFailure(); -		} -	} - -	void onCompletionOrFailure() -	{ -		assert (!mCompletionOrFailureCalled); -		mCompletionOrFailureCalled = true; -		 -		// Will never call onCompletion() if any item has been flagged as -		// a failure - otherwise could wind up with corrupted -		// outfit, involuntary nudity, etc. -		reportStats(); -		if (!mTrackingPhase.empty()) -		{ -			selfStopPhase(mTrackingPhase); -		} -		if (!mFailCount) -		{ -			onCompletion(); -		} -		else -		{ -			onFailure(); -		} -	} - -	void onFailure() -	{ -		LL_INFOS() << "failed" << LL_ENDL; -		mOnFailureFunc(); -	} - -	void onCompletion() -	{ -		LL_INFOS() << "done" << LL_ENDL; -		mOnCompletionFunc(); -	} -	 -	// virtual -	// Will be deleted after returning true - only safe to do this if all callbacks have fired. -	BOOL tick() -	{ -		// mPendingRequests will be zero if all requests have been -		// responded to.  mWaitTimes.empty() will be true if we have -		// received at least one reply for each UUID.  If requests -		// have been dropped and retried, these will not necessarily -		// be the same.  Only safe to return true if all requests have -		// been serviced, since it will result in this object being -		// deleted. -		bool all_done = (mPendingRequests==0); - -		if (!mWaitTimes.empty()) -		{ -			LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; -			for (std::map<LLUUID,LLTimer>::iterator it = mWaitTimes.begin(); -				 it != mWaitTimes.end();) -			{ -				// Use a copy of iterator because it may be erased/invalidated. -				std::map<LLUUID,LLTimer>::iterator curr_it = it; -				++it; -				 -				F32 time_waited = curr_it->second.getElapsedTimeF32(); -				S32 retries = mRetryCounts[curr_it->first]; -				if (time_waited > mRetryAfter) -				{ -					if (retries < mMaxRetries) -					{ -						LL_DEBUGS("Avatar") << "Waited " << time_waited << -							" for " << curr_it->first << ", retrying" << LL_ENDL; -						mRetryCount++; -						addItem(curr_it->first); -					} -					else -					{ -						LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL; -						mWaitTimes.erase(curr_it); -						mFailCount++; -					} -				} -				if (mWaitTimes.empty()) -				{ -					onCompletionOrFailure(); -				} - -			} -		} -		return all_done; -	} - -	void reportStats() -	{ -		LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << LL_ENDL; -		LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << LL_ENDL; -		LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << LL_ENDL; -		LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL; -		LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL; -	} -	 -	virtual ~LLCallAfterInventoryBatchMgr() -	{ -		LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; -	} - -protected: -	std::string mTrackingPhase; -	std::map<LLUUID,LLTimer> mWaitTimes; -	std::map<LLUUID,S32> mRetryCounts; -	LLUUID mDstCatID; -	nullary_func_t mOnCompletionFunc; -	nullary_func_t mOnFailureFunc; -	F32 mRetryAfter; -	S32 mMaxRetries; -	S32 mPendingRequests; -	S32 mFailCount; -	S32 mRetryCount; -	bool mCompletionOrFailureCalled; -	LLViewerStats::StatsAccumulator mTimeStats; -}; - -class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr -{ -public: -	LLCallAfterInventoryCopyMgr(LLInventoryModel::item_array_t& src_items, -								const LLUUID& dst_cat_id, -								const std::string& phase_name, -								nullary_func_t on_completion_func, -								nullary_func_t on_failure_func = no_op, -								 F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, -								 S32 max_retries = DEFAULT_MAX_RETRIES -		): -		LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) -	{ -		addItems(src_items); -		sInstanceCount++; -	} - -	~LLCallAfterInventoryCopyMgr() -	{ -		sInstanceCount--; -	} -	 -	virtual bool requestOperation(const LLUUID& item_id) -	{ -		LLViewerInventoryItem *item = gInventory.getItem(item_id); -		llassert(item); -		LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL; -		if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) -		{ -			LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; -			return true; -		} -		copy_inventory_item( -			gAgent.getID(), -			item->getPermissions().getOwner(), -			item->getUUID(), -			mDstCatID, -			std::string(), -			new LLBoostFuncInventoryCallback(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer())) -			); -		return true; -	} - -	static S32 getInstanceCount() { return sInstanceCount; } -	 -private: -	static S32 sInstanceCount; -}; - -S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; - -class LLWearCategoryAfterCopy: public LLInventoryCallback -{ -public: -	LLWearCategoryAfterCopy(bool append): -		mAppend(append) -	{} - -	// virtual -	void fire(const LLUUID& id) -	{ -		// Wear the inventory category. -		LLInventoryCategory* cat = gInventory.getCategory(id); -		LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend); -	} - -private: -	bool mAppend; -}; - -class LLTrackPhaseWrapper : public LLInventoryCallback -{ -public: -	LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL): -		mTrackingPhase(phase_name), -		mCB(cb) -	{ -		selfStartPhase(mTrackingPhase); -	} - -	// virtual -	void fire(const LLUUID& id) -	{ -		if (mCB) -		{ -			mCB->fire(id); -		} -	} - -	// virtual -	~LLTrackPhaseWrapper() -	{ -		selfStopPhase(mTrackingPhase); -	} - -protected: -	std::string mTrackingPhase; -	LLPointer<LLInventoryCallback> mCB; -}; - -LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions, -														 bool enforce_ordering, -														 nullary_func_t post_update_func  -	): -	mFireCount(0), -	mEnforceItemRestrictions(enforce_item_restrictions), -	mEnforceOrdering(enforce_ordering), -	mPostUpdateFunc(post_update_func) -{ -	selfStartPhase("update_appearance_on_destroy"); -} - -void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) -{ -	LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); -	const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD -	LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; -#endif -	mFireCount++; -} - -LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() -{ -	if (!LLApp::isExiting()) -	{ -		// speculative fix for MAINT-1150 -		LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL; - -		selfStopPhase("update_appearance_on_destroy"); - -		LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, -															mEnforceOrdering, -															mPostUpdateFunc); -	} -} - -LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id): -	mItemID(item_id) -{ -} - -void edit_wearable_and_customize_avatar(LLUUID item_id) -{ -	// Start editing the item if previously requested. -	gAgentWearables.editWearableIfRequested(item_id); -	 -	// TODO: camera mode may not be changed if a debug setting is tweaked -	if( gAgentCamera.cameraCustomizeAvatar() ) -	{ -		// If we're in appearance editing mode, the current tab may need to be refreshed -		LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>( -			LLFloaterSidePanelContainer::getPanel("appearance")); -		if (panel) -		{ -			panel->showDefaultSubpart(); -		} -	} -} - -LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy() -{ -	if (!LLApp::isExiting()) -	{ -		LLAppearanceMgr::instance().updateAppearanceFromCOF( -			true,true, -			boost::bind(edit_wearable_and_customize_avatar, mItemID)); -	} -} - - -struct LLFoundData -{ -	LLFoundData() : -		mAssetType(LLAssetType::AT_NONE), -		mWearableType(LLWearableType::WT_INVALID), -		mWearable(NULL) {} - -	LLFoundData(const LLUUID& item_id, -				const LLUUID& asset_id, -				const std::string& name, -				const LLAssetType::EType& asset_type, -				const LLWearableType::EType& wearable_type, -				const bool is_replacement = false -		) : -		mItemID(item_id), -		mAssetID(asset_id), -		mName(name), -		mAssetType(asset_type), -		mWearableType(wearable_type), -		mIsReplacement(is_replacement), -		mWearable( NULL ) {} -	 -	LLUUID mItemID; -	LLUUID mAssetID; -	std::string mName; -	LLAssetType::EType mAssetType; -	LLWearableType::EType mWearableType; -	LLViewerWearable* mWearable; -	bool mIsReplacement; -}; - -	 -class LLWearableHoldingPattern -{ -	LOG_CLASS(LLWearableHoldingPattern); - -public: -	LLWearableHoldingPattern(); -	~LLWearableHoldingPattern(); - -	bool pollFetchCompletion(); -	void onFetchCompletion(); -	bool isFetchCompleted(); -	bool isTimedOut(); - -	void checkMissingWearables(); -	bool pollMissingWearables(); -	bool isMissingCompleted(); -	void recoverMissingWearable(LLWearableType::EType type); -	void clearCOFLinksForMissingWearables(); -	 -	void onWearableAssetFetch(LLViewerWearable *wearable); -	void onAllComplete(); - -	typedef std::list<LLFoundData> found_list_t; -	found_list_t& getFoundList(); -	void eraseTypeToLink(LLWearableType::EType type); -	void eraseTypeToRecover(LLWearableType::EType type); -	void setObjItems(const LLInventoryModel::item_array_t& items); -	void setGestItems(const LLInventoryModel::item_array_t& items); -	bool isMostRecent(); -	void handleLateArrivals(); -	void resetTime(F32 timeout); -	static S32 countActive() { return sActiveHoldingPatterns.size(); } -	S32 index() { return mIndex; } -	 -private: -	found_list_t mFoundList; -	LLInventoryModel::item_array_t mObjItems; -	LLInventoryModel::item_array_t mGestItems; -	typedef std::set<S32> type_set_t; -	type_set_t mTypesToRecover; -	type_set_t mTypesToLink; -	S32 mResolved; -	LLTimer mWaitTime; -	bool mFired; -	typedef std::set<LLWearableHoldingPattern*> type_set_hp; -	static type_set_hp sActiveHoldingPatterns; -	static S32 sNextIndex; -	S32 mIndex; -	bool mIsMostRecent; -	std::set<LLViewerWearable*> mLateArrivals; -	bool mIsAllComplete; -}; - -LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns; -S32 LLWearableHoldingPattern::sNextIndex = 0; - -LLWearableHoldingPattern::LLWearableHoldingPattern(): -	mResolved(0), -	mFired(false), -	mIsMostRecent(true), -	mIsAllComplete(false) -{ -	if (countActive()>0) -	{ -		LL_INFOS() << "Creating LLWearableHoldingPattern when " -				   << countActive() -				   << " other attempts are active." -				   << " Flagging others as invalid." -				   << LL_ENDL; -		for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); -			 it != sActiveHoldingPatterns.end(); -			 ++it) -		{ -			(*it)->mIsMostRecent = false; -		} -			  -	} -	mIndex = sNextIndex++; -	sActiveHoldingPatterns.insert(this); -	LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL; -	selfStartPhase("holding_pattern"); -} - -LLWearableHoldingPattern::~LLWearableHoldingPattern() -{ -	sActiveHoldingPatterns.erase(this); -	if (isMostRecent()) -	{ -		selfStopPhase("holding_pattern"); -	} -	LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL; -} - -bool LLWearableHoldingPattern::isMostRecent() -{ -	return mIsMostRecent; -} - -LLWearableHoldingPattern::found_list_t& LLWearableHoldingPattern::getFoundList() -{ -	return mFoundList; -} - -void LLWearableHoldingPattern::eraseTypeToLink(LLWearableType::EType type) -{ -	mTypesToLink.erase(type); -} - -void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type) -{ -	mTypesToRecover.erase(type); -} - -void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items) -{ -	mObjItems = items; -} - -void LLWearableHoldingPattern::setGestItems(const LLInventoryModel::item_array_t& items) -{ -	mGestItems = items; -} - -bool LLWearableHoldingPattern::isFetchCompleted() -{ -	return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for? -} - -bool LLWearableHoldingPattern::isTimedOut() -{ -	return mWaitTime.hasExpired(); -} - -void LLWearableHoldingPattern::checkMissingWearables() -{ -	if (!isMostRecent()) -	{ -		// runway why don't we actually skip here? -		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -	} - -	std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0); -	std::vector<S32> requested_by_type(LLWearableType::WT_COUNT,0); -	for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) -	{ -		LLFoundData &data = *it; -		if (data.mWearableType < LLWearableType::WT_COUNT) -			requested_by_type[data.mWearableType]++; -		if (data.mWearable) -			found_by_type[data.mWearableType]++; -	} - -	for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type) -	{ -		if (requested_by_type[type] > found_by_type[type]) -		{ -			LL_WARNS() << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << LL_ENDL; -		} -		if (found_by_type[type] > 0) -			continue; -		if ( -			// If at least one wearable of certain types (pants/shirt/skirt) -			// was requested but none was found, create a default asset as a replacement. -			// In all other cases, don't do anything. -			// For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud  -			// due to logic in LLVOAvatarSelf::getIsCloud(). -			// For non-critical types (tatoo, socks, etc.) the wearable will just be missing. -			(requested_by_type[type] > 0) &&   -			((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT))) -		{ -			mTypesToRecover.insert(type); -			mTypesToLink.insert(type); -			recoverMissingWearable((LLWearableType::EType)type); -			LL_WARNS() << self_av_string() << "need to replace " << type << LL_ENDL;  -		} -	} - -	resetTime(60.0F); - -	if (isMostRecent()) -	{ -		selfStartPhase("get_missing_wearables_2"); -	} -	if (!pollMissingWearables()) -	{ -		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); -	} -} - -void LLWearableHoldingPattern::onAllComplete() -{ -	if (isAgentAvatarValid()) -	{ -		gAgentAvatarp->outputRezTiming("Agent wearables fetch complete"); -	} - -	if (!isMostRecent()) -	{ -		// runway need to skip here? -		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -	} - -	// Activate all gestures in this folder -	if (mGestItems.size() > 0) -	{ -		LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.size() << " gestures" << LL_ENDL; -		 -		LLGestureMgr::instance().activateGestures(mGestItems); -		 -		// Update the inventory item labels to reflect the fact -		// they are active. -		LLViewerInventoryCategory* catp = -			gInventory.getCategory(LLAppearanceMgr::instance().getCOF()); -		 -		if (catp) -		{ -			gInventory.updateCategory(catp); -			gInventory.notifyObservers(); -		} -	} - -	if (isAgentAvatarValid()) -	{ -		LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL; -		LLAgentWearables::llvo_vec_t objects_to_remove; -		LLAgentWearables::llvo_vec_t objects_to_retain; -		LLInventoryModel::item_array_t items_to_add; - -		LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems, -													   objects_to_remove, -													   objects_to_retain, -													   items_to_add); - -		LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() -							<< " attachments" << LL_ENDL; - -		// Here we remove the attachment pos overrides for *all* -		// attachments, even those that are not being removed. This is -		// needed to get joint positions all slammed down to their -		// pre-attachment states. -		gAgentAvatarp->clearAttachmentPosOverrides(); - -		// Take off the attachments that will no longer be in the outfit. -		LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); -		 -		// Update wearables. -		LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " -						   << mResolved << " wearable items " << LL_ENDL; -		LLAppearanceMgr::instance().updateAgentWearables(this); -		 -		// Restore attachment pos overrides for the attachments that -		// are remaining in the outfit. -		for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); -			 it != objects_to_retain.end(); -			 ++it) -		{ -			LLViewerObject *objectp = *it; -			gAgentAvatarp->addAttachmentPosOverridesForObject(objectp); -		} -		 -		// Add new attachments to match those requested. -		LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; -		LLAgentWearables::userAttachMultipleAttachments(items_to_add); -	} - -	if (isFetchCompleted() && isMissingCompleted()) -	{ -		// Only safe to delete if all wearable callbacks and all missing wearables completed. -		delete this; -	} -	else -	{ -		mIsAllComplete = true; -		handleLateArrivals(); -	} -} - -void LLWearableHoldingPattern::onFetchCompletion() -{ -	if (isMostRecent()) -	{ -		selfStopPhase("get_wearables_2"); -	} -		 -	if (!isMostRecent()) -	{ -		// runway skip here? -		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -	} - -	checkMissingWearables(); -} - -// Runs as an idle callback until all wearables are fetched (or we time out). -bool LLWearableHoldingPattern::pollFetchCompletion() -{ -	if (!isMostRecent()) -	{ -		// runway skip here? -		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -	} - -	bool completed = isFetchCompleted(); -	bool timed_out = isTimedOut(); -	bool done = completed || timed_out; - -	if (done) -	{ -		LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out -				<< " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; - -		mFired = true; -		 -		if (timed_out) -		{ -			LL_WARNS() << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << LL_ENDL; -		} - -		onFetchCompletion(); -	} -	return done; -} - -void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder) -{ -	if (!holder->isMostRecent()) -	{ -		LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -		// runway skip here? -	} - -	LL_INFOS() << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; -	holder->eraseTypeToLink(type); -	// Add wearable to FoundData for actual wearing -	LLViewerInventoryItem *item = gInventory.getItem(item_id); -	LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - -	if (linked_item) -	{ -		gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); -			 -		if (item) -		{ -			LLFoundData found(linked_item->getUUID(), -							  linked_item->getAssetUUID(), -							  linked_item->getName(), -							  linked_item->getType(), -							  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, -							  true // is replacement -				); -			found.mWearable = wearable; -			holder->getFoundList().push_front(found); -		} -		else -		{ -			LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL; -		} -	} -	else -	{ -		LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; -	} -} - -void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder) -{ -	if (!holder->isMostRecent()) -	{ -		// runway skip here? -		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -	} - -	LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; -	LLConstPointer<LLInventoryObject> itemp = gInventory.getItem(item_id); -	wearable->setItemID(item_id); -	holder->eraseTypeToRecover(type); -	llassert(itemp); -	if (itemp) -	{ -		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); - -		link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb); -	} -} - -void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type) -{ -	if (!isMostRecent()) -	{ -		// runway skip here? -		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -	} -	 -		// Try to recover by replacing missing wearable with a new one. -	LLNotificationsUtil::add("ReplacedMissingWearable"); -	LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) -				<< " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL; -	LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); - -	// Add a new one in the lost and found folder. -	const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); -	LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_cb,_1,type,wearable,this)); - -	create_inventory_item(gAgent.getID(), -						  gAgent.getSessionID(), -						  lost_and_found_id, -						  wearable->getTransactionID(), -						  wearable->getName(), -						  wearable->getDescription(), -						  wearable->getAssetType(), -						  LLInventoryType::IT_WEARABLE, -						  wearable->getType(), -						  wearable->getPermissions().getMaskNextOwner(), -						  cb); -} - -bool LLWearableHoldingPattern::isMissingCompleted() -{ -	return mTypesToLink.size()==0 && mTypesToRecover.size()==0; -} - -void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() -{ -	for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) -	{ -		LLFoundData &data = *it; -		if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) -		{ -			// Wearable link that was never resolved; remove links to it from COF -			LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; -			LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); -		} -	} -} - -bool LLWearableHoldingPattern::pollMissingWearables() -{ -	if (!isMostRecent()) -	{ -		// runway skip here? -		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -	} -	 -	bool timed_out = isTimedOut(); -	bool missing_completed = isMissingCompleted(); -	bool done = timed_out || missing_completed; - -	if (!done) -	{ -		LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size() -				<< " links " << mTypesToLink.size() -				<< " wearables, timed out " << timed_out -				<< " elapsed " << mWaitTime.getElapsedTimeF32() -				<< " done " << done << LL_ENDL; -	} - -	if (done) -	{ -		if (isMostRecent()) -		{ -			selfStopPhase("get_missing_wearables_2"); -		} - -		gAgentAvatarp->debugWearablesLoaded(); - -		// BAP - if we don't call clearCOFLinksForMissingWearables() -		// here, we won't have to add the link back in later if the -		// wearable arrives late.  This is to avoid corruption of -		// wearable ordering info.  Also has the effect of making -		// unworn item links visible in the COF under some -		// circumstances. - -		//clearCOFLinksForMissingWearables(); -		onAllComplete(); -	} -	return done; -} - -// Handle wearables that arrived after the timeout period expired. -void LLWearableHoldingPattern::handleLateArrivals() -{ -	// Only safe to run if we have previously finished the missing -	// wearables and other processing - otherwise we could be in some -	// intermediate state - but have not been superceded by a later -	// outfit change request. -	if (mLateArrivals.size() == 0) -	{ -		// Nothing to process. -		return; -	} -	if (!isMostRecent()) -	{ -		LL_WARNS() << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << LL_ENDL; -	} -	if (!mIsAllComplete) -	{ -		LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL; -	} - -	LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; - -	// Update mFoundList using late-arriving wearables. -	std::set<LLWearableType::EType> replaced_types; -	for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); -		 iter != getFoundList().end(); ++iter) -	{ -		LLFoundData& data = *iter; -		for (std::set<LLViewerWearable*>::iterator wear_it = mLateArrivals.begin(); -			 wear_it != mLateArrivals.end(); -			 ++wear_it) -		{ -			LLViewerWearable *wearable = *wear_it; - -			if(wearable->getAssetID() == data.mAssetID) -			{ -				data.mWearable = wearable; - -				replaced_types.insert(data.mWearableType); - -				// BAP - if we didn't call -				// clearCOFLinksForMissingWearables() earlier, we -				// don't need to restore the link here.  Fixes -				// wearable ordering problems. - -				// LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false); - -				// BAP failing this means inventory or asset server -				// are corrupted in a way we don't handle. -				llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType)); -				break; -			} -		} -	} - -	// Remove COF links for any default wearables previously used to replace the late arrivals. -	// All this pussyfooting around with a while loop and explicit -	// iterator incrementing is to allow removing items from the list -	// without clobbering the iterator we're using to navigate. -	LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); -	while (iter != getFoundList().end()) -	{ -		LLFoundData& data = *iter; - -		// If an item of this type has recently shown up, removed the corresponding replacement wearable from COF. -		if (data.mWearable && data.mIsReplacement && -			replaced_types.find(data.mWearableType) != replaced_types.end()) -		{ -			LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); -			std::list<LLFoundData>::iterator clobber_ator = iter; -			++iter; -			getFoundList().erase(clobber_ator); -		} -		else -		{ -			++iter; -		} -	} - -	// Clear contents of late arrivals. -	mLateArrivals.clear(); - -	// Update appearance based on mFoundList -	LLAppearanceMgr::instance().updateAgentWearables(this); -} - -void LLWearableHoldingPattern::resetTime(F32 timeout) -{ -	mWaitTime.reset(); -	mWaitTime.setTimerExpirySec(timeout); -} - -void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) -{ -	if (!isMostRecent()) -	{ -		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -	} -	 -	mResolved += 1;  // just counting callbacks, not successes. -	LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; -	if (!wearable) -	{ -		LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; -	} - -	if (mFired) -	{ -		LL_WARNS() << self_av_string() << "called after holder fired" << LL_ENDL; -		if (wearable) -		{ -			mLateArrivals.insert(wearable); -			if (mIsAllComplete) -			{ -				handleLateArrivals(); -			} -		} -		return; -	} - -	if (!wearable) -	{ -		return; -	} - -	for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); -		 iter != getFoundList().end(); ++iter) -	{ -		LLFoundData& data = *iter; -		if(wearable->getAssetID() == data.mAssetID) -		{ -			// Failing this means inventory or asset server are corrupted in a way we don't handle. -			if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) -			{ -				LL_WARNS() << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << LL_ENDL; -				break; -			} - -			data.mWearable = wearable; -		} -	} -} - -static void onWearableAssetFetch(LLViewerWearable* wearable, void* data) -{ -	LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; -	holder->onWearableAssetFetch(wearable); -} - - -static void removeDuplicateItems(LLInventoryModel::item_array_t& items) -{ -	LLInventoryModel::item_array_t new_items; -	std::set<LLUUID> items_seen; -	std::deque<LLViewerInventoryItem*> tmp_list; -	// Traverse from the front and keep the first of each item -	// encountered, so we actually keep the *last* of each duplicate -	// item.  This is needed to give the right priority when adding -	// duplicate items to an existing outfit. -	for (S32 i=items.size()-1; i>=0; i--) -	{ -		LLViewerInventoryItem *item = items.at(i); -		LLUUID item_id = item->getLinkedUUID(); -		if (items_seen.find(item_id)!=items_seen.end()) -			continue; -		items_seen.insert(item_id); -		tmp_list.push_front(item); -	} -	for (std::deque<LLViewerInventoryItem*>::iterator it = tmp_list.begin(); -		 it != tmp_list.end(); -		 ++it) -	{ -		new_items.push_back(*it); -	} -	items = new_items; -} - -const LLUUID LLAppearanceMgr::getCOF() const -{ -	return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); -} - -S32 LLAppearanceMgr::getCOFVersion() const -{ -	LLViewerInventoryCategory *cof = gInventory.getCategory(getCOF()); -	if (cof) -	{ -		return cof->getVersion(); -	} -	else -	{ -		return LLViewerInventoryCategory::VERSION_UNKNOWN; -	} -} - -const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() -{ -	const LLUUID& current_outfit_cat = getCOF(); -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	// Can't search on FT_OUTFIT since links to categories return FT_CATEGORY for type since they don't -	// return preferred type. -	LLIsType is_category( LLAssetType::AT_CATEGORY );  -	gInventory.collectDescendentsIf(current_outfit_cat, -									cat_array, -									item_array, -									false, -									is_category); -	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); -		 iter != item_array.end(); -		 iter++) -	{ -		const LLViewerInventoryItem *item = (*iter); -		const LLViewerInventoryCategory *cat = item->getLinkedCategory(); -		if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT) -		{ -			const LLUUID parent_id = cat->getParentUUID(); -			LLViewerInventoryCategory*  parent_cat =  gInventory.getCategory(parent_id); -			// if base outfit moved to trash it means that we don't have base outfit -			if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH) -			{ -				return NULL; -			} -			return item; -		} -	} -	return NULL; -} - -bool LLAppearanceMgr::getBaseOutfitName(std::string& name) -{ -	const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); -	if(outfit_link) -	{ -		const LLViewerInventoryCategory *cat = outfit_link->getLinkedCategory(); -		if (cat) -		{ -			name = cat->getName(); -			return true; -		} -	} +	mHttpRequest->update(0L);  	return false;  } - -const LLUUID LLAppearanceMgr::getBaseOutfitUUID() -{ -	const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); -	if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null; - -	const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory(); -	if (!outfit_cat) return LLUUID::null; - -	if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT) -	{ -		LL_WARNS() << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << LL_ENDL; -		return LLUUID::null; -	} - -	return outfit_cat->getUUID(); -} - -void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false) -{ -	if (inv_item.isNull()) -		return; -	 -	LLViewerInventoryItem *item = gInventory.getItem(inv_item); -	if (item) -	{ -		LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, do_replace); -	} -} - -bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, -									   bool do_update, -									   bool replace, -									   LLPointer<LLInventoryCallback> cb) -{ - -	if (item_id_to_wear.isNull()) return false; - -	// *TODO: issue with multi-wearable should be fixed: -	// in this case this method will be called N times - loading started for each item -	// and than N times will be called - loading completed for each item. -	// That means subscribers will be notified that loading is done after first item in a batch is worn. -	// (loading indicator disappears for example before all selected items are worn) -	// Have not fix this issue for 2.1 because of stability reason. EXT-7777. - -	// Disabled for now because it is *not* acceptable to call updateAppearanceFromCOF() multiple times -//	gAgentWearables.notifyLoadingStarted(); - -	LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear); -	if (!item_to_wear) return false; - -	if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID())) -	{ -		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace)); -		copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb); -		return false; -	}  -	else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) -	{ -		return false; // not in library and not in agent's inventory -	} -	else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) -	{ -		LLNotificationsUtil::add("CannotWearTrash"); -		return false; -	} -	else if (isLinkedInCOF(item_to_wear->getUUID())) // EXT-84911 -	{ -		return false; -	} - -	switch (item_to_wear->getType()) -	{ -		case LLAssetType::AT_CLOTHING: -		if (gAgentWearables.areWearablesLoaded()) -		{ -			if (!cb && do_update) -			{ -				cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); -			} -			S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType()); -			if ((replace && wearable_count != 0) || -				(wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) ) -			{ -				LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), -																   wearable_count-1); -				removeCOFItemLinks(item_id, cb); -			} - -			addCOFItemLink(item_to_wear, cb); -		}  -		break; - -		case LLAssetType::AT_BODYPART: -		// TODO: investigate wearables may not be loaded at this point EXT-8231 -		 -		// Remove the existing wearables of the same type. -		// Remove existing body parts anyway because we must not be able to wear e.g. two skins. -		removeCOFLinksOfType(item_to_wear->getWearableType()); -		if (!cb && do_update) -		{ -			cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); -		} -		addCOFItemLink(item_to_wear, cb); -		break; - -		case LLAssetType::AT_OBJECT: -		rez_attachment(item_to_wear, NULL, replace); -		break; - -		default: return false;; -	} - -	return true; -} - -// Update appearance from outfit folder. -void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool append) -{ -	if (!proceed) -		return; -	LLAppearanceMgr::instance().updateCOF(category,append); -} - -void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit) -{ -	LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit); -	wearInventoryCategory(cat, false, false); -} - -// Open outfit renaming dialog. -void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id) -{ -	LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id); -	if (!cat) -	{ -		return; -	} - -	LLSD args; -	args["NAME"] = cat->getName(); - -	LLSD payload; -	payload["cat_id"] = outfit_id; - -	LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2)); -} - -// User typed new outfit name. -// static -void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if (option != 0) return; // canceled - -	std::string outfit_name = response["new_name"].asString(); -	LLStringUtil::trim(outfit_name); -	if (!outfit_name.empty()) -	{ -		LLUUID cat_id = notification["payload"]["cat_id"].asUUID(); -		rename_category(&gInventory, cat_id, outfit_name); -	} -} - -void LLAppearanceMgr::setOutfitLocked(bool locked) -{ -	if (mOutfitLocked == locked) -	{ -		return; -	} - -	mOutfitLocked = locked; -	if (locked) -	{ -		mUnlockOutfitTimer->reset(); -		mUnlockOutfitTimer->start(); -	} -	else -	{ -		mUnlockOutfitTimer->stop(); -	} - -	LLOutfitObserver::instance().notifyOutfitLockChanged(); -} - -void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id) -{ -	LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); -	wearInventoryCategory(cat, false, true); -} - -void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) -{ -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); - -	gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); - -	LLInventoryModel::item_array_t::const_iterator it = items.begin(); -	const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); -	uuid_vec_t uuids_to_remove; -	for( ; it_end != it; ++it) -	{ -		LLViewerInventoryItem* item = *it; -		uuids_to_remove.push_back(item->getUUID()); -	} -	removeItemsFromAvatar(uuids_to_remove); - -	// deactivate all gestures in the outfit folder -	LLInventoryModel::item_array_t gest_items; -	getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE); -	for(S32 i = 0; i  < gest_items.size(); ++i) -	{ -		LLViewerInventoryItem *gest_item = gest_items[i]; -		if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) -		{ -			LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); -		} -	} -} - -// Create a copy of src_id + contents as a subfolder of dst_id. -void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, -											  LLPointer<LLInventoryCallback> cb) -{ -	LLInventoryCategory *src_cat = gInventory.getCategory(src_id); -	if (!src_cat) -	{ -		LL_WARNS() << "folder not found for src " << src_id.asString() << LL_ENDL; -		return; -	} -	LL_INFOS() << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << LL_ENDL; -	LLUUID parent_id = dst_id; -	if(parent_id.isNull()) -	{ -		parent_id = gInventory.getRootFolderID(); -	} -	LLUUID subfolder_id = gInventory.createNewCategory( parent_id, -														LLFolderType::FT_NONE, -														src_cat->getName()); -	shallowCopyCategoryContents(src_id, subfolder_id, cb); - -	gInventory.notifyObservers(); -} - -void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, -										bool include_folder_links, LLPointer<LLInventoryCallback> cb) -{ -	LLInventoryModel::cat_array_t* cats; -	LLInventoryModel::item_array_t* items; -	LLSD contents = LLSD::emptyArray(); -	gInventory.getDirectDescendentsOf(src_id, cats, items); -	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; -	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); -		 iter != items->end(); -		 ++iter) -	{ -		const LLViewerInventoryItem* item = (*iter); -		switch (item->getActualType()) -		{ -			case LLAssetType::AT_LINK: -			{ -				LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; -				//getActualDescription() is used for a new description  -				//to propagate ordering information saved in descriptions of links -				LLSD item_contents; -				item_contents["name"] = item->getName(); -				item_contents["desc"] = item->getActualDescription(); -				item_contents["linked_id"] = item->getLinkedUUID(); -				item_contents["type"] = LLAssetType::AT_LINK;  -				contents.append(item_contents); -				break; -			} -			case LLAssetType::AT_LINK_FOLDER: -			{ -				LLViewerInventoryCategory *catp = item->getLinkedCategory(); -				if (catp && include_folder_links) -				{ -					LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; -					LLSD base_contents; -					base_contents["name"] = catp->getName(); -					base_contents["desc"] = ""; // categories don't have descriptions. -					base_contents["linked_id"] = catp->getLinkedUUID(); -					base_contents["type"] = LLAssetType::AT_LINK_FOLDER;  -					contents.append(base_contents); -				} -				break; -			} -			default: -			{ -				// Linux refuses to compile unless all possible enums are handled. Really, Linux? -				break; -			} -		} -	} -	slam_inventory_folder(dst_id, contents, cb); -} -// Copy contents of src_id to dst_id. -void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, -													  LLPointer<LLInventoryCallback> cb) -{ -	LLInventoryModel::cat_array_t* cats; -	LLInventoryModel::item_array_t* items; -	gInventory.getDirectDescendentsOf(src_id, cats, items); -	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; -	LLInventoryObject::const_object_list_t link_array; -	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); -		 iter != items->end(); -		 ++iter) -	{ -		const LLViewerInventoryItem* item = (*iter); -		switch (item->getActualType()) -		{ -			case LLAssetType::AT_LINK: -			{ -				LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; -				link_array.push_back(LLConstPointer<LLInventoryObject>(item)); -				break; -			} -			case LLAssetType::AT_LINK_FOLDER: -			{ -				LLViewerInventoryCategory *catp = item->getLinkedCategory(); -				// Skip copying outfit links. -				if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) -				{ -					LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; -					link_array.push_back(LLConstPointer<LLInventoryObject>(item)); -				} -				break; -			} -			case LLAssetType::AT_CLOTHING: -			case LLAssetType::AT_OBJECT: -			case LLAssetType::AT_BODYPART: -			case LLAssetType::AT_GESTURE: -			{ -				LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL; -				copy_inventory_item(gAgent.getID(), -									item->getPermissions().getOwner(), -									item->getUUID(), -									dst_id, -									item->getName(), -									cb); -				break; -			} -			default: -				// Ignore non-outfit asset types -				break; -		} -	} -	if (!link_array.empty()) -	{ -		link_inventory_array(dst_id, link_array, cb); -	} -} - -BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) -{ -	// These are the wearable items that are required for considering this -	// folder as containing a complete outfit. -	U32 required_wearables = 0; -	required_wearables |= 1LL << LLWearableType::WT_SHAPE; -	required_wearables |= 1LL << LLWearableType::WT_SKIN; -	required_wearables |= 1LL << LLWearableType::WT_HAIR; -	required_wearables |= 1LL << LLWearableType::WT_EYES; - -	// These are the wearables that the folder actually contains. -	U32 folder_wearables = 0; -	LLInventoryModel::cat_array_t* cats; -	LLInventoryModel::item_array_t* items; -	gInventory.getDirectDescendentsOf(folder_id, cats, items); -	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); -		 iter != items->end(); -		 ++iter) -	{ -		const LLViewerInventoryItem* item = (*iter); -		if (item->isWearableType()) -		{ -			const LLWearableType::EType wearable_type = item->getWearableType(); -			folder_wearables |= 1LL << wearable_type; -		} -	} - -	// If the folder contains the required wearables, return TRUE. -	return ((required_wearables & folder_wearables) == required_wearables); -} - -bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) -{ -	// Disallow removing the base outfit. -	if (outfit_cat_id == getBaseOutfitUUID()) -	{ -		return false; -	} - -	// Check if the outfit folder itself is removable. -	if (!get_is_category_removable(&gInventory, outfit_cat_id)) -	{ -		return false; -	} - -	// Check for the folder's non-removable descendants. -	LLFindNonRemovableObjects filter_non_removable; -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	LLInventoryModel::item_array_t::const_iterator it; -	gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable); -	if (!cats.empty() || !items.empty()) -	{ -		return false; -	} - -	return true; -} - -// static -bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) -{ -	if (gAgentWearables.isCOFChangeInProgress()) -	{ -		return false; -	} - -	LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); -	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, is_worn); -} - -// static -bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) -{ -	if (gAgentWearables.isCOFChangeInProgress()) -	{ -		return false; -	} - -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); -	gInventory.collectDescendentsIf(outfit_cat_id, -		cats, -		items, -		LLInventoryModel::EXCLUDE_TRASH, -		not_worn); - -	return items.size() > 0; -} - -bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) -{ -	// Don't allow wearing anything while we're changing appearance. -	if (gAgentWearables.isCOFChangeInProgress()) -	{ -		return false; -	} - -	// Check whether it's the base outfit. -	if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID()) -	{ -		return false; -	} - -	// Check whether the outfit contains any wearables we aren't wearing already (STORM-702). -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); -	gInventory.collectDescendentsIf(outfit_cat_id, -		cats, -		items, -		LLInventoryModel::EXCLUDE_TRASH, -		is_worn); - -	return items.size() > 0; -} - -void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb) -{ -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	gInventory.collectDescendents(category, cats, items, -								  LLInventoryModel::EXCLUDE_TRASH); -	for (S32 i = 0; i < items.size(); ++i) -	{ -		LLViewerInventoryItem *item = items.at(i); -		if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) -			continue; -		LLViewerInventoryCategory* catp = item->getLinkedCategory(); -		if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) -		{ -			remove_inventory_item(item->getUUID(), cb); -		} -	} -} - -// Keep the last N wearables of each type.  For viewer 2.0, N is 1 for -// both body parts and clothing items. -void LLAppearanceMgr::filterWearableItems( -	LLInventoryModel::item_array_t& items, S32 max_per_type) -{ -	// Divvy items into arrays by wearable type. -	std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT); -	divvyWearablesByType(items, items_by_type); - -	// rebuild items list, retaining the last max_per_type of each array -	items.clear(); -	for (S32 i=0; i<LLWearableType::WT_COUNT; i++) -	{ -		S32 size = items_by_type[i].size(); -		if (size <= 0) -			continue; -		S32 start_index = llmax(0,size-max_per_type); -		for (S32 j = start_index; j<size; j++) -		{ -			items.push_back(items_by_type[i][j]); -		} -	} -} - -void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) -{ -	LLViewerInventoryCategory *pcat = gInventory.getCategory(category); -	if (!pcat) -	{ -		LL_WARNS() << "no category found for id " << category << LL_ENDL; -		return; -	} -	LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; - -	const LLUUID cof = getCOF(); - -	// Deactivate currently active gestures in the COF, if replacing outfit -	if (!append) -	{ -		LLInventoryModel::item_array_t gest_items; -		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); -		for(S32 i = 0; i  < gest_items.size(); ++i) -		{ -			LLViewerInventoryItem *gest_item = gest_items.at(i); -			if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) -			{ -				LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); -			} -		} -	} -	 -	// Collect and filter descendents to determine new COF contents. - -	// - Body parts: always include COF contents as a fallback in case any -	// required parts are missing. -	// Preserve body parts from COF if appending. -	LLInventoryModel::item_array_t body_items; -	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); -	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); -	if (append) -		reverse(body_items.begin(), body_items.end()); -	// Reduce body items to max of one per type. -	removeDuplicateItems(body_items); -	filterWearableItems(body_items, 1); - -	// - Wearables: include COF contents only if appending. -	LLInventoryModel::item_array_t wear_items; -	if (append) -		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); -	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); -	// Reduce wearables to max of one per type. -	removeDuplicateItems(wear_items); -	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); - -	// - Attachments: include COF contents only if appending. -	LLInventoryModel::item_array_t obj_items; -	if (append) -		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); -	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); -	removeDuplicateItems(obj_items); - -	// - Gestures: include COF contents only if appending. -	LLInventoryModel::item_array_t gest_items; -	if (append) -		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); -	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); -	removeDuplicateItems(gest_items); -	 -	// Create links to new COF contents. -	LLInventoryModel::item_array_t all_items; -	std::copy(body_items.begin(), body_items.end(), std::back_inserter(all_items)); -	std::copy(wear_items.begin(), wear_items.end(), std::back_inserter(all_items)); -	std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items)); -	std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); - -	// Find any wearables that need description set to enforce ordering. -	desc_map_t desc_map; -	getWearableOrderingDescUpdates(wear_items, desc_map); - -	// Will link all the above items. -	// link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). -	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); -	LLSD contents = LLSD::emptyArray(); - -	for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); -		 it != all_items.end(); ++it) -	{ -		LLSD item_contents; -		LLInventoryItem *item = *it; - -		std::string desc; -		desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID()); -		if (desc_iter != desc_map.end()) -		{ -			desc = desc_iter->second; -			LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc -								<< " (was: " << item->getActualDescription() << ")" << LL_ENDL; -		} -		else -		{ -			desc = item->getActualDescription(); -		} - -		item_contents["name"] = item->getName(); -		item_contents["desc"] = desc; -		item_contents["linked_id"] = item->getLinkedUUID(); -		item_contents["type"] = LLAssetType::AT_LINK;  -		contents.append(item_contents); -	} -	const LLUUID& base_id = append ? getBaseOutfitUUID() : category; -	LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); -	if (base_cat) -	{ -		LLSD base_contents; -		base_contents["name"] = base_cat->getName(); -		base_contents["desc"] = ""; -		base_contents["linked_id"] = base_cat->getLinkedUUID(); -		base_contents["type"] = LLAssetType::AT_LINK_FOLDER;  -		contents.append(base_contents); -	} -	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -	{ -		dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); -	} -	slam_inventory_folder(getCOF(), contents, link_waiter); - -	LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; -} - -void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) -{ -	LLSidepanelAppearance* panel_appearance = -		dynamic_cast<LLSidepanelAppearance *>(LLFloaterSidePanelContainer::getPanel("appearance")); -	if (panel_appearance) -	{ -		panel_appearance->refreshCurrentOutfitName(name); -	} -} - -void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter) -{ -	const LLUUID cof = getCOF(); -	LLViewerInventoryCategory* catp = gInventory.getCategory(category); -	std::string new_outfit_name = ""; - -	purgeBaseOutfitLink(cof, link_waiter); - -	if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) -	{ -		link_inventory_object(cof, catp, link_waiter); -		new_outfit_name = catp->getName(); -	} -	 -	updatePanelOutfitName(new_outfit_name); -} - -void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) -{ -	LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL; -	LLInventoryItem::item_array_t items; -	std::vector< LLViewerWearable* > wearables; -	wearables.reserve(32); - -	// For each wearable type, find the wearables of that type. -	for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) -	{ -		for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->getFoundList().begin(); -			 iter != holder->getFoundList().end(); ++iter) -		{ -			LLFoundData& data = *iter; -			LLViewerWearable* wearable = data.mWearable; -			if( wearable && ((S32)wearable->getType() == i) ) -			{ -				LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); -				if( item && (item->getAssetUUID() == wearable->getAssetID()) ) -				{ -					items.push_back(item); -					wearables.push_back(wearable); -				} -			} -		} -	} - -	if(wearables.size() > 0) -	{ -		gAgentWearables.setWearableOutfit(items, wearables); -	} -} - -S32 LLAppearanceMgr::countActiveHoldingPatterns() -{ -	return LLWearableHoldingPattern::countActive(); -} - -static void remove_non_link_items(LLInventoryModel::item_array_t &items) -{ -	LLInventoryModel::item_array_t pruned_items; -	for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); -		 iter != items.end(); -		 ++iter) -	{ - 		const LLViewerInventoryItem *item = (*iter); -		if (item && item->getIsLinkType()) -		{ -			pruned_items.push_back((*iter)); -		} -	} -	items = pruned_items; -} - -//a predicate for sorting inventory items by actual descriptions -bool sort_by_actual_description(const LLInventoryItem* item1, const LLInventoryItem* item2) -{ -	if (!item1 || !item2)  -	{ -		LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; -		return true; -	} - -	return item1->getActualDescription() < item2->getActualDescription(); -} - -void item_array_diff(LLInventoryModel::item_array_t& full_list, -					 LLInventoryModel::item_array_t& keep_list, -					 LLInventoryModel::item_array_t& kill_list) -	 -{ -	for (LLInventoryModel::item_array_t::iterator it = full_list.begin(); -		 it != full_list.end(); -		 ++it) -	{ -		LLViewerInventoryItem *item = *it; -		if (std::find(keep_list.begin(), keep_list.end(), item) == keep_list.end()) -		{ -			kill_list.push_back(item); -		} -	} -} - -S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, -												 LLAssetType::EType type, -												 S32 max_items, -												 LLInventoryObject::object_list_t& items_to_kill) -{ -	S32 to_kill_count = 0; - -	LLInventoryModel::item_array_t items; -	getDescendentsOfAssetType(cat_id, items, type); -	LLInventoryModel::item_array_t curr_items = items; -	removeDuplicateItems(items); -	if (max_items > 0) -	{ -		filterWearableItems(items, max_items); -	} -	LLInventoryModel::item_array_t kill_items; -	item_array_diff(curr_items,items,kill_items); -	for (LLInventoryModel::item_array_t::iterator it = kill_items.begin(); -		 it != kill_items.end(); -		 ++it) -	{ -		items_to_kill.push_back(LLPointer<LLInventoryObject>(*it)); -		to_kill_count++; -	} -	return to_kill_count; -} -	 - -void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id, -													LLInventoryObject::object_list_t& items_to_kill) -{ -	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, -							   1, items_to_kill); -	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, -							   LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); -	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, -							   -1, items_to_kill); -} - -void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb) -{ -	LLInventoryObject::object_list_t items_to_kill; -	findAllExcessOrDuplicateItems(getCOF(), items_to_kill); -	if (items_to_kill.size()>0) -	{ -		// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but -		// this should catch anything that gets through. -		remove_inventory_items(items_to_kill, cb); -	} -} - -void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, -											  bool enforce_ordering, -											  nullary_func_t post_update_func) -{ -	if (mIsInUpdateAppearanceFromCOF) -	{ -		LL_WARNS() << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << LL_ENDL; -		return; -	} - -	LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; - -	if (enforce_item_restrictions) -	{ -		// The point here is just to call -		// updateAppearanceFromCOF() again after excess items -		// have been removed. That time we will set -		// enforce_item_restrictions to false so we don't get -		// caught in a perpetual loop. -		LLPointer<LLInventoryCallback> cb( -			new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func)); -		enforceCOFItemRestrictions(cb); -		return; -	} - -	if (enforce_ordering) -	{ -		//checking integrity of the COF in terms of ordering of wearables,  -		//checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) - -		// As with enforce_item_restrictions handling above, we want -		// to wait for the update callbacks, then (finally!) call -		// updateAppearanceFromCOF() with no additional COF munging needed. -		LLPointer<LLInventoryCallback> cb( -			new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); -		updateClothingOrderingInfo(LLUUID::null, cb); -		return; -	} - -	if (!validateClothingOrderingInfo()) -	{ -		LL_WARNS() << "Clothing ordering error" << LL_ENDL; -	} - -	BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); -	selfStartPhase("update_appearance_from_cof"); - -	// update dirty flag to see if the state of the COF matches -	// the saved outfit stored as a folder link -	updateIsDirty(); - -	// Send server request for appearance update -	if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) -	{ -		requestServerAppearanceUpdate(); -	} - -	LLUUID current_outfit_id = getCOF(); - -	// Find all the wearables that are in the COF's subtree. -	LL_DEBUGS() << "LLAppearanceMgr::updateFromCOF()" << LL_ENDL; -	LLInventoryModel::item_array_t wear_items; -	LLInventoryModel::item_array_t obj_items; -	LLInventoryModel::item_array_t gest_items; -	getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items); -	// Get rid of non-links in case somehow the COF was corrupted. -	remove_non_link_items(wear_items); -	remove_non_link_items(obj_items); -	remove_non_link_items(gest_items); - -	dumpItemArray(wear_items,"asset_dump: wear_item"); -	dumpItemArray(obj_items,"asset_dump: obj_item"); - -	LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); -	if (!gInventory.isCategoryComplete(current_outfit_id)) -	{ -		LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() -				<< " descendent_count " << cof->getDescendentCount() -				<< " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; -	} -	if(!wear_items.size()) -	{ -		LLNotificationsUtil::add("CouldNotPutOnOutfit"); -		return; -	} - -	//preparing the list of wearables in the correct order for LLAgentWearables -	sortItemsByActualDescription(wear_items); - - -	LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; -	LLTimer hp_block_timer; -	LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; - -	holder->setObjItems(obj_items); -	holder->setGestItems(gest_items); -		 -	// Note: can't do normal iteration, because if all the -	// wearables can be resolved immediately, then the -	// callback will be called (and this object deleted) -	// before the final getNextData(). - -	for(S32 i = 0; i  < wear_items.size(); ++i) -	{ -		LLViewerInventoryItem *item = wear_items.at(i); -		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - -		// Fault injection: use debug setting to test asset  -		// fetch failures (should be replaced by new defaults in -		// lost&found). -		U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); - -		if (item && item->getIsLinkType() && linked_item) -		{ -			LLFoundData found(linked_item->getUUID(), -							  linked_item->getAssetUUID(), -							  linked_item->getName(), -							  linked_item->getType(), -							  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID -				); - -			if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) -			{ -				found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB -			} -			//pushing back, not front, to preserve order of wearables for LLAgentWearables -			holder->getFoundList().push_back(found); -		} -		else -		{ -			if (!item) -			{ -				LL_WARNS() << "Attempt to wear a null item " << LL_ENDL; -			} -			else if (!linked_item) -			{ -				LL_WARNS() << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << LL_ENDL; -			} -		} -	} - -	selfStartPhase("get_wearables_2"); - -	for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); -		 it != holder->getFoundList().end(); ++it) -	{ -		LLFoundData& found = *it; - -		LL_DEBUGS() << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << LL_ENDL; - -		// Fetch the wearables about to be worn. -		LLWearableList::instance().getAsset(found.mAssetID, -											found.mName, -											gAgentAvatarp, -											found.mAssetType, -											onWearableAssetFetch, -											(void*)holder); - -	} - -	holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime")); -	if (!holder->pollFetchCompletion()) -	{ -		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); -	} -	post_update_func(); - -	LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL; -} - -void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category, -													LLInventoryModel::item_array_t& items, -													LLAssetType::EType type) -{ -	LLInventoryModel::cat_array_t cats; -	LLIsType is_of_type(type); -	gInventory.collectDescendentsIf(category, -									cats, -									items, -									LLInventoryModel::EXCLUDE_TRASH, -									is_of_type); -} - -void LLAppearanceMgr::getUserDescendents(const LLUUID& category,  -											 LLInventoryModel::item_array_t& wear_items, -											 LLInventoryModel::item_array_t& obj_items, -											 LLInventoryModel::item_array_t& gest_items) -{ -	LLInventoryModel::cat_array_t wear_cats; -	LLFindWearables is_wearable; -	gInventory.collectDescendentsIf(category, -									wear_cats, -									wear_items, -									LLInventoryModel::EXCLUDE_TRASH, -									is_wearable); - -	LLInventoryModel::cat_array_t obj_cats; -	LLIsType is_object( LLAssetType::AT_OBJECT ); -	gInventory.collectDescendentsIf(category, -									obj_cats, -									obj_items, -									LLInventoryModel::EXCLUDE_TRASH, -									is_object); - -	// Find all gestures in this folder -	LLInventoryModel::cat_array_t gest_cats; -	LLIsType is_gesture( LLAssetType::AT_GESTURE ); -	gInventory.collectDescendentsIf(category, -									gest_cats, -									gest_items, -									LLInventoryModel::EXCLUDE_TRASH, -									is_gesture); -} - -void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) -{ -	if(!category) return; - -	selfClearPhases(); -	selfStartPhase("wear_inventory_category"); - -	gAgentWearables.notifyLoadingStarted(); - -	LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() -			 << " )" << LL_ENDL; - -	// If we are copying from library, attempt to use AIS to copy the category. -	bool ais_ran=false; -	if (copy && AISCommand::isAPIAvailable()) -	{ -		LLUUID parent_id; -		parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); -		if (parent_id.isNull()) -		{ -			parent_id = gInventory.getRootFolderID(); -		} - -		LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append); -		LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper( -													std::string("wear_inventory_category_callback"), copy_cb); -		LLPointer<AISCommand> cmd_ptr = new CopyLibraryCategoryCommand(category->getUUID(), parent_id, track_cb); -		ais_ran=cmd_ptr->run_command(); -	} - -	if (!ais_ran) -	{ -		selfStartPhase("wear_inventory_category_fetch"); -		callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, -															   &LLAppearanceMgr::instance(), -															   category->getUUID(), copy, append)); -	} -} - -S32 LLAppearanceMgr::getActiveCopyOperations() const -{ -	return LLCallAfterInventoryCopyMgr::getInstanceCount();  -} - -void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) -{ -	LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; - -	selfStopPhase("wear_inventory_category_fetch"); -	 -	// We now have an outfit ready to be copied to agent inventory. Do -	// it, and wear that outfit normally. -	LLInventoryCategory* cat = gInventory.getCategory(cat_id); -	if(copy_items) -	{ -		LLInventoryModel::cat_array_t* cats; -		LLInventoryModel::item_array_t* items; -		gInventory.getDirectDescendentsOf(cat_id, cats, items); -		std::string name; -		if(!cat) -		{ -			// should never happen. -			name = "New Outfit"; -		} -		else -		{ -			name = cat->getName(); -		} -		LLViewerInventoryItem* item = NULL; -		LLInventoryModel::item_array_t::const_iterator it = items->begin(); -		LLInventoryModel::item_array_t::const_iterator end = items->end(); -		LLUUID pid; -		for(; it < end; ++it) -		{ -			item = *it; -			if(item) -			{ -				if(LLInventoryType::IT_GESTURE == item->getInventoryType()) -				{ -					pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); -				} -				else -				{ -					pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); -				} -				break; -			} -		} -		if(pid.isNull()) -		{ -			pid = gInventory.getRootFolderID(); -		} -		 -		LLUUID new_cat_id = gInventory.createNewCategory( -			pid, -			LLFolderType::FT_NONE, -			name); - -		// Create a CopyMgr that will copy items, manage its own destruction -		new LLCallAfterInventoryCopyMgr( -			*items, new_cat_id, std::string("wear_inventory_category_callback"), -			boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar, -						LLAppearanceMgr::getInstance(), -						gInventory.getCategory(new_cat_id), -						append)); - -		// BAP fixes a lag in display of created dir. -		gInventory.notifyObservers(); -	} -	else -	{ -		// Wear the inventory category. -		LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, append); -	} -} - -// *NOTE: hack to get from avatar inventory to avatar -void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append ) -{ -	// Avoid unintentionally overwriting old wearables.  We have to do -	// this up front to avoid having to deal with the case of multiple -	// wearables being dirty. -	if (!category) return; - -	if ( !LLInventoryCallbackManager::is_instantiated() ) -	{ -		// shutting down, ignore. -		return; -	} - -	LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName() -			 << "'" << LL_ENDL; -			 	 -	if (gAgentCamera.cameraCustomizeAvatar()) -	{ -		// switching to outfit editor should automagically save any currently edited wearable -		LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); -	} - -	LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); -} - -// FIXME do we really want to search entire inventory for matching name? -void LLAppearanceMgr::wearOutfitByName(const std::string& name) -{ -	LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	LLNameCategoryCollector has_name(name); -	gInventory.collectDescendentsIf(gInventory.getRootFolderID(), -									cat_array, -									item_array, -									LLInventoryModel::EXCLUDE_TRASH, -									has_name); -	bool copy_items = false; -	LLInventoryCategory* cat = NULL; -	if (cat_array.size() > 0) -	{ -		// Just wear the first one that matches -		cat = cat_array.at(0); -	} -	else -	{ -		gInventory.collectDescendentsIf(LLUUID::null, -										cat_array, -										item_array, -										LLInventoryModel::EXCLUDE_TRASH, -										has_name); -		if(cat_array.size() > 0) -		{ -			cat = cat_array.at(0); -			copy_items = true; -		} -	} - -	if(cat) -	{ -		LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); -	} -	else -	{ -		LL_WARNS() << "Couldn't find outfit " <<name<< " in wearOutfitByName()" -				<< LL_ENDL; -	} -} - -bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventoryItem *b) -{ -	return (a->isWearableType() && b->isWearableType() && -			(a->getWearableType() == b->getWearableType())); -} - -class LLDeferredCOFLinkObserver: public LLInventoryObserver -{ -public: -	LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description): -		mItemID(item_id), -		mCallback(cb), -		mDescription(description) -	{ -	} - -	~LLDeferredCOFLinkObserver() -	{ -	} -	 -	/* virtual */ void changed(U32 mask) -	{ -		const LLInventoryItem *item = gInventory.getItem(mItemID); -		if (item) -		{ -			gInventory.removeObserver(this); -			LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription); -			delete this; -		} -	} - -private: -	const LLUUID mItemID; -	std::string mDescription; -	LLPointer<LLInventoryCallback> mCallback; -}; - - -// BAP - note that this runs asynchronously if the item is not already loaded from inventory. -// Dangerous if caller assumes link will exist after calling the function. -void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, -									 LLPointer<LLInventoryCallback> cb, -									 const std::string description) -{ -	const LLInventoryItem *item = gInventory.getItem(item_id); -	if (!item) -	{ -		LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description); -		gInventory.addObserver(observer); -	} -	else -	{ -		addCOFItemLink(item, cb, description); -	} -} - -void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, -									 LLPointer<LLInventoryCallback> cb, -									 const std::string description) -{ -	const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item); -	if (!vitem) -	{ -		LL_WARNS() << "not an llviewerinventoryitem, failed" << LL_ENDL; -		return; -	} - -	gInventory.addChangedMask(LLInventoryObserver::LABEL, vitem->getLinkedUUID()); - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	gInventory.collectDescendents(LLAppearanceMgr::getCOF(), -								  cat_array, -								  item_array, -								  LLInventoryModel::EXCLUDE_TRASH); -	bool linked_already = false; -	U32 count = 0; -	for (S32 i=0; i<item_array.size(); i++) -	{ -		// Are these links to the same object? -		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -		const LLWearableType::EType wearable_type = inv_item->getWearableType(); - -		const bool is_body_part =    (wearable_type == LLWearableType::WT_SHAPE)  -								  || (wearable_type == LLWearableType::WT_HAIR)  -								  || (wearable_type == LLWearableType::WT_EYES) -								  || (wearable_type == LLWearableType::WT_SKIN); - -		if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) -		{ -			linked_already = true; -		} -		// Are these links to different items of the same body part -		// type? If so, new item will replace old. -		else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type)) -		{ -			++count; -			if (is_body_part && inv_item->getIsLinkType()  && (vitem->getWearableType() == wearable_type)) -			{ -				remove_inventory_item(inv_item->getUUID(), cb); -			} -			else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) -			{ -				// MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE -				remove_inventory_item(inv_item->getUUID(), cb); -			} -		} -	} - -	if (!linked_already) -	{ -		LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; -		copy_item->copyViewerItem(vitem); -		copy_item->setDescription(description); -		link_inventory_object(getCOF(), copy_item, cb); -	} -} - -LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id) -{ - -	LLInventoryModel::item_array_t result; -	const LLViewerInventoryItem *vitem = -		dynamic_cast<const LLViewerInventoryItem*>(gInventory.getItem(item_id)); - -	if (vitem) -	{ -		LLInventoryModel::cat_array_t cat_array; -		LLInventoryModel::item_array_t item_array; -		gInventory.collectDescendents(LLAppearanceMgr::getCOF(), -									  cat_array, -									  item_array, -									  LLInventoryModel::EXCLUDE_TRASH); -		for (S32 i=0; i<item_array.size(); i++) -		{ -			const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -			if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) -			{ -				result.push_back(item_array.at(i)); -			} -		} -	} -	return result; -} - -bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) -{ -	LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); -	return links.size() > 0; -} - -void LLAppearanceMgr::removeAllClothesFromAvatar() -{ -	// Fetch worn clothes (i.e. the ones in COF). -	LLInventoryModel::item_array_t clothing_items; -	LLInventoryModel::cat_array_t dummy; -	LLIsType is_clothing(LLAssetType::AT_CLOTHING); -	gInventory.collectDescendentsIf(getCOF(), -									dummy, -									clothing_items, -									LLInventoryModel::EXCLUDE_TRASH, -									is_clothing); -	uuid_vec_t item_ids; -	for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin(); -		it != clothing_items.end(); ++it) -	{ -		item_ids.push_back((*it).get()->getLinkedUUID()); -	} - -	// Take them off by removing from COF. -	removeItemsFromAvatar(item_ids); -} - -void LLAppearanceMgr::removeAllAttachmentsFromAvatar() -{ -	if (!isAgentAvatarValid()) return; - -	LLAgentWearables::llvo_vec_t objects_to_remove; -	 -	for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();  -		 iter != gAgentAvatarp->mAttachmentPoints.end();) -	{ -		LLVOAvatar::attachment_map_t::iterator curiter = iter++; -		LLViewerJointAttachment* attachment = curiter->second; -		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); -			 attachment_iter != attachment->mAttachedObjects.end(); -			 ++attachment_iter) -		{ -			LLViewerObject *attached_object = (*attachment_iter); -			if (attached_object) -			{ -				objects_to_remove.push_back(attached_object); -			} -		} -	} -	uuid_vec_t ids_to_remove; -	for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_remove.begin(); -		 it != objects_to_remove.end(); -		 ++it) -	{ -		ids_to_remove.push_back((*it)->getAttachmentItemID()); -	} -	removeItemsFromAvatar(ids_to_remove); -} - -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) -{ -	gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	gInventory.collectDescendents(LLAppearanceMgr::getCOF(), -								  cat_array, -								  item_array, -								  LLInventoryModel::EXCLUDE_TRASH); -	for (S32 i=0; i<item_array.size(); i++) -	{ -		const LLInventoryItem* item = item_array.at(i).get(); -		if (item->getIsLinkType() && item->getLinkedUUID() == item_id) -		{ -			bool immediate_delete = false; -			if (item->getType() == LLAssetType::AT_OBJECT) -			{ -				immediate_delete = true; -			} -			remove_inventory_item(item->getUUID(), cb, immediate_delete); -		} -	} -} - -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb) -{ -	LLFindWearablesOfType filter_wearables_of_type(type); -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	LLInventoryModel::item_array_t::const_iterator it; - -	gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); -	for (it = items.begin(); it != items.end(); ++it) -	{ -		const LLViewerInventoryItem* item = *it; -		if (item->getIsLinkType()) // we must operate on links only -		{ -			remove_inventory_item(item->getUUID(), cb); -		} -	} -} - -bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInventoryItem* item2) -{ -	if (!item1 || !item2) -	{ -		LL_WARNS() << "item1, item2 cannot be null, something is very wrong" << LL_ENDL; -		return true; -	} - -	return item1->getLinkedUUID() < item2->getLinkedUUID(); -} - -void LLAppearanceMgr::updateIsDirty() -{ -	LLUUID cof = getCOF(); -	LLUUID base_outfit; - -	// find base outfit link  -	const LLViewerInventoryItem* base_outfit_item = getBaseOutfitLink(); -	LLViewerInventoryCategory* catp = NULL; -	if (base_outfit_item && base_outfit_item->getIsLinkType()) -	{ -		catp = base_outfit_item->getLinkedCategory(); -	} -	if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) -	{ -		base_outfit = catp->getUUID(); -	} - -	// Set dirty to "false" if no base outfit found to disable "Save" -	// and leave only "Save As" enabled in My Outfits. -	mOutfitIsDirty = false; - -	if (base_outfit.notNull()) -	{ -		LLIsValidItemLink collector; - -		LLInventoryModel::cat_array_t cof_cats; -		LLInventoryModel::item_array_t cof_items; -		gInventory.collectDescendentsIf(cof, cof_cats, cof_items, -									  LLInventoryModel::EXCLUDE_TRASH, collector); - -		LLInventoryModel::cat_array_t outfit_cats; -		LLInventoryModel::item_array_t outfit_items; -		gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items, -									  LLInventoryModel::EXCLUDE_TRASH, collector); - -		if(outfit_items.size() != cof_items.size()) -		{ -			LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL; -			// Current outfit folder should have one more item than the outfit folder. -			// this one item is the link back to the outfit folder itself. -			mOutfitIsDirty = true; -			return; -		} - -		//"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions) -		std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid); -		std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid); - -		for (U32 i = 0; i < cof_items.size(); ++i) -		{ -			LLViewerInventoryItem *item1 = cof_items.at(i); -			LLViewerInventoryItem *item2 = outfit_items.at(i); - -			if (item1->getLinkedUUID() != item2->getLinkedUUID() ||  -				item1->getName() != item2->getName() || -				item1->getActualDescription() != item2->getActualDescription()) -			{ -				if (item1->getLinkedUUID() != item2->getLinkedUUID()) -				{ -					LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; -				} -				else -				{ -					if (item1->getName() != item2->getName()) -					{ -						LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; -					} -					if (item1->getActualDescription() != item2->getActualDescription()) -					{ -						LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() -											<< " " << item2->getActualDescription()  -											<< " names " << item1->getName() << " " << item2->getName() << LL_ENDL; -					} -				} -				mOutfitIsDirty = true; -				return; -			} -		} -	} -	llassert(!mOutfitIsDirty); -	LL_DEBUGS("Avatar") << "clean" << LL_ENDL; -} - -// *HACK: Must match name in Library or agent inventory -const std::string ROOT_GESTURES_FOLDER = "Gestures"; -const std::string COMMON_GESTURES_FOLDER = "Common Gestures"; -const std::string MALE_GESTURES_FOLDER = "Male Gestures"; -const std::string FEMALE_GESTURES_FOLDER = "Female Gestures"; -const std::string SPEECH_GESTURES_FOLDER = "Speech Gestures"; -const std::string OTHER_GESTURES_FOLDER = "Other Gestures"; - -void LLAppearanceMgr::copyLibraryGestures() -{ -	LL_INFOS("Avatar") << self_av_string() << "Copying library gestures" << LL_ENDL; - -	// Copy gestures -	LLUUID lib_gesture_cat_id = -		gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE,false); -	if (lib_gesture_cat_id.isNull()) -	{ -		LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL; -	} -	LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); - -	std::vector<std::string> gesture_folders_to_copy; -	gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER); -	gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER); -	gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER); -	gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER); -	gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER); - -	for(std::vector<std::string>::iterator it = gesture_folders_to_copy.begin(); -		it != gesture_folders_to_copy.end(); -		++it) -	{ -		std::string& folder_name = *it; - -		LLPointer<LLInventoryCallback> cb(NULL); - -		// After copying gestures, activate Common, Other, plus -		// Male and/or Female, depending upon the initial outfit gender. -		ESex gender = gAgentAvatarp->getSex(); - -		std::string activate_male_gestures; -		std::string activate_female_gestures; -		switch (gender) { -			case SEX_MALE: -				activate_male_gestures = MALE_GESTURES_FOLDER; -				break; -			case SEX_FEMALE: -				activate_female_gestures = FEMALE_GESTURES_FOLDER; -				break; -			case SEX_BOTH: -				activate_male_gestures = MALE_GESTURES_FOLDER; -				activate_female_gestures = FEMALE_GESTURES_FOLDER; -				break; -		} - -		if (folder_name == activate_male_gestures || -			folder_name == activate_female_gestures || -			folder_name == COMMON_GESTURES_FOLDER || -			folder_name == OTHER_GESTURES_FOLDER) -		{ -			cb = new LLBoostFuncInventoryCallback(activate_gesture_cb); -		} - -		LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); -		if (cat_id.isNull()) -		{ -			LL_WARNS() << self_av_string() << "failed to find gesture folder for " << folder_name << LL_ENDL; -		} -		else -		{ -			LL_DEBUGS("Avatar") << self_av_string() << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << LL_ENDL; -			callAfterCategoryFetch(cat_id, -								   boost::bind(&LLAppearanceMgr::shallowCopyCategory, -											   &LLAppearanceMgr::instance(), -											   cat_id, dst_id, cb)); -		} -	} -} - -// Handler for anything that's deferred until avatar de-clouds. -void LLAppearanceMgr::onFirstFullyVisible() -{ -	gAgentAvatarp->outputRezTiming("Avatar fully loaded"); -	gAgentAvatarp->reportAvatarRezTime(); -	gAgentAvatarp->debugAvatarVisible(); - -	// If this is the first time we've ever logged in, -	// then copy default gestures from the library. -	if (gAgent.isFirstLogin()) { -		copyLibraryGestures(); -	} -} - -// update "dirty" state - defined outside class to allow for calling -// after appearance mgr instance has been destroyed. -void appearance_mgr_update_dirty_state() -{ -	if (LLAppearanceMgr::instanceExists()) -	{ -		LLAppearanceMgr::getInstance()->updateIsDirty(); -		LLAppearanceMgr::getInstance()->setOutfitLocked(false); -		gAgentWearables.notifyLoadingFinished(); -	} -} - -void update_base_outfit_after_ordering() -{ -	LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); -	 -	LLPointer<LLInventoryCallback> dirty_state_updater = -		new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); - -	//COF contains only links so we copy to the Base Outfit only links -	const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID(); -	bool copy_folder_links = false; -	app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); - -} - -// Save COF changes - update the contents of the current base outfit -// to match the current COF. Fails if no current base outfit is set. -bool LLAppearanceMgr::updateBaseOutfit() -{ -	if (isOutfitLocked()) -	{ -		// don't allow modify locked outfit -		llassert(!isOutfitLocked()); -		return false; -	} - -	setOutfitLocked(true); - -	gAgentWearables.notifyLoadingStarted(); - -	const LLUUID base_outfit_id = getBaseOutfitUUID(); -	if (base_outfit_id.isNull()) return false; -	LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL; - -	LLPointer<LLInventoryCallback> cb = -		new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering); -	// Really shouldn't be needed unless there's a race condition - -	// updateAppearanceFromCOF() already calls updateClothingOrderingInfo. -	updateClothingOrderingInfo(LLUUID::null, cb); - -	return true; -} - -void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type) -{ -	items_by_type.resize(LLWearableType::WT_COUNT); -	if (items.empty()) return; - -	for (S32 i=0; i<items.size(); i++) -	{ -		LLViewerInventoryItem *item = items.at(i); -		if (!item) -		{ -			LL_WARNS("Appearance") << "NULL item found" << LL_ENDL; -			continue; -		} -		// Ignore non-wearables. -		if (!item->isWearableType()) -			continue; -		LLWearableType::EType type = item->getWearableType(); -		if(type < 0 || type >= LLWearableType::WT_COUNT) -		{ -			LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; -			continue; -		} -		items_by_type[type].push_back(item); -	} -} - -std::string build_order_string(LLWearableType::EType type, U32 i) -{ -		std::ostringstream order_num; -		order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; -		return order_num.str(); -} - -struct WearablesOrderComparator -{ -	LOG_CLASS(WearablesOrderComparator); -	WearablesOrderComparator(const LLWearableType::EType type) -	{ -		mControlSize = build_order_string(type, 0).size(); -	}; - -	bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) -	{ -		const std::string& desc1 = item1->getActualDescription(); -		const std::string& desc2 = item2->getActualDescription(); -		 -		bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); -		bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); - -		if (item1_valid && item2_valid) -			return desc1 < desc2; - -		//we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, -		//items with ordering information but not for the associated wearables type -		if (!item1_valid && item2_valid)  -			return false; -		else if (item1_valid && !item2_valid) -			return true; - -		return item1->getName() < item2->getName(); -	} - -	U32 mControlSize; -}; - -void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, -													 desc_map_t& desc_map) -{ -	wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); -	divvyWearablesByType(wear_items, items_by_type); - -	for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) -	{ -		U32 size = items_by_type[type].size(); -		if (!size) continue; -		 -		//sinking down invalid items which need reordering -		std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); -		 -		//requesting updates only for those links which don't have "valid" descriptions -		for (U32 i = 0; i < size; i++) -		{ -			LLViewerInventoryItem* item = items_by_type[type][i]; -			if (!item) continue; -			 -			std::string new_order_str = build_order_string((LLWearableType::EType)type, i); -			if (new_order_str == item->getActualDescription()) continue; -			 -			desc_map[item->getUUID()] = new_order_str; -		} -	} -} - -bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id) -{ -	// COF is processed if cat_id is not specified -	if (cat_id.isNull()) -	{ -		cat_id = getCOF(); -	} - -	LLInventoryModel::item_array_t wear_items; -	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); - -	// Identify items for which desc needs to change. -	desc_map_t desc_map; -	getWearableOrderingDescUpdates(wear_items, desc_map); - -	for (desc_map_t::const_iterator it = desc_map.begin(); -		 it != desc_map.end(); ++it) -	{ -		const LLUUID& item_id = it->first; -		const std::string& new_order_str = it->second; -		LLViewerInventoryItem *item = gInventory.getItem(item_id); -		LL_WARNS() << "Order validation fails: " << item->getName() -				<< " needs to update desc to: " << new_order_str -				<< " (from: " << item->getActualDescription() << ")" << LL_ENDL; -	} -	 -	return desc_map.size() == 0; -} - -void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, -												 LLPointer<LLInventoryCallback> cb) -{ -	// COF is processed if cat_id is not specified -	if (cat_id.isNull()) -	{ -		cat_id = getCOF(); -	} - -	LLInventoryModel::item_array_t wear_items; -	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); - -	// Identify items for which desc needs to change. -	desc_map_t desc_map; -	getWearableOrderingDescUpdates(wear_items, desc_map); - -	for (desc_map_t::const_iterator it = desc_map.begin(); -		 it != desc_map.end(); ++it) -	{ -		LLSD updates; -		const LLUUID& item_id = it->first; -		const std::string& new_order_str = it->second; -		LLViewerInventoryItem *item = gInventory.getItem(item_id); -		LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str -			<< " (was: " << item->getActualDescription() << ")" << LL_ENDL; -		updates["desc"] = new_order_str; -		update_inventory_item(item_id,updates,cb); -	} -		 -} - -#if 1 -class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(RequestAgentUpdateAppearanceResponder); - -	friend class LLAppearanceMgr; -	 -public: -	RequestAgentUpdateAppearanceResponder(); - -	virtual ~RequestAgentUpdateAppearanceResponder(); - -private: -	// Called when sendServerAppearanceUpdate called. May or may not -	// trigger a request depending on various bits of state. -	void onRequestRequested(); - -	// Post the actual appearance request to cap. -	void sendRequest(); - -	void debugCOF(const LLSD& content); - -protected: -	// Successful completion. -	/* virtual */ void httpSuccess(); - -	// Error -	/*virtual*/ void httpFailure(); - -	void onFailure(); -	void onSuccess(); - -	S32 mInFlightCounter; -	LLTimer mInFlightTimer; -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; - -RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder() -{ -	bool retry_on_4xx = true; -	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx); -	mInFlightCounter = 0; -} - -RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder() -{ -} - -void RequestAgentUpdateAppearanceResponder::onRequestRequested() -{ -	// If we have already received an update for this or higher cof version, ignore. -	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); -	S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; -	S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; -	LL_DEBUGS("Avatar") << "cof_version " << cof_version -						<< " last_rcv " << last_rcv -						<< " last_req " << last_req -						<< " in flight " << mInFlightCounter << LL_ENDL; -	if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired())) -	{ -		LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; -		mInFlightCounter = 0; -	} -	if (cof_version < last_rcv) -	{ -		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv -							<< " will not request for " << cof_version << LL_ENDL; -		return; -	} -	if (mInFlightCounter>0 && last_req >= cof_version) -	{ -		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req  -							<< " will not request for " << cof_version << LL_ENDL; -		return; -	} - -	// Actually send the request. -	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; -	mRetryPolicy->reset(); -	sendRequest(); -} -	 -void RequestAgentUpdateAppearanceResponder::sendRequest() -{ -	if (gAgentAvatarp->isEditingAppearance())  -	{ -		// don't send out appearance updates if in appearance editing mode -		return; -	} - -	if (!gAgent.getRegion()) -	{ -		LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; -		return; -	} -	if (gAgent.getRegion()->getCentralBakeVersion()==0) -	{ -		LL_WARNS() << "Region does not support baking" << LL_ENDL; -	} -	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 -	if (url.empty()) -	{ -		LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; -		return; -	} -	 -	LLSD body; -	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); -	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) -	{ -		body = LLAppearanceMgr::instance().dumpCOF(); -	} -	else -	{ -		body["cof_version"] = cof_version; -		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) -		{ -			body["cof_version"] = cof_version+999; -		} -	} -	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; - -	mInFlightCounter++; -	mInFlightTimer.setTimerExpirySec(60.0); -	LLHTTPClient::post(url, body, this); -	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); -	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; -} - -void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) -{ -	LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() -					   << " ================================= " << LL_ENDL; -	std::set<LLUUID> ais_items, local_items; -	const LLSD& cof_raw = content["cof_raw"]; -	for (LLSD::array_const_iterator it = cof_raw.beginArray(); -		 it != cof_raw.endArray(); ++it) -	{ -		const LLSD& item = *it; -		if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) -		{ -			ais_items.insert(item["item_id"].asUUID()); -			if (item["type"].asInteger() == 24) // link -			{ -				LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << LL_ENDL;  -			} -			else if (item["type"].asInteger() == 25) // folder link -			{ -				LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << LL_ENDL;  -			} -			else -			{ -				LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << " type: " << item["type"].asInteger() -								   << LL_ENDL;  -			} -		} -	} -	LL_INFOS("Avatar") << LL_ENDL; -	LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()  -					   << " ================================= " << LL_ENDL; -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), -								  cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); -	for (S32 i=0; i<item_array.size(); i++) -	{ -		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -		local_items.insert(inv_item->getUUID()); -		LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() -						   << " linked_item_id: " << inv_item->getLinkedUUID() -						   << " name: " << inv_item->getName() -						   << " parent: " << inv_item->getParentUUID() -						   << LL_ENDL; -	} -	LL_INFOS("Avatar") << " ================================= " << LL_ENDL; -	S32 local_only = 0, ais_only = 0; -	for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) -	{ -		if (ais_items.find(*it) == ais_items.end()) -		{ -			LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; -			local_only++; -		} -	} -	for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) -	{ -		if (local_items.find(*it) == local_items.end()) -		{ -			LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; -			ais_only++; -		} -	} -	if (local_only==0 && ais_only==0) -	{ -		LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " -						   << content["observed"].asInteger() -						   << " rcv " << content["expected"].asInteger() -						   << ")" << LL_ENDL; -	} -} - -/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	if (content["success"].asBoolean()) -	{ -		LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; -		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -		{ -			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); -		} - -		onSuccess(); -	} -	else -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content); -	} -} - -void RequestAgentUpdateAppearanceResponder::onSuccess() -{ -	mInFlightCounter = llmax(mInFlightCounter-1,0); -} - -/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure() -{ -	LL_WARNS("Avatar") << "appearance update request failed, status " -					   << getStatus() << " reason " << getReason() << LL_ENDL; - -	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -	{ -		const LLSD& content = getContent(); -		dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); -		debugCOF(content); -	} -	onFailure(); -} - -void RequestAgentUpdateAppearanceResponder::onFailure() -{ -	mInFlightCounter = llmax(mInFlightCounter-1,0); - -	F32 seconds_to_wait; -	mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); -	if (mRetryPolicy->shouldRetry(seconds_to_wait)) -	{ -		LL_INFOS() << "retrying" << LL_ENDL; -		doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), -						seconds_to_wait); -	} -	else -	{ -		LL_WARNS() << "giving up after too many retries" << LL_ENDL; -	} -}	 -#else - - -#endif - - -LLSD LLAppearanceMgr::dumpCOF() const -{ -	LLSD links = LLSD::emptyArray(); -	LLMD5 md5; -	 -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	gInventory.collectDescendents(getCOF(),cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); -	for (S32 i=0; i<item_array.size(); i++) -	{ -		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -		LLSD item; -		LLUUID item_id(inv_item->getUUID()); -		md5.update((unsigned char*)item_id.mData, 16); -		item["description"] = inv_item->getActualDescription(); -		md5.update(inv_item->getActualDescription()); -		item["asset_type"] = inv_item->getActualType(); -		LLUUID linked_id(inv_item->getLinkedUUID()); -		item["linked_id"] = linked_id; -		md5.update((unsigned char*)linked_id.mData, 16); - -		if (LLAssetType::AT_LINK == inv_item->getActualType()) -		{ -			const LLViewerInventoryItem* linked_item = inv_item->getLinkedItem(); -			if (NULL == linked_item) -			{ -				LL_WARNS() << "Broken link for item '" << inv_item->getName() -						<< "' (" << inv_item->getUUID() -						<< ") during requestServerAppearanceUpdate" << LL_ENDL; -				continue; -			} -			// Some assets may be 'hidden' and show up as null in the viewer. -			//if (linked_item->getAssetUUID().isNull()) -			//{ -			//	LL_WARNS() << "Broken link (null asset) for item '" << inv_item->getName() -			//			<< "' (" << inv_item->getUUID() -			//			<< ") during requestServerAppearanceUpdate" << LL_ENDL; -			//	continue; -			//} -			LLUUID linked_asset_id(linked_item->getAssetUUID()); -			md5.update((unsigned char*)linked_asset_id.mData, 16); -			U32 flags = linked_item->getFlags(); -			md5.update(boost::lexical_cast<std::string>(flags)); -		} -		else if (LLAssetType::AT_LINK_FOLDER != inv_item->getActualType()) -		{ -			LL_WARNS() << "Non-link item '" << inv_item->getName() -					<< "' (" << inv_item->getUUID() -					<< ") type " << (S32) inv_item->getActualType() -					<< " during requestServerAppearanceUpdate" << LL_ENDL; -			continue; -		} -		links.append(item); -	} -	LLSD result = LLSD::emptyMap(); -	result["cof_contents"] = links; -	char cof_md5sum[MD5HEX_STR_SIZE]; -	md5.finalize(); -	md5.hex_digest(cof_md5sum); -	result["cof_md5sum"] = std::string(cof_md5sum); -	return result; -} - -void LLAppearanceMgr::requestServerAppearanceUpdate() -{ -	mAppearanceResponder->onRequestRequested(); -} - -class LLIncrementCofVersionResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLIncrementCofVersionResponder); -public: -	LLIncrementCofVersionResponder() : LLHTTPClient::Responder() -	{ -		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5); -	} - -	virtual ~LLIncrementCofVersionResponder() -	{ -	} - -protected: -	virtual void httpSuccess() -	{ -		LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL; -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		S32 new_version = content["category"]["version"].asInteger(); - -		// cof_version should have increased -		llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion); - -		gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version; -	} - -	virtual void httpFailure() -	{ -		LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error " -						   << dumpResponse() << LL_ENDL; -		F32 seconds_to_wait; -		mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); -		if (mRetryPolicy->shouldRetry(seconds_to_wait)) -		{ -			LL_INFOS() << "retrying" << LL_ENDL; -			doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, -										LLAppearanceMgr::getInstance(), -										LLHTTPClient::ResponderPtr(this)), -										seconds_to_wait); -		} -		else -		{ -			LL_WARNS() << "giving up after too many retries" << LL_ENDL; -		} -	} - -private: -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; - -void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr) -{ -	// If we don't have a region, report it as an error -	if (gAgent.getRegion() == NULL) -	{ -		LL_WARNS() << "Region not set, cannot request cof_version increment" << LL_ENDL; -		return; -	} - -	std::string url = gAgent.getRegion()->getCapability("IncrementCofVersion"); -	if (url.empty()) -	{ -		LL_WARNS() << "No cap for IncrementCofVersion." << LL_ENDL; -		return; -	} - -	LL_INFOS() << "Requesting cof_version be incremented via capability to: " -			<< url << LL_ENDL; -	LLSD headers; -	LLSD body = LLSD::emptyMap(); - -	if (!responder_ptr.get()) -	{ -		responder_ptr = LLHTTPClient::ResponderPtr(new LLIncrementCofVersionResponder()); -	} - -	LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f); -} - -U32 LLAppearanceMgr::getNumAttachmentsInCOF() -{ -	const LLUUID cof = getCOF(); -	LLInventoryModel::item_array_t obj_items; -	getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); -	return obj_items.size(); -} - - -std::string LLAppearanceMgr::getAppearanceServiceURL() const -{ -	if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) -	{ -		return mAppearanceServiceURL; -	} -	return gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride"); -} - -void show_created_outfit(LLUUID& folder_id, bool show_panel = true) -{ -	if (!LLApp::isRunning()) -	{ -		LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; -		return; -	} -	 -	LL_DEBUGS("Avatar") << "called" << LL_ENDL; -	LLSD key; -	 -	//EXT-7727. For new accounts inventory callback is created during login process -	// and may be processed after login process is finished -	if (show_panel) -	{ -		LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL; -		LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); -		 -	} -	LLOutfitsList *outfits_list = -		dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); -	if (outfits_list) -	{ -		outfits_list->setSelectedOutfitByUUID(folder_id); -	} -	 -	LLAppearanceMgr::getInstance()->updateIsDirty(); -	gAgentWearables.notifyLoadingFinished(); // New outfit is saved. -	LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); - -	// For SSB, need to update appearance after we add a base outfit -	// link, since, the COF version has changed. There is a race -	// condition in initial outfit setup which can lead to rez -	// failures - SH-3860. -	LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; -	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; -	LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); -} - -void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel) -{ -	LLPointer<LLInventoryCallback> cb = -		new LLBoostFuncInventoryCallback(no_op_inventory_func, -										 boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); -	updateClothingOrderingInfo(LLUUID::null, cb); -} - -void LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel) -{ -	LLPointer<LLInventoryCallback> cb = -		new LLBoostFuncInventoryCallback(no_op_inventory_func, -										 boost::bind(show_created_outfit,folder_id,show_panel)); -	bool copy_folder_links = false; -	slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb); -} - -void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) -{ -	if (!isAgentAvatarValid()) return; - -	LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL; - -	gAgentWearables.notifyLoadingStarted(); - -	// First, make a folder in the My Outfits directory. -	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	if (AISCommand::isAPIAvailable()) -	{ -		// cap-based category creation was buggy until recently. use -		// existence of AIS as an indicator the fix is present. Does -		// not actually use AIS to create the category. -		inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel); -		LLUUID folder_id = gInventory.createNewCategory( -			parent_id, -			LLFolderType::FT_OUTFIT, -			new_folder_name, -			func); -	} -	else -	{		 -		LLUUID folder_id = gInventory.createNewCategory( -			parent_id, -			LLFolderType::FT_OUTFIT, -			new_folder_name); -		onOutfitFolderCreated(folder_id, show_panel); -	} -} - -void LLAppearanceMgr::wearBaseOutfit() -{ -	const LLUUID& base_outfit_id = getBaseOutfitUUID(); -	if (base_outfit_id.isNull()) return; -	 -	updateCOF(base_outfit_id); -} - -void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) -{ -	if (ids_to_remove.empty()) -	{ -		LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; -		return; -	} -	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; -	for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) -	{ -		const LLUUID& id_to_remove = *it; -		const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); -		removeCOFItemLinks(linked_item_id, cb); -		addDoomedTempAttachment(linked_item_id); -	} -} - -void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) -{ -	LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove); -	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; -	removeCOFItemLinks(linked_item_id, cb); -	addDoomedTempAttachment(linked_item_id); -} - - -// Adds the given item ID to mDoomedTempAttachmentIDs iff it's a temp attachment -void LLAppearanceMgr::addDoomedTempAttachment(const LLUUID& id_to_remove) -{ -	LLViewerObject * attachmentp = gAgentAvatarp->findAttachmentByID(id_to_remove); -	if (attachmentp && -		attachmentp->isTempAttachment()) -	{	// If this is a temp attachment and we want to remove it, record the ID  -		// so it will be deleted when attachments are synced up with COF -		mDoomedTempAttachmentIDs.insert(id_to_remove); -		//LL_INFOS() << "Will remove temp attachment id " << id_to_remove << LL_ENDL; -	} -} - -// Find AND REMOVES the given UUID from mDoomedTempAttachmentIDs -bool LLAppearanceMgr::shouldRemoveTempAttachment(const LLUUID& item_id) -{ -	doomed_temp_attachments_t::iterator iter = mDoomedTempAttachmentIDs.find(item_id); -	if (iter != mDoomedTempAttachmentIDs.end()) -	{ -		mDoomedTempAttachmentIDs.erase(iter); -		return true; -	} -	return false; -} - - -bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) -{ -	if (!item || !item->isWearableType()) return false; -	if (item->getType() != LLAssetType::AT_CLOTHING) return false; -	if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false; - -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	LLFindWearablesOfType filter_wearables_of_type(item->getWearableType()); -	gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); -	if (items.empty()) return false; - -	// We assume that the items have valid descriptions. -	std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType())); - -	if (closer_to_body && items.front() == item) return false; -	if (!closer_to_body && items.back() == item) return false; -	 -	LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item); -	if (items.end() == it) return false; - - -	//swapping descriptions -	closer_to_body ? --it : ++it; -	LLViewerInventoryItem* swap_item = *it; -	if (!swap_item) return false; -	std::string tmp = swap_item->getActualDescription(); -	swap_item->setDescription(item->getActualDescription()); -	item->setDescription(tmp); - -	// LL_DEBUGS("Inventory") << "swap, item " -	// 					   << ll_pretty_print_sd(item->asLLSD()) -	// 					   << " swap_item " -	// 					   << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL; - -	// FIXME switch to use AISv3 where supported. -	//items need to be updated on a dataserver -	item->setComplete(TRUE); -	item->updateServer(FALSE); -	gInventory.updateItem(item); - -	swap_item->setComplete(TRUE); -	swap_item->updateServer(FALSE); -	gInventory.updateItem(swap_item); - -	//to cause appearance of the agent to be updated -	bool result = false; -	if ((result = gAgentWearables.moveWearable(item, closer_to_body))) -	{ -		gAgentAvatarp->wearableUpdated(item->getWearableType()); -	} - -	setOutfitDirty(true); - -	//*TODO do we need to notify observers here in such a way? -	gInventory.notifyObservers(); - -	return result; -} - -//static -void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items) -{ -	if (items.size() < 2) return; - -	std::sort(items.begin(), items.end(), sort_by_actual_description); -} - -//#define DUMP_CAT_VERBOSE - -void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg) -{ -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); - -#ifdef DUMP_CAT_VERBOSE -	LL_INFOS() << LL_ENDL; -	LL_INFOS() << str << LL_ENDL; -	S32 hitcount = 0; -	for(S32 i=0; i<items.size(); i++) -	{ -		LLViewerInventoryItem *item = items.get(i); -		if (item) -			hitcount++; -		LL_INFOS() << i <<" "<< item->getName() <<LL_ENDL; -	} -#endif -	LL_INFOS() << msg << " count " << items.size() << LL_ENDL; -} - -void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items, -									const std::string& msg) -{ -	for (S32 i=0; i<items.size(); i++) -	{ -		LLViewerInventoryItem *item = items.at(i); -		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; -		LLUUID asset_id; -		if (linked_item) -		{ -			asset_id = linked_item->getAssetUUID(); -		} -		LL_DEBUGS("Avatar") << self_av_string() << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << LL_ENDL; -	} -} - -LLAppearanceMgr::LLAppearanceMgr(): -	mAttachmentInvLinkEnabled(false), -	mOutfitIsDirty(false), -	mOutfitLocked(false), -	mIsInUpdateAppearanceFromCOF(false), -	mAppearanceResponder(new RequestAgentUpdateAppearanceResponder) -{ -	LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); - -	// unlock outfit on save operation completed -	outfit_observer.addCOFSavedCallback(boost::bind( -			&LLAppearanceMgr::setOutfitLocked, this, false)); - -	mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( -			"OutfitOperationsTimeout"))); - -	gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL); -} - -LLAppearanceMgr::~LLAppearanceMgr() -{ -} - -void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) -{ -	LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL; -	mAttachmentInvLinkEnabled = val; -} - -void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg) -{ -       LL_INFOS() << msg << LL_ENDL; -       for (std::set<LLUUID>::const_iterator it = atts.begin(); -               it != atts.end(); -               ++it) -       { -               LLUUID item_id = *it; -               LLViewerInventoryItem *item = gInventory.getItem(item_id); -               if (item) -                       LL_INFOS() << "atts " << item->getName() << LL_ENDL; -               else -                       LL_INFOS() << "atts " << "UNKNOWN[" << item_id.asString() << "]" << LL_ENDL; -       } -       LL_INFOS() << LL_ENDL; -} - -void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) -{ -	   gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - -	   if (mAttachmentInvLinkEnabled) -	   { -		   // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF. -		   // it will trigger gAgentWariables.notifyLoadingFinished() -		   // But it is not acceptable solution. See EXT-7777 -		   if (!isLinkedInCOF(item_id)) -		   { -			   LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(); -			   LLAppearanceMgr::addCOFItemLink(item_id, cb);  // Add COF link for item. -		   } -	   } -	   else -	   { -		   //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL; -	   } -} - -void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) -{ -	   gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - -	   if (mAttachmentInvLinkEnabled) -	   { -		   LLAppearanceMgr::removeCOFItemLinks(item_id); -	   } -	   else -	   { -		   //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL; -	   } -} - -BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const -{ -	const LLUUID& cof = getCOF(); -	if (obj_id == cof) -		return TRUE; -	const LLInventoryObject* obj = gInventory.getObject(obj_id); -	if (obj && obj->getParentUUID() == cof) -		return TRUE; -	return FALSE; -} - -// static -bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id) -{ -	const LLUUID& target_id = gInventory.getLinkedItemID(obj_id); -	LLLinkedItemIDMatches find_links(target_id); -	return gInventory.hasMatchingDirectDescendent(LLAppearanceMgr::instance().getCOF(), find_links); -} - -BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const -{ -	if (!getIsInCOF(obj_id)) return FALSE; - -	// If a non-link somehow ended up in COF, allow deletion. -	const LLInventoryObject *obj = gInventory.getObject(obj_id); -	if (obj && !obj->getIsLinkType()) -	{ -		return FALSE; -	} - -	// For now, don't allow direct deletion from the COF.  Instead, force users -	// to choose "Detach" or "Take Off". -	return TRUE; -} - -class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver -{ -public: -	CallAfterCategoryFetchStage2(const uuid_vec_t& ids, -								 nullary_func_t callable) : -		LLInventoryFetchItemsObserver(ids), -		mCallable(callable) -	{ -	} -	~CallAfterCategoryFetchStage2() -	{ -	} -	virtual void done() -	{ -		LL_INFOS() << this << " done with incomplete " << mIncomplete.size() -				<< " complete " << mComplete.size() <<  " calling callable" << LL_ENDL; - -		gInventory.removeObserver(this); -		doOnIdleOneTime(mCallable); -		delete this; -	} -protected: -	nullary_func_t mCallable; -}; - -class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver -{ -public: -	CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) : -		LLInventoryFetchDescendentsObserver(cat_id), -		mCallable(callable) -	{ -	} -	~CallAfterCategoryFetchStage1() -	{ -	} -	virtual void done() -	{ -		// What we do here is get the complete information on the -		// items in the requested category, and set up an observer -		// that will wait for that to happen. -		LLInventoryModel::cat_array_t cat_array; -		LLInventoryModel::item_array_t item_array; -		gInventory.collectDescendents(mComplete.front(), -									  cat_array, -									  item_array, -									  LLInventoryModel::EXCLUDE_TRASH); -		S32 count = item_array.size(); -		if(!count) -		{ -			LL_WARNS() << "Nothing fetched in category " << mComplete.front() -					<< LL_ENDL; -			gInventory.removeObserver(this); -			doOnIdleOneTime(mCallable); - -			delete this; -			return; -		} - -		LL_INFOS() << "stage1 got " << item_array.size() << " items, passing to stage2 " << LL_ENDL; -		uuid_vec_t ids; -		for(S32 i = 0; i < count; ++i) -		{ -			ids.push_back(item_array.at(i)->getUUID()); -		} -		 -		gInventory.removeObserver(this); -		 -		// do the fetch -		CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable); -		stage2->startFetch(); -		if(stage2->isFinished()) -		{ -			// everything is already here - call done. -			stage2->done(); -		} -		else -		{ -			// it's all on it's way - add an observer, and the inventory -			// will call done for us when everything is here. -			gInventory.addObserver(stage2); -		} -		delete this; -	} -protected: -	nullary_func_t mCallable; -}; - -void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb) -{ -	CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb); -	stage1->startFetch(); -	if (stage1->isFinished()) -	{ -		stage1->done(); -	} -	else -	{ -		gInventory.addObserver(stage1); -	} -} - -void wear_multiple(const uuid_vec_t& ids, bool replace) -{ -	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; -	 -	bool first = true; -	uuid_vec_t::const_iterator it; -	for (it = ids.begin(); it != ids.end(); ++it) -	{ -		// if replace is requested, the first item worn will replace the current top -		// item, and others will be added. -		LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb); -		first = false; -	} -} - -// SLapp for easy-wearing of a stock (library) avatar -// -class LLWearFolderHandler : public LLCommandHandler -{ -public: -	// not allowed from outside the app -	LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { } - -	bool handle(const LLSD& tokens, const LLSD& query_map, -				LLMediaCtrl* web) -	{ -		LLSD::UUID folder_uuid; - -		if (folder_uuid.isNull() && query_map.has("folder_name")) -		{ -			std::string outfit_folder_name = query_map["folder_name"]; -			folder_uuid = findDescendentCategoryIDByName( -				gInventory.getLibraryRootFolderID(), -				outfit_folder_name);	 -		} -		if (folder_uuid.isNull() && query_map.has("folder_id")) -		{ -			folder_uuid = query_map["folder_id"].asUUID(); -		} -		 -		if (folder_uuid.notNull()) -		{ -			LLPointer<LLInventoryCategory> category = new LLInventoryCategory(folder_uuid, -																			  LLUUID::null, -																			  LLFolderType::FT_CLOTHING, -																			  "Quick Appearance"); -			if ( gInventory.getCategory( folder_uuid ) != NULL ) -			{ -				LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); -				 -				// *TODOw: This may not be necessary if initial outfit is chosen already -- josh -				gAgent.setOutfitChosen(TRUE); -			} -		} - -		// release avatar picker keyboard focus -		gFocusMgr.setKeyboardFocus( NULL ); - -		return true; -	} -}; - -LLWearFolderHandler gWearFolderHandler; +
 +class LLIncrementCofVersionResponder : public LLHTTPClient::Responder
 +{
 +	LOG_CLASS(LLIncrementCofVersionResponder);
 +public:
 +	LLIncrementCofVersionResponder() : LLHTTPClient::Responder()
 +	{
 +		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5);
 +	}
 +
 +	virtual ~LLIncrementCofVersionResponder()
 +	{
 +	}
 +
 +protected:
 +	virtual void httpSuccess()
 +	{
 +		LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL;
 +		const LLSD& content = getContent();
 +		if (!content.isMap())
 +		{
 +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
 +			return;
 +		}
 +		S32 new_version = content["category"]["version"].asInteger();
 +
 +		// cof_version should have increased
 +		llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion);
 +
 +		gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version;
 +	}
 +
 +	virtual void httpFailure()
 +	{
 +		LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error "
 +						   << dumpResponse() << LL_ENDL;
 +		F32 seconds_to_wait;
 +		mRetryPolicy->onFailure(getStatus(), getResponseHeaders());
 +		if (mRetryPolicy->shouldRetry(seconds_to_wait))
 +		{
 +			LL_INFOS() << "retrying" << LL_ENDL;
 +			doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion,
 +										LLAppearanceMgr::getInstance(),
 +										LLHTTPClient::ResponderPtr(this)),
 +										seconds_to_wait);
 +		}
 +		else
 +		{
 +			LL_WARNS() << "giving up after too many retries" << LL_ENDL;
 +		}
 +	}
 +
 +private:
 +	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
 +};
 +
 +void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr)
 +{
 +	// If we don't have a region, report it as an error
 +	if (gAgent.getRegion() == NULL)
 +	{
 +		LL_WARNS() << "Region not set, cannot request cof_version increment" << LL_ENDL;
 +		return;
 +	}
 +
 +	std::string url = gAgent.getRegion()->getCapability("IncrementCofVersion");
 +	if (url.empty())
 +	{
 +		LL_WARNS() << "No cap for IncrementCofVersion." << LL_ENDL;
 +		return;
 +	}
 +
 +	LL_INFOS() << "Requesting cof_version be incremented via capability to: "
 +			<< url << LL_ENDL;
 +	LLSD headers;
 +	LLSD body = LLSD::emptyMap();
 +
 +	if (!responder_ptr.get())
 +	{
 +		responder_ptr = LLHTTPClient::ResponderPtr(new LLIncrementCofVersionResponder());
 +	}
 +
 +	LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f);
 +}
 +
 +U32 LLAppearanceMgr::getNumAttachmentsInCOF()
 +{
 +	const LLUUID cof = getCOF();
 +	LLInventoryModel::item_array_t obj_items;
 +	getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
 +	return obj_items.size();
 +}
 +
 +
 +std::string LLAppearanceMgr::getAppearanceServiceURL() const
 +{
 +	if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty())
 +	{
 +		return mAppearanceServiceURL;
 +	}
 +	return gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride");
 +}
 +
 +void show_created_outfit(LLUUID& folder_id, bool show_panel = true)
 +{
 +	if (!LLApp::isRunning())
 +	{
 +		LL_WARNS() << "called during shutdown, skipping" << LL_ENDL;
 +		return;
 +	}
 +	
 +	LL_DEBUGS("Avatar") << "called" << LL_ENDL;
 +	LLSD key;
 +	
 +	//EXT-7727. For new accounts inventory callback is created during login process
 +	// and may be processed after login process is finished
 +	if (show_panel)
 +	{
 +		LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL;
 +		LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key);
 +		
 +	}
 +	LLOutfitsList *outfits_list =
 +		dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab"));
 +	if (outfits_list)
 +	{
 +		outfits_list->setSelectedOutfitByUUID(folder_id);
 +	}
 +	
 +	LLAppearanceMgr::getInstance()->updateIsDirty();
 +	gAgentWearables.notifyLoadingFinished(); // New outfit is saved.
 +	LLAppearanceMgr::getInstance()->updatePanelOutfitName("");
 +
 +	// For SSB, need to update appearance after we add a base outfit
 +	// link, since, the COF version has changed. There is a race
 +	// condition in initial outfit setup which can lead to rez
 +	// failures - SH-3860.
 +	LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL;
 +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
 +	LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb);
 +}
 +
 +void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel)
 +{
 +	LLPointer<LLInventoryCallback> cb =
 +		new LLBoostFuncInventoryCallback(no_op_inventory_func,
 +										 boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel));
 +	updateClothingOrderingInfo(LLUUID::null, cb);
 +}
 +
 +void LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel)
 +{
 +	LLPointer<LLInventoryCallback> cb =
 +		new LLBoostFuncInventoryCallback(no_op_inventory_func,
 +										 boost::bind(show_created_outfit,folder_id,show_panel));
 +	bool copy_folder_links = false;
 +	slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb);
 +}
 +
 +void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel)
 +{
 +	if (!isAgentAvatarValid()) return;
 +
 +	LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL;
 +
 +	gAgentWearables.notifyLoadingStarted();
 +
 +	// First, make a folder in the My Outfits directory.
 +	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 +	if (AISCommand::isAPIAvailable())
 +	{
 +		// cap-based category creation was buggy until recently. use
 +		// existence of AIS as an indicator the fix is present. Does
 +		// not actually use AIS to create the category.
 +		inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel);
 +		LLUUID folder_id = gInventory.createNewCategory(
 +			parent_id,
 +			LLFolderType::FT_OUTFIT,
 +			new_folder_name,
 +			func);
 +	}
 +	else
 +	{		
 +		LLUUID folder_id = gInventory.createNewCategory(
 +			parent_id,
 +			LLFolderType::FT_OUTFIT,
 +			new_folder_name);
 +		onOutfitFolderCreated(folder_id, show_panel);
 +	}
 +}
 +
 +void LLAppearanceMgr::wearBaseOutfit()
 +{
 +	const LLUUID& base_outfit_id = getBaseOutfitUUID();
 +	if (base_outfit_id.isNull()) return;
 +	
 +	updateCOF(base_outfit_id);
 +}
 +
 +void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
 +{
 +	if (ids_to_remove.empty())
 +	{
 +		LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL;
 +		return;
 +	}
 +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
 +	for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
 +	{
 +		const LLUUID& id_to_remove = *it;
 +		const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove);
 +		removeCOFItemLinks(linked_item_id, cb);
 +		addDoomedTempAttachment(linked_item_id);
 +	}
 +}
 +
 +void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
 +{
 +	LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove);
 +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
 +	removeCOFItemLinks(linked_item_id, cb);
 +	addDoomedTempAttachment(linked_item_id);
 +}
 +
 +
 +// Adds the given item ID to mDoomedTempAttachmentIDs iff it's a temp attachment
 +void LLAppearanceMgr::addDoomedTempAttachment(const LLUUID& id_to_remove)
 +{
 +	LLViewerObject * attachmentp = gAgentAvatarp->findAttachmentByID(id_to_remove);
 +	if (attachmentp &&
 +		attachmentp->isTempAttachment())
 +	{	// If this is a temp attachment and we want to remove it, record the ID 
 +		// so it will be deleted when attachments are synced up with COF
 +		mDoomedTempAttachmentIDs.insert(id_to_remove);
 +		//LL_INFOS() << "Will remove temp attachment id " << id_to_remove << LL_ENDL;
 +	}
 +}
 +
 +// Find AND REMOVES the given UUID from mDoomedTempAttachmentIDs
 +bool LLAppearanceMgr::shouldRemoveTempAttachment(const LLUUID& item_id)
 +{
 +	doomed_temp_attachments_t::iterator iter = mDoomedTempAttachmentIDs.find(item_id);
 +	if (iter != mDoomedTempAttachmentIDs.end())
 +	{
 +		mDoomedTempAttachmentIDs.erase(iter);
 +		return true;
 +	}
 +	return false;
 +}
 +
 +
 +bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body)
 +{
 +	if (!item || !item->isWearableType()) return false;
 +	if (item->getType() != LLAssetType::AT_CLOTHING) return false;
 +	if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false;
 +
 +	LLInventoryModel::cat_array_t cats;
 +	LLInventoryModel::item_array_t items;
 +	LLFindWearablesOfType filter_wearables_of_type(item->getWearableType());
 +	gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type);
 +	if (items.empty()) return false;
 +
 +	// We assume that the items have valid descriptions.
 +	std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType()));
 +
 +	if (closer_to_body && items.front() == item) return false;
 +	if (!closer_to_body && items.back() == item) return false;
 +	
 +	LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item);
 +	if (items.end() == it) return false;
 +
 +
 +	//swapping descriptions
 +	closer_to_body ? --it : ++it;
 +	LLViewerInventoryItem* swap_item = *it;
 +	if (!swap_item) return false;
 +	std::string tmp = swap_item->getActualDescription();
 +	swap_item->setDescription(item->getActualDescription());
 +	item->setDescription(tmp);
 +
 +	// LL_DEBUGS("Inventory") << "swap, item "
 +	// 					   << ll_pretty_print_sd(item->asLLSD())
 +	// 					   << " swap_item "
 +	// 					   << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL;
 +
 +	// FIXME switch to use AISv3 where supported.
 +	//items need to be updated on a dataserver
 +	item->setComplete(TRUE);
 +	item->updateServer(FALSE);
 +	gInventory.updateItem(item);
 +
 +	swap_item->setComplete(TRUE);
 +	swap_item->updateServer(FALSE);
 +	gInventory.updateItem(swap_item);
 +
 +	//to cause appearance of the agent to be updated
 +	bool result = false;
 +	if ((result = gAgentWearables.moveWearable(item, closer_to_body)))
 +	{
 +		gAgentAvatarp->wearableUpdated(item->getWearableType());
 +	}
 +
 +	setOutfitDirty(true);
 +
 +	//*TODO do we need to notify observers here in such a way?
 +	gInventory.notifyObservers();
 +
 +	return result;
 +}
 +
 +//static
 +void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items)
 +{
 +	if (items.size() < 2) return;
 +
 +	std::sort(items.begin(), items.end(), sort_by_actual_description);
 +}
 +
 +//#define DUMP_CAT_VERBOSE
 +
 +void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg)
 +{
 +	LLInventoryModel::cat_array_t cats;
 +	LLInventoryModel::item_array_t items;
 +	gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
 +
 +#ifdef DUMP_CAT_VERBOSE
 +	LL_INFOS() << LL_ENDL;
 +	LL_INFOS() << str << LL_ENDL;
 +	S32 hitcount = 0;
 +	for(S32 i=0; i<items.size(); i++)
 +	{
 +		LLViewerInventoryItem *item = items.get(i);
 +		if (item)
 +			hitcount++;
 +		LL_INFOS() << i <<" "<< item->getName() <<LL_ENDL;
 +	}
 +#endif
 +	LL_INFOS() << msg << " count " << items.size() << LL_ENDL;
 +}
 +
 +void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items,
 +									const std::string& msg)
 +{
 +	for (S32 i=0; i<items.size(); i++)
 +	{
 +		LLViewerInventoryItem *item = items.at(i);
 +		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
 +		LLUUID asset_id;
 +		if (linked_item)
 +		{
 +			asset_id = linked_item->getAssetUUID();
 +		}
 +		LL_DEBUGS("Avatar") << self_av_string() << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << LL_ENDL;
 +	}
 +}
 +
 +bool LLAppearanceMgr::mActive = true;
 +
 +LLAppearanceMgr::LLAppearanceMgr():
 +	mAttachmentInvLinkEnabled(false),
 +	mOutfitIsDirty(false),
 +	mOutfitLocked(false),
 +	mInFlightCounter(0),
 +	mInFlightTimer(),
 +	mIsInUpdateAppearanceFromCOF(false),
 +	//mAppearanceResponder(new RequestAgentUpdateAppearanceResponder),
 +	mHttpRequest(),
 +	mHttpHeaders(),
 +	mHttpOptions(),
 +	mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
 +	mHttpPriority(0)
 +{
 +	LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
 +
 +	mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
 +	mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
 +	mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false);
 +	mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AVATAR);
 +
 +	LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
 +	// unlock outfit on save operation completed
 +	outfit_observer.addCOFSavedCallback(boost::bind(
 +			&LLAppearanceMgr::setOutfitLocked, this, false));
 +
 +	mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(
 +			"OutfitOperationsTimeout")));
 +
 +	gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL);
 +	doOnIdleRepeating(boost::bind(&LLAppearanceMgr::onIdle, this));
 +}
 +
 +LLAppearanceMgr::~LLAppearanceMgr()
 +{
 +	mActive = false;
 +}
 +
 +void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)
 +{
 +	LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL;
 +	mAttachmentInvLinkEnabled = val;
 +}
 +
 +void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
 +{
 +       LL_INFOS() << msg << LL_ENDL;
 +       for (std::set<LLUUID>::const_iterator it = atts.begin();
 +               it != atts.end();
 +               ++it)
 +       {
 +               LLUUID item_id = *it;
 +               LLViewerInventoryItem *item = gInventory.getItem(item_id);
 +               if (item)
 +                       LL_INFOS() << "atts " << item->getName() << LL_ENDL;
 +               else
 +                       LL_INFOS() << "atts " << "UNKNOWN[" << item_id.asString() << "]" << LL_ENDL;
 +       }
 +       LL_INFOS() << LL_ENDL;
 +}
 +
 +void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
 +{
 +	   gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
 +
 +	   if (mAttachmentInvLinkEnabled)
 +	   {
 +		   // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF.
 +		   // it will trigger gAgentWariables.notifyLoadingFinished()
 +		   // But it is not acceptable solution. See EXT-7777
 +		   if (!isLinkedInCOF(item_id))
 +		   {
 +			   LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy();
 +			   LLAppearanceMgr::addCOFItemLink(item_id, cb);  // Add COF link for item.
 +		   }
 +	   }
 +	   else
 +	   {
 +		   //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL;
 +	   }
 +}
 +
 +void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
 +{
 +	   gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
 +
 +	   if (mAttachmentInvLinkEnabled)
 +	   {
 +		   LLAppearanceMgr::removeCOFItemLinks(item_id);
 +	   }
 +	   else
 +	   {
 +		   //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL;
 +	   }
 +}
 +
 +BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
 +{
 +	const LLUUID& cof = getCOF();
 +	if (obj_id == cof)
 +		return TRUE;
 +	const LLInventoryObject* obj = gInventory.getObject(obj_id);
 +	if (obj && obj->getParentUUID() == cof)
 +		return TRUE;
 +	return FALSE;
 +}
 +
 +// static
 +bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id)
 +{
 +	const LLUUID& target_id = gInventory.getLinkedItemID(obj_id);
 +	LLLinkedItemIDMatches find_links(target_id);
 +	return gInventory.hasMatchingDirectDescendent(LLAppearanceMgr::instance().getCOF(), find_links);
 +}
 +
 +BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
 +{
 +	if (!getIsInCOF(obj_id)) return FALSE;
 +
 +	// If a non-link somehow ended up in COF, allow deletion.
 +	const LLInventoryObject *obj = gInventory.getObject(obj_id);
 +	if (obj && !obj->getIsLinkType())
 +	{
 +		return FALSE;
 +	}
 +
 +	// For now, don't allow direct deletion from the COF.  Instead, force users
 +	// to choose "Detach" or "Take Off".
 +	return TRUE;
 +}
 +
 +class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver
 +{
 +public:
 +	CallAfterCategoryFetchStage2(const uuid_vec_t& ids,
 +								 nullary_func_t callable) :
 +		LLInventoryFetchItemsObserver(ids),
 +		mCallable(callable)
 +	{
 +	}
 +	~CallAfterCategoryFetchStage2()
 +	{
 +	}
 +	virtual void done()
 +	{
 +		LL_INFOS() << this << " done with incomplete " << mIncomplete.size()
 +				<< " complete " << mComplete.size() <<  " calling callable" << LL_ENDL;
 +
 +		gInventory.removeObserver(this);
 +		doOnIdleOneTime(mCallable);
 +		delete this;
 +	}
 +protected:
 +	nullary_func_t mCallable;
 +};
 +
 +class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver
 +{
 +public:
 +	CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) :
 +		LLInventoryFetchDescendentsObserver(cat_id),
 +		mCallable(callable)
 +	{
 +	}
 +	~CallAfterCategoryFetchStage1()
 +	{
 +	}
 +	virtual void done()
 +	{
 +		// What we do here is get the complete information on the
 +		// items in the requested category, and set up an observer
 +		// that will wait for that to happen.
 +		LLInventoryModel::cat_array_t cat_array;
 +		LLInventoryModel::item_array_t item_array;
 +		gInventory.collectDescendents(mComplete.front(),
 +									  cat_array,
 +									  item_array,
 +									  LLInventoryModel::EXCLUDE_TRASH);
 +		S32 count = item_array.size();
 +		if(!count)
 +		{
 +			LL_WARNS() << "Nothing fetched in category " << mComplete.front()
 +					<< LL_ENDL;
 +			gInventory.removeObserver(this);
 +			doOnIdleOneTime(mCallable);
 +
 +			delete this;
 +			return;
 +		}
 +
 +		LL_INFOS() << "stage1 got " << item_array.size() << " items, passing to stage2 " << LL_ENDL;
 +		uuid_vec_t ids;
 +		for(S32 i = 0; i < count; ++i)
 +		{
 +			ids.push_back(item_array.at(i)->getUUID());
 +		}
 +		
 +		gInventory.removeObserver(this);
 +		
 +		// do the fetch
 +		CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable);
 +		stage2->startFetch();
 +		if(stage2->isFinished())
 +		{
 +			// everything is already here - call done.
 +			stage2->done();
 +		}
 +		else
 +		{
 +			// it's all on it's way - add an observer, and the inventory
 +			// will call done for us when everything is here.
 +			gInventory.addObserver(stage2);
 +		}
 +		delete this;
 +	}
 +protected:
 +	nullary_func_t mCallable;
 +};
 +
 +void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb)
 +{
 +	CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb);
 +	stage1->startFetch();
 +	if (stage1->isFinished())
 +	{
 +		stage1->done();
 +	}
 +	else
 +	{
 +		gInventory.addObserver(stage1);
 +	}
 +}
 +
 +void wear_multiple(const uuid_vec_t& ids, bool replace)
 +{
 +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
 +	
 +	bool first = true;
 +	uuid_vec_t::const_iterator it;
 +	for (it = ids.begin(); it != ids.end(); ++it)
 +	{
 +		// if replace is requested, the first item worn will replace the current top
 +		// item, and others will be added.
 +		LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb);
 +		first = false;
 +	}
 +}
 +
 +// SLapp for easy-wearing of a stock (library) avatar
 +//
 +class LLWearFolderHandler : public LLCommandHandler
 +{
 +public:
 +	// not allowed from outside the app
 +	LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { }
 +
 +	bool handle(const LLSD& tokens, const LLSD& query_map,
 +				LLMediaCtrl* web)
 +	{
 +		LLSD::UUID folder_uuid;
 +
 +		if (folder_uuid.isNull() && query_map.has("folder_name"))
 +		{
 +			std::string outfit_folder_name = query_map["folder_name"];
 +			folder_uuid = findDescendentCategoryIDByName(
 +				gInventory.getLibraryRootFolderID(),
 +				outfit_folder_name);	
 +		}
 +		if (folder_uuid.isNull() && query_map.has("folder_id"))
 +		{
 +			folder_uuid = query_map["folder_id"].asUUID();
 +		}
 +		
 +		if (folder_uuid.notNull())
 +		{
 +			LLPointer<LLInventoryCategory> category = new LLInventoryCategory(folder_uuid,
 +																			  LLUUID::null,
 +																			  LLFolderType::FT_CLOTHING,
 +																			  "Quick Appearance");
 +			if ( gInventory.getCategory( folder_uuid ) != NULL )
 +			{
 +				LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);
 +				
 +				// *TODOw: This may not be necessary if initial outfit is chosen already -- josh
 +				gAgent.setOutfitChosen(TRUE);
 +			}
 +		}
 +
 +		// release avatar picker keyboard focus
 +		gFocusMgr.setKeyboardFocus( NULL );
 +
 +		return true;
 +	}
 +};
 +
 +LLWearFolderHandler gWearFolderHandler;
 diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 7742a19c07..74d4829ed2 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -225,9 +225,22 @@ public:  	void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; }  	std::string getAppearanceServiceURL() const; + +	bool testCOFRequestVersion() const; +	void LLAppearanceMgr::decrementInFlightCounter()
 +	{
 +		mInFlightCounter = llmax(mInFlightCounter - 1, 0);
 +	}
 + +  private:  	std::string		mAppearanceServiceURL; +	LLCore::HttpRequest::ptr_t		mHttpRequest; +	LLCore::HttpHeaders::ptr_t		mHttpHeaders; +	LLCore::HttpOptions::ptr_t		mHttpOptions; +	LLCore::HttpRequest::policy_t	mHttpPolicy; +	LLCore::HttpRequest::priority_t	mHttpPriority;  protected:  	LLAppearanceMgr(); @@ -248,17 +261,20 @@ private:  	static void onOutfitRename(const LLSD& notification, const LLSD& response); +	bool onIdle(); +  	bool mAttachmentInvLinkEnabled;  	bool mOutfitIsDirty;  	bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. -	LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder; -  	/**  	 * Lock for blocking operations on outfit until server reply or timeout exceed  	 * to avoid unsynchronized outfit state or performing duplicate operations.  	 */  	bool mOutfitLocked; +	S32  mInFlightCounter;
 +	LLTimer mInFlightTimer;
 +	static bool mActive;
  	std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer; diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index 81372f10b3..065d763596 100755 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -660,7 +660,7 @@ void LLMaterialMgr::processGetQueue()  		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '" << capURL << " for " << materialsData.size() << " materials."  			<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL; -		LLCore::HttpHandle handle = LLCoreHttpUtil::requestPutWithLLSD(mHttpRequest,  +		LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,   				mHttpPolicy, mHttpPriority, capURL,   				postData, mHttpOptions, mHttpHeaders, handler); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index f7b886b2d2..702d0c3a29 100755 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -401,14 +401,6 @@ LLXMLRPCTransaction::Impl::~Impl()  	{  		XMLRPC_RequestFree(mResponse, 1);  	} -	 -	//if (mRequestText) -	//{ -	//	XMLRPC_Free(mRequestText); -	//} -	 -	//delete mCurlRequest; -	//mCurlRequest = NULL ;  }  bool LLXMLRPCTransaction::Impl::process()  | 
