diff options
Diffstat (limited to 'indra/newview')
137 files changed, 6270 insertions, 3576 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e2ae7a5a9a..405e9a5d86 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -99,6 +99,7 @@ include_directories(SYSTEM  set(viewer_SOURCE_FILES      groupchatlistener.cpp      llaccountingcostmanager.cpp +    llaisapi.cpp      llagent.cpp      llagentaccess.cpp      llagentcamera.cpp @@ -306,6 +307,7 @@ set(viewer_SOURCE_FILES      llhasheduniqueid.cpp      llhints.cpp      llhomelocationresponder.cpp +    llhttpretrypolicy.cpp      llhudeffect.cpp      llhudeffectbeam.cpp      llhudeffectlookat.cpp @@ -682,6 +684,7 @@ set(viewer_HEADER_FILES      ViewerInstall.cmake      groupchatlistener.h      llaccountingcostmanager.h +    llaisapi.h      llagent.h      llagentaccess.h      llagentcamera.h @@ -888,6 +891,7 @@ set(viewer_HEADER_FILES      llgroupmgr.h      llhasheduniqueid.h      llhints.h +    llhttpretrypolicy.h      llhomelocationresponder.h      llhudeffect.h      llhudeffectbeam.h @@ -2138,10 +2142,21 @@ if (LL_TESTS)      #llviewertexturelist.cpp    ) +  set(test_libs +    ${JSONCPP_LIBRARIES} +    ${CURL_LIBRARIES} +    ) +    set_source_files_properties(      lltranslate.cpp      PROPERTIES -    LL_TEST_ADDITIONAL_LIBRARIES "${JSONCPP_LIBRARIES}" +    LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}" +  ) + +  set_source_files_properties( +    llmediadataclient.cpp +    PROPERTIES +    LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}"    )    set_source_files_properties( @@ -2222,6 +2237,7 @@ if (LL_TESTS)    set(test_libs      ${LLMESSAGE_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES} @@ -2267,6 +2283,8 @@ if (LL_TESTS)      "${test_libs}"      ) +  LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}") +    #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)    #ADD_VIEWER_BUILD_TEST(llagentaccess viewer)    #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer) diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index 92a241857e..6594fdb249 100755 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -43,6 +43,7 @@  					<key>tags</key>  						<array>  						<!-- sample entry for debugging specific items	 +						     <string>Inventory</string>  						     <string>Avatar</string>  						     <string>Voice</string>		  						--> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 72fe21cf14..501552664a 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11422,6 +11422,17 @@        <key>Value</key>        <integer>0</integer>      </map> +  <key>TextureFetchFakeFailureRate</key> +  <map> +    <key>Comment</key> +    <string>Simulate HTTP fetch failures for some server bake textures.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>F32</string> +    <key>Value</key> +    <integer>0.0</integer> +  </map>      <key>TextureFetchSource</key>      <map>        <key>Comment</key> diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index e5b385f4aa..e28bb6969a 100755 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -7563,7 +7563,7 @@ render_pass="bump">        <param         id="868" -       group="0" +       group="3"         wearable="shirt"         edit_group="shirt"         edit_group_order="8" @@ -8686,7 +8686,7 @@ render_pass="bump">        <param         id="869" -       group="0" +       group="3"         wearable="pants"         edit_group="pants"         edit_group_order="6" @@ -9607,7 +9607,7 @@ render_pass="bump">      <param       id="163" -     group="0" +     group="3"       wearable="skin"       edit_group="skin_facedetail"       edit_group_order="3" @@ -11666,7 +11666,7 @@ render_pass="bump">      <param       id="877" -     group="0" +     group="3"       name="Jacket Wrinkles"       label="Jacket Wrinkles"       wearable="jacket" diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 7662a9689d..55d453cdcc 100755 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -36,6 +36,7 @@ LLAccountingCostManager::LLAccountingCostManager()  //===============================================================================  class LLAccountingCostResponder : public LLCurl::Responder  { +	LOG_CLASS(LLAccountingCostResponder);  public:  	LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle )  	: mObjectIDs( objectIDs ), @@ -56,24 +57,27 @@ public:  		}  	} -	void errorWithContent( U32 statusNum, const std::string& reason, const LLSD& content ) +protected: +	void httpFailure()  	{ -		llwarns << "Transport error [status:" << statusNum << "]: " << content <<llendl; +		llwarns << dumpResponse() << llendl;  		clearPendingRequests();  		LLAccountingCostObserver* observer = mObserverHandle.get();  		if (observer && observer->getTransactionID() == mTransactionID)  		{ -			observer->setErrorStatus(statusNum, reason); +			observer->setErrorStatus(getStatus(), getReason());  		}  	} -	void result( const LLSD& content ) +	void httpSuccess()  	{ +		const LLSD& content = getContent();  		//Check for error  		if ( !content.isMap() || content.has("error") )  		{ -			llwarns	<< "Error on fetched data"<< llendl; +			failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content); +			return;  		}  		else if (content.has("selected"))  		{ diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index 0bca1f54ef..3ade34c81d 100755 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -38,7 +38,7 @@ public:  	LLAccountingCostObserver() { mObserverHandle.bind(this); }  	virtual ~LLAccountingCostObserver() {}  	virtual void onWeightsUpdate(const SelectionCost& selection_cost) = 0; -	virtual void setErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setErrorStatus(S32 status, const std::string& reason) = 0;  	const LLHandle<LLAccountingCostObserver>& getObserverHandle() const { return mObserverHandle; }  	const LLUUID& getTransactionID() { return mTransactionID; } diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f4ce3c9118..5f87d73c40 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2537,17 +2537,19 @@ int LLAgent::convertTextToMaturity(char text)  class LLMaturityPreferencesResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLMaturityPreferencesResponder);  public:  	LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity);  	virtual ~LLMaturityPreferencesResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); +protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  protected:  private: -	U8 parseMaturityFromServerResponse(const LLSD &pContent); +	U8 parseMaturityFromServerResponse(const LLSD &pContent) const;  	LLAgent                                  *mAgent;  	U8                                       mPreferredMaturity; @@ -2566,39 +2568,43 @@ LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder()  {  } -void LLMaturityPreferencesResponder::result(const LLSD &pContent) +void LLMaturityPreferencesResponder::httpSuccess()  { -	U8 actualMaturity = parseMaturityFromServerResponse(pContent); +	U8 actualMaturity = parseMaturityFromServerResponse(getContent());  	if (actualMaturity != mPreferredMaturity)  	{ -		llwarns << "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) << ", llsd:" -			<< pContent << "]" << llendl; +		llwarns << "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() << llendl;  	}  	mAgent->handlePreferredMaturityResult(actualMaturity);  } -void LLMaturityPreferencesResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void LLMaturityPreferencesResponder::httpFailure()  { -	llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) -		<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', we got an error with [status:" -		<< pStatus << "]: " << (pContent.isDefined() ? pContent : LLSD(pReason)) << llendl; +	llwarns << "while attempting to change maturity preference from '"  +			<< LLViewerRegion::accessToString(mPreviousMaturity) +			<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  +			<< "', " << dumpResponse() << llendl;  	mAgent->handlePreferredMaturityError();  } -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) +U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const  {  	U8 maturity = SIM_ACCESS_MIN; -	llassert(!pContent.isUndefined()); +	llassert(pContent.isDefined());  	llassert(pContent.isMap());  	llassert(pContent.has("access_prefs"));  	llassert(pContent.get("access_prefs").isMap());  	llassert(pContent.get("access_prefs").has("max"));  	llassert(pContent.get("access_prefs").get("max").isString()); -	if (!pContent.isUndefined() && pContent.isMap() && pContent.has("access_prefs") +	if (pContent.isDefined() && pContent.isMap() && pContent.has("access_prefs")  		&& pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max")  		&& pContent.get("access_prefs").get("max").isString())  	{ @@ -2744,7 +2750,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)  		// If we don't have a region, report it as an error  		if (getRegion() == NULL)  		{ -			responderPtr->errorWithContent(0U, "region is not defined", LLSD()); +			responderPtr->failureResult(0U, "region is not defined", LLSD());  		}  		else  		{ @@ -2754,7 +2760,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)  			// If the capability is not defined, report it as an error  			if (url.empty())  			{ -				responderPtr->errorWithContent(0U,  +				responderPtr->failureResult(0U,   							"capability 'UpdateAgentInformation' is not defined for region", LLSD());  			}  			else @@ -3253,8 +3259,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode  			!input.has("body") )  		{  			//what to do with badly formed message? -			response->statusUnknownError(400); -			response->result(LLSD("Invalid message parameters")); +			response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters"));  		}  		LLSD body = input["body"]; @@ -3323,8 +3328,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode  		else  		{  			//what to do with badly formed message? -			response->statusUnknownError(400); -			response->result(LLSD("Invalid message parameters")); +			response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters"));  		}  	}  }; @@ -4303,7 +4307,7 @@ void LLAgent::sendAgentSetAppearance()  		return;  	} -	if (!isAgentAvatarValid() || (getRegion() && getRegion()->getCentralBakeVersion())) return; +	if (!isAgentAvatarValid() || gAgentAvatarp->isEditingAppearance() || (getRegion() && getRegion()->getCentralBakeVersion())) return;  	// At this point we have a complete appearance to send and are in a non-baking region.  	// DRANO FIXME @@ -4344,7 +4348,9 @@ void LLAgent::sendAgentSetAppearance()  	// to compensate for the COLLISION_TOLERANCE ugliness we will have   	// to tweak this number again  	const LLVector3 body_size = gAgentAvatarp->mBodySize + gAgentAvatarp->mAvatarOffset; -	msg->addVector3Fast(_PREHASH_Size, body_size);	 +	msg->addVector3Fast(_PREHASH_Size, body_size); +	 +	LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Sent AgentSetAppearance with height: " << body_size.mV[VZ] << " base: " << gAgentAvatarp->mBodySize.mV[VZ] << " hover: " << gAgentAvatarp->mAvatarOffset.mV[VZ] << LL_ENDL;	  	// To guard against out of order packets  	// Note: always start by sending 1.  This resets the server's count. 0 on the server means "uninitialized" @@ -4424,7 +4430,8 @@ void LLAgent::sendAgentSetAppearance()  		 param;  		 param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam())  	{ -		if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +		if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE || +			param->getGroup() == VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  		{  			msg->nextBlockFast(_PREHASH_VisualParam ); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 1edbbe2a2e..8501436b5b 100755 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -62,15 +62,15 @@ using namespace LLAvatarAppearanceDefines;  // Callback to wear and start editing an item that has just been created.  void wear_and_edit_cb(const LLUUID& inv_item) -	{ -		if (inv_item.isNull()) return; - -		// Request editing the item after it gets worn. -		gAgentWearables.requestEditingWearable(inv_item); - -		// Wear it. -		LLAppearanceMgr::instance().wearItemOnAvatar(inv_item); -	} +{ +	if (inv_item.isNull()) return; +	 +	// Request editing the item after it gets worn. +	gAgentWearables.requestEditingWearable(inv_item); +	 +	// Wear it. +	LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true); +}  /////////////////////////////////////////////////////////////////////////////// @@ -180,10 +180,10 @@ void LLAgentWearables::initClass()  }  void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) -{  +{  	llassert(avatar); -		avatar->outputRezTiming("Sending wearables request"); -		sendAgentWearablesRequest(); +	avatar->outputRezTiming("Sending wearables request"); +	sendAgentWearablesRequest();  	setAvatarAppearance(avatar);  } @@ -209,7 +209,7 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal   * @param wearable The wearable data.   * @param todo Bitmask of actions to take on completion.   */ -LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback( +LLAgentWearables::AddWearableToAgentInventoryCallback::AddWearableToAgentInventoryCallback(  	LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, U32 todo, const std::string description) :  	mType(type),  	mIndex(index),	 @@ -221,7 +221,7 @@ LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInvento  	llinfos << "constructor" << llendl;  } -void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) +void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)  {  	if (mTodo & CALL_CREATESTANDARDDONE)  	{ @@ -239,7 +239,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i  	}  	if (mTodo & CALL_RECOVERDONE)  	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); +		LLAppearanceMgr::instance().addCOFItemLink(inv_item);  		gAgentWearables.recoverMissingWearableDone();  	}  	/* @@ -247,7 +247,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i  	 */  	if (mTodo & CALL_CREATESTANDARDDONE)  	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); +		LLAppearanceMgr::instance().addCOFItemLink(inv_item);  		gAgentWearables.createStandardWearablesDone(mType, mIndex);  	}  	if (mTodo & CALL_MAKENEWOUTFITDONE) @@ -256,7 +256,8 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i  	}  	if (mTodo & CALL_WEARITEM)  	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription); +		LLAppearanceMgr::instance().addCOFItemLink(inv_item,  +			new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription);  	}  } @@ -316,12 +317,12 @@ void LLAgentWearables::sendAgentWearablesUpdate()  				if (wearable->getItemID().isNull())  				{  					LLPointer<LLInventoryCallback> cb = -						new addWearableToAgentInventoryCallback( +						new AddWearableToAgentInventoryCallback(  							LLPointer<LLRefCount>(NULL),  							(LLWearableType::EType)type,  							index,  							wearable, -							addWearableToAgentInventoryCallback::CALL_NONE); +							AddWearableToAgentInventoryCallback::CALL_NONE);  					addWearableToAgentInventory(cb, wearable);  				}  				else @@ -418,23 +419,18 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32  										  item->getFlags(),  										  item->getCreationDate());  			template_item->setTransactionID(new_wearable->getTransactionID()); -			template_item->updateServer(FALSE); -			gInventory.updateItem(template_item); -			if (name_changed) -			{ -				gInventory.notifyObservers(); -			} +			update_inventory_item(template_item, gAgentAvatarp->mEndCustomizeCallback);  		}  		else  		{  			// Add a new inventory item (shouldn't ever happen here) -			U32 todo = addWearableToAgentInventoryCallback::CALL_NONE; +			U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE;  			if (send_update)  			{ -				todo |= addWearableToAgentInventoryCallback::CALL_UPDATE; +				todo |= AddWearableToAgentInventoryCallback::CALL_UPDATE;  			}  			LLPointer<LLInventoryCallback> cb = -				new addWearableToAgentInventoryCallback( +				new AddWearableToAgentInventoryCallback(  					LLPointer<LLRefCount>(NULL),  					type,  					index, @@ -483,12 +479,12 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type,  		old_wearable,  		trunc_name);  	LLPointer<LLInventoryCallback> cb = -		new addWearableToAgentInventoryCallback( +		new AddWearableToAgentInventoryCallback(  			LLPointer<LLRefCount>(NULL),  			type,  			index,  			new_wearable, -			addWearableToAgentInventoryCallback::CALL_WEARITEM, +			AddWearableToAgentInventoryCallback::CALL_WEARITEM,  			description  			);  	LLUUID category_id; @@ -706,7 +702,7 @@ LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::ETyp  }  const LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/) const -	{ +{  	return dynamic_cast<const LLViewerWearable*> (getWearable(type, index));  } @@ -714,39 +710,39 @@ const LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType  BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type)  {  	return (gAgentWearables.getWearableCount(type) > 0); -	} -	 +} +  // virtual  void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) -	{ +{  	if (isAgentAvatarValid())  	{  		const BOOL upload_result = removed;  		gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result); -} +	}  	LLWearableData::wearableUpdated(wearable, removed);  	if (!removed) -{ +	{  		LLViewerWearable* viewer_wearable = dynamic_cast<LLViewerWearable*>(wearable);  		viewer_wearable->refreshName(); -	// Hack pt 2. If the wearable we just loaded has definition version 24, -	// then force a re-save of this wearable after slamming the version number to 22. -	// This number was incorrectly incremented for internal builds before release, and -	// this fix will ensure that the affected wearables are re-saved with the right version number. -	// the versions themselves are compatible. This code can be removed before release. -	if( wearable->getDefinitionVersion() == 24 ) -	{ -		wearable->setDefinitionVersion(22); -		U32 index = getWearableIndex(wearable); +		// Hack pt 2. If the wearable we just loaded has definition version 24, +		// then force a re-save of this wearable after slamming the version number to 22. +		// This number was incorrectly incremented for internal builds before release, and +		// this fix will ensure that the affected wearables are re-saved with the right version number. +		// the versions themselves are compatible. This code can be removed before release. +		if( wearable->getDefinitionVersion() == 24 ) +		{ +			wearable->setDefinitionVersion(22); +			U32 index = getWearableIndex(wearable);  			llinfos << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << llendl; -		saveWearable(wearable->getType(),index,TRUE); -	} +			saveWearable(wearable->getType(),index,TRUE); +		}  		checkWearableAgainstInventory(viewer_wearable); -} +	}  }  BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const @@ -908,12 +904,12 @@ void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type,  	// destory content.) JC  	const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);  	LLPointer<LLInventoryCallback> cb = -		new addWearableToAgentInventoryCallback( +		new AddWearableToAgentInventoryCallback(  			LLPointer<LLRefCount>(NULL),  			type,  			index,  			new_wearable, -			addWearableToAgentInventoryCallback::CALL_RECOVERDONE); +			AddWearableToAgentInventoryCallback::CALL_RECOVERDONE);  	addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE);  } @@ -956,17 +952,17 @@ public:  	/* virtual */ void fire(const LLUUID& inv_item)  	{  		llinfos << "One item created " << inv_item.asString() << llendl; -		LLViewerInventoryItem *item = gInventory.getItem(inv_item); -		mItemsToLink.put(item); +		LLConstPointer<LLInventoryObject> item = gInventory.getItem(inv_item); +		mItemsToLink.push_back(item);  		updatePendingWearable(inv_item);  	}  	~OnWearableItemCreatedCB()  	{  		llinfos << "All items created" << llendl;  		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; -		LLAppearanceMgr::instance().linkAll(LLAppearanceMgr::instance().getCOF(), -												mItemsToLink, -												link_waiter); +		link_inventory_array(LLAppearanceMgr::instance().getCOF(), +											mItemsToLink, +											link_waiter);  	}  	void addPendingWearable(LLViewerWearable *wearable)  	{ @@ -1015,7 +1011,7 @@ public:  	}  private: -	LLInventoryModel::item_array_t mItemsToLink; +	LLInventoryObject::const_object_list_t mItemsToLink;  	std::vector<LLViewerWearable*> mWearablesAwaitingItems;  }; @@ -1234,30 +1230,86 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo  // Assumes existing wearables are not dirty.  void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items, -										 const LLDynamicArray< LLViewerWearable* >& wearables, -										 BOOL remove) +										 const LLDynamicArray< LLViewerWearable* >& wearables)  {  	llinfos << "setWearableOutfit() start" << llendl; +	S32 count = wearables.count(); +	llassert(items.count() == count); + +	// Check for whether outfit already matches the one requested +	S32 matched = 0, mismatched = 0; +	const S32 arr_size = LLWearableType::WT_COUNT; +	S32 type_counts[arr_size]; +	std::fill(type_counts,type_counts+arr_size,0); +	for (S32 i = 0; i < count; i++) +	{ +		LLViewerWearable* new_wearable = wearables[i]; +		LLPointer<LLInventoryItem> new_item = items[i]; + +		const LLWearableType::EType type = new_wearable->getType(); +		if (type < 0 || type>=LLWearableType::WT_COUNT) +		{ +			llwarns << "invalid type " << type << llendl; +			mismatched++; +			continue; +		} +		S32 index = type_counts[type]; +		type_counts[type]++; + +		LLViewerWearable *curr_wearable = dynamic_cast<LLViewerWearable*>(getWearable(type,index)); +		if (!new_wearable || !curr_wearable || +			new_wearable->getAssetID() != curr_wearable->getAssetID()) +		{ +			LL_DEBUGS("Avatar") << "mismatch, type " << type << " index " << index +								<< " names " << (curr_wearable ? curr_wearable->getName() : "NONE")  << "," +								<< " names " << (new_wearable ? new_wearable->getName() : "NONE")  << llendl; +			mismatched++; +			continue; +		} + +		if (curr_wearable->getName() != new_item->getName() || +			curr_wearable->getItemID() != new_item->getUUID()) +		{ +			LL_DEBUGS("Avatar") << "mismatch on name or inventory id, names " +								<< curr_wearable->getName() << " vs " << new_item->getName() +								<< " item ids " << curr_wearable->getItemID() << " vs " << new_item->getUUID() +								<< llendl; +			mismatched++; +			continue; +		} +		// If we got here, everything matches. +		matched++; +	} +	LL_DEBUGS("Avatar") << "matched " << matched << " mismatched " << mismatched << llendl; +	for (S32 j=0; j<LLWearableType::WT_COUNT; j++) +	{ +		LLWearableType::EType type = (LLWearableType::EType) j; +		if (getWearableCount(type) != type_counts[j]) +		{ +			LL_DEBUGS("Avatar") << "count mismatch for type " << j << " current " << getWearableCount(j) << " requested " << type_counts[j] << llendl;  +			mismatched++; +		} +	} +	if (mismatched == 0) +	{ +		LL_DEBUGS("Avatar") << "no changes, bailing out" << llendl; +		return; +	} +	 +	  	// TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later -	if (remove) +	// note: shirt is the first non-body part wearable item. Update if wearable order changes. +	// This loop should remove all clothing, but not any body parts +	for (S32 j = 0; j < (S32)LLWearableType::WT_COUNT; j++)  	{ -		// note: shirt is the first non-body part wearable item. Update if wearable order changes. -		// This loop should remove all clothing, but not any body parts -		for (S32 type = 0; type < (S32)LLWearableType::WT_COUNT; type++) +		if (LLWearableType::getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING)  		{ -			if (LLWearableType::getAssetType((LLWearableType::EType)type) == LLAssetType::AT_CLOTHING) -			{ -				removeWearable((LLWearableType::EType)type, true, 0); -			} +			removeWearable((LLWearableType::EType)j, true, 0);  		}  	} -	S32 count = wearables.count(); -	llassert(items.count() == count); - -	S32 i; -	for (i = 0; i < count; i++) +	for (S32 i = 0; i < count; i++)  	{  		LLViewerWearable* new_wearable = wearables[i];  		LLPointer<LLInventoryItem> new_item = items[i]; @@ -1311,7 +1363,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it  	gAgentAvatarp->dumpAvatarTEs("setWearableOutfit"); -	lldebugs << "setWearableOutfit() end" << llendl; +	LL_DEBUGS("Avatar") << "setWearableOutfit() end" << llendl;  } @@ -1442,6 +1494,7 @@ void LLAgentWearables::queryWearableCache()  	{  		return;  	} +	gAgentAvatarp->setIsUsingServerBakes(false);  	// Look up affected baked textures.  	// If they exist: @@ -1496,12 +1549,12 @@ void LLAgentWearables::queryWearableCache()  // virtual  void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const  { -		// Add some garbage into the hash so that it becomes invalid. -			if (isAgentAvatarValid()) -			{ -				hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES); -			} -		} +	// Add some garbage into the hash so that it becomes invalid. +	if (isAgentAvatarValid()) +	{ +		hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES); +	} +}  // User has picked "remove from avatar" from a menu.  // static @@ -1860,24 +1913,6 @@ void LLAgentWearables::updateServer()  	gAgent.sendAgentSetAppearance();  } -void LLAgentWearables::populateMyOutfitsFolder(void) -{	 -	llinfos << "starting outfit population" << llendl; - -	const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch(my_outfits_id); -	outfits->mMyOutfitsID = my_outfits_id; -	 -	// Get the complete information on the items in the inventory and  -	// setup an observer that will wait for that to happen. -	gInventory.addObserver(outfits); -	outfits->startFetch(); -	if (outfits->isFinished()) -	{ -		outfits->done(); -	} -} -  boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb)  {  	return mLoadingStartedSignal.connect(cb); @@ -1896,6 +1931,7 @@ bool LLAgentWearables::changeInProgress() const  void LLAgentWearables::notifyLoadingStarted()  {  	mCOFChangeInProgress = true; +	mCOFChangeTimer.reset();  	mLoadingStartedSignal();  } diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 5be4648636..96fe4b80c0 100755 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -77,6 +77,7 @@ public:  	BOOL			isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const;  	BOOL			areWearablesLoaded() const;  	bool			isCOFChangeInProgress() const { return mCOFChangeInProgress; } +	F32				getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); }  	void			updateWearablesLoaded();  	void			checkWearablesLoaded() const;  	bool			canMoveWearable(const LLUUID& item_id, bool closer_to_body) const; @@ -107,7 +108,7 @@ private:  	/*virtual*/void	wearableUpdated(LLWearable *wearable, BOOL removed);  public:  	void			setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); -	void			setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLViewerWearable* >& wearables, BOOL remove); +	void			setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLViewerWearable* >& wearables);  	void			setWearableName(const LLUUID& item_id, const std::string& new_name);  	// *TODO: Move this into llappearance/LLWearableData ?  	void			addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index); @@ -170,12 +171,6 @@ protected:  	//--------------------------------------------------------------------  	// Outfits  	//-------------------------------------------------------------------- -public: -	 -	// Should only be called if we *know* we've never done so before, since users may -	// not want the Library outfits to stay in their quick outfit selector and can delete them. -	void			populateMyOutfitsFolder(); -  private:  	void			makeNewOutfitDone(S32 type, U32 index);  @@ -237,6 +232,7 @@ private:  	 * True if agent's outfit is being changed now.  	 */  	BOOL			mCOFChangeInProgress; +	LLTimer			mCOFChangeTimer;  	//--------------------------------------------------------------------------------  	// Support classes @@ -253,7 +249,7 @@ private:  		~sendAgentWearablesUpdateCallback();  	}; -	class addWearableToAgentInventoryCallback : public LLInventoryCallback +	class AddWearableToAgentInventoryCallback : public LLInventoryCallback  	{  	public:  		enum ETodo @@ -266,7 +262,7 @@ private:  			CALL_WEARITEM = 16  		}; -		addWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb, +		AddWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb,  											LLWearableType::EType type,  											U32 index,  											LLViewerWearable* wearable, diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp index 8b6b6db525..a2a667e660 100755 --- a/indra/newview/llagentwearablesfetch.cpp +++ b/indra/newview/llagentwearablesfetch.cpp @@ -35,46 +35,6 @@  #include "llvoavatarself.h" -void order_my_outfits_cb() -	{ -		if (!LLApp::isRunning()) -		{ -			llwarns << "called during shutdown, skipping" << llendl; -			return; -		} -		 -		const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -		if (my_outfits_id.isNull()) return; - -		LLInventoryModel::cat_array_t* cats; -		LLInventoryModel::item_array_t* items; -		gInventory.getDirectDescendentsOf(my_outfits_id, cats, items); -		if (!cats) return; - -		//My Outfits should at least contain saved initial outfit and one another outfit -		if (cats->size() < 2) -		{ -			llwarning("My Outfits category was not populated properly", 0); -			return; -		} - -		llinfos << "Starting updating My Outfits with wearables ordering information" << llendl; - -		for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin(); -			outfit_iter != cats->end(); ++outfit_iter) -		{ -			const LLUUID& cat_id = (*outfit_iter)->getUUID(); -			if (cat_id.isNull()) continue; - -			// saved initial outfit already contains wearables ordering information -			if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue; - -			LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id); -		} - -		llinfos << "Finished updating My Outfits with wearables ordering information" << llendl; -	} -  LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) :  	LLInventoryFetchDescendentsObserver(cof_id)  { @@ -157,26 +117,21 @@ public:  		// Link to all fetched items in COF.  		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; +		LLInventoryObject::const_object_list_t item_array;  		for (uuid_vec_t::iterator it = mIDs.begin();  			 it != mIDs.end();  			 ++it)  		{  			LLUUID id = *it; -			LLViewerInventoryItem *item = gInventory.getItem(*it); +			LLConstPointer<LLInventoryObject> item = gInventory.getItem(*it);  			if (!item)  			{ -				llwarns << "fetch failed!" << llendl; +				llwarns << "fetch failed for item " << (*it) << "!" << llendl;  				continue;  			} - -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								LLAppearanceMgr::instance().getCOF(), -								item->getName(), -								item->getDescription(), -								LLAssetType::AT_LINK, -								link_waiter); +			item_array.push_back(item);  		} +		link_inventory_array(LLAppearanceMgr::instance().getCOF(), item_array, link_waiter);  	}  }; @@ -244,357 +199,3 @@ void LLInitialWearablesFetch::processWearablesMessage()  	}  } -LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) :  -	LLInventoryFetchDescendentsObserver(my_outfits_id), -	mCurrFetchStep(LOFS_FOLDER),  -	mOutfitsPopulated(false)  -{ -	llinfos << "created" << llendl; - -	mMyOutfitsID = LLUUID::null; -	mClothingID = LLUUID::null; -	mLibraryClothingID = LLUUID::null; -	mImportedClothingID = LLUUID::null; -	mImportedClothingName = "Imported Library Clothing"; -} - -LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch() -{ -	llinfos << "destroyed" << llendl; -} - -void LLLibraryOutfitsFetch::done() -{ -	llinfos << "start" << llendl; - -	// Delay this until idle() routine, since it's a heavy operation and -	// we also can't have it run within notifyObservers. -	doOnIdleOneTime(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this)); -	gInventory.removeObserver(this); // Prevent doOnIdleOneTime from being added twice. -} - -void LLLibraryOutfitsFetch::doneIdle() -{ -	llinfos << "start" << llendl; - -	gInventory.addObserver(this); // Add this back in since it was taken out during ::done() -	 -	switch (mCurrFetchStep) -	{ -		case LOFS_FOLDER: -			folderDone(); -			mCurrFetchStep = LOFS_OUTFITS; -			break; -		case LOFS_OUTFITS: -			outfitsDone(); -			mCurrFetchStep = LOFS_LIBRARY; -			break; -		case LOFS_LIBRARY: -			libraryDone(); -			mCurrFetchStep = LOFS_IMPORTED; -			break; -		case LOFS_IMPORTED: -			importedFolderDone(); -			mCurrFetchStep = LOFS_CONTENTS; -			break; -		case LOFS_CONTENTS: -			contentsDone(); -			break; -		default: -			llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl; -			mOutfitsPopulated = TRUE; -			break; -	} - -	// We're completely done.  Cleanup. -	if (mOutfitsPopulated) -	{ -		gInventory.removeObserver(this); -		delete this; -		return; -	} -} - -void LLLibraryOutfitsFetch::folderDone() -{ -	llinfos << "start" << llendl; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	 -	// Early out if we already have items in My Outfits -	// except the case when My Outfits contains just initial outfit -	if (cat_array.count() > 1) -	{ -		mOutfitsPopulated = true; -		return; -	} - -	mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); -	mLibraryClothingID = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_CLOTHING, false); - -	// If Library->Clothing->Initial Outfits exists, use that. -	LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); -	cat_array.clear(); -	gInventory.collectDescendentsIf(mLibraryClothingID, -									cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, -									matchFolderFunctor); -	if (cat_array.count() > 0) -	{ -		const LLViewerInventoryCategory *cat = cat_array.get(0); -		mLibraryClothingID = cat->getUUID(); -	} - -	mComplete.clear(); -	 -	// Get the complete information on the items in the inventory. -	uuid_vec_t folders; -	folders.push_back(mClothingID); -	folders.push_back(mLibraryClothingID); -	setFetchIDs(folders); -	startFetch(); -	if (isFinished()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::outfitsDone() -{ -	llinfos << "start" << llendl; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	uuid_vec_t folders; -	 -	// Collect the contents of the Library's Clothing folder -	gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	 -	llassert(cat_array.count() > 0); -	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); -		 iter != cat_array.end(); -		 ++iter) -	{ -		const LLViewerInventoryCategory *cat = iter->get(); -		 -		// Get the names and id's of every outfit in the library, skip "Ruth" -		// because it's a low quality legacy outfit -		if (cat->getName() != "Ruth") -		{ -			// Get the name of every outfit in the library  -			folders.push_back(cat->getUUID()); -			mLibraryClothingFolders.push_back(cat->getUUID()); -		} -	} -	cat_array.clear(); -	wearable_array.clear(); - -	// Check if you already have an "Imported Library Clothing" folder -	LLNameCategoryCollector matchFolderFunctor(mImportedClothingName); -	gInventory.collectDescendentsIf(mClothingID,  -									cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, -									matchFolderFunctor); -	if (cat_array.size() > 0) -	{ -		const LLViewerInventoryCategory *cat = cat_array.get(0); -		mImportedClothingID = cat->getUUID(); -	} -	 -	mComplete.clear(); -	setFetchIDs(folders); -	startFetch(); -	if (isFinished()) -	{ -		done(); -	} -} - -class LLLibraryOutfitsCopyDone: public LLInventoryCallback -{ -public: -	LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher): -	mFireCount(0), mLibraryOutfitsFetcher(fetcher) -	{ -	} -	 -	virtual ~LLLibraryOutfitsCopyDone() -	{ -		if (!LLApp::isExiting() && mLibraryOutfitsFetcher) -		{ -			gInventory.addObserver(mLibraryOutfitsFetcher); -			mLibraryOutfitsFetcher->done(); -		} -	} -	 -	/* virtual */ void fire(const LLUUID& inv_item) -	{ -		mFireCount++; -	} -private: -	U32 mFireCount; -	LLLibraryOutfitsFetch * mLibraryOutfitsFetcher; -}; - -// Copy the clothing folders from the library into the imported clothing folder -void LLLibraryOutfitsFetch::libraryDone() -{ -	llinfos << "start" << llendl; - -	if (mImportedClothingID != LLUUID::null) -	{ -		// Skip straight to fetching the contents of the imported folder -		importedFolderFetch(); -		return; -	} - -	// Remove observer; next autopopulation step will be triggered externally by LLLibraryOutfitsCopyDone. -	gInventory.removeObserver(this); -	 -	LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this); -	mImportedClothingID = gInventory.createNewCategory(mClothingID, -													   LLFolderType::FT_NONE, -													   mImportedClothingName); -	// Copy each folder from library into clothing unless it already exists. -	for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin(); -		 iter != mLibraryClothingFolders.end(); -		 ++iter) -	{ -		const LLUUID& src_folder_id = (*iter); // Library clothing folder ID -		const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id); -		if (!cat) -		{ -			llwarns << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << llendl; -			continue; -		} -		 -		if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) -		{ -			llinfos << "Skipping non-outfit folder name:" << cat->getName() << llendl; -			continue; -		} -		 -		// Don't copy the category if it already exists. -		LLNameCategoryCollector matchFolderFunctor(cat->getName()); -		LLInventoryModel::cat_array_t cat_array; -		LLInventoryModel::item_array_t wearable_array; -		gInventory.collectDescendentsIf(mImportedClothingID,  -										cat_array, wearable_array,  -										LLInventoryModel::EXCLUDE_TRASH, -										matchFolderFunctor); -		if (cat_array.size() > 0) -		{ -			continue; -		} - -		LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID, -															LLFolderType::FT_NONE, -															cat->getName()); -		LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter); -	} -} - -void LLLibraryOutfitsFetch::importedFolderFetch() -{ -	llinfos << "start" << llendl; - -	// Fetch the contents of the Imported Clothing Folder -	uuid_vec_t folders; -	folders.push_back(mImportedClothingID); -	 -	mComplete.clear(); -	setFetchIDs(folders); -	startFetch(); -	if (isFinished()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::importedFolderDone() -{ -	llinfos << "start" << llendl; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	uuid_vec_t folders; -	 -	// Collect the contents of the Imported Clothing folder -	gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	 -	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); -		 iter != cat_array.end(); -		 ++iter) -	{ -		const LLViewerInventoryCategory *cat = iter->get(); -		 -		// Get the name of every imported outfit -		folders.push_back(cat->getUUID()); -		mImportedClothingFolders.push_back(cat->getUUID()); -	} -	 -	mComplete.clear(); -	setFetchIDs(folders); -	startFetch(); -	if (isFinished()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::contentsDone() -{		 -	llinfos << "start" << llendl; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	 -	LLPointer<LLInventoryCallback> order_myoutfits_on_destroy = new LLBoostFuncInventoryCallback(no_op_inventory_func, order_my_outfits_cb); - -	for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin(); -		 folder_iter != mImportedClothingFolders.end(); -		 ++folder_iter) -	{ -		const LLUUID &folder_id = (*folder_iter); -		const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); -		if (!cat) -		{ -			llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl; -			continue; -		} - -		//initial outfit should be already in My Outfits -		if (cat->getName() == LLStartUp::getInitialOutfitName()) continue; -		 -		// First, make a folder in the My Outfits directory. -		LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName()); -		 -		cat_array.clear(); -		wearable_array.clear(); -		// Collect the contents of each imported clothing folder, so we can create new outfit links for it -		gInventory.collectDescendents(folder_id, cat_array, wearable_array,  -									  LLInventoryModel::EXCLUDE_TRASH); -		 -		for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin(); -			 wearable_iter != wearable_array.end(); -			 ++wearable_iter) -		{ -			const LLViewerInventoryItem *item = wearable_iter->get(); -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								new_outfit_folder_id, -								item->getName(), -								item->getDescription(), -								LLAssetType::AT_LINK, -								order_myoutfits_on_destroy); -		} -	} - -	mOutfitsPopulated = true; -} - diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h index bedc445c0e..81b03110ae 100755 --- a/indra/newview/llagentwearablesfetch.h +++ b/indra/newview/llagentwearablesfetch.h @@ -70,45 +70,4 @@ private:  	initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg  }; -//-------------------------------------------------------------------- -// InitialWearablesFetch -//  -// This grabs outfits from the Library and copies those over to the user's -// outfits folder, typically during first-ever login. -//-------------------------------------------------------------------- -class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver -{ -public: -	enum ELibraryOutfitFetchStep -	{ -		LOFS_FOLDER = 0, -		LOFS_OUTFITS, -		LOFS_LIBRARY, -		LOFS_IMPORTED, -		LOFS_CONTENTS -	}; - -	LLLibraryOutfitsFetch(const LLUUID& my_outfits_id); -	~LLLibraryOutfitsFetch(); - -	virtual void done(); -	void doneIdle(); -	LLUUID mMyOutfitsID; -	void importedFolderFetch(); -protected: -	void folderDone(); -	void outfitsDone(); -	void libraryDone(); -	void importedFolderDone(); -	void contentsDone(); -	enum ELibraryOutfitFetchStep mCurrFetchStep; -	uuid_vec_t mLibraryClothingFolders; -	uuid_vec_t mImportedClothingFolders; -	bool mOutfitsPopulated; -	LLUUID mClothingID; -	LLUUID mLibraryClothingID; -	LLUUID mImportedClothingID; -	std::string mImportedClothingName; -}; -  #endif // LL_AGENTWEARABLESINITIALFETCH_H diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp new file mode 100755 index 0000000000..85b304d90e --- /dev/null +++ b/indra/newview/llaisapi.cpp @@ -0,0 +1,842 @@ +/**  + * @file llaisapi.cpp + * @brief classes and functions for interfacing with the v3+ ais inventory service.  + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "llaisapi.h" + +#include "llagent.h" +#include "llcallbacklist.h" +#include "llinventorymodel.h" +#include "llsdutil.h" +#include "llviewerregion.h" + +///---------------------------------------------------------------------------- +/// Classes for AISv3 support. +///---------------------------------------------------------------------------- + +// AISCommand - base class for retry-able HTTP requests using the AISv3 cap. +AISCommand::AISCommand(LLPointer<LLInventoryCallback> callback): +	mCommandFunc(NULL), +	mCallback(callback) +{ +	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); +} + +bool AISCommand::run_command() +{ +	if (NULL == mCommandFunc) +	{ +		// This may happen if a command failed to initiate itself. +		LL_WARNS("Inventory") << "AIS command attempted with null command function" << LL_ENDL; +		return false; +	} +	else +	{ +		mCommandFunc(); +		return true; +	} +} + +void AISCommand::setCommandFunc(command_func_type command_func) +{ +	mCommandFunc = command_func; +} +	 +// virtual +bool AISCommand::getResponseUUID(const LLSD& content, LLUUID& id) +{ +	return false; +} +	 +/* virtual */ +void AISCommand::httpSuccess() +{ +	// Command func holds a reference to self, need to release it +	// after a success or final failure. +	setCommandFunc(no_op); +		 +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +	mRetryPolicy->onSuccess(); +		 +	gInventory.onAISUpdateReceived("AISCommand", content); + +	if (mCallback) +	{ +		LLUUID id; // will default to null if parse fails. +		getResponseUUID(content,id); +		mCallback->fire(id); +	} +} + +/*virtual*/ +void AISCommand::httpFailure() +{ +	LL_WARNS("Inventory") << dumpResponse() << LL_ENDL; +	S32 status = getStatus(); +	const LLSD& headers = getResponseHeaders(); +	mRetryPolicy->onFailure(status, headers); +	F32 seconds_to_wait; +	if (mRetryPolicy->shouldRetry(seconds_to_wait)) +	{ +		doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait); +	} +	else +	{ +		// Command func holds a reference to self, need to release it +		// after a success or final failure. +		// *TODO: Notify user?  This seems bad. +		setCommandFunc(no_op); +	} +} + +//static +bool AISCommand::isAPIAvailable() +{ +	if (gAgent.getRegion()) +	{ +		return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3"); +	} +	return false; +} + +//static +bool AISCommand::getInvCap(std::string& cap) +{ +	if (gAgent.getRegion()) +	{ +		cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); +	} +	if (!cap.empty()) +	{ +		return true; +	} +	return false; +} + +//static +bool AISCommand::getLibCap(std::string& cap) +{ +	if (gAgent.getRegion()) +	{ +		cap = gAgent.getRegion()->getCapability("LibraryAPIv3"); +	} +	if (!cap.empty()) +	{ +		return true; +	} +	return false; +} + +//static +void AISCommand::getCapabilityNames(LLSD& capabilityNames) +{ +	capabilityNames.append("InventoryAPIv3"); +	capabilityNames.append("LibraryAPIv3"); +} + +RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id, +									 LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	std::string url = cap + std::string("/item/") + item_id.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLHTTPClient::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); +	setCommandFunc(cmd); +} + +RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id, +											 LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	std::string url = cap + std::string("/category/") + item_id.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLHTTPClient::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); +	setCommandFunc(cmd); +} + +PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id, +												 LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	std::string url = cap + std::string("/category/") + item_id.asString() + "/children"; +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); +	setCommandFunc(cmd); +} + +UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id, +									 const LLSD& updates, +									 LLPointer<LLInventoryCallback> callback): +	mUpdates(updates), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	std::string url = cap + std::string("/item/") + item_id.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	headers["Content-Type"] = "application/llsd+xml"; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout); +	setCommandFunc(cmd); +} + +UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& item_id, +											 const LLSD& updates, +											 LLPointer<LLInventoryCallback> callback): +	mUpdates(updates), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	std::string url = cap + std::string("/category/") + item_id.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	headers["Content-Type"] = "application/llsd+xml"; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout); +	setCommandFunc(cmd); +} + +CreateInventoryCommand::CreateInventoryCommand(const LLUUID& parent_id, +							 				   const LLSD& new_inventory, +							 				   LLPointer<LLInventoryCallback> callback): +	mNewInventory(new_inventory), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	LLUUID tid; +	tid.generate(); +	std::string url = cap + std::string("/category/") + parent_id.asString() + "?tid=" + tid.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	headers["Content-Type"] = "application/llsd+xml"; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::post, url, mNewInventory, responder, headers, timeout); +	setCommandFunc(cmd); +} + +SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback): +	mContents(contents), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	LLUUID tid; +	tid.generate(); +	std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString(); +	llinfos << url << llendl; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	headers["Content-Type"] = "application/llsd+xml"; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::put, url, mContents, responder, headers, timeout); +	setCommandFunc(cmd); +} + +CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id, +													   const LLUUID& dest_id, +													   LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getLibCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	LL_DEBUGS("Inventory") << "Copying library category: " << source_id << " => " << dest_id << LL_ENDL; +	LLUUID tid; +	tid.generate(); +	std::string url = cap + std::string("/category/") + source_id.asString() + "?tid=" + tid.asString(); +	llinfos << url << llendl; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::copy, url, dest_id.asString(), responder, headers, timeout); +	setCommandFunc(cmd); +} + +bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id) +{ +	if (content.has("category_id")) +	{ +		id = content["category_id"]; +		return true; +	} +	return false; +} + +AISUpdate::AISUpdate(const LLSD& update) +{ +	parseUpdate(update); +} + +void AISUpdate::clearParseResults() +{ +	mCatDescendentDeltas.clear(); +	mCatDescendentsKnown.clear(); +	mCatVersionsUpdated.clear(); +	mItemsCreated.clear(); +	mItemsUpdated.clear(); +	mCategoriesCreated.clear(); +	mCategoriesUpdated.clear(); +	mObjectsDeletedIds.clear(); +	mItemIds.clear(); +	mCategoryIds.clear(); +} + +void AISUpdate::parseUpdate(const LLSD& update) +{ +	clearParseResults(); +	parseMeta(update); +	parseContent(update); +} + +void AISUpdate::parseMeta(const LLSD& update) +{ +	// parse _categories_removed -> mObjectsDeletedIds +	uuid_list_t cat_ids; +	parseUUIDArray(update,"_categories_removed",cat_ids); +	for (uuid_list_t::const_iterator it = cat_ids.begin(); +		 it != cat_ids.end(); ++it) +	{ +		LLViewerInventoryCategory *cat = gInventory.getCategory(*it); +		mCatDescendentDeltas[cat->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it); +	} + +	// parse _categories_items_removed -> mObjectsDeletedIds +	uuid_list_t item_ids; +	parseUUIDArray(update,"_category_items_removed",item_ids); +	parseUUIDArray(update,"_removed_items",item_ids); +	for (uuid_list_t::const_iterator it = item_ids.begin(); +		 it != item_ids.end(); ++it) +	{ +		LLViewerInventoryItem *item = gInventory.getItem(*it); +		mCatDescendentDeltas[item->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it); +	} + +	// parse _broken_links_removed -> mObjectsDeletedIds +	uuid_list_t broken_link_ids; +	parseUUIDArray(update,"_broken_links_removed",broken_link_ids); +	for (uuid_list_t::const_iterator it = broken_link_ids.begin(); +		 it != broken_link_ids.end(); ++it) +	{ +		LLViewerInventoryItem *item = gInventory.getItem(*it); +		mCatDescendentDeltas[item->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it); +	} + +	// parse _created_items +	parseUUIDArray(update,"_created_items",mItemIds); + +	// parse _created_categories +	parseUUIDArray(update,"_created_categories",mCategoryIds); + +	// Parse updated category versions. +	const std::string& ucv = "_updated_category_versions"; +	if (update.has(ucv)) +	{ +		for(LLSD::map_const_iterator it = update[ucv].beginMap(), +				end = update[ucv].endMap(); +			it != end; ++it) +		{ +			const LLUUID id((*it).first); +			S32 version = (*it).second.asInteger(); +			mCatVersionsUpdated[id] = version; +		} +	} +} + +void AISUpdate::parseContent(const LLSD& update) +{ +	if (update.has("linked_id")) +	{ +		parseLink(update); +	} +	else if (update.has("item_id")) +	{ +		parseItem(update); +	} + +	if (update.has("category_id")) +	{ +		parseCategory(update); +	} +	else +	{ +		if (update.has("_embedded")) +		{ +			parseEmbedded(update["_embedded"]); +		} +	} +} + +void AISUpdate::parseItem(const LLSD& item_map) +{ +	LLUUID item_id = item_map["item_id"].asUUID(); +	LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); +	LLViewerInventoryItem *curr_item = gInventory.getItem(item_id); +	if (curr_item) +	{ +		// Default to current values where not provided. +		new_item->copyViewerItem(curr_item); +	} +	BOOL rv = new_item->unpackMessage(item_map); +	if (rv) +	{ +		if (curr_item) +		{ +			mItemsUpdated[item_id] = new_item; +			// This statement is here to cause a new entry with 0 +			// delta to be created if it does not already exist; +			// otherwise has no effect. +			mCatDescendentDeltas[new_item->getParentUUID()]; +		} +		else +		{ +			mItemsCreated[item_id] = new_item; +			mCatDescendentDeltas[new_item->getParentUUID()]++; +		} +	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		llerrs << "unpack failed" << llendl; +	} +} + +void AISUpdate::parseLink(const LLSD& link_map) +{ +	LLUUID item_id = link_map["item_id"].asUUID(); +	LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem); +	LLViewerInventoryItem *curr_link = gInventory.getItem(item_id); +	if (curr_link) +	{ +		// Default to current values where not provided. +		new_link->copyViewerItem(curr_link); +	} +	BOOL rv = new_link->unpackMessage(link_map); +	if (rv) +	{ +		const LLUUID& parent_id = new_link->getParentUUID(); +		if (curr_link) +		{ +			mItemsUpdated[item_id] = new_link; +			// This statement is here to cause a new entry with 0 +			// delta to be created if it does not already exist; +			// otherwise has no effect. +			mCatDescendentDeltas[parent_id]; +		} +		else +		{ +			LLPermissions default_perms; +			default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null); +			default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE); +			new_link->setPermissions(default_perms); +			LLSaleInfo default_sale_info; +			new_link->setSaleInfo(default_sale_info); +			//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL; +			mItemsCreated[item_id] = new_link; +			mCatDescendentDeltas[parent_id]++; +		} +	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		llerrs << "unpack failed" << llendl; +	} +} + + +void AISUpdate::parseCategory(const LLSD& category_map) +{ +	LLUUID category_id = category_map["category_id"].asUUID(); + +	// Check descendent count first, as it may be needed +	// to populate newly created categories +	if (category_map.has("_embedded")) +	{ +		parseDescendentCount(category_id, category_map["_embedded"]); +	} + +	LLPointer<LLViewerInventoryCategory> new_cat(new LLViewerInventoryCategory(category_id)); +	LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id); +	if (curr_cat) +	{ +		// Default to current values where not provided. +		new_cat->copyViewerCategory(curr_cat); +	} +	BOOL rv = new_cat->unpackMessage(category_map); +	// *NOTE: unpackMessage does not unpack version or descendent count. +	//if (category_map.has("version")) +	//{ +	//	mCatVersionsUpdated[category_id] = category_map["version"].asInteger(); +	//} +	if (rv) +	{ +		if (curr_cat) +		{ +			mCategoriesUpdated[category_id] = new_cat; +			// This statement is here to cause a new entry with 0 +			// delta to be created if it does not already exist; +			// otherwise has no effect. +			mCatDescendentDeltas[new_cat->getParentUUID()]; +			// Capture update for the category itself as well. +			mCatDescendentDeltas[category_id]; +		} +		else +		{ +			// Set version/descendents for newly created categories. +			if (category_map.has("version")) +			{ +				S32 version = category_map["version"].asInteger(); +				LL_DEBUGS("Inventory") << "Setting version to " << version +									   << " for new category " << category_id << LL_ENDL; +				new_cat->setVersion(version); +			} +			uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); +			if (mCatDescendentsKnown.end() != lookup_it) +			{ +				S32 descendent_count = lookup_it->second; +				LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count  +									   << " for new category " << category_id << LL_ENDL; +				new_cat->setDescendentCount(descendent_count); +			} +			mCategoriesCreated[category_id] = new_cat; +			mCatDescendentDeltas[new_cat->getParentUUID()]++; +		} +	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		llerrs << "unpack failed" << llendl; +	} + +	// Check for more embedded content. +	if (category_map.has("_embedded")) +	{ +		parseEmbedded(category_map["_embedded"]); +	} +} + +void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded) +{ +	// We can only determine true descendent count if this contains all descendent types. +	if (embedded.has("category") && +		embedded.has("link") && +		embedded.has("item")) +	{ +		mCatDescendentsKnown[category_id]  = embedded["category"].size(); +		mCatDescendentsKnown[category_id] += embedded["link"].size(); +		mCatDescendentsKnown[category_id] += embedded["item"].size(); +	} +} + +void AISUpdate::parseEmbedded(const LLSD& embedded) +{ +	if (embedded.has("link")) +	{ +		parseEmbeddedLinks(embedded["link"]); +	} +	if (embedded.has("item")) +	{ +		parseEmbeddedItems(embedded["item"]); +	} +	if (embedded.has("category")) +	{ +		parseEmbeddedCategories(embedded["category"]); +	} +} + +void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids) +{ +	if (content.has(name)) +	{ +		for(LLSD::array_const_iterator it = content[name].beginArray(), +				end = content[name].endArray(); +				it != end; ++it) +		{ +			ids.insert((*it).asUUID()); +		} +	} +} + +void AISUpdate::parseEmbeddedLinks(const LLSD& links) +{ +	for(LLSD::map_const_iterator linkit = links.beginMap(), +			linkend = links.endMap(); +		linkit != linkend; ++linkit) +	{ +		const LLUUID link_id((*linkit).first); +		const LLSD& link_map = (*linkit).second; +		if (mItemIds.end() == mItemIds.find(link_id)) +		{ +			LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL; +		} +		else +		{ +			parseLink(link_map); +		} +	} +} + +void AISUpdate::parseEmbeddedItems(const LLSD& items) +{ +	// Special case: this may be a single item (_embedded in a link) +	if (items.has("item_id")) +	{ +		if (mItemIds.end() != mItemIds.find(items["item_id"].asUUID())) +		{ +			parseContent(items); +		} +		return; +	} + +	for(LLSD::map_const_iterator itemit = items.beginMap(), +			itemend = items.endMap(); +		itemit != itemend; ++itemit) +	{ +		const LLUUID item_id((*itemit).first); +		const LLSD& item_map = (*itemit).second; +		if (mItemIds.end() == mItemIds.find(item_id)) +		{ +			LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL; +		} +		else +		{ +			parseItem(item_map); +		} +	} +} + +void AISUpdate::parseEmbeddedCategories(const LLSD& categories) +{ +	for(LLSD::map_const_iterator categoryit = categories.beginMap(), +			categoryend = categories.endMap(); +		categoryit != categoryend; ++categoryit) +	{ +		const LLUUID category_id((*categoryit).first); +		const LLSD& category_map = (*categoryit).second; +		if (mCategoryIds.end() == mCategoryIds.find(category_id)) +		{ +			LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL; +		} +		else +		{ +			parseCategory(category_map); +		} +	} +} + +void AISUpdate::doUpdate() +{ +	// Do version/descendent accounting. +	for (std::map<LLUUID,S32>::const_iterator catit = mCatDescendentDeltas.begin(); +		 catit != mCatDescendentDeltas.end(); ++catit) +	{ +		LL_DEBUGS("Inventory") << "descendent accounting for " << catit->first << llendl; + +		const LLUUID cat_id(catit->first); +		// Don't account for update if we just created this category. +		if (mCategoriesCreated.find(cat_id) != mCategoriesCreated.end()) +		{ +			LL_DEBUGS("Inventory") << "Skipping version increment for new category " << cat_id << LL_ENDL; +			continue; +		} + +		// Don't account for update unless AIS told us it updated that category. +		if (mCatVersionsUpdated.find(cat_id) == mCatVersionsUpdated.end()) +		{ +			LL_DEBUGS("Inventory") << "Skipping version increment for non-updated category " << cat_id << LL_ENDL; +			continue; +		} + +		// If we have a known descendent count, set that now. +		LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); +		if (cat) +		{ +			S32 descendent_delta = catit->second; +			S32 old_count = cat->getDescendentCount(); +			LL_DEBUGS("Inventory") << "Updating descendent count for " +								   << cat->getName() << " " << cat_id +								   << " with delta " << descendent_delta << " from " +								   << old_count << " to " << (old_count+descendent_delta) << LL_ENDL; +			LLInventoryModel::LLCategoryUpdate up(cat_id, descendent_delta); +			gInventory.accountForUpdate(up); +		} +		else +		{ +			LL_DEBUGS("Inventory") << "Skipping version accounting for unknown category " << cat_id << LL_ENDL; +		} +	} + +	// CREATE CATEGORIES +	for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin(); +		 create_it != mCategoriesCreated.end(); ++create_it) +	{ +		LLUUID category_id(create_it->first); +		LLPointer<LLViewerInventoryCategory> new_category = create_it->second; + +		gInventory.updateCategory(new_category); +		LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL; +	} + +	// UPDATE CATEGORIES +	for (deferred_category_map_t::const_iterator update_it = mCategoriesUpdated.begin(); +		 update_it != mCategoriesUpdated.end(); ++update_it) +	{ +		LLUUID category_id(update_it->first); +		LLPointer<LLViewerInventoryCategory> new_category = update_it->second; +		// Since this is a copy of the category *before* the accounting update, above, +		// we need to transfer back the updated version/descendent count. +		LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID()); +		if (NULL == curr_cat) +		{ +			LL_WARNS("Inventory") << "Failed to update unknown category " << new_category->getUUID() << LL_ENDL; +		} +		else +		{ +			new_category->setVersion(curr_cat->getVersion()); +			new_category->setDescendentCount(curr_cat->getDescendentCount()); +			gInventory.updateCategory(new_category); +			LL_DEBUGS("Inventory") << "updated category " << new_category->getName() << " " << category_id << LL_ENDL; +		} +	} + +	// CREATE ITEMS +	for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin(); +		 create_it != mItemsCreated.end(); ++create_it) +	{ +		LLUUID item_id(create_it->first); +		LLPointer<LLViewerInventoryItem> new_item = create_it->second; + +		// FIXME risky function since it calls updateServer() in some +		// cases.  Maybe break out the update/create cases, in which +		// case this is create. +		LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL; +		gInventory.updateItem(new_item); +	} +	 +	// UPDATE ITEMS +	for (deferred_item_map_t::const_iterator update_it = mItemsUpdated.begin(); +		 update_it != mItemsUpdated.end(); ++update_it) +	{ +		LLUUID item_id(update_it->first); +		LLPointer<LLViewerInventoryItem> new_item = update_it->second; +		// FIXME risky function since it calls updateServer() in some +		// cases.  Maybe break out the update/create cases, in which +		// case this is update. +		LL_DEBUGS("Inventory") << "updated item " << item_id << LL_ENDL; +		//LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << LL_ENDL; +		gInventory.updateItem(new_item); +	} + +	// DELETE OBJECTS +	for (uuid_list_t::const_iterator del_it = mObjectsDeletedIds.begin(); +		 del_it != mObjectsDeletedIds.end(); ++del_it) +	{ +		LL_DEBUGS("Inventory") << "deleted item " << *del_it << LL_ENDL; +		gInventory.onObjectDeletedFromServer(*del_it, false, false, false); +	} + +	// TODO - how can we use this version info? Need to be sure all +	// changes are going through AIS first, or at least through +	// something with a reliable responder. +	for (uuid_int_map_t::iterator ucv_it = mCatVersionsUpdated.begin(); +		 ucv_it != mCatVersionsUpdated.end(); ++ucv_it) +	{ +		const LLUUID id = ucv_it->first; +		S32 version = ucv_it->second; +		LLViewerInventoryCategory *cat = gInventory.getCategory(id); +		LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << llendl; +		if (cat->getVersion() != version) +		{ +			llwarns << "Possible version mismatch for category " << cat->getName() +					<< ", viewer version " << cat->getVersion() +					<< " server version " << version << llendl; +		} +	} + +	gInventory.notifyObservers(); +} + diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h new file mode 100755 index 0000000000..5d31129a16 --- /dev/null +++ b/indra/newview/llaisapi.h @@ -0,0 +1,181 @@ +/**  + * @file llaisapi.h + * @brief classes and functions for interfacing with the v3+ ais inventory service.  + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLAISAPI_H +#define LL_LLAISAPI_H + +#include "lluuid.h" +#include <map> +#include <set> +#include <string> +#include "llcurl.h" +#include "llhttpclient.h" +#include "llhttpretrypolicy.h" +#include "llviewerinventory.h" + +class AISCommand: public LLHTTPClient::Responder +{ +public: +	typedef boost::function<void()> command_func_type; + +	AISCommand(LLPointer<LLInventoryCallback> callback); + +	virtual ~AISCommand() {} + +	bool run_command(); + +	void setCommandFunc(command_func_type command_func); +	 +	// Need to do command-specific parsing to get an id here, for +	// LLInventoryCallback::fire().  May or may not need to bother, +	// since most LLInventoryCallbacks do their work in the +	// destructor. +	 +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); + +	static bool isAPIAvailable(); +	static bool getInvCap(std::string& cap); +	static bool getLibCap(std::string& cap); +	static void getCapabilityNames(LLSD& capabilityNames); + +protected: +	virtual bool getResponseUUID(const LLSD& content, LLUUID& id); + +private: +	command_func_type mCommandFunc; +	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; +	LLPointer<LLInventoryCallback> mCallback; +}; + +class RemoveItemCommand: public AISCommand +{ +public: +	RemoveItemCommand(const LLUUID& item_id, +					  LLPointer<LLInventoryCallback> callback); +}; + +class RemoveCategoryCommand: public AISCommand +{ +public: +	RemoveCategoryCommand(const LLUUID& item_id, +						  LLPointer<LLInventoryCallback> callback); +}; + +class PurgeDescendentsCommand: public AISCommand +{ +public: +	PurgeDescendentsCommand(const LLUUID& item_id, +							LLPointer<LLInventoryCallback> callback); +}; + +class UpdateItemCommand: public AISCommand +{ +public: +	UpdateItemCommand(const LLUUID& item_id, +					  const LLSD& updates, +					  LLPointer<LLInventoryCallback> callback); +private: +	LLSD mUpdates; +}; + +class UpdateCategoryCommand: public AISCommand +{ +public: +	UpdateCategoryCommand(const LLUUID& item_id, +						  const LLSD& updates, +						  LLPointer<LLInventoryCallback> callback); +private: +	LLSD mUpdates; +}; + +class SlamFolderCommand: public AISCommand +{ +public: +	SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback); +	 +private: +	LLSD mContents; +}; + +class CopyLibraryCategoryCommand: public AISCommand +{ +public: +	CopyLibraryCategoryCommand(const LLUUID& source_id, const LLUUID& dest_id, LLPointer<LLInventoryCallback> callback); + +protected: +	/* virtual */ bool getResponseUUID(const LLSD& content, LLUUID& id); +}; + +class CreateInventoryCommand: public AISCommand +{ +public: +	CreateInventoryCommand(const LLUUID& parent_id, const LLSD& new_inventory, LLPointer<LLInventoryCallback> callback); + +private: +	LLSD mNewInventory; +}; + +class AISUpdate +{ +public: +	AISUpdate(const LLSD& update); +	void parseUpdate(const LLSD& update); +	void parseMeta(const LLSD& update); +	void parseContent(const LLSD& update); +	void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); +	void parseLink(const LLSD& link_map); +	void parseItem(const LLSD& link_map); +	void parseCategory(const LLSD& link_map); +	void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded); +	void parseEmbedded(const LLSD& embedded); +	void parseEmbeddedLinks(const LLSD& links); +	void parseEmbeddedItems(const LLSD& links); +	void parseEmbeddedCategories(const LLSD& links); +	void doUpdate(); +private: +	void clearParseResults(); + +	typedef std::map<LLUUID,S32> uuid_int_map_t; +	uuid_int_map_t mCatDescendentDeltas; +	uuid_int_map_t mCatDescendentsKnown; +	uuid_int_map_t mCatVersionsUpdated; + +	typedef std::map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t; +	deferred_item_map_t mItemsCreated; +	deferred_item_map_t mItemsUpdated; +	typedef std::map<LLUUID,LLPointer<LLViewerInventoryCategory> > deferred_category_map_t; +	deferred_category_map_t mCategoriesCreated; +	deferred_category_map_t mCategoriesUpdated; + +	// These keep track of uuid's mentioned in meta values. +	// Useful for filtering out which content we are interested in. +	uuid_list_t mObjectsDeletedIds; +	uuid_list_t mItemIds; +	uuid_list_t mCategoryIds; +}; + +#endif diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index fd9236c8b3..7fbe84312e 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -52,6 +52,8 @@  #include "llwearablelist.h"  #include "llsdutil.h"  #include "llsdserialize.h" +#include "llhttpretrypolicy.h" +#include "llaisapi.h"  #if LL_MSVC  // disable boost::lexical_cast warning @@ -196,7 +198,7 @@ public:  		LLEventTimer(5.0)  	{  		if (!mTrackingPhase.empty()) -	{ +		{  			selfStartPhase(mTrackingPhase);  		}  	} @@ -212,23 +214,23 @@ public:  			addItem(item->getUUID());  		}  	} -		 +  	// Request or re-request operation for specified item.  	void addItem(const LLUUID& item_id)  	{  		LL_DEBUGS("Avatar") << "item_id " << item_id << llendl; - +		  		if (!requestOperation(item_id))  		{  			LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << llendl;  			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 @@ -242,7 +244,7 @@ public:  	void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp)  	{  		if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) -	{ +		{  			llwarns << "Simulating late operation by punting handling to later" << llendl;  			doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp),  							mRetryAfter); @@ -265,12 +267,12 @@ public:  			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. @@ -288,7 +290,7 @@ public:  			onFailure();  		}  	} -		 +  	void onFailure()  	{  		llinfos << "failed" << llendl; @@ -300,7 +302,7 @@ public:  		llinfos << "done" << llendl;  		mOnCompletionFunc();  	} - +	  	// virtual  	// Will be deleted after returning true - only safe to do this if all callbacks have fired.  	BOOL tick() @@ -313,7 +315,7 @@ public:  		// been serviced, since it will result in this object being  		// deleted.  		bool all_done = (mPendingRequests==0); -		 +  		if (!mWaitTimes.empty())  		{  			llwarns << "still waiting on " << mWaitTimes.size() << " items" << llendl; @@ -323,20 +325,20 @@ public:  				// 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" << llendl;  						mRetryCount++;  						addItem(curr_it->first); -		} -		else -		{ +					} +					else +					{  						llwarns << "Giving up on " << curr_it->first << " after too many retries" << llendl;  						mWaitTimes.erase(curr_it);  						mFailCount++; @@ -347,8 +349,8 @@ public:  					onCompletionOrFailure();  				} +			}  		} -	}  		return all_done;  	} @@ -360,7 +362,7 @@ public:  		LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << llendl;  		LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << llendl;  	} - +	  	virtual ~LLCallAfterInventoryBatchMgr()  	{  		LL_DEBUGS("Avatar") << "deleting" << llendl; @@ -396,10 +398,16 @@ public:  		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 << llendl; @@ -418,95 +426,86 @@ public:  			);  		return true;  	} + +	static S32 getInstanceCount() { return sInstanceCount; } +	 +private: +	static S32 sInstanceCount;  }; -class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr +S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; + +class LLWearCategoryAfterCopy: public LLInventoryCallback  {  public: -	LLCallAfterInventoryLinkMgr(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) +	LLWearCategoryAfterCopy(bool append): +		mAppend(append) +	{} + +	// virtual +	void fire(const LLUUID& id)  	{ -		addItems(src_items); +		// Wear the inventory category. +		LLInventoryCategory* cat = gInventory.getCategory(id); +		LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend);  	} -	 -	virtual bool requestOperation(const LLUUID& item_id) -	{ -		bool request_sent = false; -		LLViewerInventoryItem *item = gInventory.getItem(item_id); -		if (item) -		{ -			if (item->getParentUUID() == mDstCatID) -			{ -				LL_DEBUGS("Avatar") << "item " << item_id << " name " << item->getName() << " is already a child of " << mDstCatID << llendl; -				return false; -			} -			LL_DEBUGS("Avatar") << "linking item " << item_id << " name " << item->getName() << " to " << mDstCatID << llendl; -			// create an inventory item link. -			if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) -			{ -				LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl; -				return true; -			} -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								mDstCatID, -								item->getName(), -								item->getActualDescription(), -								LLAssetType::AT_LINK, -								new LLBoostFuncInventoryCallback( -									boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); -			return true; -		} -		else -		{ -			// create a base outfit link if appropriate. -			LLViewerInventoryCategory *catp = gInventory.getCategory(item_id); -			if (!catp) -			{ -				llwarns << "link request failed, id not found as inventory item or category " << item_id << llendl; -				return false; -			} -			const LLUUID cof = LLAppearanceMgr::instance().getCOF(); -			std::string new_outfit_name = ""; -			LLAppearanceMgr::instance().purgeBaseOutfitLink(cof); +private: +	bool mAppend; +}; -			if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) +class LLTrackPhaseWrapper : public LLInventoryCallback +{ +public: +	LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL): +		mTrackingPhase(phase_name), +		mCB(cb)  	{ -				if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) +		selfStartPhase(mTrackingPhase); +	} + +	// virtual +	void fire(const LLUUID& id) +	{ +		if (mCB)  		{ -					LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl; -					return true; -				} -				LL_DEBUGS("Avatar") << "linking folder " << item_id << " name " << catp->getName() << " to cof " << cof << llendl; -				link_inventory_item(gAgent.getID(), item_id, cof, catp->getName(), "", -									LLAssetType::AT_LINK_FOLDER,  -									new LLBoostFuncInventoryCallback( -										boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); -				new_outfit_name = catp->getName(); -				request_sent = true; -			} -	 -			LLAppearanceMgr::instance().updatePanelOutfitName(new_outfit_name); +			mCB->fire(id);  		} -		return request_sent;  	} + +	// virtual +	~LLTrackPhaseWrapper() +	{ +		selfStopPhase(mTrackingPhase); +	} + +protected: +	std::string mTrackingPhase; +	LLPointer<LLInventoryCallback> mCB;  }; -LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering): +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions, +														 bool enforce_ordering, +														 nullary_func_t post_update_func  +	):  	mFireCount(0), -	mUpdateBaseOrder(update_base_outfit_ordering) +	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()) @@ -516,20 +515,46 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()  		selfStopPhase("update_appearance_on_destroy"); -		LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder); +		LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, +															mEnforceOrdering, +															mPostUpdateFunc);  	}  } -void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id): +	mItemID(item_id)  { -	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++;  } +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() : @@ -593,6 +618,8 @@ public:  	bool isMostRecent();  	void handleLateArrivals();  	void resetTime(F32 timeout); +	static S32 countActive() { return sActiveHoldingPatterns.size(); } +	S32 index() { return mIndex; }  private:  	found_list_t mFoundList; @@ -606,12 +633,15 @@ private:  	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), @@ -619,10 +649,10 @@ LLWearableHoldingPattern::LLWearableHoldingPattern():  	mIsMostRecent(true),  	mIsAllComplete(false)  { -	if (sActiveHoldingPatterns.size()>0) +	if (countActive()>0)  	{  		llinfos << "Creating LLWearableHoldingPattern when " -				<< sActiveHoldingPatterns.size() +				<< countActive()  				<< " other attempts are active."  				<< " Flagging others as invalid."  				<< llendl; @@ -634,7 +664,9 @@ LLWearableHoldingPattern::LLWearableHoldingPattern():  		}  	} +	mIndex = sNextIndex++;  	sActiveHoldingPatterns.insert(this); +	LL_DEBUGS("Avatar") << "HP " << index() << " created" << llendl;  	selfStartPhase("holding_pattern");  } @@ -645,6 +677,7 @@ LLWearableHoldingPattern::~LLWearableHoldingPattern()  	{  		selfStopPhase("holding_pattern");  	} +	LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << llendl;  }  bool LLWearableHoldingPattern::isMostRecent() @@ -692,7 +725,7 @@ void LLWearableHoldingPattern::checkMissingWearables()  	if (!isMostRecent())  	{  		// runway why don't we actually skip here? -		llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +		llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;  	}  	std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0); @@ -710,7 +743,7 @@ void LLWearableHoldingPattern::checkMissingWearables()  	{  		if (requested_by_type[type] > found_by_type[type])  		{ -			llwarns << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl; +			llwarns << self_av_string() << "HP " << index() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl;  		}  		if (found_by_type[type] > 0)  			continue; @@ -727,13 +760,16 @@ void LLWearableHoldingPattern::checkMissingWearables()  			mTypesToRecover.insert(type);  			mTypesToLink.insert(type);  			recoverMissingWearable((LLWearableType::EType)type); -			llwarns << self_av_string() << "need to replace " << type << llendl;  +			llwarns << self_av_string() << "HP " << index() << " need to replace wearable of type " << type << llendl;   		}  	}  	resetTime(60.0F); -	selfStartPhase("get_missing_wearables"); +	if (isMostRecent()) +	{ +		selfStartPhase("get_missing_wearables_2"); +	}  	if (!pollMissingWearables())  	{  		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); @@ -750,13 +786,13 @@ void LLWearableHoldingPattern::onAllComplete()  	if (!isMostRecent())  	{  		// runway need to skip here? -		llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +		llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;  	}  	// Activate all gestures in this folder  	if (mGestItems.count() > 0)  	{ -		LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.count() << " gestures" << LL_ENDL; +		LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " activating " << mGestItems.count() << " gestures" << LL_ENDL;  		LLGestureMgr::instance().activateGestures(mGestItems); @@ -773,13 +809,13 @@ void LLWearableHoldingPattern::onAllComplete()  	}  	// Update wearables. -	LL_INFOS("Avatar") << self_av_string() << "Updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; -	LLAppearanceMgr::instance().updateAgentWearables(this, false); +	LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; +	LLAppearanceMgr::instance().updateAgentWearables(this);  	// Update attachments to match those requested.  	if (isAgentAvatarValid())  	{ -		LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.count() << " attachments" << LL_ENDL; +		LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " updating " << mObjItems.count() << " attachments" << LL_ENDL;  		LLAgentWearables::userUpdateAttachments(mObjItems);  	} @@ -797,12 +833,15 @@ void LLWearableHoldingPattern::onAllComplete()  void LLWearableHoldingPattern::onFetchCompletion()  { -	selfStopPhase("get_wearables"); +	if (isMostRecent()) +	{ +		selfStopPhase("get_wearables_2"); +	}  	if (!isMostRecent())  	{  		// runway skip here? -		llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +		llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;  	}  	checkMissingWearables(); @@ -814,7 +853,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion()  	if (!isMostRecent())  	{  		// runway skip here? -		llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +		llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;  	}  	bool completed = isFetchCompleted(); @@ -823,14 +862,14 @@ bool LLWearableHoldingPattern::pollFetchCompletion()  	if (done)  	{ -		LL_INFOS("Avatar") << self_av_string() << "polling, done status: " << completed << " timed out " << timed_out +		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)  		{ -			llwarns << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; +			llwarns << self_av_string() << "HP " << index() << " exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl;  		}  		onFetchCompletion(); @@ -841,82 +880,77 @@ bool LLWearableHoldingPattern::pollFetchCompletion()  void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)  {  	if (!holder->isMostRecent()) -		{ -			llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; -			// runway skip here? -		} +	{ +		llwarns << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +		// runway skip here? +	} -	llinfos << "Recovered item link for type " << type << llendl; +	llinfos << "HP " << holder->index() << " recovered item link for type " << type << llendl;  	holder->eraseTypeToLink(type); -		// Add wearable to FoundData for actual wearing -		LLViewerInventoryItem *item = gInventory.getItem(item_id); -		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; +	// 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 (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 -					); +		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 -			{ -				llwarns << self_av_string() << "inventory item not found for recovered wearable" << llendl; -			}  		}  		else  		{ -			llwarns << self_av_string() << "inventory link not found for recovered wearable" << llendl; +			llwarns << self_av_string() << "HP " << holder->index() << " inventory item not found for recovered wearable" << llendl;  		}  	} +	else +	{ +		llwarns << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << llendl; +	} +}  void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)  {  	if (!holder->isMostRecent()) -		{ -			// runway skip here? -			llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; -		} +	{ +		// runway skip here? +		llwarns << self_av_string() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +	} -	LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; -		LLViewerInventoryItem *itemp = gInventory.getItem(item_id); +	LL_DEBUGS("Avatar") << self_av_string() << "HP " << holder->index() << " recovered item for type " << type << LL_ENDL; +	LLConstPointer<LLInventoryObject> itemp = gInventory.getItem(item_id);  	wearable->setItemID(item_id); -	LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder));  	holder->eraseTypeToRecover(type); -		llassert(itemp); -		if (itemp) -		{ -			link_inventory_item( gAgent.getID(), -					     item_id, -					     LLAppearanceMgr::instance().getCOF(), -					     itemp->getName(), -						 itemp->getDescription(), -					     LLAssetType::AT_LINK, -					     cb); -		} +	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? -		llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +		llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;  	}  		// Try to recover by replacing missing wearable with a new one.  	LLNotificationsUtil::add("ReplacedMissingWearable"); -	lldebugs << "Wearable " << LLWearableType::getTypeLabel(type) -			 << " could not be downloaded.  Replaced inventory item with default wearable." << llendl; +	LL_DEBUGS("Avatar") << "HP " << index() << " wearable " << LLWearableType::getTypeLabel(type) +						<< " could not be downloaded.  Replaced inventory item with default wearable." << llendl;  	LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);  	// Add a new one in the lost and found folder. @@ -949,7 +983,7 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()  		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() << "removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; +			LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL;  			LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID);  		}  	} @@ -960,7 +994,7 @@ bool LLWearableHoldingPattern::pollMissingWearables()  	if (!isMostRecent())  	{  		// runway skip here? -		llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +		llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;  	}  	bool timed_out = isTimedOut(); @@ -969,7 +1003,7 @@ bool LLWearableHoldingPattern::pollMissingWearables()  	if (!done)  	{ -		LL_INFOS("Avatar") << self_av_string() << "polling missing wearables, waiting for items " << mTypesToRecover.size() +		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() @@ -978,7 +1012,10 @@ bool LLWearableHoldingPattern::pollMissingWearables()  	if (done)  	{ -		selfStopPhase("get_missing_wearables"); +		if (isMostRecent()) +		{ +			selfStopPhase("get_missing_wearables_2"); +		}  		gAgentAvatarp->debugWearablesLoaded(); @@ -1009,14 +1046,14 @@ void LLWearableHoldingPattern::handleLateArrivals()  	}  	if (!isMostRecent())  	{ -		llwarns << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << llendl; +		llwarns << self_av_string() << "HP " << index() << " late arrivals not handled - outfit change no longer valid" << llendl;  	}  	if (!mIsAllComplete)  	{ -		llwarns << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << llendl; +		llwarns << self_av_string() << "HP " << index() << " late arrivals not handled - in middle of missing wearables processing" << llendl;  	} -	LL_INFOS("Avatar") << self_av_string() << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << 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; @@ -1079,7 +1116,7 @@ void LLWearableHoldingPattern::handleLateArrivals()  	mLateArrivals.clear();  	// Update appearance based on mFoundList -	LLAppearanceMgr::instance().updateAgentWearables(this, false); +	LLAppearanceMgr::instance().updateAgentWearables(this);  }  void LLWearableHoldingPattern::resetTime(F32 timeout) @@ -1092,19 +1129,19 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable)  {  	if (!isMostRecent())  	{ -		llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; +		llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;  	}  	mResolved += 1;  // just counting callbacks, not successes. -	LL_DEBUGS("Avatar") << self_av_string() << "resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; +	LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL;  	if (!wearable)  	{ -		llwarns << self_av_string() << "no wearable found" << llendl; +		llwarns << self_av_string() << "HP " << index() << " " << "no wearable found" << llendl;  	}  	if (mFired)  	{ -		llwarns << self_av_string() << "called after holder fired" << llendl; +		llwarns << self_av_string() << "HP " << index() << " " << "called after holder fired" << llendl;  		if (wearable)  		{  			mLateArrivals.insert(wearable); @@ -1130,7 +1167,9 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable)  			// 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))  			{ -				llwarns << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl; +				llwarns << self_av_string() << "HP " << index() << " " +						<< "recovered wearable but type invalid. inventory wearable type: " +						<< data.mWearableType << " asset wearable type: " << wearable->getType() << llendl;  				break;  			} @@ -1203,8 +1242,7 @@ const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()  									cat_array,  									item_array,  									false, -									is_category, -									false); +									is_category);  	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();  		 iter != item_array.end();  		 iter++) @@ -1270,8 +1308,12 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false)  	}  } -bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace, LLPointer<LLInventoryCallback> cb) +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: @@ -1290,7 +1332,7 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up  	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); +		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())) @@ -1310,15 +1352,22 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up  	switch (item_to_wear->getType())  	{  	case LLAssetType::AT_CLOTHING: -		if (gAgentWearables.areWearablesLoaded()) +	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) )  			{ -				removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1)); +				LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), +																   wearable_count-1); +				removeCOFItemLinks(item_id, cb);  			} -			addCOFItemLink(item_to_wear, do_update, cb); + +			addCOFItemLink(item_to_wear, cb);  		}   		break;  	case LLAssetType::AT_BODYPART: @@ -1327,8 +1376,11 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up  		// 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()); - -		addCOFItemLink(item_to_wear, do_update, cb); +		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); @@ -1457,6 +1509,58 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds  	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); +	llinfos << "copying " << items->count() << " items" << llendl; +	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() << llendl; +				//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() << llendl; +					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) @@ -1465,6 +1569,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  	LLInventoryModel::item_array_t* items;  	gInventory.getDirectDescendentsOf(src_id, cats, items);  	llinfos << "copying " << items->count() << " items" << llendl; +	LLInventoryObject::const_object_list_t link_array;  	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();  		 iter != items->end();  		 ++iter) @@ -1474,14 +1579,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  		{  			case LLAssetType::AT_LINK:  			{ -				//getActualDescription() is used for a new description  -				//to propagate ordering information saved in descriptions of links -				link_inventory_item(gAgent.getID(), -									item->getLinkedUUID(), -									dst_id, -									item->getName(), -									item->getActualDescription(), -									LLAssetType::AT_LINK, cb); +				LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << llendl; +				link_array.push_back(LLConstPointer<LLInventoryObject>(item));  				break;  			}  			case LLAssetType::AT_LINK_FOLDER: @@ -1490,12 +1589,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  				// Skip copying outfit links.  				if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT)  				{ -					link_inventory_item(gAgent.getID(), -										item->getLinkedUUID(), -										dst_id, -										item->getName(), -										item->getDescription(), -										LLAssetType::AT_LINK_FOLDER, cb); +					LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << llendl; +					link_array.push_back(LLConstPointer<LLInventoryObject>(item));  				}  				break;  			} @@ -1504,7 +1599,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  			case LLAssetType::AT_BODYPART:  			case LLAssetType::AT_GESTURE:  			{ -				llinfos << "copying inventory item " << item->getName() << llendl; +				LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << llendl;  				copy_inventory_item(gAgent.getID(),  									item->getPermissions().getOwner(),  									item->getUUID(), @@ -1518,6 +1613,10 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  				break;  		}  	} +	if (!link_array.empty()) +	{ +		link_inventory_array(dst_id, link_array, cb); +	}  }  BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) @@ -1582,15 +1681,13 @@ bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id)  // static  bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id)  { -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; +	if (gAgentWearables.isCOFChangeInProgress()) +	{ +		return false; +	} +  	LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); -	gInventory.collectDescendentsIf(outfit_cat_id, -		cats, -		items, -		LLInventoryModel::EXCLUDE_TRASH, -		is_worn); -	return items.size() > 0; +	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, is_worn);  }  // static @@ -1601,15 +1698,8 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id)  		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; +	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn);  }  bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) @@ -1627,18 +1717,11 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)  	}  	// 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; +	LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); +	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn);  } -void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) +void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb)  {  	LLInventoryModel::cat_array_t cats;  	LLInventoryModel::item_array_t items; @@ -1649,46 +1732,14 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)  		LLViewerInventoryItem *item = items.get(i);  		if (item->getActualType() != LLAssetType::AT_LINK_FOLDER)  			continue; -		if (item->getIsLinkType()) +		LLViewerInventoryCategory* catp = item->getLinkedCategory(); +		if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)  		{ -			LLViewerInventoryCategory* catp = item->getLinkedCategory(); -			if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) -			{ -				gInventory.purgeObject(item->getUUID()); -			} +			remove_inventory_item(item->getUUID(), cb);  		}  	}  } -void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items) -{ -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	gInventory.collectDescendents(category, cats, items, -								  LLInventoryModel::EXCLUDE_TRASH); -	for (S32 i = 0; i < items.count(); ++i) -	{ -		LLViewerInventoryItem *item = items.get(i); -		if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) -			continue; -		if (item->getIsLinkType()) -		{ -#if 0 -			if (keep_items && keep_items->find(item) != LLInventoryModel::item_array_t::FAIL) -			{ -				llinfos << "preserved item" << llendl; -			} -			else -			{ -			gInventory.purgeObject(item->getUUID()); -		} -#else -			gInventory.purgeObject(item->getUUID()); -		} -#endif -	} -} -  // 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( @@ -1713,33 +1764,14 @@ void LLAppearanceMgr::filterWearableItems(  	}  } -// Create links to all listed items. -void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, -							  LLInventoryModel::item_array_t& items, -							  LLPointer<LLInventoryCallback> cb) -{ -	for (S32 i=0; i<items.count(); i++) -	{ -		const LLInventoryItem* item = items.get(i).get(); -		link_inventory_item(gAgent.getID(), -							item->getLinkedUUID(), -							cat_uuid, -							item->getName(), -							item->getActualDescription(), -							LLAssetType::AT_LINK, -							cb); - -		const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); -		const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD -		LL_DEBUGS("Avatar") << self_av_string() << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << LL_ENDL; -#endif -	} -} -  void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  {  	LLViewerInventoryCategory *pcat = gInventory.getCategory(category); +	if (!pcat) +	{ +		llwarns << "no category found for id " << category << llendl; +		return; +	}  	LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;  	const LLUUID cof = getCOF(); @@ -1748,7 +1780,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	if (!append)  	{  		LLInventoryModel::item_array_t gest_items; -		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); +		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE);  		for(S32 i = 0; i  < gest_items.count(); ++i)  		{  			LLViewerInventoryItem *gest_item = gest_items.get(i); @@ -1765,8 +1797,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	// required parts are missing.  	// Preserve body parts from COF if appending.  	LLInventoryModel::item_array_t body_items; -	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); -	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); +	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. @@ -1776,8 +1808,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	// - Wearables: include COF contents only if appending.  	LLInventoryModel::item_array_t wear_items;  	if (append) -		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); -	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); +		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); @@ -1785,15 +1817,15 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	// - Attachments: include COF contents only if appending.  	LLInventoryModel::item_array_t obj_items;  	if (append) -		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); -	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); +		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, false); -	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); +		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); +	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE);  	removeDuplicateItems(gest_items);  	// Create links to new COF contents. @@ -1803,23 +1835,56 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	all_items += obj_items;  	all_items += gest_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. -	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; -	linkAll(cof,all_items,link_waiter); +	// 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(); -	// Add link to outfit if category is an outfit.  -	if (!append) +	for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); +		 it != all_items.end(); ++it)  	{ -		createBaseOutfitLink(category, link_waiter); -	} +		LLSD item_contents; +		LLInventoryItem *item = *it; -	// Remove current COF contents.  Have to do this after creating -	// the link_waiter so links can be followed for any items that get -	// carried over (e.g. keeping old shape if the new outfit does not -	// contain one) -	bool keep_outfit_links = append; -	purgeCategory(cof, keep_outfit_links, &all_items); -	gInventory.notifyObservers(); +		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() << ")" << llendl; +		} +		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;  } @@ -1840,21 +1905,21 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI  	LLViewerInventoryCategory* catp = gInventory.getCategory(category);  	std::string new_outfit_name = ""; -	purgeBaseOutfitLink(cof); +	purgeBaseOutfitLink(cof, link_waiter);  	if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)  	{ -		link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "", -							LLAssetType::AT_LINK_FOLDER, link_waiter); +		link_inventory_object(cof, catp, link_waiter);  		new_outfit_name = catp->getName();  	}  	updatePanelOutfitName(new_outfit_name);  } -void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, bool append) +void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder)  { -	lldebugs << "updateAgentWearables()" << llendl; +	LL_DEBUGS("Avatar") << "starts" << llendl; +	LLTimer timer;  	LLInventoryItem::item_array_t items;  	LLDynamicArray< LLViewerWearable* > wearables; @@ -1880,8 +1945,14 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo  	if(wearables.count() > 0)  	{ -		gAgentWearables.setWearableOutfit(items, wearables, !append); +		gAgentWearables.setWearableOutfit(items, wearables);  	} +	LL_DEBUGS("Avatar") << "ends, elapsed " << timer.getElapsedTimeF32() << llendl; +} + +S32 LLAppearanceMgr::countActiveHoldingPatterns() +{ +	return LLWearableHoldingPattern::countActive();  }  static void remove_non_link_items(LLInventoryModel::item_array_t &items) @@ -1932,12 +2003,12 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list,  S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,  												 LLAssetType::EType type,  												 S32 max_items, -												 LLInventoryModel::item_array_t& items_to_kill) +												 LLInventoryObject::object_list_t& items_to_kill)  {  	S32 to_kill_count = 0;  	LLInventoryModel::item_array_t items; -	getDescendentsOfAssetType(cat_id, items, type, false); +	getDescendentsOfAssetType(cat_id, items, type);  	LLInventoryModel::item_array_t curr_items = items;  	removeDuplicateItems(items);  	if (max_items > 0) @@ -1950,40 +2021,39 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,  		 it != kill_items.end();  		 ++it)  	{ -		items_to_kill.push_back(*it); +		items_to_kill.push_back(LLPointer<LLInventoryObject>(*it));  		to_kill_count++;  	}  	return to_kill_count;  } -												  -void LLAppearanceMgr::enforceItemRestrictions() -{ -	S32 purge_count = 0; -	LLInventoryModel::item_array_t items_to_kill; -	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART, -											  1, items_to_kill); -	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING, -											  LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); -	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT, -											  -1, items_to_kill); +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)  	{ -		for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin(); -			 it != items_to_kill.end(); -			 ++it) -		{ -			LLViewerInventoryItem *item = *it; -			LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL; -			gInventory.purgeObject(item->getUUID()); -		} -		gInventory.notifyObservers(); +		// 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 update_base_outfit_ordering) +void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, +											  bool enforce_ordering, +											  nullary_func_t post_update_func)  {  	if (mIsInUpdateAppearanceFromCOF)  	{ @@ -1991,19 +2061,43 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  		return;  	} -	BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); -	selfStartPhase("update_appearance_from_cof"); -  	LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; -	//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) -	updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering); +	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()) +	{ +		llwarns << "Clothing ordering error" << llendl; +	} + +	BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); +	selfStartPhase("update_appearance_from_cof"); -	// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but -	// this should catch anything that gets through. -	enforceItemRestrictions(); -	  	// update dirty flag to see if the state of the COF matches  	// the saved outfit stored as a folder link  	updateIsDirty(); @@ -2013,13 +2107,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	{  		requestServerAppearanceUpdate();  	} -	// DRANO really should wait for the appearance message to set this. -	// verify that deleting this line doesn't break anything. -	//gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()); -	 -	//dumpCat(getCOF(),"COF, start"); -	bool follow_folder_links = false;  	LLUUID current_outfit_id = getCOF();  	// Find all the wearables that are in the COF's subtree. @@ -2027,7 +2115,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	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, follow_folder_links); +	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); @@ -2046,6 +2134,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	sortItemsByActualDescription(wear_items); +	LL_DEBUGS("Avatar") << "HP block starts" << llendl; +	LLTimer hp_block_timer;  	LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;  	holder->setObjItems(obj_items); @@ -2095,7 +2185,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  		}  	} -	selfStartPhase("get_wearables"); +	selfStartPhase("get_wearables_2");  	for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin();  		 it != holder->getFoundList().end(); ++it) @@ -2119,12 +2209,14 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	{  		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder));  	} +	post_update_func(); + +	LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << llendl;  }  void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category,  													LLInventoryModel::item_array_t& items, -													LLAssetType::EType type, -													bool follow_folder_links) +													LLAssetType::EType type)  {  	LLInventoryModel::cat_array_t cats;  	LLIsType is_of_type(type); @@ -2132,15 +2224,13 @@ void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category,  									cats,  									items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_of_type, -									follow_folder_links); +									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, -											 bool follow_folder_links) +											 LLInventoryModel::item_array_t& gest_items)  {  	LLInventoryModel::cat_array_t wear_cats;  	LLFindWearables is_wearable; @@ -2148,8 +2238,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,  									wear_cats,  									wear_items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_wearable, -									follow_folder_links); +									is_wearable);  	LLInventoryModel::cat_array_t obj_cats;  	LLIsType is_object( LLAssetType::AT_OBJECT ); @@ -2157,8 +2246,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,  									obj_cats,  									obj_items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_object, -									follow_folder_links); +									is_object);  	// Find all gestures in this folder  	LLInventoryModel::cat_array_t gest_cats; @@ -2167,8 +2255,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,  									gest_cats,  									gest_items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_gesture, -									follow_folder_links); +									is_gesture);  }  void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) @@ -2183,10 +2270,36 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool  	LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName()  			 << " )" << LL_ENDL; -	selfStartPhase("wear_inventory_category_fetch"); -	callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, -														   &LLAppearanceMgr::instance(), -														   category->getUUID(), copy, append)); +	// 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) @@ -2267,7 +2380,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego  	// 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 (!category) return;  	if ( !LLInventoryCallbackManager::is_instantiated() )  	{ @@ -2287,6 +2400,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego  	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; @@ -2340,9 +2454,8 @@ bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventor  class LLDeferredCOFLinkObserver: public LLInventoryObserver  {  public: -	LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL, std::string description = ""): +	LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description):  		mItemID(item_id), -		mDoUpdate(do_update),  		mCallback(cb),  		mDescription(description)  	{ @@ -2358,14 +2471,13 @@ public:  		if (item)  		{  			gInventory.removeObserver(this); -			LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback); +			LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription);  			delete this;  		}  	}  private:  	const LLUUID mItemID; -	bool mDoUpdate;  	std::string mDescription;  	LLPointer<LLInventoryCallback> mCallback;  }; @@ -2373,42 +2485,26 @@ private:  // 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, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description) +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, do_update, cb, description); +		LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description);  		gInventory.addObserver(observer);  	}  	else  	{ -		addCOFItemLink(item, do_update, cb, description); -	} -} - -void modified_cof_cb(const LLUUID& inv_item) -{		 -	LLAppearanceMgr::instance().updateAppearanceFromCOF(); - -	// Start editing the item if previously requested. -	gAgentWearables.editWearableIfRequested(inv_item); - -	// 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(); -		} +		addCOFItemLink(item, cb, description);  	}  } -void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description) -{		 -	std::string link_description = description; +void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, +									 LLPointer<LLInventoryCallback> cb, +									 const std::string description) +{  	const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);  	if (!vitem)  	{ @@ -2448,43 +2544,23 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update  			++count;  			if (is_body_part && inv_item->getIsLinkType()  && (vitem->getWearableType() == wearable_type))  			{ -				gInventory.purgeObject(inv_item->getUUID()); +				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 -				gInventory.purgeObject(inv_item->getUUID()); +				remove_inventory_item(inv_item->getUUID(), cb);  			}  		}  	} -	if (linked_already) +	if (!linked_already)  	{ -		if (do_update) -		{	 -			LLAppearanceMgr::updateAppearanceFromCOF(); -		} -		return; -	} -	else -	{ -		if(do_update && cb.isNull()) -		{ -			cb = new LLBoostFuncInventoryCallback(modified_cof_cb); -		} -		if (vitem->getIsLinkType()) -		{ -			link_description = vitem->getActualDescription(); -		} -		link_inventory_item( gAgent.getID(), -							 vitem->getLinkedUUID(), -							 getCOF(), -							 vitem->getName(), -							 link_description, -							 LLAssetType::AT_LINK, -							 cb); +		LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; +		copy_item->copyViewerItem(vitem); +		copy_item->setDescription(description); +		link_inventory_object(getCOF(), copy_item, cb);  	} -	return;  }  LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id) @@ -2524,8 +2600,7 @@ void LLAppearanceMgr::removeAllClothesFromAvatar()  									dummy,  									clothing_items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_clothing, -									false); +									is_clothing);  	uuid_vec_t item_ids;  	for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin();  		it != clothing_items.end(); ++it) @@ -2569,7 +2644,7 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar()  	removeItemsFromAvatar(ids_to_remove);  } -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id) +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb)  {  	gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); @@ -2584,12 +2659,12 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id)  		const LLInventoryItem* item = item_array.get(i).get();  		if (item->getIsLinkType() && item->getLinkedUUID() == item_id)  		{ -			gInventory.purgeObject(item->getUUID()); +			remove_inventory_item(item->getUUID(), cb);  		}  	}  } -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type) +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb)  {  	LLFindWearablesOfType filter_wearables_of_type(type);  	LLInventoryModel::cat_array_t cats; @@ -2602,7 +2677,7 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type)  		const LLViewerInventoryItem* item = *it;  		if (item->getIsLinkType()) // we must operate on links only  		{ -			gInventory.purgeObject(item->getUUID()); +			remove_inventory_item(item->getUUID(), cb);  		}  	}  } @@ -2641,7 +2716,7 @@ void LLAppearanceMgr::updateIsDirty()  	if (base_outfit.notNull())  	{ -		LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK); +		LLIsValidItemLink collector;  		LLInventoryModel::cat_array_t cof_cats;  		LLInventoryModel::item_array_t cof_items; @@ -2655,6 +2730,7 @@ void LLAppearanceMgr::updateIsDirty()  		if(outfit_items.count() != cof_items.count())  		{ +			LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.count() << " cof " << cof_items.count() << llendl;  			// 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; @@ -2674,11 +2750,30 @@ void LLAppearanceMgr::updateIsDirty()  				item1->getName() != item2->getName() ||  				item1->getActualDescription() != item2->getActualDescription())  			{ +				if (item1->getLinkedUUID() != item2->getLinkedUUID()) +				{ +					LL_DEBUGS("Avatar") << "link id different " << llendl; +				} +				else +				{ +					if (item1->getName() != item2->getName()) +					{ +						LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << llendl; +					} +					if (item1->getActualDescription() != item2->getActualDescription()) +					{ +						LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() +											<< " " << item2->getActualDescription()  +											<< " names " << item1->getName() << " " << item2->getName() << llendl; +					} +				}  				mOutfitIsDirty = true;  				return;  			}  		}  	} +	llassert(!mOutfitIsDirty); +	LL_DEBUGS("Avatar") << "clean" << llendl;  }  // *HACK: Must match name in Library or agent inventory @@ -2760,23 +2855,6 @@ void LLAppearanceMgr::copyLibraryGestures()  	}  } -void LLAppearanceMgr::autopopulateOutfits() -{ -	// If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) -	// then auto-populate outfits from the library into the My Outfits folder. - -	LL_INFOS("Avatar") << self_av_string() << "avatar fully visible" << LL_ENDL; - -	static bool check_populate_my_outfits = true; -	if (check_populate_my_outfits &&  -		(LLInventoryModel::getIsFirstTimeInViewer2()  -		 || gSavedSettings.getBOOL("MyOutfitsAutofill"))) -	{ -		gAgentWearables.populateMyOutfitsFolder(); -	} -	check_populate_my_outfits = false; -} -  // Handler for anything that's deferred until avatar de-clouds.  void LLAppearanceMgr::onFirstFullyVisible()  { @@ -2784,10 +2862,6 @@ void LLAppearanceMgr::onFirstFullyVisible()  	gAgentAvatarp->reportAvatarRezTime();  	gAgentAvatarp->debugAvatarVisible(); -	// The auto-populate is failing at the point of generating outfits -	// folders, so don't do the library copy until that is resolved. -	// autopopulateOutfits(); -  	// If this is the first time we've ever logged in,  	// then copy default gestures from the library.  	if (gAgent.isFirstLogin()) { @@ -2802,9 +2876,27 @@ 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()) @@ -2813,23 +2905,20 @@ bool LLAppearanceMgr::updateBaseOutfit()  		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 << llendl; -	updateClothingOrderingInfo(); - -	// in a Base Outfit we do not remove items, only links -	purgeCategory(base_outfit_id, false); - -	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 -	shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater); +	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;  } @@ -2877,12 +2966,6 @@ struct WearablesOrderComparator  	bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2)  	{ -		if (!item1 || !item2) -		{ -			llwarning("either item1 or item2 is NULL", 0); -			return true; -		} -		  		const std::string& desc1 = item1->getActualDescription();  		const std::string& desc2 = item2->getActualDescription(); @@ -2896,260 +2979,374 @@ struct WearablesOrderComparator  		//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 true; +		return item1->getName() < item2->getName();  	}  	U32 mControlSize;  }; -void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering) +void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, +													 desc_map_t& desc_map)  { -	if (cat_id.isNull()) -	{ -		cat_id = getCOF(); -		if (update_base_outfit_ordering) -		{ -			const LLUUID base_outfit_id = getBaseOutfitUUID(); -			if (base_outfit_id.notNull()) -			{ -				updateClothingOrderingInfo(base_outfit_id,false); -			} -		} -	} - -	// COF is processed if cat_id is not specified -	LLInventoryModel::item_array_t wear_items; -	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false); -  	wearables_by_type_t items_by_type(LLWearableType::WT_COUNT);  	divvyWearablesByType(wear_items, items_by_type); -	bool inventory_changed = false;  	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; - -			item->setDescription(new_order_str); -			item->setComplete(TRUE); - 			item->updateServer(FALSE); -			gInventory.updateItem(item); -			inventory_changed = true; +			desc_map[item->getUUID()] = new_order_str;  		}  	} - -	//*TODO do we really need to notify observers? -	if (inventory_changed) gInventory.notifyObservers();  } -// This is intended for use with HTTP Clients/Responders, but is not -// specifically coupled with those classes. -class LLHTTPRetryPolicy: public LLThreadSafeRefCount +bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id)  { -public: -	LLHTTPRetryPolicy() {} -	virtual ~LLHTTPRetryPolicy() {} -	virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0; -}; +	// COF is processed if cat_id is not specified +	if (cat_id.isNull()) +	{ +		cat_id = getCOF(); +	} -// Example of simplest possible policy, not necessarily recommended. -class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy -{ -public: -	LLAlwaysRetryImmediatelyPolicy() {} -	bool shouldRetry(U32 status, F32& seconds_to_wait) +	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)  	{ -		seconds_to_wait = 0.0; -		return true; +		const LLUUID& item_id = it->first; +		const std::string& new_order_str = it->second; +		LLViewerInventoryItem *item = gInventory.getItem(item_id); +		llwarns << "Order validation fails: " << item->getName() +				<< " needs to update desc to: " << new_order_str +				<< " (from: " << item->getActualDescription() << ")" << llendl;  	} -}; +	 +	return desc_map.size() == 0; +} -// Very general policy with geometric back-off after failures, -// up to a maximum delay, and maximum number of retries. -class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, +												 LLPointer<LLInventoryCallback> cb)  { -public: -	LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries): -		mMinDelay(min_delay), -		mMaxDelay(max_delay), -		mBackoffFactor(backoff_factor), -		mMaxRetries(max_retries), -		mDelay(min_delay), -		mRetryCount(0) +	// COF is processed if cat_id is not specified +	if (cat_id.isNull())  	{ +		cat_id = getCOF();  	} -	bool shouldRetry(U32 status, F32& seconds_to_wait) +	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)  	{ -		seconds_to_wait = mDelay; -		mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); -		mRetryCount++; -		return (mRetryCount<=mMaxRetries); +		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() << ")" << llendl; +		updates["desc"] = new_order_str; +		update_inventory_item(item_id,updates,cb);  	} +		 +} + +class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder +{ +	LOG_CLASS(RequestAgentUpdateAppearanceResponder); + +	friend class LLAppearanceMgr; +	 +public: +	RequestAgentUpdateAppearanceResponder(); + +	virtual ~RequestAgentUpdateAppearanceResponder();  private: -	F32 mMinDelay; // delay never less than this value -	F32 mMaxDelay; // delay never exceeds this value -	F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. -	U32 mMaxRetries; // maximum number of times shouldRetry will return true. -	F32 mDelay; // current delay. -	U32 mRetryCount; // number of times shouldRetry has been called. +	// Called when sendServerAppearanceUpdate called. May or may not +	// trigger a request depending on various bits of state. +	void onRequestRequested(); + +	// Post the actual appearance request to cap. +	void sendRequest(); + +	void debugCOF(const LLSD& content); + +protected: +	// Successful completion. +	/* virtual */ void httpSuccess(); + +	// Error +	/*virtual*/ void httpFailure(); + +	void onFailure(); +	void onSuccess(); + +	S32 mInFlightCounter; +	LLTimer mInFlightTimer; +	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;  }; -class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder +RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder()  { -public: -	RequestAgentUpdateAppearanceResponder() +	bool retry_on_4xx = true; +	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx); +	mInFlightCounter = 0; +} + +RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder() +{ +} + +void RequestAgentUpdateAppearanceResponder::onRequestRequested() +{ +	// If we have already received an update for this or higher cof version, ignore. +	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); +	S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; +	S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; +	LL_DEBUGS("Avatar") << "cof_version " << cof_version +						<< " last_rcv " << last_rcv +						<< " last_req " << last_req +						<< " in flight " << mInFlightCounter << llendl; +	if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired()))  	{ -		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); +		LL_WARNS("Avatar") << "in flight timer expired, resetting " << llendl; +		mInFlightCounter = 0;  	} - -	virtual ~RequestAgentUpdateAppearanceResponder() +	if (cof_version < last_rcv)  	{ +		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv +							<< " will not request for " << cof_version << llendl; +		return;  	} - -	// Successful completion. -	/* virtual */ void result(const LLSD& content) +	if (mInFlightCounter>0 && last_req >= cof_version)  	{ -		LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL; -		if (content["success"].asBoolean()) -		{ -			LL_DEBUGS("Avatar") << "OK" << LL_ENDL; -			if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -			{ -				dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); -			} -		} -		else -		{ -			onFailure(200); -		} +		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req  +							<< " will not request for " << cof_version << llendl; +		return;  	} -	// Error -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	// Actually send the request. +	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << llendl; +	mRetryPolicy->reset(); +	sendRequest(); +} +	 +void RequestAgentUpdateAppearanceResponder::sendRequest() +{ +	if (gAgentAvatarp->isEditingAppearance())   	{ -		llwarns << "appearance update request failed, status: " << status << " reason: " << reason << " code: " << content["code"].asInteger() << " error: \"" << content["error"].asString() << "\"" << llendl; -		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -		{ -			dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_error", content); -			debugCOF(content); -		 -		} -		onFailure(status); -	}	 +		// don't send out appearance updates if in appearance editing mode +		return; +	} -	void onFailure(U32 status) +	if (!gAgent.getRegion())  	{ -		F32 seconds_to_wait; -		if (mRetryPolicy->shouldRetry(status,seconds_to_wait)) -		{ -			llinfos << "retrying" << llendl; -			doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate, -										LLAppearanceMgr::getInstance(), -										LLCurl::ResponderPtr(this)), -							seconds_to_wait); -		} -		else +		llwarns << "Region not set, cannot request server appearance update" << llendl; +		return; +	} +	if (gAgent.getRegion()->getCentralBakeVersion()==0) +	{ +		llwarns << "Region does not support baking" << llendl; +	} +	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 +	if (url.empty()) +	{ +		llwarns << "No cap for UpdateAvatarAppearance." << llendl; +		return; +	} +	 +	LLSD body; +	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); +	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) +	{ +		body = LLAppearanceMgr::instance().dumpCOF(); +	} +	else +	{ +		body["cof_version"] = cof_version; +		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))  		{ -			llwarns << "giving up after too many retries" << llendl; +			body["cof_version"] = cof_version+999;  		} -	}	 - -	void dumpContents(const std::string outprefix, const LLSD& content) -	{ -		std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); -		std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); -		std::ofstream ofs(fullpath.c_str(), std::ios_base::out); -		ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY); -		LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL;  	} +	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << llendl; -	void debugCOF(const LLSD& content) +	mInFlightCounter++; +	mInFlightTimer.setTimerExpirySec(60.0); +	LLHTTPClient::post(url, body, this); +	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); +	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; +} + +void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) +{ +	LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() +					   << " ================================= " << llendl; +	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)  	{ -		LL_DEBUGS("Avatar") << "AIS COF, version found: " << content["expected"].asInteger() << llendl; -		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())  		{ -			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  			{ -				ais_items.insert(item["item_id"].asUUID()); -				if (item["type"].asInteger() == 24) // link -				{ -					LL_DEBUGS("Avatar") << "Link: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< llendl;  -				} -				else if (item["type"].asInteger() == 25) // folder link -				{ -					LL_DEBUGS("Avatar") << "Folder link: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< llendl;  +				LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() +								   << " linked_item_id: " << item["asset_id"].asUUID() +								   << " name: " << item["name"].asString() +								   << llendl;  +			} +			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() +								   << llendl;  -				} -				else -				{ -					LL_DEBUGS("Avatar") << "Other: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< llendl;  -				} +			} +			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() +								   << llendl;   			}  		} -		LL_DEBUGS("Avatar") << llendl; -		LL_DEBUGS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() << llendl; -		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.count(); i++) +	} +	LL_INFOS("Avatar") << llendl; +	LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()  +					   << " ================================= " << llendl; +	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.count(); i++) +	{ +		const LLViewerInventoryItem* inv_item = item_array.get(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() +						   << llendl; +	} +	LL_INFOS("Avatar") << " ================================= " << llendl; +	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())  		{ -			const LLViewerInventoryItem* inv_item = item_array.get(i).get(); -			local_items.insert(inv_item->getUUID()); -			LL_DEBUGS("Avatar") << "item_id: " << inv_item->getUUID() -								<< " linked_item_id: " << inv_item->getLinkedUUID() -								<< " name: " << inv_item->getName() -								<< llendl; +			LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << llendl; +			local_only++;  		} -		LL_DEBUGS("Avatar") << llendl; -		for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) +	} +	for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) +	{ +		if (local_items.find(*it) == local_items.end())  		{ -			if (ais_items.find(*it) == ais_items.end()) -			{ -				LL_DEBUGS("Avatar") << "LOCAL ONLY: " << *it << llendl; -			} +			LL_INFOS("Avatar") << "AIS ONLY: " << *it << llendl; +			ais_only++;  		} -		for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) +	} +	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() +						   << ")" << llendl; +	} +} + +/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() +{ +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +	if (content["success"].asBoolean()) +	{ +		LL_DEBUGS("Avatar") << "succeeded" << llendl; +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))  		{ -			if (local_items.find(*it) == local_items.end()) -			{ -				LL_DEBUGS("Avatar") << "AIS ONLY: " << *it << llendl; -			} +			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);  		} + +		onSuccess(); +	} +	else +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content);  	} +} + +void RequestAgentUpdateAppearanceResponder::onSuccess() +{ +	mInFlightCounter = llmax(mInFlightCounter-1,0); +} + +/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure() +{ +	LL_WARNS("Avatar") << "appearance update request failed, status " +					   << getStatus() << " reason " << getReason() << LL_ENDL; + +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +	{ +		const LLSD& content = getContent(); +		dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); +		debugCOF(content); +	} +	onFailure(); +} + +void RequestAgentUpdateAppearanceResponder::onFailure() +{ +	mInFlightCounter = llmax(mInFlightCounter-1,0); + +	F32 seconds_to_wait; +	mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); +	if (mRetryPolicy->shouldRetry(seconds_to_wait)) +	{ +		llinfos << "retrying" << llendl; +		doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), +						seconds_to_wait); +	} +	else +	{ +		llwarns << "giving up after too many retries" << llendl; +	} +}	 -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -};  LLSD LLAppearanceMgr::dumpCOF() const  { @@ -3214,58 +3411,14 @@ LLSD LLAppearanceMgr::dumpCOF() const  	return result;  } -void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr) +void LLAppearanceMgr::requestServerAppearanceUpdate()  { -	if (gAgentAvatarp->isEditingAppearance())  -	{ -		// don't send out appearance updates if in appearance editing mode -		return; -	} - -	if (!gAgent.getRegion()) -	{ -		llwarns << "Region not set, cannot request server appearance update" << llendl; -		return; -	} -	if (gAgent.getRegion()->getCentralBakeVersion()==0) -	{ -		llwarns << "Region does not support baking" << llendl; -	} -	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 -	if (url.empty()) -	{ -		llwarns << "No cap for UpdateAvatarAppearance." << llendl; -		return; -	} - -	LLSD body; -	S32 cof_version = getCOFVersion(); -	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) -	{ -		body = dumpCOF(); -	} -	else -	{ -		body["cof_version"] = cof_version; -		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) -		{ -			body["cof_version"] = cof_version+999; -		} -	} -	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << llendl; - -	//LLCurl::ResponderPtr responder_ptr; -	if (!responder_ptr.get()) -	{ -		responder_ptr = new RequestAgentUpdateAppearanceResponder; -	} -	LLHTTPClient::post(url, body, responder_ptr); -	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); -	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; +	mAppearanceResponder->onRequestRequested();  }  class LLIncrementCofVersionResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLIncrementCofVersionResponder);  public:  	LLIncrementCofVersionResponder() : LLHTTPClient::Responder()  	{ @@ -3276,22 +3429,31 @@ public:  	{  	} -	virtual void result(const LLSD &pContent) +protected: +	virtual void httpSuccess()  	{  		llinfos << "Successfully incremented agent's COF." << llendl; -		S32 new_version = pContent["category"]["version"].asInteger(); +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		} +		S32 new_version = content["category"]["version"].asInteger();  		// cof_version should have increased  		llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion);  		gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version;  	} -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& content) + +	virtual void httpFailure()  	{ -		llwarns << "While attempting to increment the agent's cof we got an error with [status:" -				<< pStatus << "]: " << content << llendl; +		LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error " +				<< dumpResponse() << LL_ENDL;  		F32 seconds_to_wait; -		if (mRetryPolicy->shouldRetry(pStatus,seconds_to_wait)) +		mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); +		if (mRetryPolicy->shouldRetry(seconds_to_wait))  		{  			llinfos << "retrying" << llendl;  			doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, @@ -3305,6 +3467,7 @@ public:  		}  	} +private:  	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;  }; @@ -3337,6 +3500,15 @@ void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_p  	LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f);  } +U32 LLAppearanceMgr::getNumAttachmentsInCOF() +{ +	const LLUUID cof = getCOF(); +	LLInventoryModel::item_array_t obj_items; +	getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); +	return obj_items.size(); +} + +  std::string LLAppearanceMgr::getAppearanceServiceURL() const  {  	if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) @@ -3347,57 +3519,91 @@ std::string LLAppearanceMgr::getAppearanceServiceURL() const  }  void show_created_outfit(LLUUID& folder_id, bool show_panel = true) +{ +	if (!LLApp::isRunning())  	{ -		if (!LLApp::isRunning()) -		{ -			llwarns << "called during shutdown, skipping" << llendl; -			return; -		} - -		LLSD key; -		 +		llwarns << "called during shutdown, skipping" << llendl; +		return; +	} +	 +	LL_DEBUGS("Avatar") << "called" << llendl; +	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) -		{ -			LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); - -		} -		LLOutfitsList *outfits_list = -			dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); -		if (outfits_list) -		{ +	{ +		LL_DEBUGS("Avatar") << "showing panel" << llendl; +		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("");  	} +	 +	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" << llendl; +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +	LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); +} -LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) +void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel)  { -	if (!isAgentAvatarValid()) return LLUUID::null; - -	gAgentWearables.notifyLoadingStarted(); +	LLPointer<LLInventoryCallback> cb = +		new LLBoostFuncInventoryCallback(no_op_inventory_func, +										 boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); +	updateClothingOrderingInfo(LLUUID::null, cb); +} -	// First, make a folder in the My Outfits directory. -	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	LLUUID folder_id = gInventory.createNewCategory( -		parent_id, -		LLFolderType::FT_OUTFIT, -		new_folder_name); +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); +} -	updateClothingOrderingInfo(); +void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) +{ +	if (!isAgentAvatarValid()) return; -	LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(no_op_inventory_func, -																		 boost::bind(show_created_outfit,folder_id,show_panel)); -	shallowCopyCategoryContents(getCOF(),folder_id, cb); -	createBaseOutfitLink(folder_id, cb); +	LL_DEBUGS("Avatar") << "creating new outfit" << llendl; -	dumpCat(folder_id,"COF, new outfit"); +	gAgentWearables.notifyLoadingStarted(); -	return folder_id; +	// 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() @@ -3413,21 +3619,22 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)  	if (ids_to_remove.empty())  	{  		llwarns << "called with empty list, nothing to do" << llendl; +		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); -			} -	updateAppearanceFromCOF(); +		removeCOFItemLinks(linked_item_id, cb);  	} +}  void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)  {  	LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove); -	removeCOFItemLinks(linked_item_id); -	updateAppearanceFromCOF(); +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +	removeCOFItemLinks(linked_item_id, cb);  }  bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) @@ -3460,7 +3667,12 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b  	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()) << llendl; +	// FIXME switch to use AISv3 where supported.  	//items need to be updated on a dataserver  	item->setComplete(TRUE);  	item->updateServer(FALSE); @@ -3536,7 +3748,8 @@ LLAppearanceMgr::LLAppearanceMgr():  	mAttachmentInvLinkEnabled(false),  	mOutfitIsDirty(false),  	mOutfitLocked(false), -	mIsInUpdateAppearanceFromCOF(false) +	mIsInUpdateAppearanceFromCOF(false), +	mAppearanceResponder(new RequestAgentUpdateAppearanceResponder)  {  	LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); @@ -3586,7 +3799,8 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)  		   // 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 -		   LLAppearanceMgr::addCOFItemLink(item_id, false);  // Add COF link for item. +		   LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(); +		   LLAppearanceMgr::addCOFItemLink(item_id, cb);  // Add COF link for item.  	   }  	   else  	   { @@ -3610,22 +3824,21 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)  BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const  { -	return gInventory.isObjectDescendentOf(obj_id, getCOF()); +	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)  { -	 LLInventoryModel::cat_array_t cats; -	 LLInventoryModel::item_array_t items; -	 LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id)); -	 gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), -									 cats, -									 items, -	 LLInventoryModel::EXCLUDE_TRASH, -	 find_links); - -	 return !items.empty(); +	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 @@ -3642,18 +3855,6 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const  	// For now, don't allow direct deletion from the COF.  Instead, force users  	// to choose "Detach" or "Take Off".  	return TRUE; -	/* -	const LLInventoryObject *obj = gInventory.getObject(obj_id); -	if (!obj) return FALSE; - -	// Can't delete bodyparts, since this would be equivalent to removing the item. -	if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE; - -	// Can't delete the folder link, since this is saved for bookkeeping. -	if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; - -	return FALSE; -	*/  }  class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 46252afbde..3a90c3840a 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -38,6 +38,7 @@  class LLWearableHoldingPattern;  class LLInventoryCallback;  class LLOutfitUnLockTimer; +class RequestAgentUpdateAppearanceResponder;  class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>  { @@ -49,7 +50,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>  public:  	typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t; -	void updateAppearanceFromCOF(bool update_base_outfit_ordering = false); +	void updateAppearanceFromCOF(bool enforce_item_restrictions = true, +								 bool enforce_ordering = true, +								 nullary_func_t post_update_func = no_op);  	bool needToSaveCOF();  	void updateCOF(const LLUUID& category, bool append = false);  	void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); @@ -64,9 +67,18 @@ public:  	S32 findExcessOrDuplicateItems(const LLUUID& cat_id,  								   LLAssetType::EType type,  								   S32 max_items, -								   LLInventoryModel::item_array_t& items_to_kill); -	void enforceItemRestrictions(); - +								   LLInventoryObject::object_list_t& items_to_kill); +	void findAllExcessOrDuplicateItems(const LLUUID& cat_id, +									  LLInventoryObject::object_list_t& items_to_kill); +	void enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb); + +	S32 getActiveCopyOperations() const; + +	// Replace category contents with copied links via the slam_inventory_folder +	// command (single inventory operation where supported) +	void slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, +						   bool include_folder_links, LLPointer<LLInventoryCallback> cb); +   	// Copy all items and the src category itself.  	void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,  							 LLPointer<LLInventoryCallback> cb); @@ -105,15 +117,18 @@ public:  	const LLUUID getBaseOutfitUUID();  	// Wear/attach an item (from a user's inventory) on the agent -	bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true, bool replace = false, LLPointer<LLInventoryCallback> cb = NULL); +	bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false, +						  LLPointer<LLInventoryCallback> cb = NULL);  	// Update the displayed outfit name in UI.  	void updatePanelOutfitName(const std::string& name); -	void purgeBaseOutfitLink(const LLUUID& category); +	void purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb = NULL);  	void createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter); -	void updateAgentWearables(LLWearableHoldingPattern* holder, bool append); +	void updateAgentWearables(LLWearableHoldingPattern* holder); + +	S32 countActiveHoldingPatterns();  	// For debugging - could be moved elsewhere.  	void dumpCat(const LLUUID& cat_id, const std::string& msg); @@ -124,21 +139,16 @@ public:  	void registerAttachment(const LLUUID& item_id);  	void setAttachmentInvLinkEnable(bool val); -	// utility function for bulk linking. -	void linkAll(const LLUUID& category, -				 LLInventoryModel::item_array_t& items, -				 LLPointer<LLInventoryCallback> cb); -  	// Add COF link to individual item. -	void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); -	void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); +	void addCOFItemLink(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); +	void addCOFItemLink(const LLInventoryItem *item, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = "");  	// Find COF entries referencing the given item.  	LLInventoryModel::item_array_t findCOFItemLinks(const LLUUID& item_id);  	// Remove COF entries -	void removeCOFItemLinks(const LLUUID& item_id); -	void removeCOFLinksOfType(LLWearableType::EType type); +	void removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL); +	void removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb = NULL);  	void removeAllClothesFromAvatar();  	void removeAllAttachmentsFromAvatar(); @@ -152,12 +162,11 @@ public:  	// should only be necessary to do on initial login.  	void updateIsDirty(); +	void setOutfitLocked(bool locked); +  	// Called when self avatar is first fully visible.  	void onFirstFullyVisible(); -	// Create initial outfits from library. -	void autopopulateOutfits(); -  	// Copy initial gestures from library.  	void copyLibraryGestures(); @@ -172,7 +181,10 @@ public:  	void removeItemFromAvatar(const LLUUID& item_id); -	LLUUID makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true); +	void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel); +	void onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel); + +	void makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true);  	bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body); @@ -181,18 +193,27 @@ public:  	//Divvy items into arrays by wearable type  	static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type); +	typedef std::map<LLUUID,std::string> desc_map_t; + +	void getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, desc_map_t& desc_map); +  	//Check ordering information on wearables stored in links' descriptions and update if it is invalid  	// COF is processed if cat_id is not specified -	void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, bool update_base_outfit_ordering = false); +	bool validateClothingOrderingInfo(LLUUID cat_id = LLUUID::null); +	 +	void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, +									LLPointer<LLInventoryCallback> cb = NULL);  	bool isOutfitLocked() { return mOutfitLocked; }  	bool isInUpdateAppearanceFromCOF() { return mIsInUpdateAppearanceFromCOF; } -	void requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr = NULL); +	void requestServerAppearanceUpdate();  	void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL); +	U32 getNumAttachmentsInCOF(); +  	// *HACK Remove this after server side texture baking is deployed on all sims.  	void incrementCofVersionLegacy(); @@ -213,24 +234,21 @@ private:  	void getDescendentsOfAssetType(const LLUUID& category,   										  LLInventoryModel::item_array_t& items, -										  LLAssetType::EType type, -										  bool follow_folder_links); +										  LLAssetType::EType type);  	void getUserDescendents(const LLUUID& category,   								   LLInventoryModel::item_array_t& wear_items,  								   LLInventoryModel::item_array_t& obj_items, -								   LLInventoryModel::item_array_t& gest_items, -								   bool follow_folder_links); +								   LLInventoryModel::item_array_t& gest_items); -	void purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items = NULL);  	static void onOutfitRename(const LLSD& notification, const LLSD& response); -	void setOutfitLocked(bool locked); -  	bool mAttachmentInvLinkEnabled;  	bool mOutfitIsDirty;  	bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. +	LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder; +  	/**  	 * Lock for blocking operations on outfit until server reply or timeout exceed  	 * to avoid unsynchronized outfit state or performing duplicate operations. @@ -256,17 +274,31 @@ public:  class LLUpdateAppearanceOnDestroy: public LLInventoryCallback  {  public: -	LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false); +	LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions = true, +								bool enforce_ordering = true, +								nullary_func_t post_update_func = no_op);  	virtual ~LLUpdateAppearanceOnDestroy();  	/* virtual */ void fire(const LLUUID& inv_item);  private:  	U32 mFireCount; -	bool mUpdateBaseOrder; +	bool mEnforceItemRestrictions; +	bool mEnforceOrdering; +	nullary_func_t mPostUpdateFunc;  }; +class LLUpdateAppearanceAndEditWearableOnDestroy: public LLInventoryCallback +{ +public: +	LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id); + +	/* virtual */ void fire(const LLUUID& item_id) {} -#define SUPPORT_ENSEMBLES 0 +	~LLUpdateAppearanceAndEditWearableOnDestroy(); +	 +private: +	LLUUID mItemID; +};  LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name); diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index 4bdb690225..cde9bc9dc0 100755 --- a/indra/newview/llassetuploadqueue.cpp +++ b/indra/newview/llassetuploadqueue.cpp @@ -36,6 +36,7 @@  class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder  { +	LOG_CLASS(LLAssetUploadChainResponder);  public:  	LLAssetUploadChainResponder(const LLSD& post_data, @@ -51,52 +52,54 @@ public:  		mDataSize(data_size),  		mScriptName(script_name)  	{ - 	} +	}  	virtual ~LLAssetUploadChainResponder()  -   	{ -   		if(mSupplier) -   		{ -   			LLAssetUploadQueue *queue = mSupplier->get(); -   			if (queue) -   			{ -   				// Give ownership of supplier back to queue. -   				queue->mSupplier = mSupplier; -   				mSupplier = NULL; -   			} -   		} -   		delete mSupplier; +	{ +		if(mSupplier) +		{ +			LLAssetUploadQueue *queue = mSupplier->get(); +			if (queue) +			{ +				// Give ownership of supplier back to queue. +				queue->mSupplier = mSupplier; +				mSupplier = NULL; +			} +		} +		delete mSupplier;  		delete mData; -   	} +	} -	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -   	{ -		llwarns << "LLAssetUploadChainResponder Error [status:"  -				<< statusNum << "]: " << content << llendl; -		LLUpdateTaskInventoryResponder::errorWithContent(statusNum, reason, content); -   		LLAssetUploadQueue *queue = mSupplier->get(); -   		if (queue) +protected: +	virtual void httpFailure() +	{ +		// Parent class will spam the failure. +		//llwarns << dumpResponse() << llendl; +		LLUpdateTaskInventoryResponder::httpFailure(); +		LLAssetUploadQueue *queue = mSupplier->get(); +		if (queue) +		{ +			queue->request(&mSupplier); +		} +	} + +	virtual void httpSuccess() +	{ +		LLUpdateTaskInventoryResponder::httpSuccess(); +		LLAssetUploadQueue *queue = mSupplier->get(); +		if (queue)  		{ -   			queue->request(&mSupplier); -   		} -   	} - -	virtual void result(const LLSD& content) -   	{ -		LLUpdateTaskInventoryResponder::result(content); -   		LLAssetUploadQueue *queue = mSupplier->get(); -   		if (queue) -   		{ -   			// Responder is reused across 2 phase upload, -   			// so only start next upload after 2nd phase complete. -   			std::string state = content["state"]; -   			if(state == "complete") -   			{ -   				queue->request(&mSupplier); -   			} -   		}	 -   	} +			// Responder is reused across 2 phase upload, +			// so only start next upload after 2nd phase complete. +			const std::string& state = getContent()["state"].asStringRef(); +			if(state == "complete") +			{ +				queue->request(&mSupplier); +			} +		} +	} +public:  	virtual void uploadUpload(const LLSD& content)  	{  		std::string uploader = content["uploader"]; diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 2564802387..ea511b18e2 100755 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -225,37 +225,41 @@ LLAssetUploadResponder::~LLAssetUploadResponder()  }  // virtual -void LLAssetUploadResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLAssetUploadResponder::httpFailure()  { -	llinfos << "LLAssetUploadResponder::error [status:"  -			<< statusNum << "]: " << content << llendl; +	// *TODO: Add adaptive retry policy? +	llwarns << dumpResponse() << llendl;  	LLSD args; -	switch(statusNum) +	if (isHttpClientErrorStatus(getStatus()))  	{ -		case 400: -			args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); -			args["REASON"] = "Error in upload request.  Please visit " -				"http://secondlife.com/support for help fixing this problem."; -			LLNotificationsUtil::add("CannotUploadReason", args); -			break; -		case 500: -		default: -			args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); -			args["REASON"] = "The server is experiencing unexpected " -				"difficulties."; -			LLNotificationsUtil::add("CannotUploadReason", args); -			break; +		args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); +		args["REASON"] = "Error in upload request.  Please visit " +			"http://secondlife.com/support for help fixing this problem."; +		LLNotificationsUtil::add("CannotUploadReason", args); +	} +	else +	{ +		args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); +		args["REASON"] = "The server is experiencing unexpected " +			"difficulties."; +		LLNotificationsUtil::add("CannotUploadReason", args);  	}  	LLUploadDialog::modalUploadFinished();  	LLFilePicker::instance().reset();  // unlock file picker when bulk upload fails  }  //virtual  -void LLAssetUploadResponder::result(const LLSD& content) +void LLAssetUploadResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl; -	std::string state = content["state"]; +	const std::string& state = content["state"].asStringRef();  	if (state == "upload")  	{ @@ -280,7 +284,7 @@ void LLAssetUploadResponder::result(const LLSD& content)  void LLAssetUploadResponder::uploadUpload(const LLSD& content)  { -	std::string uploader = content["uploader"]; +	const std::string& uploader = content["uploader"].asStringRef();  	if (mFileName.empty())  	{  		LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this); @@ -293,6 +297,7 @@ void LLAssetUploadResponder::uploadUpload(const LLSD& content)  void LLAssetUploadResponder::uploadFailure(const LLSD& content)  { +	llwarns << dumpResponse() << llendl;  	// remove the "Uploading..." message  	LLUploadDialog::modalUploadFinished();  	LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); @@ -301,7 +306,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content)  		floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory")));  	} -	std::string reason = content["state"]; +	const std::string& reason = content["state"].asStringRef();  	// deal with L$ errors  	if (reason == "insufficient funds")  	{ @@ -340,9 +345,9 @@ LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(  }  // virtual -void LLNewAgentInventoryResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLNewAgentInventoryResponder::httpFailure()  { -	LLAssetUploadResponder::errorWithContent(statusNum, reason, content); +	LLAssetUploadResponder::httpFailure();  	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE);  } @@ -487,10 +492,9 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content)  	}  } -void LLSendTexLayerResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLSendTexLayerResponder::httpFailure()  { -	llinfos << "LLSendTexLayerResponder error [status:" -			<< statusNum << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  	// Invoke the original callback with an error result  	LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); @@ -1009,19 +1013,14 @@ LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResp  	delete mImpl;  } -void LLNewAgentInventoryVariablePriceResponder::errorWithContent( -	U32 statusNum, -	const std::string& reason, -	const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpFailure()  { -	lldebugs  -		<< "LLNewAgentInventoryVariablePrice::error " << statusNum  -		<< " reason: " << reason << llendl; +	const LLSD& content = getContent(); +	LL_WARNS("Upload") << dumpResponse() << LL_ENDL; -	if ( content.has("error") ) +	static const std::string _ERROR = "error"; +	if ( content.has(_ERROR) )  	{ -		static const std::string _ERROR = "error"; -  		mImpl->onTransportError(content[_ERROR]);  	}  	else @@ -1030,8 +1029,14 @@ void LLNewAgentInventoryVariablePriceResponder::errorWithContent(  	}  } -void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	// Parse out application level errors and the appropriate  	// responses for them  	static const std::string _ERROR = "error"; @@ -1047,6 +1052,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)  	// Check for application level errors  	if ( content.has(_ERROR) )  	{ +		LL_WARNS("Upload") << dumpResponse() << LL_ENDL;  		onApplicationLevelError(content[_ERROR]);  		return;  	} @@ -1090,6 +1096,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)  	}  	else  	{ +		LL_WARNS("Upload") << dumpResponse() << LL_ENDL;  		onApplicationLevelError("");  	}  } diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index a6d1016136..abfdc4ca77 100755 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -33,6 +33,8 @@  // via capabilities  class LLAssetUploadResponder : public LLHTTPClient::Responder  { +protected: +	LOG_CLASS(LLAssetUploadResponder);  public:  	LLAssetUploadResponder(const LLSD& post_data,  							const LLUUID& vfile_id, @@ -42,8 +44,11 @@ public:  							LLAssetType::EType asset_type);  	~LLAssetUploadResponder(); -    virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); -	virtual void result(const LLSD& content); +protected: +	virtual void httpFailure(); +	virtual void httpSuccess(); + +public:  	virtual void uploadUpload(const LLSD& content);  	virtual void uploadComplete(const LLSD& content);  	virtual void uploadFailure(const LLSD& content); @@ -58,6 +63,7 @@ protected:  // TODO*: Remove this once deprecated  class LLNewAgentInventoryResponder : public LLAssetUploadResponder  { +	LOG_CLASS(LLNewAgentInventoryResponder);  public:  	LLNewAgentInventoryResponder(  		const LLSD& post_data, @@ -67,9 +73,10 @@ public:  		const LLSD& post_data,  		const std::string& file_name,  		LLAssetType::EType asset_type); -    virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content);  	virtual void uploadComplete(const LLSD& content);  	virtual void uploadFailure(const LLSD& content); +protected: +	virtual void httpFailure();  };  // A base class which goes through and performs some default @@ -79,6 +86,7 @@ public:  class LLNewAgentInventoryVariablePriceResponder :  	public LLHTTPClient::Responder  { +	LOG_CLASS(LLNewAgentInventoryVariablePriceResponder);  public:  	LLNewAgentInventoryVariablePriceResponder(  		const LLUUID& vfile_id, @@ -91,12 +99,11 @@ public:  		const LLSD& inventory_info);  	virtual ~LLNewAgentInventoryVariablePriceResponder(); -	void errorWithContent( -		U32 statusNum, -		const std::string& reason, -		const LLSD& content); -	void result(const LLSD& content); +private: +	/* virtual */ void httpFailure(); +	/* virtual */ void httpSuccess(); +public:  	virtual void onApplicationLevelError(  		const LLSD& error);  	virtual void showConfirmationDialog( @@ -122,8 +129,11 @@ public:  	~LLSendTexLayerResponder();  	virtual void uploadComplete(const LLSD& content); -	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); +protected: +	virtual void httpFailure(); + +private:  	LLBakedUploadData * mBakedUploadData;  }; diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp index e3cd83e174..923662e887 100755 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ b/indra/newview/llclassifiedstatsresponder.cpp @@ -44,8 +44,14 @@ mClassifiedID(classified_id)  }  /*virtual*/ -void LLClassifiedStatsResponder::result(const LLSD& content) +void LLClassifiedStatsResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	S32 teleport = content["teleport_clicks"].asInteger();  	S32 map = content["map_clicks"].asInteger();  	S32 profile = content["profile_clicks"].asInteger(); @@ -62,7 +68,8 @@ void LLClassifiedStatsResponder::result(const LLSD& content)  }  /*virtual*/ -void LLClassifiedStatsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLClassifiedStatsResponder::httpFailure()  { -	llinfos << "LLClassifiedStatsResponder::error [status:" << status << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  } + diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h index 06dcb62fd0..efa4d82411 100755 --- a/indra/newview/llclassifiedstatsresponder.h +++ b/indra/newview/llclassifiedstatsresponder.h @@ -33,13 +33,15 @@  class LLClassifiedStatsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLClassifiedStatsResponder);  public:  	LLClassifiedStatsResponder(LLUUID classified_id); + +protected:  	//If we get back a normal response, handle it here -	virtual void result(const LLSD& content); +	virtual void httpSuccess();  	//If we get back an error (not found, etc...), handle it here -	 -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +	virtual void httpFailure();  protected:  	LLUUID mClassifiedID; diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 2669b0340f..db2c15a444 100755 --- a/indra/newview/llestateinfomodel.cpp +++ b/indra/newview/llestateinfomodel.cpp @@ -112,19 +112,19 @@ void LLEstateInfoModel::notifyCommit()  class LLEstateChangeInfoResponder : public LLHTTPClient::Responder  { -public: - +	LOG_CLASS(LLEstateChangeInfoResponder); +protected:  	// if we get a normal response, handle it here -	virtual void result(const LLSD& content) +	virtual void httpSuccesss()  	{  		llinfos << "Committed estate info" << llendl;  		LLEstateInfoModel::instance().notifyCommit();  	}  	// if we get an error response -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	virtual void httpFailure()  	{ -		llwarns << "Failed to commit estate info [status:" << status << "]: " << content << llendl; +		llwarns << "Failed to commit estate info " << dumpResponse() << llendl;  	}  }; diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index c1630318e8..c3b53d5e4a 100755 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -31,7 +31,7 @@  #include "llagent.h"  #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llsdserialize.h"  #include "lleventtimer.h"  #include "llviewerregion.h" @@ -49,6 +49,7 @@ namespace  	class LLEventPollResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(LLEventPollResponder);  	public:  		static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender); @@ -56,19 +57,19 @@ namespace  		void makeRequest(); +		/* virtual */ void completedRaw(const LLChannelDescriptors& channels, +								  const LLIOPipe::buffer_ptr_t& buffer); +  	private:  		LLEventPollResponder(const std::string&	pollURL, const LLHost& sender);  		~LLEventPollResponder();  		void handleMessage(const LLSD& content); -		virtual	void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -		virtual	void result(const LLSD&	content); -		virtual void completedRaw(U32 status, -									const std::string& reason, -									const LLChannelDescriptors& channels, -									const LLIOPipe::buffer_ptr_t& buffer); +		/* virtual */ void httpFailure(); +		/* virtual */ void httpSuccess(); +  	private:  		bool	mDone; @@ -149,20 +150,18 @@ namespace  	}  	// virtual  -	void LLEventPollResponder::completedRaw(U32 status, -									const std::string& reason, -									const LLChannelDescriptors& channels, -									const LLIOPipe::buffer_ptr_t& buffer) +	void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels, +											const LLIOPipe::buffer_ptr_t& buffer)  	{ -		if (status == HTTP_BAD_GATEWAY) +		if (getStatus() == HTTP_BAD_GATEWAY)  		{  			// These errors are not parsable as LLSD,   			// which LLHTTPClient::Responder::completedRaw will try to do. -			completed(status, reason, LLSD()); +			httpCompleted();  		}  		else  		{ -			LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer); +			LLHTTPClient::Responder::completedRaw(channels,buffer);  		}  	} @@ -187,13 +186,13 @@ namespace  	}  	//virtual -	void LLEventPollResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	void LLEventPollResponder::httpFailure()  	{  		if (mDone) return;  		// A HTTP_BAD_GATEWAY (502) error is our standard timeout response  		// we get this when there are no events. -		if ( status == HTTP_BAD_GATEWAY )	 +		if ( getStatus() == HTTP_BAD_GATEWAY )  		{  			mErrorCount = 0;  			makeRequest(); @@ -207,13 +206,13 @@ namespace  										+ mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC  									, this); -			llwarns << "LLEventPollResponder error [status:" << status << "]: " << content << llendl; +			llwarns << dumpResponse() << llendl;  		}  		else  		{ -			llwarns << "LLEventPollResponder error <" << mCount  -					<< "> [status:" << status << "]: " << content -					<<	(mDone ? " -- done"	: "") << llendl; +			llwarns << dumpResponse() +					<< " [count:" << mCount << "] " +					<< (mDone ? " -- done" : "") << llendl;  			stop();  			// At this point we have given up and the viewer will not receive HTTP messages from the simulator. @@ -234,7 +233,7 @@ namespace  	}  	//virtual -	void LLEventPollResponder::result(const LLSD& content) +	void LLEventPollResponder::httpSuccess()  	{  		lldebugs <<	"LLEventPollResponder::result <" << mCount	<< ">"  				 <<	(mDone ? " -- done"	: "") << llendl; @@ -243,10 +242,12 @@ namespace  		mErrorCount = 0; -		if (!content.get("events") || +		const LLSD& content = getContent(); +		if (!content.isMap() || +			!content.get("events") ||  			!content.get("id"))  		{ -			llwarns << "received event poll with no events or id key" << llendl; +			llwarns << "received event poll with no events or id key: " << dumpResponse() << llendl;  			makeRequest();  			return;  		} diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 9d292ce7bb..e311e09c8b 100755 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -40,6 +40,7 @@  #include "llsecondlifeurls.h"  #include "llappviewer.h" +#include "llbufferstream.h"  #include "llhttpclient.h"  #include "llnotificationsutil.h"  #include "llviewercontrol.h" @@ -561,6 +562,7 @@ void LLFeatureManager::parseGPUTable(std::string filename)  // responder saves table into file  class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLHTTPFeatureTableResponder);  public:  	LLHTTPFeatureTableResponder(std::string filename) : @@ -569,11 +571,10 @@ public:  	} -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, +	virtual void completedRaw(const LLChannelDescriptors& channels,  							  const LLIOPipe::buffer_ptr_t& buffer)  	{ -		if (isGoodStatus(status)) +		if (isGoodStatus())  		{  			// write to file @@ -592,7 +593,18 @@ public:  				out.close();  			}  		} -		 +		else +		{ +			char body[1025];  +			body[1024] = '\0'; +			LLBufferStream istr(channels, buffer.get()); +			istr.get(body,1024); +			if (strlen(body) > 0) +			{ +				mContent["body"] = body; +			} +			llwarns << dumpResponse() << llendl; +		}  	}  private: diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index d13f85baa2..89d74666f7 100755 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1240,9 +1240,9 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)  {  	GtkFileFilter *gfilter = gtk_file_filter_new();  	gtk_file_filter_add_pattern(gfilter, "*.tga"); -	gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); -	gtk_file_filter_add_mime_type(gfilter, "image/png"); -	gtk_file_filter_add_mime_type(gfilter, "image/bmp"); +	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); +	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); +	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str());  	std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)";  	add_common_filters_to_gtkchooser(gfilter, picker, filtername);  	return filtername; @@ -1250,13 +1250,13 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)  static std::string add_script_filter_to_gtkchooser(GtkWindow *picker)  { -	return add_simple_mime_filter_to_gtkchooser(picker,  "text/plain", +	return add_simple_mime_filter_to_gtkchooser(picker,  HTTP_CONTENT_TEXT_PLAIN,  							LLTrans::getString("script_files") + " (*.lsl)");  }  static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker)  { -	return add_simple_mime_filter_to_gtkchooser(picker,  "text/plain", +	return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN,  							LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)");  } @@ -1294,7 +1294,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename  			break;  		case FFSAVE_BMP:  			caption += add_simple_mime_filter_to_gtkchooser -				(picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)"); +				(picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)");  			suggest_ext = ".bmp";  			break;  		case FFSAVE_AVI: @@ -1319,6 +1319,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename  			suggest_ext = ".raw";  			break;  		case FFSAVE_J2C: +			// *TODO: Should this be 'image/j2c' ?  			caption += add_simple_mime_filter_to_gtkchooser  				(picker, "images/jp2",  				 LLTrans::getString("compressed_image_files") + " (*.j2c)"); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index fea8e34729..29300ba90c 100755 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -79,14 +79,9 @@ class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder  {  	LOG_CLASS(LLServerReleaseNotesURLFetcher);  public: -  	static void startFetch(); -	/*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content); -	/*virtual*/ void completedRaw( -		U32 status, -		const std::string& reason, -		const LLChannelDescriptors& channels, -		const LLIOPipe::buffer_ptr_t& buffer); +private: +	/* virtual */ void httpCompleted();  };  ///---------------------------------------------------------------------------- @@ -477,32 +472,26 @@ void LLServerReleaseNotesURLFetcher::startFetch()  }  // virtual -void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::string& reason, const LLSD& content) +void LLServerReleaseNotesURLFetcher::httpCompleted()  { -	lldebugs << "Status: " << status << llendl; -	lldebugs << "Reason: " << reason << llendl; -	lldebugs << "Headers: " << content << llendl; +	LL_DEBUGS("ServerReleaseNotes") << dumpResponse()  +		<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL;  	LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about");  	if (floater_about)  	{ -		std::string location = content["location"].asString(); +		const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);  		if (location.empty())  		{ -			location = floater_about->getString("ErrorFetchingServerReleaseNotesURL"); +			LL_WARNS("ServerReleaseNotes") << "Missing Location header " +				<< dumpResponse() << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; +			floater_about->updateServerReleaseNotesURL( +						floater_about->getString("ErrorFetchingServerReleaseNotesURL")); +		} +		else +		{ +			floater_about->updateServerReleaseNotesURL(location);  		} -		floater_about->updateServerReleaseNotesURL(location);  	}  } -// virtual -void LLServerReleaseNotesURLFetcher::completedRaw( -	U32 status, -	const std::string& reason, -	const LLChannelDescriptors& channels, -	const LLIOPipe::buffer_ptr_t& buffer) -{ -	// Do nothing. -	// We're overriding just because the base implementation tries to -	// deserialize LLSD which triggers warnings. -} diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index c0afb72cff..c6003dcc17 100755 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -458,13 +458,15 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const  class LLAvatarPickerResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLAvatarPickerResponder);  public:  	LLUUID mQueryID;      std::string mName;  	LLAvatarPickerResponder(const LLUUID& id, const std::string& name) : mQueryID(id), mName(name) { } -	/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) +protected: +	/*virtual*/ void httpCompleted()  	{  		//std::ostringstream ss;  		//LLSDSerialize::toPrettyXML(content, ss); @@ -472,19 +474,18 @@ public:  		// in case of invalid characters, the avatar picker returns a 400  		// just set it to process so it displays 'not found' -		if (isGoodStatus(status) || status == 400) +		if (isGoodStatus() || getStatus() == HTTP_BAD_REQUEST)  		{  			LLFloaterAvatarPicker* floater =  				LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", mName);  			if (floater)  			{ -				floater->processResponse(mQueryID, content); +				floater->processResponse(mQueryID, getContent());  			}  		}  		else  		{ -			llwarns << "avatar picker failed [status:" << status << "]: " << content << llendl; -			 +			llwarns << "avatar picker failed " << dumpResponse() << llendl;  		}  	}  }; diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp index 013cf74c7b..6e641e7d40 100755 --- a/indra/newview/llfloaterbuycurrencyhtml.cpp +++ b/indra/newview/llfloaterbuycurrencyhtml.cpp @@ -27,6 +27,7 @@  #include "llviewerprecompiledheaders.h"  #include "llfloaterbuycurrencyhtml.h" +#include "llhttpconstants.h"  #include "llstatusbar.h"  //////////////////////////////////////////////////////////////////////////////// @@ -85,7 +86,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL()  	llinfos << "Buy currency HTML parsed URL is " << buy_currency_url << llendl;  	// kick off the navigation -	mBrowser->navigateTo( buy_currency_url, "text/html" ); +	mBrowser->navigateTo( buy_currency_url, HTTP_CONTENT_TEXT_HTML );  }  //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 56051ff684..af5c11e12c 100755 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -617,9 +617,10 @@ void LLFloaterGesture::addToCurrentOutFit()  	uuid_vec_t ids;  	getSelectedIds(ids);  	LLAppearanceMgr* am = LLAppearanceMgr::getInstance(); +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;  	for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)  	{ -		am->addCOFItemLink(*it); +		am->addCOFItemLink(*it, cb);  	}  } diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index 4cb632bd6a..c0bb213540 100755 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -29,6 +29,7 @@  #include "llfloaterhelpbrowser.h"  #include "llfloaterreg.h" +#include "llhttpconstants.h"  #include "llpluginclassmedia.h"  #include "llmediactrl.h"  #include "llviewerwindow.h" @@ -37,7 +38,6 @@  #include "llui.h"  #include "llurlhistory.h" -#include "llmediactrl.h"  #include "llviewermedia.h"  #include "llviewerhelp.h" @@ -148,7 +148,7 @@ void LLFloaterHelpBrowser::openMedia(const std::string& media_url)  {  	// explicitly make the media mime type for this floater since it will  	// only ever display one type of content (Web). -	mBrowser->setHomePageUrl(media_url, "text/html"); -	mBrowser->navigateTo(media_url, "text/html"); +	mBrowser->setHomePageUrl(media_url, HTTP_CONTENT_TEXT_HTML); +	mBrowser->navigateTo(media_url, HTTP_CONTENT_TEXT_HTML);  	setCurrentURL(media_url);  } diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index 5cb9df5625..bfad4a73f2 100755 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -1145,16 +1145,17 @@ BOOL LLFloaterIMSession::isInviteAllowed() const  class LLSessionInviteResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLSessionInviteResponder);  public:  	LLSessionInviteResponder(const LLUUID& session_id)  	{  		mSessionID = session_id;  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: +	void httpFailure()  	{ -		llwarns << "Error inviting all agents to session [status:"  -				<< statusNum << "]: " << content << llendl; +		llwarns << "Error inviting all agents to session " << dumpResponse() << llendl;  		//throw something back to the viewer here?  	} diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 100f1d580b..5830156fdd 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -5839,7 +5839,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()  	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());  } -void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) +void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason)  {  	llwarns << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << llendl;  	doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); @@ -5915,7 +5915,7 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)  	getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);  } -void LLFloaterModelPreview::setPermissonsErrorStatus(U32 status, const std::string& reason) +void LLFloaterModelPreview::setPermissonsErrorStatus(S32 status, const std::string& reason)  {  	llwarns << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << llendl; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index e588418f7b..6c0c60b87f 100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -200,11 +200,11 @@ public:  	/*virtual*/ void onPermissionsReceived(const LLSD& result);  	// called when error occurs during permissions request -	/*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setPermissonsErrorStatus(S32 status, const std::string& reason);  	/*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url);  				void handleModelPhysicsFeeReceived(); -	/*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason);  	/*virtual*/ void onModelUploadSuccess(); diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 6d3800bfa4..9f1fc06e14 100755 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -45,7 +45,7 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions()  	if (!url.empty())  	{  		llinfos<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <<llendl; -		LLHTTPClient::get(url, new LLUploadModelPremissionsResponder(getPermObserverHandle())); +		LLHTTPClient::get(url, new LLUploadModelPermissionsResponder(getPermObserverHandle()));  	}  	else  	{ diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index a52bc28687..d9a8879687 100755 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -37,13 +37,13 @@ public:  	virtual ~LLFloaterModelUploadBase(){}; -	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0;  	virtual void onPermissionsReceived(const LLSD& result) = 0;  	virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; -	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0;  	virtual void onModelUploadSuccess() {}; diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp index 0862cd2897..c11a0568a6 100755 --- a/indra/newview/llfloaterobjectweights.cpp +++ b/indra/newview/llfloaterobjectweights.cpp @@ -123,7 +123,7 @@ void LLFloaterObjectWeights::onWeightsUpdate(const SelectionCost& selection_cost  }  //virtual -void LLFloaterObjectWeights::setErrorStatus(U32 status, const std::string& reason) +void LLFloaterObjectWeights::setErrorStatus(S32 status, const std::string& reason)  {  	const std::string text = getString("nothing_selected"); diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h index 9a244573be..1a2c317bad 100755 --- a/indra/newview/llfloaterobjectweights.h +++ b/indra/newview/llfloaterobjectweights.h @@ -63,7 +63,7 @@ public:  	/*virtual*/ void onOpen(const LLSD& key);  	/*virtual*/ void onWeightsUpdate(const SelectionCost& selection_cost); -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);  	void updateLandImpacts(const LLParcel* parcel);  	void refresh(); diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 4bfef8b45f..9986bdbd7f 100755 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -162,21 +162,17 @@ void LLFloaterOpenObject::moveToInventory(bool wear)  	{  		parent_category_id = gInventory.getRootFolderID();  	} -	 -	LLCategoryCreate* cat_data = new LLCategoryCreate(object_id, wear); -	 + +	inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear);  	LLUUID category_id = gInventory.createNewCategory(parent_category_id,   													  LLFolderType::FT_NONE,   													  name, -													  callbackCreateInventoryCategory, -													  (void*)cat_data); +													  func);  	//If we get a null category ID, we are using a capability in createNewCategory and we will  	//handle the following in the callbackCreateInventoryCategory routine.  	if ( category_id.notNull() )  	{ -		delete cat_data; -		  		LLCatAndWear* data = new LLCatAndWear;  		data->mCatID = category_id;  		data->mWear = wear; @@ -198,20 +194,17 @@ void LLFloaterOpenObject::moveToInventory(bool wear)  }  // static -void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, void* data) +void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear)  { -	LLCategoryCreate* cat_data = (LLCategoryCreate*)data; -	 -	LLUUID category_id = result["folder_id"].asUUID();  	LLCatAndWear* wear_data = new LLCatAndWear;  	wear_data->mCatID = category_id; -	wear_data->mWear = cat_data->mWear; +	wear_data->mWear = wear;  	wear_data->mFolderResponded = true;  	// Copy and/or move the items into the newly created folder.  	// Ignore any "you're going to break this item" messages. -	BOOL success = move_inv_category_world_to_agent(cat_data->mObjectID, category_id, TRUE, +	BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,  													callbackMoveInventory,   													(void*)wear_data);  	if (!success) @@ -221,7 +214,6 @@ void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, vo  		LLNotificationsUtil::add("OpenObjectCannotCopy");  	} -	delete cat_data;	  }  // static diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index bf7fe69c65..8e472804a4 100755 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -45,15 +45,6 @@ public:  	void dirty(); -	class LLCategoryCreate -	{ -		public: -			LLCategoryCreate(LLUUID object_id, bool wear) : mObjectID(object_id), mWear(wear) {} -		public: -			LLUUID mObjectID; -			bool mWear; -	}; -	  	struct LLCatAndWear  	{  		LLUUID mCatID; @@ -72,7 +63,7 @@ protected:  	void onClickMoveToInventory();  	void onClickMoveAndWear(); -	static void callbackCreateInventoryCategory(const LLSD& result, void* data); +	static void callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear);  	static void callbackMoveInventory(S32 result, void* data);  private: diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index 3a7ca17b73..efc04ac358 100755 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -73,24 +73,29 @@ namespace  	// called if this request times out.  	class AsyncConsoleResponder : public LLHTTPClient::Responder  	{ -	public: +		LOG_CLASS(AsyncConsoleResponder); +	protected:  		/* virtual */ -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +		void httpFailure()  		{ +			LL_WARNS("Console") << dumpResponse() << LL_ENDL;  			sConsoleReplySignal(UNABLE_TO_SEND_COMMAND);  		}  	};  	class ConsoleResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(ConsoleResponder);  	public:  		ConsoleResponder(LLTextEditor *output) : mOutput(output)  		{  		} +	protected:  		/*virtual*/ -		void error(U32 status, const std::string& reason) +		void httpFailure()  		{ +			LL_WARNS("Console") << dumpResponse() << LL_ENDL;  			if (mOutput)  			{  				mOutput->appendText( @@ -100,8 +105,10 @@ namespace  		}  		/*virtual*/ -		void result(const LLSD& content) +		void httpSuccess()  		{ +			const LLSD& content = getContent(); +			LL_DEBUGS("Console") << content << LL_ENDL;  			if (mOutput)  			{  				mOutput->appendText( @@ -109,6 +116,7 @@ namespace  			}  		} +	public:  		LLTextEditor * mOutput;  	}; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 50c013a49d..ddfae005bb 100755 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -756,12 +756,12 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L  class ConsoleRequestResponder : public LLHTTPClient::Responder  { -public: +	LOG_CLASS(ConsoleRequestResponder); +protected:  	/*virtual*/ -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	void httpFailure()  	{ -		llwarns << "ConsoleRequestResponder error requesting mesh_rez_enabled [status:" -				<< status << "]: " << content << llendl; +		llwarns << "error requesting mesh_rez_enabled " << dumpResponse() << llendl;  	}  }; @@ -769,12 +769,12 @@ public:  // called if this request times out.  class ConsoleUpdateResponder : public LLHTTPClient::Responder  { -public: +	LOG_CLASS(ConsoleUpdateResponder); +protected:  	/* virtual */ -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	void httpFailure()  	{ -		llwarns << "ConsoleRequestResponder error updating mesh enabled region setting [status:" -				<< status << "]: " << content << llendl; +		llwarns << "error updating mesh enabled region setting " << dumpResponse() << llendl;  	}  }; @@ -2233,14 +2233,16 @@ void LLPanelEstateInfo::getEstateOwner()  class LLEstateChangeInfoResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLEstateChangeInfoResponder);  public:  	LLEstateChangeInfoResponder(LLPanelEstateInfo* panel)  	{  		mpPanel = panel->getHandle();  	} +protected:  	// if we get a normal response, handle it here -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{  		LL_INFOS("Windlight") << "Successfully committed estate info" << llendl; @@ -2251,10 +2253,9 @@ public:  	}  	// if we get an error response -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	virtual void httpFailure()  	{ -		llinfos << "LLEstateChangeInfoResponder::error [status:" -			<< status << "]: " << content << llendl; +		LL_WARNS("Windlight") << dumpResponse() << LL_ENDL;  	}  private:  	LLHandle<LLPanel> mpPanel; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 35b63c5480..cc4199a758 100755 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -707,16 +707,18 @@ public:  class LLUserReportResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLUserReportResponder);  public:  	LLUserReportResponder(): LLHTTPClient::Responder()  {} -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -	{ -		// *TODO do some user messaging here -		LLUploadDialog::modalUploadFinished(); -	} -	void result(const LLSD& content) +private: +	void httpCompleted()  	{ +		if (!isGoodStatus()) +		{ +			// *TODO do some user messaging here +			LL_WARNS("UserReport") << dumpResponse() << LL_ENDL; +		}  		// we don't care about what the server returns  		LLUploadDialog::modalUploadFinished();  	} diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 13cb3c2eb0..11a0d3ebe4 100755 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -183,8 +183,14 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr)  // Responders  ///---------------------------------------------------------------------------- -void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	//we don't need to test with a fake respose here (shouldn't anyway)  #ifdef DUMP_REPLIES_TO_LLINFOS @@ -221,13 +227,14 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content)  	}  } -void fetchScriptLimitsRegionInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpFailure()  { -	llwarns << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  } -void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionSummaryResponder::httpSuccess()  { +	const LLSD& content_ref = getContent();  #ifdef USE_FAKE_RESPONSES  	LLSD fake_content; @@ -268,6 +275,12 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)  #endif +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +  #ifdef DUMP_REPLIES_TO_LLINFOS @@ -291,7 +304,7 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)  		LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");  		if(tab)  		{ -		LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); +			LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");  			if(panel_memory)  			{  				panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); @@ -301,20 +314,21 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)  				{  					btn->setEnabled(true);  				} -				 -		panel_memory->setRegionSummary(content); -	} -} + +				panel_memory->setRegionSummary(content); +			} +		}  	}  } -void fetchScriptLimitsRegionSummaryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionSummaryResponder::httpFailure()  { -	llwarns << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  } -void fetchScriptLimitsRegionDetailsResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionDetailsResponder::httpSuccess()  { +	const LLSD& content_ref = getContent();  #ifdef USE_FAKE_RESPONSES  /*  Updated detail service, ** denotes field added: @@ -377,6 +391,12 @@ result (map)  #endif +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +  #ifdef DUMP_REPLIES_TO_LLINFOS  	LLSDNotationStreamer notation_streamer(content); @@ -417,13 +437,14 @@ result (map)  	}  } -void fetchScriptLimitsRegionDetailsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionDetailsResponder::httpFailure()  { -	llwarns << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  } -void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) +void fetchScriptLimitsAttachmentInfoResponder::httpSuccess()  { +	const LLSD& content_ref = getContent();  #ifdef USE_FAKE_RESPONSES @@ -465,6 +486,12 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)  #endif +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +  #ifdef DUMP_REPLIES_TO_LLINFOS  	LLSDNotationStreamer notation_streamer(content); @@ -513,9 +540,9 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)  	}  } -void fetchScriptLimitsAttachmentInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsAttachmentInfoResponder::httpFailure()  { -	llwarns << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  }  ///---------------------------------------------------------------------------- @@ -586,7 +613,7 @@ void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id)  }  // virtual -void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::string& reason) +void LLPanelScriptLimitsRegionMemory::setErrorStatus(S32 status, const std::string& reason)  {  	llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;  } diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index f8732ef94b..a5cb1b6184 100755 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -85,49 +85,49 @@ protected:  class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder  { -	public: -		fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; - -		void result(const LLSD& content); -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	public: -	protected: -		LLSD mInfo; +	LOG_CLASS(fetchScriptLimitsRegionInfoResponder); +public: +	fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; + +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +	LLSD mInfo;  };  class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder  { -	public: -		fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; - -		void result(const LLSD& content); -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	public: -	protected: -		LLSD mInfo; +	LOG_CLASS(fetchScriptLimitsRegionSummaryResponder); +public: +	fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; + +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +	LLSD mInfo;  };  class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder  { -	public: -		fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; - -		void result(const LLSD& content); -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	public: -	protected: -		LLSD mInfo; +	LOG_CLASS(fetchScriptLimitsRegionDetailsResponder); +public: +	fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; + +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +	LLSD mInfo;  };  class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder  { -	public: -		fetchScriptLimitsAttachmentInfoResponder() {}; +	LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder); +public: +	fetchScriptLimitsAttachmentInfoResponder() {}; -		void result(const LLSD& content); -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	public: -	protected: +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure();  };  ///////////////////////////////////////////////////////////////////////////// @@ -190,7 +190,7 @@ protected:  // LLRemoteParcelInfoObserver interface:  /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);  /*virtual*/ void setParcelID(const LLUUID& parcel_id); -/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);  	static void onClickRefresh(void* userdata);  	static void onClickHighlight(void* userdata); diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 2a946b1edf..a446b767ac 100755 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -30,6 +30,7 @@  #include "llcommandhandler.h"  #include "llfloaterreg.h"  #include "llfloatersearch.h" +#include "llhttpconstants.h"  #include "llmediactrl.h"  #include "llnotificationsutil.h"  #include "lllogininstance.h" @@ -200,5 +201,5 @@ void LLFloaterSearch::search(const SearchQuery &p)  	url = LLWeb::expandURLSubstitutions(url, subs);  	// and load the URL in the web view -	mWebBrowser->navigateTo(url, "text/html"); +	mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);  } diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index a242b224cd..0613ffc94d 100755 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -36,7 +36,7 @@  #include "llbutton.h"  #include "llevents.h"  #include "llhttpclient.h" -#include "llhttpstatuscodes.h"	// for HTTP_FOUND +#include "llhttpconstants.h"  #include "llnotificationsutil.h"  #include "llradiogroup.h"  #include "lltextbox.h" @@ -62,42 +62,46 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data)  // on parent class indicating if the web server is working or not  class LLIamHere : public LLHTTPClient::Responder  { -	private: -		LLIamHere( LLFloaterTOS* parent ) : -		   mParent( parent ) -		{} +	LOG_CLASS(LLIamHere); +private: +	LLIamHere( LLFloaterTOS* parent ) : +	   mParent( parent ) +	{} -		LLFloaterTOS* mParent; +	LLFloaterTOS* mParent; -	public: - -		static LLIamHere* build( LLFloaterTOS* parent ) -		{ -			return new LLIamHere( parent ); -		}; -		 -		virtual void  setParent( LLFloaterTOS* parentIn ) -		{ -			mParent = parentIn; -		}; -		 -		virtual void result( const LLSD& content ) +public: +	static LLIamHere* build( LLFloaterTOS* parent ) +	{ +		return new LLIamHere( parent ); +	} +	 +	virtual void  setParent( LLFloaterTOS* parentIn ) +	{ +		mParent = parentIn; +	} +	 +protected: +	virtual void httpSuccess() +	{ +		if ( mParent )  		{ -			if ( mParent ) -				mParent->setSiteIsAlive( true ); -		}; +			mParent->setSiteIsAlive( true ); +		} +	} -		virtual void error( U32 status, const std::string& reason ) +	virtual void httpFailure() +	{ +		LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL; +		if ( mParent )  		{ -			if ( mParent ) -			{ -				// *HACK: For purposes of this alive check, 302 Found -				// (aka Moved Temporarily) is considered alive.  The web site -				// redirects this link to a "cache busting" temporary URL. JC -				bool alive = (status == HTTP_FOUND); -				mParent->setSiteIsAlive( alive ); -			} -		}; +			// *HACK: For purposes of this alive check, 302 Found +			// (aka Moved Temporarily) is considered alive.  The web site +			// redirects this link to a "cache busting" temporary URL. JC +			bool alive = (getStatus() == HTTP_FOUND); +			mParent->setSiteIsAlive( alive ); +		} +	}  };  // this is global and not a class member to keep crud out of the header file diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index e85d849c9a..e26f1e9ea5 100755 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -48,31 +48,30 @@ static LLFloaterURLEntry* sInstance = NULL;  // on the Panel Land Media and to discover the MIME type  class LLMediaTypeResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLMediaTypeResponder);  public:  	LLMediaTypeResponder( const LLHandle<LLFloater> parent ) : -	  mParent( parent ) -	  {} - -	  LLHandle<LLFloater> mParent; - - -	  virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) -	  { -		  std::string media_type = content["content-type"].asString(); -		  std::string::size_type idx1 = media_type.find_first_of(";"); -		  std::string mime_type = media_type.substr(0, idx1); -		  completeAny(status, mime_type); -	  } - -	  void completeAny(U32 status, const std::string& mime_type) -	  { -		  // Set empty type to none/none.  Empty string is reserved for legacy parcels -		  // which have no mime type set. -		  std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); -		  LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); -		  if ( floater_url_entry ) -			  floater_url_entry->headerFetchComplete( status, resolved_mime_type ); -	  } +		mParent( parent ) +	{} + +	LLHandle<LLFloater> mParent; + +private: +	/* virtual */ void httpCompleted() +	{ +		const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); +		std::string::size_type idx1 = media_type.find_first_of(";"); +		std::string mime_type = media_type.substr(0, idx1); + +		// Set empty type to none/none.  Empty string is reserved for legacy parcels +		// which have no mime type set. +		std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); +		LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); +		if ( floater_url_entry ) +		{ +			floater_url_entry->headerFetchComplete( getStatus(), resolved_mime_type ); +		} +	}  };  //----------------------------------------------------------------------------- @@ -136,7 +135,7 @@ void LLFloaterURLEntry::buildURLHistory()  	}  } -void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type) +void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_type)  {  	LLPanelLandMedia* panel_media = dynamic_cast<LLPanelLandMedia*>(mPanelLandMediaHandle.get());  	if (panel_media) diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index dfb49fe5ac..bdd1ebe592 100755 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -40,7 +40,7 @@ public:  	// that panel via the handle.  	static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url);  	/*virtual*/	BOOL	postBuild(); -	void headerFetchComplete(U32 status, const std::string& mime_type); +	void headerFetchComplete(S32 status, const std::string& mime_type);  	bool addURLToCombobox(const std::string& media_url); diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 3fe2518de6..21b171446f 100755 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -29,6 +29,7 @@  #include "llcombobox.h"  #include "lliconctrl.h"  #include "llfloaterreg.h" +#include "llhttpconstants.h"  #include "lllayoutstack.h"  #include "llpluginclassmedia.h"  #include "llprogressbar.h" @@ -234,9 +235,9 @@ void LLFloaterWebContent::open_media(const Params& p)  {  	// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.  	LLViewerMedia::proxyWindowOpened(p.target(), p.id()); -	mWebBrowser->setHomePageUrl(p.url, "text/html"); +	mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML);  	mWebBrowser->setTarget(p.target); -	mWebBrowser->navigateTo(p.url, "text/html"); +	mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML);  	set_current_url(p.url); @@ -451,7 +452,7 @@ void LLFloaterWebContent::onEnterAddress()  	std::string url = mAddressCombo->getValue().asString();  	if ( url.length() > 0 )  	{ -		mWebBrowser->navigateTo( url, "text/html"); +		mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);  	};  } diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index 16ed3f990c..a6be604222 100755 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -86,7 +86,7 @@ const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollect  	if (cats_count > 1)  	{ -		LL_WARNS("LLFriendCardsManager") +		LL_WARNS_ONCE("LLFriendCardsManager")  			<< "There is more than one Friend card folder."  			<< "The first folder will be used."  			<< LL_ENDL; diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index b56c34573d..08e209c847 100755 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -299,6 +299,12 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id,  } +void notify_update_label(const LLUUID& base_item_id) +{ +	gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); +	LLGestureMgr::instance().notifyObservers(); +} +  void LLGestureMgr::deactivateGesture(const LLUUID& item_id)  {  	const LLUUID& base_item_id = get_linked_uuid(item_id); @@ -322,7 +328,6 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id)  	}  	mActive.erase(it); -	gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id);  	// Inform the database of this change  	LLMessageSystem* msg = gMessageSystem; @@ -338,9 +343,11 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id)  	gAgent.sendReliableMessage(); -	LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id); +	LLPointer<LLInventoryCallback> cb = +		new LLBoostFuncInventoryCallback(no_op_inventory_func, +										 boost::bind(notify_update_label,base_item_id)); -	notifyObservers(); +	LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id, cb);  } diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index cbd844cdac..472e3862ea 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1843,23 +1843,31 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,  // Responder class for capability group management  class GroupMemberDataResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(GroupMemberDataResponder);  public: -		GroupMemberDataResponder() {} -		virtual ~GroupMemberDataResponder() {} -		virtual void result(const LLSD& pContent); -		virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); +	GroupMemberDataResponder() {} +	virtual ~GroupMemberDataResponder() {} +  private: -		LLSD mMemberData; +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +	LLSD mMemberData;  }; -void GroupMemberDataResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void GroupMemberDataResponder::httpFailure()  { -	LL_WARNS("GrpMgr") << "Error receiving group member data [status:"  -		<< pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS("GrpMgr") << "Error receiving group member data " +		<< dumpResponse() << LL_ENDL;  } -void GroupMemberDataResponder::result(const LLSD& content) +void GroupMemberDataResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	LLGroupMgr::processCapGroupMembersRequest(content);  } diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp index 37428c4a44..b1286cccf2 100755 --- a/indra/newview/llhomelocationresponder.cpp +++ b/indra/newview/llhomelocationresponder.cpp @@ -33,71 +33,76 @@  #include "llagent.h"  #include "llviewerregion.h" -void LLHomeLocationResponder::result( const LLSD& content ) +void LLHomeLocationResponder::httpSuccess()  { +  const LLSD& content = getContent();    LLVector3 agent_pos;    bool      error = true; -		 +    do { -	 +      // was the call to /agent/<agent-id>/home-location successful?      // If not, we keep error set to true      if( ! content.has("success") )      {        break;      } -		 +      if( 0 != strncmp("true", content["success"].asString().c_str(), 4 ) )      {        break;      } -		 +      // did the simulator return a "justified" home location?      // If no, we keep error set to true      if( ! content.has( "HomeLocation" ) )      {        break;      } -		 +      if( ! content["HomeLocation"].has("LocationPos") )      {        break;      } -		 +      if( ! content["HomeLocation"]["LocationPos"].has("X") )      {        break;      }      agent_pos.mV[VX] = content["HomeLocation"]["LocationPos"]["X"].asInteger(); -		 +      if( ! content["HomeLocation"]["LocationPos"].has("Y") )      {        break;      }      agent_pos.mV[VY] = content["HomeLocation"]["LocationPos"]["Y"].asInteger(); -		 +      if( ! content["HomeLocation"]["LocationPos"].has("Z") )      {        break;      }      agent_pos.mV[VZ] = content["HomeLocation"]["LocationPos"]["Z"].asInteger(); -		 +      error = false;    } while( 0 ); -	 -  if( ! error ) + +  if( error ) +  { +    failureResult(HTTP_INTERNAL_ERROR, "Invalid server response content", content); +  } +  else    {      llinfos << "setting home position" << llendl; -		 +      LLViewerRegion *viewer_region = gAgent.getRegion();      gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos );    }  } -void LLHomeLocationResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content ) +void LLHomeLocationResponder::httpFailure()  { -	llwarns << "LLHomeLocationResponder error [status:" << status << "]: " << content << llendl; +  llwarns << dumpResponse() << llendl;  } diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h index 9bf4b12c4e..adc6c8cb58 100755 --- a/indra/newview/llhomelocationresponder.h +++ b/indra/newview/llhomelocationresponder.h @@ -35,8 +35,10 @@  /* Typedef, Enum, Class, Struct, etc. */  class LLHomeLocationResponder : public LLHTTPClient::Responder  { -	virtual void result( const LLSD& content ); -	virtual void errorWithContent( U32 status, const std::string& reason, const LLSD& content ); +	LOG_CLASS(LLHomeLocationResponder); +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure();  };  #endif diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp new file mode 100755 index 0000000000..ae429f11f8 --- /dev/null +++ b/indra/newview/llhttpretrypolicy.cpp @@ -0,0 +1,142 @@ +/**  + * @file llhttpretrypolicy.h + * @brief Header for a retry policy class intended for use with http responders. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "llhttpretrypolicy.h" + +LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx): +	mMinDelay(min_delay), +	mMaxDelay(max_delay), +	mBackoffFactor(backoff_factor), +	mMaxRetries(max_retries), +	mRetryOn4xx(retry_on_4xx) +{ +	init(); +} + +void LLAdaptiveRetryPolicy::init() +{ +	mDelay = mMinDelay; +	mRetryCount = 0; +	mShouldRetry = true; +} + +void LLAdaptiveRetryPolicy::reset() +{ +	init(); +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, F32& retry_header_time) +{ +	return (headers.has(HTTP_IN_HEADER_RETRY_AFTER) +			&& getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)); +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time) +{ +	if (headers) +	{ +		const std::string *retry_value = headers->find(HTTP_IN_HEADER_RETRY_AFTER.c_str());  +		if (retry_value &&  +			getSecondsUntilRetryAfter(*retry_value, retry_header_time)) +		{ +			return true; +		} +	} +	return false; +} + +void LLAdaptiveRetryPolicy::onSuccess() +{ +	init(); +} + +void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) +{ +	F32 retry_header_time; +	bool has_retry_header_time = getRetryAfter(headers,retry_header_time); +	onFailureCommon(status, has_retry_header_time, retry_header_time); +} +   +void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response) +{ +	F32 retry_header_time; +	const LLCore::HttpHeaders *headers = response->getHeaders(); +	bool has_retry_header_time = getRetryAfter(headers,retry_header_time); +	onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time); +} + +void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) +{ +	if (!mShouldRetry) +	{ +		llinfos << "keep on failing" << llendl; +		return; +	} +	if (mRetryCount > 0) +	{ +		mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); +	} +	// Honor server Retry-After header. +	// Status 503 may ask us to wait for a certain amount of time before retrying. +	F32 wait_time = mDelay; +	if (has_retry_header_time) +	{ +		wait_time = retry_header_time; +	} + +	if (mRetryCount>=mMaxRetries) +	{ +		llinfos << "Too many retries " << mRetryCount << ", will not retry" << llendl; +		mShouldRetry = false; +	} +	if (!mRetryOn4xx && !isHttpServerErrorStatus(status)) +	{ +		llinfos << "Non-server error " << status << ", will not retry" << llendl; +		mShouldRetry = false; +	} +	if (mShouldRetry) +	{ +		llinfos << "Retry count " << mRetryCount << " should retry after " << wait_time << llendl; +		mRetryTimer.reset(); +		mRetryTimer.setTimerExpirySec(wait_time); +	} +	mRetryCount++; +} +	 + +bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const +{ +	if (mRetryCount == 0) +	{ +		// Called shouldRetry before any failure. +		seconds_to_wait = F32_MAX; +		return false; +	} +	seconds_to_wait = mShouldRetry ? mRetryTimer.getRemainingTimeF32() : F32_MAX; +	return mShouldRetry; +} diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h new file mode 100755 index 0000000000..cf79e0b401 --- /dev/null +++ b/indra/newview/llhttpretrypolicy.h @@ -0,0 +1,98 @@ +/**  + * @file file llhttpretrypolicy.h + * @brief declarations for http retry policy class. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ +										 +#ifndef LL_RETRYPOLICY_H +#define LL_RETRYPOLICY_H + +#include "lltimer.h" +#include "llthread.h" + +#include "llhttpconstants.h" + +// For compatibility with new core http lib. +#include "httpresponse.h" +#include "httpheaders.h" + +// This is intended for use with HTTP Clients/Responders, but is not +// specifically coupled with those classes. +class LLHTTPRetryPolicy: public LLThreadSafeRefCount +{ +public: +	LLHTTPRetryPolicy() {} + +	virtual ~LLHTTPRetryPolicy() {} +	// Call after a sucess to reset retry state. + +	virtual void onSuccess() = 0; +	// Call once after an HTTP failure to update state. +	virtual void onFailure(S32 status, const LLSD& headers) = 0; + +	virtual void onFailure(const LLCore::HttpResponse *response) = 0; + +	virtual bool shouldRetry(F32& seconds_to_wait) const = 0; + +	virtual void reset() = 0; +}; + +// Very general policy with geometric back-off after failures, +// up to a maximum delay, and maximum number of retries. +class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +{ +public: +	LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx = false); + +	// virtual +	void onSuccess(); + +	void reset(); +	 +	// virtual +	void onFailure(S32 status, const LLSD& headers); +	// virtual +	void onFailure(const LLCore::HttpResponse *response); +	// virtual +	bool shouldRetry(F32& seconds_to_wait) const; + +protected: +	void init(); +	bool getRetryAfter(const LLSD& headers, F32& retry_header_time); +	bool getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time); +	void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time); + +private: + +	const F32 mMinDelay; // delay never less than this value +	const F32 mMaxDelay; // delay never exceeds this value +	const F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. +	const U32 mMaxRetries; // maximum number of times shouldRetry will return true. +	F32 mDelay; // current default delay. +	U32 mRetryCount; // number of times shouldRetry has been called. +	LLTimer mRetryTimer; // time until next retry. +	bool mShouldRetry; // Becomes false after too many retries, or the wrong sort of status received, etc. +	bool mRetryOn4xx; // Normally only retry on 5xx server errors. +}; + +#endif diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 59272d721f..8a02dde88c 100755 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -388,16 +388,17 @@ void LLFloaterIMPanel::draw()  class LLSessionInviteResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLSessionInviteResponder);  public:  	LLSessionInviteResponder(const LLUUID& session_id)  	{  		mSessionID = session_id;  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: +	void httpFailure()  	{ -		llwarns << "Error inviting all agents to session [status:"  -				<< statusNum << "]: " << content << llendl; +		llwarns << "Error inviting all agents to session " << dumpResponse() << llendl;  		//throw something back to the viewer here?  	} diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 9e23755d73..c667492427 100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -254,7 +254,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)      // 0. nothing - exit      if (("noaction" == user_preferences ||      		ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status) -    	&& session_floater->isMessagePaneExpanded()) +    	    && session_floater->isMessagePaneExpanded())      {      	return;      } @@ -971,7 +971,7 @@ void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& m  	LLIMSession* session = findIMSession(session_id);  	if (!session)  	{ -		llwarns << "session " << session_id << "does not exist " << llendl; +		llwarns << "session " << session_id << " does not exist " << llendl;  		return;  	} @@ -993,7 +993,7 @@ void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id)  	LLIMSession* session = findIMSession(session_id);  	if (!session)  	{ -		llwarns << "session " << session_id << "does not exist " << llendl; +		llwarns << "session " << session_id << " does not exist " << llendl;  		return;  	} @@ -1013,7 +1013,7 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from,  	if (!session)   	{ -		llwarns << "session " << session_id << "does not exist " << llendl; +		llwarns << "session " << session_id << " does not exist " << llendl;  		return false;  	} @@ -1088,7 +1088,7 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id,  	if (!session)  	{ -		llwarns << "session " << session_id << "does not exist " << llendl; +		llwarns << "session " << session_id << " does not exist " << llendl;  		return NULL;  	} @@ -1125,7 +1125,7 @@ const std::string LLIMModel::getName(const LLUUID& session_id) const  	if (!session)  	{ -		llwarns << "session " << session_id << "does not exist " << llendl; +		llwarns << "session " << session_id << " does not exist " << llendl;  		return LLTrans::getString("no_session_message");  	} @@ -1137,7 +1137,7 @@ const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const  	LLIMSession* session = findIMSession(session_id);  	if (!session)  	{ -		llwarns << "session " << session_id << "does not exist " << llendl; +		llwarns << "session " << session_id << " does not exist " << llendl;  		return -1;  	} @@ -1161,7 +1161,7 @@ EInstantMessage LLIMModel::getType(const LLUUID& session_id) const  	LLIMSession* session = findIMSession(session_id);  	if (!session)  	{ -		llwarns << "session " << session_id << "does not exist " << llendl; +		llwarns << "session " << session_id << " does not exist " << llendl;  		return IM_COUNT;  	} @@ -1173,7 +1173,7 @@ LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const  	LLIMSession* session = findIMSession(session_id);  	if (!session)  	{ -		llwarns << "session " << session_id << "does not exist " << llendl; +		llwarns << "session " << session_id << " does not exist " << llendl;  		return NULL;  	} @@ -1459,6 +1459,7 @@ void start_deprecated_conference_chat(  class LLStartConferenceChatResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLStartConferenceChatResponder);  public:  	LLStartConferenceChatResponder(  		const LLUUID& temp_session_id, @@ -1472,10 +1473,12 @@ public:  		mAgents = agents_to_invite;  	} -	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: +	virtual void httpFailure()  	{  		//try an "old school" way. -		if ( statusNum == 400 ) +		// *TODO: What about other error status codes?  4xx 5xx? +		if ( getStatus() == HTTP_BAD_REQUEST )  		{  			start_deprecated_conference_chat(  				mTempSessionID, @@ -1484,8 +1487,7 @@ public:  				mAgents);  		} -		llwarns << "LLStartConferenceChatResponder error [status:" -				<< statusNum << "]: " << content << llendl; +		llwarns << dumpResponse() << llendl;  		//else throw an error back to the client?  		//in theory we should have just have these error strings @@ -1577,6 +1579,7 @@ bool LLIMModel::sendStartSession(  class LLViewerChatterBoxInvitationAcceptResponder :  	public LLHTTPClient::Responder  { +	LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder);  public:  	LLViewerChatterBoxInvitationAcceptResponder(  		const LLUUID& session_id, @@ -1586,8 +1589,15 @@ public:  		mInvitiationType = invitation_type;  	} -	void result(const LLSD& content) +private: +	void httpSuccess()  	{ +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		if ( gIMMgr)  		{  			LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); @@ -1632,19 +1642,17 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -	{		 -		llwarns << "LLViewerChatterBoxInvitationAcceptResponder error [status:" -				<< statusNum << "]: " << content << llendl; +	void httpFailure() +	{ +		llwarns << dumpResponse() << llendl;  		//throw something back to the viewer here?  		if ( gIMMgr )  		{  			gIMMgr->clearPendingAgentListUpdates(mSessionID);  			gIMMgr->clearPendingInvitation(mSessionID); -			if ( 404 == statusNum ) +			if ( HTTP_NOT_FOUND == getStatus() )  			{ -				std::string error_string; -				error_string = "session_does_not_exist_error"; +				static const std::string error_string("session_does_not_exist_error");  				gIMMgr->showSessionStartError(error_string, mSessionID);  			}  		} diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 9c6db3676f..6ff16742dd 100755 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -292,11 +292,7 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data)  	delete mPropertiesRequest;  	mPropertiesRequest = NULL;  } -/* -prep# -			virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -				llwarns << "MuteVoiceResponder error [status:" << status << "]: " << content << llendl; -	*/ +  void LLInspectAvatar::updateVolumeSlider()  { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index e4fc469bb7..c9fe2127fe 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -200,6 +200,7 @@ const std::string& LLInvFVBridge::getDisplayName() const  	{  		buildDisplayName();  	} +  	return mDisplayName;  } @@ -1159,17 +1160,10 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,  void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)  { -	LLInventoryCategory* cat = model->getCategory(uuid); -	if (cat) -	{ -		model->purgeDescendentsOf(uuid); -		model->notifyObservers(); -	}  	LLInventoryObject* obj = model->getObject(uuid);  	if (obj)  	{ -		model->purgeObject(uuid); -		model->notifyObservers(); +		remove_inventory_object(uuid, NULL);  	}  } @@ -1573,18 +1567,18 @@ void LLItemBridge::buildDisplayName() const  	else  	{  		mDisplayName.assign(LLStringUtil::null); -} - +	} +	  	mSearchableName.assign(mDisplayName);  	mSearchableName.append(getLabelSuffix());  	LLStringUtil::toUpper(mSearchableName); - +	      //Name set, so trigger a sort      if(mParent) -{ -        mParent->requestSort(); -	} +	{ +		mParent->requestSort();  	} +}  LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const  { @@ -1698,13 +1692,9 @@ BOOL LLItemBridge::renameItem(const std::string& new_name)  	LLViewerInventoryItem* item = getItem();  	if(item && (item->getName() != new_name))  	{ -		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); -		new_item->rename(new_name); -		new_item->updateServer(FALSE); -		model->updateItem(new_item); - -		model->notifyObservers(); -		buildDisplayName(); +		LLSD updates; +		updates["name"] = new_name; +		update_inventory_item(item->getUUID(),updates, NULL);  	}  	// return FALSE because we either notified observers (& therefore  	// rebuilt) or we didn't update. @@ -1901,49 +1891,19 @@ void LLFolderBridge::buildDisplayName() const  void LLFolderBridge::update()  { -	bool possibly_has_children = false; -	bool up_to_date = isUpToDate(); -	if(!up_to_date && hasChildren()) // we know we have children but  haven't  fetched them (doesn't obey filter) -	{ -		possibly_has_children = true; -	} - -	bool loading = (possibly_has_children -		&& !up_to_date ); +	// we know we have children but  haven't  fetched them (doesn't obey filter) +	bool loading = !isUpToDate() && hasChildren() && mFolderViewItem->isOpen();  	if (loading != mIsLoading)  	{ -		if ( loading && !mIsLoading ) +		if ( loading )  		{  			// Measure how long we've been in the loading state  			mTimeSinceRequestStart.reset();  		} +		mIsLoading = loading; -		const BOOL in_inventory = gInventory.isObjectDescendentOf(getUUID(),   gInventory.getRootFolderID()); -		const BOOL in_library = gInventory.isObjectDescendentOf(getUUID(),   gInventory.getLibraryRootFolderID()); - -		bool root_is_loading = false; -		if (in_inventory) -		{ -			root_is_loading =   LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress(); -		} -		if (in_library) -		{ -			root_is_loading =   LLInventoryModelBackgroundFetch::instance().libraryFetchInProgress(); -		} -		if ((mIsLoading -				&&	mTimeSinceRequestStart.getElapsedTimeF32() >=   gSavedSettings.getF32("FolderLoadingMessageWaitTime")) -			||	(LLInventoryModelBackgroundFetch::instance().folderFetchActive() -				&&	root_is_loading)) -		{ -			mDisplayName = LLInvFVBridge::getDisplayName() + " ( " +   LLTrans::getString("LoadingData") + " ) "; -			mIsLoading = true; -		} -		else -		{ -			mDisplayName = LLInvFVBridge::getDisplayName(); -			mIsLoading = false; -		} +		mFolderViewItem->refresh();  	}  } @@ -2456,49 +2416,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  					}  				}  			} -			// if target is an outfit or current outfit folder we use link -			if (move_is_into_current_outfit || move_is_into_outfit) +			// if target is current outfit folder we use link +			if (move_is_into_current_outfit && +				inv_cat->getPreferredType() == LLFolderType::FT_NONE)  			{ -				if (inv_cat->getPreferredType() == LLFolderType::FT_NONE) -				{ -					if (move_is_into_current_outfit) -					{ -						// traverse category and add all contents to currently worn. -						BOOL append = true; -						LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append); -					} -					else -					{ -						// Recursively create links in target outfit. -						LLInventoryModel::cat_array_t cats; -						LLInventoryModel::item_array_t items; -						model->collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); -						LLAppearanceMgr::instance().linkAll(mUUID,items,NULL); -					} -				} -				else -				{ -#if SUPPORT_ENSEMBLES -					// BAP - should skip if dup. -					if (move_is_into_current_outfit) -					{ -						LLAppearanceMgr::instance().addEnsembleLink(inv_cat); -					} -					else -					{ -						LLPointer<LLInventoryCallback> cb = NULL; -						const std::string empty_description = ""; -						link_inventory_item( -							gAgent.getID(), -							cat_id, -							mUUID, -							inv_cat->getName(), -							empty_description, -							LLAssetType::AT_LINK_FOLDER, -							cb); -					} -#endif -				} +				// traverse category and add all contents to currently worn. +				BOOL append = true; +				LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);  			}  			else if (move_is_into_outbox && !move_is_from_outbox)  			{ @@ -2890,17 +2814,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)  		modifyOutfit(FALSE);  		return;  	} -#if SUPPORT_ENSEMBLES -	else if ("wearasensemble" == action) -	{ -		LLInventoryModel* model = getInventoryModel(); -		if(!model) return; -		LLViewerInventoryCategory* cat = getCategory(); -		if(!cat) return; -		LLAppearanceMgr::instance().addEnsembleLink(cat,true); -		return; -	} -#endif  	else if ("addtooutfit" == action)  	{  		modifyOutfit(TRUE); @@ -3063,6 +2976,13 @@ LLUIImagePtr LLFolderBridge::getIconOverlay() const  	return NULL;  } +std::string LLFolderBridge::getLabelSuffix() const +{ +	static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime"); +	return mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()  +		? llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()) +		: LLStringUtil::null; +}  BOOL LLFolderBridge::renameItem(const std::string& new_name)  { @@ -3303,28 +3223,9 @@ void LLFolderBridge::pasteLinkFromClipboard()  					dropToOutfit(item, move_is_into_current_outfit);  				}  			} -			else if (LLInventoryCategory *cat = model->getCategory(object_id)) -			{ -				const std::string empty_description = ""; -				link_inventory_item( -					gAgent.getID(), -					cat->getUUID(), -					parent_id, -					cat->getName(), -					empty_description, -					LLAssetType::AT_LINK_FOLDER, -					LLPointer<LLInventoryCallback>(NULL)); -			} -			else if (LLInventoryItem *item = model->getItem(object_id)) +			else if (LLConstPointer<LLInventoryObject> obj = model->getObject(object_id))  			{ -				link_inventory_item( -					gAgent.getID(), -					item->getLinkedUUID(), -					parent_id, -					item->getName(), -					item->getDescription(), -					LLAssetType::AT_LINK, -					LLPointer<LLInventoryCallback>(NULL)); +				link_inventory_object(parent_id, obj, LLPointer<LLInventoryCallback>(NULL));  			}  		}  		// Change mode to paste for next paste @@ -3415,16 +3316,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items  				items.push_back(std::string("New Clothes"));  				items.push_back(std::string("New Body Parts"));  			} -#if SUPPORT_ENSEMBLES -			// Changing folder types is an unfinished unsupported feature -			// and can lead to unexpected behavior if enabled. -			items.push_back(std::string("Change Type")); -			const LLViewerInventoryCategory *cat = getCategory(); -			if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) -			{ -				disabled_items.push_back(std::string("Change Type")); -			} -#endif  			getClipboardEntries(false, items, disabled_items, flags);  		}  		else @@ -3586,6 +3477,10 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&  		{  			disabled_items.push_back(std::string("Replace Outfit"));  		} +		if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) +		{ +			disabled_items.push_back(std::string("Add To Outfit")); +		}  		items.push_back(std::string("Outfit Separator"));  	}  } @@ -3916,14 +3811,7 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c  	else  	{  		LLPointer<LLInventoryCallback> cb = NULL; -		link_inventory_item( -			gAgent.getID(), -			inv_item->getLinkedUUID(), -			mUUID, -			inv_item->getName(), -			inv_item->getDescription(), -			LLAssetType::AT_LINK, -			cb); +		link_inventory_object(mUUID, LLConstPointer<LLInventoryObject>(inv_item), cb);  	}  } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 517153e171..2a937b574d 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -248,7 +248,7 @@ public:  	LLFolderBridge(LLInventoryPanel* inventory,   				   LLFolderView* root,  				   const LLUUID& uuid)  -        :       LLInvFVBridge(inventory, root, uuid), +	:	LLInvFVBridge(inventory, root, uuid),  		mCallingCards(FALSE),  		mWearables(FALSE),  		mIsLoading(false) @@ -272,6 +272,8 @@ public:  	virtual LLUIImagePtr getIconOverlay() const;  	static LLUIImagePtr getIcon(LLFolderType::EType preferred_type); +	 +	virtual std::string getLabelSuffix() const;  	virtual BOOL renameItem(const std::string& new_name); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index f1a4889f5a..faa5d70952 100755 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -123,12 +123,9 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s  		return;  	} -	LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); -	new_cat->rename(new_name); -	new_cat->updateServer(FALSE); -	model->updateCategory(new_cat); - -	model->notifyObservers(); +	LLSD updates; +	updates["name"] = new_name; +	update_inventory_category(cat_id, updates, NULL);  }  void copy_inventory_category(LLInventoryModel* model, @@ -741,6 +738,13 @@ bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item  	return FALSE;  } +bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +	LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); +	if (!vitem) return false; +	return (vitem->getActualType() == LLAssetType::AT_LINK  && !vitem->getIsBrokenLink()); +} +  bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)  {  	if(mType == LLAssetType::AT_CATEGORY) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index f1066a4dc9..6b3861aa79 100755 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -186,6 +186,13 @@ protected:  	LLAssetType::EType mType;  }; +class LLIsValidItemLink : public LLInventoryCollectFunctor +{ +public: +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +}; +  class LLIsTypeWithPermissions : public LLInventoryCollectFunctor  {  public: diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 935fe2b4d0..be1a396fff 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -27,6 +27,7 @@  #include "llviewerprecompiledheaders.h"  #include "llinventorymodel.h" +#include "llaisapi.h"  #include "llagent.h"  #include "llagentwearables.h"  #include "llappearancemgr.h" @@ -48,6 +49,7 @@  #include "llcallbacklist.h"  #include "llvoavatarself.h"  #include "llgesturemgr.h" +#include "llsdutil.h"  #include <typeinfo>  //#define DIFF_INVENTORY_FILES @@ -252,6 +254,23 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL  	return NULL;  } +bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const +{ +	LLInventoryObject *object = getObject(object_id); +	while (object && object->getParentUUID().notNull()) +	{ +		LLInventoryObject *parent_object = getObject(object->getParentUUID()); +		if (!parent_object) +		{ +			llwarns << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << llendl; +			return false; +		} +		object = parent_object; +	} +	result = object->getUUID(); +	return true; +} +  // Get the object by id. Returns NULL if not found.  LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const  { @@ -369,16 +388,13 @@ void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id)  	mItemLock[cat_id] = false;  } -// findCategoryUUIDForType() returns the uuid of the category that -// specifies 'type' as what it defaults to containing. The category is -// not necessarily only for that type. *NOTE: This will create a new -// inventory category on the fly if one does not exist. -const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder/*,  -					  bool find_in_library*/) +const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( +	LLFolderType::EType preferred_type, +	bool create_folder, +	const LLUUID& root_id)  {  	LLUUID rv = LLUUID::null; -	const LLUUID &root_id = /*(find_in_library) ? gInventory.getLibraryRootFolderID() :*/ gInventory.getRootFolderID();  	if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)  	{  		rv = root_id; @@ -394,14 +410,17 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe  			{  				if(cats->get(i)->getPreferredType() == preferred_type)  				{ -					rv = cats->get(i)->getUUID(); -					break; +					const LLUUID& folder_id = cats->get(i)->getUUID(); +					if (rv.isNull() || folder_id < rv) +					{ +						rv = folder_id; +					}  				}  			}  		}  	} -	if(rv.isNull() && isInventoryUsable() && (create_folder && true/*!find_in_library*/)) +	if(rv.isNull() && isInventoryUsable() && create_folder)  	{  		if(root_id.notNull())  		{ @@ -411,68 +430,49 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe  	return rv;  } -const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +// findCategoryUUIDForType() returns the uuid of the category that +// specifies 'type' as what it defaults to containing. The category is +// not necessarily only for that type. *NOTE: This will create a new +// inventory category on the fly if one does not exist. +const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)  { -	LLUUID rv = LLUUID::null; - -	const LLUUID &root_id = gInventory.getLibraryRootFolderID(); -	if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) -	{ -		rv = root_id; -	} -	else if (root_id.notNull()) -	{ -		cat_array_t* cats = NULL; -		cats = get_ptr_in_map(mParentChildCategoryTree, root_id); -		if(cats) -		{ -			S32 count = cats->count(); -			for(S32 i = 0; i < count; ++i) -			{ -				if(cats->get(i)->getPreferredType() == preferred_type) -				{ -					rv = cats->get(i)->getUUID(); -					break; -				} -			} -		} -	} +	return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID()); +} -	if(rv.isNull() && isInventoryUsable() && (create_folder && true/*!find_in_library*/)) -	{ -		if(root_id.notNull()) -		{ -			return createNewCategory(root_id, preferred_type, LLStringUtil::null); -		} -	} -	return rv; +const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +{ +	return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID());  }  class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLCreateInventoryCategoryResponder);  public:  	LLCreateInventoryCategoryResponder(LLInventoryModel* model,  -									   void (*callback)(const LLSD&, void*), -									   void* user_data) : -										mModel(model), -										mCallback(callback),  -										mData(user_data)  +									   boost::optional<inventory_func_type> callback): +		mModel(model), +		mCallback(callback)   	{  	} -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +protected: +	virtual void httpFailure()  	{ -		LL_WARNS("InvAPI") << "CreateInventoryCategory failed [status:" -				<< status << "]: " << content << LL_ENDL; +		LL_WARNS("InvAPI") << dumpResponse() << LL_ENDL;  	} -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{  		//Server has created folder. -		 +		const LLSD& content = getContent(); +		if (!content.isMap() || !content.has("folder_id")) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLUUID category_id = content["folder_id"].asUUID(); -		 +		LL_DEBUGS("Avatar") << ll_pretty_print_sd(content) << llendl;  		// Add the category to the internal representation  		LLPointer<LLViewerInventoryCategory> cat =  		new LLViewerInventoryCategory( category_id,  @@ -485,17 +485,15 @@ public:  		LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);  		mModel->accountForUpdate(update);  		mModel->updateCategory(cat); -		 -		if (mCallback && mData) + +		if (mCallback)  		{ -			mCallback(content, mData); +			mCallback.get()(category_id);  		} -		  	}  private: -	void (*mCallback)(const LLSD&, void*); -	void* mData; +	boost::optional<inventory_func_type> mCallback;  	LLInventoryModel* mModel;  }; @@ -506,8 +504,7 @@ private:  LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  										   LLFolderType::EType preferred_type,  										   const std::string& pname, -										   void (*callback)(const LLSD&, void*),	//Default to NULL -										   void* user_data)							//Default to NULL +										   boost::optional<inventory_func_type> callback)  {  	LLUUID id; @@ -534,33 +531,32 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  		name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));  	} -	if ( callback && user_data )  //callback required for acked message. +	LLViewerRegion* viewer_region = gAgent.getRegion(); +	std::string url; +	if ( viewer_region ) +		url = viewer_region->getCapability("CreateInventoryCategory"); +	 +	if (!url.empty() && callback.get_ptr())  	{ -		LLViewerRegion* viewer_region = gAgent.getRegion(); -		std::string url; -		if ( viewer_region ) -			url = viewer_region->getCapability("CreateInventoryCategory"); +		//Let's use the new capability. -		if (!url.empty()) -		{ -			//Let's use the new capability. -			 -			LLSD request, body; -			body["folder_id"] = id; -			body["parent_id"] = parent_id; -			body["type"] = (LLSD::Integer) preferred_type; -			body["name"] = name; -			 -			request["message"] = "CreateInventoryCategory"; -			request["payload"] = body; -			 -	//		viewer_region->getCapAPI().post(request); -			LLHTTPClient::post( -							   url, -							   body, -							   new LLCreateInventoryCategoryResponder(this, callback, user_data) ); -			return LLUUID::null; -		} +		LLSD request, body; +		body["folder_id"] = id; +		body["parent_id"] = parent_id; +		body["type"] = (LLSD::Integer) preferred_type; +		body["name"] = name; +		 +		request["message"] = "CreateInventoryCategory"; +		request["payload"] = body; + +		LL_DEBUGS("Avatar") << "create category request: " << ll_pretty_print_sd(request) << llendl; +		//		viewer_region->getCapAPI().post(request); +		LLHTTPClient::post( +			url, +			body, +			new LLCreateInventoryCategoryResponder(this, callback) ); + +		return LLUUID::null;  	}  	// Add the category to the internal representation @@ -587,6 +583,40 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  	return id;  } +// This is optimized for the case that we just want to know whether a +// category has any immediate children meeting a condition, without +// needing to recurse or build up any lists. +bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, +												   LLInventoryCollectFunctor& filter) +{ +	LLInventoryModel::cat_array_t *cats; +	LLInventoryModel::item_array_t *items; +	getDirectDescendentsOf(cat_id, cats, items); +	if (cats) +	{ +		for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); +			 it != cats->end(); ++it) +		{ +			if (filter(*it,NULL)) +			{ +				return true; +			} +		} +	} +	if (items) +	{ +		for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); +			 it != items->end(); ++it) +		{ +			if (filter(NULL,*it)) +			{ +				return true; +			} +		} +	} +	return false; +} +												    // Starting with the object specified, add it's descendents to the  // array provided, but do not add the inventory object specified by  // id. There is no guaranteed order. Neither array will be erased @@ -618,8 +648,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,  											cat_array_t& cats,  											item_array_t& items,  											BOOL include_trash, -											LLInventoryCollectFunctor& add, -											BOOL follow_folder_links) +											LLInventoryCollectFunctor& add)  {  	// Start with categories  	if(!include_trash) @@ -646,36 +675,6 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,  	LLViewerInventoryItem* item = NULL;  	item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); -	// Follow folder links recursively.  Currently never goes more -	// than one level deep (for current outfit support) -	// Note: if making it fully recursive, need more checking against infinite loops. -	if (follow_folder_links && item_array) -	{ -		S32 count = item_array->count(); -		for(S32 i = 0; i < count; ++i) -		{ -			item = item_array->get(i); -			if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) -			{ -				LLViewerInventoryCategory *linked_cat = item->getLinkedCategory(); -				if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT) -					// BAP - was  -					// LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType())) -					// Change back once ensemble typing is in place. -				{ -					if(add(linked_cat,NULL)) -					{ -						// BAP should this be added here?  May not -						// matter if it's only being used in current -						// outfit traversal. -						cats.put(LLPointer<LLViewerInventoryCategory>(linked_cat)); -					} -					collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); -				} -			} -		} -	} -	  	// Move onto items  	if(item_array)  	{ @@ -748,6 +747,10 @@ LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID  																	const LLUUID& start_folder_id)  {  	item_array_t items; +	const LLInventoryObject *obj = getObject(id); +	if (!obj || obj->getIsLinkType()) +		return items; +	  	LLInventoryModel::cat_array_t cat_array;  	LLLinkedItemIDMatches is_linked_item_match(id);  	collectDescendentsIf((start_folder_id == LLUUID::null ? gInventory.getRootFolderID() : start_folder_id), @@ -1123,8 +1126,197 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,  	notifyObservers();  } +void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update) +{ +	LLTimer timer; +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +	{ +		dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update); +	} + +	AISUpdate ais_update(update); // parse update llsd into stuff to do. +	ais_update.doUpdate(); // execute the updates in the appropriate order. +	llinfos << "elapsed: " << timer.getElapsedTimeF32() << llendl; +} + +void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) +{ +	U32 mask = LLInventoryObserver::NONE; + +	LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id); +	LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << llendl; +	if(item) +	{ +		for (LLSD::map_const_iterator it = updates.beginMap(); +			 it != updates.endMap(); ++it) +		{ +			if (it->first == "name") +			{ +				llinfos << "Updating name from " << item->getName() << " to " << it->second.asString() << llendl; +				item->rename(it->second.asString()); +				mask |= LLInventoryObserver::LABEL; +			} +			else if (it->first == "desc") +			{ +				llinfos << "Updating description from " << item->getActualDescription() +						<< " to " << it->second.asString() << llendl; +				item->setDescription(it->second.asString()); +			} +			else +			{ +				llerrs << "unhandled updates for field: " << it->first << llendl; +			} +		} +		mask |= LLInventoryObserver::INTERNAL; +		addChangedMask(mask, item->getUUID()); +		if (update_parent_version) +		{ +			// Descendent count is unchanged, but folder version incremented. +			LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); +			accountForUpdate(up); +		} +		gInventory.notifyObservers(); // do we want to be able to make this optional? +	} +} + +void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates) +{ +	U32 mask = LLInventoryObserver::NONE; + +	LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id); +	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << llendl; +	if(cat) +	{ +		for (LLSD::map_const_iterator it = updates.beginMap(); +			 it != updates.endMap(); ++it) +		{ +			if (it->first == "name") +			{ +				llinfos << "Updating name from " << cat->getName() << " to " << it->second.asString() << llendl; +				cat->rename(it->second.asString()); +				mask |= LLInventoryObserver::LABEL; +			} +			else +			{ +				llerrs << "unhandled updates for field: " << it->first << llendl; +			} +		} +		mask |= LLInventoryObserver::INTERNAL; +		addChangedMask(mask, cat->getUUID()); +		gInventory.notifyObservers(); // do we want to be able to make this optional? +	} +} + +// Update model after descendents have been purged. +void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links) +{ +	LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); +	if (cat.notNull()) +	{ +		// do the cache accounting +		S32 descendents = cat->getDescendentCount(); +		if(descendents > 0) +		{ +			LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); +			accountForUpdate(up); +		} + +		// we know that descendent count is 0, however since the +		// accounting may actually not do an update, we should force +		// it here. +		cat->setDescendentCount(0); + +		// unceremoniously remove anything we have locally stored. +		LLInventoryModel::cat_array_t categories; +		LLInventoryModel::item_array_t items; +		collectDescendents(object_id, +						   categories, +						   items, +						   LLInventoryModel::INCLUDE_TRASH); +		S32 count = items.count(); + +		LLUUID uu_id; +		for(S32 i = 0; i < count; ++i) +		{ +			uu_id = items.get(i)->getUUID(); + +			// This check prevents the deletion of a previously deleted item. +			// This is necessary because deletion is not done in a hierarchical +			// order. The current item may have been already deleted as a child +			// of its deleted parent. +			if (getItem(uu_id)) +			{ +				deleteObject(uu_id, fix_broken_links); +			} +		} + +		count = categories.count(); +		// Slightly kludgy way to make sure categories are removed +		// only after their child categories have gone away. + +		// FIXME: Would probably make more sense to have this whole +		// descendent-clearing thing be a post-order recursive +		// function to get the leaf-up behavior automatically. +		S32 deleted_count; +		S32 total_deleted_count = 0; +		do +		{ +			deleted_count = 0; +			for(S32 i = 0; i < count; ++i) +			{ +				uu_id = categories.get(i)->getUUID(); +				if (getCategory(uu_id)) +				{ +					cat_array_t* cat_list = getUnlockedCatArray(uu_id); +					if (!cat_list || (cat_list->size() == 0)) +					{ +						deleteObject(uu_id, fix_broken_links); +						deleted_count++; +					} +				} +			} +			total_deleted_count += deleted_count; +		} +		while (deleted_count > 0); +		if (total_deleted_count != count) +		{ +			llwarns << "Unexpected count of categories deleted, got " +					<< total_deleted_count << " expected " << count << llendl; +		} +		//gInventory.validate(); +	} +} + +// Update model after an item is confirmed as removed from +// server. Works for categories or items. +void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers) +{ +	LLPointer<LLInventoryObject> obj = getObject(object_id); +	if(obj) +	{ +		if (getCategory(object_id)) +		{ +			// For category, need to delete/update all children first. +			onDescendentsPurgedFromServer(object_id, fix_broken_links); +		} + + +		// From item/cat removeFromServer() +		if (update_parent_version) +		{ +			LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); +			accountForUpdate(up); +		} + +		// From purgeObject() +		LLPreview::hide(object_id); +		deleteObject(object_id, fix_broken_links, do_notify_observers); +	} +} + +  // Delete a particular inventory object by ID. -void LLInventoryModel::deleteObject(const LLUUID& id) +void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers)  {  	lldebugs << "LLInventoryModel::deleteObject()" << llendl;  	LLPointer<LLInventoryObject> obj = getObject(id); @@ -1155,31 +1347,37 @@ void LLInventoryModel::deleteObject(const LLUUID& id)  	item_list = getUnlockedItemArray(id);  	if(item_list)  	{ +		if (item_list->size()) +		{ +			llwarns << "Deleting cat " << id << " while it still has child items" << llendl; +		}  		delete item_list;  		mParentChildItemTree.erase(id);  	}  	cat_list = getUnlockedCatArray(id);  	if(cat_list)  	{ +		if (cat_list->size()) +		{ +			llwarns << "Deleting cat " << id << " while it still has child cats" << llendl; +		}  		delete cat_list;  		mParentChildCategoryTree.erase(id);  	}  	addChangedMask(LLInventoryObserver::REMOVE, id); +	 +	// Can't have links to links, so there's no need for this update +	// if the item removed is a link. Can also skip if source of the +	// update is getting broken link info separately. +	bool is_link_type = obj->getIsLinkType();  	obj = NULL; // delete obj -	updateLinkedObjectsFromPurge(id); -	gInventory.notifyObservers(); -} - -// Delete a particular inventory item by ID, and remove it from the server. -void LLInventoryModel::purgeObject(const LLUUID &id) -{ -	lldebugs << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << llendl; -	LLPointer<LLInventoryObject> obj = getObject(id); -	if(obj) +	if (fix_broken_links && !is_link_type)  	{ -		obj->removeFromServer(); -		LLPreview::hide(id); -		deleteObject(id); +		updateLinkedObjectsFromPurge(id); +	} +	if (do_notify_observers) +	{ +		notifyObservers();  	}  } @@ -1189,129 +1387,19 @@ void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)  	// REBUILD is expensive, so clear the current change list first else  	// everything else on the changelist will also get rebuilt. -	gInventory.notifyObservers(); -	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); -		 iter != item_array.end(); -		 iter++) -	{ -		const LLViewerInventoryItem *linked_item = (*iter); -		const LLUUID &item_id = linked_item->getUUID(); -		if (item_id == baseobj_id) continue; -		addChangedMask(LLInventoryObserver::REBUILD, item_id); -	} -	gInventory.notifyObservers(); -} - -// This is a method which collects the descendents of the id -// provided. If the category is not found, no action is -// taken. This method goes through the long winded process of -// cancelling any calling cards, removing server representation of -// folders, items, etc in a fairly efficient manner. -void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) -{ -	EHasChildren children = categoryHasChildren(id); -	if(children == CHILDREN_NO) -	{ -		llinfos << "Not purging descendents of " << id << llendl; -		return; -	} -	LLPointer<LLViewerInventoryCategory> cat = getCategory(id); -	if (cat.notNull()) +	if (item_array.size() > 0)  	{ -		if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) +		gInventory.notifyObservers(); +		for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); +			iter != item_array.end(); +			iter++)  		{ -			// Something on the clipboard is in "cut mode" and needs to be preserved -			llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() -			<< " iterate and purge non hidden items" << llendl; -			cat_array_t* categories; -			item_array_t* items; -			// Get the list of direct descendants in tha categoy passed as argument -			getDirectDescendentsOf(id, categories, items); -			std::vector<LLUUID> list_uuids; -			// Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) -			// Note: we need to do that shallow copy as purging things will invalidate the categories or items lists -			for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) -			{ -				list_uuids.push_back((*it)->getUUID()); -			} -			for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) -			{ -				list_uuids.push_back((*it)->getUUID()); -			} -			// Iterate through the list and only purge the UUIDs that are not on the clipboard -			for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) -			{ -				if (!LLClipboard::instance().isOnClipboard(*it)) -				{ -					purgeObject(*it); -				} -			} -		} -		else -		{ -			// Fast purge -			// do the cache accounting -			llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() -				<< llendl; -			S32 descendents = cat->getDescendentCount(); -			if(descendents > 0) -			{ -				LLCategoryUpdate up(id, -descendents); -				accountForUpdate(up); -			} - -			// we know that descendent count is 0, however since the -			// accounting may actually not do an update, we should force -			// it here. -			cat->setDescendentCount(0); - -			// send it upstream -			LLMessageSystem* msg = gMessageSystem; -			msg->newMessage("PurgeInventoryDescendents"); -			msg->nextBlock("AgentData"); -			msg->addUUID("AgentID", gAgent.getID()); -			msg->addUUID("SessionID", gAgent.getSessionID()); -			msg->nextBlock("InventoryData"); -			msg->addUUID("FolderID", id); -			gAgent.sendReliableMessage(); - -			// unceremoniously remove anything we have locally stored. -			cat_array_t categories; -			item_array_t items; -			collectDescendents(id, -							   categories, -							   items, -							   INCLUDE_TRASH); -			S32 count = items.count(); - -			item_map_t::iterator item_map_end = mItemMap.end(); -			cat_map_t::iterator cat_map_end = mCategoryMap.end(); -			LLUUID uu_id; - -			for(S32 i = 0; i < count; ++i) -			{ -				uu_id = items.get(i)->getUUID(); - -				// This check prevents the deletion of a previously deleted item. -				// This is necessary because deletion is not done in a hierarchical -				// order. The current item may have been already deleted as a child -				// of its deleted parent. -				if (mItemMap.find(uu_id) != item_map_end) -				{ -					deleteObject(uu_id); -				} -			} - -			count = categories.count(); -			for(S32 i = 0; i < count; ++i) -			{ -				uu_id = categories.get(i)->getUUID(); -				if (mCategoryMap.find(uu_id) != cat_map_end) -				{ -					deleteObject(uu_id); -				} -			} +			const LLViewerInventoryItem *linked_item = (*iter); +			const LLUUID &item_id = linked_item->getUUID(); +			if (item_id == baseobj_id) continue; +			addChangedMask(LLInventoryObserver::REBUILD, item_id);  		} +		gInventory.notifyObservers();  	}  } @@ -1396,8 +1484,14 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)  }  // If we get back a normal response, handle it here -void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) -{	 +void LLInventoryModel::fetchInventoryResponder::httpSuccess() +{ +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	start_new_inventory_observer();  	/*LLUUID agent_id; @@ -1456,9 +1550,9 @@ void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)  }  //If we get back an error (not found, etc...), handle it here -void LLInventoryModel::fetchInventoryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLInventoryModel::fetchInventoryResponder::httpFailure()  { -	llwarns << "fetchInventory error [status:" << status << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  	gInventory.notifyObservers();  } @@ -1601,7 +1695,6 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const  	LLViewerInventoryCategory* cat = getCategory(update.mCategoryID);  	if(cat)  	{ -		bool accounted = false;  		S32 version = cat->getVersion();  		if(version != LLViewerInventoryCategory::VERSION_UNKNOWN)  		{ @@ -1616,22 +1709,27 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const  			}  			if(descendents_server == descendents_actual)  			{ -				accounted = true;  				descendents_actual += update.mDescendentDelta;  				cat->setDescendentCount(descendents_actual);  				cat->setVersion(++version); -				lldebugs << "accounted: '" << cat->getName() << "' " +				LL_DEBUGS("Inventory") << "accounted: '" << cat->getName() << "' "  						 << version << " with " << descendents_actual -						 << " descendents." << llendl; +						 << " descendents." << LL_ENDL; +			} +			else +			{ +				// Error condition, this means that the category did not register that +				// it got new descendents (perhaps because it is still being loaded) +				// which means its descendent count will be wrong. +				llwarns << "Accounting failed for '" << cat->getName() << "' version:" +						 << version << " due to mismatched descendent count:  server == " +						 << descendents_server << ", viewer == " << descendents_actual << llendl;  			}  		} -		if(!accounted) +		else  		{ -			// Error condition, this means that the category did not register that -			// it got new descendents (perhaps because it is still being loaded) -			// which means its descendent count will be wrong. -			llwarns << "Accounting failed for '" << cat->getName() << "' version:" -					 << version << llendl; +			llwarns << "Accounting failed for '" << cat->getName() << "' version: unknown ("  +					<< version << ")" << llendl;  		}  	}  	else @@ -1665,47 +1763,6 @@ void LLInventoryModel::accountForUpdate(  	}  } - -/* -void LLInventoryModel::incrementCategoryVersion(const LLUUID& category_id) -{ -	LLViewerInventoryCategory* cat = getCategory(category_id); -	if(cat) -	{ -		S32 version = cat->getVersion(); -		if(LLViewerInventoryCategory::VERSION_UNKNOWN != version) -		{ -			cat->setVersion(version + 1); -			llinfos << "IncrementVersion: " << cat->getName() << " " -					<< cat->getVersion() << llendl; -		} -		else -		{ -			llinfos << "Attempt to increment version when unknown: " -					<< category_id << llendl; -		} -	} -	else -	{ -		llinfos << "Attempt to increment category: " << category_id << llendl; -	} -} -void LLInventoryModel::incrementCategorySetVersion( -	const std::set<LLUUID>& categories) -{ -	if(!categories.empty()) -	{  -		std::set<LLUUID>::const_iterator it = categories.begin(); -		std::set<LLUUID>::const_iterator end = categories.end(); -		for(; it != end; ++it) -		{ -			incrementCategoryVersion(*it); -		} -	} -} -*/ - -  LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(  	const LLUUID& cat_id) const  { @@ -2091,11 +2148,16 @@ void LLInventoryModel::buildParentChildMap()  	S32 count = cats.count();  	S32 i;  	S32 lost = 0; +	cat_array_t lost_cats;  	for(i = 0; i < count; ++i)  	{  		LLViewerInventoryCategory* cat = cats.get(i);  		catsp = getUnlockedCatArray(cat->getParentUUID()); -		if(catsp) +		if(catsp && +		   // Only the two root folders should be children of null. +		   // Others should go to lost & found. +		   (cat->getParentUUID().notNull() ||  +			cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY ))  		{  			catsp->put(cat);  		} @@ -2107,35 +2169,10 @@ void LLInventoryModel::buildParentChildMap()  			// implement it, we would need a set or map of uuid pairs  			// which would be (folder_id, new_parent_id) to be sent up  			// to the server. -			llinfos << "Lost categroy: " << cat->getUUID() << " - " +			llinfos << "Lost category: " << cat->getUUID() << " - "  					<< cat->getName() << llendl;  			++lost; -			// plop it into the lost & found. -			LLFolderType::EType pref = cat->getPreferredType(); -			if(LLFolderType::FT_NONE == pref) -			{ -				cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); -			} -			else if(LLFolderType::FT_ROOT_INVENTORY == pref) -			{ -				// it's the root -				cat->setParent(LLUUID::null); -			} -			else -			{ -				// it's a protected folder. -				cat->setParent(gInventory.getRootFolderID()); -			} -			cat->updateServer(TRUE); -			catsp = getUnlockedCatArray(cat->getParentUUID()); -			if(catsp) -			{ -				catsp->put(cat); -			} -			else -			{		 -				llwarns << "Lost and found Not there!!" << llendl; -			} +			lost_cats.put(cat);  		}  	}  	if(lost) @@ -2143,6 +2180,42 @@ void LLInventoryModel::buildParentChildMap()  		llwarns << "Found  " << lost << " lost categories." << llendl;  	} +	// Do moves in a separate pass to make sure we've properly filed +	// the FT_LOST_AND_FOUND category before we try to find its UUID. +	for(i = 0; i<lost_cats.count(); ++i) +	{ +		LLViewerInventoryCategory *cat = lost_cats.get(i); + +		// plop it into the lost & found. +		LLFolderType::EType pref = cat->getPreferredType(); +		if(LLFolderType::FT_NONE == pref) +		{ +			cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); +		} +		else if(LLFolderType::FT_ROOT_INVENTORY == pref) +		{ +			// it's the root +			cat->setParent(LLUUID::null); +		} +		else +		{ +			// it's a protected folder. +			cat->setParent(gInventory.getRootFolderID()); +		} +		// FIXME note that updateServer() fails with protected +		// types, so this will not work as intended in that case. +		cat->updateServer(TRUE); +		catsp = getUnlockedCatArray(cat->getParentUUID()); +		if(catsp) +		{ +			catsp->put(cat); +		} +		else +		{		 +			llwarns << "Lost and found Not there!!" << llendl; +		} +	} +  	const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null);  	sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); @@ -2271,6 +2344,11 @@ void LLInventoryModel::buildParentChildMap()  			notifyObservers();  		}  	} + +	if (!gInventory.validate()) +	{ +	 	llwarns << "model failed validity check!" << llendl; +	}  }  struct LLUUIDAndName @@ -2809,7 +2887,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	LLUUID tid;  	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid);  #ifndef LL_RELEASE_FOR_DOWNLOAD -	llinfos << "Bulk inventory: " << tid << llendl; +	LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << llendl;  #endif  	update_map_t update; @@ -2821,9 +2899,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	{  		LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());  		tfolder->unpackMessage(msg, _PREHASH_FolderData, i); -		llinfos << "unpacked folder '" << tfolder->getName() << "' (" -				<< tfolder->getUUID() << ") in " << tfolder->getParentUUID() -				<< llendl; +		LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" +							   << tfolder->getUUID() << ") in " << tfolder->getParentUUID() +							   << llendl;  		if(tfolder->getUUID().notNull())  		{  			folders.push_back(tfolder); @@ -2863,8 +2941,8 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	{  		LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;  		titem->unpackMessage(msg, _PREHASH_ItemData, i); -		llinfos << "unpacked item '" << titem->getName() << "' in " -				<< titem->getParentUUID() << llendl; +		LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " +							   << titem->getParentUUID() << llendl;  		U32 callback_id;  		msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);  		if(titem->getUUID().notNull() ) // && callback_id.notNull() ) @@ -2941,6 +3019,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  		InventoryCallbackInfo cbinfo = (*inv_it);  		gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);  	} + +	//gInventory.validate(); +  	// Don't show the inventory.  We used to call showAgentInventory here.  	//LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();  	//if(view) @@ -2999,7 +3080,8 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**)  		// If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added.  		if (gInventory.getItem(titem->getUUID()))  		{ -			lldebugs << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl; +			LL_DEBUGS("Inventory") << "Skipping prefetched item [ Name: " << titem->getName() +								   << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl;  			continue;  		}  		gInventory.updateItem(titem); @@ -3085,8 +3167,7 @@ bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const L  	if (option == 0) // YES  	{  		const LLUUID folder_id = findCategoryUUIDForType(preferred_type); -		purgeDescendentsOf(folder_id); -		notifyObservers(); +		purge_descendents_of(folder_id, NULL);  	}  	return false;  } @@ -3101,8 +3182,7 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT  	else  	{  		const LLUUID folder_id = findCategoryUUIDForType(preferred_type); -		purgeDescendentsOf(folder_id); -		notifyObservers(); +		purge_descendents_of(folder_id, NULL);  	}  } @@ -3389,6 +3469,254 @@ void LLInventoryModel::dumpInventory() const  	llinfos << "\n**********************\nEnd Inventory Dump" << llendl;  } +// Do various integrity checks on model, logging issues found and +// returning an overall good/bad flag. +bool LLInventoryModel::validate() const +{ +	bool valid = true; + +	if (getRootFolderID().isNull()) +	{ +		llwarns << "no root folder id" << llendl; +		valid = false; +	} +	if (getLibraryRootFolderID().isNull()) +	{ +		llwarns << "no root folder id" << llendl; +		valid = false; +	} + +	if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) +	{ +		// ParentChild should be one larger because of the special entry for null uuid. +		llinfos << "unexpected sizes: cat map size " << mCategoryMap.size() +				<< " parent/child " << mParentChildCategoryTree.size() << llendl; +		valid = false; +	} +	S32 cat_lock = 0; +	S32 item_lock = 0; +	S32 desc_unknown_count = 0; +	S32 version_unknown_count = 0; +	for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) +	{ +		const LLUUID& cat_id = cit->first; +		const LLViewerInventoryCategory *cat = cit->second; +		if (!cat) +		{ +			llwarns << "invalid cat" << llendl; +			valid = false; +			continue; +		} +		if (cat_id != cat->getUUID()) +		{ +			llwarns << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << llendl; +			valid = false; +		} + +		if (cat->getParentUUID().isNull()) +		{ +			if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) +			{ +				llwarns << "cat " << cat_id << " has no parent, but is not root (" +						<< getRootFolderID() << ") or library root (" +						<< getLibraryRootFolderID() << ")" << llendl; +			} +		} +		cat_array_t* cats; +		item_array_t* items; +		getDirectDescendentsOf(cat_id,cats,items); +		if (!cats || !items) +		{ +			llwarns << "invalid direct descendents for " << cat_id << llendl; +			valid = false; +			continue; +		} +		if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) +		{ +			desc_unknown_count++; +		} +		else if (cats->size() + items->size() != cat->getDescendentCount()) +		{ +			llwarns << "invalid desc count for " << cat_id << " name [" << cat->getName() +					<< "] parent " << cat->getParentUUID() +					<< " cached " << cat->getDescendentCount() +					<< " expected " << cats->size() << "+" << items->size() +					<< "=" << cats->size() +items->size() << llendl; +			valid = false; +		} +		if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) +		{ +			version_unknown_count++; +		} +		if (mCategoryLock.count(cat_id)) +		{ +			cat_lock++; +		} +		if (mItemLock.count(cat_id)) +		{ +			item_lock++; +		} +		for (S32 i = 0; i<items->size(); i++) +		{ +			LLViewerInventoryItem *item = items->get(i); + +			if (!item) +			{ +				llwarns << "null item at index " << i << " for cat " << cat_id << llendl; +				valid = false; +				continue; +			} + +			const LLUUID& item_id = item->getUUID(); +			 +			if (item->getParentUUID() != cat_id) +			{ +				llwarns << "wrong parent for " << item_id << " found " +						<< item->getParentUUID() << " expected " << cat_id +						<< llendl; +				valid = false; +			} + + +			// Entries in items and mItemMap should correspond. +			item_map_t::const_iterator it = mItemMap.find(item_id); +			if (it == mItemMap.end()) +			{ +				llwarns << "item " << item_id << " found as child of " +						<< cat_id << " but not in top level mItemMap" << llendl; +				valid = false; +			} +			else +			{ +				LLViewerInventoryItem *top_item = it->second; +				if (top_item != item) +				{ +					llwarns << "item mismatch, item_id " << item_id +							<< " top level entry is different, uuid " << top_item->getUUID() << llendl; +				} +			} + +			// Topmost ancestor should be root or library. +			LLUUID topmost_ancestor_id; +			bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); +			if (!found) +			{ +				llwarns << "unable to find topmost ancestor for " << item_id << llendl; +				valid = false; +			} +			else +			{ +				if (topmost_ancestor_id != getRootFolderID() && +					topmost_ancestor_id != getLibraryRootFolderID()) +				{ +					llwarns << "unrecognized top level ancestor for " << item_id +							<< " got " << topmost_ancestor_id +							<< " expected " << getRootFolderID() +							<< " or " << getLibraryRootFolderID() << llendl; +					valid = false; +				} +			} +		} + +		// Does this category appear as a child of its supposed parent? +		const LLUUID& parent_id = cat->getParentUUID(); +		if (!parent_id.isNull()) +		{ +			cat_array_t* cats; +			item_array_t* items; +			getDirectDescendentsOf(parent_id,cats,items); +			if (!cats) +			{ +				llwarns << "cat " << cat_id << " name [" << cat->getName() +						<< "] orphaned - no child cat array for alleged parent " << parent_id << llendl; +				valid = false; +			} +			else +			{ +				bool found = false; +				for (S32 i = 0; i<cats->size(); i++) +				{ +					LLViewerInventoryCategory *kid_cat = cats->get(i); +					if (kid_cat == cat) +					{ +						found = true; +						break; +					} +				} +				if (!found) +				{ +					llwarns << "cat " << cat_id << " name [" << cat->getName() +							<< "] orphaned - not found in child cat array of alleged parent " << parent_id << llendl; +				} +			} +		} +	} + +	for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) +	{ +		const LLUUID& item_id = iit->first; +		LLViewerInventoryItem *item = iit->second; +		if (item->getUUID() != item_id) +		{ +			llwarns << "item_id " << item_id << " does not match " << item->getUUID() << llendl; +			valid = false; +		} + +		const LLUUID& parent_id = item->getParentUUID(); +		if (parent_id.isNull()) +		{ +			llwarns << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << llendl; +		} +		else +		{ +			cat_array_t* cats; +			item_array_t* items; +			getDirectDescendentsOf(parent_id,cats,items); +			if (!items) +			{ +				llwarns << "item " << item_id << " name [" << item->getName() +						<< "] orphaned - alleged parent has no child items list " << parent_id << llendl; +			} +			else +			{ +				bool found = false; +				for (S32 i=0; i<items->size(); ++i) +				{ +					if (items->get(i) == item)  +					{ +						found = true; +						break; +					} +				} +				if (!found) +				{ +					llwarns << "item " << item_id << " name [" << item->getName() +							<< "] orphaned - not found as child of alleged parent " << parent_id << llendl; +				} +			} +				 +		} +	} +	 +	if (cat_lock > 0 || item_lock > 0) +	{ +		llwarns << "Found locks on some categories: sub-cat arrays " +				<< cat_lock << ", item arrays " << item_lock << llendl; +	} +	if (desc_unknown_count != 0) +	{ +		llinfos << "Found " << desc_unknown_count << " cats with unknown descendent count" << llendl;  +	} +	if (version_unknown_count != 0) +	{ +		llinfos << "Found " << version_unknown_count << " cats with unknown version" << llendl; +	} + +	llinfos << "Validate done, valid = " << (U32) valid << llendl; + +	return valid; +} +  ///----------------------------------------------------------------------------  /// Local function definitions  ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 8aac879a93..7afe1dea35 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -34,6 +34,7 @@  #include "llhttpclient.h"  #include "lluuid.h"  #include "llpermissionsflags.h" +#include "llviewerinventory.h"  #include "llstring.h"  #include "llmd5.h"  #include <map> @@ -45,14 +46,9 @@ class LLInventoryObserver;  class LLInventoryObject;  class LLInventoryItem;  class LLInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory;  class LLMessageSystem;  class LLInventoryCollectFunctor; -  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // LLInventoryModel  // @@ -81,11 +77,12 @@ public:  	class fetchInventoryResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(fetchInventoryResponder);  	public:  		fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; -		void result(const LLSD& content);			 -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content);  	protected: +		virtual void httpSuccess(); +		virtual void httpFailure();  		LLSD mRequestSD;  	}; @@ -204,6 +201,9 @@ public:  		EXCLUDE_TRASH = FALSE,   		INCLUDE_TRASH = TRUE   	}; +	// Simpler existence test if matches don't actually need to be collected. +	bool hasMatchingDirectDescendent(const LLUUID& cat_id, +									 LLInventoryCollectFunctor& filter);  	void collectDescendents(const LLUUID& id,  							cat_array_t& categories,  							item_array_t& items, @@ -212,8 +212,7 @@ public:  							  cat_array_t& categories,  							  item_array_t& items,  							  BOOL include_trash, -							  LLInventoryCollectFunctor& add, -							  BOOL follow_folder_links = FALSE); +							  LLInventoryCollectFunctor& add);  	// Collect all items in inventory that are linked to item_id.  	// Assumes item_id is itself not a linked item. @@ -224,10 +223,18 @@ public:  	// Check if one object has a parent chain up to the category specified by UUID.  	BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const; +	// Follow parent chain to the top. +	bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const; +	  	//--------------------------------------------------------------------  	// Find  	//--------------------------------------------------------------------  public: +	const LLUUID findCategoryUUIDForTypeInRoot( +		LLFolderType::EType preferred_type, +		bool create_folder, +		const LLUUID& root_id); +  	// Returns the uuid of the category that specifies 'type' as what it   	// defaults to containing. The category is not necessarily only for that type.   	//    NOTE: If create_folder is true, this will create a new inventory category  @@ -322,11 +329,31 @@ public:  	// Delete  	//--------------------------------------------------------------------  public: + +	// Update model after an AISv3 update received for any operation. +	void onAISUpdateReceived(const std::string& context, const LLSD& update); +		 +	// Update model after an item is confirmed as removed from +	// server. Works for categories or items. +	void onObjectDeletedFromServer(const LLUUID& item_id, +								   bool fix_broken_links = true, +								   bool update_parent_version = true, +								   bool do_notify_observers = true); + +	// Update model after all descendents removed from server. +	void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); + +	// Update model after an existing item gets updated on server. +	void onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version); + +	// Update model after an existing category gets updated on server. +	void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates); +  	// Delete a particular inventory object by ID. Will purge one  	// object from the internal data structures, maintaining a  	// consistent internal state. No cache accounting, observer  	// notification, or server update is performed. -	void deleteObject(const LLUUID& id); +	void deleteObject(const LLUUID& id, bool fix_broken_links = true, bool do_notify_observers = true);  	/// move Item item_id to Trash  	void removeItem(const LLUUID& item_id);  	/// move Category category_id to Trash @@ -334,17 +361,6 @@ public:  	/// removeItem() or removeCategory(), whichever is appropriate  	void removeObject(const LLUUID& object_id); -	// Delete a particular inventory object by ID, and delete it from -	// the server. Also updates linked items. -	void purgeObject(const LLUUID& id); - -	// Collects and purges the descendants of the id -	// provided. If the category is not found, no action is -	// taken. This method goes through the long winded process of -	// removing server representation of folders and items while doing -	// cache accounting in a fairly efficient manner. This method does -	// not notify observers (though maybe it should...) -	void purgeDescendentsOf(const LLUUID& id);  protected:  	void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id); @@ -379,8 +395,7 @@ public:  	LLUUID createNewCategory(const LLUUID& parent_id,  							 LLFolderType::EType preferred_type,  							 const std::string& name, -							 void (*callback)(const LLSD&, void*) = NULL, -							 void* user_data = NULL ); +							 boost::optional<inventory_func_type> callback = boost::optional<inventory_func_type>());  protected:  	// Internal methods that add inventory and make sure that all of  	// the internal data structures are consistent. These methods @@ -551,6 +566,7 @@ private:  	//--------------------------------------------------------------------  public:  	void dumpInventory() const; +	bool validate() const;  /**                    Miscellaneous   **                                                                            ** diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index d88e0c3192..864f38cbde 100755 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -1,6 +1,6 @@  /**  - * @file llinventorymodel.cpp - * @brief Implementation of the inventory model used to track agent inventory. + * @file llinventorymodelbackgroundfetch.cpp + * @brief Implementation of background fetching of inventory.   *   * $LicenseInfo:firstyear=2002&license=viewerlgpl$   * Second Life Viewer Source Code @@ -172,8 +172,11 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()  		mRecursiveLibraryFetchStarted)  	{  		mAllFoldersFetched = TRUE; +		//llinfos << "All folders fetched, validating" << llendl; +		//gInventory.validate();  	}  	mFolderFetchActive = false; +	mBackgroundFetchActive = false;  }  void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) @@ -363,35 +366,40 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching)  class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder  { +	LOG_CLASS(LLInventoryModelFetchItemResponder);  public: -	LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {}; -	void result(const LLSD& content);			 -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +	LLInventoryModelFetchItemResponder(const LLSD& request_sd) : +		LLInventoryModel::fetchInventoryResponder(request_sd) +	{ +		LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); +	} +private: +	/* virtual */ void httpCompleted() +	{ +		LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +		LLInventoryModel::fetchInventoryResponder::httpCompleted(); +	}  }; -void LLInventoryModelFetchItemResponder::result( const LLSD& content ) -{ -	LLInventoryModel::fetchInventoryResponder::result(content); -	LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - -void LLInventoryModelFetchItemResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content ) -{ -	LLInventoryModel::fetchInventoryResponder::errorWithContent(status, reason, content); -	LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - -  class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder  { +	LOG_CLASS(LLInventoryModelFetchDescendentsResponder);  public:  	LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) :   		mRequestSD(request_sd),  		mRecursiveCatUUIDs(recursive_cats) -	{}; +	{ +		LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); +	}  	//LLInventoryModelFetchDescendentsResponder() {}; -	void result(const LLSD& content); -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +private: +	/* virtual */ void httpCompleted() +	{ +		LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +		LLHTTPClient::Responder::httpCompleted(); +	} +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure();  protected:  	BOOL getIsRecursive(const LLUUID& cat_id) const;  private: @@ -400,8 +408,14 @@ private:  };  // If we get back a normal response, handle it here. -void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();  	if (content.has("folders"))	  	{ @@ -508,16 +522,15 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)  		for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray();  			folder_it != content["bad_folders"].endArray();  			++folder_it) -		{	 +		{ +			// *TODO: Stop copying data  			LLSD folder_sd = *folder_it;  			// These folders failed on the dataserver.  We probably don't want to retry them. -			llinfos << "Folder " << folder_sd["folder_id"].asString()  +			llwarns << "Folder " << folder_sd["folder_id"].asString()   					<< "Error: " << folder_sd["error"].asString() << llendl;  		}  	} - -	fetcher->incrFetchCount(-1);  	if (fetcher->isBulkFetchProcessingComplete())  	{ @@ -529,21 +542,17 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)  }  // If we get back an error (not found, etc...), handle it here. -void LLInventoryModelFetchDescendentsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::httpFailure()  { +	llwarns << dumpResponse() << llendl;  	LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); -	llinfos << "LLInventoryModelFetchDescendentsResponder::error [status:" -			<< status << "]: " << content << llendl; -						 -	fetcher->incrFetchCount(-1); - -	if (status==499) // timed out +	if (getStatus()==HTTP_INTERNAL_ERROR) // timed out or curl failure  	{  		for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray();  			folder_it != mRequestSD["folders"].endArray();  			++folder_it) -		{	 +		{  			LLSD folder_sd = *folder_it;  			LLUUID folder_id = folder_sd["folder_id"];  			const BOOL recursive = getIsRecursive(folder_id); @@ -586,7 +595,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()  		(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))  	{  		return; // just bail if we are disconnected -	}	 +	}  	U32 item_count=0;  	U32 folder_count=0; @@ -686,63 +695,46 @@ void LLInventoryModelBackgroundFetch::bulkFetch()  	{  		if (folder_count)  		{ -			std::string url = region->getCapability("FetchInventoryDescendents2");    +			std::string url = region->getCapability("FetchInventoryDescendents2");   			  			if ( !url.empty() )  			{ -			mFetchCount++; -			if (folder_request_body["folders"].size()) -			{ -				LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); -				LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); -			} -			if (folder_request_body_lib["folders"].size()) -			{ -				std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); +				if (folder_request_body["folders"].size()) +				{ +					LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); +					LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); +				} +				if (folder_request_body_lib["folders"].size()) +				{ +					std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); -				LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); -				LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); +					LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); +					LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); +				}  			}  		} -		}  		if (item_count)  		{  			std::string url;  			if (item_request_body.size())  			{ -				mFetchCount++;  				url = region->getCapability("FetchInventory2");  				if (!url.empty())  				{  					LLSD body; -					body["agent_id"]	= gAgent.getID();  					body["items"] = item_request_body;  					LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));  				} -				//else -				//{ -				//	LLMessageSystem* msg = gMessageSystem; -				//	msg->newMessage("FetchInventory"); -				//	msg->nextBlock("AgentData"); -				//	msg->addUUID("AgentID", gAgent.getID()); -				//	msg->addUUID("SessionID", gAgent.getSessionID()); -				//	msg->nextBlock("InventoryData"); -				//	msg->addUUID("OwnerID", mPermissions.getOwner()); -				//	msg->addUUID("ItemID", mUUID); -				//	gAgent.sendReliableMessage(); -				//}  			}  			if (item_request_body_lib.size())  			{ -				mFetchCount++;  				url = region->getCapability("FetchLib2");  				if (!url.empty())  				{  					LLSD body; -					body["agent_id"]	= gAgent.getID();  					body["items"] = item_request_body_lib;  					LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 0b009b68f7..28e1df725a 100755 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -99,7 +99,7 @@ namespace LLMarketplaceImport  	bool hasSessionCookie();  	bool inProgress();  	bool resultPending(); -	U32 getResultStatus(); +	S32 getResultStatus();  	const LLSD& getResults();  	bool establishMarketplaceSessionCookie(); @@ -113,7 +113,7 @@ namespace LLMarketplaceImport  	static bool sImportInProgress = false;  	static bool sImportPostPending = false;  	static bool sImportGetPending = false; -	static U32 sImportResultStatus = 0; +	static S32 sImportResultStatus = 0;  	static LLSD sImportResults = LLSD::emptyMap();  	static LLTimer slmGetTimer; @@ -123,22 +123,22 @@ namespace LLMarketplaceImport  	class LLImportPostResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(LLImportPostResponder);  	public:  		LLImportPostResponder() : LLCurl::Responder() {} -		 -		void completed(U32 status, const std::string& reason, const LLSD& content) + +	protected: +		/* virtual */ void httpCompleted()  		{  			slmPostTimer.stop();  			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  			{ -				llinfos << " SLM POST status: " << status << llendl; -				llinfos << " SLM POST reason: " << reason << llendl; -				llinfos << " SLM POST content: " << content.asString() << llendl; - -				llinfos << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << llendl; +				llinfos << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] " +						<< dumpResponse() << llendl;  			} +			S32 status = getStatus();  			if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) ||  				(status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) ||  				(status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) @@ -154,38 +154,35 @@ namespace LLMarketplaceImport  			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE);  			sImportPostPending = false;  			sImportResultStatus = status; -			sImportId = content; +			sImportId = getContent();  		}  	};  	class LLImportGetResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(LLImportGetResponder);  	public:  		LLImportGetResponder() : LLCurl::Responder() {} -		void completedHeader(U32 status, const std::string& reason, const LLSD& content) +	protected: +		/* virtual */ void httpCompleted()  		{ -			const std::string& set_cookie_string = content["set-cookie"].asString(); +			const std::string& set_cookie_string = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);  			if (!set_cookie_string.empty())  			{  				sMarketplaceCookie = set_cookie_string;  			} -		} -		 -		void completed(U32 status, const std::string& reason, const LLSD& content) -		{ +  			slmGetTimer.stop();  			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  			{ -				llinfos << " SLM GET status: " << status << llendl; -				llinfos << " SLM GET reason: " << reason << llendl; -				llinfos << " SLM GET content: " << content.asString() << llendl; - -				llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl; +				llinfos << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] " +						<< dumpResponse() << llendl;  			} +			S32 status = getStatus();  			if ((status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) ||  				(status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))  			{ @@ -200,7 +197,7 @@ namespace LLMarketplaceImport  			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);  			sImportGetPending = false;  			sImportResultStatus = status; -			sImportResults = content; +			sImportResults = getContent();  		}  	}; @@ -221,7 +218,7 @@ namespace LLMarketplaceImport  		return (sImportPostPending || sImportGetPending);  	} -	U32 getResultStatus() +	S32 getResultStatus()  	{  		return sImportResultStatus;  	} @@ -280,10 +277,11 @@ namespace LLMarketplaceImport  		// Make the headers for the post  		LLSD headers = LLSD::emptyMap(); -		headers["Accept"] = "*/*"; -		headers["Cookie"] = sMarketplaceCookie; -		headers["Content-Type"] = "application/llsd+xml"; -		headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); +		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; +		headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; +		// *TODO: Why are we setting Content-Type for a GET request? +		headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; +		headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent();  		if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  		{ @@ -313,11 +311,11 @@ namespace LLMarketplaceImport  		// Make the headers for the post  		LLSD headers = LLSD::emptyMap(); -		headers["Accept"] = "*/*"; -		headers["Connection"] = "Keep-Alive"; -		headers["Cookie"] = sMarketplaceCookie; -		headers["Content-Type"] = "application/xml"; -		headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); +		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; +		headers[HTTP_OUT_HEADER_CONNECTION] = "Keep-Alive"; +		headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; +		headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; +		headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent();  		if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  		{ diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 2075aeed63..cb5640b4da 100755 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -52,6 +52,7 @@  #include "llsdutil.h"  #include "lllayoutstack.h"  #include "lliconctrl.h" +#include "llhttpconstants.h"  #include "lltextbox.h"  #include "llbutton.h"  #include "llcheckboxctrl.h" @@ -576,7 +577,7 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str  	{  		mCurrentNavUrl = expanded_filename;  		mMediaSource->setSize(mTextureWidth, mTextureHeight); -		mMediaSource->navigateTo(expanded_filename, "text/html", false); +		mMediaSource->navigateTo(expanded_filename, HTTP_CONTENT_TEXT_HTML, false);  	}  } @@ -948,7 +949,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL;  			if ( mErrorPageURL.length() > 0 )  			{ -				navigateTo(mErrorPageURL, "text/html"); +				navigateTo(mErrorPageURL, HTTP_CONTENT_TEXT_HTML);  			};  		};  		break; diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index e3b46d5d2f..691be13610 100755 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -35,7 +35,7 @@  #include <boost/lexical_cast.hpp> -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llsdutil.h"  #include "llmediaentry.h"  #include "lltextureentry.h" @@ -564,7 +564,7 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request)  }  /*virtual*/ -void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLMediaDataClient::Responder::httpFailure()  {  	mRequest->stopTracking(); @@ -574,9 +574,17 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin  		return;  	} -	if (status == HTTP_SERVICE_UNAVAILABLE) +	if (getStatus() == HTTP_SERVICE_UNAVAILABLE)  	{ -		F32 retry_timeout = mRequest->getRetryTimerDelay(); +		F32 retry_timeout; +#if 0 +		// *TODO: Honor server Retry-After header. +		if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER) +			|| !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout)) +#endif +		{ +			retry_timeout = mRequest->getRetryTimerDelay(); +		}  		mRequest->incRetryCount(); @@ -594,15 +602,16 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin  				<< mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;  		}  	} +	// *TODO: Redirect on 3xx status codes.  	else   	{ -		LL_WARNS("LLMediaDataClient") << *mRequest << " http error [status:"  -				<< status << "]:" << content << ")" << LL_ENDL; +		LL_WARNS("LLMediaDataClient") << *mRequest << " http failure " +				<< dumpResponse() << LL_ENDL;  	}  }  /*virtual*/ -void LLMediaDataClient::Responder::result(const LLSD& content) +void LLMediaDataClient::Responder::httpSuccess()  {  	mRequest->stopTracking(); @@ -612,7 +621,7 @@ void LLMediaDataClient::Responder::result(const LLSD& content)  		return;  	} -	LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL; +	LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " " << dumpResponse() << LL_ENDL;  }  ////////////////////////////////////////////////////////////////////////////////////// @@ -876,7 +885,7 @@ LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResp  /*virtual*/ -void LLObjectMediaDataClient::Responder::result(const LLSD& content) +void LLObjectMediaDataClient::Responder::httpSuccess()  {  	getRequest()->stopTracking(); @@ -886,10 +895,16 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content)  		return;  	} +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +  	// This responder is only used for GET requests, not UPDATE. +	LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; -	LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL; -	  	// Look for an error  	if (content.has("error"))  	{ @@ -1003,7 +1018,7 @@ LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::crea  }  /*virtual*/ -void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpFailure()  {  	getRequest()->stopTracking(); @@ -1015,14 +1030,14 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const  	// Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base  	// class -	if (status == HTTP_SERVICE_UNAVAILABLE) +	if (getStatus() == HTTP_SERVICE_UNAVAILABLE)  	{ -		LLMediaDataClient::Responder::errorWithContent(status, reason, content); +		LLMediaDataClient::Responder::httpFailure();  	}  	else  	{  		// bounce the face back -		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL; +		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: " << dumpResponse() << LL_ENDL;  		const LLSD &payload = getRequest()->getPayload();  		// bounce the face back  		getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); @@ -1030,7 +1045,7 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const  }  /*virtual*/ -void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpSuccess()  {  	getRequest()->stopTracking(); @@ -1040,8 +1055,9 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)  		return;  	} -	LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL; +	LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << dumpResponse() << LL_ENDL; +	const LLSD& content = getContent();  	if (content.has("error"))  	{  		const LLSD &error = content["error"]; @@ -1065,6 +1081,6 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)  	else   	{  		// No action required. -		LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " result : " << ll_print_sd(content) << LL_ENDL; +		LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL;  	}  } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 89e20a28d0..231b883c32 100755 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -74,8 +74,9 @@ public:  // Abstracts the Cap URL, the request, and the responder  class LLMediaDataClient : public LLRefCount  { -public: +protected:      LOG_CLASS(LLMediaDataClient); +public:      const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s)  	const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs @@ -192,14 +193,16 @@ protected:  	// Responder  	class Responder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(Responder);  	public:  		Responder(const request_ptr_t &request); +		request_ptr_t &getRequest() { return mRequest; } + +	protected:  		//If we get back an error (not found, etc...), handle it here -		virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +		virtual void httpFailure();  		//If we get back a normal response, handle it here.	 Default just logs it. -		virtual void result(const LLSD& content); - -		request_ptr_t &getRequest() { return mRequest; } +		virtual void httpSuccess();  	private:  		request_ptr_t mRequest; @@ -287,8 +290,9 @@ private:  // MediaDataClient specific for the ObjectMedia cap  class LLObjectMediaDataClient : public LLMediaDataClient  { -public: +protected:      LOG_CLASS(LLObjectMediaDataClient); +public:      LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,  							F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,  							U32 max_retries = MAX_RETRIES, @@ -341,10 +345,12 @@ protected:      class Responder : public LLMediaDataClient::Responder      { +        LOG_CLASS(Responder);      public:          Responder(const request_ptr_t &request)              : LLMediaDataClient::Responder(request) {} -        virtual void result(const LLSD &content); +    protected: +        virtual void httpSuccess();      };  private:  	// The Get/Update data client needs a second queue to avoid object updates starving load-ins. @@ -362,8 +368,9 @@ private:  // MediaDataClient specific for the ObjectMediaNavigate cap  class LLObjectMediaNavigateClient : public LLMediaDataClient  { -public: +protected:      LOG_CLASS(LLObjectMediaNavigateClient); +public:  	// NOTE: from llmediaservice.h  	static const int ERROR_PERMISSION_DENIED_CODE = 8002; @@ -397,11 +404,13 @@ protected:      class Responder : public LLMediaDataClient::Responder      { +        LOG_CLASS(Responder);      public:          Responder(const request_ptr_t &request)              : LLMediaDataClient::Responder(request) {} -		virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -        virtual void result(const LLSD &content); +    protected: +        virtual void httpFailure(); +        virtual void httpSuccess();      private:          void mediaNavigateBounceBack();      }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8d3539d297..a888445060 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -29,7 +29,7 @@  #include "apr_pools.h"  #include "apr_dso.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llmeshrepository.h"  #include "llagent.h" @@ -203,6 +203,7 @@ U32	LLMeshRepoThread::sMaxConcurrentRequests = 1;  class LLMeshHeaderResponder : public LLCurl::Responder  { +	LOG_CLASS(LLMeshHeaderResponder);  public:  	LLVolumeParams mMeshParams;  	bool mProcessed; @@ -231,14 +232,14 @@ public:  		}  	} -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, +	virtual void completedRaw(const LLChannelDescriptors& channels,  							  const LLIOPipe::buffer_ptr_t& buffer);  };  class LLMeshLODResponder : public LLCurl::Responder  { +	LOG_CLASS(LLMeshLODResponder);  public:  	LLVolumeParams mMeshParams;  	S32 mLOD; @@ -267,14 +268,14 @@ public:  		}  	} -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, +	virtual void completedRaw(const LLChannelDescriptors& channels,  							  const LLIOPipe::buffer_ptr_t& buffer);  };  class LLMeshSkinInfoResponder : public LLCurl::Responder  { +	LOG_CLASS(LLMeshSkinInfoResponder);  public:  	LLUUID mMeshID;  	U32 mRequestedBytes; @@ -292,14 +293,14 @@ public:  		llassert(mProcessed);  	} -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, +	virtual void completedRaw(const LLChannelDescriptors& channels,  							  const LLIOPipe::buffer_ptr_t& buffer);  };  class LLMeshDecompositionResponder : public LLCurl::Responder  { +	LOG_CLASS(LLMeshDecompositionResponder);  public:  	LLUUID mMeshID;  	U32 mRequestedBytes; @@ -317,14 +318,14 @@ public:  		llassert(mProcessed);  	} -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, +	virtual void completedRaw(const LLChannelDescriptors& channels,  							  const LLIOPipe::buffer_ptr_t& buffer);  };  class LLMeshPhysicsShapeResponder : public LLCurl::Responder  { +	LOG_CLASS(LLMeshPhysicsShapeResponder);  public:  	LLUUID mMeshID;  	U32 mRequestedBytes; @@ -342,8 +343,7 @@ public:  		llassert(mProcessed);  	} -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, +	virtual void completedRaw(const LLChannelDescriptors& channels,  							  const LLIOPipe::buffer_ptr_t& buffer);  }; @@ -399,6 +399,7 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s  class LLWholeModelFeeResponder: public LLCurl::Responder  { +	LOG_CLASS(LLWholeModelFeeResponder);  	LLMeshUploadThread* mThread;  	LLSD mModelData;  	LLHandle<LLWholeModelFeeObserver> mObserverHandle; @@ -422,21 +423,20 @@ public:  		}  	} -	virtual void completed(U32 status, -						   const std::string& reason, -						   const LLSD& content) +protected: +	virtual void httpCompleted()  	{ -		LLSD cc = content; +		LLSD cc = getContent();  		if (gSavedSettings.getS32("MeshUploadFakeErrors")&1)  		{  			cc = llsd_from_file("fake_upload_error.xml");  		} -			 +  		dump_llsd_to_file(cc,make_dump_name("whole_model_fee_response_",dump_num));  		LLWholeModelFeeObserver* observer = mObserverHandle.get(); -		if (isGoodStatus(status) && +		if (isGoodStatus() &&  			cc["state"].asString() == "upload")  		{  			mThread->mWholeModelUploadURL = cc["uploader"].asString(); @@ -449,13 +449,14 @@ public:  		}  		else  		{ -			llwarns << "fee request failed" << llendl; +			llwarns << "fee request failed " << dumpResponse() << llendl; +			S32 status = getStatus();  			log_upload_error(status,cc,"fee",mModelData["name"]);  			mThread->mWholeModelUploadURL = "";  			if (observer)  			{ -				observer->setModelPhysicsFeeErrorStatus(status, reason); +				observer->setModelPhysicsFeeErrorStatus(status, getReason());  			}  		}  	} @@ -464,6 +465,7 @@ public:  class LLWholeModelUploadResponder: public LLCurl::Responder  { +	LOG_CLASS(LLWholeModelUploadResponder);  	LLMeshUploadThread* mThread;  	LLSD mModelData;  	LLHandle<LLWholeModelUploadObserver> mObserverHandle; @@ -488,11 +490,10 @@ public:  		}  	} -	virtual void completed(U32 status, -						   const std::string& reason, -						   const LLSD& content) +protected: +	virtual void httpCompleted()  	{ -		LLSD cc = content; +		LLSD cc = getContent();  		if (gSavedSettings.getS32("MeshUploadFakeErrors")&2)  		{  			cc = llsd_from_file("fake_upload_error.xml"); @@ -504,7 +505,7 @@ public:  		// requested "mesh" asset type isn't actually the type  		// of the resultant object, fix it up here. -		if (isGoodStatus(status) && +		if (isGoodStatus() &&  			cc["state"].asString() == "complete")  		{  			mModelData["asset_type"] = "object"; @@ -517,9 +518,9 @@ public:  		}  		else  		{ -			llwarns << "upload failed" << llendl; +			llwarns << "upload failed " << dumpResponse() << llendl;  			std::string model_name = mModelData["name"].asString(); -			log_upload_error(status,cc,"upload",model_name); +			log_upload_error(getStatus(),cc,"upload",model_name);  			if (observer)  			{ @@ -808,7 +809,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  			//reading from VFS failed for whatever reason, fetch from sim  			std::vector<std::string> headers; -			headers.push_back("Accept: application/octet-stream"); +			headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);  			std::string http_url = constructUrl(mesh_id);  			if (!http_url.empty()) @@ -890,7 +891,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  			//reading from VFS failed for whatever reason, fetch from sim  			std::vector<std::string> headers; -			headers.push_back("Accept: application/octet-stream"); +			headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);  			std::string http_url = constructUrl(mesh_id);  			if (!http_url.empty()) @@ -971,7 +972,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  			//reading from VFS failed for whatever reason, fetch from sim  			std::vector<std::string> headers; -			headers.push_back("Accept: application/octet-stream"); +			headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);  			std::string http_url = constructUrl(mesh_id);  			if (!http_url.empty()) @@ -1052,7 +1053,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c  	//either cache entry doesn't exist or is corrupt, request header from simulator	  	bool retval = true ;  	std::vector<std::string> headers; -	headers.push_back("Accept: application/octet-stream"); +	headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);  	std::string http_url = constructUrl(mesh_params.getSculptID());  	if (!http_url.empty()) @@ -1127,7 +1128,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,  			//reading from VFS failed for whatever reason, fetch from sim  			std::vector<std::string> headers; -			headers.push_back("Accept: application/octet-stream"); +			headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);  			std::string http_url = constructUrl(mesh_id);  			if (!http_url.empty()) @@ -1899,10 +1900,10 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)  } -void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshLODResponder::completedRaw(const LLChannelDescriptors& channels, +									  const LLIOPipe::buffer_ptr_t& buffer)  { +	S32 status = getStatus();  	mProcessed = true;  	// thread could have already be destroyed during logout @@ -1913,14 +1914,15 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,  	S32 data_size = buffer->countAfter(channels.in(), NULL); +	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?  	if (status < 200 || status > 400)  	{ -		llwarns << status << ": " << reason << llendl; +		llwarns << dumpResponse() << llendl;  	}  	if (data_size < mRequestedBytes)  	{ -		if (status == 499 || status == 503) +		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)  		{ //timeout or service unavailable, try again  			llwarns << "Timeout or service unavailable, retrying." << llendl;  			LLMeshRepository::sHTTPRetryCount++; @@ -1928,8 +1930,8 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,  		}  		else  		{ -			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint -			llwarns << "Unhandled status " << status << llendl; +			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint +			llwarns << "Unhandled status " << dumpResponse() << llendl;  		}  		return;  	} @@ -1963,10 +1965,10 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,  	delete [] data;  } -void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshSkinInfoResponder::completedRaw(const LLChannelDescriptors& channels, +										   const LLIOPipe::buffer_ptr_t& buffer)  { +	S32 status = getStatus();  	mProcessed = true;  	// thread could have already be destroyed during logout @@ -1977,14 +1979,15 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason  	S32 data_size = buffer->countAfter(channels.in(), NULL); +	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?  	if (status < 200 || status > 400)  	{ -		llwarns << status << ": " << reason << llendl; +		llwarns << dumpResponse() << llendl;  	}  	if (data_size < mRequestedBytes)  	{ -		if (status == 499 || status == 503) +		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)  		{ //timeout or service unavailable, try again  			llwarns << "Timeout or service unavailable, retrying." << llendl;  			LLMeshRepository::sHTTPRetryCount++; @@ -1992,8 +1995,8 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason  		}  		else  		{ -			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint -			llwarns << "Unhandled status " << status << llendl; +			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint +			llwarns << "Unhandled status " << dumpResponse() << llendl;  		}  		return;  	} @@ -2027,10 +2030,10 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason  	delete [] data;  } -void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshDecompositionResponder::completedRaw(const LLChannelDescriptors& channels, +												const LLIOPipe::buffer_ptr_t& buffer)  { +	S32 status = getStatus();  	mProcessed = true;  	if( !gMeshRepo.mThread ) @@ -2040,14 +2043,15 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r  	S32 data_size = buffer->countAfter(channels.in(), NULL); +	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?  	if (status < 200 || status > 400)  	{ -		llwarns << status << ": " << reason << llendl; +		llwarns << dumpResponse() << llendl;  	}  	if (data_size < mRequestedBytes)  	{ -		if (status == 499 || status == 503) +		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)  		{ //timeout or service unavailable, try again  			llwarns << "Timeout or service unavailable, retrying." << llendl;  			LLMeshRepository::sHTTPRetryCount++; @@ -2055,8 +2059,8 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r  		}  		else  		{ -			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint -			llwarns << "Unhandled status " << status << llendl; +			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint +			llwarns << "Unhandled status " << dumpResponse() << llendl;  		}  		return;  	} @@ -2090,10 +2094,10 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r  	delete [] data;  } -void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshPhysicsShapeResponder::completedRaw(const LLChannelDescriptors& channels, +											   const LLIOPipe::buffer_ptr_t& buffer)  { +	S32 status = getStatus();  	mProcessed = true;  	// thread could have already be destroyed during logout @@ -2104,14 +2108,15 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re  	S32 data_size = buffer->countAfter(channels.in(), NULL); +	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?  	if (status < 200 || status > 400)  	{ -		llwarns << status << ": " << reason << llendl; +		llwarns << dumpResponse() << llendl;  	}  	if (data_size < mRequestedBytes)  	{ -		if (status == 499 || status == 503) +		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)  		{ //timeout or service unavailable, try again  			llwarns << "Timeout or service unavailable, retrying." << llendl;  			LLMeshRepository::sHTTPRetryCount++; @@ -2119,8 +2124,8 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re  		}  		else  		{ -			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint -			llwarns << "Unhandled status " << status << llendl; +			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint +			llwarns << "Unhandled status " << dumpResponse() << llendl;  		}  		return;  	} @@ -2154,10 +2159,10 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re  	delete [] data;  } -void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshHeaderResponder::completedRaw(const LLChannelDescriptors& channels, +										 const LLIOPipe::buffer_ptr_t& buffer)  { +	S32 status = getStatus();  	mProcessed = true;  	// thread could have already be destroyed during logout @@ -2166,6 +2171,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,  		return;  	} +	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?  	if (status < 200 || status > 400)  	{  		//llwarns @@ -2179,9 +2185,9 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,  		// and (somewhat more optional than the others) retries  		// again after some set period of time -		llassert(status == 503 || status == 499); +		llassert(status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_INTERNAL_ERROR); -		if (status == 503 || status == 499) +		if (status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_INTERNAL_ERROR)  		{ //retry  			llwarns << "Timeout or service unavailable, retrying." << llendl;  			LLMeshRepository::sHTTPRetryCount++; @@ -2193,7 +2199,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,  		}  		else  		{ -			llwarns << "Unhandled status." << llendl; +			llwarns << "Unhandled status " << dumpResponse() << llendl;  		}  	} @@ -2215,9 +2221,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,  	if (!success)  	{ -		llwarns -			<< "Unable to parse mesh header: " -			<< status << ": " << reason << llendl; +		llwarns << "Unable to parse mesh header: " << dumpResponse() << llendl;  	}  	else if (data && data_size > 0)  	{ diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 862e4be203..4f5e07c566 100755 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -95,15 +95,11 @@ class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder  {  	LOG_CLASS(LLClassifiedClickMessageResponder); -public: +protected:  	// If we get back an error (not found, etc...), handle it here -	virtual void errorWithContent( -		U32 status, -		const std::string& reason, -		const LLSD& content) +	virtual void httpFailure()  	{ -		llwarns << "Sending click message failed (" << status << "): [" << reason << "]" << llendl; -		llwarns << "Content: [" << content << "]" << llendl; +		llwarns << "Sending click message failed " << dumpResponse() << llendl;  	}  }; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index e71dba5cae..582998c973 100755 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1079,10 +1079,10 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)          if (force_save_as)          { -                // the name of the wearable has changed, re-save wearable with new name -                LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID()); +			// the name of the wearable has changed, re-save wearable with new name +			LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID(),gAgentAvatarp->mEndCustomizeCallback);  			gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, description, FALSE); -                mNameEditor->setText(mWearableItem->getName()); +			mNameEditor->setText(mWearableItem->getName());          }          else          { @@ -1092,17 +1092,19 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)  			if (link_item)  			{  				// Create new link -				link_inventory_item( gAgent.getID(), -									 link_item->getLinkedUUID(), -									 LLAppearanceMgr::instance().getCOF(), -									 link_item->getName(), -									 description, -									 LLAssetType::AT_LINK, -									 NULL); +				LL_DEBUGS("Avatar") << "link refresh, creating new link to " << link_item->getLinkedUUID() +									<< " removing old link at " << link_item->getUUID() +									<< " wearable item id " << mWearablePtr->getItemID() << llendl; + +				LLInventoryObject::const_object_list_t obj_array; +				obj_array.push_back(LLConstPointer<LLInventoryObject>(link_item)); +				link_inventory_array(LLAppearanceMgr::instance().getCOF(), +									 obj_array,  +									 gAgentAvatarp->mEndCustomizeCallback);  				// Remove old link -				gInventory.purgeObject(link_item->getUUID()); +				remove_inventory_item(link_item->getUUID(), gAgentAvatarp->mEndCustomizeCallback);  			} -                gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name); +			gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name);          } diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 88400e4ef2..d1a18fdc8c 100755 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -527,7 +527,7 @@ void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id)  }  // virtual -void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason) +void LLLandmarksPanel::setErrorStatus(S32 status, const std::string& reason)  {  	llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;  } diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 8fae0f0b67..a39338304c 100755 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -106,7 +106,7 @@ protected:  	//LLRemoteParcelInfoObserver interface  	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);  	/*virtual*/ void setParcelID(const LLUUID& parcel_id); -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);  private:  	void initFavoritesInventoryPanel(); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 911ecaad9d..3ce066aa3c 100755 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -432,7 +432,7 @@ void LLPanelLogin::showLoginWidgets()  		sInstance->reshapeBrowser();  		// *TODO: Append all the usual login parameters, like first_login=Y etc.  		std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); -		web_browser->navigateTo( splash_screen_url, "text/html" ); +		web_browser->navigateTo( splash_screen_url, HTTP_CONTENT_TEXT_HTML );  		LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo");  		username_combo->setFocus(TRUE);  	} @@ -786,7 +786,7 @@ void LLPanelLogin::loadLoginPage()  	if (web_browser->getCurrentNavUrl() != login_uri.asString())  	{  		LL_DEBUGS("AppInit") << "loading:    " << login_uri << LL_ENDL; -		web_browser->navigateTo( login_uri.asString(), "text/html" ); +		web_browser->navigateTo( login_uri.asString(), HTTP_CONTENT_TEXT_HTML );  	}  } diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index c09d4393c8..0e3057dcad 100755 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1184,12 +1184,12 @@ BOOL LLPanelOutfitEdit::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  			 * second argument is used to delay the appearance update until all dragged items  			 * are added to optimize user experience.  			 */ -			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), false); +			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID());  		}  		else  		{  			// if asset id is not available for the item we must wear it immediately (attachments only) -			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), true); +			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), new LLUpdateAppearanceAndEditWearableOnDestroy(item->getUUID()));  		}  	} diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index f90236f6f2..21b77ef471 100755 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -76,7 +76,8 @@ BOOL LLPanelOutfitsInventory::postBuild()  	// Fetch your outfits folder so that the links are in memory.  	// ( This is only necessary if we want to show a warning if a user deletes an item that has a  	// a link in an outfit, see "ConfirmItemDeleteHasLinks". ) -	const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTFIT, false); + +	const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);  	if (outfits_cat.notNull())  	{  		LLInventoryModelBackgroundFetch::instance().start(outfits_cat); @@ -183,7 +184,7 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD&  		LLStringUtil::trim(outfit_name);  		if( !outfit_name.empty() )  		{ -			LLUUID outfit_folder = LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name); +			LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name);  			LLSidepanelAppearance* panel_appearance = getAppearanceSP();  			if (panel_appearance) diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 3c1f14759c..7a8bd66fcf 100755 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -86,7 +86,7 @@ public:  	//This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing  	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);  	/*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; } -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason) {}; +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {};  protected: diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index 4ae0c0eb12..4e7c5f6ed2 100755 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -169,15 +169,15 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLUUID& region_id,  }  // virtual -void LLPanelPlaceInfo::setErrorStatus(U32 status, const std::string& reason) +void LLPanelPlaceInfo::setErrorStatus(S32 status, const std::string& reason)  {  	// We only really handle 404 and 499 errors  	std::string error_text; -	if(status == 404) +	if(status == HTTP_NOT_FOUND)  	{  		error_text = getString("server_error_text");  	} -	else if(status == 499) +	else if(status == HTTP_INTERNAL_ERROR)  	{  		error_text = getString("server_forbidden_text");  	} diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 64f0b6b550..30327378ef 100755 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -86,7 +86,7 @@ public:  	void displayParcelInfo(const LLUUID& region_id,  						   const LLVector3d& pos_global); -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);  	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 6c2a01fc82..730df2ea23 100755 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -217,7 +217,7 @@ public:  			LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);  		}  	} -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason) +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason)  	{  		llerrs << "Can't complete remote parcel request. Http Status: "  			   << status << ". Reason : " << reason << llendl; diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index c277359133..a9c755de35 100755 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -103,17 +103,16 @@ LLHTTPRegistration<LLAgentStateChangeNode> gHTTPRegistrationAgentStateChangeNode  class NavMeshStatusResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(NavMeshStatusResponder);  public: -	NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly); +	NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly);  	virtual ~NavMeshStatusResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string    mCapabilityURL;  	LLViewerRegion *mRegion;  	LLUUID         mRegionUUID;  	bool           mIsGetStatusOnly; @@ -125,17 +124,16 @@ private:  class NavMeshResponder : public LLHTTPClient::Responder  { +    LOG_CLASS(NavMeshResponder);  public: -	NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); +	NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr);  	virtual ~NavMeshResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string             mCapabilityURL;  	U32                     mNavMeshVersion;  	LLPathfindingNavMeshPtr mNavMeshPtr;  }; @@ -146,17 +144,14 @@ private:  class AgentStateResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(AgentStateResponder);  public: -	AgentStateResponder(const std::string &pCapabilityURL); +	AgentStateResponder();  	virtual ~AgentStateResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); -  protected: - -private: -	std::string mCapabilityURL; +	virtual void httpSuccess(); +	virtual void httpFailure();  }; @@ -165,17 +160,16 @@ private:  //---------------------------------------------------------------------------  class NavMeshRebakeResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(NavMeshRebakeResponder);  public: -	NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); +	NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback);  	virtual ~NavMeshRebakeResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string                                     mCapabilityURL;  	LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback;  }; @@ -190,11 +184,9 @@ public:  	virtual ~LinksetsResponder();  	void handleObjectLinksetsResult(const LLSD &pContent); -	void handleObjectLinksetsError(U32 pStatus, const std::string &pReason,  -								   const LLSD& pContent, const std::string &pURL); +	void handleObjectLinksetsError();  	void handleTerrainLinksetsResult(const LLSD &pContent); -	void handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, -									const LLSD& pContent, const std::string &pURL); +	void handleTerrainLinksetsError();  protected: @@ -227,17 +219,16 @@ typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr;  class ObjectLinksetsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(ObjectLinksetsResponder);  public: -	ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); +	ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr);  	virtual ~ObjectLinksetsResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string          mCapabilityURL;  	LinksetsResponderPtr mLinksetsResponsderPtr;  }; @@ -247,17 +238,16 @@ private:  class TerrainLinksetsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(TerrainLinksetsResponder);  public: -	TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); +	TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr);  	virtual ~TerrainLinksetsResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string          mCapabilityURL;  	LinksetsResponderPtr mLinksetsResponsderPtr;  }; @@ -267,17 +257,16 @@ private:  class CharactersResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(TerrainLinksetsResponder);  public: -	CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); +	CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback);  	virtual ~CharactersResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string                                     mCapabilityURL;  	LLPathfindingManager::request_id_t              mRequestId;  	LLPathfindingManager::object_request_callback_t mCharactersCallback;  }; @@ -364,7 +353,7 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b  		std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion);  		llassert(!navMeshStatusURL.empty());  		navMeshPtr->handleNavMeshCheckVersion(); -		LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion, pIsGetStatusOnly); +		LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly);  		LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder);  	}  } @@ -398,12 +387,12 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re  			bool doRequestTerrain = isAllowViewTerrainProperties();  			LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); -			LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); +			LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr);  			LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder);  			if (doRequestTerrain)  			{ -				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); +				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr);  				LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder);  			}  		} @@ -447,13 +436,13 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP  			if (!objectPostData.isUndefined())  			{ -				LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); +				LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr);  				LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder);  			}  			if (!terrainPostData.isUndefined())  			{ -				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); +				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr);  				LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder);  			}  		} @@ -486,7 +475,7 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_  		{  			pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); -			LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(charactersURL, pRequestId, pCharactersCallback); +			LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback);  			LLHTTPClient::get(charactersURL, charactersResponder);  		}  	} @@ -519,7 +508,7 @@ void LLPathfindingManager::requestGetAgentState()  		{  			std::string agentStateURL = getAgentStateURLForRegion(currentRegion);  			llassert(!agentStateURL.empty()); -			LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL); +			LLHTTPClient::ResponderPtr responder = new AgentStateResponder();  			LLHTTPClient::get(agentStateURL, responder);  		}  	} @@ -543,7 +532,7 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak  		llassert(!navMeshStatusURL.empty());  		LLSD postData;			  		postData["command"] = "rebuild"; -		LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(navMeshStatusURL, pRebakeNavMeshCallback); +		LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback);  		LLHTTPClient::post(navMeshStatusURL, postData, responder);  	}  } @@ -565,7 +554,7 @@ void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPt  		else  		{  			navMeshPtr->handleNavMeshStart(pNavMeshStatus); -			LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshStatus.getVersion(), navMeshPtr); +			LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr);  			LLSD postData;  			LLHTTPClient::post(navMeshURL, postData, responder); @@ -779,9 +768,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c  // NavMeshStatusResponder  //--------------------------------------------------------------------------- -NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly) +NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mRegion(pRegion),  	mRegionUUID(),  	mIsGetStatusOnly(pIsGetStatusOnly) @@ -796,15 +784,15 @@ NavMeshStatusResponder::~NavMeshStatusResponder()  {  } -void NavMeshStatusResponder::result(const LLSD &pContent) +void NavMeshStatusResponder::httpSuccess()  { -	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, pContent); +	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent());  	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly);  } -void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void NavMeshStatusResponder::httpFailure()  { -	llwarns << "NavMeshStatusResponder error [status:" << pStatus << "]: " << pContent << llendl; +	llwarns << dumpResponse() << llendl;  	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID);  	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly);  } @@ -813,9 +801,8 @@ void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pR  // NavMeshResponder  //--------------------------------------------------------------------------- -NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) +NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mNavMeshVersion(pNavMeshVersion),  	mNavMeshPtr(pNavMeshPtr)  { @@ -825,23 +812,23 @@ NavMeshResponder::~NavMeshResponder()  {  } -void NavMeshResponder::result(const LLSD &pContent) +void NavMeshResponder::httpSuccess()  { -	mNavMeshPtr->handleNavMeshResult(pContent, mNavMeshVersion); +	mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion);  } -void NavMeshResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void NavMeshResponder::httpFailure()  { -	mNavMeshPtr->handleNavMeshError(pStatus, pReason, pContent, mCapabilityURL, mNavMeshVersion); +	llwarns << dumpResponse() << llendl; +	mNavMeshPtr->handleNavMeshError(mNavMeshVersion);  }  //---------------------------------------------------------------------------  // AgentStateResponder  //--------------------------------------------------------------------------- -AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL) +AgentStateResponder::AgentStateResponder()  : LLHTTPClient::Responder() -, mCapabilityURL(pCapabilityURL)  {  } @@ -849,17 +836,18 @@ AgentStateResponder::~AgentStateResponder()  {  } -void AgentStateResponder::result(const LLSD &pContent) +void AgentStateResponder::httpSuccess()  { +	const LLSD& pContent = getContent();  	llassert(pContent.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD));  	llassert(pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean());  	BOOL canRebakeRegion = pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean();  	LLPathfindingManager::getInstance()->handleAgentState(canRebakeRegion);  } -void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void AgentStateResponder::httpFailure()  { -	llwarns << "AgentStateResponder error [status:" << pStatus << "]: " << pContent << llendl; +	llwarns << dumpResponse() << llendl;  	LLPathfindingManager::getInstance()->handleAgentState(FALSE);  } @@ -867,9 +855,8 @@ void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReas  //---------------------------------------------------------------------------  // navmesh rebake responder  //--------------------------------------------------------------------------- -NavMeshRebakeResponder::NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) +NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mRebakeNavMeshCallback(pRebakeNavMeshCallback)  {  } @@ -878,14 +865,14 @@ NavMeshRebakeResponder::~NavMeshRebakeResponder()  {  } -void NavMeshRebakeResponder::result(const LLSD &pContent) +void NavMeshRebakeResponder::httpSuccess()  {  	mRebakeNavMeshCallback(true);  } -void NavMeshRebakeResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void NavMeshRebakeResponder::httpFailure()  { -	llwarns << "NavMeshRebakeResponder error [status:" << pStatus << "]: " << pContent << llendl; +	llwarns << dumpResponse() << llendl;  	mRebakeNavMeshCallback(false);  } @@ -918,11 +905,8 @@ void LinksetsResponder::handleObjectLinksetsResult(const LLSD &pContent)  	}  } -void LinksetsResponder::handleObjectLinksetsError(U32 pStatus, const std::string &pReason, -												 const LLSD& pContent, const std::string &pURL) +void LinksetsResponder::handleObjectLinksetsError()  { -	llwarns << "LinksetsResponder object linksets error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << llendl;  	mObjectMessagingState = kReceivedError;  	if (mTerrainMessagingState != kWaiting)  	{ @@ -941,11 +925,8 @@ void LinksetsResponder::handleTerrainLinksetsResult(const LLSD &pContent)  	}  } -void LinksetsResponder::handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, -												   const LLSD& pContent, const std::string &pURL) +void LinksetsResponder::handleTerrainLinksetsError()  { -	llwarns << "LinksetsResponder terrain linksets error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << llendl;  	mTerrainMessagingState = kReceivedError;  	if (mObjectMessagingState != kWaiting)  	{ @@ -979,9 +960,8 @@ void LinksetsResponder::sendCallback()  // ObjectLinksetsResponder  //--------------------------------------------------------------------------- -ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mLinksetsResponsderPtr(pLinksetsResponsderPtr)  {  } @@ -990,23 +970,23 @@ ObjectLinksetsResponder::~ObjectLinksetsResponder()  {  } -void ObjectLinksetsResponder::result(const LLSD &pContent) +void ObjectLinksetsResponder::httpSuccess()  { -	mLinksetsResponsderPtr->handleObjectLinksetsResult(pContent); +	mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent());  } -void ObjectLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void ObjectLinksetsResponder::httpFailure()  { -	mLinksetsResponsderPtr->handleObjectLinksetsError(pStatus, pReason, pContent, mCapabilityURL); +	llwarns << dumpResponse() << llendl; +	mLinksetsResponsderPtr->handleObjectLinksetsError();  }  //---------------------------------------------------------------------------  // TerrainLinksetsResponder  //--------------------------------------------------------------------------- -TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mLinksetsResponsderPtr(pLinksetsResponsderPtr)  {  } @@ -1015,23 +995,23 @@ TerrainLinksetsResponder::~TerrainLinksetsResponder()  {  } -void TerrainLinksetsResponder::result(const LLSD &pContent) +void TerrainLinksetsResponder::httpSuccess()  { -	mLinksetsResponsderPtr->handleTerrainLinksetsResult(pContent); +	mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent());  } -void TerrainLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void TerrainLinksetsResponder::httpFailure()  { -	mLinksetsResponsderPtr->handleTerrainLinksetsError(pStatus, pReason, pContent, mCapabilityURL); +	llwarns << dumpResponse() << llendl; +	mLinksetsResponsderPtr->handleTerrainLinksetsError();  }  //---------------------------------------------------------------------------  // CharactersResponder  //--------------------------------------------------------------------------- -CharactersResponder::CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) +CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mRequestId(pRequestId),  	mCharactersCallback(pCharactersCallback)  { @@ -1041,15 +1021,15 @@ CharactersResponder::~CharactersResponder()  {  } -void CharactersResponder::result(const LLSD &pContent) +void CharactersResponder::httpSuccess()  { -	LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(pContent)); +	LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent()));  	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr);  } -void CharactersResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void CharactersResponder::httpFailure()  { -	llwarns << "CharactersResponder error [status:" << pStatus << "]: " << pContent << llendl; +	llwarns << dumpResponse() << llendl;  	LLPathfindingObjectListPtr characterListPtr =  LLPathfindingObjectListPtr(new LLPathfindingCharacterList());  	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr); diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp index 0c23e5ac92..555105cf40 100755 --- a/indra/newview/llpathfindingnavmesh.cpp +++ b/indra/newview/llpathfindingnavmesh.cpp @@ -184,10 +184,8 @@ void LLPathfindingNavMesh::handleNavMeshError()  	setRequestStatus(kNavMeshRequestError);  } -void LLPathfindingNavMesh::handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion) +void LLPathfindingNavMesh::handleNavMeshError(U32 pNavMeshVersion)  { -	llwarns << "LLPathfindingNavMesh error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << llendl;  	if (mNavMeshStatus.getVersion() == pNavMeshVersion)  	{  		handleNavMeshError(); diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h index b872ccad7c..87f32b8d56 100755 --- a/indra/newview/llpathfindingnavmesh.h +++ b/indra/newview/llpathfindingnavmesh.h @@ -74,7 +74,7 @@ public:  	void handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion);  	void handleNavMeshNotEnabled();  	void handleNavMeshError(); -	void handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion); +	void handleNavMeshError(U32 pNavMeshVersion);  protected: diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index 04934b13f1..452efad291 100755 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -401,13 +401,6 @@ void LLPreview::onDiscardBtn(void* data)  	self->mForceClose = TRUE;  	self->closeFloater(); -	// Delete the item entirely -	/* -	item->removeFromServer(); -	gInventory.deleteObject(item->getUUID()); -	gInventory.notifyObservers(); -	*/ -  	// Move the item to the trash  	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);  	if (item->getParentUUID() != trash_id) diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index 1390000fc5..94a6389f8a 100755 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -35,18 +35,24 @@  class LLProductInfoRequestResponder : public LLHTTPClient::Responder  { -public: +	LOG_CLASS(LLProductInfoRequestResponder); +private:  	//If we get back a normal response, handle it here -	virtual void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{ -		LLProductInfoRequestManager::instance().setSkuDescriptions(content); +		const LLSD& content = getContent(); +		if (!content.isArray()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		} +		LLProductInfoRequestManager::instance().setSkuDescriptions(getContent());  	}  	//If we get back an error (not found, etc...), handle it here -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	/* virtual */ void httpFailure()  	{ -		llwarns << "LLProductInfoRequest error [status:" -				<< status << ":] " << content << llendl; +		llwarns << dumpResponse() << llendl;  	}  }; diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 500dec7ee5..7418bbf615 100755 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -47,9 +47,15 @@ LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle<LLRemote  //If we get back a normal response, handle it here  //virtual -void LLRemoteParcelRequestResponder::result(const LLSD& content) +void LLRemoteParcelRequestResponder::httpSuccess()  { -	LLUUID parcel_id = content["parcel_id"]; +	const LLSD& content = getContent(); +	if (!content.isMap() || !content.has("parcel_id")) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +	LLUUID parcel_id = getContent()["parcel_id"];  	// Panel inspecting the information may be closed and destroyed  	// before this response is received. @@ -62,17 +68,16 @@ void LLRemoteParcelRequestResponder::result(const LLSD& content)  //If we get back an error (not found, etc...), handle it here  //virtual -void LLRemoteParcelRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLRemoteParcelRequestResponder::httpFailure()  { -	llwarns << "LLRemoteParcelRequest error [status:" -			<< status << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  	// Panel inspecting the information may be closed and destroyed  	// before this response is received.  	LLRemoteParcelInfoObserver* observer = mObserverHandle.get();  	if (observer)  	{ -		observer->setErrorStatus(status, reason); +		observer->setErrorStatus(getStatus(), getReason());  	}  } diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index b87056573b..0f8ae41d76 100755 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -37,16 +37,17 @@ class LLRemoteParcelInfoObserver;  class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLRemoteParcelRequestResponder);  public:  	LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle); +private:  	//If we get back a normal response, handle it here -	/*virtual*/ void result(const LLSD& content); +	/*virtual*/ void httpSuccess();  	//If we get back an error (not found, etc...), handle it here -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +	/*virtual*/ void httpFailure(); -protected:  	LLHandle<LLRemoteParcelInfoObserver> mObserverHandle;  }; @@ -78,7 +79,7 @@ public:  	virtual ~LLRemoteParcelInfoObserver() {}  	virtual void processParcelInfo(const LLParcelData& parcel_data) = 0;  	virtual void setParcelID(const LLUUID& parcel_id) = 0; -	virtual void setErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setErrorStatus(S32 status, const std::string& reason) = 0;  	LLHandle<LLRemoteParcelInfoObserver>	getObserverHandle() const { return mObserverHandle; }  protected: diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index df413ab849..e5637bcaf7 100755 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -452,7 +452,7 @@ void LLSidepanelAppearance::editWearable(LLViewerWearable *wearable, LLView *dat  	LLFloaterSidePanelContainer::showPanel("appearance", LLSD());  	LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(data);  	if (panel) -	{ +	{	  		panel->showWearableEditPanel(wearable, disable_camera_switch);  	}  } diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index a4582071e8..bf209df863 100755 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -268,21 +268,23 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id)  class ModerationResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(ModerationResponder);  public:  	ModerationResponder(const LLUUID& session_id)  	{  		mSessionID = session_id;  	} -	virtual void error(U32 status, const std::string& reason) +protected: +	virtual void httpFailure()  	{ -		llwarns << status << ": " << reason << llendl; +		llwarns << dumpResponse() << llendl;;  		if ( gIMMgr )  		{  			//403 == you're not a mod  			//should be disabled if you're not a moderator -			if ( 403 == status ) +			if ( HTTP_FORBIDDEN == getStatus() )  			{  				gIMMgr->showSessionEventError(  											  "mute", @@ -853,10 +855,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)  		}  	}  } -/*prep# -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -		llwarns << "ModerationResponder error [status:" << status << "]: " << content << llendl; -		*/ +  void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)  {  	LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 67a76460a7..1c9276bab9 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1287,6 +1287,8 @@ bool idle_startup()  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);  		LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; +		LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " +		<< gFirstSimSeedCap << LL_ENDL;  		regionp->setSeedCapability(gFirstSimSeedCap);  		LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;  		display_startup(); @@ -2617,10 +2619,10 @@ void LLStartUp::saveInitialOutfit()  	if (sWearablesLoadedCon.connected())  	{ -		lldebugs << "sWearablesLoadedCon is connected, disconnecting" << llendl; +		LL_DEBUGS("Avatar") << "sWearablesLoadedCon is connected, disconnecting" << llendl;  		sWearablesLoadedCon.disconnect();  	} -	lldebugs << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << llendl; +	LL_DEBUGS("Avatar") << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << llendl;  	LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);  } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 6173e76a35..70e2c0f2dc 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2000&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, 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 @@ -36,7 +36,7 @@  #include "lldir.h"  #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llimage.h"  #include "llimagej2c.h"  #include "llimageworker.h" @@ -63,6 +63,8 @@  #include "bufferarray.h"  #include "bufferstream.h" +#include "llhttpretrypolicy.h" +  bool LLTextureFetchDebugger::sDebuggerEnabled = false ;  LLStat LLTextureFetch::sCacheHitRate("texture_cache_hits", 128);  LLStat LLTextureFetch::sCacheReadLatency("texture_cache_read_latency", 128); @@ -244,6 +246,25 @@ static const S32 HTTP_REQUESTS_IN_QUEUE_LOW_WATER = 20;			// Active level at whi  ////////////////////////////////////////////////////////////////////////////// +static const char* e_state_name[] = +{ +	"INVALID", +	"INIT", +	"LOAD_FROM_TEXTURE_CACHE", +	"CACHE_POST", +	"LOAD_FROM_NETWORK", +	"LOAD_FROM_SIMULATOR", +	"WAIT_HTTP_RESOURCE", +	"WAIT_HTTP_RESOURCE2", +	"SEND_HTTP_REQ", +	"WAIT_HTTP_REQ", +	"DECODE_IMAGE", +	"DECODE_IMAGE_UPDATE", +	"WRITE_TO_CACHE", +	"WAIT_ON_WRITE", +	"DONE" +}; +  class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler  { @@ -382,12 +403,14 @@ public:  	void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }  	bool getCanUseHTTP() const { return mCanUseHTTP; } +	void setUrl(const std::string& url) { mUrl = url; } +  	LLTextureFetch & getFetcher() { return *mFetcher; }  	// Inherited from LLCore::HttpHandler  	// Threads:  Ttf  	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); -	 +  protected:  	LLTextureFetchWorker(LLTextureFetch* fetcher, FTType f_type,  						 const std::string& url, const LLUUID& id, const LLHost& host, @@ -547,6 +570,8 @@ private:  	S32 mActiveCount;  	LLCore::HttpStatus mGetStatus;  	std::string mGetReason; +	LLAdaptiveRetryPolicy mFetchRetryPolicy; +  	// Work Data  	LLMutex mWorkMutex; @@ -889,7 +914,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,  	  mHttpHasResource(false),  	  mCacheReadCount(0U),  	  mCacheWriteCount(0U), -	  mResourceWaitCount(0U) +	  mResourceWaitCount(0U), +	  mFetchRetryPolicy(10.0,3600.0,2.0,10)  {  	mCanUseNET = mUrl.empty() ; @@ -1148,6 +1174,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  		mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE  		LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)  							 << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; +  		// fall through  	} @@ -1270,6 +1297,21 @@ bool LLTextureFetchWorker::doWork(S32 param)  	if (mState == LOAD_FROM_NETWORK)  	{ +		// Check for retries to previous server failures. +		F32 wait_seconds; +		if (mFetchRetryPolicy.shouldRetry(wait_seconds)) +		{ +			if (wait_seconds <= 0.0) +			{ +				llinfos << mID << " retrying now" << llendl; +			} +			else +			{ +				//llinfos << mID << " waiting to retry for " << wait_seconds << " seconds" << llendl; +				return false; +			} +		} +  		static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP");  // 		if (mHost != LLHost::invalid) get_url = false; @@ -1286,7 +1328,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  				std::string http_url = region->getHttpUrl() ;  				if (!http_url.empty())  				{ -					mUrl = http_url + "/?texture_id=" + mID.asString().c_str(); +					setUrl(http_url + "/?texture_id=" + mID.asString().c_str());  					mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.  				}  				else @@ -1340,7 +1382,6 @@ bool LLTextureFetchWorker::doWork(S32 param)  			//recordTextureStart(false);  			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); -			LL_DEBUGS("Texture") << mID << " does this happen?" << llendl;  			return false;  		}  	} @@ -1482,12 +1523,14 @@ bool LLTextureFetchWorker::doWork(S32 param)  								 << LL_ENDL;  			// Will call callbackHttpGet when curl request completes +			// Only server bake images use the returned headers currently, for getting retry-after field. +			LLCore::HttpOptions *options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions;  			mHttpHandle = mFetcher->mHttpRequest->requestGetByteRange(mHttpPolicyClass,  																	  mWorkPriority,  																	  mUrl,  																	  mRequestedOffset,  																	  mRequestedSize, -																	  mFetcher->mHttpOptions, +																	  options,  																	  mFetcher->mHttpHeaders,  																	  this);  		} @@ -1519,15 +1562,22 @@ bool LLTextureFetchWorker::doWork(S32 param)  			{  				if (http_not_found == mGetStatus)  				{ -					if(mWriteToCacheState == NOT_WRITE) //map tiles +					if (mFTType != FTT_MAP_TILE) +					{ +						llwarns << "Texture missing from server (404): " << mUrl << llendl; +					} + +					if(mWriteToCacheState == NOT_WRITE) //map tiles or server bakes  					{  						setState(DONE);  						releaseHttpSemaphore(); -						LL_DEBUGS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << llendl; -						return true; // failed, means no map tile on the empty region. +						if (mFTType != FTT_MAP_TILE) +						{ +							LL_WARNS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << llendl; +						} +						return true;   					} -					llwarns << "Texture missing from server (404): " << mUrl << llendl;  					// roll back to try UDP  					if (mCanUseNET) @@ -1543,6 +1593,10 @@ bool LLTextureFetchWorker::doWork(S32 param)  				else if (http_service_unavail == mGetStatus)  				{  					LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; +					llinfos << "503: HTTP GET failed for: " << mUrl +							<< " Status: " << mGetStatus.toHex() +							<< " Reason: '" << mGetReason << "'" +							<< llendl;  				}  				else if (http_not_sat == mGetStatus)  				{ @@ -1551,7 +1605,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  				}  				else  				{ -					llinfos << "HTTP GET failed for: " << mUrl +					llinfos << "other: HTTP GET failed for: " << mUrl  							<< " Status: " << mGetStatus.toHex()  							<< " Reason: '" << mGetReason << "'"  							<< llendl; @@ -1891,14 +1945,48 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe  		mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);  	} +	static LLCachedControl<F32> fake_failure_rate(gSavedSettings, "TextureFetchFakeFailureRate"); +	F32 rand_val = ll_frand(); +	F32 rate = fake_failure_rate; +	if (mFTType == FTT_SERVER_BAKE && (fake_failure_rate > 0.0) && (rand_val < fake_failure_rate)) +	{ +		llwarns << mID << " for debugging, setting fake failure status for texture " << mID +				<< " (rand was " << rand_val << "/" << rate << ")" << llendl; +		response->setStatus(LLCore::HttpStatus(503)); +	}  	bool success = true;  	bool partial = false;  	LLCore::HttpStatus status(response->getStatus()); +	if (!status && (mFTType == FTT_SERVER_BAKE)) +	{ +		llinfos << mID << " state " << e_state_name[mState] << llendl; +		mFetchRetryPolicy.onFailure(response); +		F32 retry_after; +		if (mFetchRetryPolicy.shouldRetry(retry_after)) +		{ +			llinfos << mID << " will retry after " << retry_after << " seconds, resetting state to LOAD_FROM_NETWORK" << llendl; +			mFetcher->removeFromHTTPQueue(mID, 0); +			std::string reason(status.toString()); +			setGetStatus(status, reason); +			releaseHttpSemaphore(); +			setState(LOAD_FROM_NETWORK); +			return; +		} +		else +		{ +			llinfos << mID << " will not retry" << llendl; +		} +	} +	else +	{ +		mFetchRetryPolicy.onSuccess(); +	}  	LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID -			 << " status: " << status.toHex() -			 << " '" << status.toString() << "'" -			 << llendl; +						 << " status: " << status.toHex() +						 << " '" << status.toString() << "'" +						 << llendl; +  //	unsigned int offset(0), length(0), full_length(0);  //	response->getRange(&offset, &length, &full_length);  // 	llwarns << "HTTP COMPLETE: " << mID << " handle: " << handle @@ -1907,13 +1995,16 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe  // 			<< " offset: " << offset << " length: " << length  // 			<< llendl; +	std::string reason(status.toString()); +	setGetStatus(status, reason);  	if (! status)  	{  		success = false; -		std::string reason(status.toString()); -		setGetStatus(status, reason); -		llwarns << "CURL GET FAILED, status: " << status.toHex() -				<< " reason: " << reason << llendl; +		if (mFTType != FTT_MAP_TILE) // missing map tiles are normal, don't complain about them. +		{ +			llwarns << mID << " CURL GET FAILED, status: " << status.toHex() +					<< " reason: " << reason << llendl; +		}  	}  	else  	{ @@ -2376,6 +2467,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image  	  mQAMode(qa_mode),  	  mHttpRequest(NULL),  	  mHttpOptions(NULL), +	  mHttpOptionsWithHeaders(NULL),  	  mHttpHeaders(NULL),  	  mHttpMetricsHeaders(NULL),  	  mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), @@ -2406,10 +2498,13 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image  	mHttpRequest = new LLCore::HttpRequest;  	mHttpOptions = new LLCore::HttpOptions; +	mHttpOptionsWithHeaders = new LLCore::HttpOptions; +	mHttpOptionsWithHeaders->setWantHeaders(true);  	mHttpHeaders = new LLCore::HttpHeaders; -	mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c"); +	// *TODO: Should this be 'image/j2c' instead of 'image/x-j2c' ? +	mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C);  	mHttpMetricsHeaders = new LLCore::HttpHeaders; -	mHttpMetricsHeaders->mHeaders.push_back("Content-Type: application/llsd+xml"); +	mHttpMetricsHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);  	mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicyDefault();  } @@ -2430,6 +2525,12 @@ LLTextureFetch::~LLTextureFetch()  		mHttpOptions = NULL;  	} +	if (mHttpOptionsWithHeaders) +	{ +		mHttpOptionsWithHeaders->release(); +		mHttpOptionsWithHeaders = NULL; +	} +  	if (mHttpHeaders)  	{  		mHttpHeaders->release(); @@ -2464,7 +2565,11 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const  	{  		return false;  	} -	 + +	if (f_type == FTT_SERVER_BAKE) +	{ +		LL_DEBUGS("Avatar") << " requesting " << id << " " << w << "x" << h << " discard " << desired_discard << llendl; +	}  	LLTextureFetchWorker* worker = getWorker(id) ;  	if (worker)  	{ @@ -2522,7 +2627,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const  		worker->mNeedsAux = needs_aux;  		worker->setImagePriority(priority);  		worker->setDesiredDiscard(desired_discard, desired_size); -		worker->setCanUseHTTP(can_use_http) ; +		worker->setCanUseHTTP(can_use_http); +		worker->setUrl(url);  		if (!worker->haveWork())  		{  			worker->setState(LLTextureFetchWorker::INIT); @@ -2549,7 +2655,7 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const  		worker->unlockWorkMutex();										// -Mw  	} - 	LL_DEBUGS("Texture") << "REQUESTED: " << id << " Discard: " << desired_discard << " size " << desired_size << llendl; + 	LL_DEBUGS("Texture") << "REQUESTED: " << id << " f_type " << fttype_to_string(f_type) << " Discard: " << desired_discard << " size " << desired_size << llendl;  	return true;  } @@ -2728,7 +2834,8 @@ LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)  // Threads:  T*  bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, -										LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux) +										LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, +										LLCore::HttpStatus& last_http_get_status)  {  	bool res = false;  	LLTextureFetchWorker* worker = getWorker(id); @@ -2750,6 +2857,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,  		else if (worker->checkWork())  		{  			worker->lockWorkMutex();									// +Mw +			last_http_get_status = worker->mGetStatus;  			discard_level = worker->mDecodedDiscard;  			raw = worker->mRawImage;  			aux = worker->mAuxImage; @@ -3220,25 +3328,14 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size)  void LLTextureFetchWorker::setState(e_state new_state)  { -	static const char* e_state_name[] = -	{ -		"INVALID", -		"INIT", -		"LOAD_FROM_TEXTURE_CACHE", -		"CACHE_POST", -		"LOAD_FROM_NETWORK", -		"LOAD_FROM_SIMULATOR", -		"WAIT_HTTP_RESOURCE", -		"WAIT_HTTP_RESOURCE2", -		"SEND_HTTP_REQ", -		"WAIT_HTTP_REQ", -		"DECODE_IMAGE", -		"DECODE_IMAGE_UPDATE", -		"WRITE_TO_CACHE", -		"WAIT_ON_WRITE", -		"DONE" -	}; -	LL_DEBUGS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << llendl; +	if (mFTType == FTT_SERVER_BAKE) +	{ +	// NOTE: turning on these log statements is a reliable way to get +	// blurry images fairly frequently. Presumably this is an +	// indication of some subtle timing or locking issue. + +//		LL_INFOS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << llendl; +	}  	mState = new_state;  } @@ -4041,7 +4138,8 @@ void LLTextureFetchDebugger::init()  	if (! mHttpHeaders)  	{  		mHttpHeaders = new LLCore::HttpHeaders; -		mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c"); +		// *TODO: Should this be 'image/j2c' instead of 'image/x-j2c' ? +		mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C);  	}  } diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 902a3d7a25..237912cde7 100755 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2000&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, 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 @@ -95,7 +95,8 @@ public:  	// Threads:  T*  	bool getRequestFinished(const LLUUID& id, S32& discard_level, -							LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux); +							LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, +							LLCore::HttpStatus& last_http_get_status);  	// Threads:  T*  	bool updateRequestPriority(const LLUUID& id, F32 priority); @@ -351,6 +352,7 @@ private:  	// LLCurl interfaces used in the past.  	LLCore::HttpRequest *				mHttpRequest;					// Ttf  	LLCore::HttpOptions *				mHttpOptions;					// Ttf +	LLCore::HttpOptions *				mHttpOptionsWithHeaders;		// Ttf  	LLCore::HttpHeaders *				mHttpHeaders;					// Ttf  	LLCore::HttpHeaders *				mHttpMetricsHeaders;			// Ttf  	LLCore::HttpRequest::policy_t		mHttpPolicyClass;				// T* @@ -395,6 +397,9 @@ private:  	e_tex_source mFetchSource;  	e_tex_source mOriginFetchSource; +	// Retry logic +	//LLAdaptiveRetryPolicy mFetchRetryPolicy; +	  public:  	//debug use  	LLTextureFetchDebugger* getFetchDebugger() { return mFetchDebugger;} diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 148e5a015b..71e0509d03 100755 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -54,6 +54,7 @@  #include "llviewercamera.h"  #include "llviewertexturelist.h"  #include "llviewerobject.h" +#include "llviewerwearable.h"  #include "llviewerwindow.h"  #include "llvoavatarself.h"  #include "pipeline.h" @@ -147,13 +148,20 @@ BOOL LLVisualParamHint::needsRender()  void LLVisualParamHint::preRender(BOOL clear_depth)  { +	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; +	if (wearable) +	{ +		wearable->setVolatile(TRUE); +	}  	mLastParamWeight = mVisualParam->getWeight();  	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE);  	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE);  	gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f);  	gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f);  	gAgentAvatarp->updateComposites(); -	gAgentAvatarp->updateVisualParams(); +	// Calling LLCharacter version, as we don't want position/height changes to cause the avatar to jump +	// up and down when we're doing preview renders. -Nyx +	gAgentAvatarp->LLCharacter::updateVisualParams();  	gAgentAvatarp->updateGeometry(gAgentAvatarp->mDrawable);  	gAgentAvatarp->updateLOD(); @@ -239,6 +247,12 @@ BOOL LLVisualParamHint::render()  	}  	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);  	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); +	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; +	if (wearable) +	{ +		wearable->setVolatile(FALSE); +	} +  	gAgentAvatarp->updateVisualParams();  	gGL.color4f(1,1,1,1);  	mGLTexturep->setGLTextureCreated(true); diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index f3d8de1904..ae934d9f5a 100755 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -84,7 +84,7 @@ bool LLGoogleTranslationHandler::parseResponse(  		return false;  	} -	if (status != STATUS_OK) +	if (status != HTTP_OK)  	{  		// Request failed. Extract error message from the response.  		parseErrorResponse(root, status, err_msg); @@ -186,7 +186,7 @@ bool LLBingTranslationHandler::parseResponse(  	std::string& detected_lang,  	std::string& err_msg) const  { -	if (status != STATUS_OK) +	if (status != HTTP_OK)  	{  		static const std::string MSG_BEGIN_MARKER = "Message: ";  		size_t begin = body.find(MSG_BEGIN_MARKER); @@ -251,8 +251,6 @@ LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_la  // virtual  void LLTranslate::TranslationReceiver::completedRaw( -	U32 http_status, -	const std::string& reason,  	const LLChannelDescriptors& channels,  	const LLIOPipe::buffer_ptr_t& buffer)  { @@ -262,8 +260,8 @@ void LLTranslate::TranslationReceiver::completedRaw(  	const std::string body = strstrm.str();  	std::string translation, detected_lang, err_msg; -	int status = http_status; -	LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL; +	int status = getStatus(); +	LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL;  	LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL;  	if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg))  	{ @@ -301,12 +299,10 @@ LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const  // virtual  void LLTranslate::KeyVerificationReceiver::completedRaw( -	U32 http_status, -	const std::string& reason,  	const LLChannelDescriptors& channels,  	const LLIOPipe::buffer_ptr_t& buffer)  { -	bool ok = (http_status == 200); +	bool ok = (getStatus() == HTTP_OK);  	setVerificationStatus(ok);  } @@ -398,8 +394,8 @@ void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr  			LLVersionInfo::getPatch(),  			LLVersionInfo::getBuild()); -		sHeader.insert("Accept", "text/plain"); -		sHeader.insert("User-Agent", user_agent); +		sHeader.insert(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); +		sHeader.insert(HTTP_OUT_HEADER_USER_AGENT, user_agent);  	}  	LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT); diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index db5ad9479c..972274714a 100755 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -95,9 +95,6 @@ public:  	virtual bool isConfigured() const = 0;  	virtual ~LLTranslationAPIHandler() {} - -protected: -	static const int STATUS_OK = 200;  };  /// Google Translate v2 API handler. @@ -201,8 +198,6 @@ public :  		 * @see mHandler  		 */  		/*virtual*/ void completedRaw( -			U32 http_status, -			const std::string& reason,  			const LLChannelDescriptors& channels,  			const LLIOPipe::buffer_ptr_t& buffer); @@ -250,8 +245,6 @@ public :  		 * @see setVerificationStatus()  		 */  		/*virtual*/ void completedRaw( -			U32 http_status, -			const std::string& reason,  			const LLChannelDescriptors& channels,  			const LLIOPipe::buffer_ptr_t& buffer); diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp index 1d777b3f7f..88c48ba0a3 100755 --- a/indra/newview/lluploadfloaterobservers.cpp +++ b/indra/newview/lluploadfloaterobservers.cpp @@ -1,6 +1,6 @@  /**   * @file lluploadfloaterobservers.cpp - * @brief LLUploadModelPremissionsResponder definition + * @brief LLUploadModelPermissionsResponder definition   *   * $LicenseInfo:firstyear=2011&license=viewerlgpl$   * Second Life Viewer Source Code @@ -28,26 +28,31 @@  #include "lluploadfloaterobservers.h" -LLUploadModelPremissionsResponder::LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer) +LLUploadModelPermissionsResponder::LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer)  :mObserverHandle(observer)  {  } -void LLUploadModelPremissionsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLUploadModelPermissionsResponder::httpFailure()  { -	llwarns << "LLUploadModelPremissionsResponder error [status:" -			<< status << "]: " << content << llendl; +	llwarns << dumpResponse() << llendl;  	LLUploadPermissionsObserver* observer = mObserverHandle.get();  	if (observer)  	{ -		observer->setPermissonsErrorStatus(status, reason); +		observer->setPermissonsErrorStatus(getStatus(), getReason());  	}  } -void LLUploadModelPremissionsResponder::result(const LLSD& content) +void LLUploadModelPermissionsResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	LLUploadPermissionsObserver* observer = mObserverHandle.get();  	if (observer) @@ -55,3 +60,4 @@ void LLUploadModelPremissionsResponder::result(const LLSD& content)  		observer->onPermissionsReceived(content);  	}  } + diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index b43ddb44d9..4ff4a827a5 100755 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -1,6 +1,6 @@  /**   * @file lluploadfloaterobservers.h - * @brief LLUploadModelPremissionsResponder declaration + * @brief LLUploadModelPermissionsResponder declaration   *   * $LicenseInfo:firstyear=2011&license=viewerlgpl$   * Second Life Viewer Source Code @@ -39,7 +39,7 @@ public:  	virtual ~LLUploadPermissionsObserver() {}  	virtual void onPermissionsReceived(const LLSD& result) = 0; -	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0;  	LLHandle<LLUploadPermissionsObserver> getPermObserverHandle() const {return mUploadPermObserverHandle;} @@ -54,7 +54,7 @@ public:  	virtual ~LLWholeModelFeeObserver() {}  	virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; -	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0;  	LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; } @@ -80,17 +80,16 @@ protected:  }; -class LLUploadModelPremissionsResponder : public LLHTTPClient::Responder +class LLUploadModelPermissionsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLUploadModelPermissionsResponder);  public: - -	LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer); - -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - -	void result(const LLSD& content); +	LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer);  private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +  	LLHandle<LLUploadPermissionsObserver> mObserverHandle;  }; diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index f81206ffec..3f836efdd3 100755 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -58,12 +58,12 @@ namespace LLViewerDisplayName  class LLSetDisplayNameResponder : public LLHTTPClient::Responder  { -public: +	LOG_CLASS(LLSetDisplayNameResponder); +private:  	// only care about errors -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	/*virtual*/ void httpFailure()  	{ -		llwarns << "LLSetDisplayNameResponder error [status:" -				<< status << "]: " << content << llendl; +		llwarns << dumpResponse() << llendl;  		LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD());  		LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();  	} @@ -86,7 +86,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl  	// People API can return localized error messages.  Indicate our  	// language preference via header.  	LLSD headers; -	headers["Accept-Language"] = LLUI::getLanguage(); +	headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage();  	// People API requires both the old and new value to change a variable.  	// Our display name will be in cache before the viewer's UI is available @@ -128,7 +128,7 @@ public:  		LLSD body = input["body"];  		S32 status = body["status"].asInteger(); -		bool success = (status == 200); +		bool success = (status == HTTP_OK);  		std::string reason = body["reason"].asString();  		LLSD content = body["content"]; @@ -137,7 +137,7 @@ public:  		// If viewer's concept of display name is out-of-date, the set request  		// will fail with 409 Conflict.  If that happens, fetch up-to-date  		// name information. -		if (status == 409) +		if (status == HTTP_CONFLICT)  		{  			LLUUID agent_id = gAgent.getID();  			// Flush stale data diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index a179b61cff..4e028d2163 100755 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -139,14 +139,10 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()  	addEntry(LLFolderType::FT_NONE, 				new ViewerFolderEntry("New Folder",				"Inv_FolderOpen",		"Inv_FolderClosed",		FALSE,     false, "default")); -#if SUPPORT_ENSEMBLES -	initEnsemblesFromFile(); -#else  	for (U32 type = (U32)LLFolderType::FT_ENSEMBLE_START; type <= (U32)LLFolderType::FT_ENSEMBLE_END; ++type)  	{  		addEntry((LLFolderType::EType)type, 		new ViewerFolderEntry("New Folder",				"Inv_FolderOpen",		"Inv_FolderClosed",		FALSE,     false)); -	}	 -#endif +	}  }  bool LLViewerFolderDictionary::initEnsemblesFromFile() diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index fff9821e86..b623b23e1a 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -31,6 +31,7 @@  #include "llsdserialize.h"  #include "message.h" +#include "llaisapi.h"  #include "llagent.h"  #include "llagentcamera.h"  #include "llagentwearables.h" @@ -65,9 +66,12 @@  #include "llavataractions.h"  #include "lllogininstance.h"  #include "llfavoritesbar.h" +#include "llclipboard.h" +#include "llhttpretrypolicy.h" -// Two do-nothing ops for use in callbacks. +// do-nothing ops for use in callbacks.  void no_op_inventory_func(const LLUUID&) {}  +void no_op_llsd_func(const LLSD&) {}  void no_op() {}  ///---------------------------------------------------------------------------- @@ -256,7 +260,6 @@ public:  };  LLInventoryHandler gInventoryHandler; -  ///----------------------------------------------------------------------------  /// Class LLViewerInventoryItem  ///---------------------------------------------------------------------------- @@ -345,24 +348,6 @@ void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& ne  	}  } -void LLViewerInventoryItem::removeFromServer() -{ -	lldebugs << "Removing inventory item " << mUUID << " from server." -			 << llendl; - -	LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); -	gInventory.accountForUpdate(up); - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_RemoveInventoryItem); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());  -	msg->nextBlockFast(_PREHASH_InventoryData); -	msg->addUUIDFast(_PREHASH_ItemID, mUUID); -	gAgent.sendReliableMessage(); -} -  void LLViewerInventoryItem::updateServer(BOOL is_new) const  {  	if(!mIsComplete) @@ -376,7 +361,8 @@ void LLViewerInventoryItem::updateServer(BOOL is_new) const  	if(gAgent.getID() != mPermissions.getOwner())  	{  		// *FIX: deal with this better. -		llwarns << "LLViewerInventoryItem::updateServer() - for unowned item" +		llwarns << "LLViewerInventoryItem::updateServer() - for unowned item " +			    << ll_pretty_print_sd(this->asLLSD())  				<< llendl;  		return;  	} @@ -444,7 +430,7 @@ void LLViewerInventoryItem::fetchFromServer(void) const  }  // virtual -BOOL LLViewerInventoryItem::unpackMessage(LLSD item) +BOOL LLViewerInventoryItem::unpackMessage(const LLSD& item)  {  	BOOL rv = LLInventoryItem::fromLLSD(item); @@ -469,7 +455,7 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_  {  	mTransactionID = transaction_id;  } -// virtual +  void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const  {  	msg->addUUIDFast(_PREHASH_ItemID, mUUID); @@ -488,6 +474,7 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const  	U32 crc = getCRC32();  	msg->addU32Fast(_PREHASH_CRC, crc);  } +  // virtual  BOOL LLViewerInventoryItem::importFile(LLFILE* fp)  { @@ -599,6 +586,15 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego  } +void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const +{ +	msg->addUUIDFast(_PREHASH_FolderID, mUUID); +	msg->addUUIDFast(_PREHASH_ParentID, mParentUUID); +	S8 type = static_cast<S8>(mPreferredType); +	msg->addS8Fast(_PREHASH_Type, type); +	msg->addStringFast(_PREHASH_Name, mName); +} +  void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const  {  	LLMessageSystem* msg = gMessageSystem; @@ -637,30 +633,6 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const  	gAgent.sendReliableMessage();  } -void LLViewerInventoryCategory::removeFromServer( void ) -{ -	llinfos << "Removing inventory category " << mUUID << " from server." -			<< llendl; -	// communicate that change with the server. -	if(LLFolderType::lookupIsProtectedType(mPreferredType)) -	{ -		LLNotificationsUtil::add("CannotRemoveProtectedCategories"); -		return; -	} - -	LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); -	gInventory.accountForUpdate(up); - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_RemoveInventoryFolder); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	msg->nextBlockFast(_PREHASH_FolderData); -	msg->addUUIDFast(_PREHASH_FolderID, mUUID); -	gAgent.sendReliableMessage(); -} -  S32 LLViewerInventoryCategory::getVersion() const  {  	return mVersion; @@ -894,6 +866,21 @@ void LLViewerInventoryCategory::localizeName()  	LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);  } +// virtual +BOOL LLViewerInventoryCategory::unpackMessage(const LLSD& category) +{ +	BOOL rv = LLInventoryCategory::fromLLSD(category); +	localizeName(); +	return rv; +} + +// virtual +void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num) +{ +	LLInventoryCategory::unpackMessage(msg, block, block_num); +	localizeName(); +} +  ///----------------------------------------------------------------------------  /// Local function definitions  ///---------------------------------------------------------------------------- @@ -1087,77 +1074,152 @@ void copy_inventory_item(  	gAgent.sendReliableMessage();  } -void link_inventory_item( -	const LLUUID& agent_id, -	const LLUUID& item_id, -	const LLUUID& parent_id, -	const std::string& new_name, -	const std::string& new_description, -	const LLAssetType::EType asset_type, -	LLPointer<LLInventoryCallback> cb) +// Create link to single inventory object. +void link_inventory_object(const LLUUID& category, +			 LLConstPointer<LLInventoryObject> baseobj, +			 LLPointer<LLInventoryCallback> cb)  { -	const LLInventoryObject *baseobj = gInventory.getObject(item_id);  	if (!baseobj)  	{ -		llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl; -		return; -	} -	if (baseobj && baseobj->getIsLinkType()) -	{ -		llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl; +		llwarns << "Attempt to link to non-existent object" << llendl;  		return;  	} -	if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType())) -	{ -		// Fail if item can be found but is of a type that can't be linked. -		// Arguably should fail if the item can't be found too, but that could -		// be a larger behavioral change. -		llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl; -		return; -	} -	 -	LLUUID transaction_id; -	LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; -	if (dynamic_cast<const LLInventoryCategory *>(baseobj)) -	{ -		inv_type = LLInventoryType::IT_CATEGORY; -	} -	else +	LLInventoryObject::const_object_list_t obj_array; +	obj_array.push_back(baseobj); +	link_inventory_array(category, obj_array, cb); +} + +void link_inventory_object(const LLUUID& category, +			 const LLUUID& id, +			 LLPointer<LLInventoryCallback> cb) +{ +	LLConstPointer<LLInventoryObject> baseobj = gInventory.getObject(id); +	link_inventory_object(category, baseobj, cb); +} + +// Create links to all listed inventory objects. +void link_inventory_array(const LLUUID& category, +			 LLInventoryObject::const_object_list_t& baseobj_array, +			 LLPointer<LLInventoryCallback> cb) +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD +	const LLViewerInventoryCategory *cat = gInventory.getCategory(category); +	const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; +#endif +	LLInventoryObject::const_object_list_t::const_iterator it = baseobj_array.begin(); +	LLInventoryObject::const_object_list_t::const_iterator end = baseobj_array.end(); +	LLSD links = LLSD::emptyArray(); +	for (; it != end; ++it)  	{ -		const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj); -		if (baseitem) +		const LLInventoryObject* baseobj = *it; +		if (!baseobj)  		{ -			inv_type = baseitem->getInventoryType(); +			llwarns << "attempt to link to unknown object" << llendl; +			continue;  		} -	} -#if 1 // debugging stuff -	LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); -	lldebugs << "cat: " << cat << llendl; -	 +		if (!LLAssetType::lookupCanLink(baseobj->getType())) +		{ +			// Fail if item can be found but is of a type that can't be linked. +			// Arguably should fail if the item can't be found too, but that could +			// be a larger behavioral change. +			llwarns << "attempt to link an unlinkable object, type = " << baseobj->getActualType() << llendl; +			continue; +		} +		 +		LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; +		LLAssetType::EType asset_type = LLAssetType::AT_NONE; +		std::string new_desc; +		LLUUID linkee_id; +		if (dynamic_cast<const LLInventoryCategory *>(baseobj)) +		{ +			inv_type = LLInventoryType::IT_CATEGORY; +			asset_type = LLAssetType::AT_LINK_FOLDER; +			linkee_id = baseobj->getUUID(); +		} +		else +		{ +			const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj); +			if (baseitem) +			{ +				inv_type = baseitem->getInventoryType(); +				new_desc = baseitem->getActualDescription(); +				switch (baseitem->getActualType()) +				{ +					case LLAssetType::AT_LINK: +					case LLAssetType::AT_LINK_FOLDER: +						linkee_id = baseobj->getLinkedUUID(); +						asset_type = baseitem->getActualType(); +						break; +					default: +						linkee_id = baseobj->getUUID(); +						asset_type = LLAssetType::AT_LINK; +						break; +				} +			} +			else +			{ +				llwarns << "could not convert object into an item or category: " << baseobj->getUUID() << llendl; +				continue; +			} +		} + +		LLSD link = LLSD::emptyMap(); +		link["linked_id"] = linkee_id; +		link["type"] = (S8)asset_type; +		link["inv_type"] = (S8)inv_type; +		link["name"] = baseobj->getName(); +		link["desc"] = new_desc; +		links.append(link); + +#ifndef LL_RELEASE_FOR_DOWNLOAD +		LL_DEBUGS("Inventory") << "Linking Object [ name:" << baseobj->getName()  +							   << " UUID:" << baseobj->getUUID()  +							   << " ] into Category [ name:" << cat_name  +							   << " UUID:" << category << " ] " << LL_ENDL;  #endif -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_LinkInventoryItem); -	msg->nextBlock(_PREHASH_AgentData); +	} + +	bool ais_ran = false; +	if (AISCommand::isAPIAvailable())  	{ -		msg->addUUIDFast(_PREHASH_AgentID, agent_id); -		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +		LLSD new_inventory = LLSD::emptyMap(); +		new_inventory["links"] = links; +		LLPointer<AISCommand> cmd_ptr = new CreateInventoryCommand(category, new_inventory, cb); +		ais_ran = cmd_ptr->run_command();  	} -	msg->nextBlock(_PREHASH_InventoryBlock); + +	if (!ais_ran)  	{ -		msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); -		msg->addUUIDFast(_PREHASH_FolderID, parent_id); -		msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); -		msg->addUUIDFast(_PREHASH_OldItemID, item_id); -		msg->addS8Fast(_PREHASH_Type, (S8)asset_type); -		msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); -		msg->addStringFast(_PREHASH_Name, new_name); -		msg->addStringFast(_PREHASH_Description, new_description); +		LLMessageSystem* msg = gMessageSystem; +		for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter ) +		{ +			msg->newMessageFast(_PREHASH_LinkInventoryItem); +			msg->nextBlock(_PREHASH_AgentData); +			{ +				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			} +			msg->nextBlock(_PREHASH_InventoryBlock); +			{ +				LLSD link = (*iter); +				msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); +				msg->addUUIDFast(_PREHASH_FolderID, category); +				msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); +				msg->addUUIDFast(_PREHASH_OldItemID, link["linked_id"].asUUID()); +				msg->addS8Fast(_PREHASH_Type, link["type"].asInteger()); +				msg->addS8Fast(_PREHASH_InvType, link["inv_type"].asInteger()); +				msg->addStringFast(_PREHASH_Name, link["name"].asString()); +				msg->addStringFast(_PREHASH_Description, link["desc"].asString()); +			} +			gAgent.sendReliableMessage(); +		}  	} -	gAgent.sendReliableMessage();  } + +  void move_inventory_item(  	const LLUUID& agent_id,  	const LLUUID& session_id, @@ -1179,6 +1241,381 @@ void move_inventory_item(  	gAgent.sendReliableMessage();  } +// Should call this with an update_item that's been copied and +// modified from an original source item, rather than modifying the +// source item directly. +void update_inventory_item( +	LLViewerInventoryItem *update_item, +	LLPointer<LLInventoryCallback> cb) +{ +	const LLUUID& item_id = update_item->getUUID(); +	bool ais_ran = false; +	if (AISCommand::isAPIAvailable()) +	{ +		LLSD updates = update_item->asLLSD(); +		LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); +		ais_ran = cmd_ptr->run_command(); +	} +	if (!ais_ran) +	{ +		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << llendl; +		if(obj) +		{ +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_UpdateInventoryItem); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			msg->addUUIDFast(_PREHASH_TransactionID, update_item->getTransactionID()); +			msg->nextBlockFast(_PREHASH_InventoryData); +			msg->addU32Fast(_PREHASH_CallbackID, 0); +			update_item->packMessage(msg); +			gAgent.sendReliableMessage(); + +			LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(), 0); +			gInventory.accountForUpdate(up); +			gInventory.updateItem(update_item); +			if (cb) +			{ +				cb->fire(item_id); +			} +		} +	} +} + +// Note this only supports updating an existing item. Goes through AISv3 +// code path where available. Not all uses of item->updateServer() can +// easily be switched to this paradigm. +void update_inventory_item( +	const LLUUID& item_id, +	const LLSD& updates, +	LLPointer<LLInventoryCallback> cb) +{ +	bool ais_ran = false; +	if (AISCommand::isAPIAvailable()) +	{ +		LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); +		ais_ran = cmd_ptr->run_command(); +	} +	if (!ais_ran) +	{ +		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl; +		if(obj) +		{ +			LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); +			new_item->copyViewerItem(obj); +			new_item->fromLLSD(updates,false); + +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_UpdateInventoryItem); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID()); +			msg->nextBlockFast(_PREHASH_InventoryData); +			msg->addU32Fast(_PREHASH_CallbackID, 0); +			new_item->packMessage(msg); +			gAgent.sendReliableMessage(); + +			LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0); +			gInventory.accountForUpdate(up); +			gInventory.updateItem(new_item); +			if (cb) +			{ +				cb->fire(item_id); +			} +		} +	} +} + +void update_inventory_category( +	const LLUUID& cat_id, +	const LLSD& updates, +	LLPointer<LLInventoryCallback> cb) +{ +	LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id); +	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl; +	if(obj) +	{ +		if (LLFolderType::lookupIsProtectedType(obj->getPreferredType())) +		{ +			LLNotificationsUtil::add("CannotModifyProtectedCategories"); +			return; +		} + +		LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj); +		new_cat->fromLLSD(updates); +		// FIXME - restore this once the back-end work has been done. +		if (AISCommand::isAPIAvailable()) +		{ +			LLSD new_llsd = new_cat->asLLSD(); +			LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb); +			cmd_ptr->run_command(); +		} +		else // no cap +		{ +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_UpdateInventoryFolder); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			msg->nextBlockFast(_PREHASH_FolderData); +			new_cat->packMessage(msg); +			gAgent.sendReliableMessage(); + +			LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0); +			gInventory.accountForUpdate(up); +			gInventory.updateCategory(new_cat); +			if (cb) +			{ +				cb->fire(cat_id); +			} +		} +	} +} + +void remove_inventory_items( +	LLInventoryObject::object_list_t& items_to_kill, +	LLPointer<LLInventoryCallback> cb) +{ +	for (LLInventoryObject::object_list_t::iterator it = items_to_kill.begin(); +		 it != items_to_kill.end(); +		 ++it) +	{ +		remove_inventory_item(*it, cb); +	} +} + +void remove_inventory_item( +	const LLUUID& item_id, +	LLPointer<LLInventoryCallback> cb) +{ +	LLPointer<LLInventoryObject> obj = gInventory.getItem(item_id); +	if (obj) +	{ +		remove_inventory_item(obj, cb); +	} +	else +	{ +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << "(NOT FOUND)" << llendl; +	} +} + +void remove_inventory_item( +	LLPointer<LLInventoryObject> obj, +	LLPointer<LLInventoryCallback> cb) +{ +	if(obj) +	{ +		const LLUUID item_id(obj->getUUID()); +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << obj->getName() << llendl; +		if (AISCommand::isAPIAvailable()) +		{ +			LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb); +			cmd_ptr->run_command(); +		} +		else // no cap +		{ +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_RemoveInventoryItem); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());  +			msg->nextBlockFast(_PREHASH_InventoryData); +			msg->addUUIDFast(_PREHASH_ItemID, item_id); +			gAgent.sendReliableMessage(); + +			// Update inventory and call callback immediately since +			// message-based system has no callback mechanism (!) +			gInventory.onObjectDeletedFromServer(item_id); +			if (cb) +			{ +				cb->fire(item_id); +			} +		} +	} +	else +	{ +		// *TODO: Clean up callback? +		llwarns << "remove_inventory_item called for invalid or nonexistent item." << llendl; +	} +} + +class LLRemoveCategoryOnDestroy: public LLInventoryCallback +{ +public: +	LLRemoveCategoryOnDestroy(const LLUUID& cat_id, LLPointer<LLInventoryCallback> cb): +		mID(cat_id), +		mCB(cb) +	{ +	} +	/* virtual */ void fire(const LLUUID& item_id) {} +	~LLRemoveCategoryOnDestroy() +	{ +		LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(mID); +		if(children != LLInventoryModel::CHILDREN_NO) +		{ +			llwarns << "remove descendents failed, cannot remove category " << llendl; +		} +		else +		{ +			remove_inventory_category(mID, mCB); +		} +	} +private: +	LLUUID mID; +	LLPointer<LLInventoryCallback> mCB; +}; + +void remove_inventory_category( +	const LLUUID& cat_id, +	LLPointer<LLInventoryCallback> cb) +{ +	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] " << llendl; +	LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id); +	if(obj) +	{ +		if(LLFolderType::lookupIsProtectedType(obj->getPreferredType())) +		{ +			LLNotificationsUtil::add("CannotRemoveProtectedCategories"); +			return; +		} +		if (AISCommand::isAPIAvailable()) +		{ +			LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb); +			cmd_ptr->run_command(); +		} +		else // no cap +		{ +			// RemoveInventoryFolder does not remove children, so must +			// clear descendents first. +			LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(cat_id); +			if(children != LLInventoryModel::CHILDREN_NO) +			{ +				LL_DEBUGS("Inventory") << "Will purge descendents first before deleting category " << cat_id << llendl; +				LLPointer<LLInventoryCallback> wrap_cb = new LLRemoveCategoryOnDestroy(cat_id, cb);  +				purge_descendents_of(cat_id, wrap_cb); +				return; +			} + +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_RemoveInventoryFolder); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			msg->nextBlockFast(_PREHASH_FolderData); +			msg->addUUIDFast(_PREHASH_FolderID, cat_id); +			gAgent.sendReliableMessage(); + +			// Update inventory and call callback immediately since +			// message-based system has no callback mechanism (!) +			gInventory.onObjectDeletedFromServer(cat_id); +			if (cb) +			{ +				cb->fire(cat_id); +			} +		} +	} +	else +	{ +		llwarns << "remove_inventory_category called for invalid or nonexistent item " << cat_id << llendl; +	} +} + +void remove_inventory_object( +	const LLUUID& object_id, +	LLPointer<LLInventoryCallback> cb) +{ +	if (gInventory.getCategory(object_id)) +	{ +		remove_inventory_category(object_id, cb); +	} +	else +	{ +		remove_inventory_item(object_id, cb); +	} +} + +// This is a method which collects the descendents of the id +// provided. If the category is not found, no action is +// taken. This method goes through the long winded process of +// cancelling any calling cards, removing server representation of +// folders, items, etc in a fairly efficient manner. +void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb) +{ +	LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(id); +	if(children == LLInventoryModel::CHILDREN_NO) +	{ +		LL_DEBUGS("Inventory") << "No descendents to purge for " << id << llendl; +		return; +	} +	LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(id); +	if (cat.notNull()) +	{ +		if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) +		{ +			// Something on the clipboard is in "cut mode" and needs to be preserved +			LL_DEBUGS("Inventory") << "purge_descendents_of clipboard case " << cat->getName() +								   << " iterate and purge non hidden items" << llendl; +			LLInventoryModel::cat_array_t* categories; +			LLInventoryModel::item_array_t* items; +			// Get the list of direct descendants in tha categoy passed as argument +			gInventory.getDirectDescendentsOf(id, categories, items); +			std::vector<LLUUID> list_uuids; +			// Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) +			// Note: we need to do that shallow copy as purging things will invalidate the categories or items lists +			for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) +			{ +				list_uuids.push_back((*it)->getUUID()); +			} +			for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) +			{ +				list_uuids.push_back((*it)->getUUID()); +			} +			// Iterate through the list and only purge the UUIDs that are not on the clipboard +			for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) +			{ +				if (!LLClipboard::instance().isOnClipboard(*it)) +				{ +					remove_inventory_object(*it, NULL); +				} +			} +		} +		else +		{ +			if (AISCommand::isAPIAvailable()) +			{ +				LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb); +				cmd_ptr->run_command(); +			} +			else // no cap +			{ +				// Fast purge +				LL_DEBUGS("Inventory") << "purge_descendents_of fast case " << cat->getName() << llendl; + +				// send it upstream +				LLMessageSystem* msg = gMessageSystem; +				msg->newMessage("PurgeInventoryDescendents"); +				msg->nextBlock("AgentData"); +				msg->addUUID("AgentID", gAgent.getID()); +				msg->addUUID("SessionID", gAgent.getSessionID()); +				msg->nextBlock("InventoryData"); +				msg->addUUID("FolderID", id); +				gAgent.sendReliableMessage(); + +				// Update model immediately because there is no callback mechanism. +				gInventory.onDescendentsPurgedFromServer(id); +				if (cb) +				{ +					cb->fire(id); +				} +			} +		} +	} +} +  const LLUUID get_folder_by_itemtype(const LLInventoryItem *src)  {  	LLUUID retval = LLUUID::null; @@ -1278,6 +1715,53 @@ void create_new_item(const std::string& name,  }	 +void slam_inventory_folder(const LLUUID& folder_id, +						   const LLSD& contents, +						   LLPointer<LLInventoryCallback> cb) +{ +	if (AISCommand::isAPIAvailable()) +	{ +		LL_DEBUGS("Avatar") << "using AISv3 to slam folder, id " << folder_id +							<< " new contents: " << ll_pretty_print_sd(contents) << llendl; +		LLPointer<AISCommand> cmd_ptr = new SlamFolderCommand(folder_id, contents, cb); +		cmd_ptr->run_command(); +	} +	else // no cap +	{ +		LL_DEBUGS("Avatar") << "using item-by-item calls to slam folder, id " << folder_id +							<< " new contents: " << ll_pretty_print_sd(contents) << llendl; +		for (LLSD::array_const_iterator it = contents.beginArray(); +			 it != contents.endArray(); +			 ++it) +		{ +			const LLSD& item_contents = *it; +			LLViewerInventoryItem *item = new LLViewerInventoryItem; +			item->fromLLSD(item_contents); +			link_inventory_object(folder_id, item, cb); +		} +		remove_folder_contents(folder_id,false,cb); +	} +} + +void remove_folder_contents(const LLUUID& category, bool keep_outfit_links, +							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.count(); ++i) +	{ +		LLViewerInventoryItem *item = items.get(i); +		if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) +			continue; +		if (item->getIsLinkType()) +		{ +			remove_inventory_item(item->getUUID(), cb); +		} +	} +} +  const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not)  const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not)  const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) @@ -1713,3 +2197,5 @@ BOOL LLViewerInventoryItem::regenerateLink()  	gInventory.notifyObservers();  	return TRUE;  } + + diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index ab19a12014..c82c2b6fbe 100755 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -118,14 +118,13 @@ public:  	void cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const;  	// virtual methods -	virtual void removeFromServer( void );  	virtual void updateParentOnServer(BOOL restamp) const;  	virtual void updateServer(BOOL is_new) const;  	void fetchFromServer(void) const; -	//virtual void packMessage(LLMessageSystem* msg) const; +	virtual void packMessage(LLMessageSystem* msg) const;  	virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); -	virtual BOOL unpackMessage(LLSD item); +	virtual BOOL unpackMessage(const LLSD& item);  	virtual BOOL importFile(LLFILE* fp);  	virtual BOOL importLegacyStream(std::istream& input_stream); @@ -139,7 +138,6 @@ public:  	void setComplete(BOOL complete) { mIsComplete = complete; }  	//void updateAssetOnServer() const; -	virtual void packMessage(LLMessageSystem* msg) const;  	virtual void setTransactionID(const LLTransactionID& transaction_id);  	struct comparePointers  	{ @@ -198,10 +196,11 @@ public:  	LLViewerInventoryCategory(const LLViewerInventoryCategory* other);  	void copyViewerCategory(const LLViewerInventoryCategory* other); -	virtual void removeFromServer();  	virtual void updateParentOnServer(BOOL restamp_children) const;  	virtual void updateServer(BOOL is_new) const; +	virtual void packMessage(LLMessageSystem* msg) const; +  	const LLUUID& getOwnerID() const { return mOwnerID; }  	// Version handling @@ -225,6 +224,8 @@ public:  	bool importFileLocal(LLFILE* fp);  	void determineFolderType();  	void changeType(LLFolderType::EType new_folder_type); +	virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); +	virtual BOOL unpackMessage(const LLSD& category);  private:  	friend class LLInventoryModel; @@ -264,9 +265,11 @@ private:  };  typedef boost::function<void(const LLUUID&)> inventory_func_type; -void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func - +typedef boost::function<void(const LLSD&)> llsd_func_type;  typedef boost::function<void()> nullary_func_type; + +void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func +void no_op_llsd_func(const LLSD&); // likewise for LLSD  void no_op(); // A do-nothing nullary func.  // Shim between inventory callback and boost function/callable @@ -274,7 +277,7 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback  {  public: -	LLBoostFuncInventoryCallback(inventory_func_type fire_func, +	LLBoostFuncInventoryCallback(inventory_func_type fire_func = no_op_inventory_func,  								 nullary_func_type destroy_func = no_op):  		mFireFunc(fire_func),  		mDestroyFunc(destroy_func) @@ -348,14 +351,16 @@ void copy_inventory_item(  	const std::string& new_name,  	LLPointer<LLInventoryCallback> cb); -void link_inventory_item( -	const LLUUID& agent_id, -	const LLUUID& item_id, -	const LLUUID& parent_id, -	const std::string& new_name, -	const std::string& new_description, -	const LLAssetType::EType asset_type, -	LLPointer<LLInventoryCallback> cb); +// utility functions for inventory linking. +void link_inventory_object(const LLUUID& category, +			 LLConstPointer<LLInventoryObject> baseobj, +			 LLPointer<LLInventoryCallback> cb); +void link_inventory_object(const LLUUID& category, +			 const LLUUID& id, +			 LLPointer<LLInventoryCallback> cb); +void link_inventory_array(const LLUUID& category, +						  LLInventoryObject::const_object_list_t& baseobj_array, +						  LLPointer<LLInventoryCallback> cb);  void move_inventory_item(  	const LLUUID& agent_id, @@ -365,6 +370,44 @@ void move_inventory_item(  	const std::string& new_name,  	LLPointer<LLInventoryCallback> cb); +void update_inventory_item( +	LLViewerInventoryItem *update_item, +	LLPointer<LLInventoryCallback> cb); + +void update_inventory_item( +	const LLUUID& item_id, +	const LLSD& updates, +	LLPointer<LLInventoryCallback> cb); + +void update_inventory_category( +	const LLUUID& cat_id, +	const LLSD& updates, +	LLPointer<LLInventoryCallback> cb); + +void remove_inventory_items( +	LLInventoryObject::object_list_t& items, +	LLPointer<LLInventoryCallback> cb); + +void remove_inventory_item( +	LLPointer<LLInventoryObject> obj, +	LLPointer<LLInventoryCallback> cb); + +void remove_inventory_item( +	const LLUUID& item_id, +	LLPointer<LLInventoryCallback> cb); +	 +void remove_inventory_category( +	const LLUUID& cat_id, +	LLPointer<LLInventoryCallback> cb); +	 +void remove_inventory_object( +	const LLUUID& object_id, +	LLPointer<LLInventoryCallback> cb); + +void purge_descendents_of( +	const LLUUID& cat_id, +	LLPointer<LLInventoryCallback> cb); +  const LLUUID get_folder_by_itemtype(const LLInventoryItem *src);  void copy_inventory_from_notecard(const LLUUID& destination_id, @@ -379,4 +422,11 @@ void menu_create_inventory_item(LLInventoryPanel* root,  								const LLSD& userdata,  								const LLUUID& default_parent_uuid = LLUUID::null); +void slam_inventory_folder(const LLUUID& folder_id, +						   const LLSD& contents, +						   LLPointer<LLInventoryCallback> cb); + +void remove_folder_contents(const LLUUID& folder_id, bool keep_outfit_links, +							  LLPointer<LLInventoryCallback> cb); +  #endif // LL_LLVIEWERINVENTORY_H diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2df028de69..2cec808f19 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -158,7 +158,7 @@ LLViewerMediaObserver::~LLViewerMediaObserver()  // on the Panel Land Media and to discover the MIME type  class LLMimeDiscoveryResponder : public LLHTTPClient::Responder  { -LOG_CLASS(LLMimeDiscoveryResponder); +	LOG_CLASS(LLMimeDiscoveryResponder);  public:  	LLMimeDiscoveryResponder( viewer_media_t media_impl)  		: mMediaImpl(media_impl), @@ -177,13 +177,19 @@ public:  		disconnectOwner();  	} -	virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpCompleted()  	{ -		std::string media_type = content["content-type"].asString(); +		if (!isGoodStatus()) +		{ +			llwarns << dumpResponse() +					<< " [headers:" << getResponseHeaders() << "]" << llendl; +		} +		const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE);  		std::string::size_type idx1 = media_type.find_first_of(";");  		std::string mime_type = media_type.substr(0, idx1); -		lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl; +		lldebugs << "status is " << getStatus() << ", media type \"" << media_type << "\"" << llendl;  		// 2xx status codes indicate success.  		// Most 4xx status codes are successful enough for our purposes. @@ -200,32 +206,27 @@ public:  //			)  		// We now no longer check the error code returned from the probe.  		// If we have a mime type, use it.  If not, default to the web plugin and let it handle error reporting. -		if(1) +		//if(1)  		{  			// The probe was successful.  			if(mime_type.empty())  			{  				// Some sites don't return any content-type header at all.  				// Treat an empty mime type as text/html. -				mime_type = "text/html"; +				mime_type = HTTP_CONTENT_TEXT_HTML;  			} -			 -			completeAny(status, mime_type);  		} -		else -		{ -			llwarns << "responder failed with status " << status << ", reason " << reason << llendl; -		 -			if(mMediaImpl) -			{ -				mMediaImpl->mMediaSourceFailed = true; -			} -		} - -	} +		//else +		//{ +		//	llwarns << "responder failed with status " << dumpResponse() << llendl; +		// +		//	if(mMediaImpl) +		//	{ +		//		mMediaImpl->mMediaSourceFailed = true; +		//	} +		//	return; +		//} -	void completeAny(U32 status, const std::string& mime_type) -	{  		// the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.  		// Make a local copy so we can call loadURI() afterwards.  		LLViewerMediaImpl *impl = mMediaImpl; @@ -241,6 +242,7 @@ public:  		}  	} +public:  	void cancelRequest()  	{  		disconnectOwner(); @@ -269,7 +271,7 @@ public:  class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder  { -LOG_CLASS(LLViewerMediaOpenIDResponder); +	LOG_CLASS(LLViewerMediaOpenIDResponder);  public:  	LLViewerMediaOpenIDResponder( )  	{ @@ -279,23 +281,17 @@ public:  	{  	} -	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) -	{ -		LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; -		LL_DEBUGS("MediaAuth") << content << LL_ENDL; -		std::string cookie = content["set-cookie"].asString(); -		 -		LLViewerMedia::openIDCookieResponse(cookie); -	} -  	/* virtual */ void completedRaw( -		U32 status, -		const std::string& reason,  		const LLChannelDescriptors& channels,  		const LLIOPipe::buffer_ptr_t& buffer)  	{ -		// This is just here to disable the default behavior (attempting to parse the response as llsd). -		// We don't care about the content of the response, only the set-cookie header. +		// We don't care about the content of the response, only the Set-Cookie header. +		LL_DEBUGS("MediaAuth") << dumpResponse()  +				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; +		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); +		 +		// *TODO: What about bad status codes?  Does this destroy previous cookies? +		LLViewerMedia::openIDCookieResponse(cookie);  	}  }; @@ -313,17 +309,23 @@ public:  	{  	} -	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) +	 void completedRaw( +		const LLChannelDescriptors& channels, +		const LLIOPipe::buffer_ptr_t& buffer)  	{ -		LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; +		// We don't care about the content of the response, only the set-cookie header. +		LL_WARNS("MediaAuth") << dumpResponse()  +				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; -		LLSD stripped_content = content; -		stripped_content.erase("set-cookie"); +		LLSD stripped_content = getResponseHeaders(); +		// *TODO: Check that this works. +		stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE);  		LL_WARNS("MediaAuth") << stripped_content << LL_ENDL; -		std::string cookie = content["set-cookie"].asString(); +		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);  		LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL; +		// *TODO: What about bad status codes?  Does this destroy previous cookies?  		LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);  		// Set cookie for snapshot publishing. @@ -331,16 +333,6 @@ public:  		LLWebProfile::setAuthCookie(auth_cookie);  	} -	 void completedRaw( -		U32 status, -		const std::string& reason, -		const LLChannelDescriptors& channels, -		const LLIOPipe::buffer_ptr_t& buffer) -	{ -		// This is just here to disable the default behavior (attempting to parse the response as llsd). -		// We don't care about the content of the response, only the set-cookie header. -	} -  	std::string mHost;  }; @@ -1387,10 +1379,12 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom  LLSD LLViewerMedia::getHeaders()  {  	LLSD headers = LLSD::emptyMap(); -	headers["Accept"] = "*/*"; -	headers["Content-Type"] = "application/xml"; -	headers["Cookie"] = sOpenIDCookie; -	headers["User-Agent"] = getCurrentUserAgent(); +	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; +	// *TODO: Should this be 'application/llsd+xml' ? +	// *TODO: Should this even be set at all?   This header is only not overridden in 'GET' methods. +	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; +	headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; +	headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();  	return headers;  } @@ -1431,9 +1425,9 @@ void LLViewerMedia::setOpenIDCookie()  		// Do a web profile get so we can store the cookie   		LLSD headers = LLSD::emptyMap(); -		headers["Accept"] = "*/*"; -		headers["Cookie"] = sOpenIDCookie; -		headers["User-Agent"] = getCurrentUserAgent(); +		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; +		headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; +		headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();  		std::string profile_url = getProfileURL("");  		LLURL raw_profile_url( profile_url.c_str() ); @@ -1463,9 +1457,9 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string  	LLSD headers = LLSD::emptyMap();  	// Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header -	headers["Accept"] = "*/*"; +	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";  	// and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" -	headers["Content-Type"] = "application/x-www-form-urlencoded"; +	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "application/x-www-form-urlencoded";  	// postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here.  	size_t size = openid_token.size(); @@ -1537,7 +1531,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()  		// The null owner will keep the browser plugin from fully initializing   		// (specifically, it keeps LLPluginClassMedia from negotiating a size change,   		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) -		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); +		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0);  	}  } @@ -2633,16 +2627,16 @@ void LLViewerMediaImpl::navigateInternal()  			//    Accept: application/llsd+xml  			// which is really not what we want.  			LLSD headers = LLSD::emptyMap(); -			headers["Accept"] = "*/*"; +			headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";  			// Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com -			headers["Cookie"] = ""; +			headers[HTTP_OUT_HEADER_COOKIE] = "";  			LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f);  		}  		else if("data" == scheme || "file" == scheme || "about" == scheme)  		{  			// FIXME: figure out how to really discover the type for these schemes  			// We use "data" internally for a text/html url for loading the login screen -			if(initializeMedia("text/html")) +			if(initializeMedia(HTTP_CONTENT_TEXT_HTML))  			{  				loadURI();  			} diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e3335c9cd8..aecffb4ff5 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3970,6 +3970,8 @@ void process_teleport_finish(LLMessageSystem* msg, void**)  	gAgent.setTeleportState( LLAgent::TELEPORT_MOVING );  	gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); +	LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == " +			<< seedCap << LL_ENDL;  	regionp->setSeedCapability(seedCap);  	// Don't send camera updates to the new region until we're @@ -4224,6 +4226,9 @@ void process_crossed_region(LLMessageSystem* msg, void**)  	send_complete_agent_movement(sim_host);  	LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + +	LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " +			<< seedCap << LL_ENDL;  	regionp->setSeedCapability(seedCap);  } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 6f7b2f40e6..91efed1508 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5257,6 +5257,28 @@ void LLViewerObject::clearDrawableState(U32 state, BOOL recursive)  	}  } +BOOL LLViewerObject::isDrawableState(U32 state, BOOL recursive) const +{ +	BOOL matches = FALSE; +	if (mDrawable) +	{ +		matches = mDrawable->isState(state); +	} +	if (recursive) +	{ +		for (child_list_t::const_iterator iter = mChildList.begin(); +			 (iter != mChildList.end()) && matches; iter++) +		{ +			LLViewerObject* child = *iter; +			matches &= child->isDrawableState(state, recursive); +		} +	} + +	return matches; +} + + +  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  // RN: these functions assume a 2-level hierarchy   //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index ea0d55cda5..0b92af4a93 100755 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -410,6 +410,7 @@ public:  	void setDrawableState(U32 state, BOOL recursive = TRUE);  	void clearDrawableState(U32 state, BOOL recursive = TRUE); +	BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const;  	// Called when the drawable shifts  	virtual void onShift(const LLVector4a &shift_vector)	{ } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 66615657d8..a90694da7a 100755 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -670,6 +670,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)  class LLObjectCostResponder : public LLCurl::Responder  { +	LOG_CLASS(LLObjectCostResponder);  public:  	LLObjectCostResponder(const LLSD& object_ids)  		: mObjectIDs(object_ids) @@ -690,20 +691,19 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpFailure()  	{ -		llwarns -			<< "Transport error requesting object cost " -			<< "[status: " << statusNum << "]: " -			<< content << llendl; +		llwarns << dumpResponse() << llendl;  		// TODO*: Error message to user  		// For now just clear the request from the pending list  		clear_object_list_pending_requests();  	} -	void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{ +		const LLSD& content = getContent();  		if ( !content.isMap() || content.has("error") )  		{  			// Improper response or the request had an error, @@ -759,6 +759,7 @@ private:  class LLPhysicsFlagsResponder : public LLCurl::Responder  { +	LOG_CLASS(LLPhysicsFlagsResponder);  public:  	LLPhysicsFlagsResponder(const LLSD& object_ids)  		: mObjectIDs(object_ids) @@ -779,20 +780,19 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpFailure()  	{ -		llwarns -			<< "Transport error requesting object physics flags " -			<< "[status: " << statusNum << "]: " -			<< content << llendl; +		llwarns << dumpResponse() << llendl;  		// TODO*: Error message to user  		// For now just clear the request from the pending list  		clear_object_list_pending_requests();  	} -	void result(const LLSD& content) +	/* virtual void */ void httpSuccess()  	{ +		const LLSD& content = getContent();  		if ( !content.isMap() || content.has("error") )  		{  			// Improper response or the request had an error, diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 386b2fd400..d7e14ac6f5 100755 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -99,7 +99,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel)  			std::string mediaCurrentUrl = std::string( parcel->getMediaCurrentURL());  			// if we have a current (link sharing) url, use it instead -			if (mediaCurrentUrl != "" && parcel->getMediaType() == "text/html") +			if (mediaCurrentUrl != "" && parcel->getMediaType() == HTTP_CONTENT_TEXT_HTML)  			{  				mediaUrl = mediaCurrentUrl;  			} diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 8422708add..7150089380 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -30,6 +30,7 @@  // linden libraries  #include "indra_constants.h" +#include "llaisapi.h"  #include "llavatarnamecache.h"		// name lookup cap url  #include "llfloaterreg.h"  #include "llmath.h" @@ -75,6 +76,11 @@  	#pragma warning(disable:4355)  #endif +// When we receive a base grant of capabilities that has a different number of  +// capabilities than the original base grant received for the region, print  +// out the two lists of capabilities for analysis. +//#define DEBUG_CAPS_GRANTS +  const F32 WATER_TEXTURE_SCALE = 8.f;			//  Number of times to repeat the water texture across a region  const S16 MAX_MAP_DIST = 10;  // The server only keeps our pending agent info for 60 seconds. @@ -87,6 +93,8 @@ const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;  typedef std::map<std::string, std::string> CapabilityMap; +static void log_capabilities(const CapabilityMap &capmap); +  class LLViewerRegionImpl {  public:  	LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) @@ -143,7 +151,7 @@ public:  	CapabilityMap mCapabilities;  	CapabilityMap mSecondCapabilitiesTracker;  -	 +  	LLEventPoll* mEventPoll;  	S32 mSeedCapMaxAttempts; @@ -204,24 +212,30 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder  {  	LOG_CLASS(BaseCapabilitiesComplete);  public: -    BaseCapabilitiesComplete(U64 region_handle, S32 id) +	BaseCapabilitiesComplete(U64 region_handle, S32 id)  		: mRegionHandle(region_handle), mID(id) -    { } +	{ }  	virtual ~BaseCapabilitiesComplete()  	{ } -    void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -    { -		LL_WARNS2("AppInit", "Capabilities") << "[status:" << statusNum << ":] " << content << LL_ENDL; +	static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) +	{ +		return new BaseCapabilitiesComplete(region_handle, id); +	} + +private: +	/* virtual */void httpFailure() +	{ +		LL_WARNS2("AppInit", "Capabilities") << dumpResponse() << LL_ENDL;  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if (regionp)  		{  			regionp->failedSeedCapability();  		} -    } +	} -    void result(const LLSD& content) -    { +	/* virtual */ void httpSuccess() +	{  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if(!regionp) //region was removed  		{ @@ -234,11 +248,17 @@ public:  			return ;  		} +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLSD::map_const_iterator iter;  		for(iter = content.beginMap(); iter != content.endMap(); ++iter)  		{  			regionp->setCapability(iter->first, iter->second); -			 +  			LL_DEBUGS2("AppInit", "Capabilities") << "got capability for "   				<< iter->first << LL_ENDL; @@ -257,11 +277,6 @@ public:  		}  	} -    static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) -    { -		return new BaseCapabilitiesComplete(region_handle, id); -    } -  private:  	U64 mRegionHandle;  	S32 mID; @@ -278,19 +293,32 @@ public:  	virtual ~BaseCapabilitiesCompleteTracker()  	{ } -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +	static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) +	{ +		return new BaseCapabilitiesCompleteTracker( region_handle ); +	} + +private: +	/* virtual */ void httpFailure()  	{ -		llwarns << "BaseCapabilitiesCompleteTracker error [status:" -				<< statusNum << "]: " << content << llendl; +		llwarns << dumpResponse() << llendl;  	} -	void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if( !regionp )   		{ +			LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL;  			return ; -		}		 +		} + +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLSD::map_const_iterator iter;  		for(iter = content.beginMap(); iter != content.endMap(); ++iter)  		{ @@ -300,27 +328,46 @@ public:  		if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() )  		{ -			llinfos<<"BaseCapabilitiesCompleteTracker "<<"Sim sent duplicate seed caps that differs in size - most likely content."<<llendl;			 -			//todo#add cap debug versus original check? -			/*CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin(); -			while (iter!=regionp->getRegionImpl()->mCapabilities.end() ) +			LL_WARNS2("AppInit", "Capabilities")  +				<< "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " +				<< "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size() +				<< " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() +				<< LL_ENDL; +#ifdef DEBUG_CAPS_GRANTS +			LL_WARNS2("AppInit", "Capabilities") +				<< "Initial Base capabilities: " << LL_ENDL; + +			log_capabilities(regionp->getRegionImpl()->mCapabilities); + +			LL_WARNS2("AppInit", "Capabilities") +							<< "Latest base capabilities: " << LL_ENDL; + +			log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); + +#endif + +			if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() )  			{ -				llinfos<<"BaseCapabilitiesCompleteTracker Original "<<iter->first<<" "<< iter->second<<llendl; -				++iter; +				// *HACK Since we were granted more base capabilities in this grant request than the initial, replace +				// the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a +				// sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the +				// inventory api capability grants. + +				// Need to clear a std::map before copying into it because old keys take precedence. +				regionp->getRegionImplNC()->mCapabilities.clear(); +				regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker;  			} -			*/ -			regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear();  		} - +		else +		{ +			LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; +		} +		regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear();  	} -	static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) -	{ -		return new BaseCapabilitiesCompleteTracker( region_handle ); -	}  private: -	U64 mRegionHandle;	 +	U64 mRegionHandle;  }; @@ -1568,7 +1615,11 @@ void LLViewerRegion::unpackRegionHandshake()  	msg->addUUID("AgentID", gAgent.getID());  	msg->addUUID("SessionID", gAgent.getSessionID());  	msg->nextBlock("RegionInfo"); -	msg->addU32("Flags", 0x0 ); + +	U32 flags = 0; +	flags |= REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE; + +	msg->addU32("Flags", flags );  	msg->sendReliable(host);  } @@ -1587,12 +1638,13 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("EventQueueGet");  	if (gSavedSettings.getBOOL("UseHTTPInventory")) -	{ +	{	  		capabilityNames.append("FetchLib2");  		capabilityNames.append("FetchLibDescendents2");  		capabilityNames.append("FetchInventory2");  		capabilityNames.append("FetchInventoryDescendents2");  		capabilityNames.append("IncrementCOFVersion"); +		AISCommand::getCapabilityNames(capabilityNames);  	}  	capabilityNames.append("GetDisplayNames"); @@ -1606,7 +1658,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("LandResources");  	capabilityNames.append("MapLayer");  	capabilityNames.append("MapLayerGod"); -	capabilityNames.append("MeshUploadFlag"); +	capabilityNames.append("MeshUploadFlag");	  	capabilityNames.append("NavMeshGenerationStatus");  	capabilityNames.append("NewFileAgentInventory");  	capabilityNames.append("ObjectMedia"); @@ -1617,7 +1669,6 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("ProductInfoRequest");  	capabilityNames.append("ProvisionVoiceAccountRequest");  	capabilityNames.append("RemoteParcelRequest"); -	capabilityNames.append("RenderMaterials");  	capabilityNames.append("RequestTextureDownload");  	capabilityNames.append("ResourceCostSelected");  	capabilityNames.append("RetrieveNavMeshSrc"); @@ -1647,7 +1698,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("ViewerMetrics");  	capabilityNames.append("ViewerStartAuction");  	capabilityNames.append("ViewerStats"); -	 +  	// Please add new capabilities alphabetically to reduce  	// merge conflicts.  } @@ -1655,8 +1706,10 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  void LLViewerRegion::setSeedCapability(const std::string& url)  {  	if (getCapability("Seed") == url) -    { -		// llwarns << "Ignoring duplicate seed capability" << llendl; +    {	 +		setCapabilityDebug("Seed", url); +		LL_DEBUGS("CrossingCaps") <<  "Received duplicate seed capability, posting to seed " << +				url	<< llendl;  		//Instead of just returning we build up a second set of seed caps and compare them   		//to the "original" seed cap received and determine why there is problem!  		LLSD capabilityNames = LLSD::emptyArray(); @@ -1729,31 +1782,37 @@ class SimulatorFeaturesReceived : public LLHTTPClient::Responder  {  	LOG_CLASS(SimulatorFeaturesReceived);  public: -    SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle,  +	SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle,   			S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) -	: mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) -    { } -	 -	 -    void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -    { -		LL_WARNS2("AppInit", "SimulatorFeatures") << "[status:" << statusNum << "]: " << content << LL_ENDL; +		: mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) +	{ } + +private: +	/* virtual */ void httpFailure() +	{ +		LL_WARNS2("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL;  		retry(); -    } +	} -    void result(const LLSD& content) -    { +	/* virtual */ void httpSuccess() +	{  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if(!regionp) //region is removed or responder is not created.  		{ -			LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; +			LL_WARNS2("AppInit", "SimulatorFeatures")  +				<< "Received results for region that no longer exists!" << LL_ENDL;  			return ;  		} -		 + +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		regionp->setSimulatorFeatures(content);  	} -private:  	void retry()  	{  		if (mAttempt < mMaxAttempts) @@ -1763,7 +1822,7 @@ private:  			LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);  		}  	} -	 +  	std::string mRetryURL;  	U64 mRegionHandle;  	S32 mAttempt; @@ -1800,7 +1859,16 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u  void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url)  { -	mImpl->mSecondCapabilitiesTracker[name] = url; +	// Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later. +	if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) ) +	{ +		mImpl->mSecondCapabilitiesTracker[name] = url; +		if(name == "GetTexture") +		{ +			mHttpUrl = url ; +		} +	} +  }  bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) @@ -1812,7 +1880,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const  {  	if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))  	{ -		llwarns << "getCapability called before caps received" << llendl; +		llwarns << "getCapability called before caps received for " << name << llendl;  	}  	CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); @@ -1824,6 +1892,22 @@ std::string LLViewerRegion::getCapability(const std::string& name) const  	return iter->second;  } +bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const +{ +	if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) +	{ +		llwarns << "isCapabilityAvailable called before caps received for " << name << llendl; +	} +	 +	CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); +	if(iter == mImpl->mCapabilities.end()) +	{ +		return false; +	} + +	return true; +} +  bool LLViewerRegion::capabilitiesReceived() const  {  	return mCapabilitiesReceived; @@ -1851,16 +1935,7 @@ boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(cons  void LLViewerRegion::logActiveCapabilities() const  { -	int count = 0; -	CapabilityMap::const_iterator iter; -	for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) -	{ -		if (!iter->second.empty()) -		{ -			llinfos << iter->first << " URL is " << iter->second << llendl; -		} -	} -	llinfos << "Dumped " << count << " entries." << llendl; +	log_capabilities(mImpl->mCapabilities);  }  LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) @@ -1944,3 +2019,19 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const  			 mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean());  } +/* Static Functions */ + +void log_capabilities(const CapabilityMap &capmap) +{ +	S32 count = 0; +	CapabilityMap::const_iterator iter; +	for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count) +	{ +		if (!iter->second.empty()) +		{ +			llinfos << "log_capabilities: " << iter->first << " URL is " << iter->second << llendl; +		} +	} +	llinfos << "log_capabilities: Dumped " << count << " entries." << llendl; +} + diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 56cd0c9ea1..6beaaf0e7b 100755 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -49,6 +49,8 @@  #define WATER 2  const U32	MAX_OBJECT_CACHE_ENTRIES = 50000; +// Region handshake flags +const U32 REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE = 1U << 2;  class LLEventPoll;  class LLVLComposition; @@ -242,6 +244,7 @@ public:  	S32 getNumSeedCapRetries();  	void setCapability(const std::string& name, const std::string& url);  	void setCapabilityDebug(const std::string& name, const std::string& url); +	bool isCapabilityAvailable(const std::string& name) const;  	// implements LLCapabilityProvider      virtual std::string getCapability(const std::string& name) const; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 35bba4184e..68633fba6e 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -527,18 +527,19 @@ void update_statistics()  class ViewerStatsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(ViewerStatsResponder);  public: -    ViewerStatsResponder() { } +	ViewerStatsResponder() { } -    void error(U32 statusNum, const std::string& reason) -    { -		llinfos << "ViewerStatsResponder::error " << statusNum << " " -				<< reason << llendl; -    } +private: +	/* virtual */ void httpFailure() +	{ +		llwarns << dumpResponse() << llendl; +	} -    void result(const LLSD& content) -    { -		llinfos << "ViewerStatsResponder::result" << llendl; +	/* virtual */ void httpSuccess() +	{ +		llinfos << "OK" << llendl;  	}  }; @@ -733,44 +734,28 @@ void send_stats()  	LLHTTPClient::post(url, body, new ViewerStatsResponder());  } -LLFrameTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name) +LLTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name)  {  	phase_map_t::iterator iter = mPhaseMap.find(phase_name);  	if (iter == mPhaseMap.end())  	{ -		LLFrameTimer timer; +		LLTimer timer;  		mPhaseMap[phase_name] = timer;  	} -	LLFrameTimer& timer = mPhaseMap[phase_name]; +	LLTimer& timer = mPhaseMap[phase_name];  	return timer;  }  void LLViewerStats::PhaseMap::startPhase(const std::string& phase_name)  { -	LLFrameTimer& timer = getPhaseTimer(phase_name); -	lldebugs << "startPhase " << phase_name << llendl; -	timer.unpause(); -} - -void LLViewerStats::PhaseMap::stopAllPhases() -{ -	for (phase_map_t::iterator iter = mPhaseMap.begin(); -		 iter != mPhaseMap.end(); ++iter) -	{ -		const std::string& phase_name = iter->first; -		if (iter->second.getStarted()) -		{ -			// Going from started to paused state - record stats. -			recordPhaseStat(phase_name,iter->second.getElapsedTimeF32()); -		} -		lldebugs << "stopPhase (all) " << phase_name << llendl; -		iter->second.pause(); -	} +	LLTimer& timer = getPhaseTimer(phase_name); +	timer.start(); +	LL_DEBUGS("Avatar") << "startPhase " << phase_name << llendl;  }  void LLViewerStats::PhaseMap::clearPhases()  { -	lldebugs << "clearPhases" << llendl; +	LL_DEBUGS("Avatar") << "clearPhases" << llendl;  	mPhaseMap.clear();  } @@ -795,7 +780,6 @@ LLViewerStats::PhaseMap::PhaseMap()  {  } -  void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)  {  	phase_map_t::iterator iter = mPhaseMap.find(phase_name); @@ -808,6 +792,7 @@ void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)  		}  	}  } +  // static  LLViewerStats::StatsAccumulator& LLViewerStats::PhaseMap::getPhaseStats(const std::string& phase_name)  { @@ -831,14 +816,18 @@ void LLViewerStats::PhaseMap::recordPhaseStat(const std::string& phase_name, F32  bool LLViewerStats::PhaseMap::getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed)  {  	phase_map_t::iterator iter = mPhaseMap.find(phase_name); +	bool found = false;  	if (iter != mPhaseMap.end())  	{ +		found = true;  		elapsed =  iter->second.getElapsedTimeF32();  		completed = !iter->second.getStarted(); -		return true; +		LL_DEBUGS("Avatar") << " phase_name " << phase_name << " elapsed " << elapsed << " completed " << completed << " timer addr " << (S32)(&iter->second) << llendl;  	}  	else  	{ -		return false; +		LL_DEBUGS("Avatar") << " phase_name " << phase_name << " NOT FOUND"  << llendl;  	} + +	return found;  } diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 6b2461be41..eaa0b6beff 100755 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -279,7 +279,7 @@ public:  	// Phase tracking (originally put in for avatar rezzing), tracking  	// progress of active/completed phases for activities like outfit changing. -	typedef std::map<std::string,LLFrameTimer>	phase_map_t; +	typedef std::map<std::string,LLTimer>	phase_map_t;  	typedef std::map<std::string,StatsAccumulator>	phase_stats_t;  	class PhaseMap  	{ @@ -288,11 +288,10 @@ public:  		static phase_stats_t sStats;  	public:  		PhaseMap(); -		LLFrameTimer& 	getPhaseTimer(const std::string& phase_name); +		LLTimer& 		getPhaseTimer(const std::string& phase_name);  		bool 			getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed);  		void			startPhase(const std::string& phase_name);  		void			stopPhase(const std::string& phase_name); -		void			stopAllPhases();  		void			clearPhases();  		LLSD			dumpPhases();  		static StatsAccumulator& getPhaseStats(const std::string& phase_name); diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index 777e1f9c76..777e1f9c76 100755..100644 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 84f66c359f..7e35af7e63 100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -931,6 +931,27 @@ void LLViewerTexture::updateBindStatsForTester()  //end of LLViewerTexture  //---------------------------------------------------------------------------------------------- +const std::string& fttype_to_string(const FTType& fttype) +{ +	static const std::string ftt_unknown("FTT_UNKNOWN"); +	static const std::string ftt_default("FTT_DEFAULT"); +	static const std::string ftt_server_bake("FTT_SERVER_BAKE"); +	static const std::string ftt_host_bake("FTT_HOST_BAKE"); +	static const std::string ftt_map_tile("FTT_MAP_TILE"); +	static const std::string ftt_local_file("FTT_LOCAL_FILE"); +	static const std::string ftt_error("FTT_ERROR"); +	switch(fttype) +	{ +		case FTT_UNKNOWN: return ftt_unknown; break; +		case FTT_DEFAULT: return ftt_default; break; +		case FTT_SERVER_BAKE: return ftt_server_bake; break; +		case FTT_HOST_BAKE: return ftt_host_bake; break; +		case FTT_MAP_TILE: return ftt_map_tile; break; +		case FTT_LOCAL_FILE: return ftt_local_file; break; +	} +	return ftt_error; +} +  //----------------------------------------------------------------------------------------------  //start of LLViewerFetchedTexture  //---------------------------------------------------------------------------------------------- @@ -1799,7 +1820,8 @@ bool LLViewerFetchedTexture::updateFetch()  		if (mRawImage.notNull()) sRawCount--;  		if (mAuxRawImage.notNull()) sAuxCount--; -		bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage); +		bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage, +																		   mLastHttpGetStatus);  		if (mRawImage.notNull()) sRawCount++;  		if (mAuxRawImage.notNull()) sAuxCount++;  		if (finished) @@ -1864,10 +1886,15 @@ bool LLViewerFetchedTexture::updateFetch()  				// We finished but received no data  				if (current_discard < 0)  				{ -					llwarns << "!mIsFetching, setting as missing, decode_priority " << decode_priority -							<< " mRawDiscardLevel " << mRawDiscardLevel -							<< " current_discard " << current_discard -							<< llendl; +					if (getFTType() != FTT_MAP_TILE) +					{ +						llwarns << mID +								<< " Fetch failure, setting as missing, decode_priority " << decode_priority +								<< " mRawDiscardLevel " << mRawDiscardLevel +								<< " current_discard " << current_discard +								<< " stats " << mLastHttpGetStatus.toHex() +								<< llendl; +					}  					setIsMissingAsset();  					desired_discard = -1;  				} @@ -2046,29 +2073,43 @@ void LLViewerFetchedTexture::forceToDeleteRequest()  	mDesiredDiscardLevel = getMaxDiscardLevel() + 1;  } -void LLViewerFetchedTexture::setIsMissingAsset() +void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing)  { -	if (mUrl.empty()) +	if (is_missing == mIsMissingAsset)  	{ -		llwarns << mID << ": Marking image as missing" << llendl; +		return;  	} -	else +	if (is_missing)  	{ -		// This may or may not be an error - it is normal to have no -		// map tile on an empty region, but bad if we're failing on a -		// server bake texture. -		llwarns << mUrl << ": Marking image as missing" << llendl; +		if (mUrl.empty()) +		{ +			llwarns << mID << ": Marking image as missing" << llendl; +		} +		else +		{ +			// This may or may not be an error - it is normal to have no +			// map tile on an empty region, but bad if we're failing on a +			// server bake texture. +			if (getFTType() != FTT_MAP_TILE) +			{ +				llwarns << mUrl << ": Marking image as missing" << llendl; +			} +		} +		if (mHasFetcher) +		{ +			LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); +			mHasFetcher = FALSE; +			mIsFetching = FALSE; +			mLastPacketTimer.reset(); +			mFetchState = 0; +			mFetchPriority = 0; +		}  	} -	if (mHasFetcher) +	else  	{ -		LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); -		mHasFetcher = FALSE; -		mIsFetching = FALSE; -		mLastPacketTimer.reset(); -		mFetchState = 0; -		mFetchPriority = 0; +		llinfos << mID << ": un-flagging missing asset" << llendl;  	} -	mIsMissingAsset = TRUE; +	mIsMissingAsset = is_missing;  }  void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 10101a4b9b..d9a537d304 100755 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -34,7 +34,7 @@  #include "llgltypes.h"  #include "llrender.h"  #include "llmetricperformancetester.h" -#include "llface.h" +#include "httpcommon.h"  #include <map>  #include <list> @@ -42,6 +42,7 @@  #define MIN_VIDEO_RAM_IN_MEGA_BYTES    32  #define MAX_VIDEO_RAM_IN_MEGA_BYTES    512 // 512MB max for performance reasons. +class LLFace;  class LLImageGL ;  class LLImageRaw;  class LLViewerObject; @@ -98,6 +99,7 @@ public:  		DYNAMIC_TEXTURE,  		FETCHED_TEXTURE,  		LOD_TEXTURE, +		ATLAS_TEXTURE,  		INVALID_TEXTURE_TYPE  	}; @@ -120,7 +122,7 @@ public:  	LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;  	virtual S8 getType() const; -	virtual BOOL isMissingAsset()const ; +	virtual BOOL isMissingAsset() const ;  	virtual void dump();	// debug info to llinfos  	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ; @@ -217,7 +219,8 @@ public:  	static S32 sMaxSmallImageSize ;  	static BOOL sFreezeImageScalingDown ;//do not scale down image res if set.  	static F32  sCurrentTime ; -	 +	static BOOL sUseTextureAtlas ; +  	enum EDebugTexels  	{  		DEBUG_TEXELS_OFF, @@ -244,6 +247,8 @@ enum FTType  	FTT_LOCAL_FILE // fetch directly from a local file.  }; +const std::string& fttype_to_string(const FTType& fttype); +  //  //textures are managed in gTextureList.  //raw image data is fetched from remote or local cache @@ -340,8 +345,8 @@ public:  	// more data.  	/*virtual*/ void setKnownDrawSize(S32 width, S32 height); -	void setIsMissingAsset(); -	/*virtual*/ BOOL isMissingAsset()	const		{ return mIsMissingAsset; } +	void setIsMissingAsset(BOOL is_missing = true); +	/*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; }  	// returns dimensions of original image for local files (before power of two scaling)  	// and returns 0 for all asset system images @@ -402,12 +407,17 @@ protected:  	S32 getCurrentDiscardLevelForFetching() ;  private: -	void init(bool firstinit) ; +	void init(bool firstinit) ;	  	void cleanup() ;  	void saveRawImage() ;  	void setCachedRawImage() ; +	//for atlas +	void resetFaceAtlas() ; +	void invalidateAtlas(BOOL rebuild_geom) ; +	BOOL insertToAtlas() ; +  private:  	BOOL  mFullyLoaded;  	BOOL  mInDebug; @@ -443,8 +453,9 @@ protected:  	S8  mIsRawImageValid;  	S8  mHasFetcher;				// We've made a fecth request  	S8  mIsFetching;				// Fetch request is active -	bool mCanUseHTTP ;              //This texture can be fetched through http if true. -	 +	bool mCanUseHTTP;              //This texture can be fetched through http if true. +	LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture. +  	FTType mFTType; // What category of image is this - map tile, server bake, etc?  	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		 diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index e8425dc76a..76f94935b8 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -72,14 +72,16 @@ private:  static std::string asset_id_to_filename(const LLUUID &asset_id);  LLViewerWearable::LLViewerWearable(const LLTransactionID& transaction_id) : -	LLWearable() +	LLWearable(), +	mVolatile(FALSE)  {  	mTransactionID = transaction_id;  	mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID());  }  LLViewerWearable::LLViewerWearable(const LLAssetID& asset_id) : -	LLWearable() +	LLWearable(), +	mVolatile(FALSE)  {  	mAssetID = asset_id;  	mTransactionID.setNull(); diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index 65566f23a5..ef8c29323e 100644 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -68,6 +68,8 @@ public:  	void				setParamsToDefaults();  	void				setTexturesToDefaults(); +	void				setVolatile(BOOL is_volatile) { mVolatile = is_volatile; } // TRUE when doing preview renders, some updates will be suppressed. +	BOOL				getVolatile() { return mVolatile; }  	/*virtual*/ LLUUID	getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const; @@ -96,6 +98,8 @@ protected:  	LLAssetID			mAssetID;  	LLTransactionID		mTransactionID; +	BOOL 				mVolatile; // True when rendering preview images. Can suppress some updates. +  	LLUUID				mItemID;  // ID of the inventory item in the agent's inventory	  }; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 40b8560071..f8e2a27f63 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1966,7 +1966,7 @@ void LLViewerWindow::initWorldUI()  		destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));  		std::string url = gSavedSettings.getString("DestinationGuideURL");  		url = LLWeb::expandURLSubstitutions(url, LLSD()); -		destinations->navigateTo(url, "text/html"); +		destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);  	}  	LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");  	if (avatar_picker) @@ -1974,7 +1974,7 @@ void LLViewerWindow::initWorldUI()  		avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));  		std::string url = gSavedSettings.getString("AvatarPickerURL");  		url = LLWeb::expandURLSubstitutions(url, LLSD()); -		avatar_picker->navigateTo(url, "text/html"); +		avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);  	}  } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 1a050800b4..0bd51d9c15 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -106,7 +106,7 @@ extern F32 SPEED_ADJUST_MAX;  extern F32 SPEED_ADJUST_MAX_SEC;  extern F32 ANIM_SPEED_MAX;  extern F32 ANIM_SPEED_MIN; - +extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG;  // #define OUTPUT_BREAST_DATA @@ -802,17 +802,17 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c  //------------------------------------------------------------------------  LLVOAvatar::~LLVOAvatar()  { -		if (!mFullyLoaded) -		{ +	if (!mFullyLoaded) +	{  		debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud"); -		} -		else -		{ +	} +	else +	{  		debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding"); -		} +	}  	logPendingPhases(); - +	  	lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;  	std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer()); @@ -1196,7 +1196,7 @@ void LLVOAvatar::initInstance(void)  		registerMotion( ANIM_AGENT_TARGET,					LLTargetingMotion::create );  		registerMotion( ANIM_AGENT_WALK_ADJUST,				LLWalkAdjustMotion::create );  	} -	 +  	LLAvatarAppearance::initInstance();  	// preload specific motions here @@ -1234,6 +1234,7 @@ LLTexLayerSet* LLVOAvatar::createTexLayerSet()  const LLVector3 LLVOAvatar::getRenderPosition() const  { +  	if (mDrawable.isNull() || mDrawable->getGeneration() < 0)  	{  		return getPositionAgent(); @@ -1256,6 +1257,8 @@ const LLVector3 LLVOAvatar::getRenderPosition() const  	{  		return getPosition() * mDrawable->getParent()->getRenderMatrix();  	} +	 +	  }  void LLVOAvatar::updateDrawable(BOOL force_damped) @@ -1291,6 +1294,8 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)  		mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition();  		mDrawable->setPositionGroup(pos_group);  	} +	 +	  }  void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) @@ -1543,7 +1548,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector  	return hit;  } - +	  LLVOAvatar* LLVOAvatar::asAvatar()  {  	return this; @@ -1878,22 +1883,26 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU  	}  	if (!result) -{ +	{  		const std::string url = getImageURL(te,uuid);  		if (!url.empty()) -	{ -			LL_DEBUGS("Avatar") << avString() << "from URL " << url << llendl; +		{ +			LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << llendl;  			result = LLViewerTextureManager::getFetchedTextureFromUrl(  				url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); -	} -	else -	{ -			LL_DEBUGS("Avatar") << avString() << "from host " << uuid << llendl; +			if (result->isMissingAsset()) +			{ +				result->setIsMissingAsset(false); +			} +		} +		else +		{ +			LL_DEBUGS("Avatar") << avString() << "get old-bake image from host " << uuid << llendl;  			LLHost host = getObjectHost();  			result = LLViewerTextureManager::getFetchedTexture(  				uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); +		}  	} -}  	return result;  } @@ -2145,7 +2154,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)  		{  			LLVector3 tagPos = mRoot->getWorldPosition();  			tagPos[VZ] -= mPelvisToFoot; -			tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); +			tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); // does not need mAvatarOffset -Nyx  			mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos );  		}  	}//if ( voiceEnabled ) @@ -2886,6 +2895,8 @@ void LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)  	local_camera_up.normalize();  	local_camera_up = local_camera_up * inv_root_rot; + +	// position is based on head position, does not require mAvatarOffset here. - Nyx  	LLVector3 avatar_ellipsoid(mBodySize.mV[VX] * 0.4f,  								mBodySize.mV[VY] * 0.4f,  								mBodySize.mV[VZ] * NAMETAG_VERT_OFFSET_WEIGHT); @@ -2987,7 +2998,7 @@ bool LLVOAvatar::isVisuallyMuted() const  // called on both your avatar and other avatars  //------------------------------------------------------------------------  BOOL LLVOAvatar::updateCharacter(LLAgent &agent) -{ +{	  	// clear debug text  	mDebugText.clear(); @@ -3502,6 +3513,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  	//mesh vertices need to be reskinned  	mNeedsSkin = TRUE; + +		 +	  	return TRUE;  }  //----------------------------------------------------------------------------- @@ -3535,9 +3549,9 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,  {  	mHasPelvisOffset = hasOffset;  	if ( mHasPelvisOffset ) -	{ +	{	  		//Store off last pelvis to foot value -		mLastPelvisToFoot = mPelvisToFoot; +		mLastPelvisToFoot = mPelvisToFoot;		  		mPelvisOffset	  = offsetAmount;  		mLastPelvisFixup  = mPelvisFixup;  		mPelvisFixup	  = pelvisFixup; @@ -3547,18 +3561,16 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,  // postPelvisSetRecalc  //------------------------------------------------------------------------  void LLVOAvatar::postPelvisSetRecalc( void ) -{	 -	computeBodySize();  -	mRoot->touch(); -	mRoot->updateWorldMatrixChildren();	 -	dirtyMesh(); -	updateHeadOffset(); +{		 +	mRoot->updateWorldMatrixChildren();			 +	computeBodySize(); +	dirtyMesh(2);  }  //------------------------------------------------------------------------ -// pelisPoke +// setPelvisOffset  //------------------------------------------------------------------------  void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount ) -{	 +{		  	mHasPelvisOffset  = true;  	mLastPelvisFixup  = mPelvisFixup;	  	mPelvisFixup	  = pelvisFixupAmount;	 @@ -3980,7 +3992,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)  		{  			LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);  			if (hair_mesh) -		{ +			{  				num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);  			}  			first_pass = FALSE; @@ -3990,7 +4002,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)  			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);  		}  	} -	 +  	return num_indices;  } @@ -4409,7 +4421,7 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture  }  const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames.	 -const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames +const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL = S32_MAX ; //frames  void LLVOAvatar::checkTextureLoading()  {  	static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds @@ -4472,11 +4484,11 @@ const F32  ADDITIONAL_PRI = 0.5f;  void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level)  {  	//Note: -	//if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames,  +	//if this function is not called for the last MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL frames,   	//the texture pipeline will stop fetching this texture.  	imagep->resetTextureStats(); -	imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); +	imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);  	imagep->resetMaxVirtualSizeResetCounter() ;  	mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); @@ -4920,70 +4932,39 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )  	return jointp;  } - -//----------------------------------------------------------------------------- -// resetJointPositions -//----------------------------------------------------------------------------- -void LLVOAvatar::resetJointPositions( void ) -{ -	avatar_joint_list_t::iterator iter = mSkeleton.begin(); -	avatar_joint_list_t::iterator end  = mSkeleton.end(); -	for (; iter != end; ++iter) -	{ -		(*iter)->restoreOldXform(); -		(*iter)->setId( LLUUID::null ); -	} -	mHasPelvisOffset = false; -	mPelvisFixup	 = mLastPelvisFixup; -} -//----------------------------------------------------------------------------- -// resetSpecificJointPosition -//----------------------------------------------------------------------------- -void LLVOAvatar::resetSpecificJointPosition( const std::string& name ) -{ -	LLJoint* pJoint = mRoot->findJoint( name ); -	 -	if ( pJoint  && pJoint->doesJointNeedToBeReset() ) -	{ -		pJoint->restoreOldXform(); -		pJoint->setId( LLUUID::null ); -		//If we're reseting the pelvis position make sure not to apply offset -		if ( name == "mPelvis" ) -		{ -			mHasPelvisOffset = false; -		} -	} -	else -	{ -		llinfos<<"Did not find "<< name.c_str()<<llendl; -	} -}  //-----------------------------------------------------------------------------  // resetJointPositionsToDefault  //-----------------------------------------------------------------------------  void LLVOAvatar::resetJointPositionsToDefault( void ) -{ +{	  	//Subsequent joints are relative to pelvis  	avatar_joint_list_t::iterator iter = mSkeleton.begin();  	avatar_joint_list_t::iterator end  = mSkeleton.end(); + +	LLJoint* pJointPelvis = getJoint("mPelvis"); +	  	for (; iter != end; ++iter)  	{  		LLJoint* pJoint = (*iter); -		if ( pJoint->doesJointNeedToBeReset() ) +		//Reset joints except for pelvis +		if ( pJoint && pJoint != pJointPelvis && pJoint->doesJointNeedToBeReset() ) +		{			 +			pJoint->setId( LLUUID::null ); +			pJoint->restoreOldXform(); +		}		 +		else +		if ( pJoint && pJoint == pJointPelvis && pJoint->doesJointNeedToBeReset() )  		{  			pJoint->setId( LLUUID::null ); -			//restore joints to default positions, however skip over the pelvis -			// *TODO: How does this pointer check skip over pelvis? -			if ( pJoint ) -			{ -				pJoint->restoreOldXform(); -			} -		} -	} +			pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) ); +			pJoint->setJointResetFlag( false ); +		}		 +	}	 +		  	//make sure we don't apply the joint offset  	mHasPelvisOffset = false;  	mPelvisFixup	 = mLastPelvisFixup; -	postPelvisSetRecalc(); +	postPelvisSetRecalc();	  }  //-----------------------------------------------------------------------------  // getCharacterPosition() @@ -5107,9 +5088,9 @@ BOOL LLVOAvatar::loadSkeletonNode ()  {  	if (!LLAvatarAppearance::loadSkeletonNode())  	{ -				return FALSE; -			} -	 +		return FALSE; +	} +  	// ATTACHMENTS  	{  		LLAvatarXmlInfo::attachment_info_list_t::iterator iter; @@ -5138,7 +5119,7 @@ BOOL LLVOAvatar::loadSkeletonNode ()  			{  				attachment->setOriginalPosition(info->mPosition);  			} - +			  			if (info->mHasRotation)  			{  				LLQuaternion rotation; @@ -5208,7 +5189,6 @@ void LLVOAvatar::updateVisualParams()  	dirtyMesh();  	updateHeadOffset();  } -  //-----------------------------------------------------------------------------  // isActive()  //----------------------------------------------------------------------------- @@ -5547,6 +5527,7 @@ void LLVOAvatar::lazyAttach()  void LLVOAvatar::resetHUDAttachments()  { +  	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();   		 iter != mAttachmentPoints.end();  		 ++iter) @@ -5599,10 +5580,10 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )  		{  			const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj );  			if (pSkinData  -				&& pSkinData->mJointNames.size() > 20				// full rig -				&& pSkinData->mAlternateBindMatrix.size() > 0) -					{ -						LLVOAvatar::resetJointPositionsToDefault(); +				&& pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG	// full rig +				&& pSkinData->mAlternateBindMatrix.size() > 0 ) +					{				 +						LLVOAvatar::resetJointPositionsToDefault();							  						//Need to handle the repositioning of the cam, updating rig data etc during outfit editing   						//This handles the case where we detach a replacement rig.  						if ( gAgentCamera.cameraCustomizeAvatar() ) @@ -5620,6 +5601,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )  //-----------------------------------------------------------------------------  BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  { +  	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();   		 iter != mAttachmentPoints.end();  		 ++iter) @@ -5628,7 +5610,9 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  		if (attachment->isObjectAttached(viewer_object))  		{ +		  			cleanupAttachedMesh( viewer_object ); +		  			attachment->removeObject(viewer_object);  			lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl;  			return TRUE; @@ -5826,26 +5810,24 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const  	{  		const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_iter->second;  		if (texture_dict->mWearableType == type) -	{ +		{  			// Thus, you must check to see if the corresponding baked texture is defined.  			// NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing  			// this works for detecting a skirt (most important), but is ineffective at any piece of clothing that  			// gets baked into a texture that always exists (upper or lower).  			if (texture_dict->mIsUsedByBakedTexture) -	{ +			{  				const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;  				return isTextureDefined(LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex); -	} +			}  			return FALSE; -	} +		}  	}  	return FALSE;  } - -  // virtual  void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result )  { @@ -5880,7 +5862,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL  			{  				LLAvatarJointMesh* mesh = (*iter);  				if (mesh) -			{ +				{  					mesh->setColor( color );  				}  			} @@ -5948,9 +5930,9 @@ void LLVOAvatar::updateRezzedStatusTimers()  		{  			// load level has decreased. start phase timers for higher load levels.  			for (S32 i = rez_status+1; i <= mLastRezzedStatus; i++) -		{ +			{  				startPhase("load_" + LLVOAvatar::rezStatusToString(i)); -		} +			}  		}  		else if (rez_status > mLastRezzedStatus)  		{ @@ -5959,16 +5941,16 @@ void LLVOAvatar::updateRezzedStatusTimers()  			{  				stopPhase("load_" + LLVOAvatar::rezStatusToString(i));  				stopPhase("first_load_" + LLVOAvatar::rezStatusToString(i), false); -		} +			}  			if (rez_status == 3) -		{ +			{  				// "fully loaded", mark any pending appearance change complete.  				selfStopPhase("update_appearance_from_cof");  				selfStopPhase("wear_inventory_category", false);  				selfStopPhase("process_initial_wearables_update", false);  			}  		} -		 +  		mLastRezzedStatus = rez_status;  	}  } @@ -5980,9 +5962,12 @@ void LLVOAvatar::clearPhases()  void LLVOAvatar::startPhase(const std::string& phase_name)  { -	F32 elapsed; -	bool completed; -	if (getPhases().getPhaseValues(phase_name, elapsed, completed)) +	F32 elapsed = 0.0; +	bool completed = false; +	bool found = getPhases().getPhaseValues(phase_name, elapsed, completed); +	//LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name +	//					<< " found " << found << " elapsed " << elapsed << " completed " << completed << llendl; +	if (found)  	{  		if (!completed)  		{ @@ -5990,15 +5975,18 @@ void LLVOAvatar::startPhase(const std::string& phase_name)  			return;  		}  	} -	LL_DEBUGS("Avatar") << "started phase " << phase_name << llendl; +	LL_DEBUGS("Avatar") << avString() << " started phase " << phase_name << llendl;  	getPhases().startPhase(phase_name);  }  void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) -		{ -	F32 elapsed; -	bool completed; -	if (getPhases().getPhaseValues(phase_name, elapsed, completed)) +{ +	F32 elapsed = 0.0; +	bool completed = false; +	bool found = getPhases().getPhaseValues(phase_name, elapsed, completed); +	//LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name +	//					<< " found " << found << " elapsed " << elapsed << " completed " << completed << llendl; +	if (found)  	{  		if (!completed)  		{ @@ -6027,7 +6015,7 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)  void LLVOAvatar::logPendingPhases()  {  	if (!isAgentAvatarValid()) -		{ +	{  		return;  	} @@ -6043,14 +6031,14 @@ void LLVOAvatar::logPendingPhases()  			if (!completed)  			{  				logMetricsTimerRecord(phase_name, elapsed, completed); -		} +			}  		}  	} -		} +}  //static  void LLVOAvatar::logPendingPhasesAllAvatars() -		{ +{  	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();  		 iter != LLCharacter::sInstances.end(); ++iter)  	{ @@ -6061,14 +6049,14 @@ void LLVOAvatar::logPendingPhasesAllAvatars()  		}  		inst->logPendingPhases();  	} -		} +}  void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed) -		{ +{  	if (!isAgentAvatarValid()) -		{ +	{  		return; -		} +	}  	LLSD record;  	record["timer_name"] = phase_name; @@ -6077,15 +6065,15 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse  	record["completed"] = completed;  	U32 grid_x(0), grid_y(0);  	if (getRegion()) -		{ +	{  		record["central_bake_version"] = LLSD::Integer(getRegion()->getCentralBakeVersion());  		grid_from_region_handle(getRegion()->getHandle(), &grid_x, &grid_y); -		} +	}  	record["grid_x"] = LLSD::Integer(grid_x);  	record["grid_y"] = LLSD::Integer(grid_y);  	record["is_using_server_bakes"] = ((bool) isUsingServerBakes());  	record["is_self"] = isSelf(); -		 +	  	if (isAgentAvatarValid())  	{  		gAgentAvatarp->addMetricsTimerRecord(record); @@ -6293,28 +6281,28 @@ void LLVOAvatar::updateMeshTextures()  										   use_lkg_baked_layer[i],  										   last_id_string.c_str());  	} - +	  	for (U32 i=0; i < mBakedTextureDatas.size(); i++)  	{  		debugColorizeSubMeshes(i, LLColor4::white);  		LLViewerTexLayerSet* layerset = getTexLayerSet(i);  		if (use_lkg_baked_layer[i] && !isUsingLocalAppearance() ) -	{ +		{  			LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[i].mLastTextureID);  			mBakedTextureDatas[i].mIsUsed = TRUE;  			debugColorizeSubMeshes(i,LLColor4::red); -	 +  			avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();  			avatar_joint_mesh_list_t::iterator end  = mBakedTextureDatas[i].mJointMeshes.end();  			for (; iter != end; ++iter) -	{ +			{  				LLAvatarJointMesh* mesh = (*iter);  				if (mesh) -		{ +				{  					mesh->setTexture( baked_img ); -			} +				}  			}  		}  		else if (!isUsingLocalAppearance() && is_layer_baked[i]) @@ -6340,6 +6328,9 @@ void LLVOAvatar::updateMeshTextures()  				}  				baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ),   					src_callback_list, paused ); + +                               // this could add paused texture callbacks +                               mLoadedCallbacksPaused |= paused;   			}  		}  		else if (layerset && isUsingLocalAppearance()) @@ -6358,7 +6349,7 @@ void LLVOAvatar::updateMeshTextures()  				if (mesh)  				{  					mesh->setLayerSet( layerset ); -			} +				}  			}  		}  		else @@ -6380,7 +6371,7 @@ void LLVOAvatar::updateMeshTextures()  		{  			LLAvatarJointMesh* mesh = (*iter);  			if (mesh) -		{ +			{  				mesh->setColor( color );  				mesh->setTexture( hair_img );  			} @@ -6468,18 +6459,17 @@ void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_com  	for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin();  		 iter != mBakedTextureDatas[index].mMaskedMorphs.end(); ++iter) -{ +	{  		const LLMaskedMorph* maskedMorph = (*iter);  		LLPolyMorphTarget* morph_target = dynamic_cast<LLPolyMorphTarget*>(maskedMorph->mMorphTarget);  		if (morph_target) -	{ +		{  			morph_target->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert); -} +		}  	}  } -  // returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise  BOOL LLVOAvatar::morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index)  { @@ -6690,6 +6680,9 @@ void LLVOAvatar::onFirstTEMessageReceived()  				LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL;  				image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ),   					src_callback_list, paused ); + +                               // this could add paused texture callbacks +                               mLoadedCallbacksPaused |= paused;   			}  		} @@ -6757,12 +6750,12 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)  					LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str()  //					param_location_name(vparam->getParamLocation()).c_str()  		); -	} -	 +} +  void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,  	const LLAppearanceMessageContents& contents) -	{ +{  	std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml");  	const std::vector<F32>& params_for_dump = contents.mParamWeights;  	const LLTEContents& tec = contents.mTEContents; @@ -6772,9 +6765,9 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,  	outfile.open(fullpath, LL_APR_WB );  	apr_file_t* file = outfile.getFileHandle();  	if (!file) -		{ -			return; -		} +	{ +		return; +	}  	else  	{  		LL_DEBUGS("Avatar") << "dumping appearance message to " << fullpath << llendl; @@ -6789,7 +6782,8 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,  	LLVisualParam* param = getFirstVisualParam();  	for (S32 i = 0; i < params_for_dump.size(); i++)  	{ -		while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +		while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&  +						 (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  		{  			param = getNextVisualParam();  		} @@ -6808,7 +6802,7 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,  		apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", i, uuid_str.c_str());  	}  	apr_file_printf(file, "</textures>\n"); -	} +}  void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& contents)  { @@ -6825,7 +6819,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe  		// For future use:  		//mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0);  	} -	 +  	// Parse visual params, if any.  	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);  	bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing @@ -6843,7 +6837,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe  		{  			for( S32 i = 0; i < num_blocks; i++ )  			{ -				while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +				while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&  +								 (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  				{  					param = getNextVisualParam();  				} @@ -6864,7 +6859,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe  			}  		} -		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) + +											 getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  		if (num_blocks != expected_tweakable_count)  		{  			LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << ").  Processing what we can.  object: " << getID() << llendl; @@ -6931,7 +6927,7 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32  void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  {  	LL_DEBUGS("Avatar") << "starts" << llendl; -	 +  	bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");  	std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_";  	if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages")) @@ -7006,7 +7002,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		return;  	} -	mLastUpdateReceivedCOFVersion = this_update_cof_version; +	// No backsies zone - if we get here, the message should be valid and usable. +	if (appearance_version > 0) +	{ +		// Note: +		// RequestAgentUpdateAppearanceResponder::onRequestRequested() +		// assumes that cof version is only updated with server-bake +		// appearance messages. +		mLastUpdateReceivedCOFVersion = this_update_cof_version; +	}  	setIsUsingServerBakes(appearance_version > 0); @@ -7019,9 +7023,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  			&& mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT  			&& baked_index != BAKED_SKIRT)  		{ +			LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << llendl;  			setTEImage(mBakedTextureDatas[baked_index].mTextureIndex,   				LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));  		} +		else +		{ +			LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using texture id " +								<< getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << llendl; +		}  	}  	// runway - was @@ -7047,32 +7057,38 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL;  		BOOL params_changed = FALSE;  		BOOL interp_params = FALSE; +		S32 params_changed_count = 0;  		for( S32 i = 0; i < num_params; i++ )  		{  			LLVisualParam* param = contents.mParams[i];  			F32 newWeight = contents.mParamWeights[i]; -				if (is_first_appearance_message || (param->getWeight() != newWeight)) +			if (is_first_appearance_message || (param->getWeight() != newWeight)) +			{ +				params_changed = TRUE; +				params_changed_count++; +				if(is_first_appearance_message)  				{ -					params_changed = TRUE; -					if(is_first_appearance_message) -					{ -						param->setWeight(newWeight, FALSE); -					} -					else -					{ -						interp_params = TRUE; -						param->setAnimationTarget(newWeight, FALSE); -					} +					//LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << llendl; +					param->setWeight(newWeight, FALSE); +				} +				else +				{ +					//LL_DEBUGS("Avatar") << std::setprecision(5) << " param target " << i << " " << param->getWeight() << " -> " << newWeight << llendl; +					interp_params = TRUE; +					param->setAnimationTarget(newWeight, FALSE);  				} +			}  		} -		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) + +											 getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  		if (num_params != expected_tweakable_count)  		{  			LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_params << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << ").  Processing what we can.  object: " << getID() << llendl;  		} +		LL_DEBUGS("Avatar") << "Changed " << params_changed_count << " params" << llendl;  		if (params_changed)  		{  			if (interp_params) @@ -7122,7 +7138,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  	}  	updateMeshTextures(); -  	//if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");  } @@ -7305,7 +7320,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )  		LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 );  		if (id == image_baked->getID())  		{ -			LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; +			//LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL;  			mBakedTextureDatas[i].mIsLoaded = true;  			mBakedTextureDatas[i].mLastTextureID = id;  			mBakedTextureDatas[i].mIsUsed = true; @@ -7321,12 +7336,12 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )  				avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();  				avatar_joint_mesh_list_t::iterator end  = mBakedTextureDatas[i].mJointMeshes.end();  				for (; iter != end; ++iter) -			{ +				{  					LLAvatarJointMesh* mesh = (*iter);  					if (mesh) -			{ +					{  						mesh->setTexture( image_baked ); -			} +					}  				}  			} @@ -7350,7 +7365,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )  				{  					LLAvatarJointMesh* mesh = (*iter);  					if (mesh) -				{ +					{  						mesh->setColor( LLColor4::white );  					}  				} @@ -7369,7 +7384,7 @@ std::string get_sequential_numbered_file_name(const std::string& prefix,  	file_num_type::iterator it = file_nums.find(prefix);  	S32 num = 0;  	if (it != file_nums.end()) -{ +	{  		num = it->second;  	}  	file_nums[prefix] = num+1; @@ -7378,6 +7393,15 @@ std::string get_sequential_numbered_file_name(const std::string& prefix,  	return outfilename;  } +void dump_sequential_xml(const std::string outprefix, const LLSD& content) +{ +	std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); +	std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); +	std::ofstream ofs(fullpath.c_str(), std::ios_base::out); +	ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY); +	LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL; +} +  void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_wearables )  {  	std::string outprefix(prefix); @@ -7386,10 +7410,6 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara  		outprefix = getFullname() + (isSelf()?"_s":"_o");  	}  	if (outprefix.empty()) -{ -		outprefix = getFullname() + (isSelf()?"_s":"_o"); -	} -	if (outprefix.empty())  	{  		outprefix = std::string("new_archetype");  	} @@ -7415,36 +7435,36 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara  	if (group_by_wearables)  	{  		for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++) -	{ -		const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type); -		apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() ); +		{ +			const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type); +			apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );  			for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam()) -		{ -			LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; -			if( (viewer_param->getWearableType() == type) &&  -				(viewer_param->isTweakable() ) )  			{ +				LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; +				if( (viewer_param->getWearableType() == type) &&  +					(viewer_param->isTweakable() ) ) +				{  					dump_visual_param(file, viewer_param, viewer_param->getWeight()); +				}  			} -		} -		for (U8 te = 0; te < TEX_NUM_INDICES; te++) -		{ -				if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type) +			for (U8 te = 0; te < TEX_NUM_INDICES; te++)  			{ -				// MULTIPLE_WEARABLES: extend to multiple wearables? -					LLViewerTexture* te_image = getImage((ETextureIndex)te, 0); -				if( te_image ) +				if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type)  				{ -					std::string uuid_str; -					te_image->getID().toString( uuid_str ); -					apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str()); +					// MULTIPLE_WEARABLES: extend to multiple wearables? +					LLViewerTexture* te_image = getImage((ETextureIndex)te, 0); +					if( te_image ) +					{ +						std::string uuid_str; +						te_image->getID().toString( uuid_str ); +						apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str()); +					}  				}  			}  		}  	} -		}  	else   	{  		// Just dump all params sequentially. @@ -7456,6 +7476,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara  		for (U8 te = 0; te < TEX_NUM_INDICES; te++)  		{ +			{  				// MULTIPLE_WEARABLES: extend to multiple wearables?  				LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);  				if( te_image ) @@ -7467,6 +7488,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara  			}  		} +	}  	apr_file_printf( file, "\t</archetype>\n" );  	apr_file_printf( file, "\n</linden_genepool>\n" ); @@ -7588,14 +7610,14 @@ void LLVOAvatar::startAppearanceAnimation()  	}  } -// virtual +//virtual  void LLVOAvatar::bodySizeChanged() -{	 +{  	if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF())  	{	// notify simulator of change in size  		// but not if we are in the middle of updating appearance  		gAgent.sendAgentSetAppearance(); -} +	}  }  BOOL LLVOAvatar::isUsingServerBakes() const @@ -7607,25 +7629,25 @@ BOOL LLVOAvatar::isUsingServerBakes() const  	F32 wt = appearance_version_param->getWeight();  	F32 expect_wt = mUseServerBakes ? 1.0 : 0.0;  	if (!is_approx_equal(wt,expect_wt)) -{ +	{  		llwarns << "wt " << wt << " differs from expected " << expect_wt << llendl;  	}  #endif  	return mUseServerBakes; -		} -		 +} +  void LLVOAvatar::setIsUsingServerBakes(BOOL newval) -		{ +{  	mUseServerBakes = newval;  	LLVisualParam* appearance_version_param = getVisualParam(11000);  	llassert(appearance_version_param);  	appearance_version_param->setWeight(newval ? 1.0 : 0.0, false); -		} +}  // virtual  void LLVOAvatar::removeMissingBakedTextures() -			{ +{	  }  //virtual diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index b05eed344b..8d047045cb 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -199,9 +199,7 @@ public:  	virtual LLJoint*		getJoint(const std::string &name); -	void					resetJointPositions( void );  	void					resetJointPositionsToDefault( void ); -	void					resetSpecificJointPosition( const std::string& name );  	/*virtual*/ const LLUUID&	getID() const;  	/*virtual*/ void			addDebugText(const std::string& text); @@ -210,7 +208,7 @@ public:  	/*virtual*/ F32				getPixelArea() const;  	/*virtual*/ LLVector3d		getPosGlobalFromAgent(const LLVector3 &position);  	/*virtual*/ LLVector3		getPosAgentFromGlobal(const LLVector3d &position); -	virtual void			updateVisualParams(); +	virtual void				updateVisualParams();  /**                    Inherited @@ -991,10 +989,11 @@ protected: // Shared with LLVOAvatarSelf  }; // LLVOAvatar  extern const F32 SELF_ADDITIONAL_PRI; -extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; +extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL;  std::string get_sequential_numbered_file_name(const std::string& prefix,  											  const std::string& suffix); +void dump_sequential_xml(const std::string outprefix, const LLSD& content);  void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value);  #endif // LL_VOAVATAR_H diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 15628d5ab2..ac59aa0907 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -63,6 +63,7 @@  #include "llsdutil.h"  #include "llstartup.h"  #include "llsdserialize.h" +#include "llversioninfo.h"  #if LL_MSVC  // disable boost::lexical_cast warning @@ -234,6 +235,33 @@ void LLVOAvatarSelf::initInstance()  	//doPeriodically(output_self_av_texture_diagnostics, 30.0);  	doPeriodically(update_avatar_rez_metrics, 5.0);  	doPeriodically(check_for_unsupported_baked_appearance, 120.0); +	doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); +} + +bool LLVOAvatarSelf::checkStuckAppearance() +{ +	const F32 CONDITIONAL_UNSTICK_INTERVAL = 300.0; +	const F32 UNCONDITIONAL_UNSTICK_INTERVAL = 600.0; +	 +	if (gAgentWearables.isCOFChangeInProgress()) +	{ +		LL_DEBUGS("Avatar") << "checking for stuck appearance" << llendl; +		F32 change_time = gAgentWearables.getCOFChangeTime(); +		LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << llendl; +		S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns(); +		LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << llendl; +		S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations(); +		LL_DEBUGS("Avatar") << "active copy operations " << active_copies << llendl; + +		if ((change_time > CONDITIONAL_UNSTICK_INTERVAL && active_copies == 0) || +			(change_time > UNCONDITIONAL_UNSTICK_INTERVAL)) +		{ +			gAgentWearables.notifyLoadingFinished(); +		} +	} + +	// Return false to continue running check periodically. +	return LLApp::isExiting();  }  // virtual @@ -602,7 +630,7 @@ LLVOAvatarSelf::~LLVOAvatarSelf()   **                                                                             **   *********************************************************************************/ -//virtual +// virtual  BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent)  {  	// update screen joint size @@ -644,11 +672,6 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name)  	}  	return LLVOAvatar::getJoint(name);  } -//virtual -void LLVOAvatarSelf::resetJointPositions( void ) -{ -	return LLVOAvatar::resetJointPositions(); -}  // virtual  BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake )  { @@ -866,10 +889,10 @@ void LLVOAvatarSelf::removeMissingBakedTextures()  		updateMeshTextures();  		if (getRegion() && !getRegion()->getCentralBakeVersion())  		{ -		requestLayerSetUploads(); +			requestLayerSetUploads(); +		}  	}  } -}  //virtual  void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) @@ -1310,7 +1333,7 @@ void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *sr  			discard_level < local_tex_obj->getDiscard())  		{  			local_tex_obj->setDiscard(discard_level); -				requestLayerSetUpdate(index); +			requestLayerSetUpdate(index);  			if (isEditingAppearance())  			{  				LLVisualParamHint::requestHintUpdates(); @@ -1799,11 +1822,11 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te  					{  						requestLayerSetUpdate(type);  						if (isEditingAppearance()) -					{ -						LLVisualParamHint::requestHintUpdates(); +						{ +							LLVisualParamHint::requestHintUpdates(); +						}  					}  				} -				}  				else  				{					  					tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), type), NULL); @@ -2241,6 +2264,7 @@ LLSD LLVOAvatarSelf::metricsData()  class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder  { +	LOG_CLASS(ViewerAppearanceChangeMetricsResponder);  public:  	ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,  											volatile const S32 & live_sequence, @@ -2251,32 +2275,25 @@ public:  	{  	} -	virtual void completed(U32 status, -						   const std::string& reason, -						   const LLSD& content) +private: +	/* virtual */ void httpSuccess()  	{ -		gPendingMetricsUploads--; // if we add retry, this should be moved to the isGoodStatus case. -		if (isGoodStatus(status)) -		{ -			LL_DEBUGS("Avatar") << "OK" << LL_ENDL; -			result(content); -		} -		else -		{ -			LL_WARNS("Avatar") << "Failed " << status << " reason " << reason << LL_ENDL; -			errorWithContent(status,reason,content); -		} -	} +		LL_DEBUGS("Avatar") << "OK" << LL_ENDL; -	// virtual -	void result(const LLSD & content) -	{ +		gPendingMetricsUploads--;  		if (mLiveSequence == mExpectedSequence)  		{  			mReportingStarted = true;  		}  	} +	/* virtual */ void httpFailure() +	{ +		// if we add retry, this should be removed from the httpFailure case +		LL_WARNS("Avatar") << dumpResponse() << LL_ENDL; +		gPendingMetricsUploads--; +	} +  private:  	S32 mExpectedSequence;  	volatile const S32 & mLiveSequence; @@ -2357,12 +2374,29 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records,  	return result;  } +// Valid characters for tsdb are alphanumeric, _-./. Others must be cleaned out. +void sanitize_for_tsdb_tag(std::string& s) +{ +	for (std::string::iterator it = s.begin(); it != s.end(); ++it) +	{ +		if (std::isalnum(*it) || *it == '.' || *it == '_' || *it == '-' || *it == '/') +		{ +			continue; +		} +		*it = '_'; +	} +} +  void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  { -	// gAgentAvatarp->stopAllPhases();  	static volatile bool reporting_started(false);  	static volatile S32 report_sequence(0); +	std::string viewer_version_channel = LLVersionInfo::getChannel(); +	sanitize_for_tsdb_tag(viewer_version_channel); +	std::string viewer_version_short = LLVersionInfo::getShortVersion(); +	std::string viewer_version_build = llformat("%d", LLVersionInfo::getBuild()); +  	LLSD msg; // = metricsData();  	msg["message"] = "ViewerAppearanceChangeMetrics";  	msg["session_id"] = gAgentSessionID; @@ -2371,6 +2405,9 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  	msg["initial"] = !reporting_started;  	msg["break"] = false;  	msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32(); +	msg["viewer_version_channel"] = viewer_version_channel; +	msg["viewer_version_short"] = viewer_version_short; +	msg["viewer_version_build"] = viewer_version_build;  	// Status of our own rezzing.  	msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); @@ -2425,6 +2462,7 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder  { +	LOG_CLASS(CheckAgentAppearanceServiceResponder);  public:  	CheckAgentAppearanceServiceResponder()  	{ @@ -2434,22 +2472,24 @@ public:  	{  	} -	/* virtual */ void result(const LLSD& content) +private: +	/* virtual */ void httpSuccess()  	{ -		LL_DEBUGS("Avatar") << "status OK" << llendl; +		LL_DEBUGS("Avatar") << "OK" << llendl;  	}  	// Error -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	/*virtual*/ void httpFailure()  	{  		if (isAgentAvatarValid())  		{ -			LL_DEBUGS("Avatar") << "failed, will rebake [status:" -					<< status << "]: " << content << llendl; +			LL_DEBUGS("Avatar") << "failed, will rebake " +					<< dumpResponse() << LL_ENDL;  			forceAppearanceUpdate();  		} -	}	 +	} +public:  	static void forceAppearanceUpdate()  	{  		// Trying to rebake immediately after crossing region boundary @@ -2580,25 +2620,25 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe  	//if (!covered_by_baked)  	{  		if (imagep->getID() != IMG_DEFAULT_AVATAR) -	{ +		{  			imagep->setNoDelete();  			if (imagep->getDiscardLevel() != 0) -		{ -			F32 desired_pixels; -			desired_pixels = llmin(mPixelArea, (F32)getTexImageArea()); - -			imagep->setBoostLevel(getAvatarBoostLevel()); -				imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; -			imagep->resetTextureStats(); -			imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); -			imagep->addTextureStats( desired_pixels / texel_area_ratio ); -			imagep->forceUpdateBindStats() ; -			if (imagep->getDiscardLevel() < 0)  			{ -				mHasGrey = TRUE; // for statistics gathering +				F32 desired_pixels; +				desired_pixels = llmin(mPixelArea, (F32)getTexImageArea()); +				 +				imagep->setBoostLevel(getAvatarBoostLevel()); +				imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; +				imagep->resetTextureStats(); +				imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); +				imagep->addTextureStats( desired_pixels / texel_area_ratio ); +				imagep->forceUpdateBindStats() ; +				if (imagep->getDiscardLevel() < 0) +				{ +					mHasGrey = TRUE; // for statistics gathering +				}  			}  		} -		}  		else  		{  			// texture asset is missing @@ -2921,17 +2961,17 @@ void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index )  LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const  { -	/* switch(index) -		case TEX_HEAD_BAKED: -		case TEX_HEAD_BODYPAINT: -			return mHeadLayerSet; */ +       /* switch(index) +               case TEX_HEAD_BAKED: +               case TEX_HEAD_BODYPAINT: +                       return mHeadLayerSet; */         const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index); -	if (texture_dict->mIsUsedByBakedTexture) -	{ -		const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; +       if (texture_dict->mIsUsedByBakedTexture) +       { +               const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;                 return getLayerSet(baked_index); -	} -	return NULL; +       } +       return NULL;  }  LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index) const @@ -2955,11 +2995,16 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch)  {  	if (isAgentAvatarValid())  	{ +		if (!gAgentAvatarp->mEndCustomizeCallback.get()) +		{ +			gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy; +		} +		  		gAgentAvatarp->mIsEditingAppearance = true;  		gAgentAvatarp->mUseLocalAppearance = true;  		if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch) -{ +		{  			gAgentCamera.changeCameraToCustomizeAvatar();  		} @@ -2994,8 +3039,11 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch)  			gAgentCamera.changeCameraToDefault();  			gAgentCamera.resetView();  		} -	 -		LLAppearanceMgr::instance().updateAppearanceFromCOF();	 + +		// Dereferencing the previous callback will cause +		// updateAppearanceFromCOF to be called, whenever all refs +		// have resolved. +		gAgentAvatarp->mEndCustomizeCallback = NULL;  	}  } diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 3b7b6bac64..3cbf2b5cf5 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -32,6 +32,7 @@  #include "llvoavatar.h"  struct LocalTextureData; +class LLInventoryCallback;  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -138,6 +139,7 @@ public:  public:  	/*virtual*/ BOOL 	updateCharacter(LLAgent &agent);  	/*virtual*/ void 	idleUpdateTractorBeam(); +	bool				checkStuckAppearance();  	//--------------------------------------------------------------------  	// Loading state @@ -341,6 +343,7 @@ private:  public:  	static void		onCustomizeStart(bool disable_camera_switch = false);  	static void		onCustomizeEnd(bool disable_camera_switch = false); +	LLPointer<LLInventoryCallback> mEndCustomizeCallback;  	//--------------------------------------------------------------------  	// Visibility diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index ac2a34ba1e..397c5cd81f 100755 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -53,26 +53,27 @@ const U32 DEFAULT_RETRIES_COUNT = 3;  class LLVoiceCallCapResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLVoiceCallCapResponder);  public:  	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; +protected:  	// called with bad status codes -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	virtual void result(const LLSD& content); +	virtual void httpFailure(); +	virtual void httpSuccess();  private:  	LLUUID mSessionID;  }; -void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLVoiceCallCapResponder::httpFailure()  { -	LL_WARNS("Voice") << "LLVoiceCallCapResponder error [status:" -		<< status << "]: " << content << LL_ENDL; +	LL_WARNS("Voice") << dumpResponse() << LL_ENDL;  	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);  	if ( channelp )  	{ -		if ( 403 == status ) +		if ( HTTP_FORBIDDEN == getStatus() )  		{  			//403 == no ability  			LLNotificationsUtil::add( @@ -89,12 +90,18 @@ void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& re  	}  } -void LLVoiceCallCapResponder::result(const LLSD& content) +void LLVoiceCallCapResponder::httpSuccess()  {  	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);  	if (channelp)  	{  		//*TODO: DEBUG SPAM +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLSD::map_const_iterator iter;  		for(iter = content.beginMap(); iter != content.endMap(); ++iter)  		{ diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index cff3551607..d30fd5677d 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -124,17 +124,19 @@ static int scale_speaker_volume(float volume)  class LLVivoxVoiceAccountProvisionResponder :  	public LLHTTPClient::Responder  { +	LOG_CLASS(LLVivoxVoiceAccountProvisionResponder);  public:  	LLVivoxVoiceAccountProvisionResponder(int retries)  	{  		mRetries = retries;  	} -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpFailure()  	{  		LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, "  			<<  ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" ) -			<< status << "]: " << content << LL_ENDL; +			<< " " << dumpResponse() << LL_ENDL;  		if ( mRetries > 0 )  		{ @@ -146,14 +148,19 @@ public:  		}  	} -	virtual void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{ -  		std::string voice_sip_uri_hostname;  		std::string voice_account_server_uri; -		LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; +		LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		if(content.has("voice_sip_uri_hostname"))  			voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); @@ -166,7 +173,6 @@ public:  			content["password"].asString(),  			voice_sip_uri_hostname,  			voice_account_server_uri); -  	}  private: @@ -190,33 +196,34 @@ static bool sMuteListListener_listening = false;  class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLVivoxVoiceClientCapResponder);  public:  	LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {}; +private:  	// called with bad status codes -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	virtual void result(const LLSD& content); +	/* virtual */ void httpFailure(); +	/* virtual */ void httpSuccess(); -private:  	LLVivoxVoiceClient::state mRequestingState;  // state   }; -void LLVivoxVoiceClientCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpFailure()  { -	LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder error [status:" -		<< status << "]: " << content << LL_ENDL; +	LL_WARNS("Voice") << dumpResponse() << LL_ENDL;  	LLVivoxVoiceClient::getInstance()->sessionTerminate();  } -void LLVivoxVoiceClientCapResponder::result(const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpSuccess()  {  	LLSD::map_const_iterator iter; -	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; +	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << dumpResponse() << LL_ENDL;  	std::string uri;  	std::string credentials; +	const LLSD& content = getContent();  	if ( content.has("voice_credentials") )  	{  		LLSD voice_credentials = content["voice_credentials"]; @@ -2647,7 +2654,7 @@ void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString  	// Status code of 20200 means "bad password".  We may want to special-case that at some point. -	if ( statusCode == 401 ) +	if ( statusCode == HTTP_UNAUTHORIZED )  	{  		// Login failure which is probably caused by the delay after a user's password being updated.  		LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; @@ -3149,7 +3156,7 @@ void LLVivoxVoiceClient::mediaStreamUpdatedEvent(  		switch(statusCode)  		{  			case 0: -			case 200: +			case HTTP_OK:  				// generic success  				// Don't change the saved error code (it may have been set elsewhere)  			break; @@ -3422,7 +3429,7 @@ void LLVivoxVoiceClient::messageEvent(  	LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL;  //	LL_DEBUGS("Voice") << "    header " << messageHeader << ", body: \n" << messageBody << LL_ENDL; -	if(messageHeader.find("text/html") != std::string::npos) +	if(messageHeader.find(HTTP_CONTENT_TEXT_HTML) != std::string::npos)  	{  		std::string message; @@ -5389,9 +5396,10 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta  		{  			switch(mAudioSession->mErrorStatusCode)  			{ -				case 404:	// NOT_FOUND +				case HTTP_NOT_FOUND:	// NOT_FOUND +				// *TODO: Should this be 503?  				case 480:	// TEMPORARILY_UNAVAILABLE -				case 408:	// REQUEST_TIMEOUT +				case HTTP_REQUEST_TIME_OUT:	// REQUEST_TIMEOUT  					// call failed because other user was not available  					// treat this as an error case  					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e6385dceea..fab900cc74 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -83,7 +83,7 @@ const S32 MIN_QUIET_FRAMES_COALESCE = 30;  const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;  const F32 FORCE_CULL_AREA = 8.f;  const F32 MAX_LOD_DISTANCE = 24.f; - +U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 20;  BOOL gAnimateTextures = TRUE;  //extern BOOL gHideSelectedObjects; @@ -4396,6 +4396,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  	bool emissive = false; +	//Determine if we've received skininfo that contains an +	//alternate bind matrix - if it does then apply the translational component +	//to the joints of the avatar. +	bool pelvisGotSet = false; +  	{  		LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST); @@ -4477,18 +4482,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  					is_rigged = true;  					//get drawpool of avatar with rigged face -					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); -				 -					//Determine if we've received skininfo that contains an -					//alternate bind matrix - if it does then apply the translational component -					//to the joints of the avatar. -					bool pelvisGotSet = false; - +					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);				 +					  					if ( pAvatarVO )  					{ -						LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); +						LLUUID currentId = vobj->getVolume()->getParams().getSculptID();						  						const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); -					  						if ( pSkinData )  						{  							const int bindCnt = pSkinData->mAlternateBindMatrix.size();								 @@ -4496,43 +4495,42 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  							{					  								const int jointCnt = pSkinData->mJointNames.size();  								const F32 pelvisZOffset = pSkinData->mPelvisOffset; -								bool fullRig = (jointCnt>=20) ? true : false; +								bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false;								  								if ( fullRig ) -								{ +								{								  									for ( int i=0; i<jointCnt; ++i )  									{  										std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); -										//llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;  										LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );  										if ( pJoint && pJoint->getId() != currentId )  										{   									  											pJoint->setId( currentId );  											const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									 +											  											//Set the joint position -											pJoint->storeCurrentXform( jointPos );																																 +											pJoint->storeCurrentXform( jointPos );					 +									  											//If joint is a pelvis then handle old/new pelvis to foot values  											if ( lookingForJoint == "mPelvis" )  											{	 -												pJoint->storeCurrentXform( jointPos );																																  												if ( !pAvatarVO->hasPelvisOffset() )  												{										  													pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); -													//Trigger to rebuild viewer AV  													pelvisGotSet = true;											  												}										  											}										 -										} -									} +										}										 +									}																  								}							  							}  						}  					} -					//If we've set the pelvis to a new position we need to also rebuild some information that the -					//viewer does at launch (e.g. body size etc.) -					if ( pelvisGotSet ) +					 +					//Rebuild body data if we altered joints/pelvis +					if ( pelvisGotSet && pAvatarVO )   					{  						pAvatarVO->postPelvisSetRecalc(); -					} +					}		  					if (pool)  					{ @@ -4852,7 +4850,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  			{  				drawablep->clearState(LLDrawable::RIGGED);  			} +			  		} + +		 +		 +			 +		 +					 + +		  	}  	group->mBufferUsage = useage; diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index ef1a953f59..49b3c27ea0 100755 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -81,6 +81,7 @@ void LLWearableList::getAsset(const LLAssetID& assetID, const std::string& weara  	LLViewerWearable* instance = get_if_there(mList, assetID, (LLViewerWearable*)NULL );  	if( instance )  	{ +		LL_DEBUGS("Avatar") << "wearable " << assetID << " found in LLWearableList" << llendl;  		asset_arrived_callback( instance, userdata );  	}  	else diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 641f338f2c..567138e160 100755 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -67,9 +67,8 @@ public:  	{  	} +	// *TODO: Check for 'application/json' content type, and parse json at the base class.  	/*virtual*/ void completedRaw( -		U32 status, -		const std::string& reason,  		const LLChannelDescriptors& channels,  		const LLIOPipe::buffer_ptr_t& buffer)  	{ @@ -78,9 +77,9 @@ public:  		strstrm << istr.rdbuf();  		const std::string body = strstrm.str(); -		if (status != 200) +		if (getStatus() != HTTP_OK)  		{ -			llwarns << "Failed to get upload config (" << status << ")" << llendl; +			llwarns << "Failed to get upload config " << dumpResponse() << llendl;  			LLWebProfile::reportImageUploadStatus(false);  			return;  		} @@ -128,14 +127,12 @@ class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient::  public:  	/*virtual*/ void completedRaw( -		U32 status, -		const std::string& reason,  		const LLChannelDescriptors& channels,  		const LLIOPipe::buffer_ptr_t& buffer)  	{ -		if (status != 200) +		if (getStatus() != HTTP_OK)  		{ -			llwarns << "Failed to upload image: " << status << " " << reason << llendl; +			llwarns << "Failed to upload image " << dumpResponse() << llendl;  			LLWebProfile::reportImageUploadStatus(false);  			return;  		} @@ -161,33 +158,36 @@ class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responde  	LOG_CLASS(LLWebProfileResponders::PostImageResponder);  public: -	/*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content) +	/*virtual*/ void completedRaw(const LLChannelDescriptors& channels, +								  const LLIOPipe::buffer_ptr_t& buffer)  	{  		// Viewer seems to fail to follow a 303 redirect on POST request  		// (URLRequest Error: 65, Send failed since rewinding of the data stream failed).  		// Handle it manually. -		if (status == 303) +		if (getStatus() == HTTP_SEE_OTHER)  		{  			LLSD headers = LLViewerMedia::getHeaders(); -			headers["Cookie"] = LLWebProfile::getAuthCookie(); -			const std::string& redir_url = content["location"]; -			LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl; -			LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); +			headers[HTTP_OUT_HEADER_COOKIE] = LLWebProfile::getAuthCookie(); +			const std::string& redir_url = getResponseHeader(HTTP_IN_HEADER_LOCATION); +			if (redir_url.empty()) +			{ +				llwarns << "Received empty redirection URL " << dumpResponse() << llendl; +				LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +				LLWebProfile::reportImageUploadStatus(false); +			} +			else +			{ +				LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl; +				LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); +			}  		}  		else  		{ -			llwarns << "Unexpected POST status: " << status << " " << reason << llendl; -			LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << llendl; +			llwarns << "Unexpected POST response " << dumpResponse() << llendl; +			LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;  			LLWebProfile::reportImageUploadStatus(false);  		}  	} - -	// Override just to suppress warnings. -	/*virtual*/ void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) -	{ -	}  };  /////////////////////////////////////////////////////////////////////////////// @@ -206,7 +206,7 @@ void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::str  	LL_DEBUGS("Snapshots") << "Requesting " << config_url << llendl;  	LLSD headers = LLViewerMedia::getHeaders(); -	headers["Cookie"] = getAuthCookie(); +	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie();  	LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers);  } @@ -230,8 +230,8 @@ void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, c  	const std::string boundary = "----------------------------0123abcdefab";  	LLSD headers = LLViewerMedia::getHeaders(); -	headers["Cookie"] = getAuthCookie(); -	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; +	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); +	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + boundary;  	std::ostringstream body; diff --git a/indra/newview/llwebsharing.cpp b/indra/newview/llwebsharing.cpp index 3a80051b9b..7036162014 100755 --- a/indra/newview/llwebsharing.cpp +++ b/indra/newview/llwebsharing.cpp @@ -32,7 +32,7 @@  #include "llagentui.h"  #include "llbufferstream.h"  #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llsdserialize.h"  #include "llsdutil.h"  #include "llurl.h" @@ -45,36 +45,79 @@  ///////////////////////////////////////////////////////////////////////////////  // -class LLWebSharingConfigResponder : public LLHTTPClient::Responder + +class LLWebSharingJSONResponder : public LLHTTPClient::Responder  { -	LOG_CLASS(LLWebSharingConfigResponder); +	LOG_CLASS(LLWebSharingJSONResponder);  public:  	/// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, +	virtual void completedRaw(const LLChannelDescriptors& channels,  							  const LLIOPipe::buffer_ptr_t& buffer)  	{ -		LLSD content;  		LLBufferStream istr(channels, buffer.get()); +		// *TODO: LLSD notation is not actually JSON.  		LLPointer<LLSDParser> parser = new LLSDNotationParser(); -		if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) +		std::string debug_body("(empty)"); +		bool parsed=true; +		if (EOF == istr.peek())  		{ -			LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; +			parsed=false;  		} -		else +		// Try to parse body as llsd, no matter what 'content-type' says. +		else if (parser->parse(istr, mContent, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)  		{ -			completed(status, reason, content); +			parsed=false; +			char body[1025];  +			body[1024] = '\0'; +			istr.seekg(0, std::ios::beg); +			istr.get(body,1024); +			if (strlen(body) > 0) +			{ +				mContent = body; +				debug_body = body; +			}  		} + +		// Only emit a warning if we failed to parse when 'content-type' == 'application/json' +		if (!parsed && (HTTP_CONTENT_JSON == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE))) +		{ +			llwarns << "Failed to deserialize LLSD from JSON response. " << getURL() +				<< " [status:" << mStatus << "] "  +				<< "(" << mReason << ") body: " << debug_body << llendl; +		} + +		if (!parsed) +		{ +			// *TODO: This isn't necessarily the server's fault.  Using a 5xx code +			// isn't really appropriate here. +			// Also, this hides the actual status returned by the server.... +			mStatus = HTTP_INTERNAL_ERROR; +			mReason = "Failed to deserialize LLSD from JSON response."; +		} + +		httpCompleted();  	} +}; -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +class LLWebSharingConfigResponder : public LLWebSharingJSONResponder +{ +	LOG_CLASS(LLWebSharingConfigResponder); +private: + +	virtual void httpFailure()  	{ -		LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; +		LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL;  	} -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{ +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLWebSharing::instance().receiveConfig(content);  	}  }; @@ -87,39 +130,34 @@ class LLWebSharingOpenIDAuthResponder : public LLHTTPClient::Responder  {  	LOG_CLASS(LLWebSharingOpenIDAuthResponder);  public: -	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) -	{ -		completed(status, reason, content); -	} - -	/* virtual */ void completedRaw(U32 status, const std::string& reason, -									const LLChannelDescriptors& channels, +	/* virtual */ void completedRaw(const LLChannelDescriptors& channels,  									const LLIOPipe::buffer_ptr_t& buffer)  	{  		/// Left empty to override the default LLSD parsing behaviour. +		httpCompleted();  	} -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +private: +	virtual void httpFailure()  	{ -		if (HTTP_UNAUTHORIZED == status) +		if (HTTP_UNAUTHORIZED == getStatus())  		{  			LL_WARNS("WebSharing") << "AU account not authenticated." << LL_ENDL;  			// *TODO: No account found on AU, so start the account creation process here.  		}  		else  		{ -			LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; +			LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL;  			LLWebSharing::instance().retryOpenIDAuth();  		} -  	} -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{ -		if (content.has("set-cookie")) +		if (hasResponseHeader(HTTP_IN_HEADER_SET_COOKIE))  		{  			// OpenID request succeeded and returned a session cookie. -			LLWebSharing::instance().receiveSessionCookie(content["set-cookie"].asString()); +			LLWebSharing::instance().receiveSessionCookie(getResponseHeader(HTTP_IN_HEADER_SET_COOKIE));  		}  	}  }; @@ -128,38 +166,19 @@ public:  ///////////////////////////////////////////////////////////////////////////////  // -class LLWebSharingSecurityTokenResponder : public LLHTTPClient::Responder +class LLWebSharingSecurityTokenResponder : public LLWebSharingJSONResponder  {  	LOG_CLASS(LLWebSharingSecurityTokenResponder); -public: -	/// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) +private: +	virtual void httpFailure()  	{ -		LLSD content; -		LLBufferStream istr(channels, buffer.get()); -		LLPointer<LLSDParser> parser = new LLSDNotationParser(); - -		if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) -		{ -			LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; -			LLWebSharing::instance().retryOpenIDAuth(); -		} -		else -		{ -			completed(status, reason, content); -		} -	} - -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -	{ -		LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; +		LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL;  		LLWebSharing::instance().retryOpenIDAuth();  	} -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{ +		const LLSD& content = getContent();  		if (content[0].has("st") && content[0].has("expires"))  		{  			const std::string& token   = content[0]["st"].asString(); @@ -172,7 +191,8 @@ public:  		}  		else  		{ -			LL_WARNS("WebSharing") << "No security token received." << LL_ENDL; +			failureResult(HTTP_INTERNAL_ERROR, "No security token received.", content); +			return;  		}  		LLWebSharing::instance().retryOpenIDAuth(); @@ -183,51 +203,18 @@ public:  ///////////////////////////////////////////////////////////////////////////////  // -class LLWebSharingUploadResponder : public LLHTTPClient::Responder +class LLWebSharingUploadResponder : public LLWebSharingJSONResponder  {  	LOG_CLASS(LLWebSharingUploadResponder); -public: -	/// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) -	{ -/* -		 // Dump the body, for debugging. - -		 LLBufferStream istr1(channels, buffer.get()); -		 std::ostringstream ostr; -		 std::string body; - -		 while (istr1.good()) -		 { -			char buf[1024]; -			istr1.read(buf, sizeof(buf)); -			body.append(buf, istr1.gcount()); -		 } -		 LL_DEBUGS("WebSharing") << body << LL_ENDL; -*/ -		LLSD content; -		LLBufferStream istr(channels, buffer.get()); -		LLPointer<LLSDParser> parser = new LLSDNotationParser(); - -		if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) -		{ -			LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; -		} -		else -		{ -			completed(status, reason, content); -		} -	} - -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +private: +	virtual void httpFailure()  	{ -		LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; +		LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL;  	} -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{ +		const LLSD& content = getContent();  		if (content[0].has("result") && content[0].has("id") &&  			content[0]["id"].asString() == "newMediaItem")  		{ @@ -235,8 +222,8 @@ public:  		}  		else  		{ -			LL_WARNS("WebSharing") << "Error [" << content[0]["code"].asString() -								   << "]: " << content[0]["message"].asString() << LL_ENDL; +			failureResult(HTTP_INTERNAL_ERROR, "Invalid response content", content); +			return;  		}  	}  }; @@ -333,7 +320,7 @@ void LLWebSharing::sendConfigRequest()  	LL_DEBUGS("WebSharing") << "Requesting Snapshot Sharing config data from: " << config_url << LL_ENDL;  	LLSD headers = LLSD::emptyMap(); -	headers["Accept"] = "application/json"; +	headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON;  	LLHTTPClient::get(config_url, new LLWebSharingConfigResponder(), headers);  } @@ -344,8 +331,8 @@ void LLWebSharing::sendOpenIDAuthRequest()  	LL_DEBUGS("WebSharing") << "Starting OpenID Auth: " << auth_url << LL_ENDL;  	LLSD headers = LLSD::emptyMap(); -	headers["Cookie"] = mOpenIDCookie; -	headers["Accept"] = "*/*"; +	headers[HTTP_OUT_HEADER_COOKIE] = mOpenIDCookie; +	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";  	// Send request, successful login will trigger fetching a security token.  	LLHTTPClient::get(auth_url, new LLWebSharingOpenIDAuthResponder(), headers); @@ -371,10 +358,10 @@ void LLWebSharing::sendSecurityTokenRequest()  	LL_DEBUGS("WebSharing") << "Fetching security token from: " << token_url << LL_ENDL;  	LLSD headers = LLSD::emptyMap(); -	headers["Cookie"] = mSessionCookie; +	headers[HTTP_OUT_HEADER_COOKIE] = mSessionCookie; -	headers["Accept"] = "application/json"; -	headers["Content-Type"] = "application/json"; +	headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON; +	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_JSON;  	std::ostringstream body;  	body << "{ \"gadgets\": [{ \"url\":\"" @@ -400,10 +387,10 @@ void LLWebSharing::sendUploadRequest()  	static const std::string BOUNDARY("------------abcdef012345xyZ");  	LLSD headers = LLSD::emptyMap(); -	headers["Cookie"] = mSessionCookie; +	headers[HTTP_OUT_HEADER_COOKIE] = mSessionCookie; -	headers["Accept"] = "application/json"; -	headers["Content-Type"] = "multipart/form-data; boundary=" + BOUNDARY; +	headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON; +	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + BOUNDARY;  	std::ostringstream body;  	body << "--" << BOUNDARY << "\r\n" diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index 93eba5b604..3bedfbe502 100755 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -95,8 +95,9 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()  {  	mID = ++sCount;  } -/*virtual*/ void LLEnvironmentRequestResponder::result(const LLSD& unvalidated_content) +/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess()  { +	const LLSD& unvalidated_content = getContent();  	LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL;  	if (mID != sCount) @@ -122,10 +123,10 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()  	LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content);  }  /*virtual*/ -void LLEnvironmentRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLEnvironmentRequestResponder::httpFailure()  { -	LL_INFOS("WindlightCaps") << "Got an error, not using region windlight... [status:"  -		<< status << "]: " << content << LL_ENDL; +	LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " +			<< dumpResponse() << LL_ENDL;  	LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD());  } @@ -169,8 +170,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)  /****   * LLEnvironmentApplyResponder   ****/ -/*virtual*/ void LLEnvironmentApplyResponder::result(const LLSD& content) +/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap() || !content.has("regionID")) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID())  	{  		LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " @@ -185,7 +192,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)  	}  	else  	{ -		LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  Reason from sim: " << content["fail_reason"].asString() << LL_ENDL; +		LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  " << dumpResponse() << LL_ENDL;  		LLSD args(LLSD::emptyMap());  		args["FAIL_REASON"] = content["fail_reason"].asString();  		LLNotificationsUtil::add("WLRegionApplyFail", args); @@ -193,14 +200,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)  	}  }  /*virtual*/ -void LLEnvironmentApplyResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLEnvironmentApplyResponder::httpFailure()  { -	LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region!  [status:" -		<< status << "]: " << content << LL_ENDL; +	LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " +		<< dumpResponse() << LL_ENDL;  	LLSD args(LLSD::emptyMap());  	std::stringstream msg; -	msg << reason << " (Code " << status << ")"; +	msg << getReason() << " (Code " << getStatus() << ")";  	args["FAIL_REASON"] = msg.str();  	LLNotificationsUtil::add("WLRegionApplyFail", args);  } diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 598ce6d52a..089c799da7 100755 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -45,9 +45,9 @@ private:  class LLEnvironmentRequestResponder: public LLHTTPClient::Responder  {  	LOG_CLASS(LLEnvironmentRequestResponder); -public: -	virtual void result(const LLSD& content); -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure();  private:  	friend class LLEnvironmentRequest; @@ -72,7 +72,7 @@ private:  class LLEnvironmentApplyResponder: public LLHTTPClient::Responder  {  	LOG_CLASS(LLEnvironmentApplyResponder); -public: +private:  	/*  	 * Expecting reply from sim in form of:  	 * { @@ -87,10 +87,10 @@ public:  	 *   fail_reason : string  	 * }  	 */ -	virtual void result(const LLSD& content); +	/* virtual */ void httpSuccess(); -	// non-200 errors only -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +	// non-2xx errors only +	/* virtual */ void httpFailure();  private:  	friend class LLEnvironmentApply; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 7996f8a640..ebd96702a1 100755 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1080,6 +1080,8 @@ public:  					<< sim << llendl;  			return;  		} +		LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from LLEstablishAgentCommunication::post. Seed cap == " +				<< input["body"]["seed-capability"] << LL_ENDL;  		regionp->setSeedCapability(input["body"]["seed-capability"]);  	}  }; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 0da70d398b..7c5f8be1b5 100755 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -331,7 +331,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)  	   This might help with bug #503 */  	mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); -    mCurlRequest->slist_append("Content-Type: text/xml"); +    mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);  	if (useGzip)  	{ diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index ebd2799ebf..6b95a0cb61 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -10146,5 +10146,7 @@ Cannot create large prims that intersect other players.  Please re-try when othe       name="okignore"       yestext="OK"/>    </notification> -   + + +   </notifications> diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp new file mode 100755 index 0000000000..25e6de46d9 --- /dev/null +++ b/indra/newview/tests/llhttpretrypolicy_test.cpp @@ -0,0 +1,328 @@ +/**  + * @file llhttpretrypolicy_test.cpp + * @brief Header tests to exercise the LLHTTPRetryPolicy classes. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "../llhttpretrypolicy.h" +#include "lltut.h" + +namespace tut +{ +struct TestData +{ +}; + +typedef test_group<TestData>	RetryPolicyTestGroup; +typedef RetryPolicyTestGroup::object		RetryPolicyTestObject; +RetryPolicyTestGroup retryPolicyTestGroup("retry_policy"); + +template<> template<> +void RetryPolicyTestObject::test<1>() +{ +	LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0); +	LLSD headers; +	F32 wait_seconds; +	 +	// No retry until we've failed a try. +	ensure("never retry 0", !never_retry.shouldRetry(wait_seconds)); + +	// 0 retries max. +	never_retry.onFailure(500,headers); +	ensure("never retry 1", !never_retry.shouldRetry(wait_seconds));  +} + +template<> template<> +void RetryPolicyTestObject::test<2>() +{ +	LLSD headers; +	F32 wait_seconds; + +	// Normally only retry on server error (5xx) +	LLAdaptiveRetryPolicy noRetry404(1.0,2.0,3.0,10); +	noRetry404.onFailure(404,headers); +	ensure("no retry on 404", !noRetry404.shouldRetry(wait_seconds));  + +	// Can retry on 4xx errors if enabled by flag. +	bool do_retry_4xx = true; +	LLAdaptiveRetryPolicy doRetry404(1.0,2.0,3.0,10,do_retry_4xx); +	doRetry404.onFailure(404,headers); +	ensure("do retry on 404", doRetry404.shouldRetry(wait_seconds));  +} + +template<> template<> +void RetryPolicyTestObject::test<3>() +{ +	// Should retry after 1.0, 2.0, 3.0, 3.0 seconds. +	LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4); +	LLSD headers; +	F32 wait_seconds; +	bool should_retry; +	U32 frac_bits = 6; + +	// No retry until we've failed a try. +	ensure("basic_retry 0", !basic_retry.shouldRetry(wait_seconds)); + +	// Starting wait 1.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 1", should_retry); +	ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits); + +	// Double wait to 2.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 2", should_retry); +	ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits); + +	// Hit max wait of 3.0 (4.0 clamped to max 3) +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 3", should_retry); +	ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits); + +	// At max wait, should stay at 3.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 4", should_retry); +	ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits); + +	// Max retries, should fail now. +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 5", !should_retry); + +	// Max retries, should fail now. +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 5", !should_retry); + +	// After a success, should reset to the starting state. +	basic_retry.onSuccess(); + +	// No retry until we've failed a try. +	ensure("basic_retry 6", !basic_retry.shouldRetry(wait_seconds)); + +	// Starting wait 1.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 7", should_retry); +	ensure_approximately_equals("basic_retry 7", wait_seconds, 1.0F, frac_bits); + +	// Double wait to 2.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 8", should_retry); +	ensure_approximately_equals("basic_retry 8", wait_seconds, 2.0F, frac_bits); +} + +// Retries should stop as soon as a non-5xx error is received. +template<> template<> +void RetryPolicyTestObject::test<4>() +{ +	// Should retry after 1.0, 2.0, 3.0, 3.0 seconds. +	LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4); +	LLSD headers; +	F32 wait_seconds; +	bool should_retry; +	U32 frac_bits = 6; + +	// Starting wait 1.0 +	killer404.onFailure(500,headers); +	should_retry = killer404.shouldRetry(wait_seconds); +	ensure("killer404 1", should_retry); +	ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits); + +	// Double wait to 2.0 +	killer404.onFailure(500,headers); +	should_retry = killer404.shouldRetry(wait_seconds); +	ensure("killer404 2", should_retry); +	ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits); + +	// Should fail on non-5xx +	killer404.onFailure(404,headers); +	should_retry = killer404.shouldRetry(wait_seconds); +	ensure("killer404 3", !should_retry); + +	// After a non-5xx, should keep failing. +	killer404.onFailure(500,headers); +	should_retry = killer404.shouldRetry(wait_seconds); +	ensure("killer404 4", !should_retry); +} + +// Test handling of "retry-after" header. If present, this header +// value overrides the computed delay, but does not affect the +// progression of delay values.  For example, if the normal +// progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls +// get a retry header of 33, the pattern would become 1,33,33,8... +template<> template<> +void RetryPolicyTestObject::test<5>() +{ +	LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6); +	LLSD headers_with_retry; +	headers_with_retry[HTTP_IN_HEADER_RETRY_AFTER] = "666"; +	LLSD headers_without_retry; +	F32 wait_seconds; +	bool should_retry; +	U32 frac_bits = 6; + +	policy.onFailure(500,headers_without_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 1", should_retry); +	ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits); + +	policy.onFailure(500,headers_without_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 2", should_retry); +	ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits); + +	policy.onFailure(500,headers_with_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 3", should_retry); +	// 4.0 overrides by header -> 666.0 +	ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits); + +	policy.onFailure(500,headers_with_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 4", should_retry); +	// 8.0 overrides by header -> 666.0 +	ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits); + +	policy.onFailure(500,headers_without_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 5", should_retry); +	ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits); + +	policy.onFailure(500,headers_without_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 6", should_retry); +	ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits); + +	policy.onFailure(500,headers_with_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 7", !should_retry); +} + +// Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait), +// used by header parsing of the retry policy. +template<> template<> +void RetryPolicyTestObject::test<6>() +{ +	F32 seconds_to_wait; +	bool success; + +	std::string str1("0"); +	seconds_to_wait = F32_MAX; +	success = getSecondsUntilRetryAfter(str1, seconds_to_wait); +	ensure("parse 1", success); +	ensure_equals("parse 1", seconds_to_wait, 0.0); + +	std::string str2("999.9"); +	seconds_to_wait = F32_MAX; +	success = getSecondsUntilRetryAfter(str2, seconds_to_wait); +	ensure("parse 2", success); +	ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8); + +	time_t nowseconds; +	time(&nowseconds); +	std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123(); +	seconds_to_wait = F32_MAX; +	success = getSecondsUntilRetryAfter(str3, seconds_to_wait); +	std::cerr << " str3 [" << str3 << "]" << std::endl; +	ensure("parse 3", success); +	ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F); +} + +// Test retry-after field in both llmessage and CoreHttp headers. +template<> template<> +void RetryPolicyTestObject::test<7>() +{ +	std::cerr << "7 starts" << std::endl; +	 +	LLSD sd_headers; +	time_t nowseconds; +	time(&nowseconds); +	LLAdaptiveRetryPolicy policy(17.0,644.0,3.0,5); +	F32 seconds_to_wait; +	bool should_retry; + +	// No retry until we've failed a try. +	ensure("header 0", !policy.shouldRetry(seconds_to_wait)); +	 +	// no retry header, use default. +	policy.onFailure(500,LLSD()); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 1", should_retry); +	ensure_approximately_equals("header 1", seconds_to_wait, 17.0F, 6); + +	// retry header should override, give delay of 0 +	std::string date_string = LLDate((F64)(nowseconds+7)).asRFC1123(); +	sd_headers[HTTP_IN_HEADER_RETRY_AFTER] = date_string; +	policy.onFailure(503,sd_headers); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 2", should_retry); +	ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F); + +	LLCore::HttpResponse *response; +	LLCore::HttpHeaders *headers; + +	response = new LLCore::HttpResponse(); +	headers = new LLCore::HttpHeaders(); +	response->setStatus(503); +	response->setHeaders(headers); +	headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600")); +	policy.onFailure(response); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 3",should_retry); +	ensure_approximately_equals("header 3", seconds_to_wait, 600.0F, 6); +	response->release(); + +	response = new LLCore::HttpResponse(); +	headers = new LLCore::HttpHeaders(); +	response->setStatus(503); +	response->setHeaders(headers); +	time(&nowseconds); +	date_string = LLDate((F64)(nowseconds+77)).asRFC1123(); +	std::cerr << "date_string [" << date_string << "]" << std::endl; +	headers->append(HTTP_IN_HEADER_RETRY_AFTER,date_string); +	policy.onFailure(response); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 4",should_retry); +	ensure_approximately_equals_range("header 4", seconds_to_wait, 77.0F, 2.0F); +	response->release(); + +	// Timeout should be clamped at max. +	policy.onFailure(500,LLSD()); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 5", should_retry); +	ensure_approximately_equals("header 5", seconds_to_wait, 644.0F, 6); + +	// No more retries. +	policy.onFailure(500,LLSD()); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 6", !should_retry); +} + +} + diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp index 3e55336f2d..6f57daf151 100755 --- a/indra/newview/tests/llmediadataclient_test.cpp +++ b/indra/newview/tests/llmediadataclient_test.cpp @@ -33,7 +33,7 @@  #include "llsdserialize.h"  #include "llsdutil.h"  #include "llerrorcontrol.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "../llmediadataclient.h"  #include "../llvovolume.h" @@ -129,7 +129,7 @@ void LLHTTPClient::post(  	{  		LLSD content;  		content["reason"] = "fake reason"; -		responder->errorWithContent(HTTP_SERVICE_UNAVAILABLE, "fake reason", content); +		responder->failureResult(HTTP_SERVICE_UNAVAILABLE, "fake reason", content);  		return;  	}  	else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR)  @@ -137,8 +137,8 @@ void LLHTTPClient::post(  		LLSD error;  		error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE;  		result["error"] = error; -	}	 -	responder->result(result); +	} +	responder->successResult(result);  }  const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index ed66066b0a..c49b0350e9 100755 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -40,12 +40,14 @@ namespace {  LLCurl::Responder::Responder() { }  LLCurl::Responder::~Responder() { } -void LLCurl::Responder::error(U32,std::string const &) { } -void LLCurl::Responder::result(LLSD const &) { } -void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { } -void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } -void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { } -void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { } +void LLCurl::Responder::httpFailure() { } +void LLCurl::Responder::httpSuccess() { } +void LLCurl::Responder::httpCompleted() { } +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) { } +void LLCurl::Responder::successResult(const LLSD& content) { } +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content) { } +std::string LLCurl::Responder::dumpResponse() const { return "(failure)"; } +void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }  void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { }  void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { }  void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { } @@ -85,7 +87,7 @@ namespace tut  		virtual void setParcelID(const LLUUID& parcel_id) { } -		virtual void setErrorStatus(U32 status, const std::string& reason) { } +		virtual void setErrorStatus(S32 status, const std::string& reason) { }  		bool mProcessed;  	}; diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp index fd9527d631..b28eb5db43 100755 --- a/indra/newview/tests/lltranslate_test.cpp +++ b/indra/newview/tests/lltranslate_test.cpp @@ -34,6 +34,8 @@  #include "lltrans.h"  #include "llui.h" +#include "../../llmessage/llhttpconstants.cpp" +  static const std::string GOOGLE_VALID_RESPONSE1 =  "{\   \"data\": {\ @@ -300,12 +302,10 @@ std::string LLControlGroup::getString(const std::string& name) { return "dummy";  LLControlGroup::~LLControlGroup() {}  LLCurl::Responder::Responder() {} -void LLCurl::Responder::completedHeader(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::completedRaw(U32, const std::string&, const LLChannelDescriptors&, const LLIOPipe::buffer_ptr_t& buffer) {} -void LLCurl::Responder::completed(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::error(U32, std::string const&) {} -void LLCurl::Responder::errorWithContent(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::result(LLSD const&) {} +void LLCurl::Responder::httpFailure() { } +void LLCurl::Responder::httpSuccess() { } +void LLCurl::Responder::httpCompleted() { } +void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }  LLCurl::Responder::~Responder() {}  void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32) {}  | 
