diff options
| author | Rider Linden <none@none> | 2015-03-26 10:34:19 -0700 | 
|---|---|---|
| committer | Rider Linden <none@none> | 2015-03-26 10:34:19 -0700 | 
| commit | f6ba7514d2392bfb5bbbe8b003b4b860118fddc5 (patch) | |
| tree | 972a4cda81e293a6734b1c5e91185193139829f0 | |
| parent | 77a9d183aa94496bd3e7d354f0744d0509bc3734 (diff) | |
Fix line endings on appearancemgr and added LLCore::Http to llAgent.
| -rwxr-xr-x | indra/newview/llagent.cpp | 156 | ||||
| -rwxr-xr-x | indra/newview/llagent.h | 14 | ||||
| -rwxr-xr-x | indra/newview/llappearancemgr.cpp | 8084 | ||||
| -rwxr-xr-x | indra/newview/llappearancemgr.h | 15 | 
4 files changed, 4154 insertions, 4115 deletions
| diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f151b15e29..ff0e2c42c1 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -95,6 +95,8 @@  #include "lscript_byteformat.h"  #include "stringize.h"  #include "boost/foreach.hpp" +#include "llhttpsdhandler.h" +#include "llcorehttputil.h"  using namespace LLAvatarAppearanceDefines; @@ -323,6 +325,7 @@ bool LLAgent::isMicrophoneOn(const LLSD& sdname)  // For a toggled version, see viewer.h for the  // TOGGLE_HACKED_GODLIKE_VIEWER define, instead.  // ************************************************************ +bool LLAgent::mActive = true;  // Constructors and Destructors @@ -361,7 +364,12 @@ LLAgent::LLAgent() :  	mMaturityPreferenceNumRetries(0U),  	mLastKnownRequestMaturity(SIM_ACCESS_MIN),  	mLastKnownResponseMaturity(SIM_ACCESS_MIN), -	mTeleportState( TELEPORT_NONE ), +	mHttpRequest(), +	mHttpHeaders(), +	mHttpOptions(), +	mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), +	mHttpPriority(0), +	mTeleportState(TELEPORT_NONE),  	mRegionp(NULL),  	mAgentOriginGlobal(), @@ -459,6 +467,15 @@ void LLAgent::init()  		mTeleportFailedSlot = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&LLAgent::handleTeleportFailed, this));  	} +	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); + +	doOnIdleRepeating(boost::bind(&LLAgent::onIdle, this)); +  	mInitialized = TRUE;  } @@ -467,6 +484,7 @@ void LLAgent::init()  //-----------------------------------------------------------------------------  void LLAgent::cleanup()  { +	mActive = false;  	mRegionp = NULL;  	if (mTeleportFinishedSlot.connected())  	{ @@ -498,6 +516,17 @@ LLAgent::~LLAgent()  	mTeleportSourceSLURL = NULL;  } +//----------------------------------------------------------------------------- +// Idle processing +//----------------------------------------------------------------------------- +bool LLAgent::onIdle() +{ +	if (!LLAgent::mActive) +		return true; +	mHttpRequest->update(0L); +	return false; +} +  // Handle any actions that need to be performed when the main app gains focus  // (such as through alt-tab).  //----------------------------------------------------------------------------- @@ -2515,66 +2544,61 @@ int LLAgent::convertTextToMaturity(char text)  	return LLAgentAccess::convertTextToMaturity(text);  } -class LLMaturityPreferencesResponder : public LLHTTPClient::Responder +//========================================================================= +class LLMaturityHttpHandler : public LLHttpSDHandler  { -	LOG_CLASS(LLMaturityPreferencesResponder);  public: -	LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity); -	virtual ~LLMaturityPreferencesResponder(); +	LLMaturityHttpHandler(const std::string& capabilityURL, LLAgent *agent, U8 preferred, U8 previous): +		LLHttpSDHandler(capabilityURL), +		mAgent(agent), +		mPreferredMaturity(preferred), +		mPreviousMaturity(previous) +	{ } -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); +	virtual ~LLMaturityHttpHandler() +	{ }  protected: +	virtual void onSuccess(LLCore::HttpResponse * response, LLSD &content); +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);  private: -	U8 parseMaturityFromServerResponse(const LLSD &pContent) const; - -	LLAgent                                  *mAgent; -	U8                                       mPreferredMaturity; -	U8                                       mPreviousMaturity; -}; +	U8 LLMaturityHttpHandler::parseMaturityFromServerResponse(const LLSD &pContent) const; -LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity) -	: LLHTTPClient::Responder(), -	mAgent(pAgent), -	mPreferredMaturity(pPreferredMaturity), -	mPreviousMaturity(pPreviousMaturity) -{ -} +	LLAgent *	mAgent; +	U8			mPreferredMaturity; +	U8          mPreviousMaturity; -LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder() -{ -} +}; -void LLMaturityPreferencesResponder::httpSuccess() +//------------------------------------------------------------------------- +void LLMaturityHttpHandler::onSuccess(LLCore::HttpResponse * response, LLSD &content)  { -	U8 actualMaturity = parseMaturityFromServerResponse(getContent()); +	U8 actualMaturity = parseMaturityFromServerResponse(content);  	if (actualMaturity != mPreferredMaturity)  	{  		LL_WARNS() << "while attempting to change maturity preference from '" -				   << LLViewerRegion::accessToString(mPreviousMaturity) -				   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  -				   << "', the server responded with '" -				   << LLViewerRegion::accessToString(actualMaturity)  -				   << "' [value:" << static_cast<U32>(actualMaturity)  -				   << "], " << dumpResponse() << LL_ENDL; +			<< LLViewerRegion::accessToString(mPreviousMaturity) +			<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) +			<< "', the server responded with '" +			<< LLViewerRegion::accessToString(actualMaturity) +			<< "' [value:" << static_cast<U32>(actualMaturity) +			<< "], " << LL_ENDL;  	}  	mAgent->handlePreferredMaturityResult(actualMaturity);  } -void LLMaturityPreferencesResponder::httpFailure() +void LLMaturityHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)  { -	LL_WARNS() << "while attempting to change maturity preference from '"  -			   << LLViewerRegion::accessToString(mPreviousMaturity) -			   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  -			<< "', " << dumpResponse() << LL_ENDL; +	LL_WARNS() << "while attempting to change maturity preference from '" +		<< LLViewerRegion::accessToString(mPreviousMaturity) +		<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) +		<< "', " << LL_ENDL;  	mAgent->handlePreferredMaturityError();  } -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const +U8 LLMaturityHttpHandler::parseMaturityFromServerResponse(const LLSD &pContent) const  {  	U8 maturity = SIM_ACCESS_MIN; @@ -2595,6 +2619,7 @@ U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &p  	return maturity;  } +//=========================================================================  void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity)  { @@ -2724,38 +2749,41 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)  		// Update the last know maturity request  		mLastKnownRequestMaturity = pPreferredMaturity; -		// Create a response handler -		LLHTTPClient::ResponderPtr responderPtr = LLHTTPClient::ResponderPtr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity)); -  		// If we don't have a region, report it as an error  		if (getRegion() == NULL)  		{ -			responderPtr->failureResult(0U, "region is not defined", LLSD()); +			LL_WARNS("Agent") << "Region is not defined, can not change Maturity setting." << LL_ENDL; +			return;  		} -		else +		std::string url = getRegion()->getCapability("UpdateAgentInformation"); + +		// If the capability is not defined, report it as an error +		if (url.empty())  		{ -			// Find the capability to send maturity preference -			std::string url = getRegion()->getCapability("UpdateAgentInformation"); +			LL_WARNS("Agent") << "'UpdateAgentInformation' is not defined for region" << LL_ENDL; +			return; +		} -			// If the capability is not defined, report it as an error -			if (url.empty()) -			{ -				responderPtr->failureResult(0U,  -							"capability 'UpdateAgentInformation' is not defined for region", LLSD()); -			} -			else -			{ -				// Set new access preference -				LLSD access_prefs = LLSD::emptyMap(); -				access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); - -				LLSD body = LLSD::emptyMap(); -				body["access_prefs"] = access_prefs; -				LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) -					<< "' via capability to: " << url << LL_ENDL; -				LLSD headers; -				LLHTTPClient::post(url, body, responderPtr, headers, 30.0f); -			} +		LLMaturityHttpHandler * handler = new LLMaturityHttpHandler(url, this, pPreferredMaturity, mLastKnownResponseMaturity); + +		LLSD access_prefs = LLSD::emptyMap(); +		access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); + +		LLSD postData = LLSD::emptyMap(); +		postData["access_prefs"] = access_prefs; +		LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) +			<< "' via capability to: " << url << LL_ENDL; + +		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") << "Maturity request post failed Reason " << status.toTerseString() +				<< " \"" << status.toString() << "\"" << LL_ENDL;  		}  	}  } diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 56bd1428ce..278e4c0fa1 100755 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -35,6 +35,9 @@  #include "llavatarappearancedefines.h"  #include "llpermissionsflags.h"  #include "v3dmath.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h"  #include <boost/function.hpp>  #include <boost/shared_ptr.hpp> @@ -112,6 +115,10 @@ public:  	void			init();  	void			cleanup(); +private: +	bool			onIdle(); + +	static bool		mActive;  	//--------------------------------------------------------------------  	// Login  	//-------------------------------------------------------------------- @@ -754,11 +761,16 @@ private:  	unsigned int                    mMaturityPreferenceNumRetries;  	U8                              mLastKnownRequestMaturity;  	U8                              mLastKnownResponseMaturity; +	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;  	bool            isMaturityPreferenceSyncedWithServer() const;  	void 			sendMaturityPreferenceToServer(U8 pPreferredMaturity); -	friend class LLMaturityPreferencesResponder; +	friend class	LLMaturityHttpHandler;  	void            handlePreferredMaturityResult(U8 pServerMaturity);  	void            handlePreferredMaturityError();  	void            reportPreferredMaturitySuccess(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index dbc858bdb0..bb4228dbb2 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1,3490 +1,3490 @@ -/** 
 - * @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;
 -}
 -
 -//=========================================================================
 -class LLAppearanceMgrHttpHandler : public LLHttpSDHandler
 -{
 -public:
 -	LLAppearanceMgrHttpHandler(const std::string& capabilityURL, LLAppearanceMgr *mgr) :
 -		LLHttpSDHandler(capabilityURL),
 -		mManager(mgr)
 -	{ }
 -
 -	virtual ~LLAppearanceMgrHttpHandler()
 -	{ }
 -
 +/**  + * @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; +} + +//========================================================================= +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;
 -
 -};
 -
 -//-------------------------------------------------------------------------
 +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();
 -
 +	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;
 -	}
 -}
 -
 -//=========================================================================
 -
 -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);
 -	}
 -		
 -}
 -
 -
 -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)
 -	{
 + +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; +	} +} + +//========================================================================= + +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); +	} +		 +} + + +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;
 -}
 -
 +		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) @@ -3492,566 +3492,566 @@ bool LLAppearanceMgr::onIdle()  	mHttpRequest->update(0L);  	return false;  } -
 -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;
 + +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 707b8d5a77..b90ef65f95 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -34,7 +34,6 @@  #include "llinventorymodel.h"  #include "llinventoryobserver.h"  #include "llviewerinventory.h" -#include "llhttpclient.h"  class LLWearableHoldingPattern;  class LLInventoryCallback; @@ -218,10 +217,10 @@ public:  	bool testCOFRequestVersion() const; -	void decrementInFlightCounter()
 -	{
 -		mInFlightCounter = llmax(mInFlightCounter - 1, 0);
 -	}
 +	void decrementInFlightCounter() +	{ +		mInFlightCounter = llmax(mInFlightCounter - 1, 0); +	}  private: @@ -263,9 +262,9 @@ private:  	 * to avoid unsynchronized outfit state or performing duplicate operations.  	 */  	bool mOutfitLocked; -	S32  mInFlightCounter;
 -	LLTimer mInFlightTimer;
 -	static bool mActive;
 +	S32  mInFlightCounter; +	LLTimer mInFlightTimer; +	static bool mActive;  	std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer; | 
